// check whether the local variable's value needs to be
// copied into or out of the outlined method. If so,
// 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