• home > webfront > browser > JavaScriptCore/V8 >

    js引擎v8源码解析(1):v8的对象基类是Object

    Author:zhoulujun Date:

    解读v8源码,从源码剖析 JavaScriptv8的对象基类是Object。我们先看一下他的类定义。

    Object

    v8的对象基类是Object。我们先看一下他的类定义。下面只列出重要的函数。

    // 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 Smi and Failure are subclasses of Object no
    // data members can be present in Object.
    class Object BASE_EMBEDDED {
     public:
      // Type testing.
      inline bool IsSmi();
      // 下面是一些列isXX的函数
      // Extract the number.
      inline double Number();
    
      Object* ToObject();             // ECMA-262 9.9.
      Object* ToBoolean();            // ECMA-262 9.2.
    
      // Convert to a JSObject if needed.
      // global_context is used when creating wrapper object.
      Object* ToObject(Context* global_context);
    
      // Converts this to a Smi if possible.
      // Failure is returned otherwise.
      inline Object* ToSmi();
    
      void Lookup(String* name, LookupResult* result);
    
      // Property access.
      inline Object* GetProperty(String* key);
      inline Object* GetProperty(String* key, PropertyAttributes* attributes);
      Object* GetPropertyWithReceiver(Object* receiver,
                                      String* key,
                                      PropertyAttributes* attributes);
      Object* GetProperty(Object* receiver,
                          LookupResult* result,
                          String* key,
                          PropertyAttributes* attributes);
      Object* GetPropertyWithCallback(Object* receiver,
                                      Object* structure,
                                      String* name,
                                      Object* holder);
    
      inline Object* GetElement(uint32_t index);
      Object* GetElementWithReceiver(Object* receiver, uint32_t index);
    
      // Return the object's prototype (might be Heap::null_value()).
      Object* GetPrototype();
    
      // Returns true if this is a JSValue containing a string and the index is
      // < the length of the string.  Used to implement [] on strings.
      inline bool IsStringObjectWithCharacterAt(uint32_t index);
    
      // Casting: This cast is only needed to satisfy macros in objects-inl.h.
      static Object* cast(Object* value) { return value; }
    
      // Layout description.
      static const int kSize = 0;  // Object does not take up any space.
    
     private:
      // 禁止对象在堆中创建
      /*
      	宏展开是
      	Object();
      	Object(const TypeName&);
      	void operator=(const Object&)
      */
      DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
    };

    我们看到类中有一个静态属性kSize,这个属性是标记该类的对象,属性需要占据的内存字节大小。
    下面我们看第一个继承于Object的类Smi。Smi是表示小整形。我们看他的定义。

    // HeapObject is the superclass for all classes describing heap allocated
    // objects.
    class HeapObject: public Object {
     public:
      // [map]: contains a Map which contains the objects reflective information.
      inline Map* map();
      inline void set_map(Map* value);
    
      // Converts an address to a HeapObject pointer.
      // 对象的地址+对象标记
      static inline HeapObject* FromAddress(Address address);
    
      // Returns the address of this HeapObject.
      // 对象的真正地址
      inline Address address();
    
      // Iterates over pointers contained in the object (including the Map)
      void Iterate(ObjectVisitor* v);
    
      // Iterates over all pointers contained in the object except the
      // first map pointer.  The object type is given in the first
      // parameter. This function does not access the map pointer in the
      // object, and so is safe to call while the map pointer is modified.
      void IterateBody(InstanceType type, int object_size, ObjectVisitor* v);
    
      // This method only applies to struct objects.  Iterates over all the fields
      // of this struct.
      void IterateStructBody(int object_size, ObjectVisitor* v);
    
      // Copy the body from the 'from' object to this.
      // Please note the two object must have the same map prior to the call.
      inline void CopyBody(JSObject* from);
    
      // Returns the heap object's size in bytes
      inline int Size();
    
      // Given a heap object's map pointer, returns the heap size in bytes
      // Useful when the map pointer field is used for other purposes.
      // GC internal.
      inline int SizeFromMap(Map* map);
    
      static inline Object* GetHeapObjectField(HeapObject* obj, int index);
    
      // Casting.
      static inline HeapObject* cast(Object* obj);
    
      // Dispatched behavior.
      void HeapObjectShortPrint(StringStream* accumulator);
    
      // Layout description.
      // First field in a heap object is map.
      static const int kMapOffset = Object::kSize;
      static const int kSize = kMapOffset + kPointerSize;
    
     protected:
      // helpers for calling an ObjectVisitor to iterate over pointers in the
      // half-open range [start, end) specified as integer offsets
      inline void IteratePointers(ObjectVisitor* v, int start, int end);
      // as above, for the single element at "offset"
      inline void IteratePointer(ObjectVisitor* v, int offset);
    
      // Computes the object size from the map.
      // Should only be used from SizeFromMap.
      int SlowSizeFromMap(Map* map);
    
     private:
      DISALLOW_IMPLICIT_CONSTRUCTORS(HeapObject);
    };

    我们先看一下HeapObject类的对象的内存布局。

     static const int kMapOffset = Object::kSize; // 0
     static const int kSize = kMapOffset + kPointerSize; // kPointerSize表示一个指针变量的大小

    下面我们开始HeapObject的实现。从之前的分析我们知道,v8很多对象的属性不是和传统的C++那样,直接定义一个类型的。而且通过给属性分配字节数去控制的。所以分析之前我们要先了解一个东西,就是如何读写对象的一个属性。

    // 获取对象某个属性的地址,p是对象的首地址,offset是偏移,kHeapObjectTag是对象的标记,算地址的时候需要减掉
    #define FIELD_ADDR(p, offset) \
      (reinterpret_cast<byte*>(p) + offset - kHeapObjectTag)
    
    // 读取对象中某个属性的值,指向对象地址空间的某个地址,转成对象指针
    #define READ_FIELD(p, offset) \
      (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)))
    
    // 给对象的某个属性赋值
    #define WRITE_FIELD(p, offset, value) \
      (*reinterpret_cast<Object**>(FIELD_ADDR(p, offset)) = value)

    然后我们接着看HeapObject的实现。

    // 堆对象的开始地址是一个Map对象
    Map* HeapObject::map() {
      return reinterpret_cast<Map*> READ_FIELD(this, kMapOffset);
    }
    
    // 设置堆对象的map对象
    void HeapObject::set_map(Map* value) {
      WRITE_FIELD(this, kMapOffset, value);
    }

    上面就是读写对象的某个属性的例子(heapObject只有一个map属性)。首先根据属性在对象内存布局中的偏移找到属性的地址,然后把他转成Object对象(基类),然后把value写进去,这里是一个Map对象。读取的时候也是先转成Object对象。然后再转成Map对象。map属性在所有对象中都是在第一个位置。

    // 封装过的地址,kHeapObjectTag表示是一个堆对象
    HeapObject* HeapObject::FromAddress(Address address) {
      ASSERT_TAG_ALIGNED(address);
      return reinterpret_cast<HeapObject*>(address + kHeapObjectTag);
    }
    
    // 对象的真正地址
    Address HeapObject::address() {
      return reinterpret_cast<Address>(this) - kHeapObjectTag;
    }

    上面是对对象地址的封装,低一位表示类型。即堆对象。这篇先分析到这里,下一篇分析完Map类后再继续分析HeapObject类的实现,因为他用到了Map类。

    VirtualMemory

    VirtualMemory是通过mmap申请一块内存,然后进行管理

    class VirtualMemory {
     public:
      // Reserves virtual memory with size. address_hint代表用户想映射的地址
      VirtualMemory(size_t size, void* address_hint = 0);
      ~VirtualMemory();
    
      // Returns whether the memory has been reserved.
      bool IsReserved();
    
      // Returns the start address of the reserved memory.
      void* address() {
        ASSERT(IsReserved());
        return address_;
      };
    
      // Returns the size of the reserved memory.
      size_t size() { return size_; }
    
      // Commits real memory. Returns whether the operation succeeded.
      bool Commit(void* address, size_t size);
    
      // Uncommit real memory.  Returns whether the operation succeeded.
      bool Uncommit(void* address, size_t size);
    
     private:
      // 管理的内存首地址,由mmap返回,用户可以自定义
      void* address_;  // Start address of the virtual memory.
      // 管理的内存大小
      size_t size_;  // Size of the virtual memory.};
    // Constants used for mmap.static const int kMmapFd = -1;static const int kMmapFdOffset = 0;VirtualMemory::VirtualMemory(size_t size, void* address_hint) {
      // 映射一块内存,不能访问,私有的,不映射到文件,写的时候如果没有物理内存则报错
      address_ = mmap(address_hint, size, PROT_NONE,
                      MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
                      kMmapFd, kMmapFdOffset);
      size_ = size;}VirtualMemory::~VirtualMemory() {
      // 已经分配了虚拟内存则释放
      if (IsReserved()) {
        if (0 == munmap(address(), size())) address_ = MAP_FAILED;
      }}// 是否分配了虚拟内存bool VirtualMemory::IsReserved() {
      return address_ != MAP_FAILED;}// bool VirtualMemory::Commit(void* address, size_t size) {
      // 修改一块虚拟内存的属性,MAP_FIXED说明分配的地址一定是address,而不能由操作系统自己选择,这里是修改属性,所以地址要固定。因为这块内存已经申请过了
      if (MAP_FAILED == mmap(address, size, PROT_READ | PROT_WRITE | PROT_EXEC,
                             MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
                             kMmapFd, kMmapFdOffset)) {
        return false;
      }
    
      UpdateAllocatedSpaceLimits(address, size);
      return true;}// 修改某块虚拟内存的属性,变成不可访问bool VirtualMemory::Uncommit(void* address, size_t size) {
      return mmap(address, size, PROT_NONE,
                  MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
                  kMmapFd, kMmapFdOffset) != MAP_FAILED;}


    原文链接:

    js引擎v8源码解析之平台相关(上篇)(基于v8 0.1.5) https://cloud.tencent.com/developer/article/1543295

    js引擎v8源码解析之对象第一篇(基于v8 0.1.5) https://cloud.tencent.com/developer/article/1543225


    转载本站文章《js引擎v8源码解析(1):v8的对象基类是Object》,
    请注明出处:https://www.zhoulujun.cn/index.php?m=content&c=index&a=show&catid=329&id=8634

    上一篇:First page
    下一篇:Last page