js引擎v8源碼解析之對象第三篇(基於v8 0.1.5)
- 2019 年 11 月 24 日
- 筆記
1 TemplateInfo
TemplateInfo是函數和對象模板的基類。
// An abstract superclass, a marker class really, for simple structure classes. // It doesn't carry much functionality but allows struct classes to me // identified in the type system. class Struct: public HeapObject { public: inline void InitializeBody(int object_size); static inline Struct* cast(Object* that); }; void Struct::InitializeBody(int object_size) { for (int offset = kSize; offset < object_size; offset += kPointerSize) { WRITE_FIELD(this, offset, Heap::undefined_value()); } } class TemplateInfo: public Struct { public: DECL_ACCESSORS(tag, Object) DECL_ACCESSORS(property_list, Object) static const int kTagOffset = HeapObject::kSize; static const int kPropertyListOffset = kTagOffset + kPointerSize; static const int kHeaderSize = kPropertyListOffset + kPointerSize; protected: friend class AGCCVersionRequiresThisClassToHaveAFriendSoHereItIs; DISALLOW_IMPLICIT_CONSTRUCTORS(TemplateInfo); };
通過前幾篇的分析,我覺得這個代碼沒必要分析了。我們直接看子類。
2 FunctionTemplateInfo
class FunctionTemplateInfo: public TemplateInfo { public: DECL_ACCESSORS(serial_number, Object) DECL_ACCESSORS(call_code, Object) DECL_ACCESSORS(property_accessors, Object) DECL_ACCESSORS(prototype_template, Object) DECL_ACCESSORS(parent_template, Object) DECL_ACCESSORS(named_property_handler, Object) DECL_ACCESSORS(indexed_property_handler, Object) DECL_ACCESSORS(instance_template, Object) DECL_ACCESSORS(class_name, Object) DECL_ACCESSORS(signature, Object) DECL_ACCESSORS(lookup_callback, Object) DECL_ACCESSORS(instance_call_handler, Object) DECL_ACCESSORS(access_check_info, Object) DECL_ACCESSORS(flag, Smi) // Following properties use flag bits. DECL_BOOLEAN_ACCESSORS(hidden_prototype) DECL_BOOLEAN_ACCESSORS(undetectable) // If the bit is set, object instances created by this function // requires access check. DECL_BOOLEAN_ACCESSORS(needs_access_check) static inline FunctionTemplateInfo* cast(Object* obj); #ifdef DEBUG void FunctionTemplateInfoPrint(); void FunctionTemplateInfoVerify(); #endif static const int kSerialNumberOffset = TemplateInfo::kHeaderSize; static const int kCallCodeOffset = kSerialNumberOffset + kPointerSize; static const int kPropertyAccessorsOffset = kCallCodeOffset + kPointerSize; static const int kPrototypeTemplateOffset = kPropertyAccessorsOffset + kPointerSize; static const int kParentTemplateOffset = kPrototypeTemplateOffset + kPointerSize; static const int kNamedPropertyHandlerOffset = kParentTemplateOffset + kPointerSize; static const int kIndexedPropertyHandlerOffset = kNamedPropertyHandlerOffset + kPointerSize; static const int kInstanceTemplateOffset = kIndexedPropertyHandlerOffset + kPointerSize; static const int kClassNameOffset = kInstanceTemplateOffset + kPointerSize; static const int kSignatureOffset = kClassNameOffset + kPointerSize; static const int kLookupCallbackOffset = kSignatureOffset + kPointerSize; static const int kInstanceCallHandlerOffset = kLookupCallbackOffset + kPointerSize; static const int kAccessCheckInfoOffset = kInstanceCallHandlerOffset + kPointerSize; static const int kFlagOffset = kAccessCheckInfoOffset + kPointerSize; static const int kSize = kFlagOffset + kPointerSize; private: DISALLOW_IMPLICIT_CONSTRUCTORS(FunctionTemplateInfo); // Bit position in the flag, from least significant bit position. static const int kHiddenPrototypeBit = 0; static const int kUndetectableBit = 1; static const int kNeedsAccessCheckBit = 2; }; ACCESSORS(FunctionTemplateInfo, serial_number, Object, kSerialNumberOffset) ACCESSORS(FunctionTemplateInfo, call_code, Object, kCallCodeOffset) ACCESSORS(FunctionTemplateInfo, property_accessors, Object, kPropertyAccessorsOffset) ACCESSORS(FunctionTemplateInfo, prototype_template, Object, kPrototypeTemplateOffset) ACCESSORS(FunctionTemplateInfo, parent_template, Object, kParentTemplateOffset) ACCESSORS(FunctionTemplateInfo, named_property_handler, Object, kNamedPropertyHandlerOffset) ACCESSORS(FunctionTemplateInfo, indexed_property_handler, Object, kIndexedPropertyHandlerOffset) ACCESSORS(FunctionTemplateInfo, instance_template, Object, kInstanceTemplateOffset) ACCESSORS(FunctionTemplateInfo, class_name, Object, kClassNameOffset) ACCESSORS(FunctionTemplateInfo, signature, Object, kSignatureOffset) ACCESSORS(FunctionTemplateInfo, lookup_callback, Object, kLookupCallbackOffset) ACCESSORS(FunctionTemplateInfo, instance_call_handler, Object, kInstanceCallHandlerOffset) ACCESSORS(FunctionTemplateInfo, access_check_info, Object, kAccessCheckInfoOffset) ACCESSORS(FunctionTemplateInfo, flag, Smi, kFlagOffset) BOOL_ACCESSORS(FunctionTemplateInfo, flag, hidden_prototype, kHiddenPrototypeBit) BOOL_ACCESSORS(FunctionTemplateInfo, flag, undetectable, kUndetectableBit) BOOL_ACCESSORS(FunctionTemplateInfo, flag, needs_access_check, kNeedsAccessCheckBit)
3 ObjectTemplateInfo
class ObjectTemplateInfo: public TemplateInfo { public: DECL_ACCESSORS(constructor, Object) DECL_ACCESSORS(internal_field_count, Object) static inline ObjectTemplateInfo* cast(Object* obj); #ifdef DEBUG void ObjectTemplateInfoPrint(); void ObjectTemplateInfoVerify(); #endif static const int kConstructorOffset = TemplateInfo::kHeaderSize; static const int kInternalFieldCountOffset = kConstructorOffset + kPointerSize; static const int kSize = kInternalFieldCountOffset + kHeaderSize; }; ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset) ACCESSORS(ObjectTemplateInfo, internal_field_count, Object, kInternalFieldCountOffset)
我們從代碼可以知道,這幾個類沒有太多的邏輯,都有一系列的屬性和對應的讀寫函數。對號入座就行。
4 BooleanBit
// BooleanBit is a helper class for setting and getting a bit in an // integer or Smi. // 比特位讀寫類 class BooleanBit : public AllStatic { public: static inline bool get(Smi* smi, int bit_position) { return get(smi->value(), bit_position); } static inline bool get(int value, int bit_position) { return (value & (1 << bit_position)) != 0; } static inline Smi* set(Smi* smi, int bit_position, bool v) { return Smi::FromInt(set(smi->value(), bit_position, v)); } static inline int set(int value, int bit_position, bool v) { if (v) { // 設置 value |= (1 << bit_position); } else { // 清除 value &= ~(1 << bit_position); } return value; } }; } }
5 AccessorInfo
class AccessorInfo: public Struct { public: DECL_ACCESSORS(getter, Object) DECL_ACCESSORS(setter, Object) DECL_ACCESSORS(data, Object) DECL_ACCESSORS(name, Object) DECL_ACCESSORS(flag, Smi) inline bool all_can_read(); inline void set_all_can_read(bool value); inline bool all_can_write(); inline void set_all_can_write(bool value); inline PropertyAttributes property_attributes(); inline void set_property_attributes(PropertyAttributes attributes); static inline AccessorInfo* cast(Object* obj); static const int kGetterOffset = HeapObject::kSize; static const int kSetterOffset = kGetterOffset + kPointerSize; static const int kDataOffset = kSetterOffset + kPointerSize; static const int kNameOffset = kDataOffset + kPointerSize; static const int kFlagOffset = kNameOffset + kPointerSize; static const int kSize = kFlagOffset + kPointerSize; private: DISALLOW_IMPLICIT_CONSTRUCTORS(AccessorInfo); // Bit positions in flag. static const int kAllCanReadBit = 0; static const int kAllCanWriteBit = 1; class AttributesField: public BitField<PropertyAttributes, 2, 3> {}; };
我們先看屬性的定義。
ACCESSORS(AccessorInfo, getter, Object, kGetterOffset) ACCESSORS(AccessorInfo, setter, Object, kSetterOffset) ACCESSORS(AccessorInfo, data, Object, kDataOffset) ACCESSORS(AccessorInfo, name, Object, kNameOffset) ACCESSORS(AccessorInfo, flag, Smi, kFlagOffset)
接着看函數的實現。我們發現private里有一個私有類
// 低兩位是可讀寫標記 class AttributesField: public BitField<PropertyAttributes, 2, 3> {};
BitField是一個模板
// BitField is a help template for encoding and decode bitfield with unsigned // content. template<class T, int shift, int size> class BitField { public: // Tells whether the provided value fits into the bit field. // 判斷低幾位之外的其他位是否都等於0 static bool is_valid(T value) { return (static_cast<uint32_t>(value) & ~((1U << (size)) - 1)) == 0; } // Returns a uint32_t mask of bit field. // 從第shift+1到shift+size位為1,其他位為0。這裡是3到5位 static uint32_t mask() { return (1U << (size + shift)) - (1U << shift); } // Returns a uint32_t with the bit field value encoded. // 設置某位的值,這裡是跳過低2位,因為低兩位是可讀寫標記 static uint32_t encode(T value) { ASSERT(is_valid(value)); return static_cast<uint32_t>(value) << shift; } // Extracts the bit field from the value. // 取某位的值,需要屏蔽其他不相關的位的值,這裡值的範圍是小於等於7 static T decode(uint32_t value) { return static_cast<T>((value >> shift) & ((1U << (size)) - 1)); } };
最後看一下其他函數的實現。
// 判斷某個值的比特是否已設置 bool AccessorInfo::all_can_read() { return BooleanBit::get(flag(), kAllCanReadBit); } // 設置某個值的某個比特 void AccessorInfo::set_all_can_read(bool value) { set_flag(BooleanBit::set(flag(), kAllCanReadBit, value)); } bool AccessorInfo::all_can_write() { return BooleanBit::get(flag(), kAllCanWriteBit); } void AccessorInfo::set_all_can_write(bool value) { set_flag(BooleanBit::set(flag(), kAllCanWriteBit, value)); } // 獲flag里取某位的值 PropertyAttributes AccessorInfo::property_attributes() { return AttributesField::decode(static_cast<uint32_t>(flag()->value())); } /* // Ecma-262 3rd 8.6.1 enum PropertyAttributes { NONE = v8::None, READ_ONLY = v8::ReadOnly, DONT_ENUM = v8::DontEnum, DONT_DELETE = v8::DontDelete, INTERCEPTED = 1 << 3, ABSENT = 16 // Used in runtime to indicate a property is absent. }; 設置flag某位的值,見AttributesField */ void AccessorInfo::set_property_attributes(PropertyAttributes attributes) { ASSERT(AttributesField::is_valid(attributes)); // 清除相關的位 int rest_value = flag()->value() & ~AttributesField::mask(); // 重新設置某位 set_flag(Smi::FromInt(rest_value | AttributesField::encode(attributes))); }
我們看到因為PropertyAttributes是3個比特可以表示全部值的。所以flag中划出3-5三位記錄著三個比特。每次設置的時候,需要把之前的清除。AccessorInfo就是我們在js里的屬性描述符。