v8源码解析之Array和FixedArray(v8 0.1.5)

v8中很多数据结构都具备数组的特性,今天我们先介绍Array和FixedArray。他们是V8中很多数据结构的基类。

1 Array

我们先看Array的定义。

class Array: public HeapObject {
 public:
  // 数组的长度
  inline int length();
  inline void set_length(int value);
  // 把对象object转成数字,存到index中
  static inline bool IndexFromObject(Object* object, uint32_t* index);
  // 布局信息
  static const int kLengthOffset = HeapObject::kSize;
  static const int kHeaderSize = kLengthOffset + kIntSize;

 private:
  // 禁止直接创建对象,复制函数,赋值函数,通过v8的接口创建
  DISALLOW_IMPLICIT_CONSTRUCTORS(Array);
};

首先我们看一下Array的内存布局。

Array的定义比较简单,我们主要看一下IndexFromObject函数。

// 把对象转数字索引
bool Array::IndexFromObject(Object* object, uint32_t* index) {
  // 是smi类型的对象(31比特)
  if (object->IsSmi()) {
  	// 直接转成整形,存到index
    int value = Smi::cast(object)->value();
    if (value < 0) return false;
    *index = value;
    return true;
  }
  // 是HeapNumber对象
  if (object->IsHeapNumber()) {
    // 转成数字double
    double value = HeapNumber::cast(object)->value();
    // 转成32位
    uint32_t uint_value = static_cast<uint32_t>(value);
    // 判断值是不是小于32位
    if (value == static_cast<double>(uint_value)) {
      *index = uint_value;
      return true;
    }
  }
  return false;
}	

2 FixedArray

FixedArray是长度固定的数组,元素是Object*。我们看一下定义。

class FixedArray: public Array {
 public:
  // 按索引存取数组元素
  inline Object* get(int index);
  inline void set(int index, Object* value);
  // 设置索引index的值
  inline void set_undefined(int index);
  inline void set_the_hole(int index);
  // 写屏障模式
  enum WriteBarrierMode { SKIP_WRITE_BARRIER, UPDATE_WRITE_BARRIER };
  inline void set(int index, Object* value, WriteBarrierMode mode);
  inline WriteBarrierMode GetWriteBarrierMode();
  // 复制元素
  Object* Copy();
  Object* CopySize(int new_length);

  Object* AddKeysFromJSArray(JSArray* array);

  Object* UnionOfKeys(FixedArray* other);

  void CopyTo(int pos, FixedArray* dest, int dest_pos, int len);

  /*
	  FixedArray继承Array,kHeaderSize是Array属性的末地址,加上元素个数*单个元素长度(Object *)
  */
  static int SizeFor(int length) { return kHeaderSize + length * kPointerSize; }

  static inline FixedArray* cast(Object* obj);
  // 算出自己所占的内存大小
  int FixedArraySize() { return SizeFor(length()); }
  void FixedArrayIterateBody(ObjectVisitor* v);
  
  // Swap two elements.
  void Swap(int i, int j);

  // Sort this array and the smis as pairs wrt. the smis.
  void SortPairs(FixedArray* smis);

 protected:
  static inline void fast_set(FixedArray* array, int index, Object* value);

 private:
  DISALLOW_IMPLICIT_CONSTRUCTORS(FixedArray);
};

我们看一下FixedArray内存布局。

FixedArray的内存布局由数组长度和存储数组元素的内存组成。接下来我们逐个看一下各个函数的实现。

2.1 get

Object* FixedArray::get(int index) {
  ASSERT(index >= 0 && index < this->length());
  return READ_FIELD(this, kHeaderSize + index * kPointerSize);
}

偏移为kHeaderSize处开始存储数据,每个元素大小的kPointerSize。

2.2 set

void FixedArray::set(int index, Object* value) {
  ASSERT(index >= 0 && index < this->length());
  int offset = kHeaderSize + index * kPointerSize;
  WRITE_FIELD(this, offset, value);
  // 写屏障
  WRITE_BARRIER(this, offset);
}

2.3 set_undefined

设置某个索引的值为undefined

void FixedArray::set_undefined(int index) {
  ASSERT(index >= 0 && index < this->length());
  ASSERT(!Heap::InNewSpace(Heap::undefined_value()));
  WRITE_FIELD(this, kHeaderSize + index * kPointerSize,
              Heap::undefined_value());
}

2.4 set_the_hole

设置某个索引的值为空

void FixedArray::set_the_hole(int index) {
  ASSERT(index >= 0 && index < this->length());
  ASSERT(!Heap::InNewSpace(Heap::the_hole_value()));
  WRITE_FIELD(this, kHeaderSize + index * kPointerSize, Heap::the_hole_value());
}

