前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >js引擎v8源码解析之map对象上篇(基于v8 0.1.5)

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

作者头像
theanarkh
发布2019-11-23 22:24:34
1.6K0
发布2019-11-23 22:24:34
举报
文章被收录于专栏:原创分享

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

代码语言:javascript
复制
// 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中的实现。

代码语言:javascript
复制
// 获取对象某个属性的地址,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还有很多函数,但是会涉及很多其他的类,等后面分析完了,再继续分析。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程杂技 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档