Search in sources :

Example 1 with JumpInsnNode

use of org.mvel2.asm.tree.JumpInsnNode in project mvel by mvel.

the class Analyzer method analyze.

/**
 * Analyzes the given method.
 *
 * @param owner
 *            the internal name of the class to which the method belongs.
 * @param m
 *            the method to be analyzed.
 * @return the symbolic state of the execution stack frame at each bytecode
 *         instruction of the method. The size of the returned array is
 *         equal to the number of instructions (and labels) of the method. A
 *         given frame is <tt>null</tt> if and only if the corresponding
 *         instruction cannot be reached (dead code).
 * @throws AnalyzerException
 *             if a problem occurs during the analysis.
 */
@SuppressWarnings("unchecked")
public Frame<V>[] analyze(final String owner, final MethodNode m) throws AnalyzerException {
    if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
        frames = (Frame<V>[]) new Frame<?>[0];
        return frames;
    }
    n = m.instructions.size();
    insns = m.instructions;
    handlers = (List<TryCatchBlockNode>[]) new List<?>[n];
    frames = (Frame<V>[]) new Frame<?>[n];
    subroutines = new Subroutine[n];
    queued = new boolean[n];
    queue = new int[n];
    top = 0;
    // computes exception handlers for each instruction
    for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
        TryCatchBlockNode tcb = m.tryCatchBlocks.get(i);
        int begin = insns.indexOf(tcb.start);
        int end = insns.indexOf(tcb.end);
        for (int j = begin; j < end; ++j) {
            List<TryCatchBlockNode> insnHandlers = handlers[j];
            if (insnHandlers == null) {
                insnHandlers = new ArrayList<TryCatchBlockNode>();
                handlers[j] = insnHandlers;
            }
            insnHandlers.add(tcb);
        }
    }
    // computes the subroutine for each instruction:
    Subroutine main = new Subroutine(null, m.maxLocals, null);
    List<AbstractInsnNode> subroutineCalls = new ArrayList<AbstractInsnNode>();
    Map<LabelNode, Subroutine> subroutineHeads = new HashMap<LabelNode, Subroutine>();
    findSubroutine(0, main, subroutineCalls);
    while (!subroutineCalls.isEmpty()) {
        JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0);
        Subroutine sub = subroutineHeads.get(jsr.label);
        if (sub == null) {
            sub = new Subroutine(jsr.label, m.maxLocals, jsr);
            subroutineHeads.put(jsr.label, sub);
            findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls);
        } else {
            sub.callers.add(jsr);
        }
    }
    for (int i = 0; i < n; ++i) {
        if (subroutines[i] != null && subroutines[i].start == null) {
            subroutines[i] = null;
        }
    }
    // initializes the data structures for the control flow analysis
    Frame<V> current = newFrame(m.maxLocals, m.maxStack);
    Frame<V> handler = newFrame(m.maxLocals, m.maxStack);
    current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)));
    Type[] args = Type.getArgumentTypes(m.desc);
    int local = 0;
    if ((m.access & ACC_STATIC) == 0) {
        Type ctype = Type.getObjectType(owner);
        current.setLocal(local++, interpreter.newValue(ctype));
    }
    for (int i = 0; i < args.length; ++i) {
        current.setLocal(local++, interpreter.newValue(args[i]));
        if (args[i].getSize() == 2) {
            current.setLocal(local++, interpreter.newValue(null));
        }
    }
    while (local < m.maxLocals) {
        current.setLocal(local++, interpreter.newValue(null));
    }
    merge(0, current, null);
    init(owner, m);
    // control flow analysis
    while (top > 0) {
        int insn = queue[--top];
        Frame<V> f = frames[insn];
        Subroutine subroutine = subroutines[insn];
        queued[insn] = false;
        AbstractInsnNode insnNode = null;
        try {
            insnNode = m.instructions.get(insn);
            int insnOpcode = insnNode.getOpcode();
            int insnType = insnNode.getType();
            if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
                merge(insn + 1, f, subroutine);
                newControlFlowEdge(insn, insn + 1);
            } else {
                current.init(f).execute(insnNode, interpreter);
                subroutine = subroutine == null ? null : subroutine.copy();
                if (insnNode instanceof JumpInsnNode) {
                    JumpInsnNode j = (JumpInsnNode) insnNode;
                    if (insnOpcode != GOTO && insnOpcode != JSR) {
                        merge(insn + 1, current, subroutine);
                        newControlFlowEdge(insn, insn + 1);
                    }
                    int jump = insns.indexOf(j.label);
                    if (insnOpcode == JSR) {
                        merge(jump, current, new Subroutine(j.label, m.maxLocals, j));
                    } else {
                        merge(jump, current, subroutine);
                    }
                    newControlFlowEdge(insn, jump);
                } else if (insnNode instanceof LookupSwitchInsnNode) {
                    LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
                    int jump = insns.indexOf(lsi.dflt);
                    merge(jump, current, subroutine);
                    newControlFlowEdge(insn, jump);
                    for (int j = 0; j < lsi.labels.size(); ++j) {
                        LabelNode label = lsi.labels.get(j);
                        jump = insns.indexOf(label);
                        merge(jump, current, subroutine);
                        newControlFlowEdge(insn, jump);
                    }
                } else if (insnNode instanceof TableSwitchInsnNode) {
                    TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
                    int jump = insns.indexOf(tsi.dflt);
                    merge(jump, current, subroutine);
                    newControlFlowEdge(insn, jump);
                    for (int j = 0; j < tsi.labels.size(); ++j) {
                        LabelNode label = tsi.labels.get(j);
                        jump = insns.indexOf(label);
                        merge(jump, current, subroutine);
                        newControlFlowEdge(insn, jump);
                    }
                } else if (insnOpcode == RET) {
                    if (subroutine == null) {
                        throw new AnalyzerException(insnNode, "RET instruction outside of a sub routine");
                    }
                    for (int i = 0; i < subroutine.callers.size(); ++i) {
                        JumpInsnNode caller = subroutine.callers.get(i);
                        int call = insns.indexOf(caller);
                        if (frames[call] != null) {
                            merge(call + 1, frames[call], current, subroutines[call], subroutine.access);
                            newControlFlowEdge(insn, call + 1);
                        }
                    }
                } else if (insnOpcode != ATHROW && (insnOpcode < IRETURN || insnOpcode > RETURN)) {
                    if (subroutine != null) {
                        if (insnNode instanceof VarInsnNode) {
                            int var = ((VarInsnNode) insnNode).var;
                            subroutine.access[var] = true;
                            if (insnOpcode == LLOAD || insnOpcode == DLOAD || insnOpcode == LSTORE || insnOpcode == DSTORE) {
                                subroutine.access[var + 1] = true;
                            }
                        } else if (insnNode instanceof IincInsnNode) {
                            int var = ((IincInsnNode) insnNode).var;
                            subroutine.access[var] = true;
                        }
                    }
                    merge(insn + 1, current, subroutine);
                    newControlFlowEdge(insn, insn + 1);
                }
            }
            List<TryCatchBlockNode> insnHandlers = handlers[insn];
            if (insnHandlers != null) {
                for (int i = 0; i < insnHandlers.size(); ++i) {
                    TryCatchBlockNode tcb = insnHandlers.get(i);
                    Type type;
                    if (tcb.type == null) {
                        type = Type.getObjectType("java/lang/Throwable");
                    } else {
                        type = Type.getObjectType(tcb.type);
                    }
                    int jump = insns.indexOf(tcb.handler);
                    if (newControlFlowExceptionEdge(insn, tcb)) {
                        handler.init(f);
                        handler.clearStack();
                        handler.push(interpreter.newValue(type));
                        merge(jump, handler, subroutine);
                    }
                }
            }
        } catch (AnalyzerException e) {
            throw new AnalyzerException(e.node, "Error at instruction " + insn + ": " + e.getMessage(), e);
        } catch (Exception e) {
            throw new AnalyzerException(insnNode, "Error at instruction " + insn + ": " + e.getMessage(), e);
        }
    }
    return frames;
}
Also used : LabelNode(org.mvel2.asm.tree.LabelNode) TryCatchBlockNode(org.mvel2.asm.tree.TryCatchBlockNode) TableSwitchInsnNode(org.mvel2.asm.tree.TableSwitchInsnNode) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) AbstractInsnNode(org.mvel2.asm.tree.AbstractInsnNode) Type(org.mvel2.asm.Type) JumpInsnNode(org.mvel2.asm.tree.JumpInsnNode) IincInsnNode(org.mvel2.asm.tree.IincInsnNode) ArrayList(java.util.ArrayList) List(java.util.List) InsnList(org.mvel2.asm.tree.InsnList) LookupSwitchInsnNode(org.mvel2.asm.tree.LookupSwitchInsnNode) VarInsnNode(org.mvel2.asm.tree.VarInsnNode)

Example 2 with JumpInsnNode

use of org.mvel2.asm.tree.JumpInsnNode in project mvel by mvel.

the class JSRInlinerAdapter method markSubroutineWalkDFS.

/**
 * Performs a simple DFS of the instructions, assigning each to the
 * subroutine <code>sub</code>. Starts from <code>index</code>. Invoked only
 * by <code>markSubroutineWalk()</code>.
 *
 * @param sub
 *            the subroutine whose instructions must be computed.
 * @param index
 *            an instruction of this subroutine.
 * @param anyvisited
 *            indexes of the already visited instructions, i.e. marked as
 *            part of this subroutine or any previously computed subroutine.
 */
private void markSubroutineWalkDFS(final BitSet sub, int index, final BitSet anyvisited) {
    while (true) {
        AbstractInsnNode node = instructions.get(index);
        // don't visit a node twice
        if (sub.get(index)) {
            return;
        }
        sub.set(index);
        // check for those nodes already visited by another subroutine
        if (anyvisited.get(index)) {
            dualCitizens.set(index);
            if (LOGGING) {
                log("Instruction #" + index + " is dual citizen.");
            }
        }
        anyvisited.set(index);
        if (node.getType() == AbstractInsnNode.JUMP_INSN && node.getOpcode() != JSR) {
            // we do not follow recursively called subroutines here; but any
            // other sort of branch we do follow
            JumpInsnNode jnode = (JumpInsnNode) node;
            int destidx = instructions.indexOf(jnode.label);
            markSubroutineWalkDFS(sub, destidx, anyvisited);
        }
        if (node.getType() == AbstractInsnNode.TABLESWITCH_INSN) {
            TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
            int destidx = instructions.indexOf(tsnode.dflt);
            markSubroutineWalkDFS(sub, destidx, anyvisited);
            for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
                LabelNode l = tsnode.labels.get(i);
                destidx = instructions.indexOf(l);
                markSubroutineWalkDFS(sub, destidx, anyvisited);
            }
        }
        if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) {
            LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
            int destidx = instructions.indexOf(lsnode.dflt);
            markSubroutineWalkDFS(sub, destidx, anyvisited);
            for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
                LabelNode l = lsnode.labels.get(i);
                destidx = instructions.indexOf(l);
                markSubroutineWalkDFS(sub, destidx, anyvisited);
            }
        }
        // or not; if not, return.
        switch(instructions.get(index).getOpcode()) {
            case GOTO:
            case RET:
            case TABLESWITCH:
            case LOOKUPSWITCH:
            case IRETURN:
            case LRETURN:
            case FRETURN:
            case DRETURN:
            case ARETURN:
            case RETURN:
            case ATHROW:
                /*
                 * note: this either returns from this subroutine, or a parent
                 * subroutine which invoked it
                 */
                return;
        }
        // Use tail recursion here in the form of an outer while loop to
        // avoid our stack growing needlessly:
        index++;
        // but this is more complicated).
        if (index >= instructions.size()) {
            return;
        }
    }
}
Also used : LabelNode(org.mvel2.asm.tree.LabelNode) TableSwitchInsnNode(org.mvel2.asm.tree.TableSwitchInsnNode) JumpInsnNode(org.mvel2.asm.tree.JumpInsnNode) LookupSwitchInsnNode(org.mvel2.asm.tree.LookupSwitchInsnNode) AbstractInsnNode(org.mvel2.asm.tree.AbstractInsnNode)

