Kilimソース分析の3つーー編入の構造/合併BaicBlock
13652 ワード
前のページでは、編入判定可能なコードを分析し、編入部分の構造/統合BaicBlockを分析し続けます。
まず分析方法kilim.analys.MethodFlow.analze()に含まれる機能を見てみます。
asmフレームを分析した他のLabel:(全部何を含みますか?)
まず分析方法kilim.analys.MethodFlow.analze()に含まれる機能を見てみます。
//
public void analyze() throws KilimException {
buildBasicBlocks();// BasicBlock, ?
if (basicBlocks.size() == 0) return;
consolidateBasicBlocks();//
assignCatchHandlers();// tryCatchBlocks Handler, handler , handler, tryCatch catch bb ;tryCatchBlock pos bb , bb start end pos ?consolidate ?
inlineSubroutines();// 1.5 jsr ;finally pausable ;finally pausable jsr/ret goto , 1.5 , try/catch
doLiveVarAnalysis();//
dataFlow();//
this.labelToBBMap = null; // we don't need this mapping anymore
}
buildBaic Block方法と呼び出しに関する方法の実現ロジックを見てください。 // BasicBlock
void buildBasicBlocks() {
// preparatory phase
int numInstructions = instructions.size();
basicBlocks = new BBList();//Basic Block
// Note: i modified within the loop
for (int i = 0; i < numInstructions; i++) {
Label l = getOrCreateLabelAtPos(i);// Label, i ,
BasicBlock bb = getOrCreateBasicBlock(l);// Label BasicBlock
i = bb.initialize(i); // i now points to the last instruction in bb. bb.initialize(i) ,i
basicBlocks.add(bb);// bb
}
}
Label getOrCreateLabelAtPos(int pos) {
Label ret = null;
if (pos < posToLabelMap.size()) {
ret = posToLabelMap.get(pos);// List, Map
}
if (ret == null) {
ret = new Label();
setLabel(pos, ret);// pos Label
}
return ret;
}
void setLabel(int pos, Label l) {
// posToLabelMap pos - posToLabelMap.size() + 1 null, , null Label
for (int i = pos - posToLabelMap.size() + 1; i >= 0; i--) {
//pad with nulls ala perl
posToLabelMap.add(null);
}
assert posToLabelMap.get(pos) == null;
posToLabelMap.set(pos, l);// pos Label
labelToPosMap.put(l, pos);//Label
}
BaicBlockのinitializeを重点的に分析します。分析の前に二つの概念を紹介します。Baic Blockは一つのコマンドセットです。これらのコマンドセットは一つのノードとも言われています。順序通りに実行しなければならない命令群です。中にはジャンプがありません。命令が順序に従って実行され、現在のノードの最後の命令が実行され、次に実行される次のノードの第1の命令との間に物理的に隣接している場合、次のノードは現在のノードのフォロワーである。一つのブロックからジャンプまたは非ジャンプ命令によって直接に到達できるノードは、現在のノードの後継ノードsuccess orと呼ばれ、現在のノードも後継ノードと呼ばれる前駆ノードpredeestorである。 /**
* Absorb as many instructions until the next label or the next transfer of
* control instruction. In the first pass we may end up creating many many
* BBs because there may be a lot of non-target labels (esp. when debug
* information is available). The constraints are as follows:
* , 。 pass, bbs, label( )
* 1. A transfer of control instruction must be the last instruction. It
* may also be the first (and only) instruction. BasicBlock
* 2. A labeled instruction must be the first instruction in a BB. It
* may optionally be the last (and only) instruction. BasicBlock
* 3. A pausable method is treated like a labeled instruction, and is
* given a label if there isn't one already. Constraint 2 applies. Pausable
*/
@SuppressWarnings("unchecked")
int initialize(int pos) {
AbstractInsnNode ain;
startPos = pos;
BasicBlock bb;
boolean endOfBB = false;
boolean hasFollower = true;//
int size = flow.instructions.size();
for (; pos < size; pos++) {// ,
if (pos > startPos && flow.getLabelAt(pos) != null) {// Label
pos--;//
hasFollower = true;//
endOfBB = true;//BasicBlock
break;
}
ain = getInstruction(pos);//
int opcode = ain.getOpcode();//
switch (opcode) {
case ALOAD:
case ILOAD:
case LLOAD:
case FLOAD:
case DLOAD:
usage.read(((VarInsnNode) ain).var);//load ,
break;
case ISTORE:
case LSTORE:
case FSTORE:
case DSTORE:
case ASTORE:
usage.write(((VarInsnNode) ain).var);//store ,
break;
case IINC:
int v = ((IincInsnNode)ain).var;
usage.read(v);
usage.write(v);//iinc
break;
case IFEQ:
case IFNE:
case IFLT:
case IFGE:
case IFGT:
case IFLE:
case IFNULL:
case IFNONNULL:
case IF_ICMPEQ:
case IF_ICMPNE:
case IF_ICMPLT:
case IF_ICMPGE:
case IF_ICMPGT:
case IF_ICMPLE:
case IF_ACMPEQ:
case IF_ACMPNE:
case JSR:
case GOTO://if 、jsr、goto
Label l = ((JumpInsnNode) ain).label;// label
bb = flow.getOrCreateBasicBlock(l);// Label
if (opcode == JSR) {//jsr , IS_SUBROUTINE
bb.setFlag(IS_SUBROUTINE);
hasFollower = false;// jsr bb follower
}
addSuccessor(bb);// BasicBlock , 1
if (opcode == GOTO) {// goto bb follower
hasFollower = false;
}
endOfBB = true;//bb
break;
case RET://finally
case IRETURN:
case LRETURN:
case FRETURN:
case DRETURN:
case ARETURN:
case RETURN:
case ATHROW:// return、throw bb follower, successor
hasFollower = false;
endOfBB = true;//bb
break;
case TABLESWITCH:
case LOOKUPSWITCH://switch
Label defaultLabel;//default label
List<Label> otherLabels;// default labels
if (opcode == TABLESWITCH) {
defaultLabel = ((TableSwitchInsnNode) ain).dflt;
otherLabels = ((TableSwitchInsnNode) ain).labels;
} else {
defaultLabel = ((LookupSwitchInsnNode) ain).dflt;
otherLabels = ((LookupSwitchInsnNode) ain).labels;
}
//switch Label bb
for (Iterator<Label> it = otherLabels.iterator(); it.hasNext();) {
l = (Label) it.next();
addSuccessor(flow.getOrCreateBasicBlock(l));
}
addSuccessor(flow.getOrCreateBasicBlock(defaultLabel));
endOfBB = true;
hasFollower = false;
break;
case INVOKEVIRTUAL:
case INVOKESTATIC:
case INVOKEINTERFACE:
case INVOKESPECIAL://
if (flow.isPausableMethodInsn((MethodInsnNode) ain)) {// Pausable
if (pos == startPos) {// , pausable
setFlag(PAUSABLE);
} else {// , , pausable bb
l = flow.getOrCreateLabelAtPos(pos);
bb = flow.getOrCreateBasicBlock(l);
bb.setFlag(PAUSABLE);
addSuccessor(bb);// bb
pos--; // don't consume this instruction
hasFollower = true;// follower
endOfBB = true;//
}
}
break;
default:
if (opcode >= 26 && opcode <= 45)
throw new IllegalStateException("instruction variants not expected here");
break;
}
if (endOfBB) break;
}
endPos = pos;
// follower, bb follower
if (hasFollower && (pos + 1) < flow.instructions.size()) {
// add the following basic block as a successor
Label l = flow.getOrCreateLabelAtPos(pos + 1);
bb = flow.getOrCreateBasicBlock(l);
addFollower(bb);//follower
}
return pos;
}
上記のコードを整理して、jsr、goto、return、throw、switchのようなタイプの命令で終了したBaic Blockにはフォローがありません。ifまたはpausable方法でコマンドを呼び出して終了したBaic Blocにはフォロワーがあり、if、jsr、goto、return、throw、switch、pausableメソッドでコマンドを呼び出す前の命令が終了したbbには後継ノードがあります。asmフレームを分析した他のLabel:(全部何を含みますか?)
/**
* In the first pass (buildBasicBlocks()), we create BBs whenever we
* encounter a label. We don't really know until we are done with that
* pass whether a label is the target of a branch instruction or it is
* there because of an exception handler. See coalesceWithFollowingBlock()
* for more detail. bb
*/
private void consolidateBasicBlocks() {
BBList newBBs = new BBList(basicBlocks.size());
int pos = 0;
for (BasicBlock bb: basicBlocks) {
if (!bb.hasFlag(COALESCED)) {
bb.coalesceTrivialFollowers();//
// The original bb's followers should have been marked as processed.
bb.setId(pos++);
newBBs.add(bb);
}
}
basicBlocks = newBBs;
assert checkNoBasicBlockLeftBehind();// bb ,
}
/**
* Blocks connected by an edge are candidates for coalescing if: <dl> <li>
* There is a single edge between the two and neither has any other edges.
* </li>
*
* <li> The edge connecting the two is not because of a GOTO. We only want
* those where one block falls into the other. The reason is that each block
* marks out a *contiguous* range of instructions. Most compilers would have
* gotten rid of this unnecessary jump anyway. </li>
*
* <li> The successor block doesn't begin with a method call that we are
* interested in (like pausable methods). This is a boundary we are
* interested in maintaining in subsequent processing. </li>
* label bb ?
* </dl>
*/
void coalesceTrivialFollowers() {
while (true) {
if (successors.size() == 1) {//
BasicBlock succ = successors.get(0);
if (succ.numPredecessors == 1 && lastInstruction() != GOTO && lastInstruction() != JSR
&& !succ.isPausable()) {// , goto/jsr, pausable
// successor can be merged
// absorb succesors and usage mask
this.successors = succ.successors;
this.follower = succ.follower;
this.usage.absorb(succ.usage);//usage
this.endPos = succ.endPos;
succ.setFlag(COALESCED);// coalesced
// mark succ so it doesn't get visited. This block's merk remains 0. We'll let the outer driver
// loop to revisit this block and its new successors
continue;
}
}
break;
}
}