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);
}