深入V8引擎-引擎内部类管理解析
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都把这个封装到一个宏里,声明的时候直接调用就行了,这些后面深入的时候再来细说把。