consider return type when calculating stack change

This commit is contained in:
金戟 2020-11-16 23:13:45 +08:00
parent 43cd4aeeec
commit 7d2dd83410
2 changed files with 14 additions and 10 deletions

View File

@ -122,21 +122,17 @@ public class SourceClassHandler extends BaseClassHandler {
for (int i = rangeEnd - 1; i >= 0; i--) {
switch (instructions[i].getOpcode()) {
case Opcodes.INVOKESPECIAL:
stackLevel += ClassUtil.getParameterTypes(((MethodInsnNode)instructions[i]).desc).size();
case Opcodes.INVOKEVIRTUAL:
case Opcodes.INVOKEINTERFACE:
stackLevel += stackEffectOfInvocation(instructions[i]) + 1;
if (((MethodInsnNode)instructions[i]).name.equals(ConstPool.CONSTRUCTOR)) {
// constructor implicitly eat 2 more stack and return 1 value
// constructor must be INVOKESPECIAL and implicitly pop 1 more stack
stackLevel++;
}
break;
case Opcodes.INVOKESTATIC:
case Opcodes.INVOKEDYNAMIC:
// static and dynamic invoke implicitly return 1 value
stackLevel += (ClassUtil.getParameterTypes(((MethodInsnNode)instructions[i]).desc).size() - 1);
break;
case Opcodes.INVOKEVIRTUAL:
case Opcodes.INVOKEINTERFACE:
// virtual and interface invoke implicitly eat 1 more stack and return 1 value, deuce
stackLevel += ClassUtil.getParameterTypes(((MethodInsnNode)instructions[i]).desc).size();
stackLevel += stackEffectOfInvocation(instructions[i]);
break;
case -1:
// reach LineNumberNode or LabelNode
@ -151,6 +147,11 @@ public class SourceClassHandler extends BaseClassHandler {
return -1;
}
private int stackEffectOfInvocation(AbstractInsnNode instruction) {
String desc = ((MethodInsnNode)instruction).desc;
return ClassUtil.getParameterTypes(desc).size() - (ClassUtil.getReturnType(desc).isEmpty() ? 0 : 1);
}
private AbstractInsnNode[] replaceNewOps(ClassNode cn, MethodNode mn, String newOperatorInjectMethodName,
AbstractInsnNode[] instructions, int start, int end) {
LogUtil.debug(" Using %s mock new operation in %s", newOperatorInjectMethodName, mn.name);

View File

@ -26,6 +26,7 @@ public class ClassUtil {
public static final byte TYPE_CLASS = 'L';
public static final byte TYPE_SHORT = 'S';
public static final byte TYPE_BOOL = 'Z';
public static final byte TYPE_VOID = 'V';
private static final byte PARAM_END = ')';
private static final byte CLASS_END = ';';
private static final byte TYPE_ARRAY = '[';
@ -39,6 +40,7 @@ public class ClassUtil {
private static final String CLASS_LONG = "java/lang/Long";
private static final String CLASS_SHORT = "java/lang/Short";
private static final String CLASS_BOOLEAN = "java/lang/Boolean";
private static final String EMPTY = "";
private static final String METHOD_VALUE_OF = "valueOf";
private final static String JOINER = "::";
@ -56,6 +58,7 @@ public class ClassUtil {
TYPE_MAPPING.put(TYPE_LONG, CLASS_LONG);
TYPE_MAPPING.put(TYPE_SHORT, CLASS_SHORT);
TYPE_MAPPING.put(TYPE_BOOL, CLASS_BOOLEAN);
TYPE_MAPPING.put(TYPE_VOID, EMPTY);
}
/**
@ -159,7 +162,7 @@ public class ClassUtil {
} else if (TYPE_MAPPING.containsKey((byte)typeChar)) {
return TYPE_MAPPING.get((byte)typeChar);
} else {
return "";
return EMPTY;
}
}