深入V8引擎-引擎內部類管理解析

書生小龍發表於2019-06-05

v8的初始化三部曲,前面花了三篇解決了第一步,由於只是生成了一個物件,第二步就是將其嵌入v8中,先看一下三個步驟。

// 生成預設Platform物件
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
// 將其嵌入V8引擎內
v8::V8::InitializePlatform(platform.get());
// 初始化V8引擎
v8::V8::Initialize();

第一步可以由使用者自己手動實現platform,只要按照規範來繼承對應基類,一般也不會有人搞吧。

這裡的嵌入,如果用程式碼來進行解釋,實際上是叫做"名稱空間"。v8引擎的體量非常巨大,所以需要有完善的規範來管理各個類。如果完整的閱讀過v8原始碼,可以發現v8對類的邏輯管理用到了兩個方法,其中一個是名稱空間,另外一個則是語義化巨集。

先來看看名稱空間的定義(對C++熟悉就很簡單了),如果只是跟我一樣的前端頁面仔,可以理解成模組。舉一個例子,在前面一篇有一個類叫PageAllocator,在看原始碼發現有兩個同名類,但是其中一個是掛在v8的名稱空間下,另外一個則在v8::base的名稱空間下,如下。

namespace v8 {
  class PageAllocator {}
}
namespace v8 {
namespace base {
  class PageAllocator : public ::v8::PageAllocator {}
}
}

通過對v8名稱空間所有類進行觀察,發現其所有的類都是一個基類,提供了宣告和一些虛擬函式,都是需要被繼承去實現的類。而對v8::base進行搜尋時,發現了其名稱空間下的所有方法都是實現類,可以看出,v8通過名稱空間來對所有的class進行分類。

另外,其名稱空間的名字也是有意義的,base名稱空間下的類提供的功能都是比較底層的功能,比如說CPU、Hash、EnumSet等等。而之前那篇講的DefaultPlatform、TaskRunner,其名稱空間都掛在v8::platform的下面。此外,WorkThread雖然從繼承關係上是屬於Thread型別,但是作為TaskRunner的內部類,實際上名稱空間還是屬於platform,也就是隻看名稱空間就可以理解類的歸屬和功能。

比較典型的還有v8::debug包含垃圾回收、記憶體管理相關,v8::tracing包含呼叫棧追蹤的相關等等,這裡就不一一舉例了。

 

除去名稱空間,另外一個對類進行分類的就是語義化巨集。這個命名是自己想的,主要是聯想到了語義化標籤,進行過格式化,實際上div和p在表現上並沒有什麼區別,實際使用上只是為了語義化。同理,v8的很多巨集會對類進行修飾,也是無意義的,純粹的語義化。

基本上所有的類都會有巨集去修飾,還是拿之前的DefaultPlatform舉例。

// 巨集定義
#define NON_EXPORTED_BASE(code) code
#define V8_PLATFORM_EXPORT
// 類宣告
class V8_PLATFORM_EXPORT DefaultPlatform : public NON_EXPORTED_BASE(Platform) {};

這裡分別對實現類和基類都進行了修飾,V8_PLATFORM_EXPORT表明這個類是屬於platform模組,且是一個實現類,可以輸出並使用。而NON_EXPORTED_BASE則表明該類不可直接使用,需要繼承實現。

巨集的定義也給出來了,沒有任何意義,只是一個純粹的為了說明,跟註釋類似但是又有著不一樣的功能。

v8原始碼的標頭檔案在類的定義上隨處可見這種巨集,通過巨集的名字就可以看出類的一些特徵,從而方便除錯和像我這樣無聊的人看原始碼……

 

其實v8內部還有更多巨集起著巨大的作用,比如在類宣告時,有時候需要禁掉這個類的拷貝建構函式和賦值功能,v8都把這個封裝到一個巨集裡,宣告的時候直接呼叫就行了,這些後面深入的時候再來細說把。

相關文章