Changed the implementation of the sparse and packed switch directives, so that they don't required the base offset label. Instead, it looks for and uses the offset of the first packed/sparse switch instruction that references it, to calculate the offset for each target

git-svn-id: https://smali.googlecode.com/svn/trunk@150 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2009-06-15 06:02:49 +00:00
parent 5a0f83d156
commit 3a76e6904b
5 changed files with 111 additions and 36 deletions

View File

@ -81,7 +81,7 @@ Label13:
return-void return-void
PackedSwitch: PackedSwitch:
.packed-switch switch: 10 .packed-switch 10
Label10: Label10:
Label11: Label11:
Label12: Label12:
@ -120,7 +120,7 @@ Label99:
return-void return-void
SparseSwitch: SparseSwitch:
.sparse-switch switch: .sparse-switch
10 -> Label10: 10 -> Label10:
13 -> Label13: 13 -> Label13:
15 -> Label15: 15 -> Label15:

View File

@ -33,7 +33,6 @@
const v0, 12 const v0, 12
switch:
packed-switch v0, PackedSwitch: packed-switch v0, PackedSwitch:
Label10: Label10:
@ -58,7 +57,7 @@ Label13:
nop nop
PackedSwitch: PackedSwitch:
.packed-switch switch: 10 .packed-switch 10
Label10: Label10:
Label11: Label11:
Label12: Label12:

View File

@ -452,8 +452,6 @@ ARRAY_DATA_PHRASE
PACKED_SWITCH_PHRASE PACKED_SWITCH_PHRASE
: PACKED_SWITCH_DIRECTIVE_EMIT : PACKED_SWITCH_DIRECTIVE_EMIT
WS
(LABEL_EMIT | OFFSET_EMIT)
WS WS
FIXED_32BIT_LITERAL_EMITCHILD FIXED_32BIT_LITERAL_EMITCHILD
(WSC (LABEL_EMIT | OFFSET_EMIT))* (WSC (LABEL_EMIT | OFFSET_EMIT))*
@ -462,10 +460,8 @@ PACKED_SWITCH_PHRASE
SPARSE_SWITCH_PHRASE SPARSE_SWITCH_PHRASE
: SPARSE_SWITCH_DIRECTIVE_EMIT : SPARSE_SWITCH_DIRECTIVE_EMIT
WS
(LABEL_EMIT | OFFSET_EMIT)
(WSC FIXED_32BIT_LITERAL_EMITCHILD WS? '->' WS? (LABEL_EMIT | OFFSET_EMIT))* (WSC FIXED_32BIT_LITERAL_EMITCHILD WS? '->' WS? (LABEL_EMIT | OFFSET_EMIT))*
WSC WSC?
END_SPARSE_SWITCH_DIRECTIVE_EMIT; END_SPARSE_SWITCH_DIRECTIVE_EMIT;
REGISTERS_PHRASE REGISTERS_PHRASE

View File

@ -63,13 +63,15 @@ tokens {
I_ARRAY_ELEMENT_SIZE; I_ARRAY_ELEMENT_SIZE;
I_ARRAY_ELEMENTS; I_ARRAY_ELEMENTS;
I_PACKED_SWITCH_START_KEY; I_PACKED_SWITCH_START_KEY;
I_PACKED_SWITCH_BASE_OFFSET;
I_PACKED_SWITCH_TARGET_COUNT; I_PACKED_SWITCH_TARGET_COUNT;
I_PACKED_SWITCH_TARGETS; I_PACKED_SWITCH_TARGETS;
I_SPARSE_SWITCH_BASE_OFFSET; I_PACKED_SWITCH_DECLARATION;
I_PACKED_SWITCH_DECLARATIONS;
I_SPARSE_SWITCH_KEYS; I_SPARSE_SWITCH_KEYS;
I_SPARSE_SWITCH_TARGET_COUNT; I_SPARSE_SWITCH_TARGET_COUNT;
I_SPARSE_SWITCH_TARGETS; I_SPARSE_SWITCH_TARGETS;
I_SPARSE_SWITCH_DECLARATION;
I_SPARSE_SWITCH_DECLARATIONS;
I_ADDRESS; I_ADDRESS;
I_CATCH; I_CATCH;
I_CATCHES; I_CATCHES;
@ -153,6 +155,14 @@ import org.jf.dexlib.code.Format.*;
public String getErrorHeader(RecognitionException e) { public String getErrorHeader(RecognitionException e) {
return getSourceName()+"["+ e.line+","+e.charPositionInLine+"]"; return getSourceName()+"["+ e.line+","+e.charPositionInLine+"]";
} }
private CommonTree buildTree(int type, String text, List<CommonTree> children) {
CommonTree root = new CommonTree(new CommonToken(type, text));
for (CommonTree child: children) {
root.addChild(child);
}
return root;
}
} }
@ -235,10 +245,17 @@ fully_qualified_field
-> reference_type_descriptor MEMBER_NAME nonvoid_type_descriptor; -> reference_type_descriptor MEMBER_NAME nonvoid_type_descriptor;
statements_and_directives statements_and_directives
scope {boolean hasRegistersDirective;} scope
{
boolean hasRegistersDirective;
List<CommonTree> packedSwitchDeclarations;
List<CommonTree> sparseSwitchDeclarations;
}
: { : {
$method::currentAddress = 0; $method::currentAddress = 0;
$statements_and_directives::hasRegistersDirective = false; $statements_and_directives::hasRegistersDirective = false;
$statements_and_directives::packedSwitchDeclarations = new ArrayList<CommonTree>();
$statements_and_directives::sparseSwitchDeclarations = new ArrayList<CommonTree>();
} }
( instruction {$method::currentAddress += $instruction.size/2;} ( instruction {$method::currentAddress += $instruction.size/2;}
| {!$statements_and_directives::hasRegistersDirective}?=> registers_directive {$statements_and_directives::hasRegistersDirective = true;} | {!$statements_and_directives::hasRegistersDirective}?=> registers_directive {$statements_and_directives::hasRegistersDirective = true;}
@ -250,6 +267,8 @@ statements_and_directives
)* )*
-> ^(I_REGISTERS registers_directive?) -> ^(I_REGISTERS registers_directive?)
^(I_LABELS label*) ^(I_LABELS label*)
{buildTree(I_PACKED_SWITCH_DECLARATIONS, "I_PACKED_SWITCH_DECLARATIONS", $statements_and_directives::packedSwitchDeclarations)}
{buildTree(I_SPARSE_SWITCH_DECLARATIONS, "I_SPARSE_SWITCH_DECLARATIONS", $statements_and_directives::sparseSwitchDeclarations)}
^(I_STATEMENTS instruction*) ^(I_STATEMENTS instruction*)
^(I_CATCHES catch_directive*) ^(I_CATCHES catch_directive*)
^(I_PARAMETERS parameter_directive*) ^(I_PARAMETERS parameter_directive*)
@ -389,8 +408,23 @@ instruction returns [int size]
INSTRUCTION_FORMAT31i REGISTER fixed_32bit_literal {$size = Format.Format31i.size;} INSTRUCTION_FORMAT31i REGISTER fixed_32bit_literal {$size = Format.Format31i.size;}
-> ^(I_STATEMENT_FORMAT31i[$start, "I_STATEMENT_FORMAT31i"] INSTRUCTION_FORMAT31i REGISTER fixed_32bit_literal) -> ^(I_STATEMENT_FORMAT31i[$start, "I_STATEMENT_FORMAT31i"] INSTRUCTION_FORMAT31i REGISTER fixed_32bit_literal)
| //e.g. fill-array-data v0, ArrayData: | //e.g. fill-array-data v0, ArrayData:
INSTRUCTION_FORMAT31t REGISTER (LABEL | OFFSET) {$size = Format.Format31t.size;} INSTRUCTION_FORMAT31t REGISTER offset_or_label {$size = Format.Format31t.size;}
-> ^(I_STATEMENT_FORMAT31t[$start, "I_STATEMENT_FORMAT31t"] INSTRUCTION_FORMAT31t REGISTER LABEL? OFFSET?) {
if ($INSTRUCTION_FORMAT31t.text.equals("packed-switch")) {
CommonTree root = new CommonTree(new CommonToken(I_PACKED_SWITCH_DECLARATION, "I_PACKED_SWITCH_DECLARATION"));
CommonTree address = new CommonTree(new CommonToken(I_ADDRESS, Integer.toString($method::currentAddress)));
root.addChild(address);
root.addChild($offset_or_label.tree.dupNode());
$statements_and_directives::packedSwitchDeclarations.add(root);
} else if ($INSTRUCTION_FORMAT31t.text.equals("sparse-switch")) {
CommonTree root = new CommonTree(new CommonToken(I_SPARSE_SWITCH_DECLARATION, "I_SPARSE_SWITCH_DECLARATION"));
CommonTree address = new CommonTree(new CommonToken(I_ADDRESS, Integer.toString($method::currentAddress)));
root.addChild(address);
root.addChild($offset_or_label.tree.dupNode());
$statements_and_directives::sparseSwitchDeclarations.add(root);
}
}
-> ^(I_STATEMENT_FORMAT31t[$start, "I_STATEMENT_FORMAT31t"] INSTRUCTION_FORMAT31t REGISTER offset_or_label)
| //e.g. move/16 v4567, v1234 | //e.g. move/16 v4567, v1234
INSTRUCTION_FORMAT32x REGISTER REGISTER {$size = Format.Format32x.size;} INSTRUCTION_FORMAT32x REGISTER REGISTER {$size = Format.Format32x.size;}
-> ^(I_STATEMENT_FORMAT32x[$start, "I_STATEMENT_FORMAT32x"] INSTRUCTION_FORMAT32x REGISTER REGISTER) -> ^(I_STATEMENT_FORMAT32x[$start, "I_STATEMENT_FORMAT32x"] INSTRUCTION_FORMAT32x REGISTER REGISTER)
@ -440,8 +474,6 @@ instruction returns [int size]
} }
} }
base_offset = offset_or_label
fixed_32bit_literal fixed_32bit_literal
(switch_target += offset_or_label {$size+=4; targetCount++;})* (switch_target += offset_or_label {$size+=4; targetCount++;})*
@ -451,13 +483,11 @@ instruction returns [int size]
/*add a nop statement before this if needed to force the correct alignment*/ /*add a nop statement before this if needed to force the correct alignment*/
-> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"]) -> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"])
^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"] ^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"]
^(I_PACKED_SWITCH_BASE_OFFSET[$start, "I_PACKED_SWITCH_BASE_OFFSET"] $base_offset)
^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal) ^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal)
^(I_PACKED_SWITCH_TARGETS[$start, "I_PACKED_SWITCH_TARGETS"] I_PACKED_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] $switch_target*) ^(I_PACKED_SWITCH_TARGETS[$start, "I_PACKED_SWITCH_TARGETS"] I_PACKED_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] $switch_target*)
) )
-> ^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"] -> ^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"]
^(I_PACKED_SWITCH_BASE_OFFSET[$start, "I_PACKED_SWITCH_BASE_OFFSET"] $base_offset)
^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal) ^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal)
^(I_PACKED_SWITCH_TARGETS[$start, "I_PACKED_SWITCH_TARGETS"] I_PACKED_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] $switch_target*) ^(I_PACKED_SWITCH_TARGETS[$start, "I_PACKED_SWITCH_TARGETS"] I_PACKED_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] $switch_target*)
) )
@ -474,8 +504,6 @@ instruction returns [int size]
} }
} }
base_offset = offset_or_label
(fixed_32bit_literal switch_target += offset_or_label {$size += 8; targetCount++;})* (fixed_32bit_literal switch_target += offset_or_label {$size += 8; targetCount++;})*
END_SPARSE_SWITCH_DIRECTIVE {$size = $size + 4;} END_SPARSE_SWITCH_DIRECTIVE {$size = $size + 4;}
@ -483,12 +511,10 @@ instruction returns [int size]
/*add a nop statement before this if needed to force the correct alignment*/ /*add a nop statement before this if needed to force the correct alignment*/
-> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"]) -> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"])
^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"] ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"]
^(I_SPARSE_SWITCH_BASE_OFFSET[$start, "I_SPARSE_SWITCH_BASE_OFFSET"] $base_offset)
I_SPARSE_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] I_SPARSE_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)]
^(I_SPARSE_SWITCH_KEYS[$start, "I_SPARSE_SWITCH_KEYS"] fixed_32bit_literal*) ^(I_SPARSE_SWITCH_KEYS[$start, "I_SPARSE_SWITCH_KEYS"] fixed_32bit_literal*)
^(I_SPARSE_SWITCH_TARGETS $switch_target*)) ^(I_SPARSE_SWITCH_TARGETS $switch_target*))
-> ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"] -> ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"]
^(I_SPARSE_SWITCH_BASE_OFFSET[$start, "I_SPARSE_SWITCH_BASE_OFFSET"] $base_offset)
I_SPARSE_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] I_SPARSE_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)]
^(I_SPARSE_SWITCH_KEYS[$start, "I_SPARSE_SWITCH_KEYS"] fixed_32bit_literal*) ^(I_SPARSE_SWITCH_KEYS[$start, "I_SPARSE_SWITCH_KEYS"] fixed_32bit_literal*)
^(I_SPARSE_SWITCH_TARGETS $switch_target*)) ^(I_SPARSE_SWITCH_TARGETS $switch_target*))

