本文译自:http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokestatic
invokestatic
操作:
调用一个类(static)方法。
格式:
invokestatic
indexbyte1
indexbyte2
编码:
invokestatic = 184 (0xb8)
操作数栈
[arg1, [arg2 ...]] →
描述
无符号indexbyte1andindexbyte2用来构造一个指向当前类的运行时常量池索引,索引值通过(indexbyte1 << 8) | indexbyte2.构造得出。运行时常量池在该索引的位置必须为一个方法类型的符号引用,该符号引用给出了该方法的名称和描述以及包含该方法的类的符号引用。该方法被解析。解析得出的方法必须不是实例初始化方法,类初始化方法或者接口初始化方法。必须是static方法而且不能是abstract的。
一旦成功解析了该方法,如果包含该方法的类还没有被初始化,则初始化该类。
操作数栈必须包含nargs个参数,这些参数的个数,类型和顺序必须和方法描述符一致。
如果该方法为同步方法(synchronized),则在与解析出的Class对象关联的监视器上执行进入或重入操作,就像在当前线程执行monitorenter指令一样。
如果该方法不是native的。从操作数栈中弹出nargs个参数,在当前JVM栈中为该方法创建一个新的栈帧。nargs个参数相继作为新栈帧的局部变量,args1对应slot0(或者,如果arg0是long或者double类型,则占用slot0和slot1)以此类推。任何float类型的参数在存入局部变量表之前都会先进行值集转换。新的栈帧成为当前栈帧,JVM的PC设置为当前被调用方法的第一条指令,程序执行从该方法的第一条指令继续。
如果解析出的方法是native的,并且平台相关的实现代码尚未绑定到JVM。nargs个参数从操作数栈中弹出作为参数传递给该方法的实现代码。任何float类型的参数在存入局部变量表之前都会先进行值集转换。参数的传递和代码的执行按照平台相关的方式,当平台相关代码返回时,发生以下这些情况:
- 如果方法是native的,则和解析出的Class对象关联的监视器被更新并可能退出,就像在当前线程中执行monitorexit指令一样。
- 如果native方法有返回值,则该返回值按照平台相关的方式转换成该函数的返回类型,并压入操作数栈。
链接异常
在对该方法的符号引用进行解析时,任何与方法解析相关的异常都可能被抛出,并且,如果解析出的方法是实例方法,则invokestatic指令会抛出一个IncompatibleClassChangeError错误。
运行时异常
如果执行
invokestatic导致引用的类被初始化,则可能抛出类初始化阶段相关的错误。
如果解析出来的方法是
native的,但实现代码无法绑定到JVM,则
invokestatic指令会抛出一个
UnsatisfiedLinkError错误。
注意
nargs个参数并不一定就对应nargs个局部变量,对于long或double类型的参数值就需要连续两个局部变量的位置来存储,这时,nargs个参数的传递就需要多于nargs个的局部变量位置。