Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.adrninistrator.javacg.handler.InstructionHandler Maven / Gradle / Ivy
package com.adrninistrator.javacg.handler;
import com.adrninistrator.javacg.common.JavaCGCommonNameConstants;
import com.adrninistrator.javacg.common.JavaCGConstants;
import com.adrninistrator.javacg.common.enums.JavaCGConstantTypeEnum;
import com.adrninistrator.javacg.dto.element.BaseElement;
import com.adrninistrator.javacg.dto.element.constant.ConstElementDouble;
import com.adrninistrator.javacg.dto.element.constant.ConstElementFloat;
import com.adrninistrator.javacg.dto.element.constant.ConstElementInt;
import com.adrninistrator.javacg.dto.element.constant.ConstElementLong;
import com.adrninistrator.javacg.dto.element.constant.ConstElementNull;
import com.adrninistrator.javacg.dto.element.constant.ConstElementString;
import com.adrninistrator.javacg.dto.element.variable.FieldElement;
import com.adrninistrator.javacg.dto.element.variable.JSRElement;
import com.adrninistrator.javacg.dto.element.variable.LocalVariableElement;
import com.adrninistrator.javacg.dto.element.variable.StaticFieldElement;
import com.adrninistrator.javacg.dto.element.variable.StaticFieldMethodCallElement;
import com.adrninistrator.javacg.dto.element.variable.VariableElement;
import com.adrninistrator.javacg.dto.field.FieldPossibleTypes;
import com.adrninistrator.javacg.dto.frame.FieldInformation;
import com.adrninistrator.javacg.dto.frame.JavaCGLocalVariables;
import com.adrninistrator.javacg.dto.frame.JavaCGOperandStack;
import com.adrninistrator.javacg.dto.instruction.BaseInstructionParseResult;
import com.adrninistrator.javacg.dto.instruction.MethodCallParseResult;
import com.adrninistrator.javacg.dto.instruction.RetParseResult;
import com.adrninistrator.javacg.dto.instruction.ReturnParseResult;
import com.adrninistrator.javacg.exceptions.JavaCGRuntimeException;
import com.adrninistrator.javacg.util.JavaCGByteCodeUtil;
import com.adrninistrator.javacg.util.JavaCGUtil;
import org.apache.bcel.Const;
import org.apache.bcel.classfile.LocalVariable;
import org.apache.bcel.classfile.LocalVariableTable;
import org.apache.bcel.classfile.Utility;
import org.apache.bcel.generic.ANEWARRAY;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.BIPUSH;
import org.apache.bcel.generic.CHECKCAST;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETFIELD;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.IINC;
import org.apache.bcel.generic.INVOKEDYNAMIC;
import org.apache.bcel.generic.INVOKEINTERFACE;
import org.apache.bcel.generic.INVOKESPECIAL;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.LDC;
import org.apache.bcel.generic.LDC2_W;
import org.apache.bcel.generic.LoadInstruction;
import org.apache.bcel.generic.MULTIANEWARRAY;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.NEW;
import org.apache.bcel.generic.NEWARRAY;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.PUTFIELD;
import org.apache.bcel.generic.PUTSTATIC;
import org.apache.bcel.generic.RET;
import org.apache.bcel.generic.SIPUSH;
import org.apache.bcel.generic.StoreInstruction;
import org.apache.bcel.generic.Type;
import org.apache.bcel.generic.TypedInstruction;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
/**
* @author adrninistrator
* @date 2022/10/16
* @description: 对指令进行处理
*/
public class InstructionHandler {
private final MethodGen mg;
private final ConstantPoolGen cpg;
private final LocalVariableTable localVariableTable;
private JavaCGOperandStack stack;
private JavaCGLocalVariables locals;
private FieldInformation nonStaticFieldInfo;
private FieldInformation staticFieldInfo;
// 解析构造函数以获取非静态字段可能的类型的开关
private boolean recordFieldPossibleTypeFlag;
// 使用已获取的构造函数非静态字段可能的类型的开关
private boolean useFieldPossibleTypeFlag;
// 非静态字段字段所有可能的类型
private FieldPossibleTypes nonStaticFieldPossibleTypes;
public InstructionHandler(MethodGen mg,
LocalVariableTable localVariableTable,
JavaCGOperandStack stack,
JavaCGLocalVariables locals,
FieldInformation nonStaticFieldInfo,
FieldInformation staticFieldInfo) {
this.mg = mg;
this.cpg = mg.getConstantPool();
this.localVariableTable = localVariableTable;
this.stack = stack;
this.locals = locals;
this.nonStaticFieldInfo = nonStaticFieldInfo;
this.staticFieldInfo = staticFieldInfo;
}
private String getTypeString(TypedInstruction typedInstruction) {
return typedInstruction.getType(cpg).toString();
}
public BaseInstructionParseResult parse(InstructionHandle ih) {
Instruction i = ih.getInstruction();
int opCode = i.getOpcode();
BaseInstructionParseResult instructionParseResult = null;
switch (opCode) {
case Const.NOP:
// 什么也不做
break;
case Const.ACONST_NULL:
stack.push(new ConstElementNull());
break;
case Const.ICONST_M1:
case Const.ICONST_0:
case Const.ICONST_1:
case Const.ICONST_2:
case Const.ICONST_3:
case Const.ICONST_4:
case Const.ICONST_5:
stack.push(new ConstElementInt(opCode - Const.ICONST_M1 - 1));
break;
case Const.LCONST_0:
case Const.LCONST_1:
stack.push(new ConstElementLong((long) (opCode - Const.LCONST_0)));
break;
case Const.FCONST_0:
stack.push(new ConstElementFloat(0.0F));
break;
case Const.FCONST_1:
stack.push(new ConstElementFloat(1.0F));
break;
case Const.FCONST_2:
stack.push(new ConstElementFloat(2.0F));
break;
case Const.DCONST_0:
stack.push(new ConstElementDouble(0.0D));
break;
case Const.DCONST_1:
stack.push(new ConstElementDouble(1.0D));
break;
case Const.BIPUSH:
stack.push(new ConstElementInt(((BIPUSH) i).getValue()));
break;
case Const.SIPUSH:
stack.push(new ConstElementInt(((SIPUSH) i).getValue()));
break;
case Const.LDC:
case Const.LDC_W:
handleLDC((LDC) i);
break;
case Const.LDC2_W:
handleLDC2W((LDC2_W) i);
break;
case Const.ILOAD:
case Const.LLOAD:
case Const.FLOAD:
case Const.DLOAD:
case Const.ALOAD:
case Const.ILOAD_0:
case Const.ILOAD_1:
case Const.ILOAD_2:
case Const.ILOAD_3:
case Const.LLOAD_0:
case Const.LLOAD_1:
case Const.LLOAD_2:
case Const.LLOAD_3:
case Const.FLOAD_0:
case Const.FLOAD_1:
case Const.FLOAD_2:
case Const.FLOAD_3:
case Const.DLOAD_0:
case Const.DLOAD_1:
case Const.DLOAD_2:
case Const.DLOAD_3:
case Const.ALOAD_0:
case Const.ALOAD_1:
case Const.ALOAD_2:
case Const.ALOAD_3:
handleLoad((LoadInstruction) i);
break;
case Const.IALOAD:
handleArrayLoad(JavaCGConstantTypeEnum.CONSTTE_INT);
break;
case Const.LALOAD:
handleArrayLoad(JavaCGConstantTypeEnum.CONSTTE_LONG);
break;
case Const.FALOAD:
handleArrayLoad(JavaCGConstantTypeEnum.CONSTTE_FLOAT);
break;
case Const.DALOAD:
handleArrayLoad(JavaCGConstantTypeEnum.CONSTTE_DOUBLE);
break;
case Const.AALOAD:
handleArrayLoad(null, true);
break;
case Const.BALOAD:
handleArrayLoad(JavaCGConstantTypeEnum.CONSTTE_BYTE);
break;
case Const.CALOAD:
handleArrayLoad(JavaCGConstantTypeEnum.CONSTTE_CHAR);
break;
case Const.SALOAD:
handleArrayLoad(JavaCGConstantTypeEnum.CONSTTE_SHORT);
break;
case Const.ISTORE:
case Const.ISTORE_0:
case Const.ISTORE_1:
case Const.ISTORE_2:
case Const.ISTORE_3:
handleStore((StoreInstruction) i, JavaCGConstantTypeEnum.CONSTTE_INT, ih);
break;
case Const.LSTORE:
case Const.LSTORE_0:
case Const.LSTORE_1:
case Const.LSTORE_2:
case Const.LSTORE_3:
handleStore((StoreInstruction) i, JavaCGConstantTypeEnum.CONSTTE_LONG, ih);
break;
case Const.FSTORE:
case Const.FSTORE_0:
case Const.FSTORE_1:
case Const.FSTORE_2:
case Const.FSTORE_3:
handleStore((StoreInstruction) i, JavaCGConstantTypeEnum.CONSTTE_FLOAT, ih);
break;
case Const.DSTORE:
case Const.DSTORE_0:
case Const.DSTORE_1:
case Const.DSTORE_2:
case Const.DSTORE_3:
handleStore((StoreInstruction) i, JavaCGConstantTypeEnum.CONSTTE_DOUBLE, ih);
break;
case Const.ASTORE:
case Const.ASTORE_0:
case Const.ASTORE_1:
case Const.ASTORE_2:
case Const.ASTORE_3:
handleStore((StoreInstruction) i, null, ih);
break;
case Const.IASTORE:
handleArrayStore(JavaCGConstantTypeEnum.CONSTTE_INT);
break;
case Const.LASTORE:
handleArrayStore(JavaCGConstantTypeEnum.CONSTTE_LONG);
break;
case Const.FASTORE:
handleArrayStore(JavaCGConstantTypeEnum.CONSTTE_FLOAT);
break;
case Const.DASTORE:
handleArrayStore(JavaCGConstantTypeEnum.CONSTTE_DOUBLE);
break;
case Const.AASTORE:
handleArrayStore(null, true);
break;
case Const.BASTORE:
handleArrayStore(JavaCGConstantTypeEnum.CONSTTE_BYTE);
break;
case Const.CASTORE:
handleArrayStore(JavaCGConstantTypeEnum.CONSTTE_CHAR);
break;
case Const.SASTORE:
handleArrayStore(JavaCGConstantTypeEnum.CONSTTE_SHORT);
break;
case Const.POP:
stack.pop();
break;
case Const.POP2:
handlePOP2();
break;
case Const.DUP:
handleDUP();
break;
case Const.DUP_X1:
handleDUPX1();
break;
case Const.DUP_X2:
handleDUPX2();
break;
case Const.DUP2:
handleDUP2();
break;
case Const.DUP2_X1:
handleDUP2X1();
break;
case Const.DUP2_X2:
handleDUP2X2();
break;
case Const.SWAP:
handleSWAP();
break;
case Const.IADD:
case Const.ISUB:
case Const.IMUL:
case Const.IDIV:
case Const.IREM:
case Const.IAND:
case Const.IOR:
case Const.IXOR:
handleArithmeticOperation2(JavaCGConstantTypeEnum.CONSTTE_INT);
break;
case Const.LADD:
case Const.LSUB:
case Const.LMUL:
case Const.LDIV:
case Const.LREM:
case Const.LAND:
case Const.LOR:
case Const.LXOR:
handleArithmeticOperation2(JavaCGConstantTypeEnum.CONSTTE_LONG);
break;
case Const.FADD:
case Const.FSUB:
case Const.FMUL:
case Const.FDIV:
case Const.FREM:
handleArithmeticOperation2(JavaCGConstantTypeEnum.CONSTTE_FLOAT);
break;
case Const.DADD:
case Const.DSUB:
case Const.DMUL:
case Const.DDIV:
case Const.DREM:
handleArithmeticOperation2(JavaCGConstantTypeEnum.CONSTTE_DOUBLE);
break;
case Const.INEG:
handleArithmeticOperation1(JavaCGConstantTypeEnum.CONSTTE_INT);
break;
case Const.LNEG:
handleArithmeticOperation1(JavaCGConstantTypeEnum.CONSTTE_LONG);
break;
case Const.FNEG:
handleArithmeticOperation1(JavaCGConstantTypeEnum.CONSTTE_FLOAT);
break;
case Const.DNEG:
handleArithmeticOperation1(JavaCGConstantTypeEnum.CONSTTE_DOUBLE);
break;
case Const.ISHL:
case Const.ISHR:
case Const.IUSHR:
handleBitOperator(JavaCGConstantTypeEnum.CONSTTE_INT);
break;
case Const.LSHL:
case Const.LSHR:
case Const.LUSHR:
handleBitOperator(JavaCGConstantTypeEnum.CONSTTE_LONG);
break;
case Const.IINC:
handleIinc((IINC) i);
break;
case Const.I2L:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_INT, JavaCGConstantTypeEnum.CONSTTE_LONG);
break;
case Const.I2F:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_INT, JavaCGConstantTypeEnum.CONSTTE_FLOAT);
break;
case Const.I2D:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_INT, JavaCGConstantTypeEnum.CONSTTE_DOUBLE);
break;
case Const.L2I:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_LONG, JavaCGConstantTypeEnum.CONSTTE_INT);
break;
case Const.L2F:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_LONG, JavaCGConstantTypeEnum.CONSTTE_FLOAT);
break;
case Const.L2D:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_LONG, JavaCGConstantTypeEnum.CONSTTE_DOUBLE);
break;
case Const.F2I:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_FLOAT, JavaCGConstantTypeEnum.CONSTTE_INT);
break;
case Const.F2L:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_FLOAT, JavaCGConstantTypeEnum.CONSTTE_LONG);
break;
case Const.F2D:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_FLOAT, JavaCGConstantTypeEnum.CONSTTE_DOUBLE);
break;
case Const.D2I:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_DOUBLE, JavaCGConstantTypeEnum.CONSTTE_INT);
break;
case Const.D2L:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_DOUBLE, JavaCGConstantTypeEnum.CONSTTE_LONG);
break;
case Const.D2F:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_DOUBLE, JavaCGConstantTypeEnum.CONSTTE_FLOAT);
break;
case Const.I2B:
case Const.I2C:
case Const.I2S:
handleTypeConversion(JavaCGConstantTypeEnum.CONSTTE_INT, JavaCGConstantTypeEnum.CONSTTE_INT);
break;
case Const.LCMP:
handleCompare(JavaCGConstantTypeEnum.CONSTTE_LONG);
break;
case Const.FCMPL:
case Const.FCMPG:
handleCompare(JavaCGConstantTypeEnum.CONSTTE_FLOAT);
break;
case Const.DCMPL:
case Const.DCMPG:
handleCompare(JavaCGConstantTypeEnum.CONSTTE_DOUBLE);
break;
case Const.IFEQ:
case Const.IFNE:
case Const.IFLT:
case Const.IFGE:
case Const.IFGT:
case Const.IFLE:
handleIf1();
break;
case Const.IF_ICMPEQ:
case Const.IF_ICMPNE:
case Const.IF_ICMPLT:
case Const.IF_ICMPGE:
case Const.IF_ICMPGT:
case Const.IF_ICMPLE:
handleIf2();
break;
case Const.IF_ACMPEQ:
case Const.IF_ACMPNE:
stack.pop();
stack.pop();
break;
case Const.GOTO:
// 操作数栈无变化
break;
case Const.JSR:
handleJSR(ih);
break;
case Const.RET:
instructionParseResult = handleRET((RET) i);
break;
case Const.TABLESWITCH:
case Const.LOOKUPSWITCH:
stack.pop();
break;
case Const.IRETURN:
case Const.LRETURN:
case Const.FRETURN:
case Const.DRETURN:
case Const.ARETURN:
instructionParseResult = handleReturn();
break;
case Const.RETURN:
// 操作数栈无变化
break;
case Const.GETSTATIC:
handleGETSTATIC((GETSTATIC) i);
break;
case Const.PUTSTATIC:
handlePUTSTATIC((PUTSTATIC) i);
break;
case Const.GETFIELD:
handleGETFIELD((GETFIELD) i);
break;
case Const.PUTFIELD:
handlePUTFIELD((PUTFIELD) i);
break;
case Const.INVOKEVIRTUAL:
instructionParseResult = handleMethodInvoke((INVOKEVIRTUAL) i, true);
break;
case Const.INVOKESPECIAL:
instructionParseResult = handleMethodInvoke((INVOKESPECIAL) i, true);
break;
case Const.INVOKESTATIC:
instructionParseResult = handleMethodInvoke((INVOKESTATIC) i, false);
break;
case Const.INVOKEINTERFACE:
instructionParseResult = handleMethodInvoke((INVOKEINTERFACE) i, true);
break;
case Const.INVOKEDYNAMIC:
instructionParseResult = handleMethodInvoke((INVOKEDYNAMIC) i, false);
break;
case Const.NEW:
stack.push(new VariableElement(getTypeString((NEW) i)));
break;
case Const.NEWARRAY:
handleNEWARRAY((NEWARRAY) i);
break;
case Const.ANEWARRAY:
handleANEWARRAY((ANEWARRAY) i);
break;
case Const.ARRAYLENGTH:
stack.pop();
stack.push(new VariableElement(JavaCGConstantTypeEnum.CONSTTE_INT.getType()));
break;
case Const.ATHROW:
handleATHROW();
break;
case Const.CHECKCAST:
stack.pop();
stack.push(new VariableElement(getTypeString((CHECKCAST) i)));
break;
case Const.INSTANCEOF:
stack.pop();
stack.push(new VariableElement(JavaCGConstantTypeEnum.CONSTTE_INT.getType()));
break;
case Const.MONITORENTER:
case Const.MONITOREXIT:
stack.pop();
break;
case Const.WIDE:
// 操作数栈无变化
break;
case Const.MULTIANEWARRAY:
handleMULTIANEWARRAY((MULTIANEWARRAY) i);
break;
case Const.IFNULL:
case Const.IFNONNULL:
stack.pop();
break;
case Const.GOTO_W:
// 操作数栈无变化
break;
case Const.JSR_W:
handleJSR(ih);
break;
default:
System.err.println("eee 未处理的指令 " + opCode + " " + i.getClass().getName());
break;
}
return instructionParseResult;
}
private void handleLDC(LDC ldc) {
String typeString = getTypeString(ldc);
Object value = ldc.getValue(cpg);
if (JavaCGConstantTypeEnum.CONSTTE_INT.getType().equals(typeString)) {
stack.push(new ConstElementInt(value));
} else if (JavaCGConstantTypeEnum.CONSTTE_FLOAT.getType().equals(typeString)) {
stack.push(new ConstElementFloat(value));
} else if (JavaCGCommonNameConstants.CLASS_NAME_STRING.equals(typeString)) {
stack.push(new ConstElementString(value));
} else if (JavaCGCommonNameConstants.CLASS_NAME_CLASS.equals(typeString)) {
ObjectType objectType = (ObjectType) value;
stack.push(new VariableElement(objectType.getClassName()));
} else {
System.err.println("eee LDC 暂不支持的情况 " + typeString + " " + value);
}
}
private void handleLDC2W(LDC2_W ldc2W) {
String typeString = getTypeString(ldc2W);
Object value = ldc2W.getValue(cpg);
if (JavaCGConstantTypeEnum.CONSTTE_LONG.getType().equals(typeString)) {
stack.push(new ConstElementLong(value));
} else if (JavaCGConstantTypeEnum.CONSTTE_DOUBLE.getType().equals(typeString)) {
stack.push(new ConstElementDouble(value));
} else {
System.err.println("eee LDC2_W 暂不支持的情况 " + typeString + " " + value);
}
}
// 处理获取值
private void handleLoad(LoadInstruction loadInstruction) {
int index = loadInstruction.getIndex();
if (locals.size() > index) {
stack.push(locals.get(index));
return;
}
throw new JavaCGRuntimeException("本地变量不存在 " + index);
}
// 处理数组获取值
private void handleArrayLoad(JavaCGConstantTypeEnum typeEnum) {
handleArrayLoad(typeEnum.getType(), false);
}
private void handleArrayLoad(String elementType, boolean isAaload) {
// 出栈,数组索引
BaseElement indexVariable = stack.pop();
// 出栈,数组对象
BaseElement arrayVariable = stack.pop();
String usedElementType;
if (!isAaload) {
usedElementType = elementType;
} else {
String arrayType = arrayVariable.getType();
if (!JavaCGByteCodeUtil.isNullType(arrayType) && !JavaCGByteCodeUtil.isArrayType(arrayType)) {
throw new JavaCGRuntimeException("当前类型不是数组 " + arrayType);
}
usedElementType = JavaCGByteCodeUtil.removeArrayFlag(arrayType);
}
// 入栈,数组元素
stack.push(new VariableElement(usedElementType, true));
indexVariable.checkTypeString(JavaCGConstantTypeEnum.CONSTTE_INT.getType());
if (!isAaload) {
arrayVariable.checkTypeString(JavaCGByteCodeUtil.addArrayFlag(usedElementType));
}
}
// 处理赋值
private void handleStore(StoreInstruction storeInstruction, JavaCGConstantTypeEnum typeEnum, InstructionHandle ih) {
int index = storeInstruction.getIndex();
BaseElement baseElement = stack.pop();
String poppedElementType = baseElement.getType();
if (typeEnum == null) {
// 处理ASTORE指令
if (!JavaCGByteCodeUtil.isNullType(poppedElementType)) {
// 操作数栈中元素类型有值
// 添加本地变量
locals.add(poppedElementType, baseElement, index);
return;
}
}
// 处理非ASTORE指令,或操作数栈中元素类型未获取到值
// 从LocalVariableTable中获取本地变量对应类型
LocalVariable localVariable = localVariableTable.getLocalVariable(index, ih.getNext().getPosition());
String actualType;
if (localVariable != null) {
actualType = Utility.typeSignatureToString(localVariable.getSignature(), false);
} else {
actualType = (typeEnum != null ? typeEnum.getType() : poppedElementType);
}
// 添加本地变量
locals.add(actualType, baseElement, index);
}
// 处理数组赋值
private void handleArrayStore(JavaCGConstantTypeEnum typeEnum) {
handleArrayStore(typeEnum.getType(), false);
}
private void handleArrayStore(String arrayType, boolean isAastore) {
BaseElement valueVariable = stack.pop();
BaseElement indexVariable = stack.pop();
BaseElement arrayVariable = stack.pop();
indexVariable.checkTypeString(JavaCGConstantTypeEnum.CONSTTE_INT.getType());
if (!isAastore) {
valueVariable.checkTypeString(arrayType);
arrayVariable.checkTypeString(JavaCGByteCodeUtil.addArrayFlag(arrayType));
}
if (!arrayVariable.isArrayElement()) {
System.err.println("不是数组类型 " + arrayVariable.getClass().getName());
return;
}
Object indexObj = indexVariable.getValue();
if (indexObj instanceof Integer) {
// 数组赋值的元素下标是常量
Integer index = (Integer) indexObj;
// 记录数组指定下标的元素
arrayVariable.setElement(index, valueVariable);
}
}
private void handlePOP2() {
BaseElement element = stack.pop();
if (element.getElementSize() == 1) {
stack.pop();
}
}
private void handleDUP() {
BaseElement element = stack.pop();
stack.push(element);
stack.push(element);
}
private void handleDUPX1() {
BaseElement element1 = stack.pop();
BaseElement element2 = stack.pop();
stack.push(element1);
stack.push(element2);
stack.push(element1);
}
private void handleDUPX2() {
BaseElement element1 = stack.pop();
BaseElement element2 = stack.pop();
if (element2.getElementSize() == 2) {
stack.push(element1);
stack.push(element2);
stack.push(element1);
return;
}
BaseElement element3 = stack.pop();
stack.push(element1);
stack.push(element3);
stack.push(element2);
stack.push(element1);
}
private void handleDUP2() {
BaseElement element1 = stack.pop();
if (element1.getElementSize() == 2) {
stack.push(element1);
stack.push(element1);
return;
}
BaseElement element2 = stack.pop();
stack.push(element2);
stack.push(element1);
stack.push(element2);
stack.push(element1);
}
private void handleDUP2X1() {
BaseElement element1 = stack.pop();
BaseElement element2 = stack.pop();
if (element1.getElementSize() == 2) {
stack.push(element1);
stack.push(element2);
stack.push(element1);
return;
}
BaseElement element3 = stack.pop();
stack.push(element2);
stack.push(element1);
stack.push(element3);
stack.push(element2);
stack.push(element1);
}
private void handleDUP2X2() {
BaseElement element1 = stack.pop();
BaseElement element2 = stack.pop();
if (element1.getElementSize() == 2) {
if (element2.getElementSize() == 2) {
stack.push(element1);
stack.push(element2);
stack.push(element1);
return;
}
BaseElement element3 = stack.pop();
stack.push(element1);
stack.push(element3);
stack.push(element2);
stack.push(element1);
return;
}
BaseElement element3 = stack.pop();
if (element3.getElementSize() == 2) {
stack.push(element2);
stack.push(element1);
stack.push(element3);
stack.push(element2);
stack.push(element1);
return;
}
BaseElement element4 = stack.pop();
stack.push(element2);
stack.push(element1);
stack.push(element4);
stack.push(element3);
stack.push(element2);
stack.push(element1);
}
private void handleSWAP() {
BaseElement element1 = stack.pop();
BaseElement element2 = stack.pop();
stack.push(element1);
stack.push(element2);
}
// 处理双目运算
private void handleArithmeticOperation2(JavaCGConstantTypeEnum constantTypeEnum) {
BaseElement value2 = stack.pop();
BaseElement value1 = stack.pop();
stack.push(new VariableElement(constantTypeEnum.getType()));
value2.checkTypeString(constantTypeEnum.getType());
value1.checkTypeString(constantTypeEnum.getType());
}
// 处理单目运算
private void handleArithmeticOperation1(JavaCGConstantTypeEnum constantTypeEnum) {
BaseElement value = stack.pop();
stack.push(new VariableElement(constantTypeEnum.getType()));
value.checkTypeString(constantTypeEnum.getType());
}
// 处理位运算
private void handleBitOperator(JavaCGConstantTypeEnum constantTypeEnum) {
BaseElement value2 = stack.pop();
BaseElement value1 = stack.pop();
stack.push(new VariableElement(constantTypeEnum.getType()));
value2.checkTypeString(JavaCGConstantTypeEnum.CONSTTE_INT.getType());
value1.checkTypeString(constantTypeEnum.getType());
}
// 处理IINC指令
private void handleIinc(IINC iinc) {
// 将指定的本地变量值设为null
locals.setValue2Null(iinc.getIndex());
// 操作数栈无变化
}
// 处理类型转换
private void handleTypeConversion(JavaCGConstantTypeEnum oldTypeEnum, JavaCGConstantTypeEnum newTypeEnum) {
BaseElement value = stack.pop();
stack.push(new VariableElement(newTypeEnum.getType()));
value.checkTypeString(oldTypeEnum.getType());
}
// 处理比较判断
private void handleCompare(JavaCGConstantTypeEnum constantTypeEnum) {
BaseElement value2 = stack.pop();
BaseElement value1 = stack.pop();
stack.push(new VariableElement(JavaCGConstantTypeEnum.CONSTTE_INT.getType()));
value2.checkTypeString(constantTypeEnum.getType());
value1.checkTypeString(constantTypeEnum.getType());
}
// 处理if判断,1个元素
private void handleIf1() {
BaseElement value = stack.pop();
value.checkTypeString(JavaCGConstantTypeEnum.CONSTTE_INT.getType());
}
// 处理if判断,2个元素
private void handleIf2() {
BaseElement value2 = stack.pop();
BaseElement value1 = stack.pop();
value2.checkTypeString(JavaCGConstantTypeEnum.CONSTTE_INT.getType());
value1.checkTypeString(JavaCGConstantTypeEnum.CONSTTE_INT.getType());
}
private void handleJSR(InstructionHandle ih) {
stack.push(new JSRElement(ih.getNext()));
}
private RetParseResult handleRET(RET ret) {
// 根据ret指令索引获取对应的本地变量
LocalVariableElement localVariableElement = locals.get(ret.getIndex());
if (!JavaCGConstants.JSR_TYPE.equals(localVariableElement.getType()) ||
!(localVariableElement.getValue() instanceof InstructionHandle)) {
throw new JavaCGRuntimeException("ret指令对应的本地变量非法 " + localVariableElement);
}
InstructionHandle jsrNextIh = (InstructionHandle) localVariableElement.getValue();
return new RetParseResult(jsrNextIh);
}
private ReturnParseResult handleReturn() {
BaseElement baseElement = stack.pop();
return new ReturnParseResult(baseElement);
}
private void handleGETSTATIC(GETSTATIC getstatic) {
String fieldName = getstatic.getFieldName(cpg);
ObjectType classType = getstatic.getLoadClassType(cpg);
FieldElement fieldElement = staticFieldInfo.getStatic(classType.getClassName(), fieldName);
if (fieldElement == null) {
// 假如是静态字段定义的类型与实际初始化类型不一致,则以上获取的fieldElement会是null,因为代码中没有对静态初始化方法进行处理(意义不大)
String type = getstatic.getFieldType(cpg).toString();
fieldElement = new StaticFieldElement(type, false, null, fieldName, classType.getClassName());
}
stack.push(fieldElement);
}
private void handlePUTSTATIC(PUTSTATIC putstatic) {
String fieldName = putstatic.getFieldName(cpg);
ObjectType classType = putstatic.getLoadClassType(cpg);
BaseElement value = stack.pop();
StaticFieldElement staticFieldElement = new StaticFieldElement(value.getType(), value.isArrayElement(), value.getValue(), fieldName, classType.getClassName());
// 数组类型的处理
if (value.isArrayElement()) {
staticFieldElement.setArrayValueMap(value.getArrayValueMap());
}
staticFieldInfo.putStatic(classType.getClassName(), fieldName, staticFieldElement);
}
private void handleGETFIELD(GETFIELD getfield) {
String fieldName = getfield.getFieldName(cpg);
BaseElement object = stack.pop();
FieldElement fieldElement = null;
if (object instanceof LocalVariableElement) {
LocalVariableElement localVariableElement = (LocalVariableElement) object;
if (localVariableElement.isThis()) {
// 仅处理对this的变量获取
fieldElement = nonStaticFieldInfo.get(fieldName);
if (fieldElement != null) {
stack.push(fieldElement);
return;
}
}
}
if (useFieldPossibleTypeFlag) {
// 使用已获取的构造函数非静态字段可能的类型
List possibleTypeList = nonStaticFieldPossibleTypes.getPossibleTypeList(fieldName);
if (!JavaCGUtil.isCollectionEmpty(possibleTypeList)) {
if (possibleTypeList.size() == 1) {
// 字段可能的类型数量为1,则使用
String type = possibleTypeList.get(0);
fieldElement = new FieldElement(type, false, null, fieldName);
} else {
// 字段可能的类型数量大于1,无法使用
System.err.println(mg.getClassName() + " 类的构造函数解析后 " + fieldName + " 非静态字段可能的类型数量大于1 " + StringUtils.join(possibleTypeList, " "));
}
}
}
if (fieldElement == null) {
String type = getfield.getFieldType(cpg).toString();
fieldElement = new FieldElement(type, false, null, fieldName);
}
stack.push(fieldElement);
}
private void handlePUTFIELD(PUTFIELD putfield) {
String fieldName = putfield.getFieldName(cpg);
BaseElement value = stack.pop();
BaseElement object = stack.pop();
if (object instanceof LocalVariableElement) {
LocalVariableElement localVariableElement = (LocalVariableElement) object;
if (localVariableElement.isThis()) {
// 仅处理对this的变量赋值
FieldElement fieldElement = new FieldElement(value.getType(), value.isArrayElement(), value.getValue(), fieldName);
// 数组类型的处理
if (value.isArrayElement()) {
fieldElement.setArrayValueMap(value.getArrayValueMap());
}
nonStaticFieldInfo.put(fieldName, fieldElement);
if (recordFieldPossibleTypeFlag) {
String rawFieldType = putfield.getFieldType(cpg).toString();
if (!StringUtils.equals(rawFieldType, value.getType())) {
// 记录非静态字段可能的类型,仅当字段实际类型与原始类型不相同时才记录
nonStaticFieldPossibleTypes.addPossibleType(fieldName, value.getType());
}
}
}
}
}
// 处理方法调用指令
private MethodCallParseResult handleMethodInvoke(InvokeInstruction invokeInstruction, boolean userObjectReference) {
// 处理参数
int argumentNumber = invokeInstruction.getArgumentTypes(cpg).length;
List argumentList = new ArrayList<>(argumentNumber);
for (int i = 0; i < argumentNumber; i++) {
// 参数逆序处理
argumentList.add(0, stack.pop());
}
BaseElement objectElement = null;
if (userObjectReference) {
// 方法调用需要使用被调用对象
objectElement = stack.pop();
}
// 处理返回值
Type returnType = invokeInstruction.getReturnType(cpg);
if (Type.VOID != returnType) {
// 被调用方法返回类型非void
VariableElement variableElement;
if (objectElement instanceof StaticFieldElement) {
// 被调用对象属于静态字段
StaticFieldElement staticFieldElement = (StaticFieldElement) objectElement;
variableElement = new StaticFieldMethodCallElement(returnType.toString(), (returnType instanceof ArrayType), staticFieldElement.getClassName(),
staticFieldElement.getFieldName(), invokeInstruction.getMethodName(cpg));
} else {
variableElement = new VariableElement(returnType.toString());
}
stack.push(variableElement);
}
return new MethodCallParseResult(objectElement, argumentList);
}
private void handleNEWARRAY(NEWARRAY newarray) {
BaseElement countVariable = stack.pop();
VariableElement arrayElement = new VariableElement(newarray.getType().toString(), true);
stack.push(arrayElement);
countVariable.checkTypeString(JavaCGConstantTypeEnum.CONSTTE_INT.getType());
}
private void handleANEWARRAY(ANEWARRAY anewarray) {
BaseElement countVariable = stack.pop();
VariableElement arrayElement = new VariableElement(JavaCGByteCodeUtil.addArrayFlag(getTypeString(anewarray)), true);
stack.push(arrayElement);
countVariable.checkTypeString(JavaCGConstantTypeEnum.CONSTTE_INT.getType());
}
private void handleATHROW() {
BaseElement throwableElement = stack.pop();
stack.push(throwableElement);
}
private void handleMULTIANEWARRAY(MULTIANEWARRAY multianewarray) {
for (int i = 0; i < multianewarray.getDimensions(); i++) {
stack.pop();
}
VariableElement arrayElement = new VariableElement(getTypeString(multianewarray), true);
stack.push(arrayElement);
}
//
public void setStack(JavaCGOperandStack stack) {
this.stack = stack;
}
public void setLocals(JavaCGLocalVariables locals) {
this.locals = locals;
}
public void setNonStaticFieldInfo(FieldInformation nonStaticFieldInfo) {
this.nonStaticFieldInfo = nonStaticFieldInfo;
}
public void setStaticFieldInfo(FieldInformation staticFieldInfo) {
this.staticFieldInfo = staticFieldInfo;
}
public void setRecordFieldPossibleTypeFlag(boolean recordFieldPossibleTypeFlag) {
this.recordFieldPossibleTypeFlag = recordFieldPossibleTypeFlag;
}
public void setUseFieldPossibleTypeFlag(boolean useFieldPossibleTypeFlag) {
this.useFieldPossibleTypeFlag = useFieldPossibleTypeFlag;
}
public void setNonStaticFieldPossibleTypes(FieldPossibleTypes nonStaticFieldPossibleTypes) {
this.nonStaticFieldPossibleTypes = nonStaticFieldPossibleTypes;
}
}