Search in sources :

Example 1 with InsnNode

use of jdk.internal.org.objectweb.asm.tree.InsnNode 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 2 with InsnNode

use of jdk.internal.org.objectweb.asm.tree.InsnNode 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)

Aggregations

BitSet (java.util.BitSet)2 AbstractInsnNode (jdk.internal.org.objectweb.asm.tree.AbstractInsnNode)2 InsnNode (jdk.internal.org.objectweb.asm.tree.InsnNode)2 JumpInsnNode (jdk.internal.org.objectweb.asm.tree.JumpInsnNode)2 LabelNode (jdk.internal.org.objectweb.asm.tree.LabelNode)2 LocalVariableNode (jdk.internal.org.objectweb.asm.tree.LocalVariableNode)2 LookupSwitchInsnNode (jdk.internal.org.objectweb.asm.tree.LookupSwitchInsnNode)2 TableSwitchInsnNode (jdk.internal.org.objectweb.asm.tree.TableSwitchInsnNode)2 TryCatchBlockNode (jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode)2