2.5 Copy

Copy函数实现数组的浅复制。

Object* FixedArray::Copy() {
  int len = length();
  // 没有内容则不需要复制
  if (len == 0) return this;
  // 首先分配一个数组长度为len的固定数组
  Object* obj = Heap::AllocateFixedArray(len);
  if (obj->IsFailure()) return obj;
  // 转成FixedArray
  FixedArray* result = FixedArray::cast(obj);
  WriteBarrierMode mode = result->GetWriteBarrierMode();
  // 逐个元素复制内容过去
  for (int i = 0; i < len; i++) {
    result->set(i, get(i), mode);
  }
  // 设置map
  result->set_map(map());
  return result;
}

2.6 CopySize

CopySize是复制数组的前new_length个元素到新数组,如果new_length比本来的数组长度length大,则只复制length个元素。

Object* FixedArray::CopySize(int new_length) {
  if (new_length == 0) return Heap::empty_fixed_array();
  // 分配一个新的数组
  Object* obj = Heap::AllocateFixedArray(new_length);
  if (obj->IsFailure()) return obj;
  FixedArray* result = FixedArray::cast(obj);
  WriteBarrierMode mode = result->GetWriteBarrierMode();
  // Copy the content
  int len = length();
  // 取小者
  if (new_length < len) len = new_length;
  for (int i = 0; i < len; i++) {
    result->set(i, get(i), mode);
  }
  result->set_map(map());
  return result;
}

2.7 AddKeysFromJSArray

AddKeysFromJSArray首先提取数组的有效元素,然后复制到另一个数组中,再执行合并和去重。

Object* FixedArray::AddKeysFromJSArray(JSArray* array) {
  // 把数组中空洞元素移除,相当于shrink
  Object* object = array->RemoveHoles();
  if (object->IsFailure()) return object;
  // 拿到有效元素
  JSArray* compacted_array = JSArray::cast(object);
  // 数组长度
  int compacted_array_length = Smi::cast(compacted_array->length())->value();
  // 分配一个新的数组
  object = Heap::AllocateFixedArray(compacted_array_length);
  if (object->IsFailure()) return object;
  FixedArray* key_array = FixedArray::cast(object);
  // 逐个复制过去
  for (int i = 0; i < compacted_array_length; i++) {
    key_array->set(i, compacted_array->GetElement(i));
  }
  // 去重合成新数组返回
  return UnionOfKeys(key_array);
}

2.8 UnionOfKeys

UnionOfKeys实现两个数组的合并和去重

// 把this和other去重后合成一个数组
Object* FixedArray::UnionOfKeys(FixedArray* other) {
  int len0 = length();
  int len1 = other->length();
  // Optimize if either is empty.
  if (len0 == 0) return other;
  if (len1 == 0) return this;

  // Compute how many elements are not in this.
  int extra = 0;
  // 遍历other,算出多少个元素不在this中
  for (int y = 0; y < len1; y++) {
    if (!HasKey(this, other->get(y))) extra++;
  }

  // Allocate the result
  // 分配新的数组
  Object* obj = Heap::AllocateFixedArray(len0 + extra);
  if (obj->IsFailure()) return obj;
  // Fill in the content
  FixedArray* result = FixedArray::cast(obj);
  // 把之前的元素先复制过去
  for (int i = 0; i < len0; i++) {
    result->set(i, get(i));
  }
  // Fill in the extra keys.
  // 把新成员也复制过去
  int index = 0;
  for (int y = 0; y < len1; y++) {
    if (!HasKey(this, other->get(y))) {
      result->set(len0 + index, other->get(y));
      index++;
    }
  }
  ASSERT(extra == index);
  return result;
}

2.9 CopyTo

CopyTo实现把一个数组的某len个元素复制到另一个数组中。

// pos和dest_pos是两个数组开始复制的位置,len是长度
void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
  WriteBarrierMode mode = dest->GetWriteBarrierMode();
  for (int index = 0; index < len; index++) {
    dest->set(dest_pos+index, get(pos+index), mode);
  }
}

2.10 Swap

Swap实现两个元素的交换

void FixedArray::Swap(int i, int j) {
  Object* temp = get(i);
  set(i, get(j));
  set(j, temp);
}

2.11 fast_set

设置某个元素的值

void FixedArray::fast_set(FixedArray* array, int index, Object* value) {
  ASSERT(index >= 0 && index < array->length());
  WRITE_FIELD(array, kHeaderSize + index * kPointerSize, value);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值