[JVM] CallStub 函数指针 -- 个人学习笔记 - 解密Java虚拟机1

解密Java虚拟机学习笔记 1

前言:JVM的函数调用机制

JVM是用C和C++编写的一款软件,当JVM在调用java函数时,实际上执行了一段汇编代码,最终其实执行的是机器指令。(java code -> 字节码指令 -> 机器码)
JVM 从字节码解释器(效率低) 到 模板解释器 (JVM执行java函数 就是直接执行机器指令)。

JVM内部存在一个“边界”,边界外边是C程序,边界里面则直接跳转到机器码。 (C程序可以直接调用汇编指令。) 这个边界就是: 函数指针,就是 call_stub。

C 调用机器指令

在这里插入图片描述
main()函数中,通过int (*fun)(int)定义了一个函数指针fun,通过 fun = (void *)code 将该函数指针指向一个内存地址,即code数组的首地址,最后通过reslut = fun(7)调用。

JVM内部也有一个函数指针,那就是 call_stub。

call_stub 调用机制

1. call_stub 函数指针原型定义:

call_stub()函数 其实 就是 让函数指针指向了某个内存地址。

static CallStub call_stub() {
	return CAST_TO_FN_PTR(CallStub, _call_stub_entry);
}
// CallStub 是一种自定义的类型
2. 解析
2.1 将宏替换
 #define CAST_TO_FN_PTR(func_type, value) ((func_type) (castable_address(value)))
ps:  什么是 宏 ?
在 C 语言中,可以采用命令 #define 来定义宏。该命令允许把一个名称指定成任何所需的文本,例如一个常量值或者一条语句。在定义了宏之后,无论宏名称出现在源代码的何处,预处理器都会把它用定义时指定的文本替换掉。

替换后:

static CallStub call_stub() {
	return ((CallStub) (castable_address(_call_stub_entry)));
}
2.2 CallStub是一种自定义的类型 函数指针类型
//CallStub是函数指针,指向的函数,8个入参,返回值类型 void
typedef void (*CallStub) {
	address link,
	intprt_t* result,
	BasicType result_type,
	methodOopDesc* method,
	address entry_point,
	intprt_t* parameters,
	int size_of_parameters,
	TRAPS
);

JVM内部调用 call_stub()
在这里插入图片描述
call_stub()函数原型声明,并没有入参,而JVM调用call_stub() 是却传入了8个参数 。why?
JVM 隐式的调用了函数指针。call_stub()函数最终返回的是一个函数指针的实例变量。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2.3 castable_address()

call_stub() 内部就是让函数指针指向了某个内存地址。

inline address_word castable_address(address x) {
	return address_word(x);
}

address_word 自定义类型,表示 一种地址类型

typedef uintptr_t address_word;

uintprt_t 是 平台相关的, 在特定的平台上编译JVM时,编译器会自动根据平台类型,编译不同的hpp头文件。

Jvm 内部定义了3中:

  • globalDefinitions_gcc.hpp —> linux
  • globalDefinitions_aparcWorkd.hpp --> Macintosh
  • globalDefinitions_visCPP.hpp ----> windows
// linux 平台    globalDefinitions_gcc.hpp
typedef usigned int uintprt_t;

整体替换后:

static CallStub call_stub() {
	return ((CallStub) (unsigned int (_call_stub_entry)));
}

call_stub()函数的逻辑:
第一步,将_call_stub_entry 变量 转换为 usigned int 。
第二部,将_call_stub_entry 变量 转换为CallStub 自定义类型 (函数值针)。

2.4 _call_stub_entry

_call_stub_entry 本身是address 类型, 而该类型的原型是unsigned int.

 // StubRoutines.hpp
static address  _call_stub_entry;

回顾一下 JVM调用java函数的过程:
1.JVM 先调用 call_stub() 函数,返回是 CallStub类型,即函数指针。
2.JVM 将call_stub() 函数返回的 函数指针当成函数进行调用。
(call_stub() 直接返回_call_stub_entry,然后转换成函数指针,接着JVM就直接调用该函数指针)

_call_stub_entry 函数指针指向了哪里?
JVM在初始化的过程中,便将_call_stub_entry这一变量指向了某个内存地址。

在这里插入图片描述
在这里插入图片描述

2.5 CallStub()入参

CallStub是一个函数指针,并不是函数,最终JVM通过这一函数指针调用其所指向的函数。

在这里插入图片描述
在这里插入图片描述
1) 连接器link
link 其实在java函数的调用者与被调用者之间搭建了一座桥梁, 可以实现堆栈追踪,得到整个方法的调用链路。
在Java函数调用时,link指针被保存到当前方法的堆栈中。

连接器link 所属类型是 JavaCallWrapper,
在这里插入图片描述
在这里插入图片描述
2)method()
当前java方法在JVM内部的表示对象。
在这里插入图片描述
3) entry_point
在这里插入图片描述
在这里插入图片描述
4)parameters() 入参信息
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
5)size_of_parameters() 入参个数
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值