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

ASM指南翻译-9

 
阅读更多

3.1.3示例

接下来我们看看一些基本的例子,以获取关于字节码指令如何工作的具体印象。考虑下面这个Bean类:

package pkg;

public class Bean {

         private int f;

         public int getF() {

                   return this.f;

         }

         public void setF(int f) {

                   this.f = f;

         }

}

 

其中getter方法的字节码为:

ALOAD 0

GETFIELD pkg/Bean f I

IRETURN

 

第一条指令读取索引位置为0的局部变量this,这个局部变量是在这个方法调用时创建的帧的过程中被初始化的,然后将这个局部变量放置到操作数栈栈顶。第二条指令从栈顶弹出这个值,this,然后将字段f的值放置到栈顶,this.f。最后一条指令从栈顶弹出得到的字段f的值,将它返回给调用者。这个方法执行过程中帧的状态如图3.2



3.2 getF方法帧的状态:a)初始化,b)ALOAD 0以后,cGETFIELD以后

 

 

Setter方法的字节码如下:

ALOAD 0

ILOAD 1

PUTFIELD pkg/Bean f I

RETURN

 

第一条指令将this放置到操作数栈栈顶。第二条指令将索引为1的局部变量值放置到栈顶,这个索引的值为方法的参数,在方法调用创建帧的过程中初始化的。第三个指令从栈顶弹出这两个值,并将int值存贮到this对象的字段f中,this.f。最后一条指令,在源代码中是隐式定义的,但是在编译后的代码中是必须的,它负责销毁执行帧并将调用返回给调用者。这个方法的执行帧的状态如图3.3



3.3 setF方法执行帧的连续状态:a)初始化,b)ALOAD 0之后,

c)ILOAD 1以后,d)PUTFIELD以后

 

这个Bean类也有一个缺省的共有的构造方法,它是由编译器生成的,因为程序员没有显示的定义构造方法。缺省的构造方法的代码是 Bean(){ super();}。它的字节码如下:

ALOAD 0

INVOKESPECIAL java/lang/Object <init> ()V

RETURN

 

第一条指令将this放置到操作数栈栈顶。第二个指令从栈顶弹出这个值,然后调用定义在Object类中的<init>方法。这对应着super()方法调用,就是调用父类Object的构造方法。在这里可以看出这里的名称在源代码和编译后的代码中是不一样的:在编译后的类中一直为<init>,而在源代码中它们的名称和类名一样。最后一条指令返回到方法调用者。

 

下面让我们考虑一个更复杂的setter方法:

public void checkAndSetF(int f) {

         if (f >= 0) {

                   this.f = f;

         } else {

                   throw new IllegalArgumentException();

         }

}

 

这个setter方法的字节码如下:

         ILOAD 1

         IFLT label

         ALOAD 0

         ILOAD 1

         PUTFIELD pkg/Bean f I

         GOTO end

label:

         NEW java/lang/IllegalArgumentException

         DUP

         INVOKESPECIAL java/lang/IllegalArgumentException <init> ()V

         ATHROW

end:

         RETURN

 

第一条指令将索引为1的局部变量放置到操作数栈栈顶,这个局部变量就是方法参数fIFLT指令从栈顶弹出这个值,然后将它和0比较,如果结果小于0LT),执行就跳转到label表示的指令处接着执行,否则不做任何事,接着往下面执行。接下来的三条指令与之前setF中的指令相同。GOTO指令无条件地跳转到end表示的指令处,也即是RETURN指令。在labelend标签之间的指令,创建并且抛出一个异常:NEW指令创建异常对象,并将它放置到栈顶,DUP指令复制栈顶元素,并重新放置到栈顶。INVOKESPECIAL指令从栈顶取得异常的一个拷贝,然后调用这个异常对象的构造方法。最后,ATHROW指令弹出剩余的异常对象拷贝,然后抛出(这样执行流程就不会传递到下一条指令)。

 

3.1.4异常处理

没有字节码指令用于捕获异常:只有与方法关联的异常处理程序(exception handler)列表,它们指定了在方法执行的某部分发生异常时应该执行的代码。一个异常处理程序类似于try catch块:它有一个范围,就是try包含的块所对应的指令序列,异常处理程序就对应着catch块内容。范围是由startend标签指定,异常处理程序以start开始。示例代码如下:

public static void sleep(long d) {

         try {

                   Thread.sleep(d);

         } catch (InterruptedException e) {

                   e.printStackTrace();

         }

}

 

编译之后:

TRYCATCHBLOCK try catch catch java/lang/InterruptedException

try:

         LLOAD 0

         NVOKESTATIC java/lang/Thread sleep (J)V

         RETURN

catch:

         INVOKEVIRTUAL java/lang/InterruptedException printStackTrace ()V

         RETURN

 

trycatch之间的指令就对应着源码中的try代码块,catch后面的指令就对应着源码中的catch代码块。TRYCATCHBLOCK行指定了一个异常处理程序,覆盖的范围就是trycatch之间的代码,对应的处理程序从catch标签开始,对应的异常是InterruptedException的子类。这意味着在trycatch之间的任何地方发生了这样的异常,栈将被清空,异常就被放入这个空栈中,执行流程就传递到catch指令。

 

