认识Java中的Stub与StubQueue

网友投稿 352 2022-09-28


认识Java中的Stub与StubQueue

目录1、InterpreterCodelet与Stub类2、StubQueue类

在文章开始前先简单介绍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类及http://相关类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 {

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。整个解释器都是由这些小块代码例程组成的,每个小块例程完成解释器的部分功能,以此实现整个解释器。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:防火墙基础之防火墙做出口网关路由交换的配置​
下一篇:#私藏项目实操分享#如何用加密锁保护自己的程序
相关文章

 发表评论

暂时没有评论,来抢沙发吧~