JVM指令 bytecode invokespecial

本文译自:http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokespecial

invokespecial

操作

调用实例初始化,父类初始化和私有方法。

格式

invokespecial
indexbyte1
indexbyte2

编码

invokespecial = 183 (0xb7)

操作数栈

..., objectref, [arg1, [arg2 ...]] →

描述

无符号indexbyte1andindexbyte2用来构造一个指向当前类的运行时常量池索引,索引值通过(indexbyte1 << 8) | indexbyte2.构造得出。运行时常量池在该索引的位置必须为一个方法类型的符号引用,该符号引用给出了该方法的名称和描述以及包含该方法的类的符号引用。该方法被解析。最终,如果该方法是protected的,并且是当前类父类的成员方法,但没有在当前类所属的运行时package中声明,那么,objectref的类型要么为当前类,要么为当前类的子类。

下一步,如果下列条件不同时成立,则当前方法被选为将要调用的方法:

  • 当前类设置了ACC_SUPER标记。
  • 该方法所属类为当前类的父类。
  • 该方法不是实例初始化方法。

如果上述条件全部成立,则实际调用的方法按照如下过程进行查找,假设C为当前类的直接父类。

  • 如果C包含了和该方法一样的名称和描述符声明,则C中的该声明则为查找结果,超找结束。
  • 否则,在C的直接父类中执行第一步的查找,该查找迭代进行。
  • 否则,抛出AbstractMethodError错误。

Objectref必须为引用类型,在操作数栈中,nargs个参数必须紧跟在objectref后面,并且在个数,类型和顺序上必须和上述步骤查找到的方法一致。

如果该方法是同步的(synchronized),则在与objectref关联的监视器上执行enter或reenter操作,就像在当前线程中执行monitorenter指令一样。

    如果该方法不是native的,nargs个参数和objectref从栈中弹出,在当前JVM栈中为该方法创建一个新的栈帧。Objectref和nargs个参数值连续存入新栈帧的局部变量表。Objectref存入slot0,arg1存入slot1(或者,如果arg1为long或double类型,则占连续两个slot,为slot1,slot2),以此类推。任何float类型的变量在存入局部变量表之前都会先进行值集转换。新栈帧成为当前栈帧,JVM PC设置为新方法的第一条指令,程序执行从该方法第一条指令继续。

如果该方法是native的,并且平台相关的实现代码尚未绑定到当前JVM,就这样(译者:不再绑定?)。nargs个参数和objectref从操作数栈中弹出,作为参数依次传递给实现代码作为局部变量。任何float类型的变量在存入局部变量表之前都会先进行值集转换。参数的传递和代码执行方式依赖于具体的实现方式,当方法返回时,发生如下情形:

 

  • 如果native方法是同步的(synchronized),则和objectref关联的监视器被更新并可能退出,就像在当前线程中执行monitorexit指令一样。
  • 如果方法有返回值,则该平台相关的返回值按照平台相关的实现方式转换成该方法的返回类型,并压入操作数栈。

链接异常

在对该方法的符号引用进行解析时,任何与方法解析相关的异常都可能被抛出。

否则,如果解析出的方法为实例初始化方法,并且其声明所在类与当前指令符号引用的类不一致,则会抛出NoSuchMethodError错误。

否则,如果解析出的方法是类方法(static),则invokespecial指令会抛出IncompatibleClassChangeError错误。

运行时异常

否则,如果objectref是null,则invokespecial指令将抛出NullPointerException异常。

否则,如果没有方法和对应的名字和描述符匹配,则invokespecial指令将抛出AbstractMethodError错误。

否则,如果解析出的方法是native的,但实现代码无法被绑定,则invokespecial指令将抛出UnsatisfiedLinkError错误。

备注

Invokespecialinvokevirtual的区别在于,后者对方法的调用基于对象的class类型,而前者用来调用当前类的实例化方法,私有方法以及父类的方法(译者:感觉此处有误,应该是父类的实例化方法)。

早在JDK1.0.2之前,invokespecial使用invokevirtual的名字。

nargs个参数并不一定就对应nargs个局部变量,对于long或double类型的参数值就需要连续两个局部变量的位置来存储,这时,nargs个参数的传递就需要多于nargs个的局部变量位置。

posted @ 2021-07-26 22:45  方东信  阅读(177)  评论(0编辑  收藏  举报