認識Java中的Stub與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類及相關類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
。整個解釋器都是由這些小塊代碼例程組成的,每個小塊例程完成解釋器的部分功能,以此實現整個解釋器。
到此這篇關於認識Java中的Stub與StubQueue的文章就介紹到這瞭,更多相關Stub與StubQueue內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- order by + limit分頁時數據重復問題及解決方法
- LyScript尋找ROP漏洞指令片段的方法詳解
- JavaScript中各種二進制對象關系的深入講解
- Javascript File和Blob詳解
- 淺談JS的二進制傢族