ASM基础使用
ASM
Core Api
ClassVisitor
1 | visit |
visit
标记ClassVisitor开始
1 | override fun visit( |
visitSource
访问类的源代码相关的属性
1 | override fun visitSource(source: String, // 源代码 |
visitModule
visitNestHost
访问外部host。
每个类文件有一个host,除host外的类都是嵌套类。
visitNestHost所做的也就是访问嵌套类的host
如下:
A为host,B、C、D为嵌套类(所以B、C、D、E、Runnable匿名类的visitHost的结果为A的全类名)
1 | public class A { |
1 | val a = A::class.java.name |
visitOuterClass
访问匿名类和局部内部类的外部类
1 | override fun visitOuterClass( |
1 | fun testVisitOuterClass() { |
visitAnnotation
访问类的注解
1 | override fun visitAnnotation( |
visitTypeAnnotation
访问类的类类型注解
1 | override fun visitTypeAnnotation( |
visitAttribute
我得到的结论是标准的属性没法触发,也就是说用于扩展性的visit自定义的属性,
另外谁会闲的没事去使用visitAttribute。这么难用,当然是使用visitXXX api会更好
1 | override fun visitAttribute(attribute: Attribute) |
visitNestMember
用于访问一个类的内部类(匿名,局部也包含在内)
1 | override fun visitNestMember(nestMember: String) { |
1 | fun visitNestMember() { |
visitPermittedSubclass
这个方法是用于适配Jdk 17的一个新特性——sealed class
用于拜访所有sealed class的permitted class
如果ClassVisitor的对象是VisitPermittedSubClassTest则会对TestA, TestB, TestC进行访问
1 | public sealed class VisitPermittedSubClassTest permits TestA, TestB, TestC { |
1 | override fun visitPermittedSubclass( |
visitInnerClass
访问内部类的信息
1 | fun visitInnerClass() { |
VisitInnerClassTest的内部类
VisitInnerClassTest$A , VisitInnerClassTest$A$B , VisitInnerClassTest$B , VisitInnerClassTest$B$A
将被访问
1 | public class VisitInnerClassTest { |
1 | override fun visitInnerClass( |
visitRecordComponent
访问record class的成员
1 | public record VisitRecordComponentTest( |
1 | override fun visitRecordComponent( |
name:id
descriptor:I
signature:nullname:name
descriptor:Ljava/lang/String;
signature:nullname:age
descriptor:I
signature:null
visitField
访问类属性
1 | override fun visitField( |
visitMethod
访问方法
1 | override fun visitMethod( |
visitEnd
对于类的访问结束标记
1 | override fun visitEnd() |
ModuleVisitor
AnnotationVisitor
RecordComponentVisitor
FieldVisitor
访问顺序
( visitAnnotation | visitTypeAnnotation | visitAttribute )* visitEnd.
visitAnnotation
visitTypeAnnotation
同ClassVisitor.visitTypeAnnotation
visitAttribute
visitEnd
标记FieldVisitor的结束
MethodVisitor
访问顺序
( visitParameter )*
[ visitAnnotationDefault ]
( visitAnnotation | visitAnnotableParameterCount | visitParameterAnnotation | visitTypeAnnotation | visitAttribute )*
[ visitCode
( visitFrame | visitXInsn | visitLabel | visitInsnAnnotation | visitTryCatchBlock | visitTryCatchAnnotation | visitLocalVariable | visitLocalVariableAnnotation | visitLineNumber )*
visitMaxs ]
visitEnd
visitParameter
用于访问方法的参数信息
Note:由于这个方法是visit的debug信息段,需要在编译的时候加入-parameters参数
对于gradle进行如下配置
1
2
3 tasks.compileJava {
options.compilerArgs += "-parameters"
}
1 | override fun visitParameter(name: String?, // 参数名 |
对于如下方法会依此返回
name:a
access:0name:b
access:0name:c
access:0
1 | public void a(int a, String b, List<String> c,long d) {} |
visitAnnotationDefault
访问注解类中方法的default值
1 | override fun visitAnnotationDefault(): AnnotationVisitor // 用于进一步访问注解 |
如下注解
在调用visitAnnotationDefault后会调用AnnotationVisitor的visit方法
name:null
value:1name:null
value:Default
1 | public VisitDefaultMethod { |
visitAnnotation
visitTypeAnnotation
同ClassVisitor.visitTypeAnnotation
visitAnnotableParameterCount
访问方法参数被注解标记的次数
如:
1
2
3
4
public TypeCountAnno {
}
1
2
3 public void t1( { String a)
}
虽然我也不不知道他存在的意义是什么。
标记了注解才能被访问,而且只是给可能会被标记的参数个数。
感觉比较鸡肋的。
1 | override fun visitAnnotableParameterCount( |
visitParameterAnnotation
访问所有被标记的方法参数的注解
1 | override fun visitParameterAnnotation( |
如
1 | public class VisitParamAnnTest { |
会依此调用visitParameterAnnotation
parameter:0
descriptor:Lcom/example/asm/annotation/anno/ParamAnn1;
visible:trueparameter:1
descriptor:Lcom/example/asm/annotation/anno/ParamAnn2;
visible:trueparameter:2
descriptor:Lcom/example/asm/annotation/anno/ParamAnn3;
visible:true
visitAttribute
visitCode
表明开始对code进行处理操作
1 | override fun visitCode() |
visitFrame ToDo
用来访问局部变量表和栈的
//TODO
visitInsn
访问java中的单操作指令字节码
1 | NOP, // 空指令 |
当上方指令被调用的时候就会调用如下方法
1 | override fun visitInsn( |
visitIntsn
访问单操作数指令
1 | BIPUSH, // 入栈一个byte |
1 | public void visitIntInsn( |
visitVarInsn
拜访局部指令(即load store指令)
1 | ILOAD, LLOAD, FLOAD, DLOAD, ALOAD |
1 | override fun visitVarInsn( |
visitTypeInsn
访问“类型指令”
1 | NEW, |
1 | override fun visitTypeInsn( |
visitFieldInsn
访问“属性相关指令”
1 | // 获取&设置 static属性 |
1 | override fun visitFieldInsn( |
visitMethodInsn
同上,访问”Method相关指令“
1 | INVOKEVIRTUAL, |
1 | override fun visitMethodInsn( |
visitInvokeDynamicInsn
访问invokeDynamic指令
1 | override fun visitInvokeDynamicInsn( |
visitJumpInsn
访问和跳转相关的指令
1 | IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, // 栈顶元素和0对比,满足则跳转 |
1 | override fun visitJumpInsn( |
visitLabel
访问Label
1 | override fun visitLabel(label: Label?) |
visitLdcInsn
访问LDC指令
1 | override fun visitLdcInsn( |
visitIincInsn
访问累加iinc指令即 i += 2这类。
1 | override fun visitIincInsn( |
visitTableSwitchInsn
访问tableswitch指令
1 | override fun visitTableSwitchInsn( |
visitLookupSwitchInsn
访问lookupswitch指令
1 | override fun visitLookupSwitchInsn( |
visitMultiANewArrayInsn
访问多维数组指令MULTIANEWARRAY指令
1 | override fun visitMultiANewArrayInsn( |
visitInsnAnnotation
访问annotation指令
如下
1 | VisitInsnAnnotationTest i = new VisitInsnAnnotationTest(); |
1 | override fun visitInsnAnnotation( |
visitTryCatchBlock
访问try catch代码块
1 | override fun visitTryCatchBlock( |
visitTryCatchAnnotation
访问handler对应exception类型的annotation
如下
1 | public class VisitTryCatchAnnotationTest { |
1 | override fun visitTryCatchAnnotation( |
visitLocalVariable
访问局部变量
1 | override fun visitLocalVariable( |
visitLocalVariableAnnotation
访问局部变量的注解
1 | public class VisitLocalVariableAnnotationTest { |
1 | override fun visitLocalVariableAnnotation( |
visitLineNumber
访问代码行数
1 | override fun visitLineNumber( |
visitMaxs
访问栈的最大内存&本地变量表的最大容量
1 | override fun visitMaxs( |
visitEnd
方法访问结束