Package org.jnode.vm.compiler.ir

Source Code of org.jnode.vm.compiler.ir.IRBasicBlockFinder

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm.compiler.ir;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import org.jnode.vm.bytecode.BytecodeFlags;
import org.jnode.vm.bytecode.BytecodeVisitorSupport;
import org.jnode.vm.classmgr.VmByteCode;
import org.jnode.vm.classmgr.VmInterpretedExceptionHandler;
import org.jnode.vm.classmgr.VmMethod;

/**
* @author Madhu Siddalingaiah
*/
public class IRBasicBlockFinder<T> extends BytecodeVisitorSupport implements Comparator<IRBasicBlock> {
    private boolean nextIsStartOfBB;

    private IRBasicBlock currentBlock;

    private byte[] opcodeFlags;
    private byte[] branchFlags;

    private final ArrayList<IRBasicBlock<T>> blocks = new ArrayList<IRBasicBlock<T>>();
    private final HashMap<Integer, Integer> branchTargets = new HashMap<Integer, Integer>();
    private VmByteCode byteCode;
    private static final byte CONDITIONAL_BRANCH = 1;
    private static final byte UNCONDITIONAL_BRANCH = 2;

    /**
     * Create all determined basic blocks
     *
     * @return the blocks.
     */
    public IRBasicBlock<T>[] createBasicBlocks() {
        // Sort the blocks on start PC
        Collections.sort(blocks, this);
        // Create the array
        final IRBasicBlock<T>[] list = (IRBasicBlock<T>[]) blocks.toArray(new IRBasicBlock[blocks.size()]);
        // Set the EndPC's and flags
        final byte[] opcodeFlags = this.opcodeFlags;
        final byte[] branchFlags = this.branchFlags;
        final int len = opcodeFlags.length;
        int bbIndex = 0;
        for (int i = 0; i < len; i++) {
            if (isStartOfBB(i)) {
                final int start = i;
                // Find the end of the BB
                boolean nextIsSuccessor = true;
                if ((branchFlags[i] & UNCONDITIONAL_BRANCH) != 0) {
                    nextIsSuccessor = false;
                }
                i++;
                while ((i < len) && (!isStartOfBB(i))) {
                    if ((branchFlags[i] & UNCONDITIONAL_BRANCH) != 0) {
                        nextIsSuccessor = false;
                    }
                    i++;
                }
                // the BB
                final IRBasicBlock<T> bb = list[bbIndex++];
                if (nextIsSuccessor && bbIndex < list.length) {
                    bb.addSuccessor(list[bbIndex]);
                }
                if (bb.getStartPC() != start) {
                    throw new AssertionError("bb.getStartPC() != start");
                }
                bb.setEndPC(i);
                bb.setStartOfExceptionHandler(isStartOfException(start));
                i--;
            }
        }
        // TODO this is O(n^2), but it works...
        for (Map.Entry<Integer, Integer> entry : branchTargets.entrySet()) {
            final int from = entry.getKey();
            final int to = entry.getValue();
            IRBasicBlock<T> pred = findBB(list, from);
            IRBasicBlock<T> succ = findBB(list, to);
            if (pred == null || succ == null) {
                throw new AssertionError("unable to find BB!");
            }
            pred.addSuccessor(succ);
        }
        if (bbIndex != list.length) {
            throw new AssertionError("bbIndex != list.length");
        }
        return list;
    }

    private IRBasicBlock<T> findBB(IRBasicBlock<T>[] blocks, int address) {
        for (IRBasicBlock<T> b : blocks) {
            if (b.contains(address)) {
                return b;
            }
        }
        return null;
    }

    public void startMethod(VmMethod method) {
        final VmByteCode bc = method.getBytecode();
        byteCode = bc;
        final int length = bc.getLength();
        opcodeFlags = new byte[length];
        branchFlags = new byte[length];

        // The first instruction is always the start of a BB.
        this.currentBlock = startBB(0);
        currentBlock.setStackOffset(bc.getNoLocals());
        // The exception handler also start a basic block
        for (int i = 0; i < bc.getNoExceptionHandlers(); i++) {
            VmInterpretedExceptionHandler eh = bc.getExceptionHandler(i);
            IRBasicBlock tryBlock = startTryBlock(eh.getStartPC());
            IRBasicBlock endTryBlock = startTryBlockEnd(eh.getEndPC());
            IRBasicBlock catchBlock = startException(eh.getHandlerPC());
        }
    }

    public void endMethod() {
        VmByteCode bc = byteCode;
        // TODO add catch blocks to try successors
        for (int i = 0; i < bc.getNoExceptionHandlers(); i++) {
            VmInterpretedExceptionHandler eh = bc.getExceptionHandler(i);
        }
    }

