From 68075a2ead619a48a70939457b18267e72f74134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Wed, 30 Dec 2020 22:38:17 +0800 Subject: [PATCH] fix method node stack change --- .../agent/handler/SourceClassHandler.java | 26 ++++++++++++------- .../agent/handler/TestClassHandler.java | 1 + .../agent/model/ModifiedInsnNodes.java | 16 ++++++++++++ 3 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 testable-agent/src/main/java/com/alibaba/testable/agent/model/ModifiedInsnNodes.java diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java index 0d8ad31..55e85ea 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java @@ -2,6 +2,7 @@ package com.alibaba.testable.agent.handler; import com.alibaba.testable.agent.constant.ConstPool; import com.alibaba.testable.agent.model.MethodInfo; +import com.alibaba.testable.agent.model.ModifiedInsnNodes; import com.alibaba.testable.agent.util.BytecodeUtil; import com.alibaba.testable.agent.util.ClassUtil; import com.alibaba.testable.core.util.LogUtil; @@ -61,6 +62,7 @@ public class SourceClassHandler extends BaseClassHandler { AbstractInsnNode[] instructions = mn.instructions.toArray(); List memberInjectMethodList = new ArrayList(memberInjectMethods); int i = 0; + int maxStackDiff = 0; do { if (invokeOps.contains(instructions[i].getOpcode())) { MethodInsnNode node = (MethodInsnNode)instructions[i]; @@ -69,8 +71,10 @@ public class SourceClassHandler extends BaseClassHandler { // it's a member or static method and an inject method for it exist int rangeStart = getMemberMethodStart(instructions, i); if (rangeStart >= 0) { - instructions = replaceMemberCallOps(cn, mn, memberInjectMethodName, instructions, - node.owner, node.getOpcode(), rangeStart, i); + ModifiedInsnNodes modifiedInsnNodes = replaceMemberCallOps(cn, mn, memberInjectMethodName, + instructions, node.owner, node.getOpcode(), rangeStart, i); + instructions = modifiedInsnNodes.nodes; + maxStackDiff = Math.max(maxStackDiff, modifiedInsnNodes.stackDiff); i = rangeStart; } else { LogUtil.warn("Potential missed mocking at %s:%s", mn.name, getLineNum(instructions, i)); @@ -82,7 +86,10 @@ public class SourceClassHandler extends BaseClassHandler { // and an inject method for it exist int rangeStart = getConstructorStart(instructions, node.owner, i); if (rangeStart >= 0) { - instructions = replaceNewOps(cn, mn, newOperatorInjectMethodName, instructions, rangeStart, i); + ModifiedInsnNodes modifiedInsnNodes = replaceNewOps(cn, mn, newOperatorInjectMethodName, + instructions, rangeStart, i); + instructions = modifiedInsnNodes.nodes; + maxStackDiff = Math.max(maxStackDiff, modifiedInsnNodes.stackDiff); i = rangeStart; } } @@ -90,6 +97,7 @@ public class SourceClassHandler extends BaseClassHandler { } i++; } while (i < instructions.length); + mn.maxStack += maxStackDiff; } private String getMemberInjectMethodName(List memberInjectMethodList, MethodInsnNode node) { @@ -176,7 +184,7 @@ public class SourceClassHandler extends BaseClassHandler { return ClassUtil.getParameterTypes(desc).size() - (ClassUtil.getReturnType(desc).isEmpty() ? 0 : 1); } - private AbstractInsnNode[] replaceNewOps(ClassNode cn, MethodNode mn, String newOperatorInjectMethodName, + private ModifiedInsnNodes replaceNewOps(ClassNode cn, MethodNode mn, String newOperatorInjectMethodName, AbstractInsnNode[] instructions, int start, int end) { LogUtil.diagnose(" Line %d, mock method %s used", getLineNum(instructions, start), newOperatorInjectMethodName); @@ -188,7 +196,7 @@ public class SourceClassHandler extends BaseClassHandler { mn.instructions.remove(instructions[start]); mn.instructions.remove(instructions[start + 1]); mn.instructions.remove(instructions[end]); - return mn.instructions.toArray(); + return new ModifiedInsnNodes(mn.instructions.toArray(), 0); } private int getLineNum(AbstractInsnNode[] instructions, int start) { @@ -205,9 +213,9 @@ public class SourceClassHandler extends BaseClassHandler { ClassUtil.toByteCodeClassName(classType); } - private AbstractInsnNode[] replaceMemberCallOps(ClassNode cn, MethodNode mn, String substitutionMethod, - AbstractInsnNode[] instructions, String ownerClass, - int opcode, int start, int end) { + private ModifiedInsnNodes replaceMemberCallOps(ClassNode cn, MethodNode mn, String substitutionMethod, + AbstractInsnNode[] instructions, String ownerClass, + int opcode, int start, int end) { LogUtil.diagnose(" Line %d, mock method %s used", getLineNum(instructions, start), substitutionMethod); MethodInsnNode method = (MethodInsnNode)instructions[end]; String testClassName = ClassUtil.getTestClassName(cn.name); @@ -223,7 +231,7 @@ public class SourceClassHandler extends BaseClassHandler { mn.instructions.insertBefore(instructions[end], new MethodInsnNode(INVOKESTATIC, testClassName, substitutionMethod, addFirstParameter(method.desc, ClassUtil.fitCompanionClassName(ownerClass)), false)); mn.instructions.remove(instructions[end]); - return mn.instructions.toArray(); + return new ModifiedInsnNodes(mn.instructions.toArray(), 1); } private boolean isCompanionMethod(String ownerClass, int opcode) { diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java index 19fdae3..0c2d6ef 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java @@ -60,6 +60,7 @@ public class TestClassHandler extends BaseClassHandler { il.add(new FieldInsnNode(PUTSTATIC, cn.name, REF_TESTABLE_CONTEXT, ClassUtil.toByteCodeClassName(CLASS_MOCK_CONTEXT))); mn.instructions.insertBefore(mn.instructions.get(0), il); + mn.maxStack++; } private void handleMockMethod(ClassNode cn, MethodNode mn) { diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/model/ModifiedInsnNodes.java b/testable-agent/src/main/java/com/alibaba/testable/agent/model/ModifiedInsnNodes.java new file mode 100644 index 0000000..626b8f3 --- /dev/null +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/model/ModifiedInsnNodes.java @@ -0,0 +1,16 @@ +package com.alibaba.testable.agent.model; + +import org.objectweb.asm.tree.AbstractInsnNode; + +public class ModifiedInsnNodes { + + public AbstractInsnNode[] nodes; + + public int stackDiff; + + public ModifiedInsnNodes(AbstractInsnNode[] nodes, int stackDiff) { + this.nodes = nodes; + this.stackDiff = stackDiff; + } + +}