Example 3 with JumpInsnNode

use of org.mvel2.asm.tree.JumpInsnNode in project mvel by mvel.

the class Analyzer method findSubroutine.

private void findSubroutine(int insn, final Subroutine sub, final List<AbstractInsnNode> calls) throws AnalyzerException {
    while (true) {
        if (insn < 0 || insn >= n) {
            throw new AnalyzerException(null, "Execution can fall off end of the code");
        }
        if (subroutines[insn] != null) {
            return;
        }
        subroutines[insn] = sub.copy();
        AbstractInsnNode node = insns.get(insn);
        // calls findSubroutine recursively on normal successors
        if (node instanceof JumpInsnNode) {
            if (node.getOpcode() == JSR) {
                // do not follow a JSR, it leads to another subroutine!
                calls.add(node);
            } else {
                JumpInsnNode jnode = (JumpInsnNode) node;
                findSubroutine(insns.indexOf(jnode.label), sub, calls);
            }
        } else if (node instanceof TableSwitchInsnNode) {
            TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
            findSubroutine(insns.indexOf(tsnode.dflt), sub, calls);
            for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
                LabelNode l = tsnode.labels.get(i);
                findSubroutine(insns.indexOf(l), sub, calls);
            }
        } else if (node instanceof LookupSwitchInsnNode) {
            LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
            findSubroutine(insns.indexOf(lsnode.dflt), sub, calls);
            for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
                LabelNode l = lsnode.labels.get(i);
                findSubroutine(insns.indexOf(l), sub, calls);
            }
        }
        // calls findSubroutine recursively on exception handler successors
        List<TryCatchBlockNode> insnHandlers = handlers[insn];
        if (insnHandlers != null) {
            for (int i = 0; i < insnHandlers.size(); ++i) {
                TryCatchBlockNode tcb = insnHandlers.get(i);
                findSubroutine(insns.indexOf(tcb.handler), sub, calls);
            }
        }
        // if insn does not falls through to the next instruction, return.
        switch(node.getOpcode()) {
            case GOTO:
            case RET:
            case TABLESWITCH:
            case LOOKUPSWITCH:
            case IRETURN:
            case LRETURN:
            case FRETURN:
            case DRETURN:
            case ARETURN:
            case RETURN:
            case ATHROW:
                return;
        }
        insn++;
    }
}
Also used : LabelNode(org.mvel2.asm.tree.LabelNode) TryCatchBlockNode(org.mvel2.asm.tree.TryCatchBlockNode) TableSwitchInsnNode(org.mvel2.asm.tree.TableSwitchInsnNode) JumpInsnNode(org.mvel2.asm.tree.JumpInsnNode) LookupSwitchInsnNode(org.mvel2.asm.tree.LookupSwitchInsnNode) AbstractInsnNode(org.mvel2.asm.tree.AbstractInsnNode)

