js引擎v8源码解析之map对象上篇(基于v8 0.1.5)

  • 2019 年 11 月 23 日
  • 筆記

这一篇首先介绍Map类。下面先看类定义

// All heap objects have a Map that describes their structure.  //  A Map contains information about:  //  - Size information about the object  //  - How to iterate over an object (for garbage collection)  class Map: public HeapObject {   public:    // instance size.    inline int instance_size();    inline void set_instance_size(int value);      // instance type.    inline InstanceType instance_type();    inline void set_instance_type(InstanceType value);      // tells how many unused property fields are available in the instance.    // (only used for JSObject in fast mode).    inline int unused_property_fields();    inline void set_unused_property_fields(int value);      // bit field.    inline byte bit_field();    inline void set_bit_field(byte value);      // Tells whether this object has a special lookup behavior.    void set_special_lookup() {      set_bit_field(bit_field() | (1 << kHasSpecialLookup));    }      bool has_special_lookup() {      return ((1 << kHasSpecialLookup) & bit_field()) != 0;    }      // Tells whether the object in the prototype property will be used    // for instances created from this function.  If the prototype    // property is set to a value that is not a JSObject, the prototype    // property will not be used to create instances of the function.    // See ECMA-262, 13.2.2.    inline void set_non_instance_prototype(bool value);    inline bool has_non_instance_prototype();      // Tells whether the instance with this map should be ignored by the    // __proto__ accessor.    inline void set_is_hidden_prototype() {      set_bit_field(bit_field() | (1 << kIsHiddenPrototype));    }      inline bool is_hidden_prototype() {      return ((1 << kIsHiddenPrototype) & bit_field()) != 0;    }      // Tells whether the instance has a named interceptor.    inline void set_has_named_interceptor() {      set_bit_field(bit_field() | (1 << kHasNamedInterceptor));    }      inline bool has_named_interceptor() {      return ((1 << kHasNamedInterceptor) & bit_field()) != 0;    }      // Tells whether the instance has a named interceptor.    inline void set_has_indexed_interceptor() {      set_bit_field(bit_field() | (1 << kHasIndexedInterceptor));    }      inline bool has_indexed_interceptor() {      return ((1 << kHasIndexedInterceptor) & bit_field()) != 0;    }      // Tells whether the instance is undetectable.    // An undetectable object is a special class of JSObject: 'typeof' operator    // returns undefined, ToBoolean returns false. Otherwise it behaves like    // a normal JS object.  It is useful for implementing undetectable    // document.all in Firefox & Safari.    // See https://bugzilla.mozilla.org/show_bug.cgi?id=248549.    inline void set_is_undetectable() {      set_bit_field(bit_field() | (1 << kIsUndetectable));    }      inline bool is_undetectable() {      return ((1 << kIsUndetectable) & bit_field()) != 0;    }      // Tells whether the instance has a call-as-function handler.    inline void set_has_instance_call_handler() {      set_bit_field(bit_field() | (1 << kHasInstanceCallHandler));    }      inline bool has_instance_call_handler() {      return ((1 << kHasInstanceCallHandler) & bit_field()) != 0;    }      // Tells whether the instance needs security checks when accessing its    // properties.    inline void set_needs_access_check() {      set_bit_field(bit_field() | (1 << kNeedsAccessCheck));    }      inline bool needs_access_check() {      return ((1 << kNeedsAccessCheck) & bit_field()) != 0;    }      // [prototype]: implicit prototype object.    /*          #define DECL_ACCESSORS(name, type)          inline type* name();                         inline void set_##name(type* value)        宏展开后变成,定义了读写某个属性的函数        Object * prototype();        void * set_prototype(Object * value);          属性的定义如下(宏展开后也是读写某个属性):          #define ACCESSORS(holder, name, type, offset)                                               type* holder::name() { return type::cast(READ_FIELD(this, offset)); }             void holder::set_##name(type* value) {                                              WRITE_FIELD(this, offset, value);                                                 WRITE_BARRIER(this, offset);                                                    }            // 定义各个类的读写某属性的函数,第三第四个参数是类型和偏移          ACCESSORS(Map, instance_descriptors, DescriptorArray,                    kInstanceDescriptorsOffset)          ACCESSORS(Map, code_cache, FixedArray, kCodeCacheOffset)          ACCESSORS(Map, constructor, Object, kConstructorOffset    */    DECL_ACCESSORS(prototype, Object)      // [constructor]: points back to the function responsible for this map.    DECL_ACCESSORS(constructor, Object)      // [instance descriptors]: describes the object.    DECL_ACCESSORS(instance_descriptors, DescriptorArray)      // [stub cache]: contains stubs compiled for this map.    DECL_ACCESSORS(code_cache, FixedArray)      // Returns a copy of the map.    Object* Copy();      // Returns the property index for name (only valid for FAST MODE).    int PropertyIndexFor(String* name);      // Returns the next free property index (only valid for FAST MODE).    int NextFreePropertyIndex();      // Returns the number of properties described in instance_descriptors.    int NumberOfDescribedProperties();      // Casting.    static inline Map* cast(Object* obj);      // Locate an accessor in the instance descriptor.    AccessorDescriptor* FindAccessor(String* name);      // Make sure the instance descriptor has no map transitions    Object* EnsureNoMapTransitions();      // Code cache operations.      // Clears the code cache.    inline void ClearCodeCache();      // Update code cache.    Object* UpdateCodeCache(String* name, Code* code);      // Returns the found code or undefined if absent.    Object* FindInCodeCache(String* name, Code::Flags flags);      // Tells whether code is in the code cache.    bool IncludedInCodeCache(Code* code);      // Dispatched behavior.    void MapIterateBody(ObjectVisitor* v);  #ifdef DEBUG    void MapPrint();    void MapVerify();  #endif      // Layout description.    static const int kInstanceAttributesOffset = HeapObject::kSize;    static const int kPrototypeOffset = kInstanceAttributesOffset + kIntSize;    static const int kConstructorOffset = kPrototypeOffset + kPointerSize;    static const int kInstanceDescriptorsOffset =        kConstructorOffset + kPointerSize;    static const int kCodeCacheOffset = kInstanceDescriptorsOffset + kPointerSize;    static const int kSize = kCodeCacheOffset + kIntSize;      // Byte offsets within kInstanceAttributesOffset attributes.    static const int kInstanceSizeOffset = kInstanceAttributesOffset + 0;    static const int kInstanceTypeOffset = kInstanceAttributesOffset + 1;    static const int kUnusedPropertyFieldsOffset = kInstanceAttributesOffset + 2;    static const int kBitFieldOffset = kInstanceAttributesOffset + 3;      // kBitFieldOffset对应的一个字节,下面分别是该一个字节各比特位的标记    static const int kHasSpecialLookup = 0;    static const int kHasNonInstancePrototype = 1;    static const int kIsHiddenPrototype = 2;    static const int kHasNamedInterceptor = 3;    static const int kHasIndexedInterceptor = 4;    static const int kIsUndetectable = 5;    static const int kHasInstanceCallHandler = 6;    static const int kNeedsAccessCheck = 7;   private:    DISALLOW_IMPLICIT_CONSTRUCTORS(Map);  };

