Search in sources :

Example 6 with LabelNode

use of jdk.internal.org.objectweb.asm.tree.LabelNode in project Bytecoder by mirkosertic.

the class JSRInlinerAdapter method emitSubroutine.

/**
 * Emits one instantiation of one subroutine, specified by
 * <code>instant</code>. May add new instantiations that are invoked by this
 * one to the <code>worklist</code> parameter, and new try/catch blocks to
 * <code>newTryCatchBlocks</code>.
 *
 * @param instant
 *            the instantiation that must be performed.
 * @param worklist
 *            list of the instantiations that remain to be done.
 * @param newInstructions
 *            the instruction list to which the instantiated code must be
 *            appended.
 * @param newTryCatchBlocks
 *            the exception handler list to which the instantiated handlers
 *            must be appended.
 */
private void emitSubroutine(final Instantiation instant, final List<Instantiation> worklist, final InsnList newInstructions, final List<TryCatchBlockNode> newTryCatchBlocks, final List<LocalVariableNode> newLocalVariables) {
    LabelNode duplbl = null;
    if (LOGGING) {
        log("--------------------------------------------------------");
        log("Emitting instantiation of subroutine " + instant.subroutine);
    }
    // labels and jump targets as we go:
    for (int i = 0, c = instructions.size(); i < c; i++) {
        AbstractInsnNode insn = instructions.get(i);
        Instantiation owner = instant.findOwner(i);
        // Always remap labels:
        if (insn.getType() == AbstractInsnNode.LABEL) {
            // Translate labels into their renamed equivalents.
            // Avoid adding the same label more than once. Note
            // that because we own this instruction the gotoTable
            // and the rangeTable will always agree.
            LabelNode ilbl = (LabelNode) insn;
            LabelNode remap = instant.rangeLabel(ilbl);
            if (LOGGING) {
                // TODO use of default toString().
                log("Translating lbl #" + i + ':' + ilbl + " to " + remap);
            }
            if (remap != duplbl) {
                newInstructions.add(remap);
                duplbl = remap;
            }
            continue;
        }
        // that do not invoke each other.
        if (owner != instant) {
            continue;
        }
        if (LOGGING) {
            log("Emitting inst #" + i);
        }
        if (insn.getOpcode() == RET) {
            // Translate RET instruction(s) to a jump to the return label
            // for the appropriate instantiation. The problem is that the
            // subroutine may "fall through" to the ret of a parent
            // subroutine; therefore, to find the appropriate ret label we
            // find the lowest subroutine on the stack that claims to own
            // this instruction. See the class javadoc comment for an
            // explanation on why this technique is safe (note: it is only
            // safe if the input is verifiable).
            LabelNode retlabel = null;
            for (Instantiation p = instant; p != null; p = p.previous) {
                if (p.subroutine.get(i)) {
                    retlabel = p.returnLabel;
                }
            }
            if (retlabel == null) {
                // code.
                throw new RuntimeException("Instruction #" + i + " is a RET not owned by any subroutine");
            }
            newInstructions.add(new JumpInsnNode(GOTO, retlabel));
        } else if (insn.getOpcode() == JSR) {
            LabelNode lbl = ((JumpInsnNode) insn).label;
            BitSet sub = subroutineHeads.get(lbl);
            Instantiation newinst = new Instantiation(instant, sub);
            LabelNode startlbl = newinst.gotoLabel(lbl);
            if (LOGGING) {
                log(" Creating instantiation of subr " + sub);
            }
            // Rather than JSRing, we will jump to the inline version and
            // push NULL for what was once the return value. This hack
            // allows us to avoid doing any sort of data flow analysis to
            // figure out which instructions manipulate the old return value
            // pointer which is now known to be unneeded.
            newInstructions.add(new InsnNode(ACONST_NULL));
            newInstructions.add(new JumpInsnNode(GOTO, startlbl));
            newInstructions.add(newinst.returnLabel);
            // Insert this new instantiation into the queue to be emitted
            // later.
            worklist.add(newinst);
        } else {
            newInstructions.add(insn.clone(instant));
        }
    }
    // Emit try/catch blocks that are relevant to this method.
    for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it.hasNext(); ) {
        TryCatchBlockNode trycatch = it.next();
        if (LOGGING) {
            // TODO use of default toString().
            log("try catch block original labels=" + trycatch.start + '-' + trycatch.end + "->" + trycatch.handler);
        }
        final LabelNode start = instant.rangeLabel(trycatch.start);
        final LabelNode end = instant.rangeLabel(trycatch.end);
        // Ignore empty try/catch regions
        if (start == end) {
            if (LOGGING) {
                log(" try catch block empty in this subroutine");
            }
            continue;
        }
        final LabelNode handler = instant.gotoLabel(trycatch.handler);
        if (LOGGING) {
            // TODO use of default toString().
            log(" try catch block new labels=" + start + '-' + end + "->" + handler);
        }
        if (start == null || end == null || handler == null) {
            throw new RuntimeException("Internal error!");
        }
        newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler, trycatch.type));
    }
    for (Iterator<LocalVariableNode> it = localVariables.iterator(); it.hasNext(); ) {
        LocalVariableNode lvnode = it.next();
        if (LOGGING) {
            log("local var " + lvnode.name);
        }
        final LabelNode start = instant.rangeLabel(lvnode.start);
        final LabelNode end = instant.rangeLabel(lvnode.end);
        if (start == end) {
            if (LOGGING) {
                log("  local variable empty in this sub");
            }
            continue;
        }
        newLocalVariables.add(new LocalVariableNode(lvnode.name, lvnode.desc, lvnode.signature, start, end, lvnode.index));
    }
}
Also used : LabelNode(jdk.internal.org.objectweb.asm.tree.LabelNode) InsnNode(jdk.internal.org.objectweb.asm.tree.InsnNode) TableSwitchInsnNode(jdk.internal.org.objectweb.asm.tree.TableSwitchInsnNode) JumpInsnNode(jdk.internal.org.objectweb.asm.tree.JumpInsnNode) AbstractInsnNode(jdk.internal.org.objectweb.asm.tree.AbstractInsnNode) LookupSwitchInsnNode(jdk.internal.org.objectweb.asm.tree.LookupSwitchInsnNode) TryCatchBlockNode(jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode) BitSet(java.util.BitSet) JumpInsnNode(jdk.internal.org.objectweb.asm.tree.JumpInsnNode) AbstractInsnNode(jdk.internal.org.objectweb.asm.tree.AbstractInsnNode) LocalVariableNode(jdk.internal.org.objectweb.asm.tree.LocalVariableNode)