View File

@ -132,6 +132,7 @@ smali_file
} }
header returns[TypeIdItem classType, int accessFlags, TypeIdItem superType, TypeListItem implementsList, StringIdItem sourceSpec] header returns[TypeIdItem classType, int accessFlags, TypeIdItem superType, TypeListItem implementsList, StringIdItem sourceSpec]
: class_spec super_spec implements_list source_spec : class_spec super_spec implements_list source_spec
{ {
@ -141,6 +142,7 @@ header returns[TypeIdItem classType, int accessFlags, TypeIdItem superType, Type
$super_spec.type, $implements_list.implementsList, $source_spec.source, classDataItem); $super_spec.type, $implements_list.implementsList, $source_spec.source, classDataItem);
}; };
class_spec returns[TypeIdItem type, int accessFlags] class_spec returns[TypeIdItem type, int accessFlags]
: class_type_descriptor access_list : class_type_descriptor access_list
{ {
@ -313,7 +315,7 @@ array_elements returns[List<byte[\]> values]
packed_switch_target_count returns[int targetCount] packed_switch_target_count returns[int targetCount]
: I_PACKED_SWITCH_TARGET_COUNT {$targetCount = Integer.parseInt($I_PACKED_SWITCH_TARGET_COUNT.text);}; : I_PACKED_SWITCH_TARGET_COUNT {$targetCount = Integer.parseInt($I_PACKED_SWITCH_TARGET_COUNT.text);};
packed_switch_targets[int baseOffset] returns[int[\] targets] packed_switch_targets[int baseAddress] returns[int[\] targets]
: :
^(I_PACKED_SWITCH_TARGETS ^(I_PACKED_SWITCH_TARGETS
packed_switch_target_count packed_switch_target_count
@ -325,7 +327,7 @@ packed_switch_targets[int baseOffset] returns[int[\] targets]
(offset_or_label (offset_or_label
{ {
targets[targetsPosition++] = $offset_or_label.offsetValue - $baseOffset; $targets[targetsPosition++] = ($method::currentAddress + $offset_or_label.offsetValue) - $baseAddress;
})* })*
); );
@ -344,7 +346,8 @@ sparse_switch_keys[int targetCount] returns[int[\] keys]
})* })*
); );
sparse_switch_targets[int baseOffset, int targetCount] returns[int[\] targets]
sparse_switch_targets[int baseAddress, int targetCount] returns[int[\] targets]
: { : {
$targets = new int[$targetCount]; $targets = new int[$targetCount];
int targetsPosition = 0; int targetsPosition = 0;
@ -352,7 +355,7 @@ sparse_switch_targets[int baseOffset, int targetCount] returns[int[\] targets]
^(I_SPARSE_SWITCH_TARGETS ^(I_SPARSE_SWITCH_TARGETS
(offset_or_label (offset_or_label
{ {
$targets[targetsPosition++] = $offset_or_label.offsetValue - $baseOffset; $targets[targetsPosition++] = ($method::currentAddress + $offset_or_label.offsetValue) - $baseAddress;
})* })*
); );
@ -365,6 +368,8 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod,
TryListBuilder tryList; TryListBuilder tryList;
int currentAddress; int currentAddress;
DebugInfoBuilder debugInfo; DebugInfoBuilder debugInfo;
HashMap<Integer, Integer> packedSwitchDeclarations;
HashMap<Integer, Integer> sparseSwitchDeclarations;
} }
@init @init
{ {
@ -379,6 +384,8 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod,
$method::tryList = new TryListBuilder(); $method::tryList = new TryListBuilder();
$method::currentAddress = 0; $method::currentAddress = 0;
$method::debugInfo = new DebugInfoBuilder(); $method::debugInfo = new DebugInfoBuilder();
$method::packedSwitchDeclarations = new HashMap<Integer, Integer>();
$method::sparseSwitchDeclarations = new HashMap<Integer, Integer>();
} }
^( I_METHOD ^( I_METHOD
method_name_and_prototype method_name_and_prototype
@ -394,6 +401,8 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod,
totalMethodRegisters = $registers_directive.registers; totalMethodRegisters = $registers_directive.registers;
} }
labels labels
packed_switch_declarations
sparse_switch_declarations
statements[totalMethodRegisters, methodParameterRegisters] statements[totalMethodRegisters, methodParameterRegisters]
catches catches
parameters parameters
@ -525,6 +534,34 @@ label_def
$method::labels.put(labelName, $address.address); $method::labels.put(labelName, $address.address);
}; };
packed_switch_declarations
: ^(I_PACKED_SWITCH_DECLARATIONS packed_switch_declaration*);
packed_switch_declaration
: ^(I_PACKED_SWITCH_DECLARATION address offset_or_label_absolute[$address.address])
{
int switchDataAddress = $offset_or_label_absolute.address;
if ((switchDataAddress \% 2) != 0) {
switchDataAddress++;
}
if (!$method::packedSwitchDeclarations.containsKey(switchDataAddress)) {
$method::packedSwitchDeclarations.put(switchDataAddress, $address.address);
}
};
sparse_switch_declarations
: ^(I_SPARSE_SWITCH_DECLARATIONS sparse_switch_declaration*);
sparse_switch_declaration
: ^(I_SPARSE_SWITCH_DECLARATION address offset_or_label_absolute[$address.address])
{
int switchDataAddress = $offset_or_label_absolute.address;
if ((switchDataAddress \% 2) != 0) {
switchDataAddress++;
}
if (!$method::sparseSwitchDeclarations.containsKey(switchDataAddress)) {
$method::sparseSwitchDeclarations.put(switchDataAddress, $address.address);
}
};
catches : ^(I_CATCHES catch_directive*); catches : ^(I_CATCHES catch_directive*);
catch_directive catch_directive
@ -1032,7 +1069,15 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
} }
| |
^(I_STATEMENT_PACKED_SWITCH ^(I_PACKED_SWITCH_BASE_OFFSET base_offset=offset_or_label) ^(I_PACKED_SWITCH_START_KEY fixed_32bit_literal) packed_switch_targets[$base_offset.offsetValue]) ^(I_STATEMENT_PACKED_SWITCH ^(I_PACKED_SWITCH_START_KEY fixed_32bit_literal)
{
int currentAddress = $method::currentAddress;
Integer baseAddress = $method::packedSwitchDeclarations.get(currentAddress);
if (baseAddress == null) {
baseAddress = 0;
}
}
packed_switch_targets[baseAddress])
{ {
int startKey = $fixed_32bit_literal.value; int startKey = $fixed_32bit_literal.value;
int[] targets = $packed_switch_targets.targets; int[] targets = $packed_switch_targets.targets;
@ -1040,7 +1085,16 @@ instruction[int totalMethodRegisters, int methodParameterRegisters] returns[Ins
$instruction = new InstructionField(dexFile, new PackedSwitchDataPseudoInstruction(dexFile, startKey, targets)); $instruction = new InstructionField(dexFile, new PackedSwitchDataPseudoInstruction(dexFile, startKey, targets));
} }
| |
^(I_STATEMENT_SPARSE_SWITCH ^(I_SPARSE_SWITCH_BASE_OFFSET base_offset=offset_or_label) sparse_switch_target_count sparse_switch_keys[$sparse_switch_target_count.targetCount] sparse_switch_targets[$base_offset.offsetValue, $sparse_switch_target_count.targetCount]) ^(I_STATEMENT_SPARSE_SWITCH sparse_switch_target_count sparse_switch_keys[$sparse_switch_target_count.targetCount]
{
int currentAddress = $method::currentAddress;
Integer baseAddress = $method::sparseSwitchDeclarations.get(currentAddress);
if (baseAddress == null) {
baseAddress = 0;
}
}
sparse_switch_targets[baseAddress, $sparse_switch_target_count.targetCount])
{ {
int[] keys = $sparse_switch_keys.keys; int[] keys = $sparse_switch_keys.keys;
int[] targets = $sparse_switch_targets.targets; int[] targets = $sparse_switch_targets.targets;