理解谷歌V8C++代码库中的继承

理解谷歌V8C++代码库中的继承,c++,inheritance,architecture,v8,C++,Inheritance,Architecture,V8,我无法理解Google的V8 JavaScript引擎中继承的实现。它显然实现了继承层次结构,但似乎完全取消了虚拟函数 这是继承层次结构,详见: 大多数对象类型派生自对象,其声明如下: // Object is the abstract superclass for all classes in the // object hierarchy. // Object does not use any virtual functions to avoid the // allocation of t

我无法理解Google的V8 JavaScript引擎中继承的实现。它显然实现了继承层次结构,但似乎完全取消了虚拟函数

这是继承层次结构,详见:

大多数对象类型派生自对象,其声明如下:

// Object is the abstract superclass for all classes in the
// object hierarchy.
// Object does not use any virtual functions to avoid the
// allocation of the C++ vtable.
// Since both Smi and HeapObject are subclasses of Object no
// data members can be present in Object.
class Object {
// ... bunch of method declarations and definitions
};
下面声明相对简单的Smi类:

class Smi: public Object {
 public:
 // methods declarations and static member definitions
};
等等

就我的一生而言,我无法理解,比如说,Smi的实例如何可以被用作对象;没有虚拟函数,在中找不到重写。然而,在17290行,试图理解正在发生的事情是一项艰巨的任务

另一个困难是,我在同一个头文件中发现了一个ObjectVisitor类,这个类更经典;它由虚拟方法组成。但是我在对象基类中找不到等效的AcceptVisitor*或类似的方法

具体来说,我要问的是一个简单的例子,说明这种继承模式是如何工作的。

看看Object::IsPromise,它是如何工作的:

bool Object::IsPromise(Handle<Object> object) {
  if (!object->IsJSObject()) return false;
  auto js_object = Handle<JSObject>::cast(object);
  // Promises can't have access checks.
  if (js_object->map()->is_access_check_needed()) return false;
  auto isolate = js_object->GetIsolate();
  // TODO(dcarney): this should just be read from the symbol registry so as not
  // to be context dependent.
  auto key = isolate->promise_status();
  // Shouldn't be possible to throw here.
  return JSObject::HasRealNamedProperty(js_object, key).FromJust();
}
这里使用继承的方式是静态的。也就是说,类型查询是由代理或容器使用某种隐藏的魔法完成的,乍一看,它们似乎是在使用引用来查询标记,而从对象到派生类的转换是通过静态转换完成的。这样,就可以调用派生类的成员函数

请注意,在上述函数中,类型查询和转换是由Handle类间接执行的,而不是由Object或其任何派生类执行的

还请注意,接受ObjectVisitor作为参数的函数统一称为Iterate,并且这些函数都出现在代理或句柄上。

请查看Object::IsPromise,了解其工作原理的完美示例:

bool Object::IsPromise(Handle<Object> object) {
  if (!object->IsJSObject()) return false;
  auto js_object = Handle<JSObject>::cast(object);
  // Promises can't have access checks.
  if (js_object->map()->is_access_check_needed()) return false;
  auto isolate = js_object->GetIsolate();
  // TODO(dcarney): this should just be read from the symbol registry so as not
  // to be context dependent.
  auto key = isolate->promise_status();
  // Shouldn't be possible to throw here.
  return JSObject::HasRealNamedProperty(js_object, key).FromJust();
}
这里使用继承的方式是静态的。也就是说,类型查询是由代理或容器使用某种隐藏的魔法完成的,乍一看,它们似乎是在使用引用来查询标记,而从对象到派生类的转换是通过静态转换完成的。这样,就可以调用派生类的成员函数

请注意,在上述函数中,类型查询和转换是由Handle类间接执行的,而不是由Object或其任何派生类执行的


注意到,将对象访问作为参数的函数相当一致,称为迭代,这些函数都出现在代理或句柄上。

对象中的类。h实际上不定义实际C++类。它们没有任何字段。这些类只是V8 JavaScript堆上管理的对象的外观。因此,它们也不能有任何虚拟函数,因为这需要将vtable指针放入JS堆。相反,所有分派都是通过显式类型检查和向下转换手动完成的


方法中的this指针也不是真的。对于SMI,这只是一个整数。对于其他所有内容,它都是一个指向V8堆的指针,用于标记。任何实际的访问器方法都会屏蔽该指针,并添加一个偏移量来访问堆中的适当地址。每个字段的偏移也在类中手动定义。

对象中的类。h实际上不定义实例化C++类。它们没有任何字段。这些类只是V8 JavaScript堆上管理的对象的外观。因此,它们也不能有任何虚拟函数,因为这需要将vtable指针放入JS堆。相反,所有分派都是通过显式类型检查和向下转换手动完成的


方法中的this指针也不是真的。对于SMI,这只是一个整数。对于其他所有内容,它都是一个指向V8堆的指针,用于标记。任何实际的访问器方法都会屏蔽该指针,并添加一个偏移量来访问堆中的适当地址。每个字段的偏移量也在类中手动定义。

这听起来非常复杂。你有没有参考过另一个使用这种方法的项目?这听起来很复杂。您是否参考过使用此方法的其他项目?