Example 4 with JumpInsnNode

use of org.mvel2.asm.tree.JumpInsnNode in project mvel by mvel.

the class Subroutine method merge.

public boolean merge(final Subroutine subroutine) throws AnalyzerException {
    boolean changes = false;
    for (int i = 0; i < access.length; ++i) {
        if (subroutine.access[i] && !access[i]) {
            access[i] = true;
            changes = true;
        }
    }
    if (subroutine.start == start) {
        for (int i = 0; i < subroutine.callers.size(); ++i) {
            JumpInsnNode caller = subroutine.callers.get(i);
            if (!callers.contains(caller)) {
                callers.add(caller);
                changes = true;
            }
        }
    }
    return changes;
}
Also used : JumpInsnNode(org.mvel2.asm.tree.JumpInsnNode)

Example 5 with JumpInsnNode

use of org.mvel2.asm.tree.JumpInsnNode in project mvel by mvel.

the class JSRInlinerAdapter method visitJumpInsn.

/**
 * Detects a JSR instruction and sets a flag to indicate we will need to do
 * inlining.
 */
@Override
public void visitJumpInsn(final int opcode, final Label lbl) {
    super.visitJumpInsn(opcode, lbl);
    LabelNode ln = ((JumpInsnNode) instructions.getLast()).label;
    if (opcode == JSR && !subroutineHeads.containsKey(ln)) {
        subroutineHeads.put(ln, new BitSet());
    }
}
Also used : LabelNode(org.mvel2.asm.tree.LabelNode) BitSet(java.util.BitSet) JumpInsnNode(org.mvel2.asm.tree.JumpInsnNode)

Aggregations

JumpInsnNode (org.mvel2.asm.tree.JumpInsnNode)6 LabelNode (org.mvel2.asm.tree.LabelNode)5 AbstractInsnNode (org.mvel2.asm.tree.AbstractInsnNode)4 LookupSwitchInsnNode (org.mvel2.asm.tree.LookupSwitchInsnNode)4 TableSwitchInsnNode (org.mvel2.asm.tree.TableSwitchInsnNode)4 TryCatchBlockNode (org.mvel2.asm.tree.TryCatchBlockNode)3 BitSet (java.util.BitSet)2 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Type (org.mvel2.asm.Type)1 IincInsnNode (org.mvel2.asm.tree.IincInsnNode)1 InsnList (org.mvel2.asm.tree.InsnList)1 InsnNode (org.mvel2.asm.tree.InsnNode)1 LocalVariableNode (org.mvel2.asm.tree.LocalVariableNode)1 VarInsnNode (org.mvel2.asm.tree.VarInsnNode)1