Example 7 with LabelNode

use of jdk.internal.org.objectweb.asm.tree.LabelNode in project jdk8u_jdk by JetBrains.

the class JSRInlinerAdapter method emitSubroutine.

/**
     * Emits one instantiation of one subroutine, specified by
     * <code>instant</code>. May add new instantiations that are invoked by this
     * one to the <code>worklist</code> parameter, and new try/catch blocks to
     * <code>newTryCatchBlocks</code>.
     *
     * @param instant
     *            the instantiation that must be performed.
     * @param worklist
     *            list of the instantiations that remain to be done.
     * @param newInstructions
     *            the instruction list to which the instantiated code must be
     *            appended.
     * @param newTryCatchBlocks
     *            the exception handler list to which the instantiated handlers
     *            must be appended.
     */
private void emitSubroutine(final Instantiation instant, final List<Instantiation> worklist, final InsnList newInstructions, final List<TryCatchBlockNode> newTryCatchBlocks, final List<LocalVariableNode> newLocalVariables) {
    LabelNode duplbl = null;
    if (LOGGING) {
        log("--------------------------------------------------------");
        log("Emitting instantiation of subroutine " + instant.subroutine);
    }
    // labels and jump targets as we go:
    for (int i = 0, c = instructions.size(); i < c; i++) {
        AbstractInsnNode insn = instructions.get(i);
        Instantiation owner = instant.findOwner(i);
        // Always remap labels:
        if (insn.getType() == AbstractInsnNode.LABEL) {
            // Translate labels into their renamed equivalents.
            // Avoid adding the same label more than once. Note
            // that because we own this instruction the gotoTable
            // and the rangeTable will always agree.
            LabelNode ilbl = (LabelNode) insn;
            LabelNode remap = instant.rangeLabel(ilbl);
            if (LOGGING) {
                // TODO use of default toString().
                log("Translating lbl #" + i + ':' + ilbl + " to " + remap);
            }
            if (remap != duplbl) {
                newInstructions.add(remap);
                duplbl = remap;
            }
            continue;
        }
        // that do not invoke each other.
        if (owner != instant) {
            continue;
        }
        if (LOGGING) {
            log("Emitting inst #" + i);
        }
        if (insn.getOpcode() == RET) {
            // Translate RET instruction(s) to a jump to the return label
            // for the appropriate instantiation. The problem is that the
            // subroutine may "fall through" to the ret of a parent
            // subroutine; therefore, to find the appropriate ret label we
            // find the lowest subroutine on the stack that claims to own
            // this instruction. See the class javadoc comment for an
            // explanation on why this technique is safe (note: it is only
            // safe if the input is verifiable).
            LabelNode retlabel = null;
            for (Instantiation p = instant; p != null; p = p.previous) {
                if (p.subroutine.get(i)) {
                    retlabel = p.returnLabel;
                }
            }
            if (retlabel == null) {
                // code.
                throw new RuntimeException("Instruction #" + i + " is a RET not owned by any subroutine");
            }
            newInstructions.add(new JumpInsnNode(GOTO, retlabel));
        } else if (insn.getOpcode() == JSR) {
            LabelNode lbl = ((JumpInsnNode) insn).label;
            BitSet sub = subroutineHeads.get(lbl);
            Instantiation newinst = new Instantiation(instant, sub);
            LabelNode startlbl = newinst.gotoLabel(lbl);
            if (LOGGING) {
                log(" Creating instantiation of subr " + sub);
            }
            // Rather than JSRing, we will jump to the inline version and
            // push NULL for what was once the return value. This hack
            // allows us to avoid doing any sort of data flow analysis to
            // figure out which instructions manipulate the old return value
            // pointer which is now known to be unneeded.
            newInstructions.add(new InsnNode(ACONST_NULL));
            newInstructions.add(new JumpInsnNode(GOTO, startlbl));
            newInstructions.add(newinst.returnLabel);
            // Insert this new instantiation into the queue to be emitted
            // later.
            worklist.add(newinst);
        } else {
            newInstructions.add(insn.clone(instant));
        }
    }
    // Emit try/catch blocks that are relevant to this method.
    for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it.hasNext(); ) {
        TryCatchBlockNode trycatch = it.next();
        if (LOGGING) {
            // TODO use of default toString().
            log("try catch block original labels=" + trycatch.start + '-' + trycatch.end + "->" + trycatch.handler);
        }
        final LabelNode start = instant.rangeLabel(trycatch.start);
        final LabelNode end = instant.rangeLabel(trycatch.end);
        // Ignore empty try/catch regions
        if (start == end) {
            if (LOGGING) {
                log(" try catch block empty in this subroutine");
            }
            continue;
        }
        final LabelNode handler = instant.gotoLabel(trycatch.handler);
        if (LOGGING) {
            // TODO use of default toString().
            log(" try catch block new labels=" + start + '-' + end + "->" + handler);
        }
        if (start == null || end == null || handler == null) {
            throw new RuntimeException("Internal error!");
        }
        newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler, trycatch.type));
    }
    for (Iterator<LocalVariableNode> it = localVariables.iterator(); it.hasNext(); ) {
        LocalVariableNode lvnode = it.next();
        if (LOGGING) {
            log("local var " + lvnode.name);
        }
        final LabelNode start = instant.rangeLabel(lvnode.start);
        final LabelNode end = instant.rangeLabel(lvnode.end);
        if (start == end) {
            if (LOGGING) {
                log("  local variable empty in this sub");
            }
            continue;
        }
        newLocalVariables.add(new LocalVariableNode(lvnode.name, lvnode.desc, lvnode.signature, start, end, lvnode.index));
    }
}
Also used : LabelNode(jdk.internal.org.objectweb.asm.tree.LabelNode) InsnNode(jdk.internal.org.objectweb.asm.tree.InsnNode) TableSwitchInsnNode(jdk.internal.org.objectweb.asm.tree.TableSwitchInsnNode) JumpInsnNode(jdk.internal.org.objectweb.asm.tree.JumpInsnNode) AbstractInsnNode(jdk.internal.org.objectweb.asm.tree.AbstractInsnNode) LookupSwitchInsnNode(jdk.internal.org.objectweb.asm.tree.LookupSwitchInsnNode) TryCatchBlockNode(jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode) BitSet(java.util.BitSet) JumpInsnNode(jdk.internal.org.objectweb.asm.tree.JumpInsnNode) AbstractInsnNode(jdk.internal.org.objectweb.asm.tree.AbstractInsnNode) LocalVariableNode(jdk.internal.org.objectweb.asm.tree.LocalVariableNode)

