Top Description Fields Constructors Methods
org.droidparts.dexmaker.dx.dex.code

public final Class OutputFinisher

extends Object
Class Inheritance
Imports
org.droidparts.dexmaker.dx.dex.DexOptions, org.droidparts.dexmaker.dx.io.Opcodes, org.droidparts.dexmaker.dx.rop.code.*, org.droidparts.dexmaker.dx.rop.cst.Constant, .CstMemberRef, .CstString, .CstType, org.droidparts.dexmaker.dx.rop.type.Type, org.droidparts.dexmaker.dx.util.DexException, java.util.ArrayList, .BitSet, .HashSet

Processor for instruction lists, which takes a "first cut" of instruction selection as a basis and produces a "final cut" in the form of a DalvInsnList instance.

Field Summary

Modifier and TypeField and Description
private final DexOptions
dexOptions

non-null; options for dex output

private boolean
hasAnyLocalInfo

whether any instruction has local variable info

private boolean
hasAnyPositionInfo

whether any instruction has position info

private ArrayList<DalvInsn>
insns

non-null; the list of instructions, per se

private int
reservedCount

>= 0; the count of reserved registers (low-numbered registers used when expanding instructions that can't be represented simply); becomes valid after a call to massageInstructions

private final int
unreservedRegCount

>= 0; register count for the method, not including any extra "reserved" registers needed to translate "difficult" instructions

Constructor Summary

AccessConstructor and Description
public
OutputFinisher(DexOptions
non-null; options for dex output
dexOptions
,
int
>= 0; initial capacity of the instructions list
initialCapacity
,
int
>= 0; register count for the method
regCount
)

Constructs an instance.

Method Summary

Modifier and TypeMethod and Description
public void
add(DalvInsn
non-null; the instruction to add
insn
)

Adds an instruction to the output.

private static void
addConstants(HashSet<Constant>
non-null; result set to add to
result
,
DalvInsn
non-null; instruction to scrutinize
insn
)

Helper for getAllConstants which adds all the info for a single instruction.

private static void
addConstants(HashSet<Constant>
non-null; result set to add to
result
,
RegisterSpec
null-ok; register spec to add
spec
)

Helper for getAllConstants which adds all the info for a single RegisterSpec.

private void
assignAddresses()

Helper for assignAddressesAndFixBranches, which assigns an address to each instruction, in order.

private void
assignAddressesAndFixBranches()

Helper for finishProcessingAndGetList, which assigns addresses to each instruction, possibly rewriting branches to fix ones that wouldn't otherwise be able to reach their targets.

public void
assignIndices(DalvCode.AssignIndicesCallback
non-null; callback object
callback
)

Assigns indices in all instructions that need them, using the given callback to perform lookups.

private static void
assignIndices(CstInsn
non-null; the instruction
insn
,
DalvCode.AssignIndicesCallback
non-null; the callback
callback
)

Helper for assignIndices which does assignment for one instruction.

private int

Returns:

>= 0; the count of reserved registers
calculateReservedCount
(Dop[]
non-null; array of per-instruction opcode selections
opcodes
)

Helper for reserveRegisters, which does one pass over the instructions, calculating the number of registers that need to be reserved.

private Dop

Returns:

non-null; the opcode that fits
findExpandedOpcodeForInsn
(DalvInsn
non-null; the instruction in question
insn
)

Finds the proper opcode for the given instruction, ignoring register constraints.

private Dop

Returns:

null-ok; a possibly-different opcode; either a non-null good fit or null to indicate that no simple opcode fits
findOpcodeForInsn
(DalvInsn
non-null; the instruction in question
insn
,
Dop
null-ok; the current guess as to the best opcode; null means that no simple opcode fits
guess
)

Attempts to fit the given instruction into a specific opcode, returning the opcode whose format that the instruction fits into or null to indicate that the instruction will need to be expanded.

public DalvInsnList

Returns:

non-null; the output list
finishProcessingAndGetList
()

Does final processing on this instance and gets the output as a DalvInsnList.

private boolean

Returns:

whether any branches had to be fixed
fixBranches
()

Helper for assignAddressesAndFixBranches, which checks the branch target size requirement of each branch instruction to make sure it fits.

public HashSet<Constant>

Returns:

non-null; the set of constants
getAllConstants
()

Returns the set of all constants referred to by instructions added to this instance.

public boolean

Returns:

whether this instance has any local variable information
hasAnyLocalInfo
()

Returns whether this instance has any local variable information.

public boolean

Returns:

whether any of the instructions added to this instance come with position info
hasAnyPositionInfo
()

Returns whether any of the instructions added to this instance come with position info.

private static boolean

Returns:

true iff the instruction refers to any named locals
hasLocalInfo
(DalvInsn
non-null; instruction to scrutinize
insn
)

Helper for add which scrutinizes a single instruction for local variable information.

private static boolean

Returns:

true iff the spec refers to any named locals
hasLocalInfo
(RegisterSpec
non-null; spec to scrutinize
spec
)

Helper for hasAnyLocalInfo which scrutinizes a single register spec.

public void
insert(int
>= 0; what index to insert at
at
,
DalvInsn
non-null; the instruction to insert
insn
)

Inserts an instruction in the output at the given offset.

private Dop[]

Returns:

non-null; the array of opcodes
makeOpcodesArray
()

Helper for finishProcessingAndGetList, which extracts the opcode out of each instruction into a separate array, to be further manipulated as things progress.

private void
massageInstructions(Dop[]
non-null; array of per-instruction opcode selections
opcodes
)

Helper for finishProcessingAndGetList, which goes through each instruction in the output, making sure its opcode can accomodate its arguments.

private ArrayList<DalvInsn>

Returns:

non-null; the replacement list
performExpansion
(Dop[]
non-null; array of per-instruction opcode selections
opcodes
)

Helper for massageInstructions, which constructs a replacement list, where each {link DalvInsn} instance that couldn't be represented simply (due to register representation problems) is expanded into a series of instances that together perform the proper function.

private void
reserveRegisters(Dop[]
non-null; array of per-instruction opcode selections
opcodes
)

Helper for finishProcessingAndGetList, which figures out how many reserved registers are required and then reserving them.

public void
reverseBranch(int
how many instructions back to find the branch; 0 is the most recently added instruction, 1 is the instruction before that, etc.
which
,
CodeAddress
non-null; the new target for the reversed branch
newTarget
)

Reverses a branch which is buried a given number of instructions backward in the output.

private void
updateInfo(DalvInsn
non-null; an instruction that was just introduced
insn
)

Helper for add and insert, which updates the position and local info flags.

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

dexOptionsback to summary
private final DexOptions dexOptions

non-null; options for dex output

hasAnyLocalInfoback to summary
private boolean hasAnyLocalInfo

whether any instruction has local variable info

hasAnyPositionInfoback to summary
private boolean hasAnyPositionInfo

whether any instruction has position info

insnsback to summary
private ArrayList<DalvInsn> insns

non-null; the list of instructions, per se

reservedCountback to summary
private int reservedCount

>= 0; the count of reserved registers (low-numbered registers used when expanding instructions that can't be represented simply); becomes valid after a call to massageInstructions

unreservedRegCountback to summary
private final int unreservedRegCount

>= 0; register count for the method, not including any extra "reserved" registers needed to translate "difficult" instructions

Constructor Detail

OutputFinisherback to summary
public OutputFinisher(DexOptions dexOptions, int initialCapacity, int regCount)

Constructs an instance. It initially contains no instructions.

Parameters
dexOptions:DexOptions

non-null; options for dex output

initialCapacity:int

>= 0; initial capacity of the instructions list

regCount:int

>= 0; register count for the method

Method Detail

addback to summary
public void add(DalvInsn insn)

Adds an instruction to the output.

Parameters
insn:DalvInsn

non-null; the instruction to add

addConstantsback to summary
private static void addConstants(HashSet<Constant> result, DalvInsn insn)

Helper for getAllConstants which adds all the info for a single instruction.

Parameters
result:HashSet<Constant>

non-null; result set to add to

insn:DalvInsn

non-null; instruction to scrutinize

addConstantsback to summary
private static void addConstants(HashSet<Constant> result, RegisterSpec spec)

Helper for getAllConstants which adds all the info for a single RegisterSpec.

Parameters
result:HashSet<Constant>

non-null; result set to add to

spec:RegisterSpec

null-ok; register spec to add

assignAddressesback to summary
private void assignAddresses()

Helper for assignAddressesAndFixBranches, which assigns an address to each instruction, in order.

assignAddressesAndFixBranchesback to summary
private void assignAddressesAndFixBranches()

Helper for finishProcessingAndGetList, which assigns addresses to each instruction, possibly rewriting branches to fix ones that wouldn't otherwise be able to reach their targets.

assignIndicesback to summary
public void assignIndices(DalvCode.AssignIndicesCallback callback)

Assigns indices in all instructions that need them, using the given callback to perform lookups. This should be called before calling finishProcessingAndGetList.

Parameters
callback:DalvCode.AssignIndicesCallback

non-null; callback object

assignIndicesback to summary
private static void assignIndices(CstInsn insn, DalvCode.AssignIndicesCallback callback)

Helper for assignIndices which does assignment for one instruction.

Parameters
insn:CstInsn

non-null; the instruction

callback:DalvCode.AssignIndicesCallback

non-null; the callback

calculateReservedCountback to summary
private int calculateReservedCount(Dop[] opcodes)

Helper for reserveRegisters, which does one pass over the instructions, calculating the number of registers that need to be reserved. It also updates the opcodes list to help avoid extra work in future register reservation passes.

Parameters
opcodes:Dop[]

non-null; array of per-instruction opcode selections

Returns:int

>= 0; the count of reserved registers

findExpandedOpcodeForInsnback to summary
private Dop findExpandedOpcodeForInsn(DalvInsn insn)

Finds the proper opcode for the given instruction, ignoring register constraints.

Parameters
insn:DalvInsn

non-null; the instruction in question

Returns:Dop

non-null; the opcode that fits

findOpcodeForInsnback to summary
private Dop findOpcodeForInsn(DalvInsn insn, Dop guess)

Attempts to fit the given instruction into a specific opcode, returning the opcode whose format that the instruction fits into or null to indicate that the instruction will need to be expanded. This fitting process starts with the given opcode as a first "best guess" and then pessimizes from there if necessary.

Parameters
insn:DalvInsn

non-null; the instruction in question

guess:Dop

null-ok; the current guess as to the best opcode; null means that no simple opcode fits

Returns:Dop

null-ok; a possibly-different opcode; either a non-null good fit or null to indicate that no simple opcode fits

finishProcessingAndGetListback to summary
public DalvInsnList finishProcessingAndGetList()

Does final processing on this instance and gets the output as a DalvInsnList. Final processing consists of:

  • optionally renumbering registers (to make room as needed for expanded instructions)
  • picking a final opcode for each instruction
  • rewriting instructions, because of register number, constant pool index, or branch target size issues
  • assigning final addresses

Note

This method may only be called once per instance of this class.

Returns:DalvInsnList

non-null; the output list

Exceptions
UnsupportedOperationException:
if this method has already been called
fixBranchesback to summary
private boolean fixBranches()

Helper for assignAddressesAndFixBranches, which checks the branch target size requirement of each branch instruction to make sure it fits. For instructions that don't fit, this rewrites them to use a goto of some sort. In the case of a conditional branch that doesn't fit, the sense of the test is reversed in order to branch around a goto to the original target.

Returns:boolean

whether any branches had to be fixed

getAllConstantsback to summary
public HashSet<Constant> getAllConstants()

Returns the set of all constants referred to by instructions added to this instance.

Returns:HashSet<Constant>

non-null; the set of constants

hasAnyLocalInfoback to summary
public boolean hasAnyLocalInfo()

Returns whether this instance has any local variable information.

Returns:boolean

whether this instance has any local variable information

hasAnyPositionInfoback to summary
public boolean hasAnyPositionInfo()

Returns whether any of the instructions added to this instance come with position info.

Returns:boolean

whether any of the instructions added to this instance come with position info

hasLocalInfoback to summary
private static boolean hasLocalInfo(DalvInsn insn)

Helper for add which scrutinizes a single instruction for local variable information.

Parameters
insn:DalvInsn

non-null; instruction to scrutinize

Returns:boolean

true iff the instruction refers to any named locals

hasLocalInfoback to summary
private static boolean hasLocalInfo(RegisterSpec spec)

Helper for hasAnyLocalInfo which scrutinizes a single register spec.

Parameters
spec:RegisterSpec

non-null; spec to scrutinize

Returns:boolean

true iff the spec refers to any named locals

insertback to summary
public void insert(int at, DalvInsn insn)

Inserts an instruction in the output at the given offset.

Parameters
at:int

>= 0; what index to insert at

insn:DalvInsn

non-null; the instruction to insert

makeOpcodesArrayback to summary
private Dop[] makeOpcodesArray()

Helper for finishProcessingAndGetList, which extracts the opcode out of each instruction into a separate array, to be further manipulated as things progress.

Returns:Dop[]

non-null; the array of opcodes

massageInstructionsback to summary
private void massageInstructions(Dop[] opcodes)

Helper for finishProcessingAndGetList, which goes through each instruction in the output, making sure its opcode can accomodate its arguments. In cases where the opcode is unable to do so, this replaces the instruction with a larger instruction with identical semantics that will work.

This method may also reserve a number of low-numbered registers, renumbering the instructions' original registers, in order to have register space available in which to move very-high registers when expanding instructions into multi-instruction sequences. This expansion is done when no simple instruction format can be found for a given instruction that is able to accomodate that instruction's registers.

This method ignores issues of branch target size, since final addresses aren't known at the point that this method is called.

Parameters
opcodes:Dop[]

non-null; array of per-instruction opcode selections

performExpansionback to summary
private ArrayList<DalvInsn> performExpansion(Dop[] opcodes)

Helper for massageInstructions, which constructs a replacement list, where each {link DalvInsn} instance that couldn't be represented simply (due to register representation problems) is expanded into a series of instances that together perform the proper function.

Parameters
opcodes:Dop[]

non-null; array of per-instruction opcode selections

Returns:ArrayList<DalvInsn>

non-null; the replacement list

reserveRegistersback to summary
private void reserveRegisters(Dop[] opcodes)

Helper for finishProcessingAndGetList, which figures out how many reserved registers are required and then reserving them. It also updates the given opcodes array so as to avoid extra work when constructing the massaged instruction list.

Parameters
opcodes:Dop[]

non-null; array of per-instruction opcode selections

reverseBranchback to summary
public void reverseBranch(int which, CodeAddress newTarget)

Reverses a branch which is buried a given number of instructions backward in the output. It is illegal to call this unless the indicated instruction really is a reversible branch.

Parameters
which:int

how many instructions back to find the branch; 0 is the most recently added instruction, 1 is the instruction before that, etc.

newTarget:CodeAddress

non-null; the new target for the reversed branch

updateInfoback to summary
private void updateInfo(DalvInsn insn)

Helper for add and insert, which updates the position and local info flags.

Parameters
insn:DalvInsn

non-null; an instruction that was just introduced