Heim  >  Artikel  >  Web-Frontend  >  Detaillierte Erläuterung der Objektspeicherstruktur und des Attributzugriffs von JavaScript V8

Detaillierte Erläuterung der Objektspeicherstruktur und des Attributzugriffs von JavaScript V8

黄舟
黄舟Original
2017-03-02 15:27:401920Durchsuche

V8 Objektspeicherstruktur und Attributzugriff

In den 1990er Jahren, mit der Veröffentlichung des Netscape-Browsers, gelangte JavaScript erstmals ins Blickfeld der Menschen. Später, mit dem Aufkommen der groß angelegten Anwendung von AJAX und der Ära der Rich-Client- und Single-Page-Anwendungen, nahm JavaScript eine immer wichtigere Position in der Webentwicklung ein. In frühen JavaScript-Engines wurde die Leistung zunehmend zum Engpass bei der Entwicklung von Webanwendungen. Das Designziel der V8-Engine besteht darin, die Ausführungseffizienz großer JavaScript-Anwendungen sicherzustellen. In vielen Tests konnte deutlich festgestellt werden, dass die Leistung von V8 besser ist als die von JScript (Internet Explorer), SpiderMonkey (Firefox) und JavaScriptCore (Safari) Laut der offiziellen Dokumentation der V8-Einführung liegt der Schwerpunkt hauptsächlich auf der Leistungsoptimierung unter drei Gesichtspunkten: Attributzugriff, dynamische Maschinencodegenerierung und effiziente Speicherbereinigung. Objekt ist zweifellos einer der wichtigsten Datentypen in JavaScript. In diesem Artikel erklären wir seine interne Struktur im Detail. Das Vererbungsdiagramm lautet wie folgt:

Die neu zugewiesene JavaScript-Objektstruktur in V8 lautet wie folgt:

