1. 基本概念
方法返回地址用于存放调用该方法的 pc 寄存器的值。
当一个方法开始执行后,只有两种方式退出这个方法:
第一种方式是执行引擎遇到任意一个方法返回的字节码指令,这时候可能会有返回值传递给上层的方法调用者(调用当前方法的方法称为调用者或者主调方法),方法是否有返回值以及返回值的类型将根据遇到何种方法返回指令来决定,这种退出方法的方式称为“正常调用完成”。
一个方法在正常调用完成之后究竟需要使用哪一个返回指令还需要根据方法返回值的实际数据类型而定。
在字节码指令中,返回指令包含 ireturn(当返回值是 boolean、byte、char、short 和 int 类型时使用)、lreturn、freturn、dreturn 以及 areturn(针对引用类型),另外还有一个 return 指令供声明为 void 的方法、实例初始化方法、类和接口的初始化方法使用。
另外一种退出方式是在方法执行的过程中遇到了异常,并且这个异常没有在方法体内得到妥善处理。无论是Java虚报机内部产生的异常,还是使用athrow字节码指令产生的异常。一个方法使用异常完成出口的方式退出,是不会给它的上层调用者提供任何返回值的。
正常完成出口和异常完成出口的区别在于:通过异常完成出口退出的不会给它的上层调用者产生任何的返回值。
假设 A 方法调用了 B 方法,无论 B 方法通过哪种方式退出,都会回到 A 方法调用 B 方法的调用位置。B 方法正常退出时,A 方法的 pc 计数器的值作为返回地址,即 A 方法调用 B 方法的指令的下一条指令的地址。而通过异常退出的,返回地址是要通过异常表来确定,栈帧中一般不会保存这部分信息。
本质上,方法的退出就是当前栈帧出栈的过程。此时,需要恢复上层方法的局部变量表、操作数栈、将返回值压入调用者的操作数栈、设置 PC 寄存器的值等,让调用者方法继续执行下去。