3.1.5

使用java6或者更高版本的jdk编译的类,除了包含字节码指令之外,还包含一个栈映射帧(stack map frames)集合,它们用来加速虚拟机内部的类验证流程。一个栈映射帧描述了在一个方法执行时,在一些点的执行帧状态。更精确地说法就是,它给出了在字节码指令执行前,局部变量区和操作数栈区每个值的类型(type)。

 

例如,我们来考虑之前的getF方法,我们可以定义三个栈映射帧来分别描述ALOAD,GETFIELDIRETURN这三个指令之前的执行帧状态。这三个栈映射帧对应了三种情形,见图3.2,可以如下描述,第一个括号中描述的是局部变量的类型,其它的则是操作数栈中数据的类型:

State of the execution frame before        Instruction

[pkg/Bean] []                                                 ALOAD 0

[pkg/Bean] [pkg/Bean]                               GETFIELD

[pkg/Bean] [I]                                                         IRETURN

 

我们也可以针对checkAndSetF方法进行类似的操作:

[pkg/Bean I] []                                               ILOAD 1

[pkg/Bean I] [I]                                             IFLT label

[pkg/Bean I] []                                               ALOAD 0

[pkg/Bean I] [pkg/Bean]                             ILOAD 1

[pkg/Bean I] [pkg/Bean I]                          PUTFIELD

[pkg/Bean I] []                                               GOTO end

[pkg/Bean I] []                                               label:

[pkg/Bean I] []                                               NEW

[pkg/Bean I] [Uninitialized(label)] DUP

[pkg/Bean I] [Uninitialized(label)    Uninitialized(label)] INVOKESPECIAL

[pkg/Bean I] [java/lang/IllegalArgumentException] ATHROW

[pkg/Bean I] []                                               end:

[pkg/Bean I] []                                               RETURN

 

除了Uninitialized(label)类型之外,这个和之前的方法没什么区别。这个Uninitialized(label)类型是一个特殊的类型,只用在栈映射帧中,它表示一个对象的内存已经分配,但是其构造方法还未被调用。参数表示创建这个对象的指令。对于这个值所能调用的唯一的方法就是构造方法。当构造方法调用以后,所有的Uninitialized(label)就会被替换为真实的类型,在这里就是IllegalArgumentException。栈映射帧还可以使用另外的三个特殊类型:UNINITIALIZED_THIS是构造方法中索引值为0 的局部变量的初始化类型,TOP对应着未定义的值,NULL对应着null

 

就如上面所说,从java6开始,编译的类中包含栈映射帧的集合。为了节省空间,一个编译的方法并不是每个指令都对应着一个帧:事实上只有那些对应着判断指令的目标或者异常处理程序,或者无条件跳转指令才有帧。因为其它的帧可以很容易地很快地从这些帧继承而来。

 

checkAndSetF方法的示例中,这意味着只有两个帧被存储:一个是NEW指令,因为它是IFLT指令的目标,同时它紧跟这无条件跳转指令GOTO,另外一个是RETURN指令,因为它是GOTO指令的目标,同时它紧跟着无调教跳转指令ATHROW指令。

 

为了节省更多的空间,每个帧都会被压缩,然后存储它与之前帧的不同,初始帧不被保存,因为它可以从方法的参数类型推断出来。在checkAndSetF的例子中,那两个必须被保存的帧是和初始帧相同的,因此它们使用F_SAME助记符来存储。这些帧可以在与它们关联的字节码指令之前被助记符表示。下面给出了checkAndSetF方法的最终字节码指令:

         ILOAD 1

         IFLT label

         ALOAD 0

         ILOAD 1

         PUTFIELD pkg/Bean f I

         GOTO end

label:

F_SAME

         NEW java/lang/IllegalArgumentException

         DUP

         INVOKESPECIAL java/lang/IllegalArgumentException <init> ()V

         ATHROW

end:

F_SAME

         RETURN

  • 大小: 5.4 KB
  • 大小: 6.7 KB
1
1
分享到:
评论
2 楼 aswang 2011-11-29  
wensiqun 写道
引用

[pkg/Bean] []                                                 ALOAD 0

[pkg/Bean] [pkg/Bean]                               GETFIELD

[pkg/Bean] [I]                                                         IRETURN


博主在这些指令下面有句话没译"We can do the same for the checkAndSetF method:". 不然读者以为是同一个方法的指令。


thanks!
估计当时漏掉了,我后面加上。
1 楼 wensiqun 2011-11-29  
引用

[pkg/Bean] []                                                 ALOAD 0

[pkg/Bean] [pkg/Bean]                               GETFIELD

[pkg/Bean] [I]                                                         IRETURN


博主在这些指令下面有句话没译"We can do the same for the checkAndSetF method:". 不然读者以为是同一个方法的指令。