[ class / map ] -> ... ; 指向内部类
[ properties  ] -> [empty array]
[ elements    ] -> [empty array] ; 数值类型名称的属性
[ reserved #1 ] -\
[ reserved #2 ]  |
[ reserved #3 ]  }- in object properties,即预分配的内存空间
...............  |
[ reserved #N ] -/

Erstellen eines neuen Objekts, V8 wird Erstellen Sie einen vorab zugewiesenen Speicherbereich zum Speichern der sogenannten In-Object-Eigenschaften. Die Größe des vorab zugewiesenen Bereichs wird durch die Anzahl der Parameter im Konstruktor bestimmt (this.field = expr). Wenn Sie planen, einem Objekt ein neues Attribut hinzuzufügen, versucht V8 zunächst, es in den sogenannten In-Order-Slot einzufügen. Wenn der In-Object-Slot überlastet ist, versucht V8, das neue Attribut dem Out-Slot hinzuzufügen. Liste der Objekteigenschaften. Die Zuordnungsbeziehung zwischen Attributnamen und Attributindizes wird in sogenannten versteckten Klassen gespeichert. Die Speichermethode von { a: 1, b: 2, c: 3, d: 4}-Objekten kann beispielsweise wie folgt sein:

[ class       ] -> [a: in obj #1, b: in obj #2, c: out obj #1, d: out obj #2]
[ properties  ] -> [  3  ][  4  ] ; this is linear array
[ elements    ]    
[ 1           ]
[ 2           ]

Mit zunehmender Anzahl von Attributen. V8 wechselt zurück zum traditionellen Wörterbuchmodus/Hash-Tabellenmodus:

[ class       ] -> [ OBJECT IS IN DICTIONARY MODE ]
[ properties  ] -> [a: 1, b: 2, c: 3, d: 4, e: 5] ; this is classical hash table
[ elements    ]

Referenz

  • V8 Design Elements

  • Eine Tour durch V8: Objektdarstellung

  • V8 und JavaScript-Leistung entmystifizieren

  • V8-Dokumente: Objektklassenreferenz

  • Wie verwaltet V8 den Speicher von Objektinstanzen?

Eigenschaftsname: Eigenschaftsname

Als dynamische Sprache ermöglicht uns JavaScript die Definition von Objekten in eine sehr flexible Möglichkeit, wie zum Beispiel:

obj.prop
obj["prop"]

Gemäß der Beschreibung in der JavaScript-Definitionsspezifikation ist der Attributname immer eine Zeichenfolge. Auch wenn Sie einen Namen verwenden, der kein String ist, wird er implizit konvertiert zu einem String-Typ. Wenn Sie beispielsweise ein Array erstellen und mit einem numerischen Index darauf zugreifen, konvertiert V8 es trotzdem in einen String und indiziert ihn dann, sodass die folgende Methode den gleichen Effekt erzielt:

obj[1];    //
obj["1"];  // names for the same property
obj[1.0];  //

var o = { toString: function () { return "-1.5"; } };

obj[-1.5];  // also equivalent
obj[o];     // since o is converted to string

Und in JavaScript Das Array ist nur ein Objekt, das zusätzliche length-Attribute enthält. length gibt das Ergebnis des aktuellen maximalen Index plus eins zurück (zu diesem Zeitpunkt wird der String-Index zur Berechnung in einen numerischen Typ konvertiert):

var a = new Array();
a[100] = "foo";
a.length;  //101
a[undefined] = 'a';
a.length; //0

Function ist im Wesentlichen ein Objekt, mit der Ausnahme, dass das Attribut length die Länge des Parameters zurückgibt:

> a = ()=>{}
[Function: a]
> a.length
0
> a = (b)=>{}
[Function: a]
> a.length
1

In-Objekt-Eigenschaften und schneller Eigenschaftszugriff: In-Objekt Eigenschaften und Zugriffsoptimierung

Als dynamisch typisierte Sprache können Objekteigenschaften in JavaScript zur Laufzeit dynamisch hinzugefügt und gelöscht werden, was bedeutet, dass sich die Struktur des gesamten Objekts häufig ändert. Die meisten JavaScript-Engines neigen dazu, Datenstrukturen vom Typ Wörterbuch zum Speichern von Objekteigenschaften zu verwenden. Bei jedem Zugriff auf eine Eigenschaft muss die Engine die der Eigenschaft entsprechende Indexadresse in der inneren Ebene dynamisch finden und dann den Wert lesen. Diese Methode ist einfacher zu implementieren, führt jedoch zu einer schlechten Leistung. In anderen statischen Sprachen wie Java und Smalltalk werden die festen Offset-Adressen von Mitgliedsvariablen im Speicher während der Kompilierungsphase bestimmt, und es ist nur eine einzige Anweisung erforderlich, um sie beim Zugriff auf Attribute aus dem Speicher zu laden. V8 verwendet die Methode der dynamischen Erstellung versteckter innerer Klassen, um die Speicheradresse des Attributs im Objekt dynamisch aufzuzeichnen und so die Gesamtzugriffsgeschwindigkeit des Attributs zu verbessern. Zusammenfassend lässt sich sagen, dass V8 jedes Mal, wenn einem Objekt eine neue Eigenschaft hinzugefügt wird, automatisch seine verborgene innere Klasse korrigiert. Lassen Sie uns zunächst die Existenz versteckter Klassen durch ein Experiment erfahren:

var PROPERTIES = 10000000;
var o = {};

var start = +new Date;

for (var i = 0; i < PROPERTIES; i++) {
  o[i] = i;
}

console.log(+new Date - start);

function O(size) {
  for (var i = 0; i < size; i++) {
    this[i] = null;
  }
}

var o = new O(PROPERTIES);

var start = +new Date;

for (var i = 0; i < PROPERTIES; i++) {
  o[i] = i;
}

console.log(+new Date - start);

class OClass {

    constructor(size){
        for (var i = 0; i < size; i++) {
            this[i] = null;
        }
    }

}

var o = new OClass(PROPERTIES);

var start = +new Date;

for (var i = 0; i < PROPERTIES; i++) {
  o[i] = i;
}

console.log(+new Date - start);

Die Ausführungsergebnisse dieses Programms sind wie folgt:

// Babel 下结果
385
37
49
// Chrome 下结果
416
32
31

In der ersten Implementierung handelt es sich jedes Mal um eine ObjektoBeim Festlegen eines neuen Attributs erstellt V8 eine neue versteckte interne Klasse (intern Map genannt), um die neue Speicheradresse zu speichern und die Geschwindigkeit der Attributsuche zu optimieren. In der zweiten Implementierung initialisieren wir die innere Klasse beim Erstellen eines neuen Objekts, sodass V8 diese Eigenschaften beim Zuweisen von Eigenschaften mit hoher Leistung finden kann. Die dritte Implementierung verwendet die ES6-Klasse, die unter reinem V8 die beste Leistung bietet. Lassen Sie uns als Nächstes näher erläutern, wie versteckte Klassen funktionieren. Angenommen, wir definieren eine Funktion, die den Punkt beschreibt:

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Wenn wir die new Point(x,y)-Anweisung ausführen, erstellt V8 ein neues Point-Objekt. Während des Erstellungsprozesses erstellt V8 zunächst eine versteckte interne Klasse namens C0. Da dem Objekt keine Attribute hinzugefügt wurden, ist die versteckte Klasse zu diesem Zeitpunkt noch leer:

接下来调用首个赋值语句this.x = x;为当前Point对象创建了新的属性x,此时 V8 会基于C0创建另一个隐藏类C1来替换C0,然后在C1中存放对象属性x的内存位置信息:

这里从C0C1的变化称为转换(Transitions),当我们为同一个类型的对象添加新的属性时,并不是每次都会创建新的隐藏类,而是多个对象会共用某个符合转换条件的隐藏类。接下来继续执行this.y = y 这一条语句,会为Point对象创建新的属性。此时 V8 会进行以下步骤:

  • 基于C1创建另一个隐藏类C1,并且将关于属性y的位置信息写入到C2中。

  • 更新C1为其添加转换信息,即当为Point对象添加属性 y 时,应该转换到隐藏类 C2

整个过程的伪代码描述如下:

<Point object is allocated>

  Class C0
    "x": TRANSITION to C1 at offset 0

this.x = x;

  Class C1
    "x": FIELD at offset 0
    "y": TRANSITION to C2 at offset 1

this.y = y;

  Map C2
    "x": FIELD at offset 0
    "y": FIELD at offset 1

Reused Hidden Class:重复使用的隐藏类

我们在上文中提及,如果每次添加新的属性时都创建新的隐藏类无疑是极大的性能浪费,实际上当我们再次创建新的Point对象时,V8 并不会创建新的隐藏类而是使用已有的,过程描述如下:

  • 初始化新的Point对象,并将隐藏类指向C0

  • 添加x属性时,遵循隐藏类的转换原则指向到C1 , 并且根据C1指定的偏移地址写入x

  • 添加y属性时,遵循隐藏类的转换原则指向到C2,并且根据C2指定的偏移地址写入y

另外我们在上文以链表的方式描述转换,实际上真实场景中 V8 会以树的结构来描述转换及其之间的关系,这样就能够用于类似于下面的属性一致而赋值顺序颠倒的场景:

function Point(x, y, reverse) {
  if (reverse) {
    this.x = x;
    this.y = y;
  } else {
    this.y = x;
    this.x = y;
  }
}

Methods & Prototypes:方法与原型

JavaScript 中并没有类的概念(语法糖除外),因此对于方法的调用处理会难于 C++ 或者 Java。下面这个例子中,distance方法可以被看做Point的普通属性之一,不过其并非原始类型的数据,而是指向了另一个函数:

function Point(x, y) {
  this.x = x;
  this.y = y;
  this.distance = PointDistance;
}

function PointDistance(p) {
  var dx = this.x - p.x;
  var dy = this.y - p.y;
  return Math.sqrt(dx*dx + dy*dy);
}

如果我们像上文介绍的普通的 in-object 域一样来处理distance属性,那么无疑会带来较大的内存浪费,毕竟每个对象都要存放一段外部函数引用(Reference 的内存占用往往大于原始类型)。C++ 中则是以指向多个虚函数的虚函数表(V-Tables)解决这个问题。每个包含虚函数的类的实例都会指向这个虚函数表,当调用某个虚函数时,程序会自动从虚函数表中加载该函数的地址信息然后转向到该地址调用。V8 中我们已经使用了隐藏类这一共享数据结构,因此可以很方便地改造下就可以。我们引入了所谓 Constant Functions 的概念,某个 Constant Function 即代表了对象中仅包含某个名字,而具体的属性值存放在描述符本身的概念:

<Point object is allocated>

  Class C0
    "x": TRANSITION to C1 at offset 0

this.x = x;

  Class C1
    "x": FIELD at offset 0
    "y": TRANSITION to C2 at offset 1

this.y = y;

  Class C2
    "x": FIELD at offset 0
    "y": FIELD at offset 1
    "distance": TRANSITION to C3 <PointDistance>

this.distance = PointDistance;

  Class C3
    "x": FIELD at offset 0
    "y": FIELD at offset 1
    "distance": CONSTANT_FUNCTION <PointDistance>

注意,在这里如果我们将PointDistance 重定义指向了其他函数,那么这个转换也会自动失效,V8 会创建新的隐藏类。另一种解决这个问题的方法就是使用原型,每个构造函数都会有所谓的Prototype属性,该属性会自动成为对象的原型链上的一环,上面的例子可以改写为以下方式:

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.distance = function(p) {
  var dx = this.x - p.x;
  var dy = this.y - p.y;
  return Math.sqrt(dx*dx + dy*dy);
}

...
var u = new Point(1, 2);
var v = new Point(3, 4);
var d = u.distance(v);

V8 同样会把原型链上的方法在隐藏类中映射为 Constant Function 描述符,而调用原型方法往往会比调用自身方法慢一点,毕竟引擎不仅要去扫描自身的隐藏类,还要去扫描原型链上对象的隐藏类才能得知真正的函数调用地址。不过这个不会对于代码的性能造成明显的影响,因此写代码的时候也不必小心翼翼的避免这个。

Dictionary Mode

对于复杂属性的对象,V8 会使用所谓的字典模式(Dictionary Mode)来存储对象,也就是使用哈希表来存放键值信息,这种方式存储开销会小于上文提到的包含了隐藏类的方式,不过查询速度会远小于前者。初始状态下,哈希表中的所有的键与值都被设置为了undefined,当插入新的数据时,计算得出的键名的哈希值的低位会被当做初始的存储索引地址。如果此地址已经被占用了,V8 会尝试向下一个地址进行插入,直到插入成功,伪代码表述如下:

// 插入
insert(table, key, value):
  table = ensureCapacity(table, length(table) + 1)
  code = hash(key)
  n = capacity(table)
  index = code (mod n)
  while getKey(table, index) is not undefined:
    index += 1 (mod n)
  set(table, index, key, value)

//查找
lookup(table, key):
  code = hash(key)
  n = capacity(table)
  index = code (mod n)
  k = getKey(table, index)
  while k is not null or undefined
        and k != key: 
    index += 1 (mod n)
    k = getKey(table, index)
  if k == key:
    return getValue(table, index)
  else:
    return undefined

尽管计算键名哈希值与比较的速度会比较快,但是每次读写属性的时候都进行这么多步骤无疑会大大拉低速度,因此 V8 尽可能地会避免使用这种存储方式。

Fast Elements:数值下标的属性

V8 中将属性名为非负整数(0、1、2……)的属性称为Element,每个对象都有一个指向Element数组的指针,其存放和其他属性是分开的。注意,隐藏类中并不包含 Element 的描述符,但可能包含其它有着不同 Element 类型的同一种隐藏类的转换描述符。大多数情况下,对象都会有 Fast Element,也就是说这些 Element 以连续数组的形式存放。有三种不同的 Fast Element:

  • Fast small integers

  • Fast doubles

  • Fast values

根据标准,JavaScript 中的所有数字都理应以64位浮点数形式出现。因此 V8 尽可能以31位带符号整数来表达数字(最低位总是0,这有助于垃圾回收器区分数字和指针)。因此含有Fast small integers类型的对象,其 Element 类型只会包含这样的数字。如果需要存储小数、大整数或其他特殊值,如-0,则需要将数组提升为 Fast doubles。于是这引入了潜在的昂贵的复制-转换操作,但通常不会频繁发生。Fast doubles 仍然是很快的,因为所有的数字都是无封箱存储的。但如果我们要存储的是其他类型,比如字符串或者对象,则必须将其提升为普通的 Fast Element 数组。

JavaScript 不提供任何确定存储元素多少的办法。你可能会说像这样的办法,new Array(100),但实际上这仅仅针对Array构造函数有用。如果你将值存在一个不存在的下标上,V8会重新开辟更大的内存,将原有元素复制到新内存。V8 可以处理带空洞的数组,也就是只有某些下标是存有元素,而期间的下标都是空的。其内部会安插特殊的哨兵值,因此试图访问未赋值的下标,会得到undefined。当然,Fast Element 也有其限制。如果你在远远超过当前数组大小的下标赋值,V8 会将数组转换为字典模式,将值以哈希表的形式存储。这对于稀疏数组来说很有用,但性能上肯定打了折扣,无论是从转换这一过程来说,还是从之后的访问来说。如果你需要复制整个数组,不要逆向复制(索引从高到低),因为这几乎必然触发字典模式。

    // 这会大大降低大数组的性能
    function copy(a) {
        var b = new Array();
        for (var i = a.length - 1; i >= 0; i--)
            b[i] = a[i];
        return b;
    }

由于普通的属性和数字式属性分开存放,即使数组退化为字典模式,也不会影响到其他属性的访问速度(反之亦然)。

Object 代码声明

// http://www.php.cn/
class V8_EXPORT Object : public Value {
  public:
   V8_DEPRECATE_SOON("Use maybe version",
                     bool Set(Local<Value> key, Local<Value> value));
   V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context,
                                         Local<Value> key, Local<Value> value);

   V8_DEPRECATE_SOON("Use maybe version",
                     bool Set(uint32_t index, Local<Value> value));
   V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context, uint32_t index,
                                         Local<Value> value);

   // Implements CreateDataProperty (ECMA-262, 7.3.4).
   //
   // Defines a configurable, writable, enumerable property with the given value
   // on the object unless the property already exists and is not configurable
   // or the object is not extensible.
   //
   // Returns true on success.
   V8_WARN_UNUSED_RESULT Maybe<bool> CreateDataProperty(Local<Context> context,
                                                        Local<Name> key,
                                                        Local<Value> value);
   V8_WARN_UNUSED_RESULT Maybe<bool> CreateDataProperty(Local<Context> context,
                                                        uint32_t index,
                                                        Local<Value> value);

   // Implements DefineOwnProperty.
   //
   // In general, CreateDataProperty will be faster, however, does not allow
   // for specifying attributes.
   //
   // Returns true on success.
   V8_WARN_UNUSED_RESULT Maybe<bool> DefineOwnProperty(
       Local<Context> context, Local<Name> key, Local<Value> value,
       PropertyAttribute attributes = None);

   // Sets an own property on this object bypassing interceptors and
   // overriding accessors or read-only properties.
   //
   // Note that if the object has an interceptor the property will be set
   // locally, but since the interceptor takes precedence the local property
   // will only be returned if the interceptor doesn&#39;t return a value.
   //
   // Note also that this only works for named properties.
   V8_DEPRECATED("Use CreateDataProperty / DefineOwnProperty",
                 bool ForceSet(Local<Value> key, Local<Value> value,
                               PropertyAttribute attribs = None));
   V8_DEPRECATE_SOON("Use CreateDataProperty / DefineOwnProperty",
                     Maybe<bool> ForceSet(Local<Context> context,
                                          Local<Value> key, Local<Value> value,
                                          PropertyAttribute attribs = None));

   V8_DEPRECATE_SOON("Use maybe version", Local<Value> Get(Local<Value> key));
   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
                                               Local<Value> key);

   V8_DEPRECATE_SOON("Use maybe version", Local<Value> Get(uint32_t index));
   V8_WARN_UNUSED_RESULT MaybeLocal<Value> Get(Local<Context> context,
                                               uint32_t index);

   V8_DEPRECATED("Use maybe version",
                 PropertyAttribute GetPropertyAttributes(Local<Value> key));
   V8_WARN_UNUSED_RESULT Maybe<PropertyAttribute> GetPropertyAttributes(
       Local<Context> context, Local<Value> key);

   V8_DEPRECATED("Use maybe version",
                 Local<Value> GetOwnPropertyDescriptor(Local<String> key));
   V8_WARN_UNUSED_RESULT MaybeLocal<Value> GetOwnPropertyDescriptor(
       Local<Context> context, Local<String> key);

   V8_DEPRECATE_SOON("Use maybe version", bool Has(Local<Value> key));
   V8_WARN_UNUSED_RESULT Maybe<bool> Has(Local<Context> context,
                                         Local<Value> key);

   V8_DEPRECATE_SOON("Use maybe version", bool Delete(Local<Value> key));
   // TODO(dcarney): mark V8_WARN_UNUSED_RESULT
   Maybe<bool> Delete(Local<Context> context, Local<Value> key);

   V8_DEPRECATED("Use maybe version", bool Has(uint32_t index));
   V8_WARN_UNUSED_RESULT Maybe<bool> Has(Local<Context> context, uint32_t index);

   V8_DEPRECATED("Use maybe version", bool Delete(uint32_t index));
   // TODO(dcarney): mark V8_WARN_UNUSED_RESULT
   Maybe<bool> Delete(Local<Context> context, uint32_t index);

   V8_DEPRECATED("Use maybe version",
                 bool SetAccessor(Local<String> name,
                                  AccessorGetterCallback getter,
                                  AccessorSetterCallback setter = 0,
                                  Local<Value> data = Local<Value>(),
                                  AccessControl settings = DEFAULT,
                                  PropertyAttribute attribute = None));
   V8_DEPRECATED("Use maybe version",
                 bool SetAccessor(Local<Name> name,
                                  AccessorNameGetterCallback getter,
                                  AccessorNameSetterCallback setter = 0,
                                  Local<Value> data = Local<Value>(),
                                  AccessControl settings = DEFAULT,
                                  PropertyAttribute attribute = None));
   // TODO(dcarney): mark V8_WARN_UNUSED_RESULT
   Maybe<bool> SetAccessor(Local<Context> context, Local<Name> name,
                           AccessorNameGetterCallback getter,
                           AccessorNameSetterCallback setter = 0,
                           MaybeLocal<Value> data = MaybeLocal<Value>(),
                           AccessControl settings = DEFAULT,
                           PropertyAttribute attribute = None);

   void SetAccessorProperty(Local<Name> name, Local<Function> getter,
                            Local<Function> setter = Local<Function>(),
                            PropertyAttribute attribute = None,
                            AccessControl settings = DEFAULT);

   Maybe<bool> HasPrivate(Local<Context> context, Local<Private> key);
   Maybe<bool> SetPrivate(Local<Context> context, Local<Private> key,
                          Local<Value> value);
   Maybe<bool> DeletePrivate(Local<Context> context, Local<Private> key);
   MaybeLocal<Value> GetPrivate(Local<Context> context, Local<Private> key);

   V8_DEPRECATE_SOON("Use maybe version", Local<Array> GetPropertyNames());
   V8_WARN_UNUSED_RESULT MaybeLocal<Array> GetPropertyNames(
       Local<Context> context);
   V8_WARN_UNUSED_RESULT MaybeLocal<Array> GetPropertyNames(
       Local<Context> context, KeyCollectionMode mode,
       PropertyFilter property_filter, IndexFilter index_filter);

   V8_DEPRECATE_SOON("Use maybe version", Local<Array> GetOwnPropertyNames());
   V8_WARN_UNUSED_RESULT MaybeLocal<Array> GetOwnPropertyNames(
       Local<Context> context);

   V8_WARN_UNUSED_RESULT MaybeLocal<Array> GetOwnPropertyNames(
       Local<Context> context, PropertyFilter filter);

   Local<Value> GetPrototype();

   V8_DEPRECATED("Use maybe version", bool SetPrototype(Local<Value> prototype));
   V8_WARN_UNUSED_RESULT Maybe<bool> SetPrototype(Local<Context> context,
                                                  Local<Value> prototype);

   Local<Object> FindInstanceInPrototypeChain(Local<FunctionTemplate> tmpl);

   V8_DEPRECATED("Use maybe version", Local<String> ObjectProtoToString());
   V8_WARN_UNUSED_RESULT MaybeLocal<String> ObjectProtoToString(
       Local<Context> context);

   Local<String> GetConstructorName();

   Maybe<bool> SetIntegrityLevel(Local<Context> context, IntegrityLevel level);

   int InternalFieldCount();

   V8_INLINE static int InternalFieldCount(
       const PersistentBase<Object>& object) {
     return object.val_->InternalFieldCount();
   }

   V8_INLINE Local<Value> GetInternalField(int index);

   void SetInternalField(int index, Local<Value> value);

   V8_INLINE void* GetAlignedPointerFromInternalField(int index);

   V8_INLINE static void* GetAlignedPointerFromInternalField(
       const PersistentBase<Object>& object, int index) {
     return object.val_->GetAlignedPointerFromInternalField(index);
   }

   void SetAlignedPointerInInternalField(int index, void* value);
   void SetAlignedPointerInInternalFields(int argc, int indices[],
                                          void* values[]);

   // Testers for local properties.
   V8_DEPRECATED("Use maybe version", bool HasOwnProperty(Local<String> key));
   V8_WARN_UNUSED_RESULT Maybe<bool> HasOwnProperty(Local<Context> context,
                                                    Local<Name> key);
   V8_WARN_UNUSED_RESULT Maybe<bool> HasOwnProperty(Local<Context> context,
                                                    uint32_t index);
   V8_DEPRECATE_SOON("Use maybe version",
                     bool HasRealNamedProperty(Local<String> key));
   V8_WARN_UNUSED_RESULT Maybe<bool> HasRealNamedProperty(Local<Context> context,
                                                          Local<Name> key);
   V8_DEPRECATE_SOON("Use maybe version",
                     bool HasRealIndexedProperty(uint32_t index));
   V8_WARN_UNUSED_RESULT Maybe<bool> HasRealIndexedProperty(
       Local<Context> context, uint32_t index);
   V8_DEPRECATE_SOON("Use maybe version",
                     bool HasRealNamedCallbackProperty(Local<String> key));
   V8_WARN_UNUSED_RESULT Maybe<bool> HasRealNamedCallbackProperty(
       Local<Context> context, Local<Name> key);

   V8_DEPRECATED(
       "Use maybe version",
       Local<Value> GetRealNamedPropertyInPrototypeChain(Local<String> key));
   V8_WARN_UNUSED_RESULT MaybeLocal<Value> GetRealNamedPropertyInPrototypeChain(
       Local<Context> context, Local<Name> key);

   V8_DEPRECATED(
       "Use maybe version",
       Maybe<PropertyAttribute> GetRealNamedPropertyAttributesInPrototypeChain(
           Local<String> key));
   V8_WARN_UNUSED_RESULT Maybe<PropertyAttribute>
   GetRealNamedPropertyAttributesInPrototypeChain(Local<Context> context,
                                                  Local<Name> key);

   V8_DEPRECATED("Use maybe version",
                 Local<Value> GetRealNamedProperty(Local<String> key));
   V8_WARN_UNUSED_RESULT MaybeLocal<Value> GetRealNamedProperty(
       Local<Context> context, Local<Name> key);

   V8_DEPRECATED("Use maybe version",
                 Maybe<PropertyAttribute> GetRealNamedPropertyAttributes(
                     Local<String> key));
   V8_WARN_UNUSED_RESULT Maybe<PropertyAttribute> GetRealNamedPropertyAttributes(
       Local<Context> context, Local<Name> key);

   bool HasNamedLookupInterceptor();

   bool HasIndexedLookupInterceptor();

   int GetIdentityHash();

   // TODO(dcarney): take an isolate and optionally bail out?
   Local<Object> Clone();

   Local<Context> CreationContext();

   bool IsCallable();

   bool IsConstructor();

   V8_DEPRECATED("Use maybe version",
                 Local<Value> CallAsFunction(Local<Value> recv, int argc,
                                             Local<Value> argv[]));
   V8_WARN_UNUSED_RESULT MaybeLocal<Value> CallAsFunction(Local<Context> context,
                                                          Local<Value> recv,
                                                          int argc,
                                                          Local<Value> argv[]);

   V8_DEPRECATED("Use maybe version",
                 Local<Value> CallAsConstructor(int argc, Local<Value> argv[]));
   V8_WARN_UNUSED_RESULT MaybeLocal<Value> CallAsConstructor(
       Local<Context> context, int argc, Local<Value> argv[]);

   V8_DEPRECATE_SOON("Keep track of isolate correctly", Isolate* GetIsolate());

   static Local<Object> New(Isolate* isolate);

   V8_INLINE static Object* Cast(Value* obj);

  private:
   Object();
   static void CheckCast(Value* obj);
   Local<Value> SlowGetInternalField(int index);
   void* SlowGetAlignedPointerFromInternalField(int index);
 };

 以上就是JavaScript V8 Object 内存结构与属性访问详解的内容,更多相关内容请关注PHP中文网(www.php.cn)!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn