在TemplateInterpreterGenerator::generate_all()函数中生成了许多字节码指令以及一些虚拟机辅助执行的机器指令片段,例如生成空指针异常抛出入口的实现如下:

{
CodeletMark cm(_masm, "throw exception entrypoints");
// ...
Interpreter::_throw_NullPointerException_entry = generate_exception_handler("java/lang/NullPointerException",NULL);
// ...
}

调用generate_exception_handler()函数生成抛出空指针的代码片段。

address generate_exception_handler(const char* name, const char* message) {
return generate_exception_handler_common(name, message, false);
}

调用的generate_exception_handler_common()函数的实现如下:

address TemplateInterpreterGenerator::generate_exception_handler_common(
const char* name,
const char* message,
bool pass_oop
) { assert(!pass_oop || message == NULL, "either oop or message but not both");
address entry = __ pc();
if (pass_oop) {
// object is at TOS
__ pop(c_rarg2);
} // expression stack must be empty before entering the VM if an
// exception happened
__ empty_expression_stack(); // setup parameters
__ lea(c_rarg1, ExternalAddress((address)name)); if (pass_oop) {
__ call_VM(rax,
CAST_FROM_FN_PTR(address,InterpreterRuntime::create_klass_exception),
c_rarg1,c_rarg2);
} else {
// kind of lame ExternalAddress can't take NULL because
// external_word_Relocation will assert.
if (message != NULL) {
__ lea(c_rarg2, ExternalAddress((address)message));
} else {
__ movptr(c_rarg2, NULL_WORD);
}
__ call_VM(rax,
CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception),
c_rarg1, c_rarg2);
} // throw exception
__ jump(ExternalAddress(Interpreter::throw_exception_entry())); return entry;
}

生成的汇编代码如下:

0x00007fffe10101cb: mov    -0x40(%rbp),%rsp
0x00007fffe10101cf: movq $0x0,-0x10(%rbp)
0x00007fffe10101d7: movabs $0x7ffff6e09878,%rsi
0x00007fffe10101e1: movabs $0x0,%rdx
0x00007fffe10101eb: callq 0x00007fffe10101f5
0x00007fffe10101f0: jmpq 0x00007fffe1010288
0x00007fffe10101f5: lea 0x8(%rsp),%rax
0x00007fffe10101fa: mov %r13,-0x38(%rbp)
0x00007fffe10101fe: mov %r15,%rdi
0x00007fffe1010201: mov %rbp,0x200(%r15)
0x00007fffe1010208: mov %rax,0x1f0(%r15)
0x00007fffe101020f: test $0xf,%esp
0x00007fffe1010215: je 0x00007fffe101022d
0x00007fffe101021b: sub $0x8,%rsp
0x00007fffe101021f: callq 0x00007ffff66b3fbc
0x00007fffe1010224: add $0x8,%rsp
0x00007fffe1010228: jmpq 0x00007fffe1010232
0x00007fffe101022d: callq 0x00007ffff66b3fbc
0x00007fffe1010232: movabs $0x0,%r10
0x00007fffe101023c: mov %r10,0x1f0(%r15)
0x00007fffe1010243: movabs $0x0,%r10
0x00007fffe101024d: mov %r10,0x200(%r15)
0x00007fffe1010254: cmpq $0x0,0x8(%r15)
0x00007fffe101025c: je 0x00007fffe1010267
0x00007fffe1010262: jmpq 0x00007fffe1000420
0x00007fffe1010267: mov 0x250(%r15),%rax
0x00007fffe101026e: movabs $0x0,%r10
0x00007fffe1010278: mov %r10,0x250(%r15)
0x00007fffe101027f: mov -0x38(%rbp),%r13
0x00007fffe1010283: mov -0x30(%rbp),%r14
0x00007fffe1010287: retq
0x00007fffe1010288: jmpq 0x00007fffe100f3d3

