// variables first so that they can have fixed slots in the stack
// frame for the outlined method assigned them ahead of all those
// variables that don't need to exist for the entirety of the outlined
// method invocation.
for (InstructionHandle ih = first; ih != limit; ih = ih.getNext()) {
Instruction inst = ih.getInstruction();
// MarkerInstructions are not copied, so if something else targets
// one, the targetMap will point to the nearest copied sibling
// InstructionHandle: for an OutlineableChunkEnd, the nearest
// preceding sibling; for an OutlineableChunkStart, the nearest
// following sibling.
if (inst instanceof MarkerInstruction) {
if (ih.hasTargeters()) {
if (inst instanceof OutlineableChunkEnd) {
targetMap.put(ih, lastCopyHandle);
} else {
if (!chunkStartTargetMappingsPending) {
chunkStartTargetMappingsPending = true;
pendingTargetMappingHandle = ih;
}
}
}
} else {
// Copy the instruction and append it to the outlined method's
// InstructionList.
Instruction c = inst.copy(); // Use clone for shallow copy
if (c instanceof BranchInstruction) {
lastCopyHandle = newIL.append((BranchInstruction)c);
} else {
lastCopyHandle = newIL.append(c);
}
if (c instanceof LocalVariableInstruction
|| c instanceof RET) {
// For any instruction that touches a local variable,
// 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