java虚拟机(二)

JVM函数调用机制

JVM要实现直接由C语言直接调用机器指令,通过两种方式。
第一、C语言内嵌汇编,内嵌汇编只能实现C语言直接调用汇编指令,而不是机器指令,机器指令和汇编指令还是有很大差距,例:(MOV AX,1234H 对应的机器码为:B83412)。
第二、函数指针,通过函数指针,C语言可以将一个变量指向一个函数的首地址,C语言被编译时,C函数直接被编译成为机器指令,而这个函数指针将直接指向这段机器指令的首地址。

1、JVM内部通过函数指针进行函数调用。

函数指针

int (*addPointer) (int a,int b),可以将其指向一个入参为两个int的函数。

1.1CallStub函数指针
1.1.1_call_stub_entry例程

1、pc()函数,保存当前例程所对应的一段机器码的起始位置。
2、generate_all_stub(),得到调用者函数和被调用者函数的参数关系,通过相对位置寻址。
3、CallStub:保存调用者堆栈,保存调用者函数的栈基地址,重新定义栈基地址。
4、CallStub:动态分配堆栈。JVM为了能够调用java函数,需要在运行期知道一个java函数的入参大小,然后动态的计算出所需要的堆栈空间。JVM通过堆栈的“寄生”机制,扩展别人的堆栈,存储自己所需要的数据。call_helper()并没有直接将java函数的入参传递给CallStub(),因为这个调用者并不直接是java函数自己,而是C函数调用java函数,因此在jvm的编译阶段,并没有将java函数压栈,jvm内部也抽象了面向对象的思想,所以传递给call_helper()函数的入参不是函数的实际入参,而是实际入参的引用,即指针。指针大小一样,所以通过计算指针大小与parameter_size就可以得到实际的入参所占用的堆栈空间=java函数入参数量4+44,每个指针4个字节,44则是保存调用者所执行到的java程序所对应的机器指令的基址和变址。
5、CallStub:调用者保存,这里的调用者保存与保存调用者堆栈要能够区分开来,保存调用者堆栈是保存栈基地址,而调用者保存是保存的方法内部的私有数据地址,比如长度为10的数组,找到第五个元素的时候调用另外一个函数,那么这个数组当前的位置就得保存到寄存器中。调用者保存主要是针对edi、esi与ebx寄存器而言。
6、CallStub:参数压栈。动态分配堆栈的时候说过,CallStub为被调用者分配的堆栈空间大小=java函数入参数量
4+44,这里的44指的是rdi、rsi、tbx、mxcsr这四个寄存器的位置。而java函数的入参主要通过入参数量与存储入参寄存器的首地址进行寻找,由于每个入参都是指针,所以知道入参数量便能拿到所有的入参。java函数入参通过循环写入到CallStub函数中。
7、调用entry_point例程,这个将在内存模型了解清楚后进行详解。例程就是一段预先写好的函数,jvm通过例程函数在启动过程中生成机器指令,当执行java函数调用时,jvm直接跳转到例程所生成的这段机器指令去执行。
8、CallStub:获得返回值.entry_point例程之后,会有返回值,CallStub会获取返回值进行处理。

本章总结

物理机器执行函数调用——>用函数指针实现C/C++程序中直接执行本地机器指令——>call_stub例程的学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值