在这里的重点不是读懂TemplateInterpreterGenerator::generate_exception_handler_common()函数的逻辑及生成的汇编代码,而是要清楚知道CodeletMark的应用,以及generate_exception_handler_common()函数生成的机器指令是如何写入InterpreterCodelet实例中的。之前介绍过InterpreterCodelet与CodeBuffer类,如下:

通过CodeBuffer操作InterpreterCodelet实例的存储机器指令片段的内存区域,而CodeBuffer中的代码部分(CodeSection)被赋值给AbstractAssembler::_code_section。这样我们就可以通过_code_section属性向InterpreterCodelet实例中写入机器指令了。

向CodeletMark中传入的_masm参数定义在AbstractInterpreterGenerator类中,如下:

class AbstractInterpreterGenerator: public StackObj {
protected:
InterpreterMacroAssembler* _masm;
// ...
}

generate_exception_handler_common()函数中的__是一个宏,定义如下:

#define __ _masm->

这样其实就是调用InterpreterMacroAssembler类中的相关函数写机器指令,例如

__ pop(c_rarg2);

调用的pop()函数如下:

// 定义在InterpreterMacroAssembler中
void pop(Register r ) {
((MacroAssembler*)this)->pop(r);
} // 定义在Assembler类中
void Assembler::pop(Register dst) {
int encode = prefix_and_encode(dst->encoding());
emit_int8(0x58 | encode);
} // 定义在AbstractAssembler类中
void emit_int8( int8_t x) {
code_section()->emit_int8( x);
}

code_section()函数获取的就是AbstractAssembler的_code_section属性的值。  

推荐阅读:

第1篇-关于JVM运行时,开篇说的简单些

第2篇-JVM虚拟机这样来调用Java主类的main()方法

第3篇-CallStub新栈帧的创建

第4篇-JVM终于开始调用Java主类的main()方法啦

第5篇-调用Java方法后弹出栈帧及处理返回结果

第6篇-Java方法新栈帧的创建

第7篇-为Java方法创建栈帧

第8篇-dispatch_next()函数分派字节码

第9篇-字节码指令的定义

第10篇-初始化模板表

第11篇-认识Stub与StubQueue

第12篇-认识CodeletMark

如果有问题可直接评论留言或加作者微信mazhimazh

关注公众号,有HotSpot VM源码剖析系列文章!

