outputInstructions@RopTranslator.java
private void outputInstructions() {
BasicBlockList blocks = method.getBlocks();
int[] order = this.order;
int len = order.length;
// Process the blocks in output order.
for (int i = 0; i < len; i++) {
int nextI = i + 1;
int nextLabel = (nextI == order.length) ? -1 : order[nextI];//nextLabel为order[nextI]或-1(end了)
outputBlock(blocks.labelToBlock(order[i]), nextLabel);
}
}
根据order的顺序处理blocks
其中outputBlock@RopTranslator.java
private void outputBlock(BasicBlock block, int nextLabel) {
// Append the code address for this block.
CodeAddress startAddress = addresses.getStart(block);//getStart@BlockAddresses.java return starts[x];
//starts 从RopTranslator构造跟踪下去
output.add(startAddress);
// Append the local variable state for the block.
if (locals != null) {
RegisterSpecSet starts = locals.getStarts(block);
output.add(new LocalSnapshot(startAddress.getPosition(),
starts));
}
/*
* Choose and append an output instruction for each original
* instruction.
*/
translationVisitor.setBlock(block, addresses.getLast(block));//getLast 与上面的getStart相似
block.getInsns().forEach(translationVisitor);
// Insert the block end code address.
output.add(addresses.getEnd(block));
// Set up for end-of-block activities.
int succ = block.getPrimarySuccessor();
Insn lastInsn = block.getLastInsn();
/*
* Check for (and possibly correct for) a non-optimal choice of
* which block will get output next.
*/
if ((succ >= 0) && (succ != nextLabel)) {
/*
* The block has a "primary successor" and that primary
* successor isn't the next block to be output.
*/
Rop lastRop = lastInsn.getOpcode();
if ((lastRop.getBranchingness() == Rop.BRANCH_IF) &&
(block.getSecondarySuccessor() == nextLabel)) {
/*
* The block ends with an "if" of some sort, and its
* secondary successor (the "then") is in fact the
* next block to output. So, reverse the sense of
* the test, so that we can just emit the next block
* without an interstitial goto.
*/
output.reverseBranch(1, addresses.getStart(succ));
} else {
/*
* Our only recourse is to add a goto here to get the
* flow to be correct.
*/
TargetInsn insn =
new TargetInsn(Dops.GOTO, lastInsn.getPosition(),
RegisterSpecList.EMPTY,
addresses.getStart(succ));
output.add(insn);
}
}
}
其中,
translationVisitor.setBlock(block, addresses.getLast(block));//getLast 与上面的getStart相似
block.getInsns().forEach(translationVisitor);
forEach@IntList.java
public void forEach(Insn.Visitor visitor) {
int sz = size();
for (int i = 0; i < sz; i++) {
get(i).accept(visitor);
}
}
get(i)得到的应该是Insn的子类,可能是 PlainInsn / PlainCstInsn / ThrowingCstInsn / SwitchCstInsn / FillArrayDataInsn / ThrowingInsn
每个子类中overwrite了accept方法 ,基本的形式都是这种:
visitor.visitPlainInsn(this); // visitor.visitXxxxxInsn(this);
而传进来的visitor的类型为 TranslationVisitor ,各个子类会调用 TranslationVisitor中相应的visitXxxxx 方法
@RopTranslator.java
private class TranslationVisitor implements Insn.Visitor {。。。。当中
其中构造为:
public TranslationVisitor(OutputCollector output) {
this.output = output;
}
1.
visitPlainInsn
梳理以下几个主要数据:
Rop构造:
this.opcode = opcode;//RegOps中 57个
this.result = result;
this.sources = sources;
this.exceptions = exceptions;
this.branchingness = branchingness;//?????
this.isCallLike = isCallLike;
this.nickname = nickname;
Insn构造:这个都是子类构造调用父类构造Insn构造
this.opcode = opcode; //Rop类型
this.position = position;
this.result = result;
this.sources = sources;
1-1.
SourcePosition pos = insn.getPosition();
Dop opcode = RopToDop.dopFor(insn);
DalvInsn di;
(1)getPosition 其中几个函数里有比较多的PlainInsn构造: @RopperMachine.java @Ropper.java
(2)doFor@RopToDop.java
public static Dop dopFor(Insn insn) {
Rop rop = insn.getOpcode();
/*
* First, just try looking up the rop in the MAP of easy
* cases.
*/
Dop result = MAP.get(rop);
if (result != null) {
return result;
}
switch (rop.getOpcode()) {
case RegOps.MOVE_EXCEPTION: return Dops.MOVE_EXCEPTION;
case RegOps.INVOKE_STATIC: return Dops.INVOKE_STATIC;
case RegOps.INVOKE_VIRTUAL: return Dops.INVOKE_VIRTUAL;
case RegOps.INVOKE_SUPER: return Dops.INVOKE_SUPER;
case RegOps.INVOKE_DIRECT: return Dops.INVOKE_DIRECT;
case RegOps.INVOKE_INTERFACE: return Dops.INVOKE_INTERFACE;
case RegOps.NEW_ARRAY: return Dops.NEW_ARRAY;
case RegOps.FILLED_NEW_ARRAY: return Dops.FILLED_NEW_ARRAY;
case RegOps.FILL_ARRAY_DATA: return Dops.FILL_ARRAY_DATA;
case RegOps.MOVE_RESULT: {
RegisterSpec resultReg = insn.getResult();
if (resultReg == null) {
return Dops.NOP;
} else {
switch (resultReg.getBasicType()) {
case Type.BT_INT:
case Type.BT_FLOAT:
case Type.BT_BOOLEAN:
case Type.BT_BYTE:
case Type.BT_CHAR:
case Type.BT_SHORT:
return Dops.MOVE_RESULT;
case Type.BT_LONG:
case Type.BT_DOUBLE:
return Dops.MOVE_RESULT_WIDE;
case Type.BT_OBJECT:
return Dops.MOVE_RESULT_OBJECT;
default: {
throw new RuntimeException("Unexpected basic type");
}
}
}
}
case RegOps.GET_FIELD: {
CstFieldRef ref =
(CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
int basicType = ref.getBasicType();
switch (basicType) {
case Type.BT_BOOLEAN: return Dops.IGET_BOOLEAN;
case Type.BT_BYTE: return Dops.IGET_BYTE;
case Type.BT_CHAR: return Dops.IGET_CHAR;
case Type.BT_SHORT: return Dops.IGET_SHORT;
case Type.BT_INT: return Dops.IGET;
}
break;
}
case RegOps.PUT_FIELD: {
CstFieldRef ref =
(CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
int basicType = ref.getBasicType();
switch (basicType) {
case Type.BT_BOOLEAN: return Dops.IPUT_BOOLEAN;
case Type.BT_BYTE: return Dops.IPUT_BYTE;
case Type.BT_CHAR: return Dops.IPUT_CHAR;
case Type.BT_SHORT: return Dops.IPUT_SHORT;
case Type.BT_INT: return Dops.IPUT;
}
break;
}
case RegOps.GET_STATIC: {
CstFieldRef ref =
(CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
int basicType = ref.getBasicType();
switch (basicType) {
case Type.BT_BOOLEAN: return Dops.SGET_BOOLEAN;
case Type.BT_BYTE: return Dops.SGET_BYTE;
case Type.BT_CHAR: return Dops.SGET_CHAR;
case Type.BT_SHORT: return Dops.SGET_SHORT;
case Type.BT_INT: return Dops.SGET;
}
break;
}
case RegOps.PUT_STATIC: {
CstFieldRef ref =
(CstFieldRef) ((ThrowingCstInsn) insn).getConstant();
int basicType = ref.getBasicType();
switch (basicType) {
case Type.BT_BOOLEAN: return Dops.SPUT_BOOLEAN;
case Type.BT_BYTE: return Dops.SPUT_BYTE;
case Type.BT_CHAR: return Dops.SPUT_CHAR;
case Type.BT_SHORT: return Dops.SPUT_SHORT;
case Type.BT_INT: return Dops.SPUT;
}
break;
}
case RegOps.CONST: {
Constant cst = ((ThrowingCstInsn) insn).getConstant();
if (cst instanceof CstType) {
return Dops.CONST_CLASS;
} else if (cst instanceof CstString) {
return Dops.CONST_STRING;
}
break;
}
}
throw new RuntimeException("unknown rop: " + rop);
}
}
MAP.get中会看到其他平常的指令。
1-2
di = new SimpleInsn(opcode, pos, getRegs(insn));
可能会有几种构造:
visitPlainInsn中有两个构造 SimpleInsn和TargetInsn
会在一个switch中选择。
1-3
addOutput(di); //output.add(insn);
2.
visitPlainCstInsn
2-1
RegSpecList相关的东东
2-2
SimpleInsn构造及CstInsn
3.
visitSwitchInsn
3-1
successors 相关的
3-2
switchTargets codeAddress[ ] 相关的
3-3
SwitchData构造
TargetInsn构造
3-4
addOutputSuffix
4.
visitThrowingCstInsn
4-1
SimpleInsn
CstInsn
5.
visitThrowingInsn
SimpleInsn
6.
visitFillArrayDataInsn
ArrayData构造
TargetInsn
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
上面总共提到 SimpleInsn TargetInsn CstInsn 三个指令构造函数 SwitchData ArrayData 两个数据构造函数
SimpleInsn
super(opcode, position, registers); //FixedSizeInsn
TargetInsn
比SimpleInsn多了个 this.target = target;
CstInsn
比SimpleInsn多了
this.constant = constant;
this.index = -1;
this.classIndex = -1;