模块二高效编译12讲19丨java字节码基础篇_第1页
模块二高效编译12讲19丨java字节码基础篇_第2页
模块二高效编译12讲19丨java字节码基础篇_第3页
模块二高效编译12讲19丨java字节码基础篇_第4页
模块二高效编译12讲19丨java字节码基础篇_第5页
已阅读5页,还剩16页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

具体来说便是:执行每一条指令之前,Java虚拟机要求该指令的操作数已被压入操作数栈中。在执行指令时,Java虚拟机会将该指令所需的操作数弹出,并且将指令的结果重新压iaddint1int2iaddintint3iadd2号,iadd指令并不关心它是否存在,更加不会对其进行修改。Java字节码中有好几条指令是直接作用在操作数栈上的。最为常见的便是dup:栈顶元素,以及pop:舍弃栈顶元素。dup指令常用于new指令所生成的初始化的。例如在下面这段代码的foo方法中,当执行new指令时,Java虚拟机将指向一块已分配的、未初始化的内存的压入publicvoidfoo()Objecto=new //publicvoid0newjava.lang.Object34invokespecialjava.lang.Object()7astore_18(不过Object)因此,我们需要利用dup指令一份new指令的结果,并用来调用构造器。当调用返回之后,操作数栈上仍有原本由new指令生成的,可用于接下来的操作(即偏移量为7的字节码,下面会介绍到)。popfoo用静态方法bar,但是却不用其返回值。invokestaticfooJava拟机需要额外执行pop指令,将返回值舍弃。1publicstaticbooleanbar()2return3}45publicvoidfoo()67}8//foo9publicvoid0invokestaticFooTest.bar():34需要注意的是,上述两条指令只能处理非long或者非double类型的值,这是因为long类型或者double类型的值,需要占据两个栈单元。当遇到这些值时,我们需要同时栈顶两个单元的dup2指令,以及弹出栈顶两个单元的pop2指令。swapJavaintJava虚拟机既可以通过iconst指令加载-1至5之间的int值,也可以通过bipush、sipush加载一个字节、两个字节所能代表的int值。Javaldcldc18intlongfloatdoubleStringClassJava方法的另外一个重要组成部分则是局部变量区,字节码程序可以将计算的结果缓实际上,Javathis(仅非静态方法),和操作数栈一样,longdouble2{3inti=4}5{6String2{3inti=4}5{6Strings=7}8o,foo0单元存放着this指针。第一个参数为long类型,于是数组的1、2两个单元存放着所传入的long类型参数的float3float变量数组的第4个单元将为i或者s储至局部变量数组中。这些加载、指令是区分类型的。例如,int类型的加载指令为iload,指令为istore。局部变量数组的加载、指令都需要指明所加载单元的下标。举例来说,aload0指的是加载第0个单元所的,面示例中的foo方法里指的便是加载this指针。在我印象中,Java字节码中唯一能够直接作用于局部变量区的指令是iincMN(M为非负整数,N为整数)。该指令指的是将局部变量数组的第M个单元中的int值增加N,常用于for循环中自增量的更新。 publicvoidfoo() for(inti=100;i>=0;i--) // publicvoid60bipush72istore_183goto96iinc1-1[i]//i-9iload_1ifge1publicstaticintbar(inti) return((i+1)-2)*3/3//stack=2,locals=1,789barint空间为1。当调用bar(5Java前面我已经介绍了加载常量指令、操作数栈指令以及局部变量区指令。下面我们来Java相关指令,包括各类具备语义的字节码,即new(后跟目标类,生成该类的未初始化的对象),instanceof(后跟目标类,判断栈顶元素是否为目标类/接口的实例。是则压入1,否则压入0),checkcast(如果不是便抛出异常),athrow(将栈顶异常抛出),以及monitorenter(为栈顶对象加锁)和monitorexit(为栈顶对象)。此外,该类型的指令还包括字段指令,即静态字段指令getstatic、putstatic,和实例字段指令getfield、putfield。这四条指令均附带用以定位目标字段的信息,但所以putfield为例,在上图中,它会把值v至对象obj的目标字段之中方法调用指令,包括invokestatic,invokespecial,invokevirtual,invokeinterface以及invokedynamic。这几条字节码我们已经反反复复提及了,就不再具体介绍各自的含义除invokedynamic外,其他的方法调用指令所消耗的操作数栈元素是根据调用类型以及目标方法描述符来确定的。在进行方法调用之前,程序需要依次压入调用者(invokestatic不publicintneg(inti)return- 4publicintfoo(inti)return //foo方法对应的字节码如下:foopublicintfoo(int0aload_01aload_02iload_13invokevirtualFooTest.neg(int):int6invokevirtualFooTest.neg(int):int9foo(2数组相关指令,包括新建基本类型数组的newarray,新建类型数组的anewarray,生成数组的multianewarray,以及求数组长度的arraylength。另外,它还包括数组的加载指令以及指令。这些指令是区分类型的。例如,int数组的加载指令为iaload,存储指令为iastore。控制流指令,包括无条件跳转goto,条件跳转指令,tableswitch和lookupswtich(前者针对密集的cases,后者针对稀疏的cases),返回指令,以及被废弃的jsr,ret指令。其中返回指令是区分类型的。例如,返回int值的指令为ireturn。除返回指令外,其他的控制流指令均附带一个或者多个字节码偏移量,代表需要跳转到的位置。例如下面的as方法中偏移量为1的条件跳转指令,当栈顶元素小于0时,跳转至偏移量为6的字节码。 publicintabs(inti) if(i>=0) return return- //publicintabs(int0iload_11iflt4iload_156iload_178剩余的Java今天我简单介绍了各种类型的JavaJava方法的分为操作数栈和局部变量区。通常来说,程序需要将变量从局部变量区加Java字节码可以划分为很多种类型,如加载常量指令,操作数栈指令,局部变量区访问指令,Java相关指令,方法调用指令,数组相关指令,控制流指令,以及计算相关指今天的实践环节,你可以尝试自己分析一段较为复杂的字节码,在草稿上画出局部变量数组以及操作数栈分布图。当碰到不熟悉的指令时,你可以查阅Jaa虚拟机规范第6.5小节,或者此。©归科技所有 不得售卖。页面已增加防盗追踪,将依法其上一 18|即时编译器的中间表达形下一 20|方法

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论