`
aswang
  • 浏览: 848238 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

ASM指南翻译-10 生成方法

 
阅读更多

 

3.2接口和组件

3.2.1表现

ASM API中关于方法的生成和转换的部分是基于MethodVisitor接口的(见图3.4),该接口由ClassVisitorvisitMethod方法返回。除了一些与注解和调试相关的方法之外,这些将在后面章节中介绍,MethodVisitor接口还针对每个字节码指令分类定义了一个方法,这个分类是基于这些指令的编号以及参数的类型(这些分类与3.1.2章节中出现的分类并不对应)。这些方法必须按照下面给定的顺序来调用(还包含一些定义在MethodVisitor接口的JavaDoc文档中的限制):

visitAnnotationDefault?

( visitAnnotation | visitParameterAnnotation | visitAttribute )*

( visitCode

         ( visitTryCatchBlock | visitLabel | visitFrame | visitXxxInsn |

         visitLocalVariable | visitLineNumber )*

         visitMaxs )?

         visitEnd

 

这就意味着,如果存在注解和属性,那么它们必须首先被调用,然后才是方法的字节码,这只针对非抽象方法。位于visitCodevisitMax方法之间的这些方法,必须按照顺序来调用,并且visitCodevisitMax只能调用一次。

public interface MethodVisitor {

         AnnotationVisitor visitAnnotationDefault();

         AnnotationVisitor visitAnnotation(String desc, boolean visible);

         AnnotationVisitor visitParameterAnnotation(int parameter,

         String desc, boolean visible);

         void visitAttribute(Attribute attr);

         void visitCode();

         void visitFrame(int type, int nLocal, Object[] local, int nStack,

         Object[] stack);

         void visitInsn(int opcode);

         void visitIntInsn(int opcode, int operand);

         void visitVarInsn(int opcode, int var);

         void visitTypeInsn(int opcode, String desc);

         void visitFieldInsn(int opc, String owner, String name, String desc);

         void visitMethodInsn(int opc, String owner, String name, String desc);

         void visitJumpInsn(int opcode, Label label);

         void visitLabel(Label label);

         void visitLdcInsn(Object cst);

         void visitIincInsn(int var, int increment);

         void visitTableSwitchInsn(int min, int max, Label dflt,

         Label labels[]);

         void visitLookupSwitchInsn(Label dflt, int keys[], Label labels[]);

         void visitMultiANewArrayInsn(String desc, int dims);

         void visitTryCatchBlock(Label start, Label end, Label handler,

         String type);

         void visitLocalVariable(String name, String desc, String signature,

         Label start, Label end, int index);

         void visitLineNumber(int line, Label start);

         void visitMaxs(int maxStack, int maxLocals);

         void visitEnd();

}

3.4 MethodVisitor接口

在一系列的事件中,visitCodevisitMaxs可以被用来检测方法字节码的开始和结束。就像类一样,visitEnd方法必须最后被调用,同时可以用来检测类的结束。

 

ClassVisitorMethodVisitor可以一定的顺序合并起来以生成更复杂的类:

ClassVisitor cv = ...;

cv.visit(...);

MethodVisitor mv1 = cv.visitMethod(..., "m1", ...);

mv1.visitCode();

mv1.visitInsn(...);

...

mv1.visitMaxs(...);

mv1.visitEnd();

MethodVisitor mv2 = cv.visitMethod(..., "m2", ...);

mv2.visitCode();

mv2.visitInsn(...);

...

mv2.visitMaxs(...);

mv2.visitEnd();

cv.visitEnd();

 

注意,这里没有必要结束一个方法的访问之后再去访问另外一个,事实上,MethodVisitor接口是完全独立的,它们可以任何顺序来使用,只要cv.visitEnd()方法还未被调用:

ClassVisitor cv = ...;

cv.visit(...);

MethodVisitor mv1 = cv.visitMethod(..., "m1", ...);

mv1.visitCode();

mv1.visitInsn(...);

...

MethodVisitor mv2 = cv.visitMethod(..., "m2", ...);

mv2.visitCode();

mv2.visitInsn(...);

...

mv1.visitMaxs(...);

mv1.visitEnd();

...

mv2.visitMaxs(...);

mv2.visitEnd();

cv.visitEnd();

 

ASM提供了三个基于MethodVisitor接口的组件来生成和转换方法:

 

  • ClassReader解析编译后方法的内容,然后调用MethodVisitor接口中对应的方法,其中MethodVisitor实例由ClassVisitor返回,而ClassVisitor实例被当做参数传递给ClassReaderaccept方法。
  • ClassWritervisitMethod方法返回MethodVisitor接口的一个实现,由它来直接以二进制的方式构建编译后的方法。
  • MethodAdapterMethodVisitor的一个实现,它将自己接受的方法调用委托给其他的MethodVisitor实例。

 

ClassWriter的选项

 

如我们在3.1.5章节中所见,计算一个方法的栈映射帧并不容易:你必须计算所有的帧,找到与跳转目标以及那些无条件跳转想对应的帧,最后压缩这些帧。同样地,计算一个方法的局部变量和操作数栈的大小也不容易,虽然相对而言容易点。

 

令人高兴地是,ASM可以为你计算这些东西。当你创建一个ClassWriter时,你可以指定哪些是需要自动计算的:

 

  • new  ClassWriter(0) 将不会自动进行计算。你必须自己计算帧、局部变量和操作数栈的大小。
  • new ClassWriter(ClassWriter.COMPUTE_MAXS) 局部变量和操作数栈的大小就会自动计算。但是,你仍然需要自己调用visitMaxs方法,尽管你可以使用任何参数:实际上这些参数会被忽略,然后重新计算。使用这个选项,你仍然需要计算帧的大小。
  • new ClassWriterClassWriter.COMPUTE_FRAMES 所有的大小都将自动为你计算。你也不许要调用visitFrame方法,但是你仍然需要调用visitMaxs方法(参数将被忽略然后重新计算)。

 

使用这些选项是方便很多,但是会带来一些损失:COMPUTE_MAXS选项将使得ClassWriter10%,使用COMPUTE_FRAMES选项将使得ClassWriter慢两倍。你必须将它与自己计算花费的时间相比较:与ASM提供的算法相比较,在某些特定的情况下,这里有一些更容易和快速的算法来进行计算,但是必须处理所有的情形。

 

如果你选择自己计算这些帧的大小,你可以让ClassWriter来帮你进行帧压缩。这样的话,你只能使用visitFrame(F_NEW,nLocals,locals,nStack,stack)方法去访问那些未被压缩的帧,nLocalsnStack代表局部变量和操作数栈的大小,localsstack是一些包含对应类型的数组(参看JavaDoc)。

 

注意,为了自动计算帧的大小,有时必须计算两个类共同的父类。缺省情况下,ClassWriter将会在getCommonSuperClass方法中计算这些,通过在加载这两个类进入虚拟机时,使用反射API来计算。但是,如果你将要生成的几个类相互之间引用,这将会带来问题,因为引用的类可能还不存在。在这种情况下,你可以重写getCommonSuperClass方法来解决这个问题。

 

 

3.2.2生成方法

 

3.1.3节中定义的getF方法字节码可以通过下面的方法调用来生成,其中mvMethodVisitor

mv.visitCode();

mv.visitVarInsn(ALOAD, 0);

mv.visitFieldInsn(GETFIELD, "pkg/Bean", "f", "I");

mv.visitInsn(IRETURN);

mv.visitMaxs(1, 1);

mv.visitEnd();

 

从第一个方法开始进行字节码生成,紧跟着的三个方法调用用来生成方法中的代码(字节码和ASM API之间的映射还是很简单的)。visitMaxs方法必须在其他方法被调用之后再调用,它是用来这个方法的执行帧中局部变量和操作数栈的大小的。如在3.1.3节中见到的,一个方框表示一部分。最后的方法调用是用来结束方法的生成。

 

相应地,setF方法和构造方法也可以相似的方式来生成。一个比较有意思的例子是checkAndSetF方法:

mv.visitCode();

mv.visitVarInsn(ILOAD, 1);

Label label = new Label();

mv.visitJumpInsn(IFLT, label);

mv.visitVarInsn(ALOAD, 0);

mv.visitVarInsn(ILOAD, 1);

mv.visitFieldInsn(PUTFIELD, "pkg/Bean", "f", "I");

Label end = new Label();

mv.visitJumpInsn(GOTO, end);

mv.visitLabel(label);

mv.visitFrame(F_SAME, 0, null, 0, null);

mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");

mv.visitInsn(DUP);

mv.visitMethodInsn(INVOKESPECIAL,

"java/lang/IllegalArgumentException", "<init>", "()V");

mv.visitInsn(ATHROW);

mv.visitLabel(end);

mv.visitFrame(F_SAME, 0, null, 0, null);

mv.visitInsn(RETURN);

mv.visitMaxs(2, 2);

mv.visitEnd();

 

visitCodevisitEnd调用之间的方法调用和3.1.5节最后展示的字节码是精确映射的。每个调用对应一个指令,标签或者帧(唯一的例外就是labelend label的声明和构造)。

 

注意 一个label对象指定的指令就是那些紧跟在这个labelvisitLabel方法调用之后。例如,end指定了RETURN指令,不是其后的frame,因为它不是一个指令。可以使用几个标签来指定相同的指令,但是一个标签必须指定一个指令。换句话说,可以针对不同的label连续调用visitLabel,但是在一个指令中使用的标签必须只能被visitLabel访问一次。最后一个限制就是标签不能共享,每个方法都有自己的标签。

1
3
分享到:
评论

相关推荐

    ASM使用指南-中文版

    这份中文指南将帮助开发者快速入门,通过实例和详细的解释,深入理解ASM的使用方法和最佳实践。 在阅读“ASM4使用指南.pdf”时,重点关注以下部分: - ASM的基本架构和核心组件介绍 - 如何使用ClassWriter和...

    ASM3.0指南翻译

    ### ASM3.0指南翻译——深入理解Java字节码引擎库 #### 1. 引言与背景 在软件开发领域,程序分析、生成及转换技术的应用极为广泛,覆盖从语法解析到语义分析,再到代码优化、混淆、调试、性能监控及面向切面编程等...

    ASM4使用指南.pdf

    根据提供的文件信息,以下是关于“ASM4使用指南.pdf”文档中所提及知识点的详细介绍: 1. ASM库介绍: ASM(Java字节码操作和分析框架)是一个Java字节码操作与分析框架。它被设计用于直接以类文件的形式读写和修改...

    asm4-guide.pdf

    Java的asm文档,来自官方。asm4-guide.pdf。ASM 是一个 Java 字节码操控框架。...ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。说白了asm是直接通过字节码来修改class文件。

    asm4-guide

    - Adding and removing class members:说明了如何使用ASM库向类中添加或移除成员(字段、方法等)。 - Generating classes:描述了如何使用ASM生成新的类。 - Parsing classes:说明了ASM如何解析已有的类文件。 ...

    ASM-all 6.2

    4. **类和方法的生成**:ASM提供了`ClassWriter`和`MethodWriter`类,它们可以用来生成新的类或方法的字节码,这对于动态代码生成非常关键。 5. **事件驱动的API设计**:ASM的设计基于事件驱动,这意味着在解析类或...

    asm操作指南(中文)

    ### asm操作指南(中文)知识点总结 #### 一、ASM框架简介 - **定义与功能**:ASM是一个Java字节码操纵框架,主要用于动态生成类或增强现有类的功能。通过直接生成二进制`.class`文件,ASM能够在类被加载到Java...

    ASM4使用指南

    它不仅提供了关于如何使用库的详细指南,还对 ASM4 在程序分析、生成和转换方面的作用提供了深刻的理解。这不仅包括 ASM4 的基本概念和架构,还包括更高级的主题,例如如何利用 ASM4 实现高效的类文件分析和转换,...

    asm-guide.rar

    在阅读《ASM指南》的过程中,你将逐步掌握ASM的基本用法,包括类、字段和方法的解析,以及如何生成和修改字节码。同时,书中还会提供丰富的示例代码,帮助你快速上手并应用于实际项目中。 总之,《ASM指南》是一本...

    ASM7使用指南.pdf

    ### ASM7使用指南知识点 #### 1. 引言与动机 **ASM**(Abstract Syntax Model)是一款专门针对Java字节码操作的强大工具库,它主要用于程序分析、生成及转换等场景。根据提供的文档信息来看,尽管标题为“ASM7使用...

    asm-2.0.jar.zip

    2. **字节码生成**:除了解析,ASM还支持生成新的字节码,允许开发者动态创建或修改类和方法。这对于实现Java代理、AOP(面向切面编程)或者动态语言的JVM实现是非常关键的。 3. **高性能**:ASM设计时注重性能,其...

    asm4使用指南(强烈推荐)

    标题《asm4使用指南(强烈推荐)》以及描述《java使用asm4操作字节码技术,详细介绍了asm如何对java的字节码进行操作,强烈推荐》指明了文档的核心内容是介绍ASM4这一工具在Java字节码层面操作的指南,并且给出了...

    NASM 帮助文档 语法

    #### 二、安装指南 **1.3 安装** - **1.3.1 在MS-DOS或Windows下的安装:** - 确保计算机上已安装了支持环境。 - 下载NASM的最新版本,解压缩后将其添加到系统路径中。 - **1.3.2 在Unix下的安装:** - 使用包...

    ASM4使用指南.

    ASM4使用指南. asm是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。asm可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。

    ASM4中文使用指南.zip

    ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以...ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

    Oracle 10.2 ASM 最佳实践 最终版本

    在实际应用中,结合最佳实践和技术指南,可以使ASM更好地服务于企业级数据库环境。 #### 附录 - **查看和发现字符串**:提供了一系列视图和发现字符串,用于查询ASM的相关信息。 - **单个非ASM数据文件迁移到ASM**...

    asm的jar包

    1. **文档**:这部分可能包括Javadoc文档,详细解释了ASM库中的各种类和方法,帮助开发者理解如何使用API。文档还可能包含用户指南、教程和示例代码,帮助初学者快速上手。 2. **jar文件**:ASM的核心库,即asm-*....

Global site tag (gtag.js) - Google Analytics