Java ASM系列:(031)修改已有的方法(优化-删除-复杂的变换)
本文属于[Java ASM系列一:Core API](https://blog.51cto.com/lsieun/2924583)当中的一篇。
## 1. 复杂的变换
### 1.1 stateless transformations
The stateless transformation does not depend on **the instructions that have been visited before the current one**.
举几个关于stateless transformation的例子:
- 添加指令:在方法进入和方法退出时,打印方法的参数和返回值、计算方法的运行时间。
- 删除指令:移除NOP、清空方法体。
- 修改指令:替换调用的方法。
这种stateless transformation实现起来比较容易,所以也被称为simple transformations。
### 1.2 stateful transformations
The **stateful transformation** require memorizing **some state** about **the instructions that have been visited before the current one**.
This requires storing state inside the method adapter.
举几个关于stateful transformation的例子:
- 删除指令:移除`ICONST_0 IADD`。例如,`int d = c + 0;`与`int d = c;`两者效果是一样的,所以`+ 0`的部分可以删除掉。
- 删除指令:移除`ALOAD_0 ALOAD_0 GETFIELD PUTFIELD`。例如,`this.val = this.val;`,将字段的值赋值给字段本身,无实质意义。
- 删除指令:移除`GETSTATIC LDC INVOKEVIRTUAL`。例如,`System.out.println("Hello World");`,删除打印信息。
这种stateful transformation实现起来比较困难,所以也被称为complex transformations。
那么,为什么stateless transformation实现起来比较容易,而stateful transformation会实现起来比较困难呢?做个类比,stateless transformation就类似于“一人吃饱,全家不饿”,不用考虑太多,所以实现起来就比较简单;而stateful transformation类似于“成家之后,要考虑一家人的生活状态”,考虑的事情就多一点,所以实现起来就比较困难。难归难,但是我们还是应该想办法进行实现。
那么,stateful transformation到底该如何开始着手实现呢?在stateful transformation过程中,一般都是涉及到对多个指令(Instruction)同时判断,这多个指令是一个“组合”,不能轻易拆散。我们通过三个步骤来进行实现:
- 第一步,就是将问题本身转换成Instruction指令,然后对多个指令组合的“特征”或遵循的“模式”进行总结。
- 第二步,就是使用这个总结出来的“特征”或“模式”对指令进行识别。在识别的过程当中,每一条Instruction的加入,都会引起原有状态(state)的变化,这就对应着`stateful`的部分;
- 第三步,识别成功之后,要对Class文件进行转换,这就对应着`transformation`的部分。谈到transformation,无非就是对Instruction的内容进行增加、删除和修改等操作。
到这里,就有一个新的问题产生:如何去记录第二步当中的状态(state)变化呢?我们的回答就是,借助于state machine。
### 1.3 state machine
首先,我们回答一个问题:什么是state machine?
A state machine is a behavior model. It consists of **a finite number of states** and is therefore also called finite-state machine (FSM). Based on the **current state** and **a given input** the machine performs **state transitions** and produces outputs.
对于state machine,我想到了这句话:“吾生也有涯,而知也无涯。以有涯随无涯,殆已”。这句话的意思是讲,人们的生命是有限的,而知识却是无限的。以有限的生命去追求无限的知识,势必体乏神伤。我觉得,state machine的聪明之处,就是将“无限”的操作步骤给限定在“有限”的状态里来思考。
接下来,就是给出一个具体的state machine。也就是说,下面的`MethodPatternAdapter`类,就是一个原始的state machine,我们从三个层面来把握它:
- 第一个层面,class info。`MethodPatternAdapter`类,继承自`MethodVisitor`类,本身也是一个抽象类。
- 第二个层面,fields。`MethodPatternAdapter`类,定义了两个字段,其中`SEEN_NOTHING`字段,是一个常量值,表示一个“初始状态”,而`state`字段则是用于记录不断变化的状态。
- 第三个层面,methods。`MethodPatternAdapter`类定义`visitXxxInsn()`方法,都会去调用一个自定义的`visitInsn()`方法。`visitInsn()`方法,是一个抽象方法,它的作用就是让所有的其它状态(state)都回归“初始状态”。
那么,应该怎么使用`MethodPatternAdapter`类呢?我们就是写一个`MethodPatternAdapter`类的子类,这个子类就是一个更“先进”的state machine,它做以下三件事情:
- 第一件事情,从字段层面,根据处理的问题,来定义更多的状态;也就是,类似于`SEEN_NOTHING`的字段。这里就是**对a finite number of states进行定义**。
- 第二件事情,从方法层面,处理好`visitXxxInsn()`的调用,对于`state`字段状态的影响。也就是,输入新的指令(Instruction),都会对`state`字段产生影响。这里就是**构建状态(state)变化的机制**。
- 第三件事情,从方法层面,实现`visitInsn()`方法,根据`state`字段的值,如何回归到“初始状态”。这里就是添加一个“恢复出厂设置”的功能,**让状态(state)归零**,回归到一个初始状态。**让状态(state)归零**,是**构建状态(state)变化的机制**一个比较特殊的环节。结合生活来说,生活中有不顺的地方,就从新开始,从零开始。
```java
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
public abstract class MethodPatternAdapter extends MethodVisitor {
protected final static int SEEN_NOTHING = 0;
protected int state;
public MethodPatternAdapter(int api, MethodVisitor methodVisitor) {
super(api, methodVisitor);
}
@Override
public void visitInsn(int opcode) {
visitInsn();
super.visitInsn(opcode);
}
@Override
public void visitIntInsn(int opcode, int operand) {
visitInsn();
super.visitIntInsn(opcode, operand);
}
@Override
public void visitVarInsn(int opcode, int var) {
visitInsn();
super.visitVarInsn(opcode, var);
}
@Override
public void visitTypeInsn(int opcode, String type) {
visitInsn();
super.visitTypeInsn(opcode, type);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
visitInsn();
super.visitFieldInsn(opcode, owner, name, descriptor);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor) {
visitInsn();
super.visitMethodInsn(opcode, owner, name, descriptor);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
visitInsn();
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
@Override
public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
visitInsn();
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
}
@Override
public void visitJumpInsn(int opcode, Label label) {
visitInsn();
super.visitJumpInsn(opcode, label);
}
@Override
public void visitLdcInsn(Object value) {
visitInsn();
super.visitLdcInsn(value);
}
@Override
public void visitIincInsn(int var, int increment) {
visitInsn();
super.visitIincInsn(var, increment);
}
@Override
public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
visitInsn();
super.visitTableSwitchInsn(min, max, dflt, labels);
}
@Override
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
visitInsn();
super.visitLookupSwitchInsn(dflt, keys, labels);
}
@Override
public void visitMultiANewArrayInsn(String descriptor, int numDimensions) {
visitInsn();
super.visitMultiANewArrayInsn(descriptor, numDimensions);
}
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
visitInsn();
super.visitTryCatchBlock(start, end, handler, type);
}
@Override
public void visitLabel(Label label) {
visitInsn();
super.visitLabel(label);
}
@Override
public void visitFrame(int type, int numLocal, Object[] local, int numStack, Object[] stack) {
visitInsn();
super.visitFrame(type, numLocal, local, numStack, stack);
}
@Override
public void visitMaxs(int maxStack, int maxLocals) {
visitInsn();
super.visitMaxs(maxStack, maxLocals);
}
protected abstract void visitInsn();
}
```
## 2. 示例一:加零
### 2.1 预期目标
假如有一个`HelloWorld`类,代码如下:
```java
public class HelloWorld {
public void test(int a, int b) {
int c = a + b;
int d = c + 0;
System.out.println(d);
}
}
```
我们想要实现的预期目标:将`int d = c + 0;`转换成`int d = c;`。
```text
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public void test(int, int);
Code:
0: iload_1
1: iload_2
2: iadd
3: istore_3
4: iload_3
5: iconst_0
6: iadd
7: istore 4
9: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
12: iload 4
14: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
17: return
}
```
### 2.2 编码实现
```java
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import static org.objectweb.asm.Opcodes.*;
public class MethodRemoveAddZeroVisitor extends ClassVisitor {
public MethodRemoveAddZeroVisitor(int api, ClassVisitor classVisitor) {
super(api, classVisitor);
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
if (mv != null && !"".equals(name) && !"".equals(name)) {
boolean isAbstractMethod = (access & ACC_ABSTRACT) != 0;
boolean isNativeMethod = (access & ACC_NATIVE) != 0;
if (!isAbstractMethod && !isNativeMethod) {
mv = new MethodRemoveAddZeroAdapter(api, mv);
}
}
return mv;
}
private class MethodRemoveAddZeroAdapter extends MethodPatternAdapter {
private static final int SEEN_ICONST_0 = 1;
public MethodRemoveAddZeroAdapter(int api, MethodVisitor methodVisitor) {
super(api, methodVisitor);
}
@Override
public void visitInsn(int opcode) {
// 第一,对于感兴趣的状态进行处理
switch (state) {
case SEEN_NOTHING:
if (opcode == ICONST_0) {
state = SEEN_ICONST_0;
return;
}
break;
case SEEN_ICONST_0:
if (opcode == IADD) {
state = SEEN_NOTHING;
return;
}
else if (opcode == ICONST_0) {
mv.visitInsn(ICONST_0);
return;
}
break;
}
// 第二,对于不感兴趣的状态,交给父类进行处理
super.visitInsn(opcode);
}
@Override
protected void visitInsn() {
if (state == SEEN_ICONST_0) {
mv.visitInsn(ICONST_0);
}
state = SEEN_NOTHING;
}
}
}
```
### 2.3 进行转换
```java
import lsieun.utils.FileUtils;
import org.objectweb.asm.*;
public class HelloWorldTransformCore {
public static void main(String[] args) {
String relative_path = "sample/HelloWorld.class";
String filepath = FileUtils.getFilePath(relative_path);
byte[] bytes1 = FileUtils.readBytes(filepath);
//(1)构建Cla***eader
Cla***eader cr = new Cla***eader(bytes1);
//(2)构建ClassWriter
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
//(3)串连ClassVisitor
int api = Opcodes.ASM9;
ClassVisitor cv = new MethodRemoveAddZeroVisitor(api, cw);
//(4)结合Cla***eader和ClassVisitor
int parsingOptions = Cla***eader.SKIP_DEBUG | Cla***eader.SKIP_FRAMES;
cr.accept(cv, parsingOptions);
//(5)生成byte[]
byte[] bytes2 = cw.toByteArray();
FileUtils.writeBytes(filepath, bytes2);
}
}
```
### 2.4 验证结果
```text
$ javap -c sample.HelloWorld
public class sample.HelloWorld {
...
public void test(int, int);
Code:
0: iload_1
1: iload_2
2: iadd
3: istore_3
4: iload_3
5: istore 4
7: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload 4
12: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
15: return
}
```
## 3. 示例二:字段赋值
### 3.1 预期目标
假如有一个`HelloWorld`类,代码如下:
```java
public class HelloWorld {
public int val;
public void test(int a, int b) {
int c = a + b;
this.val = this.val;
System.out.println(c);
}
}
```
我们想要实现的预期目标:删除掉`this.val = this.val;`语句。
```text
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
public int val;
...
public void test(int, int);
Code:
0: iload_1
1: iload_2
2: iadd
3: istore_3
4: aload_0
5: aload_0
6: getfield #2 // Field val:I
9: putfield #2 // Field val:I
12: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
15: iload_3
16: invokevirtual #4 // Method java/io/PrintStream.println:(I)V
19: return
}
```
### 3.2 编码实现
![](http://www.icode9.com/i/li/?n=2&i=images/20210702/1625221942271769.png?,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
```java
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import static org.objectweb.asm.Opcodes.*;
public class MethodRemoveGetFieldPutFieldVisitor extends ClassVisitor {
public MethodRemoveGetFieldPutFieldVisitor(int api, ClassVisitor classVisitor) {
super(api, classVisitor);
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
if (mv != null && !"".equals(name) && !"".equals(name)) {
boolean isAbstractMethod = (access & ACC_ABSTRACT) != 0;
boolean isNativeMethod = (access & ACC_NATIVE) != 0;
if (!isAbstractMethod && !isNativeMethod) {
mv = new MethodRemoveGetFieldPutFieldAdapter(api, mv);
}
}
return mv;
}
private class MethodRemoveGetFieldPutFieldAdapter extends MethodPatternAdapter {
private final static int SEEN_ALOAD_0 = 1;
private final static int SEEN_ALOAD_0_ALOAD_0 = 2;
private final static int SEEN_ALOAD_0_ALOAD_0_GETFIELD = 3;
private String fieldOwner;
private String fieldName;
private String fieldDesc;
public MethodRemoveGetFieldPutFieldAdapter(int api, MethodVisitor methodVisitor) {
super(api, methodVisitor);
}
@Override
public void visitVarInsn(int opcode, int var) {
// 第一,对于感兴趣的状态进行处理
switch (state) {
case SEEN_NOTHING:
if (opcode == ALOAD && var == 0) {
state = SEEN_ALOAD_0;
return;
}
break;
case SEEN_ALOAD_0:
if (opcode == ALOAD && var == 0) {
state = SEEN_ALOAD_0_ALOAD_0;
return;
}
break;
case SEEN_ALOAD_0_ALOAD_0:
if (opcode == ALOAD && var == 0) {
mv.visitVarInsn(opcode, var);
return;
}
break;
}
// 第二,对于不感兴趣的状态,交给父类进行处理
super.visitVarInsn(opcode, var);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
// 第一,对于感兴趣的状态进行处理
switch (state) {
case SEEN_ALOAD_0_ALOAD_0:
if (opcode == GETFIELD) {
state = SEEN_ALOAD_0_ALOAD_0_GETFIELD;
fieldOwner = owner;
fieldName = name;
fieldDesc = descriptor;
return;
}
break;
case SEEN_ALOAD_0_ALOAD_0_GETFIELD:
if (opcode == PUTFIELD && name.equals(fieldName)) {
state = SEEN_NOTHING;
return;
}
break;
}
// 第二,对于不感兴趣的状态,交给父类进行处理
super.visitFieldInsn(opcode, owner, name, descriptor);
}
@Override
protected void visitInsn() {
switch (state) {
case SEEN_ALOAD_0:
mv.visitVarInsn(ALOAD, 0);
break;
case SEEN_ALOAD_0_ALOAD_0:
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 0);
break;
case SEEN_ALOAD_0_ALOAD_0_GETFIELD:
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, fieldOwner, fieldName, fieldDesc);
break;
}
state = SEEN_NOTHING;
}
}
}
```
### 3.3 进行转换
```java
import lsieun.utils.FileUtils;
import org.objectweb.asm.*;
public class HelloWorldTransformCore {
public static void main(String[] args) {
String relative_path = "sample/HelloWorld.class";
String filepath = FileUtils.getFilePath(relative_path);
byte[] bytes1 = FileUtils.readBytes(filepath);
//(1)构建Cla***eader
Cla***eader cr = new Cla***eader(bytes1);
//(2)构建ClassWriter
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
//(3)串连ClassVisitor
int api = Opcodes.ASM9;
ClassVisitor cv = new MethodRemoveGetFieldPutFieldVisitor(api, cw);
//(4)结合Cla***eader和ClassVisitor
int parsingOptions = Cla***eader.SKIP_DEBUG | Cla***eader.SKIP_FRAMES;
cr.accept(cv, parsingOptions);
//(5)生成byte[]
byte[] bytes2 = cw.toByteArray();
FileUtils.writeBytes(filepath, bytes2);
}
}
```
### 3.4 验证结果
```text
$ javap -c sample.HelloWorld
public class sample.HelloWorld {
public int val;
public sample.HelloWorld();
Code:
0: aload_0
1: invokespecial #10 // Method java/lang/Object."":()V
4: return
public void test(int, int);
Code:
0: iload_1
1: iload_2
2: iadd
3: istore_3
4: getstatic #18 // Field java/lang/System.out:Ljava/io/PrintStream;
7: iload_3
8: invokevirtual #24 // Method java/io/PrintStream.println:(I)V
11: return
}
```
## 4. 示例三:删除打印语句
### 4.1 预期目标
假如有一个`HelloWorld`类,代码如下:
```java
public class HelloWorld {
public void test(int a, int b) {
System.out.println("Before a + b");
int c = a + b;
System.out.println("After a + b");
System.out.println(c);
}
}
```
我们想要实现的预期目标:删除掉打印字符串的语句。
```text
$ javap -c sample.HelloWorld
Compiled from "HelloWorld.java"
public class sample.HelloWorld {
...
public void test(int, int);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Before a + b
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: iload_1
9: iload_2
10: iadd
11: istore_3
12: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #5 // String After a + b
17: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
23: iload_3
24: invokevirtual #6 // Method java/io/PrintStream.println:(I)V
27: return
}
```
### 4.2 编码实现
```java
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import static org.objectweb.asm.Opcodes.*;
public class MethodRemovePrintVisitor extends ClassVisitor {
public MethodRemovePrintVisitor(int api, ClassVisitor classVisitor) {
super(api, classVisitor);
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
if (mv != null && !"".equals(name) && !"".equals(name)) {
boolean isAbstractMethod = (access & ACC_ABSTRACT) != 0;
boolean isNativeMethod = (access & ACC_NATIVE) != 0;
if (!isAbstractMethod && !isNativeMethod) {
mv = new MethodRemovePrintAdaptor(api, mv);
}
}
return mv;
}
private class MethodRemovePrintAdaptor extends MethodPatternAdapter {
private static final int SEEN_GETSTATIC = 1;
private static final int SEEN_GETSTATIC_LDC = 2;
private String message;
public MethodRemovePrintAdaptor(int api, MethodVisitor methodVisitor) {
super(api, methodVisitor);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
// 第一,对于感兴趣的状态进行处理
boolean flag = (opcode == GETSTATIC && owner.equals("java/lang/System") && name.equals("out")
&& descriptor.equals("Ljava/io/PrintStream;"));
switch (state) {
case SEEN_NOTHING:
if (flag) {
state = SEEN_GETSTATIC;
return;
}
break;
case SEEN_GETSTATIC:
if (flag) {
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
return;
}
}
// 第二,对于不感兴趣的状态,交给父类进行处理
super.visitFieldInsn(opcode, owner, name, descriptor);
}
@Override
public void visitLdcInsn(Object value) {
// 第一,对于感兴趣的状态进行处理
switch (state) {
case SEEN_GETSTATIC:
if (value instanceof String) {
state = SEEN_GETSTATIC_LDC;
message = (String) value;
return;
}
break;
}
// 第二,对于不感兴趣的状态,交给父类进行处理
super.visitLdcInsn(value);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
// 第一,对于感兴趣的状态进行处理
switch (state) {
case SEEN_GETSTATIC_LDC:
if (opcode == INVOKEVIRTUAL && owner.equals("java/io/PrintStream") &&
name.equals("println") && descriptor.equals("(Ljava/lang/String;)V")) {
state = SEEN_NOTHING;
return;
}
break;
}
// 第二,对于不感兴趣的状态,交给父类进行处理
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
@Override
protected void visitInsn() {
switch (state) {
case SEEN_GETSTATIC:
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
break;
case SEEN_GETSTATIC_LDC:
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn(message);
break;
}
state = SEEN_NOTHING;
}
}
}
```
### 4.3 进行转换
```java
import lsieun.utils.FileUtils;
import org.objectweb.asm.*;
public class HelloWorldTransformCore {
public static void main(String[] args) {
String relative_path = "sample/HelloWorld.class";
String filepath = FileUtils.getFilePath(relative_path);
byte[] bytes1 = FileUtils.readBytes(filepath);
//(1)构建Cla***eader
Cla***eader cr = new Cla***eader(bytes1);
//(2)构建ClassWriter
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
//(3)串连ClassVisitor
int api = Opcodes.ASM9;
ClassVisitor cv = new MethodRemovePrintVisitor(api, cw);
//(4)结合Cla***eader和ClassVisitor
int parsingOptions = Cla***eader.SKIP_DEBUG | Cla***eader.SKIP_FRAMES;
cr.accept(cv, parsingOptions);
//(5)生成byte[]
byte[] bytes2 = cw.toByteArray();
FileUtils.writeBytes(filepath, bytes2);
}
}
```
### 4.4 验证结果
```text
$ javap -c sample.HelloWorld
public class sample.HelloWorld {
...
public void test(int, int);
Code:
0: iload_1
1: iload_2
2: iadd
3: istore_3
4: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
7: iload_3
8: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
11: return
}
```
## 5. 总结
本文对stateful transformations进行介绍,内容总结如下:
- 第一点,stateful transformations可以实现复杂的操作,它是借助于state machine来进行实现的。
- 第二点,对于`MethodPatternAdapter`类来说,它是一个原始的state machine,本身是一个抽象类;我们写一个具体的子类,作为更“先进”的state machine,在子类当中主要做三件事情:
- 第一件事情,从字段层面,根据处理的问题,来定义更多的状态。
- 第二件事情,从方法层面,处理好`visitXxxInsn()`的调用,对于`state`字段状态的影响。
- 第三件事情,从方法层面,实现`visitInsn()`方法,根据`state`字段的值,如何回归到“初始状态”。