v8::StringObject的內存佈局

使用該內存佈局來查看內存數據,編譯器watch中看不到這樣的對象

特別需要說明的是length字段,它是一個smi對象,注意不是對象指針,而是對象,該類在objects.h中定義,對於32bit系統,它的最低位必須是0,也就是說它的取值需要右移一位。
例如,在編譯js過程中,使用到了source->length(),其中source是Handle<String>,該函數調用如下:
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<type*>(object);     \
  }
其中object->IsSmi定義如下:
bool Object::IsSmi() {//objects-inl.h
  return HAS_SMI_TAG(this);
}
這裏會檢查最低位是否爲0,以確定是否是Smi
#define HAS_SMI_TAG(value) \
  ((reinterpret_cast<intptr_t>(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>查看String的值,方法如下:

    取出Handle<String>中的值Location指向的值,即String對象指針。由於該對象指針是一個HeapObject*, 所以需要將其減一得到真正的String對象指針。查看該指針所表示的內存地址,第一個四字節是Map指針,第二個四字節是Hash值,第三個四字節是就 是smi對象,將其右移一位,即除以2就得到String對象的字符串長度length,這之後的length個字節就是字符串的內容

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章