in src/org/apache/xalan/xsltc/compiler/util/MethodGenerator.java [1978:2146]
boolean widenConditionalBranchTargetOffsets() {
boolean ilChanged = false;
int maxOffsetChange = 0;
InstructionList il = getInstructionList();
// Loop through all the instructions, finding those that would be
// affected by inserting new instructions in the InstructionList, and
// calculating the maximum amount by which the relative offset between
// two instructions could possibly change.
// In part this loop duplicates code in
// org.apache.bcel.generic.InstructionList.setPosition(), which does
// this to determine whether to use 16-bit or 32-bit offsets for GOTO
// and JSR instructions. Ideally, that method would do the same for
// conditional branch instructions, but it doesn't, so we duplicate the
// processing here.
for (InstructionHandle ih = il.getStart();
ih != null;
ih = ih.getNext()) {
Instruction inst = ih.getInstruction();
switch (inst.getOpcode()) {
// Instructions that may have 16-bit or 32-bit branch targets.
// The size of the branch offset might increase by two bytes.
case Constants.GOTO:
case Constants.JSR:
maxOffsetChange = maxOffsetChange + 2;
break;
// Instructions that contain padding for alignment purposes
// Up to three bytes of padding might be needed. For greater
// accuracy, we should be able to discount any padding already
// added to these instructions by InstructionList.setPosition(),
// their APIs do not expose that information.
case Constants.TABLESWITCH:
case Constants.LOOKUPSWITCH:
maxOffsetChange = maxOffsetChange + 3;
break;
// Instructions that might be rewritten by this method as a
// conditional branch followed by an unconditional branch.
// The unconditional branch would require five bytes.
case Constants.IF_ACMPEQ:
case Constants.IF_ACMPNE:
case Constants.IF_ICMPEQ:
case Constants.IF_ICMPGE:
case Constants.IF_ICMPGT:
case Constants.IF_ICMPLE:
case Constants.IF_ICMPLT:
case Constants.IF_ICMPNE:
case Constants.IFEQ:
case Constants.IFGE:
case Constants.IFGT:
case Constants.IFLE:
case Constants.IFLT:
case Constants.IFNE:
case Constants.IFNONNULL:
case Constants.IFNULL:
maxOffsetChange = maxOffsetChange + 5;
break;
}
}
// Now that the maximum number of bytes by which the method might grow
// has been determined, look for conditional branches to see which
// might possibly exceed the 16-bit relative offset.
for (InstructionHandle ih = il.getStart();
ih != null;
ih = ih.getNext()) {
Instruction inst = ih.getInstruction();
if (inst instanceof IfInstruction) {
IfInstruction oldIfInst = (IfInstruction)inst;
BranchHandle oldIfHandle = (BranchHandle)ih;
InstructionHandle target = oldIfInst.getTarget();
int relativeTargetOffset = target.getPosition()
- oldIfHandle.getPosition();
// Consider the worst case scenario in which the conditional
// branch and its target are separated by all the instructions
// in the method that might increase in size. If that results
// in a relative offset that cannot be represented as a 32-bit
// signed quantity, rewrite the instruction as described above.
if ((relativeTargetOffset - maxOffsetChange
< MIN_BRANCH_TARGET_OFFSET)
|| (relativeTargetOffset + maxOffsetChange
> MAX_BRANCH_TARGET_OFFSET)) {
// Invert the logic of the IF instruction, and append
// that to the InstructionList following the original IF
// instruction
InstructionHandle nextHandle = oldIfHandle.getNext();
IfInstruction invertedIfInst = oldIfInst.negate();
BranchHandle invertedIfHandle = il.append(oldIfHandle,
invertedIfInst);
// Append an unconditional branch to the target of the
// original IF instruction after the new IF instruction
BranchHandle gotoHandle = il.append(invertedIfHandle,
new GOTO(target));
// If the original IF was the last instruction in
// InstructionList, add a new no-op to act as the target
// of the new IF
if (nextHandle == null) {
nextHandle = il.append(gotoHandle, NOP);
}
// Make the new IF instruction branch around the GOTO
invertedIfHandle.updateTarget(target, nextHandle);
// If anything still "points" to the old IF instruction,
// make adjustments to refer to either the new IF or GOTO
// instruction
if (oldIfHandle.hasTargeters()) {
InstructionTargeter[] targeters =
oldIfHandle.getTargeters();
for (int i = 0; i < targeters.length; i++) {
InstructionTargeter targeter = targeters[i];
// Ideally, one should simply be able to use
// InstructionTargeter.updateTarget to change
// references to the old IF instruction to the new
// IF instruction. However, if a LocalVariableGen
// indicated the old IF marked the end of the range
// in which the IF variable is in use, the live
// range of the variable must extend to include the
// newly created GOTO instruction. The need for
// this sort of specific knowledge of an
// implementor of the InstructionTargeter interface
// makes the code more fragile. Future implementors
// of the interface might have similar requirements
// which wouldn't be accommodated seemlessly.
if (targeter instanceof LocalVariableGen) {
LocalVariableGen lvg =
(LocalVariableGen) targeter;
if (lvg.getStart() == oldIfHandle) {
lvg.setStart(invertedIfHandle);
} else if (lvg.getEnd() == oldIfHandle) {
lvg.setEnd(gotoHandle);
}
} else {
targeter.updateTarget(oldIfHandle,
invertedIfHandle);
}
}
}
try {
il.delete(oldIfHandle);
} catch (TargetLostException tle) {
// This can never happen - we updated the list of
// instructions that target the deleted instruction
// prior to deleting it.
String msg =
new ErrorMsg(ErrorMsg.OUTLINE_ERR_DELETED_TARGET,
tle.getMessage()).toString();
throw new InternalError(msg);
}
// Adjust the pointer in the InstructionList to point after
// the newly inserted IF instruction
ih = gotoHandle;
// Indicate that this method rewrote at least one IF
ilChanged = true;
}
}
}
// Did this method rewrite any IF instructions?
return ilChanged;
}