?? methodrewriter.java
字號:
*/
private void inlineSubroutines()
throws AnalyzerException
{
// Set up the first instruction region to be
// processed as the entire method code...
Region methodRegion = new Region(0, srcMethod.instructions.size());
// Scan through the instructions in the method and
// get organized
createSubroutineMap();
sortTryCatchBlocks(methodRegion);
// Copy the non-code information
updatedMethod = copyMethodMetadata(srcMethod);
// Set up some mapping information
lineNumberMap = createLineNumberMap();
localVariableByStartLabelMap = createLocalVariableMap();
// Copy the instructions while inlining subroutines
copyRegion(updatedMethod, methodRegion);
// The WTK reduces the visibility of the local variables
if (shouldReduceVariableVisibility(updatedMethod)) {
List instructions = updatedMethod.instructions;
int instructionCount = instructions.size();
AbstractInsnNode lastLabel =
(AbstractInsnNode) instructions.remove(instructionCount - 1);
instructions.add(instructionCount - 2, lastLabel);
}
updatedMethod.visitMaxs(srcMethod.maxStack, srcMethod.maxLocals);
}
/**
* Add a new local variabled to the variables by end label map.
*
* @param newLocalVariable
*/
private void addNewLocalVariableByEnd(LocalVariableNode newLocalVariable) {
ArrayList endLocalVariables =
(ArrayList) localVariableByEndLabelMap.get(newLocalVariable.end);
if (endLocalVariables == null) {
endLocalVariables = new ArrayList();
localVariableByEndLabelMap.put(newLocalVariable.end, endLocalVariables);
}
endLocalVariables.add(newLocalVariable);
}
/**
* Add a new stack map type.
*
* @param localOrStack
* @param region
* @param label
* @param value
*/
private void addStackMapType(List localOrStack, Label label, Value value) {
BasicValue basicValue = (BasicValue) value;
if (this == BasicValue.UNINITIALIZED_VALUE) {
localOrStack.add(newStackMapType(label, StackMapType.ITEM_Uninitialized));
} else {
Type valueType = basicValue.getType();
if (valueType == null) {
localOrStack.add(newStackMapType(label, StackMapType.ITEM_Top));
} else {
switch (valueType.getSort()) {
case Type.BOOLEAN:
case Type.BYTE:
case Type.CHAR:
case Type.INT:
case Type.SHORT:
localOrStack.add(newStackMapType(label, StackMapType.ITEM_Integer));
break;
case Type.DOUBLE:
localOrStack.add(newStackMapType(label, StackMapType.ITEM_Double));
localOrStack.add(newStackMapType(label, StackMapType.ITEM_Top));
break;
case Type.FLOAT:
localOrStack.add(newStackMapType(label, StackMapType.ITEM_Float));
break;
case Type.LONG:
localOrStack.add(newStackMapType(label, StackMapType.ITEM_Long));
localOrStack.add(newStackMapType(label, StackMapType.ITEM_Top));
break;
case Type.OBJECT:
{
StackMapType mapType = null;
String typeName = valueType.getInternalName();
if (typeName.equals("null")) {
mapType = newStackMapType(label, StackMapType.ITEM_Null);
} else {
mapType = newStackMapType(label, StackMapType.ITEM_Object);
mapType.setObject(typeName);
}
localOrStack.add(mapType);
break;
}
case Type.ARRAY:
{
StackMapType mapType = newStackMapType(label, StackMapType.ITEM_Object);
mapType.setObject(valueType.toString());
localOrStack.add(mapType);
break;
}
}
}
}
}
/**
* Copy all of the try/catch blocks in the method, realigning based on
* the rewritten code.
*
* @param methodNode
* @param methodRegion
*/
private void copyTryCatchBlocks(MethodNode methodNode, Region region, List blocks) {
Iterator tryCatchBlocks = blocks.iterator();
while (tryCatchBlocks.hasNext()) {
TryCatchBlockNode tryCatch = (TryCatchBlockNode) tryCatchBlocks.next();
if (shouldCopy(tryCatch)) {
methodNode.visitTryCatchBlock(
region.getMappedLabel(tryCatch.start),
region.getMappedLabel(tryCatch.end),
region.getMappedLabel(tryCatch.handler),
tryCatch.type);
}
}
}
/**
* Create a mapping from line number location (Label) to the instance
* of the line number nodes.
*
* @return
*/
private Map createLineNumberMap() {
Map map = new HashMap();
Iterator lineNumbers = srcMethod.lineNumbers.iterator();
while (lineNumbers.hasNext()) {
LineNumberNode lineNumber = (LineNumberNode) lineNumbers.next();
map.put(lineNumber.start, lineNumber);
}
return map;
}
/**
* Create a mapping from local variable location (Label) to the instance
* of the local variable nodes.
*
* @return
*/
private Map createLocalVariableMap() {
Map map = new HashMap();
Iterator localVariables = srcMethod.localVariables.iterator();
while (localVariables.hasNext()) {
LocalVariableNode localVariable = (LocalVariableNode) localVariables.next();
ArrayList startList = (ArrayList) map.get(localVariable.start);
if (startList == null) {
startList = new ArrayList();
map.put(localVariable.start, startList);
}
startList.add(localVariable);
}
return map;
}
/**
* Copy the method node's metadata that is not changing.
*
* @param method
* @return
*/
private MethodNode copyMethodMetadata(MethodNode method) {
// Start a new method node
String[] exceptions =
(String[]) method.exceptions.toArray(new String[method.exceptions.size()]);
return new MethodNode(
method.access,
method.name,
method.desc,
method.signature,
exceptions);
}
/**
* Copy the specified region of code potentially recursively.
*
* @param method
* @param region
* @throws AnalyzerException
*/
private void copyRegion(MethodNode method, Region region)
throws AnalyzerException
{
// Do any region-specific setup
region.enter(method);
// Walk the instructions.. inlining as we go
for (int index = region.startIndex; index < region.endIndex; ++index) {
AbstractInsnNode insnNode = getInstruction(srcMethod, index);
// Special case for labels, as they may indicate the start of
// a subroutine that can be skipped.
if (insnNode.getType() == AbstractInsnNode.LABEL) {
Label label = ((LabelNode) insnNode).label;
visitLabel(method, region, label);
if (isSubroutineStart(label)) {
// Skip over this subroutine implementation
Subroutine subroutine = (Subroutine) subroutineMap.get(label);
index = subroutine.endIndex;
}
} else {
if (!region.isSubroutineReturnStore(srcMethod, index)) {
visitInstruction(method, region, insnNode);
}
}
}
// Do any region-specific cleanup
region.exit(method);
}
/**
* Create a new stack map frame.
*
* @param region
* @param label
* @param frame
* @return
* @throws AnalyzerException
*/
private StackMapFrame newStackMapFrame(Label label, Frame frame)
throws AnalyzerException
{
// Handle the locals
ArrayList locals = new ArrayList();
int localsCount = frame.getLocals();
for (int i = 0; i < localsCount; i++) {
addStackMapType(locals, label, frame.getLocal(i));
}
removeTrailingTops(locals);
// Handle the stack
ArrayList stack = new ArrayList();
int stackCount = frame.getStackSize();
for (int i = 0; i < stackCount; i++) {
addStackMapType(stack, label, frame.getStack(i));
}
removeTrailingTops(stack);
return new StackMapFrame(label, locals, stack);
}
/**
* Create a new StackMapType instance for the specified label.
*
* @param label
* @param typeCode
* @return
*/
private StackMapType newStackMapType(Label label, int typeCode) {
StackMapType type = StackMapType.getTypeInfo(typeCode);
type.setLabel(label);
return type;
}
/**
* Remove the trailing TOP types from the specified locals or stack.
*
* @param locals
*/
private void removeTrailingTops(ArrayList localsOrStack) {
while (removeTrailingTop(localsOrStack)) { }
}
/**
* Remove the trailing TOP value from the list.
*
* @param localsOrStack
* @return
*/
private boolean removeTrailingTop(ArrayList localsOrStack) {
boolean removed = false;
if (localsOrStack.size() > 0) {
int lastIndex = localsOrStack.size() - 1;
StackMapType type = (StackMapType) localsOrStack.get(lastIndex);
if (type.getType() == StackMapType.ITEM_Top) {
localsOrStack.remove(lastIndex);
removed = true;
}
}
return removed;
}
/**
* Scan the instructions in the source method and find
* the subroutines and locations of any target labels.
*
* @param method
* @throws AnalyzerException
*/
private void createSubroutineMap()
throws AnalyzerException
{
subroutineMap = new HashMap();
// Look through the JSR instructions and collect the
// target labels. Those target labels are the starting
// points for the subroutines.
Set subroutineStartLabels = new HashSet();
Iterator jsrInstructionIndices = srcMethod.getJsrInstructionIndices().iterator();
while (jsrInstructionIndices.hasNext()) {
Integer instructionIndex = (Integer) jsrInstructionIndices.next();
JumpInsnNode jumpNode =
(JumpInsnNode) getInstruction(srcMethod, instructionIndex.intValue());
subroutineStartLabels.add(jumpNode.label);
}
// Now, start searching for the subroutine starts. This
// must be done to account for nested subroutine implementations
if (subroutineStartLabels.size() > 0) {
for (int i = 0; i < srcMethod.instructions.size(); i++) {
AbstractInsnNode insnNode = getInstruction(srcMethod, i);
if (insnNode.getType() == AbstractInsnNode.LABEL) {
LabelNode labelNode = (LabelNode) insnNode;
if (subroutineStartLabels.contains(labelNode.label)) {
// This is the start of a subroutine
i = captureSubroutine(
subroutineStartLabels,
subroutineMap,
i,
srcMethod,
(LabelNode) insnNode);
}
}
}
}
}
/**
* Capture the specified subroutine, potentially recursively
* capturing nested subroutines. Captured subroutines are
* added to the map of subroutines.
*
* @param subroutineStartLabels
* @param subroutineMap
* @param index
* @param method
* @param labelNode
* @return
*/
private int captureSubroutine(
Set subroutineStartLabels,
Map subroutineMap,
int index,
MethodNode method,
LabelNode labelNode)
{
Subroutine subroutine = new Subroutine(labelNode.label);
subroutine.startIndex = index + 1;
for (subroutine.endIndex = subroutine.startIndex; true; subroutine.endIndex++)
{
AbstractInsnNode insn = getInstruction(method, subroutine.endIndex);
if (insn.getType() == AbstractInsnNode.LABEL) {
Label label = ((LabelNode) insn).label;
if (subroutineStartLabels.contains(label)) {
subroutine.endIndex = captureSubroutine(
subroutineStartLabels,
subroutineMap,
subroutine.endIndex,
srcMethod,
(LabelNode) insn);
} else {
subroutine.addLabel(label);
}
} else {
if (insn.getOpcode() == Opcodes.RET) {
// Figure out the variable that is being used
// for the return instruction
VarInsnNode varInsnNode = (VarInsnNode) insn;
int variableNumber = varInsnNode.var;
subroutine.setReturnVariable(variableNumber);
break;
}
}
}
// Add the newly found subroutine to the map
Label label = labelNode.label;
if (!subroutineMap.containsKey(label)) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -