Search in sources :

Example 1 with AbstractInsnNode

use of org.mvel2.asm.tree.AbstractInsnNode 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 AbstractInsnNode

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

the class BasicVerifier method naryOperation.

@Override
public BasicValue naryOperation(final AbstractInsnNode insn, final List<? extends BasicValue> values) throws AnalyzerException {
    int opcode = insn.getOpcode();
    if (opcode == MULTIANEWARRAY) {
        for (int i = 0; i < values.size(); ++i) {
            if (!BasicValue.INT_VALUE.equals(values.get(i))) {
                throw new AnalyzerException(insn, null, BasicValue.INT_VALUE, values.get(i));
            }
        }
    } else {
        int i = 0;
        int j = 0;
        if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
            Type owner = Type.getObjectType(((MethodInsnNode) insn).owner);
            if (!isSubTypeOf(values.get(i++), newValue(owner))) {
                throw new AnalyzerException(insn, "Method owner", newValue(owner), values.get(0));
            }
        }
        String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc : ((MethodInsnNode) insn).desc;
        Type[] args = Type.getArgumentTypes(desc);
        while (i < values.size()) {
            BasicValue expected = newValue(args[j++]);
            BasicValue encountered = values.get(i++);
            if (!isSubTypeOf(encountered, expected)) {
                throw new AnalyzerException(insn, "Argument " + j, expected, encountered);
            }
        }
    }
    return super.naryOperation(insn, values);
}
Also used : Type(org.mvel2.asm.Type)

Example 3 with AbstractInsnNode

use of org.mvel2.asm.tree.AbstractInsnNode 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 4 with AbstractInsnNode

use of org.mvel2.asm.tree.AbstractInsnNode 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 5 with AbstractInsnNode

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

the class BasicVerifier method binaryOperation.

@Override
public BasicValue binaryOperation(final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2) throws AnalyzerException {
    BasicValue expected1;
    BasicValue expected2;
    switch(insn.getOpcode()) {
        case IALOAD:
            expected1 = newValue(Type.getType("[I"));
            expected2 = BasicValue.INT_VALUE;
            break;
        case BALOAD:
            if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
                expected1 = newValue(Type.getType("[Z"));
            } else {
                expected1 = newValue(Type.getType("[B"));
            }
            expected2 = BasicValue.INT_VALUE;
            break;
        case CALOAD:
            expected1 = newValue(Type.getType("[C"));
            expected2 = BasicValue.INT_VALUE;
            break;
        case SALOAD:
            expected1 = newValue(Type.getType("[S"));
            expected2 = BasicValue.INT_VALUE;
            break;
        case LALOAD:
            expected1 = newValue(Type.getType("[J"));
            expected2 = BasicValue.INT_VALUE;
            break;
        case FALOAD:
            expected1 = newValue(Type.getType("[F"));
            expected2 = BasicValue.INT_VALUE;
            break;
        case DALOAD:
            expected1 = newValue(Type.getType("[D"));
            expected2 = BasicValue.INT_VALUE;
            break;
        case AALOAD:
            expected1 = newValue(Type.getType("[Ljava/lang/Object;"));
            expected2 = BasicValue.INT_VALUE;
            break;
        case IADD:
        case ISUB:
        case IMUL:
        case IDIV:
        case IREM:
        case ISHL:
        case ISHR:
        case IUSHR:
        case IAND:
        case IOR:
        case IXOR:
        case IF_ICMPEQ:
        case IF_ICMPNE:
        case IF_ICMPLT:
        case IF_ICMPGE:
        case IF_ICMPGT:
        case IF_ICMPLE:
            expected1 = BasicValue.INT_VALUE;
            expected2 = BasicValue.INT_VALUE;
            break;
        case FADD:
        case FSUB:
        case FMUL:
        case FDIV:
        case FREM:
        case FCMPL:
        case FCMPG:
            expected1 = BasicValue.FLOAT_VALUE;
            expected2 = BasicValue.FLOAT_VALUE;
            break;
        case LADD:
        case LSUB:
        case LMUL:
        case LDIV:
        case LREM:
        case LAND:
        case LOR:
        case LXOR:
        case LCMP:
            expected1 = BasicValue.LONG_VALUE;
            expected2 = BasicValue.LONG_VALUE;
            break;
        case LSHL:
        case LSHR:
        case LUSHR:
            expected1 = BasicValue.LONG_VALUE;
            expected2 = BasicValue.INT_VALUE;
            break;
        case DADD:
        case DSUB:
        case DMUL:
        case DDIV:
        case DREM:
        case DCMPL:
        case DCMPG:
            expected1 = BasicValue.DOUBLE_VALUE;
            expected2 = BasicValue.DOUBLE_VALUE;
            break;
        case IF_ACMPEQ:
        case IF_ACMPNE:
            expected1 = BasicValue.REFERENCE_VALUE;
            expected2 = BasicValue.REFERENCE_VALUE;
            break;
        case PUTFIELD:
            FieldInsnNode fin = (FieldInsnNode) insn;
            expected1 = newValue(Type.getObjectType(fin.owner));
            expected2 = newValue(Type.getType(fin.desc));
            break;
        default:
            throw new Error("Internal error.");
    }
    if (!isSubTypeOf(value1, expected1)) {
        throw new AnalyzerException(insn, "First argument", expected1, value1);
    } else if (!isSubTypeOf(value2, expected2)) {
        throw new AnalyzerException(insn, "Second argument", expected2, value2);
    }
    if (insn.getOpcode() == AALOAD) {
        return getElementValue(value1);
    } else {
        return super.binaryOperation(insn, value1, value2);
    }
}
Also used : FieldInsnNode(org.mvel2.asm.tree.FieldInsnNode)

Aggregations

AbstractInsnNode (org.mvel2.asm.tree.AbstractInsnNode)4 JumpInsnNode (org.mvel2.asm.tree.JumpInsnNode)4 LabelNode (org.mvel2.asm.tree.LabelNode)4 LookupSwitchInsnNode (org.mvel2.asm.tree.LookupSwitchInsnNode)4 TableSwitchInsnNode (org.mvel2.asm.tree.TableSwitchInsnNode)4 TryCatchBlockNode (org.mvel2.asm.tree.TryCatchBlockNode)3 Type (org.mvel2.asm.Type)2 ArrayList (java.util.ArrayList)1 BitSet (java.util.BitSet)1 HashMap (java.util.HashMap)1 List (java.util.List)1 FieldInsnNode (org.mvel2.asm.tree.FieldInsnNode)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