目录
2、 call_special、call_virtual、call_static
在上一篇博客中《Hotspot JNI和字节码方法调用源码解析》中我们从JNI方法调用API和方法调用字节码指令两个层面讲解了方法调用的入口,接下来的多篇博客就以这个为出发点,顺藤摸瓜深入了解方法调用实现的具体细节,本篇博客重点讲解本地代码调用Java方法的核心入口JavaCalls的相关实现。
一、JavaValue
JavaValue是一个可以保存任何类型的Java变量的容器,其定义位于hotspot/src/share/vm/utilities/globalDefinitions.hpp中,只有两个private属性:
- _type:BasicType类型,表示变量的类型,BasicType定义了JVM中用到的所有类型
- _value:JavaCallValue类型,实际是一个union类型,用于存储具体的Java变量。
BasicType的定义在globalDefinitions.hpp中,如下:
其中T_NARROWOOP和T_NARROWKLASS表示压缩的oop和klass指针,T_METADATA就是class文件相关的元数据,T_ADDRESS表示ret指令用到的表示返回地址的returnAddress类型。
JavaCallValue类型的定义就是JavaValue内部,如下:
为啥没有jbyte,jchar,jshort,jboolean这四个类型了?答案是JVM会利用这四个类型向上转换成jint类型都不会有精度丢失的特点将这些类型在编译期或者运行期扩展成jint类型,从而避免单独为这些类型定义字节码指令,如果定义了总的字节码数量将会超过1个字节所能表示最大指令个数即255。比如某个对象的jshort类型的属性在内存中占用两字节,但是通过字节码指令对该属性做加减运算时会将其扩展成jint类型,计算完成会将结果转换成jshort类型保存在内存中。《Java虚拟机规范》中给出一张Java虚拟机中实际类型与运算类型的对应关系表,如下图:
JavaValue定义的方法也验证了上述逻辑,除了给JavaCallValue中包含的类型定义对应的set和get方法外,还给jbyte,jchar,jshort,jboolean类型单独定义了4个get方法,注意只有get方法,其实现如下:
value.i 就是以jint的方式读取_value变量,再将其强转成对应的jboolean等类型。
二、JNI_ArgumentPusher
JNI_ArgumentPusher表示JNI方法调用的参数解析工具类,其定义位于hotspot/src/share/vm/prims/jni.cpp中,其类继承关系如下图,下面逐一分析各类。
1、ResourceObj
AllocatedObj是所以从内存分配的对象的基类,主要定义了打印日志的方法,如下图:
ResourceObj是所有在资源区域(resource area,资源区域的定义参考memory/resourceArea.hpp)内分配的对象的基类,主要定义了new和delete运算符的各种重载方法,如下图:
2、SignatureIterator
SignatureIterator表示一个字段或者方法描述符的遍历器,即可以从描述符中获取类型信息,参数个数等,其定义的4个protected属性说明如下:
- _signature:Symbol指针,指向对应的描述符字符串
- _index:int类型,遍历期间用于记录当前遍历的字符在字符串中的索引
- _parameter_index:int类型,参数遍历时记录当前参数的索引
- _return_type:返回值的类型
SignatureIterator定义并实现了描述符遍历的骨架方法,将对具体参数类型的处理回调逻辑定义成do开头的虚方法,由子类去实现,如下图:
以iterate_parameters为例说明其实现逻辑,参考同目录的signature.cpp,源码说明如下:
void SignatureIterator::iterate_parameters() {
// Parse parameters
_index = 0;
_parameter_index = 0;
//方法描述符的参数部分都是以(开始的,如果不是抛出异常
expect('(');
//逐个字符往后遍历直到),_parameter_index会不断增加
while (_signature->byte_at(_index) != ')') _parameter_index += parse_type();
//方法描述符的参数部分都是以)结尾的
expect(')');
//遍历完成将_parameter_index重置成0
_parameter_index = 0;
}
int SignatureIterator::parse_type() {
// Note: This function could be simplified by using "return T_XXX_size;"
// instead of the assignment and the break statements. However, it
// seems that the product build for win32_i486 with MS VC++ 6.0 doesn't
// work (stack underflow for some tests) - this seems to be a VC++ 6.0
// compiler bug (was problem - gri 4/27/2000).
int size = -1;
//读取当前_index的字符
switch(_signature->byte_at(_index)) {
case 'B':
do_byte (); //执行回调逻辑
if (_parameter_index < 0 ) _return_type = T_BYTE; //_parameter_index小于0说明方法描述符中参数部分遍历完成,剩下的就是返回值类型
_index++; size = T_BYTE_size ; break;
case 'C': do_char (); if (_parameter_index < 0 ) _return_