dispatch_next()方法的实现
之前的文章介绍到,在generate_normal_entry()函数中会调用generate_fixed_frame()函数为Java方法的执行生成对应的栈帧,接下来还会调用dispatch_next()函数执行Java方法的字节码。generate_normal_entry()函数中调用的dispatch_next()函数的实现如下:
// 从generate_fixed_frame()函数生成固定桢的时候,如果当前是第一次调用,
// 那么r13指向的是字节码的首地址,即第一个字节码,而step为0。
void InterpreterMacroAssembler::dispatch_next(TosState state, int step) { // load next bytecode (load before advancing r13 to prevent AGI)
load_unsigned_byte(rbx, Address(r13, step)); // 在当前字节码的位置,指针向前移动step宽度,获取地址上的值,这个值即为字节码在转发表中的index,
// 存储到rbx。step的值由字节码指令和操作数决定。转发表中的index其实就是字节码(范围1~202),
// 参考void DispatchTable::set_entry(int i, EntryPoint& entry) 方法。
// advance r13
increment(r13, step);//自增r13供下一次dispatch使用 // 返回当前栈顶状态的所有字节码入口点
dispatch_base(state, Interpreter::dispatch_table(state)); // Interpreter::dispatch_table(state)
}
r13指向字节码的首地址,当第1次调用时,参数step的值为0,那么load_unsigned_byte()方法从r13指向的内存中取一个字节的值,取出来的是字节码指令的操作码。增加r13的步长,这样下次执行时就会取出来下一个字节码指令的操作码。
调用的dispatch_table()函数的实现如下:
static address* dispatch_table(TosState state) {
return _active_table.table_for(state);
}
在_active_table中获取对应栈顶缓存状态的入口地址,_active_table变量定义在TemplateInterpreter类中,如下:
static DispatchTable _active_table; // the active dispatch table (used by the interpreter for dispatch)
DispatchTable类及table_for()等方法的定义如下:
DispatchTable TemplateInterpreter::_active_table;
class DispatchTable VALUE_OBJ_CLASS_SPEC {
public:
// an entry point for each byte value (also for undefined bytecodes)
enum { length = 1 << BitsPerByte }; // BitsPerByte的值为8
private:
// dispatch tables, indexed by tosca and bytecode
address _table[number_of_states][length]; // number_of_states=9,length=256
public:
// Attributes
// ...
address* table_for(TosState state){
return _table[state];
}
address* table_for(){
return table_for((TosState)0);
}
// ...
};
address为u_char*类型的别名。_table是一个二维数组的表,维度为栈顶状态(共有9种)和字节码(最多有256个),存储的是每个栈顶状态对应的字节码的入口点。这里由于还没有介绍栈顶缓存,所以可能理解起来并不容易,不过后面传经详细介绍,等介绍完了再看这部分逻辑就比较容易理解了。
InterpreterMacroAssembler::dispatch_next()函数中调用的dispatch_base()方法的实现如下:
void InterpreterMacroAssembler::dispatch_base(TosState state, // 表示栈顶缓存状态
address* table,
bool verifyoop) {
// ...
// 获取当前栈顶状态字节码转发表的地址,保存到rscratch1
lea(rscratch1, ExternalAddress((address)table));
// 跳转到字节码对应的入口执行机器码指令
// address = rscratch1 + rbx * 8
jmp(Address(rscratch1, rbx, Address::times_8));
}
比如取一个字节的指令,那么InterpreterMacroAssembler::dispatch_next()函数生成的汇编代码如下 :
// 在generate_fixed_frame()方法中已经让%r13存储了bcp
0x00007fffe1010643: movzbl 0x0(%r13),%ebx // %ebx中存储的是字节码的操作码
// $0x7ffff73ba4a0这个地址指向的是对应state状态下的一维数组,长度为256
0x00007fffe1010648: movabs $0x7ffff73ba4a0,%r10
// 注意%r10中存储的是常量,根据计算公式%r10+%rbx*8来获取指向存储入口地址的地址,
// 通过*(%r10+%rbx*8)获取到入口地址,然后跳转到入口地址执行
0x00007fffe1010652: jmpq *(%r10,%rbx,8)
%r10指向的是对应栈顶缓存状态state下的一维数组,长度为256,其中存储的值为opcode,如下图所示。

