Kilimソース分析の3つーー編入の構造/合併BaicBlock


前のページでは、編入判定可能なコードを分析し、編入部分の構造/統合BaicBlockを分析し続けます。
        まず分析方法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;
        }
    }