From 809b1aa57f30526ca584fee8b5512434ccd09f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Mon, 16 Nov 2020 19:01:29 +0800 Subject: [PATCH] let's handle invoke and array correctly --- .../agent/handler/SourceClassHandler.java | 15 +++++++++++++-- .../testable/agent/util/BytecodeUtil.java | 16 ++++++++-------- 2 files changed, 21 insertions(+), 10 deletions(-) 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 665cdeb..9387124 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 @@ -121,11 +121,21 @@ public class SourceClassHandler extends BaseClassHandler { int stackLevel = ClassUtil.getParameterTypes(((MethodInsnNode)instructions[rangeEnd]).desc).size(); for (int i = rangeEnd - 1; i >= 0; i--) { switch (instructions[i].getOpcode()) { - case Opcodes.INVOKEVIRTUAL: case Opcodes.INVOKESPECIAL: + stackLevel += ClassUtil.getParameterTypes(((MethodInsnNode)instructions[i]).desc).size(); + if (((MethodInsnNode)instructions[i]).name.equals(ConstPool.CONSTRUCTOR)) { + // constructor implicitly eat 2 more stack and return 1 value + stackLevel++; + } + break; case Opcodes.INVOKESTATIC: - case Opcodes.INVOKEINTERFACE: 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 more value, deuce stackLevel += ClassUtil.getParameterTypes(((MethodInsnNode)instructions[i]).desc).size(); break; case -1: @@ -179,6 +189,7 @@ public class SourceClassHandler extends BaseClassHandler { mn.instructions.remove(instructions[end - 1]); } } + // method with @TestableMock will be modified as public access, so INVOKEVIRTUAL is used mn.instructions.insertBefore(instructions[end], new MethodInsnNode(INVOKEVIRTUAL, testClassName, substitutionMethod, addFirstParameter(method.desc, ClassUtil.fitCompanionClassName(ownerClass)), false)); mn.instructions.remove(instructions[end]); diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/util/BytecodeUtil.java b/testable-agent/src/main/java/com/alibaba/testable/agent/util/BytecodeUtil.java index 550e810..4885ca3 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/util/BytecodeUtil.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/util/BytecodeUtil.java @@ -51,14 +51,14 @@ public class BytecodeUtil { put(FSTORE, -1); put(DSTORE, -1); put(ASTORE, -1); - put(IASTORE, -1); - put(LASTORE, -1); - put(FASTORE, -1); - put(DASTORE, -1); - put(AASTORE, -1); - put(BASTORE, -1); - put(CASTORE, -1); - put(SASTORE, -1); + put(IASTORE, -3); + put(LASTORE, -3); + put(FASTORE, -3); + put(DASTORE, -3); + put(AASTORE, -3); + put(BASTORE, -3); + put(CASTORE, -3); + put(SASTORE, -3); put(POP, -1); put(POP2, -2); put(DUP, 1);