下面的map的属性内存布局。

我们逐个函数分析他的实现。首先看objects-inl.h中的实现。

// 获取对象某个属性的地址,p是对象的首地址,offset是偏移,kHeapObjectTag是对象的标记,算地址的时候需要减掉  #define FIELD_ADDR(p, offset)     (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)    // 读写一个字节的内容  #define READ_BYTE_FIELD(p, offset)     (*reinterpret_cast<byte*>(FIELD_ADDR(p, offset)))    #define WRITE_BYTE_FIELD(p, offset, value)     (*reinterpret_cast<byte*>(FIELD_ADDR(p, offset)) = value)      void Map::set_instance_size(int value) {    ASSERT(0 <= value && value < 256);    WRITE_BYTE_FIELD(this, kInstanceSizeOffset, static_cast<byte>(value));  }      InstanceType Map::instance_type() {    return static_cast<InstanceType>(READ_BYTE_FIELD(this, kInstanceTypeOffset));  }      void Map::set_instance_type(InstanceType value) {    ASSERT(0 <= value && value < 256);    WRITE_BYTE_FIELD(this, kInstanceTypeOffset, value);  }      int Map::unused_property_fields() {    return READ_BYTE_FIELD(this, kUnusedPropertyFieldsOffset);  }      void Map::set_unused_property_fields(int value) {    WRITE_BYTE_FIELD(this, kUnusedPropertyFieldsOffset, Min(value, 255));  }    // 读写一个字节的内容,每个比特都记录着一个标记  byte Map::bit_field() {    return READ_BYTE_FIELD(this, kBitFieldOffset);  }      void Map::set_bit_field(byte value) {    WRITE_BYTE_FIELD(this, kBitFieldOffset, value);  }      void Map::set_non_instance_prototype(bool value) {    if (value) {      // 设置该位      set_bit_field(bit_field() | (1 << kHasNonInstancePrototype));    } else {      // 清除该位      set_bit_field(bit_field() & ~(1 << kHasNonInstancePrototype));    }  }    // 是否设置了某位  bool Map::has_non_instance_prototype() {    return ((1 << kHasNonInstancePrototype) & bit_field()) != 0;  }    void Map::ClearCodeCache() {    // No write barrier is needed since empty_fixed_array is not in new space.    // Please note this function is used during marking:    //  - MarkCompactCollector::MarkUnmarkedObject    ASSERT(!Heap::InNewSpace(Heap::empty_fixed_array()));    WRITE_FIELD(this, kCodeCacheOffset, Heap::empty_fixed_array());  }

从上面的代码中我们知道,只是对某些属性或标记进行读写。根据对象的内存布局对号入座就行,至于每个属性和标记的意义,后续再慢慢探讨。map还有很多函数,但是会涉及很多其他的类,等后面分析完了,再继续分析。