    public void visit_ifeq(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_ifne(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_iflt(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_ifge(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_ifgt(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_ifle(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_if_icmpeq(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_if_icmpne(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_if_icmplt(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_if_icmpge(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_if_icmpgt(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_if_icmple(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_if_acmpeq(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_if_acmpne(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_goto(int address) {
        addBranch(address, UNCONDITIONAL_BRANCH);
    }

    public void visit_jsr(int address) {
        // TODO Not sure about this, the next block I believe it NOT a
        // direct successor. This will have to be tested.
        //addBranch(address);
    }

    public void visit_tableswitch(int defValue, int lowValue, int highValue, int[] addresses) {
        for (int address : addresses) {
            // Next block could be successor, e.g. switch could fall through
            addBranch(address, CONDITIONAL_BRANCH);
        }
        // Same for default case
        addBranch(defValue, CONDITIONAL_BRANCH);
    }

    public void visit_lookupswitch(int defValue, int[] matchValues, int[] addresses) {
        for (int address : addresses) {
            // Next block could be successor, e.g. switch could fall through
            addBranch(address, CONDITIONAL_BRANCH);
        }
        // Same for default case
        addBranch(defValue, CONDITIONAL_BRANCH);
    }

    public void visit_ifnull(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_ifnonnull(int address) {
        addBranch(address, CONDITIONAL_BRANCH);
    }

    public void visit_athrow() {
        endBB(UNCONDITIONAL_BRANCH);
    }

    public void visit_areturn() {
        endBB(UNCONDITIONAL_BRANCH);
    }

    public void visit_dreturn() {
        endBB(UNCONDITIONAL_BRANCH);
    }

    public void visit_freturn() {
        endBB(UNCONDITIONAL_BRANCH);
    }

    public void visit_ireturn() {
        endBB(UNCONDITIONAL_BRANCH);
    }

    public void visit_lreturn() {
        endBB(UNCONDITIONAL_BRANCH);
    }

    public void visit_ret(int index) {
        // Not sure about this either, this needs testing
        endBB(UNCONDITIONAL_BRANCH);
    }

    public void visit_return() {
        endBB(UNCONDITIONAL_BRANCH);
    }

    /**
     * Add branching information (to the given target) to the basic blocks information.
     *
     * @param target
     */
    private final void addBranch(int target, byte flags) {
        IRBasicBlock pred = this.currentBlock;
        IRBasicBlock succ = startBB(target);
        branchTargets.put(getInstructionAddress(), target);
        endBB(flags);
    }

    /**
     * Mark the start of a basic block
     *
     * @param address
     */
    private final IRBasicBlock<T> startBB(int address) {
        IRBasicBlock<T> next = null;
        if ((opcodeFlags[address] & BytecodeFlags.F_START_OF_BASICBLOCK) == 0) {
            opcodeFlags[address] |= BytecodeFlags.F_START_OF_BASICBLOCK;
            next = new IRBasicBlock<T>(address);
            blocks.add(next);
        } else {
            for (IRBasicBlock<T> bb : blocks) {
                if (bb.getStartPC() == address) {
                    next = bb;
                    break;
                }
            }
        }
        return next;
    }

    /**
     * Mark the end of a basic block
     */
    private final void endBB(byte flags) {
        nextIsStartOfBB = true;
        int address = getInstructionAddress();
        branchFlags[address] |= flags;
    }

    public void startInstruction(int address) {
        super.startInstruction(address);
        opcodeFlags[address] |= BytecodeFlags.F_START_OF_INSTRUCTION;
        if (nextIsStartOfBB || isStartOfBB(address)) {
            this.currentBlock = startBB(address);
            nextIsStartOfBB = false;
        }
    }

    private final boolean isStartOfBB(int address) {
        return ((opcodeFlags[address] & BytecodeFlags.F_START_OF_BASICBLOCK) != 0);
    }

    private final boolean isStartOfException(int address) {
        return ((opcodeFlags[address] & BytecodeFlags.F_START_OF_EXCEPTIONHANDLER) != 0);
    }

    /**
     * Mark the start of a exception handler
     *
     * @param address
     */
    private final IRBasicBlock startException(int address) {
        opcodeFlags[address] |= BytecodeFlags.F_START_OF_EXCEPTIONHANDLER;
        return startBB(address);
    }

    /**
     * Mark the start of a try-catch block
     *
     * @param address
     */
    private final IRBasicBlock startTryBlock(int address) {
        opcodeFlags[address] |= BytecodeFlags.F_START_OF_TRYBLOCK;
        return startBB(address);
    }

    /**
     * Mark the end of a try-catch block
     *
     * @param address
     */
    private final IRBasicBlock startTryBlockEnd(int address) {
        opcodeFlags[address] |= BytecodeFlags.F_START_OF_TRYBLOCKEND;
        return startBB(address);
    }

    public int compare(IRBasicBlock o1, IRBasicBlock o2) {
        final int sp1 = ((IRBasicBlock) o1).getStartPC();
        final int sp2 = ((IRBasicBlock) o2).getStartPC();
        return sp1 - sp2;
    }
}
TOP

Related Classes of org.jnode.vm.compiler.ir.IRBasicBlockFinder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.