CallStub相关
CallStub相关
调用入口
share/vm/runtime/stubRoutines.hpp
// Calls to Java SimonNote: 函数指针结合typedef类型定义
typedef void (*CallStub)(
address link,
intptr_t* result,
BasicType result_type,
Method* method,
address entry_point,
intptr_t* parameters,
int size_of_parameters,
TRAPS
);
// Calls to Java SimonNote: 将内存地址 转换成函数指针 CAST_TO_FN_PTR ((CallStub)(castable_address(_call_stub_entry)))
static CallStub call_stub() { return CAST_TO_FN_PTR(CallStub, _call_stub_entry); }
CAST_TO_FN_PTR 宏转换成 ((CallStub)(castable_address(_call_stub_entry)))
share/vm/runtime/javaCalls.cpp中调用call_stub部分
StubRoutines::call_stub()(
(address)&link,
// (intptr_t*)&(result->_value), // see NOTE above (compiler problem)
result_val_address, // see NOTE above (compiler problem)
result_type,
method(),
entry_point,
args->parameters(),
args->size_of_parameters(),
CHECK
);
注意: call_stub 后面先接了一个()拿到函数指针后又接了一个括号含参数列表
入参
8个入参及含义
编号 | 参数名称 | 含义 | 压栈位置 | call entry_point时的位置 |
---|---|---|---|---|
1 | link | 连接器 JavaCallWrapper类型,可以理解成调用上下文 | 2N(%ebp) | 2N(%ebp) |
2 | result_val_address | 函数返回值地址 | 3N(%ebp) | 3N(%ebp) |
3 | result_type | 函数返回类型 | 4N(%ebp) | 4N(%ebp |
4 | method() | JVM内部所表示的JAVA方法对象 | 5N(%ebp) | ebx |
5 | entry_point | JVM调用JAVA方法例程入口。JVM内部的每一段例程是在启动时生成好。要调用JAVA方法,都需要经过本例程。然后才跳转到JAVA方法字节码所对应的机器指令去执行。 | 6N(%ebp) | eax |
6 | args->parameters() | JAVA方法入参集合 | 7N(%ebp) | edx |
7 | args->size_of_parameters() | JAVA方法入参数量 | 8N(%ebp) | ecx |
8 | CHECK | 当前线程对象 | 9N(%ebp) | 9N(%ebp) |
CHECK 宏展开 the_thread); if ((((ThreadShadow*)the_thread)->has_pending_exception())) return ; (void)(0
JVM调用java程序main()主函数的路线图:
JVM主函数--> 调用CallStub(_call_stub_entry例程)--> 调用entry_point(entry_point例程)--> 调用Java函数
_call_stub_entry例程生成好了之后指向函数首地址,然后在调用时会将其强转成函数指针,这个函数就是CallStub
。转就是CAST_TO_FN_PTR宏干的。
_call_stub_entry例程生成
cpu/x86/vm/stubGenerator_x86_64.cpp
void generate_initial() {
// Generates all stubs and initializes the entry points
// This platform-specific settings are needed by generate_call_stub()
create_control_words();
// entry points that exist in all platforms Note: This is code
// that could be shared among different platforms - however the
// benefit seems to be smaller than the disadvantage of having a
// much more complicated generator structure. See also comment in
// stubRoutines.hpp.
StubRoutines::_forward_exception_entry = generate_forward_exception();
StubRoutines::_call_stub_entry =
generate_call_stub (StubRoutines::_call_stub_return_address);
....
generate_call_stub 所做的事情就是将CallStub
的函数体直接以机器码的形式写入内存区域。很猛!
大概逻辑:
- c++层面的参数入栈
- 计算实际被调用的java方法的参数大小(这个是在编译期算出来的)算出需要的栈大小
- 计算 rdi rsi rbx mxcsr 四个寄存器所占用的栈空间大小
- 将上面计算出来的栈大小(在ecx寄存器中)拿出来完成栈空间分配,sub %ecx %esp。至此,JVM完成了动态栈分配。
- 调用者保存,因为是CallStub调用了java方法,那么java方法的调用者就是CallStub。现在需要保存调用者自己的寄存器数据。主要包括edi,esi,edx。在JVM中,esi存放java指令偏移地址,ebx存放java指令基地址。调用者保存实际是将刚才几个寄存器的值在栈中暂存。
- 参数压栈。是将java方法的参数入栈。采用循环迭代参数的方式。汇编层面用了跳转指令,有用到test je jne dec inc mov指令。java函数入参数量在ecx物理寄存器中。edx中存放的是parameters首地址。压完之后 栈帧中数据大概是 C++的CallStub的8个入参,eip ebp加上步骤3的4个寄存器共6个的暂存值,接着是java方法的入参。
- 调用entry_point例程。entry_point也是函数指针。在调用entry_point例程之前,会生成一些机器码将CallStub一些入参放入寄存器,有:将method首地址放到ebx;将entry_point放到eax,将当前栈顶esp放到esi;放的方式都是基于一开始压栈的地址处理的。比如entry_point,mov 0x18(%ebp), %eax 。然后调用entry_point时,直接call ×%eax即可。为什么要将这些放入寄存器,因为调用entry_point时用的call指令,call指令会“切换新的栈帧”(是这么个意思),所以之前的这些对象就不好基于栈再寻址了,就将其先放到寄存器里。另外没放的4个参数在entry_point例程中用不到。
- 获取entry_point的返回值。调用完之后 会将栈上的被调用者的返回值与返回类型mov到edi和esi两个寄存器中。调用放要用时就到这个寄存器中获取。
CallStub相关的更多相关文章
- 嵌入式单片机STM32应用技术(课本)
目录SAIU R20 1 6 第1页第1 章. 初识STM32..................................................................... ...
- HotSpot的执行引擎-CallStub栈帧
之前多次提到接触到调用JavaCalls::call()方法来执行Java方法,如: (1)Java主类装载时,调用JavaCalls::call()方法执行的Java方法checkAndLoadMa ...
- java中的字符串相关知识整理
字符串为什么这么重要 写了多年java的开发应该对String不陌生,但是我却越发觉得它陌生.每学一门编程语言就会与字符串这个关键词打不少交道.看来它真的很重要. 字符串就是一系列的字符组合的串,如果 ...
- SQL Server相关书籍
SQL Server相关书籍 (排名不分先后) Microsoft SQL Server 企业级平台管理实践 SQL Server 2008数据库技术内幕 SQL Server性能调优实战 SQL S ...
- dotNET跨平台相关文档整理
一直在从事C#开发的相关技术工作,从C# 1.0一路用到现在的C# 6.0, 通常情况下被局限于Windows平台,Mono项目把我们C#程序带到了Windows之外的平台,在工作之余花了很多时间在M ...
- 在ASP.NET Core应用中如何设置和获取与执行环境相关的信息?
HostingEnvironment是承载应用当前执行环境的描述,它是对所有实现了IHostingEnvironment接口的所有类型以及对应对象的统称.如下面的代码片段所示,一个HostingEnv ...
- virtualbox linux虚拟机相关
linux虚拟机设置为静态IP 在virtualbox中安装好linux虚拟机后,如果采用的是NAT方式的话,linux虚拟机默认采用dhcp方式自动上网,而且用的是NetworkManager服务而 ...
- WebGIS中等值面展示的相关方案简析
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.背景 等值面是气象.环保等相关项目上常用到的效果展示.在传统的CS项 ...
- .NET同步与异步之相关背景知识(六)
在之前的五篇随笔中,已经介绍了.NET 类库中实现并行的常见方式及其基本用法,当然.这些基本用法远远不能覆盖所有,也只能作为一个引子出现在这里.以下是前五篇随笔的目录: .NET 同步与异步之封装成T ...
随机推荐
- Lucas定理 & Catalan Number & 中国剩余定理(CRT)
又双叒叕来水数论了 今天来学习\(Lucas \:\ \& \:\ Catalan Number\) 两者有着密切的联系(当然还有CRT),所以放在一起学习一下 \(Lucas\) 定义\(\ ...
- 一个有趣的问题, 你知道SqlDataAdapter中的Fill是怎么实现的吗
一:背景 1. 讲故事 最近因为各方面原因换了一份工作,去了一家主营物联柜的公司,有意思的是物联柜上的终端是用 wpf 写的,代码也算是年久失修,感觉技术债还是蛮重的,前几天在调试一个bug的时候,看 ...
- 7个获取访问者真实IP的方法,速学!!!
通常情况下,网站访问并不是简单地从用户的浏览器直达服务器,中间可能部署有CDN.WAF.高防.例如,采用这样的架构:“用户 > CDN/WAF/高防 > 源站服务器” .那么,在经过多层代 ...
- laravel报错1071 Specified key was too long; max key length is 1000 bytes
Laravel 默认使用utf8mb4字符编码,而不是的utf8编码.因此运行php artisan migrate会出现如下错误: [Illuminate\Database\QueryExcepti ...
- java动态代理——字段和方法字节码的基础结构及Proxy源码分析三
前文地址:https://www.cnblogs.com/tera/p/13280547.html 本系列文章主要是博主在学习spring aop的过程中了解到其使用了java动态代理,本着究根问底的 ...
- 企业权限管理(SSM整合)(总结)
学于黑马程序员和传智播客联合做的教学项目 感谢 黑马程序员官网 传智播客官网 个人根据教程的每天的工作进度的代码和资料 密码:cti5 b站在线视频 微信搜索"艺术行者",关注并回 ...
- C/C++编程笔记:C++入门知识丨运算符重载
本篇要学习的内容和知识结构概览 运算符重载使用场景 常规赋值操作 我们现在有一个类 想要实现这种赋值操作 具体实现如下: 所以说呢,我们在使用运算符进行运算的时候, 实际上也是通过函数来实现运算的. ...
- 程序人生丨听说程序员是相当就能当的?BAT大牛当场就不乐意了!
有一种对软件开发者的偏见是:他们都是无趣的极客,是学校里的数学天才,每天都要在计算机屏幕前花费多个小时去写代码. 没错,开发者确实会在计算机屏幕前花费多个小时去写代码.但是,每天的工作中还有很多比写代 ...
- SpringCloud生产消费者
SpringCloud生产消费者 生产者与消费者 上一篇文章介绍了Euarka的搭建,SpringCloud服务注册中心 本篇文章,我们搭建俩个服务,生产者服务与消费者服务. 本文就以电商系统为例:服 ...
- hibernate数据库连接池,常用配置
<!-- 最大连接数 --> <property name="hibernate.c3p0.max_size">20</property> &l ...