StdCatchBuilderpublic final class StdCatchBuilder extends Object implements CatchBuilderConstructor of {@link CatchTable} instances from {@link RopMethod}
and associated data. |
Fields Summary |
---|
private static final int | MAX_CATCH_RANGEthe maximum range of a single catch handler, in code units | private final com.android.dx.rop.code.RopMethod | methodnon-null; method to build the list for | private final int[] | ordernon-null; block output order | private final BlockAddresses | addressesnon-null; address objects for each block |
Constructors Summary |
---|
public StdCatchBuilder(com.android.dx.rop.code.RopMethod method, int[] order, BlockAddresses addresses)Constructs an instance. It merely holds onto its parameters for
a subsequent call to {@link #build}.
if (method == null) {
throw new NullPointerException("method == null");
}
if (order == null) {
throw new NullPointerException("order == null");
}
if (addresses == null) {
throw new NullPointerException("addresses == null");
}
this.method = method;
this.order = order;
this.addresses = addresses;
|
Methods Summary |
---|
public CatchTable | build(){@inheritDoc}
return build(method, order, addresses);
| public static CatchTable | build(com.android.dx.rop.code.RopMethod method, int[] order, BlockAddresses addresses)Builds and returns the catch table for a given method.
int len = order.length;
BasicBlockList blocks = method.getBlocks();
ArrayList<CatchTable.Entry> resultList =
new ArrayList<CatchTable.Entry>(len);
CatchHandlerList currentHandlers = CatchHandlerList.EMPTY;
BasicBlock currentStartBlock = null;
BasicBlock currentEndBlock = null;
for (int i = 0; i < len; i++) {
BasicBlock block = blocks.labelToBlock(order[i]);
if (!block.canThrow()) {
/*
* There is no need to concern ourselves with the
* placement of blocks that can't throw with respect
* to the blocks that *can* throw.
*/
continue;
}
CatchHandlerList handlers = handlersFor(block, addresses);
if (currentHandlers.size() == 0) {
// This is the start of a new catch range.
currentStartBlock = block;
currentEndBlock = block;
currentHandlers = handlers;
continue;
}
if (currentHandlers.equals(handlers)
&& rangeIsValid(currentStartBlock, block, addresses)) {
/*
* The block we are looking at now has the same handlers
* as the block that started the currently open catch
* range, and adding it to the currently open range won't
* cause it to be too long.
*/
currentEndBlock = block;
continue;
}
/*
* The block we are looking at now has incompatible handlers,
* so we need to finish off the last entry and start a new
* one. Note: We only emit an entry if it has associated handlers.
*/
if (currentHandlers.size() != 0) {
CatchTable.Entry entry =
makeEntry(currentStartBlock, currentEndBlock,
currentHandlers, addresses);
resultList.add(entry);
}
currentStartBlock = block;
currentEndBlock = block;
currentHandlers = handlers;
}
if (currentHandlers.size() != 0) {
// Emit an entry for the range that was left hanging.
CatchTable.Entry entry =
makeEntry(currentStartBlock, currentEndBlock,
currentHandlers, addresses);
resultList.add(entry);
}
// Construct the final result.
int resultSz = resultList.size();
if (resultSz == 0) {
return CatchTable.EMPTY;
}
CatchTable result = new CatchTable(resultSz);
for (int i = 0; i < resultSz; i++) {
result.set(i, resultList.get(i));
}
result.setImmutable();
return result;
| public java.util.HashSet | getCatchTypes(){@inheritDoc}
HashSet<Type> result = new HashSet<Type>(20);
BasicBlockList blocks = method.getBlocks();
int size = blocks.size();
for (int i = 0; i < size; i++) {
BasicBlock block = blocks.get(i);
TypeList catches = block.getLastInsn().getCatches();
int catchSize = catches.size();
for (int j = 0; j < catchSize; j++) {
result.add(catches.getType(j));
}
}
return result;
| private static CatchHandlerList | handlersFor(com.android.dx.rop.code.BasicBlock block, BlockAddresses addresses)Makes the {@link CatchHandlerList} for the given basic block.
IntList successors = block.getSuccessors();
int succSize = successors.size();
int primary = block.getPrimarySuccessor();
TypeList catches = block.getLastInsn().getCatches();
int catchSize = catches.size();
if (catchSize == 0) {
return CatchHandlerList.EMPTY;
}
if (((primary == -1) && (succSize != catchSize))
|| ((primary != -1) &&
((succSize != (catchSize + 1))
|| (primary != successors.get(catchSize))))) {
/*
* Blocks that throw are supposed to list their primary
* successor -- if any -- last in the successors list, but
* that constraint appears to be violated here.
*/
throw new RuntimeException(
"shouldn't happen: weird successors list");
}
/*
* Reduce the effective catchSize if we spot a catch-all that
* isn't at the end.
*/
for (int i = 0; i < catchSize; i++) {
Type type = catches.getType(i);
if (type.equals(Type.OBJECT)) {
catchSize = i + 1;
break;
}
}
CatchHandlerList result = new CatchHandlerList(catchSize);
for (int i = 0; i < catchSize; i++) {
CstType oneType = new CstType(catches.getType(i));
CodeAddress oneHandler = addresses.getStart(successors.get(i));
result.set(i, oneType, oneHandler.getAddress());
}
result.setImmutable();
return result;
| public boolean | hasAnyCatches(){@inheritDoc}
HashSet<Type> result = new HashSet<Type>(20);
BasicBlockList blocks = method.getBlocks();
int size = blocks.size();
for (int i = 0; i < size; i++) {
BasicBlock block = blocks.get(i);
TypeList catches = block.getLastInsn().getCatches();
if (catches.size() != 0) {
return true;
}
}
return false;
| private static CatchTable.Entry | makeEntry(com.android.dx.rop.code.BasicBlock start, com.android.dx.rop.code.BasicBlock end, CatchHandlerList handlers, BlockAddresses addresses)Makes a {@link CatchTable#Entry} for the given block range and
handlers.
/*
* We start at the *last* instruction of the start block, since
* that's the instruction that can throw...
*/
CodeAddress startAddress = addresses.getLast(start);
// ...And we end *after* the last instruction of the end block.
CodeAddress endAddress = addresses.getEnd(end);
return new CatchTable.Entry(startAddress.getAddress(),
endAddress.getAddress(), handlers);
| private static boolean | rangeIsValid(com.android.dx.rop.code.BasicBlock start, com.android.dx.rop.code.BasicBlock end, BlockAddresses addresses)Gets whether the address range for the given two blocks is valid
for a catch handler. This is true as long as the covered range is
under 65536 code units.
if (start == null) {
throw new NullPointerException("start == null");
}
if (end == null) {
throw new NullPointerException("end == null");
}
// See above about selection of instructions.
int startAddress = addresses.getLast(start).getAddress();
int endAddress = addresses.getEnd(end).getAddress();
return (endAddress - startAddress) <= MAX_CATCH_RANGE;
|
|