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));
}
}
}
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;
}
Aggregations