第11篇-认识Stub与StubQueue
在 第10篇-初始化模板表 我们介绍过TemplateInterpreter::initialize()函数,在这个函数中会调用TemplateTable::initialize()函数初始化模板表,随后会使用new关键字初始化定义在AbstractInterpreter类中的_code静态属性,如下:
- static StubQueue* _code;
由于TemplateInterpreter继承自AbstractInterpreter,所以在TemplateInterpreter中初始化的_code属性其实就是AbstractInterpreter类中定义的_code属性。
在initialize()函数中初始化_code变量的代码如下:
- // InterpreterCodeSize是在平台相关
- // 的templateInterpreter_x86.hpp中
- // 定义的,64位下是256 * 1024
- int code_size = InterpreterCodeSize;
- _code = new StubQueue(
- new InterpreterCodeletInterface,
- code_size,
- NULL,
- "Interpreter");
StubQueue是用来保存生成的本地代码的Stub队列,队列每一个元素对应一个InterpreterCodelet对象,InterpreterCodelet对象继承自抽象基类Stub,包含了字节码对应的本地代码以及一些调试和输出信息。下面我们介绍一下StubQueue类及相关类Stub、InterpreterCodelet类和CodeletMark类。
1、InterpreterCodelet与Stub类
Stub类的定义如下:
- class Stub VALUE_OBJ_CLASS_SPEC { ... };
InterpreterCodelet类继承自Stub类,具体的定义如下:
- class InterpreterCodelet: public Stub {
- private:
- int _size; // the size in bytes
- const char* _description; // a description of the codelet, for debugging & printing
- Bytecodes::Code _bytecode; // associated bytecode if any
- public:
- // Code info
- address code_begin() const {
- return (address)this + round_to(sizeof(InterpreterCodelet), CodeEntryAlignment);
- }
- address code_end() const {
- return (address)this + size();
- }
- int size() const {
- return _size;
- }
- // ...
- int code_size() const {
- return code_end() - code_begin();
- }
- // ...
- };
InterpreterCodelet实例存储在StubQueue中,每个InterpreterCodelet实例都代表一段机器指令(包含了字节码对应的机器指令片段以及一些调试和输出信息),如每个字节码都有一个InterpreterCodelet实例,所以在解释执行时,如果要执行某个字节码,则执行的就是由InterpreterCodelet实例代表的机器指令片段。
类中定义了3个属性及一些函数,其内存布局如下图所示。
在对齐至CodeEntryAlignment后,紧接着InterpreterCodelet的就是生成的目标代码。
2、StubQueue类
StubQueue是用来保存生成的本地机器指令片段的Stub队列,队列每一个元素都是一个InterpreterCodelet实例。
StubQueue类的定义如下:
- class StubQueue: public CHeapObj<mtCode> {
- private:
- StubInterface* _stub_interface; // the interface prototype
- address _stub_buffer; // where all stubs are stored
- int _buffer_size; // the buffer size in bytes
- int _buffer_limit; // the (byte) index of the actual buffer limit (_buffer_limit <= _buffer_size)
- int _queue_begin; // the (byte) index of the first queue entry (word-aligned)
- int _queue_end; // the (byte) index of the first entry after the queue (word-aligned)
- int _number_of_stubs; // the number of buffered stubs
- bool is_contiguous() const {
- return _queue_begin <= _queue_end;
- }
- int index_of(Stub* s) const {
- int i = (address)s - _stub_buffer;
- return i;
- }
- Stub* stub_at(int i) const {
- return (Stub*)(_stub_buffer + i);
- }
- Stub* current_stub() const {
- return stub_at(_queue_end);
- }
- // ...
- }
这个类的构造函数如下:
- StubQueue::StubQueue(
- StubInterface* stub_interface, // InterpreterCodeletInterface对象
- int buffer_size, // 256*1024
- Mutex* lock,
- const char* name) : _mutex(lock)
- {
- intptr_t size = round_to(buffer_size, 2*BytesPerWord); // BytesPerWord的值为8
- BufferBlob* blob = BufferBlob::create(name, size); // 在StubQueue中创建BufferBlob对象
- _stub_interface = stub_interface;
- _buffer_size = blob->content_size();
- _buffer_limit = blob->content_size();
- _stub_buffer = blob->content_begin();
- _queue_begin = 0;
- _queue_end = 0;
- _number_of_stubs = 0;
- }
stub_interface用来保存一个InterpreterCodeletInterface类型的实例,InterpreterCodeletInterface类中定义了操作Stub的函数,避免了在Stub中定义虚函数。每个StubQueue都有一个InterpreterCodeletInterface,可以通过这个来操作StubQueue中存储的每个Stub实例。
调用BufferBlob::create()函数为StubQueue分配内存,这里我们需要记住StubQueue用的内存是通过BufferBlob分配出来的,也就是BufferBlob其本质可能是一个StubQueue。下面就来详细介绍下create()函数。
- BufferBlob* BufferBlob::create(const char* name, int buffer_size) {
- // ...
- BufferBlob* blob = NULL;
- unsigned int size = sizeof(BufferBlob);
- // align the size to CodeEntryAlignment
- size = align_code_offset(size);
- size += round_to(buffer_size, oopSize); // oopSize是一个指针的宽度,在64位上就是8
- {
- MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
- blob = new (size) BufferBlob(name, size);
- }
- return blob;
- }
通过new关键字为BufferBlob分配内存,new重载运算符如下:
- void* BufferBlob::operator new(size_t s, unsigned size, bool is_critical) throw() {
- void* p = CodeCache::allocate(size, is_critical);
- return p;
- }
从codeCache中分配内存,CodeCache使用的是本地内存,有自己的内存管理办法,在后面将会详细介绍。
StubQueue的布局结构如下图所示。
队列中的InterpreterCodelet表示一个小例程,比如iconst_1对应的机器码,invokedynamic对应的机器码,异常处理对应的代码,方法入口点对应的代码,这些代码都是一个个InterpreterCodelet。整个解释器都是由这些小块代码例程组成的,每个小块例程完成解释器的部分功能,以此实现整个解释器。
推荐阅读:
第2篇-JVM虚拟机这样来调用Java主类的main()方法
如果有问题可直接评论留言或加作者微信mazhimazh
关注公众号,有HotSpot VM源码剖析系列文章!
第11篇-认识Stub与StubQueue的更多相关文章
- 代码生成器辅助类Stub、StubQueue与CodeletMark
在解释执行的情况下需要一些类来支持代码生成的过程. 1.InterpreterCodelet与Stub类 Stub类的定义如下: class Stub VALUE_OBJ_CLASS_SPEC { p ...
- 回顾2017系列篇(一):最佳的11篇UI/UX设计文章
2017已经接近尾声,在这一年中,设计领域发生了诸多变化.也是时候对2017年做一个总结,本文主要是从2017设计文章入手,列出了个人认为2017设计行业里最重要的UI/UX文章的前11名,供大家参考 ...
- Mysql高手系列 - 第11篇:深入了解连接查询及原理
这是Mysql系列第11篇. 环境:mysql5.7.25,cmd命令中进行演示. 当我们查询的数据来源于多张表的时候,我们需要用到连接查询,连接查询使用率非常高,希望大家都务必掌握. 本文内容 笛卡 ...
- HelloDjango 第 11 篇:自动生成文章摘要
作者:HelloGitHub-追梦人物 文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库 博客文章的模型有一个 excerpt 字段,这个字段用于存储文章的摘要.目前为止,还只 ...
- Django【第11篇】:Django之分页升级版本(组件)
分页组件 一.分页的实现与使用 class Pagination(object): """ 自定义分页 """ def __init__(s ...
- 恕我直言你可能真的不会java第11篇-Stream API终端操作
一.Java Stream管道数据处理操作 在本号之前写过的文章中,曾经给大家介绍过 Java Stream管道流是用于简化集合类元素处理的java API.在使用的过程中分为三个阶段.在开始本文之前 ...
- 从苏宁电器到卡巴斯基第11篇:我在苏宁电器当营业员 III
积分换礼的是是非非 在苏宁购物是需要会员卡的(免费办理),我们需要利用这个会员卡来开单,顾客的消费可以换算成积分,贮存在会员卡里面.这个积分可以用于积分换礼,比如电磁炉.乐扣保鲜盒或者其它一些家用器具 ...
- Python代码阅读(第11篇):展开嵌套列表
Python 代码阅读合集介绍:为什么不推荐Python初学者直接看项目源码 本篇阅读的代码实现了展开嵌套列表的功能,将一个嵌套的list展开成一个一维list(不改变原有列表的顺序). 本篇阅读的代 ...
- C++技术问题总结-第11篇 网络通信中主机序网络序
网络通信常常涉及到字节序转化,接下来理解主机序和网络序有什么异同. ①主机字节顺序HBO(Host Byte Order) 採用小头序(little-endian),从低到高的顺序存储. 低位字节排放 ...
随机推荐
- esp32 Guru Meditation 错误解决方案(转)
Guru Meditation本节将对打印在 Guru Meditation Error: Core panic'ed后面括号中的致错原因进行逐一解释.IllegalInstruction此 CPU ...
- go logrus实战应用
简单记录一下logrus实战应用,详细了解可以移步官网,这是直接使用 上代码: logrus整个项目应用封装 package log import ( "fmt" "gi ...
- java基础---类和对象(4)
一. static关键字 使用static关键字修饰成员变量表示静态的含义,此时成员变量由对象层级提升为类层级,整个类共享一份静态成员变量,该成员变量随着类的加载准备就绪,与是否创建对象无关 使用st ...
- C语言:读写TXT
fopen() 改为: if((fp=fopen("1s.txt","w+"))==NULL) fputc(p,fp); 改为:fprintf(fp," ...
- win10 IIS web.config加密不能访问:打不开 RSA 密钥容器
C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys 找到密钥文件, 根据时间判断具体是哪一个文件,赋予network service读权限
- C语言经典试题--指针
分享一道C语言的经典的题目.题目要求如下: 利用字符指针实现字符串1"I Love China"与字符串2"So do I"的输出.然后利用字符指针将字符串2的 ...
- File类与常用IO流第七章——Properties集合
Properties概述 java.util.Properties extends Hashtable<k,v> implements Map<k,v> Properties类 ...
- 使用pymysql循环删除重复数据,并修改自增字段偏移值
创建表: CREATE TABLE `info` ( `id` tinyint NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, PRIMAR ...
- 跟我一起学Go系列:gRPC 全局数据传输和超时处理
gRPC 在多个 GoRoutine 之间传递数据使用的是 Go SDK 提供的 Context 包.关于 Context 的使用可以看我之前的一篇文章:Context 使用. 但是 Context ...
- springMVC-11-验证码
springMVC-11-验证码 导入依赖 <!--Kaptcha 验证码依赖 前面已导过servlet-api需排除--> <dependency> <groupId& ...