// generate the code to perform the necessary copying, and
// use localVarMap to map the variable in the original
// method to the variable in the new method.
IndexedInstruction lvi = (IndexedInstruction)c;
int oldLocalVarIndex = lvi.getIndex();
LocalVariableGen oldLVG =
getLocalVariableRegistry()
.lookupRegisteredLocalVariable(oldLocalVarIndex,
ih.getPosition());
LocalVariableGen newLVG =
(LocalVariableGen)localVarMap.get(oldLVG);
// Has the code already mapped this local variable to a
// local in the new method?
if (localVarMap.get(oldLVG) == null) {
// Determine whether the local variable needs to be
// copied into or out of the outlined by checking
// whether the range of instructions in which the
// variable is accessible is outside the range of
// instructions in the outlineable chunk.
// Special case a chunk start offset of zero: a local
// variable live at that position must be a method
// parameter, so the code doesn't need to check whether
// the variable is live before that point; being live
// at offset zero is sufficient to know that the value
// must be copied in to the outlined method.
boolean copyInLocalValue =
offsetInLocalVariableGenRange(oldLVG,
(outlineChunkStartOffset != 0)
? outlineChunkStartOffset-1
: 0);
boolean copyOutLocalValue =
offsetInLocalVariableGenRange(oldLVG,
outlineChunkEndOffset+1);
// For any variable that needs to be copied into or out
// of the outlined method, create a field in the
// CopyLocals class, and generate the necessary code for
// copying the value.
if (copyInLocalValue || copyOutLocalValue) {
String varName = oldLVG.getName();
Type varType = oldLVG.getType();
newLVG = outlinedMethodGen.addLocalVariable(varName,
varType,
null,
null);
int newLocalVarIndex = newLVG.getIndex();
String varSignature = varType.getSignature();
// Record the mapping from the old local to the new
localVarMap.put(oldLVG, newLVG);
copyAreaFieldCount++;
String copyAreaFieldName =
"field" + copyAreaFieldCount;
copyAreaCG.addField(
new Field(ACC_PUBLIC,
copyAreaCPG.addUtf8(copyAreaFieldName),
copyAreaCPG.addUtf8(varSignature),
null, copyAreaCPG.getConstantPool()));
int fieldRef = cpg.addFieldref(argTypeName,
copyAreaFieldName,
varSignature);
if (copyInLocalValue) {
// Generate code for the old method to store the
// value of the local into the correct field in
// CopyLocals prior to invocation of the
// outlined method.
oldMethCopyInIL.append(
InstructionConstants.DUP);
InstructionHandle copyInLoad =
oldMethCopyInIL.append(
loadLocal(oldLocalVarIndex, varType));
oldMethCopyInIL.append(new PUTFIELD(fieldRef));
// If the end of the live range of the old
// variable was in the middle of the outlined
// chunk. Make the load of its value the new
// end of its range.
if (!copyOutLocalValue) {
revisedLocalVarEnd.put(oldLVG, copyInLoad);
}
// Generate code for start of the outlined
// method to copy the value from a field in
// CopyLocals to the new local in the outlined
// method
newMethCopyInIL.append(
InstructionConstants.ALOAD_1);
newMethCopyInIL.append(new GETFIELD(fieldRef));
newMethCopyInIL.append(
storeLocal(newLocalVarIndex, varType));
}
if (copyOutLocalValue) {
// Generate code for the end of the outlined
// method to copy the value from the new local
// variable into a field in CopyLocals
// method
newMethCopyOutIL.append(
InstructionConstants.ALOAD_1);
newMethCopyOutIL.append(
loadLocal(newLocalVarIndex, varType));
newMethCopyOutIL.append(new PUTFIELD(fieldRef));
// Generate code to copy the value from a field
// in CopyLocals into a local in the original
// method following invocation of the outlined
// method.
oldMethCopyOutIL.append(
InstructionConstants.DUP);
oldMethCopyOutIL.append(new GETFIELD(fieldRef));
InstructionHandle copyOutStore =
oldMethCopyOutIL.append(
storeLocal(oldLocalVarIndex, varType));
// If the start of the live range of the old
// variable was in the middle of the outlined
// chunk. Make this store into it the new start
// of its range.
if (!copyInLocalValue) {
revisedLocalVarStart.put(oldLVG,
copyOutStore);
}
}
}
}
}
if (ih.hasTargeters()) {
targetMap.put(ih, lastCopyHandle);
}
// If this is the first instruction copied following a sequence
// of OutlineableChunkStart instructions, indicate that the
// sequence of old instruction all map to this newly created
// instruction
if (chunkStartTargetMappingsPending) {
do {
targetMap.put(pendingTargetMappingHandle,
lastCopyHandle);
pendingTargetMappingHandle =
pendingTargetMappingHandle.getNext();
} while(pendingTargetMappingHandle != ih);
chunkStartTargetMappingsPending = false;
}
}
}
// Pass 2: Walk old and new instruction lists, updating branch targets
// and local variable references in the new list
InstructionHandle ih = first;
InstructionHandle ch = newIL.getStart();
while (ch != null) {
// i == old instruction; c == copied instruction
Instruction i = ih.getInstruction();
Instruction c = ch.getInstruction();
if (i instanceof BranchInstruction) {
BranchInstruction bc = (BranchInstruction)c;
BranchInstruction bi = (BranchInstruction)i;
InstructionHandle itarget = bi.getTarget(); // old target
// New target must be in targetMap
InstructionHandle newTarget =
(InstructionHandle)targetMap.get(itarget);
bc.setTarget(newTarget);
// Handle LOOKUPSWITCH or TABLESWITCH which may have many
// target instructions
if (bi instanceof Select) {
InstructionHandle[] itargets = ((Select)bi).getTargets();
InstructionHandle[] ctargets = ((Select)bc).getTargets();
// Update all targets
for (int j=0; j < itargets.length; j++) {
ctargets[j] =
(InstructionHandle)targetMap.get(itargets[j]);
}
}
} else if (i instanceof LocalVariableInstruction
|| i instanceof RET) {
// For any instruction that touches a local variable,
// map the location of the variable in the original
// method to its location in the new method.
IndexedInstruction lvi = (IndexedInstruction)c;
int oldLocalVarIndex = lvi.getIndex();
LocalVariableGen oldLVG =
getLocalVariableRegistry()
.lookupRegisteredLocalVariable(oldLocalVarIndex,
ih.getPosition());
LocalVariableGen newLVG =
(LocalVariableGen)localVarMap.get(oldLVG);
int newLocalVarIndex;
if (newLVG == null) {
// Create new variable based on old variable - use same
// name and type, but we will let the variable be active
// for the entire outlined method.
// LocalVariableGen oldLocal = oldLocals[oldLocalVarIndex];
String varName = oldLVG.getName();
Type varType = oldLVG.getType();
newLVG = outlinedMethodGen.addLocalVariable(varName,
varType,
null,
null);
newLocalVarIndex = newLVG.getIndex();
localVarMap.put(oldLVG, newLVG);
// The old variable's live range was wholly contained in
// the outlined chunk. There should no longer be stores
// of values into it or loads of its value, so we can just
// mark its live range as the reference to the outlined
// method.
revisedLocalVarStart.put(oldLVG, outlinedMethodRef);
revisedLocalVarEnd.put(oldLVG, outlinedMethodRef);
} else {
newLocalVarIndex = newLVG.getIndex();
}
lvi.setIndex(newLocalVarIndex);
}
// If the old instruction marks the end of the range of a local
// variable, make sure that any slots on the stack reserved for
// local variables are made available for reuse by calling
// MethodGenerator.removeLocalVariable
if (ih.hasTargeters()) {
InstructionTargeter[] targeters = ih.getTargeters();
for (int idx = 0; idx < targeters.length; idx++) {
InstructionTargeter targeter = targeters[idx];
if (targeter instanceof LocalVariableGen
&& ((LocalVariableGen)targeter).getEnd()==ih) {
Object newLVG = localVarMap.get(targeter);
if (newLVG != null) {
outlinedMethodGen.removeLocalVariable(
(LocalVariableGen)newLVG);
}
}
}
}
// If the current instruction in the original list was a marker,
// it wasn't copied, so don't advance through the list of copied
// instructions yet.
if (!(i instanceof MarkerInstruction)) {
ch = ch.getNext();
}
ih = ih.getNext();
}
// POP the reference to the CopyLocals object from the stack
oldMethCopyOutIL.append(InstructionConstants.POP);
// Now that the generation of the outlined code is complete, update
// the old local variables with new start and end ranges, as required.
Iterator revisedLocalVarStartPairIter = revisedLocalVarStart.entrySet()
.iterator();
while (revisedLocalVarStartPairIter.hasNext()) {
Map.Entry lvgRangeStartPair =
(Map.Entry)revisedLocalVarStartPairIter.next();
LocalVariableGen lvg = (LocalVariableGen)lvgRangeStartPair.getKey();
InstructionHandle startInst =
(InstructionHandle)lvgRangeStartPair.getValue();
lvg.setStart(startInst);
}
Iterator revisedLocalVarEndPairIter = revisedLocalVarEnd.entrySet()
.iterator();
while (revisedLocalVarEndPairIter.hasNext()) {
Map.Entry lvgRangeEndPair =
(Map.Entry)revisedLocalVarEndPairIter.next();
LocalVariableGen lvg = (LocalVariableGen)lvgRangeEndPair.getKey();
InstructionHandle endInst =
(InstructionHandle)lvgRangeEndPair.getValue();
lvg.setEnd(endInst);
}
xsltc.dumpClass(copyAreaCG.getJavaClass());
// Assemble the instruction lists so that the old method invokes the
// new outlined method
InstructionList oldMethodIL = getInstructionList();
oldMethodIL.insert(first, oldMethCopyInIL);
oldMethodIL.insert(first, oldMethCopyOutIL);
// Insert the copying code into the outlined method
newIL.insert(newMethCopyInIL);
newIL.append(newMethCopyOutIL);
newIL.append(InstructionConstants.RETURN);
// Discard instructions in outlineable chunk from old method
try {
oldMethodIL.delete(first, last);
} catch (TargetLostException e) {
InstructionHandle[] targets = e.getTargets();
// If there were still references to old instructions lingering,
// clean those up. The only instructions targetting the deleted
// instructions should have been part of the chunk that was just
// deleted, except that instructions might branch to the start of
// the outlined chunk; similarly, all the live ranges of local
// variables should have been adjusted, except for unreferenced
// variables.
for (int i = 0; i < targets.length; i++) {
InstructionHandle lostTarget = targets[i];
InstructionTargeter[] targeters = lostTarget.getTargeters();
for (int j = 0; j < targeters.length; j++) {
if (targeters[j] instanceof LocalVariableGen) {
LocalVariableGen lvgTargeter =
(LocalVariableGen) targeters[j];
// In the case of any lingering variable references,
// just make the live range point to the outlined
// function reference. Such variables should be unused
// anyway.
if (lvgTargeter.getStart() == lostTarget) {
lvgTargeter.setStart(outlinedMethodRef);
}
if (lvgTargeter.getEnd() == lostTarget) {
lvgTargeter.setEnd(outlinedMethodRef);
}
} else {
targeters[j].updateTarget(lostTarget,
outlinedMethodCallSetup);
}