Search in sources :

Example 1 with LocalVariableNode

use of org.apache.tapestry5.internal.plastic.asm.tree.LocalVariableNode in project tapestry-5 by apache.

the class JSRInlinerAdapter method emitInstantiation.

/**
 * Emits an instantiation of a subroutine, specified by <code>instantiation</code>. May add new
 * instantiations that are invoked by this one to the <code>worklist</code>, and new try/catch
 * blocks to <code>newTryCatchBlocks</code>.
 *
 * @param instantiation 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.
 * @param newLocalVariables the local variables list to which the instantiated local variables
 *     must be appended.
 */
private void emitInstantiation(final Instantiation instantiation, final List<Instantiation> worklist, final InsnList newInstructions, final List<TryCatchBlockNode> newTryCatchBlocks, final List<LocalVariableNode> newLocalVariables) {
    LabelNode previousLabelNode = null;
    for (int i = 0; i < instructions.size(); ++i) {
        AbstractInsnNode insnNode = instructions.get(i);
        if (insnNode.getType() == AbstractInsnNode.LABEL) {
            // Always clone all labels, while avoiding to add the same label more than once.
            LabelNode labelNode = (LabelNode) insnNode;
            LabelNode clonedLabelNode = instantiation.getClonedLabel(labelNode);
            if (clonedLabelNode != previousLabelNode) {
                newInstructions.add(clonedLabelNode);
                previousLabelNode = clonedLabelNode;
            }
        } else if (instantiation.findOwner(i) == instantiation) {
            if (insnNode.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 oldest
                // instantiation that claims to own this instruction.
                LabelNode retLabel = null;
                for (Instantiation retLabelOwner = instantiation; retLabelOwner != null; retLabelOwner = retLabelOwner.parent) {
                    if (retLabelOwner.subroutineInsns.get(i)) {
                        retLabel = retLabelOwner.returnLabel;
                    }
                }
                if (retLabel == null) {
                    // never happen for verifiable code.
                    throw new IllegalArgumentException("Instruction #" + i + " is a RET not owned by any subroutine");
                }
                newInstructions.add(new JumpInsnNode(GOTO, retLabel));
            } else if (insnNode.getOpcode() == JSR) {
                LabelNode jsrLabelNode = ((JumpInsnNode) insnNode).label;
                BitSet subroutineInsns = subroutinesInsns.get(jsrLabelNode);
                Instantiation newInstantiation = new Instantiation(instantiation, subroutineInsns);
                LabelNode clonedJsrLabelNode = newInstantiation.getClonedLabelForJumpInsn(jsrLabelNode);
                // Replace the JSR instruction with a GOTO to the instantiated subroutine, and push NULL
                // for what was once the return address value. This hack allows us to avoid doing any sort
                // of data flow analysis to figure out which instructions manipulate the old return
                // address value pointer which is now known to be unneeded.
                newInstructions.add(new InsnNode(ACONST_NULL));
                newInstructions.add(new JumpInsnNode(GOTO, clonedJsrLabelNode));
                newInstructions.add(newInstantiation.returnLabel);
                // Insert this new instantiation into the queue to be emitted later.
                worklist.add(newInstantiation);
            } else {
                newInstructions.add(insnNode.clone(instantiation));
            }
        }
    }
    // Emit the try/catch blocks that are relevant for this instantiation.
    for (TryCatchBlockNode tryCatchBlockNode : tryCatchBlocks) {
        final LabelNode start = instantiation.getClonedLabel(tryCatchBlockNode.start);
        final LabelNode end = instantiation.getClonedLabel(tryCatchBlockNode.end);
        if (start != end) {
            final LabelNode handler = instantiation.getClonedLabelForJumpInsn(tryCatchBlockNode.handler);
            if (start == null || end == null || handler == null) {
                throw new AssertionError("Internal error!");
            }
            newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler, tryCatchBlockNode.type));
        }
    }
    // Emit the local variable nodes that are relevant for this instantiation.
    for (LocalVariableNode localVariableNode : localVariables) {
        final LabelNode start = instantiation.getClonedLabel(localVariableNode.start);
        final LabelNode end = instantiation.getClonedLabel(localVariableNode.end);
        if (start != end) {
            newLocalVariables.add(new LocalVariableNode(localVariableNode.name, localVariableNode.desc, localVariableNode.signature, start, end, localVariableNode.index));
        }
    }
}
Also used : LabelNode(org.apache.tapestry5.internal.plastic.asm.tree.LabelNode) LookupSwitchInsnNode(org.apache.tapestry5.internal.plastic.asm.tree.LookupSwitchInsnNode) JumpInsnNode(org.apache.tapestry5.internal.plastic.asm.tree.JumpInsnNode) AbstractInsnNode(org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode) TableSwitchInsnNode(org.apache.tapestry5.internal.plastic.asm.tree.TableSwitchInsnNode) InsnNode(org.apache.tapestry5.internal.plastic.asm.tree.InsnNode) TryCatchBlockNode(org.apache.tapestry5.internal.plastic.asm.tree.TryCatchBlockNode) BitSet(java.util.BitSet) JumpInsnNode(org.apache.tapestry5.internal.plastic.asm.tree.JumpInsnNode) AbstractInsnNode(org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode) LocalVariableNode(org.apache.tapestry5.internal.plastic.asm.tree.LocalVariableNode)

Example 2 with LocalVariableNode

use of org.apache.tapestry5.internal.plastic.asm.tree.LocalVariableNode in project tapestry-5 by apache.

the class JSRInlinerAdapter method emitCode.

/**
 * Creates the new instructions, inlining each instantiation of each subroutine until the code is
 * fully elaborated.
 */
private void emitCode() {
    LinkedList<Instantiation> worklist = new LinkedList<>();
    // Create an instantiation of the main "subroutine", which is just the main routine.
    worklist.add(new Instantiation(null, mainSubroutineInsns));
    // Emit instantiations of each subroutine we encounter, including the main subroutine.
    InsnList newInstructions = new InsnList();
    List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<>();
    List<LocalVariableNode> newLocalVariables = new ArrayList<>();
    while (!worklist.isEmpty()) {
        Instantiation instantiation = worklist.removeFirst();
        emitInstantiation(instantiation, worklist, newInstructions, newTryCatchBlocks, newLocalVariables);
    }
    instructions = newInstructions;
    tryCatchBlocks = newTryCatchBlocks;
    localVariables = newLocalVariables;
}
Also used : TryCatchBlockNode(org.apache.tapestry5.internal.plastic.asm.tree.TryCatchBlockNode) ArrayList(java.util.ArrayList) InsnList(org.apache.tapestry5.internal.plastic.asm.tree.InsnList) LinkedList(java.util.LinkedList) LocalVariableNode(org.apache.tapestry5.internal.plastic.asm.tree.LocalVariableNode)

Aggregations

LocalVariableNode (org.apache.tapestry5.internal.plastic.asm.tree.LocalVariableNode)2 TryCatchBlockNode (org.apache.tapestry5.internal.plastic.asm.tree.TryCatchBlockNode)2 ArrayList (java.util.ArrayList)1 BitSet (java.util.BitSet)1 LinkedList (java.util.LinkedList)1 AbstractInsnNode (org.apache.tapestry5.internal.plastic.asm.tree.AbstractInsnNode)1 InsnList (org.apache.tapestry5.internal.plastic.asm.tree.InsnList)1 InsnNode (org.apache.tapestry5.internal.plastic.asm.tree.InsnNode)1 JumpInsnNode (org.apache.tapestry5.internal.plastic.asm.tree.JumpInsnNode)1 LabelNode (org.apache.tapestry5.internal.plastic.asm.tree.LabelNode)1 LookupSwitchInsnNode (org.apache.tapestry5.internal.plastic.asm.tree.LookupSwitchInsnNode)1 TableSwitchInsnNode (org.apache.tapestry5.internal.plastic.asm.tree.TableSwitchInsnNode)1