您的位置:首页 > 移动开发 > Objective-C

v8的HeapObject解析

2014-03-02 21:49 99 查看
一.HeapObject之内存结构
v8使用HeapObject作为js object的基类,其优点是一方面可以加快访问速度,另外还可以通过垃圾回收进行管理,所有从HeapObject派生的类,都是原始的struct结构,它使用四字节作为一个字段,第一个四字节字段是map指针,指向一个map对象,当然这个map对象也是从HeapObject派生的,我们可以从这样的派生类定义中看到其内存结构。以StringObject为例,可参看
StringObject的内存布局,
JSReceiver及其派生类的内存布局

二.HeapObject中字段的设置与获取
HeapObject及其派生类对象中的字段是靠getter和setter来获取和设置的,但是在他们的定义中却找不到getter和setter函数,那么它们定义在哪里呢?
在objects.h中,宏DECL_ACCESSORS定义如下:
#define DECL_ACCESSORS(name, type) \

inline type* name(); \

inline void set_##name(type* value, \

WriteBarrierMode mode = UPDATE_WRITE_BARRIER); \
每个HeapObject中必然有该宏来声明getter和setter函数

在objects-inl.h,宏ACCESSORS定义了getter和setter函数
#define ACCESSORS(holder, name, type, offset) \

type* holder::name() { return type::cast(READ_FIELD(this, offset)); } \

void holder::set_##name(type* value, WriteBarrierMode mode) { \

WRITE_FIELD(this, offset, value); \

CONDITIONAL_WRITE_BARRIER(GetHeap(), this, offset, value, mode); \

}
另外,在该头文件中,还有大量类使用ACCESSORS宏定义其getter和setter函数
该宏中使用了READ_FIELD和WRITE_FIELD宏来读写指定offset的内容
#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)

三.TypeChecker and Cast
由于使用了Struct的内存结构,无法像C++那样在运行期保证Object的类型,v8定义了如下的宏来保证类型和转换的正确性(在objects-inl.h中定义)
#define TYPE_CHECKER(type, instancetype) \

bool Object::Is##type() { \

return Object::IsHeapObject() && \

HeapObject::cast(this)->map()->instance_type() == instancetype; \

}
判断type是否是instancetype

#define CAST_ACCESSOR(type) \

type* type::cast(Object* object) { \

ASSERT(object->Is##type()); \

return reinterpret_cast<type*>(object); \

}
把Object指针强制转换为type*类型

我们可以看到这里使用了map的instance_type进行实例的类型判断,它们实际上定义了两类函数,TYPE_CHECKER宏为Object类定义IsType函数,CAST_ACCESSOR宏为不同的类定义cast函数,同样在该文件中,若干个类使用了这两个宏来定义IsType和cast函数

四.注意事项
这里特别需要提到的一点是在计算地址的时候,使用到了kHeapObjectTag,该值为1,而且在调试过程中我们发现这里用到计算地址的this指针都不是四字节对齐的,显然在要求四字节对齐的C/C++语言中是不可想象的,所以这个this指针一定会是做了处理,通过分析我们发现在创建Struct对象的时候,Heap分配内存后,会调用HeapObject::FromAddress函数,给四字节对齐加上一个kHeapObjectTag,所以在这里计算地址的时候,要减去这个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;

}

还有另外一点,set和get函数对成员变量操作的时候,传入的类型都是指针,需要特别注意,因为每个成员变量都是4字节的,所以他们被get出来,或者被set的时候,都是以指针的形式,当然这并不意味着它的值就一定是一个真实的地址,也可能是一个数值,被强转为指针
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: