com.adrninistrator.javacg.util.JavaCGInstructionUtil Maven / Gradle / Ivy
package com.adrninistrator.javacg.util;
import com.adrninistrator.javacg.dto.method.JavaCGMethodInfo;
import org.apache.bcel.Const;
import org.apache.bcel.generic.BranchInstruction;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.INVOKEDYNAMIC;
import org.apache.bcel.generic.IndexedInstruction;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.Type;
import org.apache.bcel.generic.TypedInstruction;
import java.util.ArrayList;
import java.util.List;
/**
* @author adrninistrator
* @date 2022/10/19
* @description:
*/
public class JavaCGInstructionUtil {
// goto及return类指令的opcode
public static final short[] GOTO_RETURN_OPCODES;
static {
List gotoReturnOpcodeList = new ArrayList<>();
gotoReturnOpcodeList.add(Const.GOTO);
gotoReturnOpcodeList.add(Const.GOTO_W);
for (short opCode = Const.IRETURN; opCode <= Const.RETURN; opCode++) {
gotoReturnOpcodeList.add(opCode);
}
GOTO_RETURN_OPCODES = new short[gotoReturnOpcodeList.size()];
for (int i = 0; i < gotoReturnOpcodeList.size(); i++) {
GOTO_RETURN_OPCODES[i] = gotoReturnOpcodeList.get(i);
}
}
/**
* 判断是否为方法调用类指令
*
* @param opCode
* @return
*/
public static boolean isMethodInvokeInstruction(short opCode) {
return opCode >= Const.INVOKEVIRTUAL && opCode <= Const.INVOKEDYNAMIC;
}
/**
* 判断是否为方法调用类指令,排除INVOKEDYNAMIC
*
* @param opCode
* @return
*/
public static boolean isMethodInvokeInstructionExcludeDynamic(short opCode) {
return opCode >= Const.INVOKEVIRTUAL && opCode <= Const.INVOKEINTERFACE;
}
/**
* 判断是否为if类指令
*
* @param opCode
* @return
*/
public static boolean isIfInstruction(int opCode) {
return (opCode >= Const.IFEQ && opCode <= Const.IF_ACMPNE) ||
opCode == Const.IFNULL ||
opCode == Const.IFNONNULL;
}
/**
* 判断是否为switch类指令
*
* @param opCode
* @return
*/
public static boolean isSwitchInstruction(int opCode) {
return opCode == Const.TABLESWITCH || opCode == Const.LOOKUPSWITCH;
}
/**
* 判断是否为goto类指令
*
* @param opCode
* @return
*/
public static boolean isGotoInstruction(int opCode) {
return opCode == Const.GOTO || opCode == Const.GOTO_W;
}
/**
* 判断是否为return或throw类指令
*
* @param opCode
* @return
*/
public static boolean isExitInstruction(int opCode) {
return (opCode >= Const.IRETURN && opCode <= Const.RETURN) ||
opCode == Const.ATHROW;
}
/**
* 判断是否为jsr类指令
*
* @param opCode
* @return
*/
public static boolean isJsrInstruction(int opCode) {
return opCode == Const.JSR || opCode == Const.JSR_W;
}
/**
* 判断是否为ret指令
*
* @param opCode
* @return
*/
public static boolean isRetInstruction(int opCode) {
return opCode == Const.RET;
}
/**
* 判断是否为return类指令
*
* @param opCode
* @return
*/
public static boolean isReturnInstruction(int opCode) {
return opCode >= Const.IRETURN && opCode <= Const.RETURN;
}
/**
* 判断是否为带返回值的return类指令
*
* @param opCode
* @return
*/
public static boolean isReturnWithValueInstruction(int opCode) {
return opCode >= Const.IRETURN && opCode <= Const.ARETURN;
}
/**
* 获取指令用于打印的信息
*
* @param ih
* @return
*/
public static String getInstructionHandlePrintInfo(InstructionHandle ih) {
Instruction instruction = ih.getInstruction();
String extra = "";
if (instruction instanceof IndexedInstruction) {
extra = " " + ((IndexedInstruction) instruction).getIndex();
} else if (instruction instanceof BranchInstruction) {
extra = " " + ((BranchInstruction) instruction).getTarget().getPosition();
}
return "[" + ih.getPosition() + "] " + instruction.getClass().getSimpleName() + extra;
}
/**
* 获取方法第一个InstructionHandle
*
* @param mg
* @return
*/
public static InstructionHandle getFirstInstructionHandle(MethodGen mg) {
InstructionList instructionList = mg.getInstructionList();
if (instructionList == null || instructionList.isEmpty()) {
return null;
}
return instructionList.getStart();
}
/**
* 根据方法调用指令获取被调用方法信息(不处理INVOKEDYNAMIC指令)
*
* @param invokeInstruction
* @param cpg
* @return
*/
public static JavaCGMethodInfo getCalleeMethodInfo(InvokeInstruction invokeInstruction, ConstantPoolGen cpg) {
String calleeMethodName = invokeInstruction.getMethodName(cpg);
Type[] calleeArgTypes = invokeInstruction.getArgumentTypes(cpg);
if (invokeInstruction instanceof INVOKEDYNAMIC) {
// getReferenceType()方法获取到的类型为java.lang.Object
String calleeClassName = JavaCGInstructionUtil.getTypeString(invokeInstruction, cpg);
return new JavaCGMethodInfo(calleeClassName, calleeMethodName, calleeArgTypes, invokeInstruction.getReturnType(cpg));
}
String calleeClassName = invokeInstruction.getReferenceType(cpg).toString();
return new JavaCGMethodInfo(calleeClassName, calleeMethodName, calleeArgTypes, invokeInstruction.getReturnType(cpg));
}
/**
* 从指定的指令开始往后找,找到第一个为指定类型的指令,到指定的结束指令为止
*
* @param startPosition
* @param endPosition
* @param opCodes
* @return
*/
public static InstructionHandle findFirstIhBetween(InstructionList instructionList, int startPosition, int endPosition, short... opCodes) {
InstructionHandle startIh = instructionList.findHandle(startPosition);
if (startIh == null) {
return null;
}
InstructionHandle currentIh = startIh;
do {
short currentOpCode = currentIh.getInstruction().getOpcode();
for (short opCode : opCodes) {
if (opCode == currentOpCode) {
return currentIh;
}
}
currentIh = currentIh.getNext();
} while (currentIh != null && currentIh.getPosition() <= endPosition);
return null;
}
/**
* 从指定的指令开始往前找,找到第一个为指定类型的指令
*
* @param ih
* @param opCodes
* @return
*/
public static InstructionHandle findLastIh(InstructionHandle ih, short... opCodes) {
InstructionHandle currentIh = ih;
do {
short currentOpCode = currentIh.getInstruction().getOpcode();
for (short opCode : opCodes) {
if (opCode == currentOpCode) {
return currentIh;
}
}
currentIh = currentIh.getPrev();
} while (currentIh != null);
return null;
}
/**
* 获取指定偏移量对应的指定的前一个指令的偏移量
*
* @param instructionList
* @param position
* @return
*/
public static int getInstructionPositionBefore(InstructionList instructionList, int position) {
InstructionHandle instructionHandle = instructionList.findHandle(position).getPrev();
return instructionHandle.getPosition();
}
/**
* 获取指令对应的类型字符串
*
* @param typedInstruction
* @param cpg
* @return
*/
public static String getTypeString(TypedInstruction typedInstruction, ConstantPoolGen cpg) {
return typedInstruction.getType(cpg).toString();
}
private JavaCGInstructionUtil() {
throw new IllegalStateException("illegal");
}
}