// The JSArray describes JavaScript Arrays // Such an array can be in one of two modes: // - fast, backing storage is a FixedArray and length <= elements.length(); // Please note: push and pop can be used to grow and shrink the array. // - slow, backing storage is a HashTable with numbers as keys. classJSArray:public JSObject { public: // [length]: The length property. DECL_ACCESSORS(length, Object)
// ...
// Number of element slots to pre-allocate for an empty array. staticconstint kPreallocatedArrayElements = 4; };
// src/objects/dictionary.h // JSObjects prefer dictionary elements if the dictionary saves this much // memory compared to a fast elements backing store. staticconstuint32_t kPreferFastElementsSizeFactor = 3;
// src/objects/js-objects-inl.h // If the fast-case backing storage takes up much more memory than a dictionary // backing storage would, the object should have slow elements. // static staticinlineboolShouldConvertToSlowElements(uint32_t used_elements, uint32_t new_capacity){ uint32_t size_threshold = NumberDictionary::kPreferFastElementsSizeFactor * NumberDictionary::ComputeCapacity(used_elements) * NumberDictionary::kEntrySize; // 快数组新容量是扩容后的容量3倍之多时,也会被转成慢数组 return size_threshold <= new_capacity; }
staticinlineboolShouldConvertToSlowElements(JSObject object, uint32_t capacity, uint32_t index, uint32_t* new_capacity){ STATIC_ASSERT(JSObject::kMaxUncheckedOldFastElementsLength <= JSObject::kMaxUncheckedFastElementsLength); if (index < capacity) { *new_capacity = capacity; returnfalse; } // 当加入的索引值(例如例3中的2000)比当前容量capacity 大于等于 1024时, // 返回true,转为慢数组 if (index - capacity >= JSObject::kMaxGap) returntrue; *new_capacity = JSObject::NewElementsCapacity(index + 1); DCHECK_LT(index, *new_capacity); // TODO(ulan): Check if it works with young large objects. if (*new_capacity <= JSObject::kMaxUncheckedOldFastElementsLength || (*new_capacity <= JSObject::kMaxUncheckedFastElementsLength && ObjectInYoungGeneration(object))) { returnfalse; } return ShouldConvertToSlowElements(object.GetFastElementsUsage(), *new_capacity); }
staticboolShouldConvertToFastElements(JSObject object, NumberDictionary dictionary, uint32_t index, uint32_t* new_capacity){ // If properties with non-standard attributes or accessors were added, we // cannot go back to fast elements. if (dictionary.requires_slow_elements()) returnfalse; // Adding a property with this index will require slow elements. if (index >= static_cast<uint32_t>(Smi::kMaxValue)) returnfalse; if (object.IsJSArray()) { Object length = JSArray::cast(object).length(); if (!length.IsSmi()) returnfalse; *new_capacity = static_cast<uint32_t>(Smi::ToInt(length)); } elseif (object.IsJSArgumentsObject()) { returnfalse; } else { *new_capacity = dictionary.max_number_key() + 1; } *new_capacity = Max(index + 1, *new_capacity); uint32_t dictionary_size = static_cast<uint32_t>(dictionary.Capacity()) * NumberDictionary::kEntrySize; // Turn fast if the dictionary only saves 50% space. return2 * dictionary_size >= *new_capacity; }
if (2 * length <= capacity) { // If more than half the elements won't be used, trim the array. isolate->heap()->RightTrimFixedArray(*backing_store, capacity - length); } else { // Otherwise, fill the unused tail with holes. BackingStore::cast(*backing_store)->FillWithHoles(length, old_length); }