下面的方法显示了对每个字节码的每个栈顶状态都设置入口地址。
void DispatchTable::set_entry(int i, EntryPoint& entry) {
assert(0 <= i && i < length, "index out of bounds");
assert(number_of_states == 9, "check the code below");
_table[btos][i] = entry.entry(btos);
_table[ctos][i] = entry.entry(ctos);
_table[stos][i] = entry.entry(stos);
_table[atos][i] = entry.entry(atos);
_table[itos][i] = entry.entry(itos);
_table[ltos][i] = entry.entry(ltos);
_table[ftos][i] = entry.entry(ftos);
_table[dtos][i] = entry.entry(dtos);
_table[vtos][i] = entry.entry(vtos);
}
其中的参数i就是opcode,各个字节码及对应的opcode可参考https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-7.html
调用dispatch_next()函数执行Java方法的字节码,其实就是根据字节码找到对应的入口地址来执行,而入口地址就是机器码的入口地址,这个机器码就是根据对应的字节码翻译过来的,这些都会在后面详细介绍。
相关文章的链接如下:
1、在Ubuntu 16.04上编译OpenJDK8的源代码
13、类加载器
14、类的双亲委派机制
15、核心类的预装载
16、Java主类的装载
17、触发类的装载
18、类文件介绍
19、文件流
20、解析Class文件
21、常量池解析(1)
22、常量池解析(2)
23、字段解析(1)
24、字段解析之伪共享(2)
25、字段解析(3)
28、方法解析
29、klassVtable与klassItable类的介绍
30、计算vtable的大小
31、计算itable的大小
32、解析Class文件之创建InstanceKlass对象
33、字段解析之字段注入
34、类的连接
35、类的连接之验证
36、类的连接之重写(1)
37、类的连接之重写(2)
38、方法的连接
39、初始化vtable
40、初始化itable
41、类的初始化
42、对象的创建
43、Java引用类型
50、CallStub栈帧
52、generate_fixed_frame()方法生成Java方法栈帧
作者持续维护的个人博客 classloading.com。
关注公众号,有HotSpot源码剖析系列文章!
参考:
(2)generate_normal_entry()方法中调用的lock_method()方法的解释参考:
dispatch_next()方法的实现的更多相关文章
- 关于面试题 Array.indexof() 方法的实现及思考
这是我在面试大公司时碰到的一个笔试题,当时自己云里雾里的胡写了一番,回头也曾思考过,最终没实现也就不了了之了. 昨天看到有网友说面试中也碰到过这个问题,我就重新思考了这个问题的实现方法. 对于想进大公 ...
- 2016 - 2 - 19 ARC内存管理知识总结(一,arc基本概念及alloc等方法的实现)
一. ARC的基本概念 1. 在objc中采用automatic reference counting 机制, 让编译器来进行内存管理.在降低程序崩溃,内存管理泄漏等风险的同时,很大程度减少了程序员的 ...
- 05_动手动脑之String.equals()方法的实现代码
Question: 请查看String.equals()方法的实现代码,注意学习其实现方法. Answer: java中的String.equals()方法的实现代码: equals()法是根类Obj ...
- Atitit paip.对象方法的实现原理与本质.txt
Atitit paip.对象方法的实现原理与本质.txt 对象方法是如何实现的1 数组,对象,字典1 对象方法是如何实现的 这显然是一个对象方法调用.但对象方法是如何实现的呢?在静态语言中,因为有编译 ...
- matchesSelector及低版本IE中对该方法的实现
matchesSelector用来匹配dom元素是否匹配某css selector.它为一些高级方法的实现提供了基础支持,比如事件代理,parent, closest等. W3C在2006年就提出了该 ...
- 动手动脑之查看String.equals()方法的实现代码及解释
动手动脑 请查看String.equals()方法的实现代码,注意学习其实现方法. 第一个是false,后三个是true. package stringtest; public class Strin ...
- OC:属性的内部实现原理、dealloc内释放实例变量、便利构造器方法的实现原理、collection的内存管理
代码: // // main.m #import <Foundation/Foundation.h> #import "Person.h" #import " ...
- java集合的contains(obj)方法的实现
在实际项目中我们通常会有一个需求就是:想知道在一个列表中是否包含某一个对象 这里ArrayList表.HashSet表和HashMap表都提供了一个contains(obj)方法, 下面说一下两个列表 ...
- [转]原生JS-查找相邻的元素-siblings方法的实现
在针对element的操作里,查找附近的元素是一个不可少的过程,比如在实现tab时,其中的一个div增加了“on”class,其他的去除“on”class.如果用jquery的朋友就肯定不会陌生sib ...
随机推荐
- Django---博客项目实战
1.urls from django.conf.urls import url from django.contrib import admin from blog import views urlp ...
- ls -bash: ls: command not found
ls -bash: ls: command not found原因:在设置环境变量时,编辑profile文件没有写正确,导致在命令行下 ls等命令不能够识别.解决方案: export PATH=/us ...
- Python环境搭建及中文编码
Python 官方下载地址:https://www.python.org/downloads/ 64 位下载客户端 32 位下载客户端 在安装之后,可能在桌面上看不到图标.这时可以到开始菜单下寻找 ...
- Hexo 静态博客指南:建站教程(中)
本文最初发布于我的个人博客Bambrow's Blog,采用 BY-NC-SA 许可协议,转载请注明出处.若有后续更新,将更新于原博客.欢迎去我的博客阅读更多文章! 本文详细记录一下站点建立过程,以便 ...
- mit-6.828 Lab01:Booting a PC Part2 理论知识
Part 2 目录 Part 2 学习理论知识 反汇编 扇区 BIOS 启动过程总结 Boot loader启动过程总结 A20 gate 读boot/boot.S 和 boot/boot.c源码 - ...
- sql_to_csv
将需要信息 导出成 csv,txt等格式 create or replace procedure sql_to_csv(p_query in varchar2, --sql query stateme ...
- Python Selenium 搭建Web UI自动化
Python搭建UI自动化环境 下载Python3 Python官网 PyCharm 环境配置 安装Python 勾选Add Python to PATH,一直下一步. 验证:CMD输入Python ...
- 【Python 实例】面向对象 | 请输入一周中某天的名称的第一个字母来判断以下是星期几,如果第一个字母一样则继续判断第二个字母
[Python 实例]面向对象 | 请输入一周中某天的名称的第一个字母来判断以下是星期几,如果第一个字母一样则继续判断第二个字母 题目: 解答: 运行结果: 题目: 请输入一周中某天的名称的第一个字母 ...
- 推荐:实现RTSP/RTMP/HLS/HTTP协议的轻量级流媒体框架,支持大并发连接请求
推荐一个比较好用的流媒体服务开源代码: ZLMediaKit: 实现RTSP/RTMP/HLS/HTTP协议的轻量级流媒体框架,支持大并发连接请求 https://gitee.com/xiahcu/Z ...
- 我还在生产玩 JDK7,JDK 15 却要来了!|新特性尝鲜
自从 JDK9 之后,每年 3 月与 9 月 JDK 都会发布一个新的版本,而2020 年 9 月即将引来 JDK15. 恰巧 IDEA 每四五个月会升级一个较大的版本,每次升级之后都会支持最新版本 ...