第13篇-通过InterpreterCodelet存储机器指令片段的更多相关文章

  1. Mysql高手系列 - 第13篇:细说NULL导致的神坑,让人防不胜防

    这是Mysql系列第13篇. 环境:mysql5.7.25,cmd命令中进行演示. 当数据的值为NULL的时候,可能出现各种意想不到的效果,让人防不胜防,我们来看看NULL导致的各种神坑,如何避免? ...

  2. 3.Ceph 基础篇 - RBD 块存储使用

    文章转载自:https://mp.weixin.qq.com/s?__biz=MzI1MDgwNzQ1MQ==&mid=2247485253&idx=1&sn=24d9b06a ...

  3. 有评论就是我最大的动力~MySQL基础篇完结(存储引擎和图形化管理工具)

    hi 今天登上来,发现竟然有了3个评论~~加油吧! 这周的计划其实远远没有达到,然后下周还有一大堆事情...那么...周末好好玩吧~ 今天试图完结MySQL的基础篇知识,小白变为大白? 1.MySQL ...

  4. Spring第13篇—–Spring整合Hibernate之声明式事务管理

    不容置疑的我们可以知道Spring的事务管理是通过AOP(AOP把我们的事务管理织入到我们的业务逻辑里面了)的方式来实现的,因为事务方面的代码与spring的绑定并以一种样板式结构使用.(面向切面编程 ...

  5. 剖析Elasticsearch集群系列第一篇 Elasticsearch的存储模型和读写操作

    剖析Elasticsearch集群系列涵盖了当今最流行的分布式搜索引擎Elasticsearch的底层架构和原型实例. 本文是这个系列的第一篇,在本文中,我们将讨论的Elasticsearch的底层存 ...

  6. Django【第13篇】:Django之Form组件

    django 之知识点总结以及Form组件 一.model常用操作 1.13个API查询:all,filter,get ,values,values_list,distinct,order_by ,r ...

  7. C++基础知识篇:C++ 存储类

    存储类定义 C++ 程序中变量/函数的范围(可见性)和生命周期.这些说明符放置在它们所修饰的类型之前.下面列出 C++ 程序中可用的存储类: auto register static extern m ...

  8. K8S系列第九篇(持久化存储,emptyDir、hostPath、PV/PVC)

    更多k8s内容,请关注威信公众好:新猿技术生态圈 一.数据持久化 Pod是由容器组成的,而容器宕机或停止之后,数据就随之丢了,那么这也就意味着我们在做Kubernetes集群的时候就不得不考虑存储的问 ...

  9. MySQL索引篇之索引存储模型

      本文重点介绍下索引的存储模型 二分查找   给定一个1~100的自然数,给你5次机会,你能猜中这个数字吗? 你会从多少开始猜?   为什么一定是50呢?这个就是二分查找的一种思想,也叫折半查找,每 ...

随机推荐

  1. 超详细!搭建本地大数据研发环境(16G内存+CDH)

    工欲善其事必先利其器,在经过大量的理论学习以后,需要有一个本地的研发环境来进行练手.已经工作的可以不依赖于公司的环境,在家也可以随意的练习.而自学大数据的同学,也可以进行本地练习,大数据是一门偏实践的 ...

  2. Python urllib翻译笔记一

    22.5.urllib- URL处理模块urllib 是一个收集几个模块以处理URL的包: urllib.request 用于打开和阅读URL urllib.error 包含由urllib.reque ...

  3. tomcat禁用PUT,DELETE等一些不必要的HTTP方法

    一.背景 公司进行安全整改, 技术要求:系统软件所需支撑的WEB容器环境应禁止除GET和POST外其他HTTP(S)方法. 提供凭证:建议在不影响业务的前提下,禁用PUT.DELETE.HEAD.OP ...

  4. Docker简易安装教程

    Docker介绍 Docker 是一种开源容器化技术,用于构建和容器化应用程序.Docker 使用客户端-服务器架构.Docker客户端与 Docker守护进程对话,后者负责构建.运行和分发 Dock ...

  5. Mac终端美化(iterm2+zsh+oh-my-zsh+powerlevel10k)

    iterm2+zsh+oh-my-zsh+powerlevel10k 一.下载iterm2 方式一:官网下载 https://iterm2.com/ 方式二:百度云下载 链接: https://pan ...

  6. TypeError: attrib() got an unexpected keyword argument 'convert'

    使用pyinstaller -F aaa.py时,报错 TypeError: attrib() got an unexpected keyword argument 'convert' 没有exe生成 ...

  7. 微信小程序创建第一个项目

    一.打开微信开发者工具,扫码登录 二.点击右侧的加号,添加小程序 第三步:创建成功后,报错 VM82:1 cloud init error: Error: invalid scope 没有权限,请先开 ...

  8. noip模拟29[简单的板子题](虽然我不会)

    \(noip模拟29\;solutions\) 这次考试给我最大的伤害,让我意识到了差距 这场考试可以说是非常的简单,就是简单到,看两眼,打个表就有结果了 但是呢?我考得非常的完蛋,只有30pts 据 ...

  9. QML用Instantiator动态创建顶级窗口

    关键点 使用Model驱动Instantiator QML里面的hashmap: QQmlPropertyMap 上一次说到用 QQmlApplicationEngine 多次load的方式创建多个一 ...

  10. D. 旅游景点 Tourist Attractions 状压DP

    题目描述 FGD想从成都去上海旅游.在旅途中他希望经过一些城市并在那里欣赏风景,品尝风味小吃或者做其他的有趣的事情.经过这些城市的顺序不是完全随意的,比如说FGD 不希望在刚吃过一顿大餐之后立刻去下一 ...