v8::StringObject的内存布局

使用该内存布局来查看内存数据,编译器watch中看不到这样的对象

特别需要说明的是length字段,它是一个smi对象,注意不是对象指针,而是对象,该类在objects.h中定义,对于32bit系统,它的最低位必须是0,也就是说它的取值需要右移一位。
例如,在编译js过程中,使用到了source->length(),其中source是Handle,该函数调用如下:
SMI_ACCESSORS(String, length, kLengthOffset) //objects-inl.h
而SMI_ACCESSORS宏定义如下:
#define SMI_ACCESSORS(holder, name, offset)             \
  int holder::name() {                                  \
    Object* value = READ_FIELD(this, offset);           \
    return Smi::cast(value)->value();                   \
  }                                                     \
  void holder::set_##name(int value) {                  \
    WRITE_FIELD(this, offset, Smi::FromInt(value));     \
  }
其中Object* value = READ_FIELD(this, offset);读取的正是上述内存布局中的Length处的4字节内容,
接着调用了Smi::cast(value)->value(),其中Smi::cast(value)的是通过如下的宏定义的:
#define CAST_ACCESSOR(type)                     \
  type* type::cast(Object* object) {            \
    ASSERT(object->Is##type());                 \
    return reinterpret_cast(object);     \
  }
其中object->IsSmi定义如下:
bool Object::IsSmi() {//objects-inl.h
  return HAS_SMI_TAG(this);
}
这里会检查最低位是否为0,以确定是否是Smi
#define HAS_SMI_TAG(value) \
  ((reinterpret_cast(value) & kSmiTagMask) == kSmiTag)
// Tag information for Smi.
const int kSmiTag = 0;
const int kSmiTagSize = 1;
const intptr_t kSmiTagMask = (1 << kSmiTagSize) - 1;
最后调用结束后,得到的Smi对象,会调用它的value函数,就是右移一位取值
int Smi::value() { //objects-inl.h
  return Internals::SmiValue(this);
}

清晰了解StringObject的内存布局之后,我们就可以在调试的时候,通过Handle查看String的值,方法如下:

    取出Handle中的值Location指向的值,即String对象指针。由于该对象指针是一个HeapObject*, 所以需要将其减一得到真正的String对象指针。查看该指针所表示的内存地址,第一个四字节是Map指针,第二个四字节是Hash值,第三个四字节是就 是smi对象,将其右移一位,即除以2就得到String对象的字符串长度length,这之后的length个字节就是字符串的内容

你可能感兴趣的:(V8,Javascript)