Example 8 with LabelNode

use of jdk.internal.org.objectweb.asm.tree.LabelNode in project jdk8u_jdk by JetBrains.

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(jdk.internal.org.objectweb.asm.tree.LabelNode) TryCatchBlockNode(jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode) TableSwitchInsnNode(jdk.internal.org.objectweb.asm.tree.TableSwitchInsnNode) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) AbstractInsnNode(jdk.internal.org.objectweb.asm.tree.AbstractInsnNode) Type(jdk.internal.org.objectweb.asm.Type) JumpInsnNode(jdk.internal.org.objectweb.asm.tree.JumpInsnNode) IincInsnNode(jdk.internal.org.objectweb.asm.tree.IincInsnNode) InsnList(jdk.internal.org.objectweb.asm.tree.InsnList) ArrayList(java.util.ArrayList) List(java.util.List) LookupSwitchInsnNode(jdk.internal.org.objectweb.asm.tree.LookupSwitchInsnNode) VarInsnNode(jdk.internal.org.objectweb.asm.tree.VarInsnNode)

Example 9 with LabelNode

use of jdk.internal.org.objectweb.asm.tree.LabelNode in project jdk8u_jdk by JetBrains.

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(jdk.internal.org.objectweb.asm.tree.LabelNode) BitSet(java.util.BitSet) JumpInsnNode(jdk.internal.org.objectweb.asm.tree.JumpInsnNode)

Example 10 with LabelNode

use of jdk.internal.org.objectweb.asm.tree.LabelNode in project jdk8u_jdk by JetBrains.

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(jdk.internal.org.objectweb.asm.tree.LabelNode) TableSwitchInsnNode(jdk.internal.org.objectweb.asm.tree.TableSwitchInsnNode) JumpInsnNode(jdk.internal.org.objectweb.asm.tree.JumpInsnNode) LookupSwitchInsnNode(jdk.internal.org.objectweb.asm.tree.LookupSwitchInsnNode) AbstractInsnNode(jdk.internal.org.objectweb.asm.tree.AbstractInsnNode)

Aggregations

LabelNode (jdk.internal.org.objectweb.asm.tree.LabelNode)12 JumpInsnNode (jdk.internal.org.objectweb.asm.tree.JumpInsnNode)10 AbstractInsnNode (jdk.internal.org.objectweb.asm.tree.AbstractInsnNode)8 LookupSwitchInsnNode (jdk.internal.org.objectweb.asm.tree.LookupSwitchInsnNode)8 TableSwitchInsnNode (jdk.internal.org.objectweb.asm.tree.TableSwitchInsnNode)8 BitSet (java.util.BitSet)6 TryCatchBlockNode (jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode)6 HashMap (java.util.HashMap)4 AbstractMap (java.util.AbstractMap)2 ArrayList (java.util.ArrayList)2 List (java.util.List)2 Map (java.util.Map)2 Type (jdk.internal.org.objectweb.asm.Type)2 IincInsnNode (jdk.internal.org.objectweb.asm.tree.IincInsnNode)2 InsnList (jdk.internal.org.objectweb.asm.tree.InsnList)2 InsnNode (jdk.internal.org.objectweb.asm.tree.InsnNode)2 LocalVariableNode (jdk.internal.org.objectweb.asm.tree.LocalVariableNode)2 VarInsnNode (jdk.internal.org.objectweb.asm.tree.VarInsnNode)2