Package org.jnode.vm.bytecode

Source Code of org.jnode.vm.bytecode.DeadBlockFinder

/*
* $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.bytecode;

import java.util.TreeMap;
import org.jnode.bootlog.BootLogInstance;
import org.jnode.vm.JvmType;
import org.jnode.vm.classmgr.VmByteCode;
import org.jnode.vm.classmgr.VmInterpretedExceptionHandler;
import org.jnode.vm.classmgr.VmMethod;

/**
* Bytecode visitor, used to determine the start addresses of basic blocks.
*
* @author Levente S\u00e1ntha
*/
public class DeadBlockFinder extends BytecodeVisitorSupport implements BytecodeFlags {
    private static final boolean debug = false;
    private final TreeMap<Integer, BasicBlock> blocks = new TreeMap<Integer, BasicBlock>();
    private byte[] opcodeFlags;
    private boolean nextIsStartOfBB;
    private boolean nextFollowsTypeStack;
    private boolean nextIsRetTarget;
    private int curAddress;
    private BasicBlock current;

    /**
     * Create all determined basic blocks
     *
     * @return the basic blocks.
     */
    public BasicBlock[] createBasicBlocks() {
        // Create the array
        final BasicBlock[] list = blocks.values().toArray(new BasicBlock[blocks.size()]);
        // Set the EndPC's and flags
        final byte[] opcodeFlags = this.opcodeFlags;
        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
                i++;
                while ((i < len) && (!isStartOfBB(i))) {
                    i++;
                }
                // the BB
                final BasicBlock bb = list[bbIndex++];
                if (bb.getStartPC() != start) {
                    throw new AssertionError("bb.getStartPC() != start");
                }
                bb.setEndPC(i);
                bb.setStartOfExceptionHandler(isStartOfException(start));
                i--;
            }
        }
        if (bbIndex != list.length) {
            throw new AssertionError("bbIndex != list.length");
        }
        return list;
    }

    /**
     * Get the per-opcode bytecode flags.
     *
     * @return byte[]
     */
    public final byte[] getOpcodeFlags() {
        return opcodeFlags;
    }

    /**
     * @param method
     * @see BytecodeVisitor#startMethod(org.jnode.vm.classmgr.VmMethod)
     */
    public void startMethod(VmMethod method) {
        final VmByteCode bc = method.getBytecode();
        final int length = bc.getLength();
        opcodeFlags = new byte[length];
        // The first instruction is always the start of a BB.
        startBB(0, true);
        // The exception handler also start a basic block
        final TypeStack ehTStack = new TypeStack();
        ehTStack.push(JvmType.REFERENCE);
        for (int i = 0; i < bc.getNoExceptionHandlers(); i++) {
            VmInterpretedExceptionHandler eh = bc.getExceptionHandler(i);
            startTryBlock(eh.getStartPC());
            startTryBlockEnd(eh.getEndPC());
            startException(eh.getHandlerPC(), ehTStack);
        }
    }

    /**
     * @param address
     * @see BytecodeVisitor#startInstruction(int)
     */
    public void startInstruction(int address) {
        if (debug) {
            BootLogInstance.get().debug("#" + address);
        }
        curAddress = address;
        super.startInstruction(address);
        opcodeFlags[address] |= F_START_OF_INSTRUCTION;
        boolean next_is_rt = nextIsRetTarget;
        if (nextIsRetTarget) {
            opcodeFlags[address] |= F_RET_TARGET;
            nextIsRetTarget = false;
        }
        boolean next_is_bb = nextIsStartOfBB;
        if (nextIsStartOfBB) {
            if (debug) BootLogInstance.get().debug("\tnextIsStartOfBB\t" + nextFollowsTypeStack);
            startBB(address, nextFollowsTypeStack);
            nextIsStartOfBB = false;
            nextFollowsTypeStack = true;
        }
        if (isStartOfBB(address)) {
            if (!next_is_bb) {
                BasicBlock bb = blocks.get(address);
                bb.addEntryBlock(current);
                current = bb;
            } else {
                current = blocks.get(address);
            }

            if (next_is_rt) {
                current.setRetTarget(true);
            }

            if (debug) BootLogInstance.get().debug("\tcurrent\t" + current);
        }
        if (debug) {
            BootLogInstance.get().debug("#" + address);
        }
    }

    /**
     * Mark the start of a basic block
     *
     * @param address
     */
    private void startBB(int address, boolean setTypeStack) {
        if ((opcodeFlags[address] & F_START_OF_BASICBLOCK) == 0) {
            opcodeFlags[address] |= F_START_OF_BASICBLOCK;
            final BasicBlock bb = new BasicBlock(address);
            blocks.put(address, bb);
            if (setTypeStack) {
                bb.addEntryBlock(current);
            }
        } else if (setTypeStack) {
            final BasicBlock bb = blocks.get(address);
            // Add entry block
            bb.addEntryBlock(current);
        }
    }

    /**
     * Mark the end of a basic block
     */
    private void endBB(boolean nextFollowsTypeStack) {
        this.nextIsStartOfBB = true;
        this.nextFollowsTypeStack = nextFollowsTypeStack;
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_ifeq(int)
     */
    public void visit_ifeq(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_ifne(int)
     */
    public void visit_ifne(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_iflt(int)
     */
    public void visit_iflt(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_ifge(int)
     */
    public void visit_ifge(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_ifgt(int)
     */
    public void visit_ifgt(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_ifle(int)
     */
    public void visit_ifle(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_if_icmpeq(int)
     */
    public void visit_if_icmpeq(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_if_icmpne(int)
     */
    public void visit_if_icmpne(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_if_icmplt(int)
     */
    public void visit_if_icmplt(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_if_icmpge(int)
     */
    public void visit_if_icmpge(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_if_icmpgt(int)
     */
    public void visit_if_icmpgt(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_if_icmple(int)
     */
    public void visit_if_icmple(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_if_acmpeq(int)
     */
    public void visit_if_acmpeq(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_if_acmpne(int)
     */
    public void visit_if_acmpne(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_goto(int)
     */
    public void visit_goto(int address) {
        // No change
        addBranch(address, false);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_jsr(int)
     */
    public void visit_jsr(int address) {
        addBranch(address, false);
        nextIsRetTarget = true;
        condYieldPoint(address);
    }

    /**
     * @param defValue
     * @param lowValue
     * @param highValue
     * @param addresses
     * @see BytecodeVisitor#visit_tableswitch(int, int, int, int[])
     */
    public void visit_tableswitch(int defValue, int lowValue, int highValue, int[] addresses) {
        for (int address : addresses) {
            addBranch(address, true);
            condYieldPoint(address);
        }
        addBranch(defValue, false);
        condYieldPoint(defValue);
    }

    /**
     * @param defValue
     * @param matchValues
     * @param addresses
     * @see BytecodeVisitor#visit_lookupswitch(int, int[], int[])
     */
    public void visit_lookupswitch(int defValue, int[] matchValues, int[] addresses) {
        for (int address : addresses) {
            addBranch(address, true);
            condYieldPoint(address);
        }
        addBranch(defValue, false);
        condYieldPoint(defValue);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_ifnull(int)
     */
    public void visit_ifnull(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @param address
     * @see BytecodeVisitor#visit_ifnonnull(int)
     */
    public void visit_ifnonnull(int address) {
        addBranch(address, true);
        condYieldPoint(address);
    }

    /**
     * @see BytecodeVisitor#visit_athrow()
     */
    public void visit_athrow() {
        endBB(false);
        // Reference is actually pushed on the stack, but that is handled
        // by the startException blocks.
    }

    /**
     * @see BytecodeVisitor#visit_areturn()
     */
    public void visit_areturn() {
        endBB(false);
    }

    /**
     * @see BytecodeVisitor#visit_dreturn()
     */
    public void visit_dreturn() {
        endBB(false);
    }

    /**
     * @see BytecodeVisitor#visit_freturn()
     */
    public void visit_freturn() {
        endBB(false);
    }

    /**
     * @see BytecodeVisitor#visit_ireturn()
     */
    public void visit_ireturn() {
        if (debug) {
            BootLogInstance.get().debug("ireturn at " + curAddress);
        }
        endBB(false);
    }

    /**
     * @see BytecodeVisitor#visit_lreturn()
     */
    public void visit_lreturn() {
        endBB(false);
    }

    /**
     * @param index
     * @see BytecodeVisitor#visit_ret(int)
     */
    public void visit_ret(int index) {
        // No change
        endBB(false);
    }

    /**
     * @see BytecodeVisitor#visit_return()
     */
    public void visit_return() {
        // No change
        endBB(false);
    }

    /**
     * Add branching information (to the given target) to the basic blocks information.
     *
     * @param target
     */
    private void addBranch(int target, boolean conditional) {
        startBB(target, true);
        endBB(conditional);
    }

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

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

    /**
     * Mark the start of a exception handler
     *
     * @param address
     */
    private void startException(int address, TypeStack tstack) {
        opcodeFlags[address] |= F_START_OF_EXCEPTIONHANDLER;
        //System.out.println("startException: " + tstack);
        startBB(address, true);
    }

    /**
     * Mark the start of a try-catch block
     *
     * @param address
     */
    private void startTryBlock(int address) {
        opcodeFlags[address] |= F_START_OF_TRYBLOCK;
        //startBB(address, false, null);
    }

    /**
     * Mark the end of a try-catch block
     *
     * @param address
     */
    private void startTryBlockEnd(int address) {
        opcodeFlags[address] |= F_START_OF_TRYBLOCKEND;
        //startBB(address, false, null);
    }

    /**
     * Mark a conditional yieldpoint.
     */
    private void condYieldPoint(int target) {
        if (target < curAddress) {
            opcodeFlags[curAddress] |= F_YIELDPOINT;
        }
    }
}
TOP

Related Classes of org.jnode.vm.bytecode.DeadBlockFinder

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.