相关推荐

    ASM3.0指南翻译

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

    ASM4使用指南.pdf

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

    ASM30-LINK30和实用程序用户指南

    根据给定的文件信息,我们可以提炼出以下几个关键的知识点,主要围绕着ASM30-LINK30和实用程序用户指南,以及Microchip Technology Inc.的相关信息进行深入解析: ### 1. 微芯科技(Microchip Technology Inc.)...

    C32Asm 反汇编工具

    在压缩包中的"读我.txt"文件,很可能是C32Asm的使用指南或注意事项,它可能包含了安装步骤、配置选项、命令行参数以及一些使用技巧。而"c32asm"可能是个可执行文件,即C32Asm工具本身,或者是一个示例文件,用于演示...

    《Win32asm与Radasm开发教程》第二阶段视频的代码和资料下载

    《汇编程序员之代码风格指南》,此书是我自己翻译的中文版,网上已有很多 地方可下载,学习汇编语言而不注意编码风格是很吃亏的事,此书能教你什么时候 该做什么,什么时候不应该做什么。良好的编码风格对于win32...

    反汇编工具 win32asm

    描述中提到的“汉化了的,好用”,意味着这个win32asm工具已经被翻译成了中文,这对于中文用户来说是一个极大的便利,因为它消除了语言障碍,使得不懂英文的开发者也能轻松使用。通常,反汇编器的界面和文档都是英文...

    ADS开发工具详细教程

    - `armasm.exe`:ARM汇编器,用于将汇编语言翻译成机器码。 - `armcc.exe`:ARM C编译器,用于将C语言源代码编译成汇编代码或机器码。 - `armcpp.exe`:ARM C++编译器,用于处理C++源代码。 - `armlink.exe`:...

    汇编程序员之代码风格指南

    本指南由著名的汇编语言专家Randall Hyde撰写,并由jhkdiy翻译成中文版。该指南旨在帮助程序员理解如何提高他们所编写的汇编代码的可读性。书中通过一系列实例来展示常见的问题及其解决方案,这些实例均来自互联网上...

    GCC中文手册.PDF

    本中文手册是由一位热心人士翻译整理的,其内容主要摘自GNU C编译器的官方文档。手册旨在为用户提供一个简明扼要的GCC使用指南,特别是针对编译器选项的解释。 #### 二、手册重要声明 1. **免责声明**:手册的内容...

    c++实现的mips汇编器

    - `ReadMe.txt`:通常包含项目说明、使用指南或者注意事项。 - `ConsoleApplication1`:可能是C++编译生成的可执行程序,包含了汇编和反汇编的功能。 - `汇编与反汇编exe`:这可能是最终生成的汇编和反汇编器的可...

    AsmToE汇编机器码转换工具

    - 中文伪指令.txt 可能包含了易语言中的特殊指令,这些指令在易语言中用中文表示,但被翻译为对应的汇编指令。 - 测试代码.txt 包含了一些示例代码,用于测试软件的功能和性能。 - 高级指令.txt 可能介绍了更复杂或...

    Linux 汇编语言开发指南

    ### Linux 汇编语言开发指南 #### 一、简介 汇编语言作为一种低级语言,在现代编程领域中虽然不如高级语言那样普及广泛,但它在特定场景下的优势不容忽视。尤其是在Linux环境中,汇编语言被用于优化性能敏感的模块...

    Windows 汇编语言编程指南

    全部翻译完了,给我的感觉就是这篇文章是为已有汇编基础但从未接触过Windows汇编编程的读者写的,虽然对我来说这些内容很简单,但也觉得说的很详细了,好过国内许多三言两语的所谓菜鸟教程;但如果读者想全面学习Win...

    Pro-E三维转二维的一些设置.pdf

    - `PRO/Emenu_translatyesnopro/enno-yes-both` 可能指的是菜单的翻译设置,用户可以根据需要选择中文、英文或者是双语界面。 - `menu_fontARIAL`:指定菜单使用的字体为Arial,确保了软件界面的一致性和可读性。 ...

    Oracle Database Reference 10.2.pdf

    2. **限制性使用**:根据许可证协议中的规定,用户不得擅自复制、翻译、广播、修改、授权、传输、分发、展示或表演软件的任何部分,除非许可证协议中有明确规定或许可,或者法律允许的情况。 3. **反向工程禁止**:...

    乐曲程序的设计与实现

    在提供的文件列表中,"huibian.doc"可能是关于ASM乐曲程序设计的一个指南或教程,可能详细介绍了如何编写和调试ASM代码以创建音乐程序。而"www.pudn.com.txt"可能是从一个编程讨论论坛或资源网站下载的资料,可能...

    dREAMtHEATER翻的国外汇编教程

    2. **Win32汇编编程指南**: - **Win32环境下的开发工具**:介绍用于编写、编译和调试Win32汇编程序所需的工具链。 - **创建Win32汇编应用程序**:讲解如何从零开始构建一个简单的Win32汇编程序。 - **Win32 API...

Global site tag (gtag.js) - Google Analytics