Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(597)

Unified Diff: src/elements.cc

Issue 2041963003: [elements] Precisely estimate elements size for large-object limits (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/elements.h ('k') | src/lookup.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/elements.cc
diff --git a/src/elements.cc b/src/elements.cc
index 02f79c60a1d07861c5b3d964d6f390a626893bc4..e8f2c79f851dbafe471fa345b6a2dc083f2e44fd 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -523,8 +523,10 @@ class ElementsAccessorBase : public ElementsAccessor {
Handle<FixedArrayBase> backing_store, uint32_t start,
uint32_t end) {
if (IsFastPackedElementsKind(kind())) return true;
+ Isolate* isolate = backing_store->GetIsolate();
for (uint32_t i = start; i < end; i++) {
- if (!Subclass::HasElementImpl(holder, i, backing_store, ALL_PROPERTIES)) {
+ if (!Subclass::HasElementImpl(isolate, holder, i, backing_store,
+ ALL_PROPERTIES)) {
return false;
}
}
@@ -551,14 +553,16 @@ class ElementsAccessorBase : public ElementsAccessor {
bool HasElement(Handle<JSObject> holder, uint32_t index,
Handle<FixedArrayBase> backing_store,
PropertyFilter filter) final {
- return Subclass::HasElementImpl(holder, index, backing_store, filter);
+ return Subclass::HasElementImpl(holder->GetIsolate(), holder, index,
+ backing_store, filter);
}
- static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
+ static bool HasElementImpl(Isolate* isolate, Handle<JSObject> holder,
+ uint32_t index,
Handle<FixedArrayBase> backing_store,
PropertyFilter filter) {
- return Subclass::GetEntryForIndexImpl(*holder, *backing_store, index,
- filter) != kMaxUInt32;
+ return Subclass::GetEntryForIndexImpl(isolate, *holder, *backing_store,
+ index, filter) != kMaxUInt32;
}
bool HasAccessors(JSObject* holder) final {
@@ -729,6 +733,15 @@ class ElementsAccessorBase : public ElementsAccessor {
JSObject::ValidateElements(array);
}
+ uint32_t NumberOfElements(JSObject* receiver) final {
+ return Subclass::NumberOfElementsImpl(receiver, receiver->elements());
+ }
+
+ static uint32_t NumberOfElementsImpl(JSObject* receiver,
+ FixedArrayBase* backing_store) {
+ UNREACHABLE();
+ }
+
static uint32_t GetMaxIndex(JSObject* receiver, FixedArrayBase* elements) {
if (receiver->IsJSArray()) {
DCHECK(JSArray::cast(receiver)->length()->IsSmi());
@@ -899,7 +912,7 @@ class ElementsAccessorBase : public ElementsAccessor {
if (!key->ToUint32(&index)) continue;
uint32_t entry = Subclass::GetEntryForIndexImpl(
- *object, object->elements(), index, filter);
+ isolate, *object, object->elements(), index, filter);
if (entry == kMaxUInt32) continue;
PropertyDetails details = Subclass::GetDetailsImpl(*object, entry);
@@ -935,9 +948,10 @@ class ElementsAccessorBase : public ElementsAccessor {
// Non-dictionary elements can't have all-can-read accessors.
uint32_t length = Subclass::GetMaxIndex(*object, *backing_store);
PropertyFilter filter = keys->filter();
- Factory* factory = keys->isolate()->factory();
+ Isolate* isolate = keys->isolate();
+ Factory* factory = isolate->factory();
for (uint32_t i = 0; i < length; i++) {
- if (Subclass::HasElementImpl(object, i, backing_store, filter)) {
+ if (Subclass::HasElementImpl(isolate, object, i, backing_store, filter)) {
keys->AddKey(factory->NewNumberFromUint(i));
}
}
@@ -950,7 +964,7 @@ class ElementsAccessorBase : public ElementsAccessor {
uint32_t insertion_index = 0) {
uint32_t length = Subclass::GetMaxIndex(*object, *backing_store);
for (uint32_t i = 0; i < length; i++) {
- if (Subclass::HasElementImpl(object, i, backing_store, filter)) {
+ if (Subclass::HasElementImpl(isolate, object, i, backing_store, filter)) {
if (convert == GetKeysConversion::kConvertToString) {
Handle<String> index_string = isolate->factory()->Uint32ToString(i);
list->set(insertion_index, *index_string);
@@ -973,6 +987,20 @@ class ElementsAccessorBase : public ElementsAccessor {
convert, filter);
}
+ static uint32_t EstimatePrependElementSize(JSObject* object,
+ FixedArrayBase* backing_store,
+ uint32_t length) {
+ if (kind() == FAST_HOLEY_ELEMENTS) {
Igor Sheludko 2016/06/07 14:50:01 FAST_HOLEY_DOUBLE_ELEMENTS ?
+ if (FixedDoubleArray::SizeFor(length) <=
+ Page::kMaxRegularHeapObjectSize) {
+ return length;
+ }
+ } else if (FixedArray::SizeFor(length) <= Page::kMaxRegularHeapObjectSize) {
+ return length;
+ }
+ return Subclass::NumberOfElementsImpl(object, backing_store);
+ }
+
static Handle<FixedArray> PrependElementIndicesImpl(
Handle<JSObject> object, Handle<FixedArrayBase> backing_store,
Handle<FixedArray> keys, GetKeysConversion convert,
@@ -980,9 +1008,17 @@ class ElementsAccessorBase : public ElementsAccessor {
Isolate* isolate = object->GetIsolate();
uint32_t nof_property_keys = keys->length();
uint32_t initial_list_length =
- Subclass::GetCapacityImpl(*object, *backing_store);
+ Subclass::GetMaxNumberOfEntries(*object, *backing_store);
Igor Sheludko 2016/06/07 14:50:01 It does not have to be called for holey kinds. May
initial_list_length += nof_property_keys;
+ if (IsHoleyElementsKind(kind())) {
+ // If we overestimate the result list size we might end up in old space
Michael Lippautz 2016/06/07 17:28:27 s/old space/large object space/
+ // which doesn't free memory on shrinking the list. Hence we try to
+ // estimate the final size for holey backing stores more precisely here.
+ initial_list_length = EstimatePrependElementSize(*object, *backing_store,
+ initial_list_length);
+ }
+
// Collect the element indices into a new list.
uint32_t nof_indices = 0;
Handle<FixedArray> combined_keys =
@@ -1049,12 +1085,13 @@ class ElementsAccessorBase : public ElementsAccessor {
return entry;
}
- static uint32_t GetEntryForIndexImpl(JSObject* holder,
+ static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
FixedArrayBase* backing_store,
uint32_t index, PropertyFilter filter) {
if (IsHoleyElementsKind(kind())) {
return index < Subclass::GetCapacityImpl(holder, backing_store) &&
- !BackingStore::cast(backing_store)->is_the_hole(index)
+ !BackingStore::cast(backing_store)
+ ->is_the_hole(isolate, index)
? index
: kMaxUInt32;
} else {
@@ -1063,9 +1100,10 @@ class ElementsAccessorBase : public ElementsAccessor {
}
}
- uint32_t GetEntryForIndex(JSObject* holder, FixedArrayBase* backing_store,
+ uint32_t GetEntryForIndex(Isolate* isolate, JSObject* holder,
+ FixedArrayBase* backing_store,
uint32_t index) final {
- return Subclass::GetEntryForIndexImpl(holder, backing_store, index,
+ return Subclass::GetEntryForIndexImpl(isolate, holder, backing_store, index,
ALL_PROPERTIES);
}
@@ -1106,6 +1144,11 @@ class DictionaryElementsAccessor
return dict->NumberOfElements();
}
+ static uint32_t NumberOfElementsImpl(JSObject* receiver,
+ FixedArrayBase* backing_store) {
+ return GetMaxNumberOfEntries(receiver, backing_store);
+ }
+
static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
uint32_t length,
Handle<FixedArrayBase> backing_store) {
@@ -1252,11 +1295,12 @@ class DictionaryElementsAccessor
object->set_elements(*new_dictionary);
}
- static bool HasEntryImpl(FixedArrayBase* store, uint32_t entry) {
+ static bool HasEntryImpl(Isolate* isolate, FixedArrayBase* store,
+ uint32_t entry) {
DisallowHeapAllocation no_gc;
SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
Object* index = dict->KeyAt(entry);
- return !index->IsTheHole(dict->GetIsolate());
+ return !index->IsTheHole(isolate);
}
static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) {
@@ -1267,11 +1311,12 @@ class DictionaryElementsAccessor
return result;
}
- static uint32_t GetEntryForIndexImpl(JSObject* holder, FixedArrayBase* store,
- uint32_t index, PropertyFilter filter) {
+ static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
+ FixedArrayBase* store, uint32_t index,
+ PropertyFilter filter) {
DisallowHeapAllocation no_gc;
SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
- int entry = dictionary->FindEntry(index);
+ int entry = dictionary->FindEntry(isolate, index);
if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
if (filter != ALL_PROPERTIES) {
PropertyDetails details = dictionary->DetailsAt(entry);
@@ -1380,8 +1425,8 @@ class DictionaryElementsAccessor
Isolate* isolate = accumulator->isolate();
Handle<Object> undefined = isolate->factory()->undefined_value();
Handle<Object> the_hole = isolate->factory()->the_hole_value();
- SeededNumberDictionary* dictionary =
- SeededNumberDictionary::cast(receiver->elements());
+ Handle<SeededNumberDictionary> dictionary(
+ SeededNumberDictionary::cast(receiver->elements()), isolate);
int capacity = dictionary->Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = dictionary->KeyAt(i);
@@ -1427,7 +1472,7 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
int j = 0;
for (int i = 0; j < capacity; i++) {
if (IsHoleyElementsKind(kind)) {
- if (BackingStore::cast(*store)->is_the_hole(i)) continue;
+ if (BackingStore::cast(*store)->is_the_hole(isolate, i)) continue;
}
Handle<Object> value = Subclass::GetImpl(*store, i);
dictionary = SeededNumberDictionary::AddNumberEntry(
@@ -1440,12 +1485,12 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
static void DeleteAtEnd(Handle<JSObject> obj,
Handle<BackingStore> backing_store, uint32_t entry) {
uint32_t length = static_cast<uint32_t>(backing_store->length());
- Heap* heap = obj->GetHeap();
+ Isolate* isolate = obj->GetIsolate();
for (; entry > 0; entry--) {
- if (!backing_store->is_the_hole(entry - 1)) break;
+ if (!backing_store->is_the_hole(isolate, entry - 1)) break;
}
if (entry == 0) {
- FixedArray* empty = heap->empty_fixed_array();
+ FixedArray* empty = isolate->heap()->empty_fixed_array();
// Dynamically ask for the elements kind here since we manually redirect
// the operations for argument backing stores.
if (obj->GetElementsKind() == FAST_SLOPPY_ARGUMENTS_ELEMENTS) {
@@ -1456,8 +1501,8 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
return;
}
- heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*backing_store,
- length - entry);
+ isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
+ *backing_store, length - entry);
}
static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
@@ -1472,6 +1517,7 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
return;
}
+ Isolate* isolate = obj->GetIsolate();
backing_store->set_the_hole(entry);
// TODO(verwaest): Move this out of elements.cc.
@@ -1488,12 +1534,13 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
} else {
length = static_cast<uint32_t>(store->length());
}
- if ((entry > 0 && backing_store->is_the_hole(entry - 1)) ||
- (entry + 1 < length && backing_store->is_the_hole(entry + 1))) {
+ if ((entry > 0 && backing_store->is_the_hole(isolate, entry - 1)) ||
+ (entry + 1 < length &&
+ backing_store->is_the_hole(isolate, entry + 1))) {
if (!obj->IsJSArray()) {
uint32_t i;
for (i = entry + 1; i < length; i++) {
- if (!backing_store->is_the_hole(i)) break;
+ if (!backing_store->is_the_hole(isolate, i)) break;
}
if (i == length) {
DeleteAtEnd(obj, backing_store, entry);
@@ -1502,7 +1549,7 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
}
int num_used = 0;
for (int i = 0; i < backing_store->length(); ++i) {
- if (!backing_store->is_the_hole(i)) {
+ if (!backing_store->is_the_hole(isolate, i)) {
++num_used;
// Bail out if a number dictionary wouldn't be able to save at least
// 75% space.
@@ -1563,19 +1610,32 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
DeleteCommon(obj, entry, handle(obj->elements()));
}
- static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
- return !BackingStore::cast(backing_store)->is_the_hole(entry);
+ static bool HasEntryImpl(Isolate* isolate, FixedArrayBase* backing_store,
+ uint32_t entry) {
+ return !BackingStore::cast(backing_store)->is_the_hole(isolate, entry);
+ }
+
+ static uint32_t NumberOfElementsImpl(JSObject* receiver,
+ FixedArrayBase* backing_store) {
+ uint32_t max_index = Subclass::GetMaxIndex(receiver, backing_store);
+ if (IsFastPackedElementsKind(Subclass::kind())) return max_index;
+ Isolate* isolate = receiver->GetIsolate();
+ uint32_t count = 0;
+ for (uint32_t i = 0; i < max_index; i++) {
+ if (Subclass::HasEntryImpl(isolate, backing_store, i)) count++;
+ }
+ return count;
}
static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
KeyAccumulator* accumulator,
AddKeyConversion convert) {
- Handle<FixedArrayBase> elements(receiver->elements(),
- accumulator->isolate());
+ Isolate* isolate = accumulator->isolate();
+ Handle<FixedArrayBase> elements(receiver->elements(), isolate);
uint32_t length = Subclass::GetMaxNumberOfEntries(*receiver, *elements);
for (uint32_t i = 0; i < length; i++) {
if (IsFastPackedElementsKind(KindTraits::Kind) ||
- HasEntryImpl(*elements, i)) {
+ HasEntryImpl(isolate, *elements, i)) {
accumulator->AddKey(Subclass::GetImpl(*elements, i), convert);
}
}
@@ -1604,12 +1664,12 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
for (int i = 0; i < length; i++) {
DCHECK(BackingStore::get(*backing_store, i, isolate)->IsSmi() ||
(IsFastHoleyElementsKind(KindTraits::Kind) &&
- backing_store->is_the_hole(i)));
+ backing_store->is_the_hole(isolate, i)));
}
} else if (KindTraits::Kind == FAST_ELEMENTS ||
KindTraits::Kind == FAST_DOUBLE_ELEMENTS) {
for (int i = 0; i < length; i++) {
- DCHECK(!backing_store->is_the_hole(i));
+ DCHECK(!backing_store->is_the_hole(isolate, i));
}
} else {
DCHECK(IsFastHoleyElementsKind(KindTraits::Kind));
@@ -1711,11 +1771,13 @@ class FastElementsAccessor : public ElementsAccessorBase<Subclass, KindTraits> {
Isolate* isolate, Handle<JSObject> object,
Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items,
PropertyFilter filter) {
+ Handle<BackingStore> elements(BackingStore::cast(object->elements()),
+ isolate);
int count = 0;
- uint32_t length = object->elements()->length();
+ uint32_t length = elements->length();
for (uint32_t index = 0; index < length; ++index) {
- if (!HasEntryImpl(object->elements(), index)) continue;
- Handle<Object> value = Subclass::GetImpl(object->elements(), index);
+ if (!HasEntryImpl(isolate, *elements, index)) continue;
+ Handle<Object> value = Subclass::GetImpl(*elements, index);
if (get_entries) {
value = MakeEntryPair(isolate, index, value);
}
@@ -1905,7 +1967,6 @@ class FastSmiOrObjectElementsAccessor
return backing_store->get(index);
}
-
// NOTE: this method violates the handlified function signature convention:
// raw pointer parameters in the function that allocates.
// See ElementsAccessor::CopyElements() for details.
@@ -2144,7 +2205,8 @@ class TypedElementsAccessor
return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
}
- static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
+ static bool HasElementImpl(Isolate* isolate, Handle<JSObject> holder,
+ uint32_t index,
Handle<FixedArrayBase> backing_store,
PropertyFilter filter) {
return index < AccessorClass::GetCapacityImpl(*holder, *backing_store);
@@ -2171,7 +2233,7 @@ class TypedElementsAccessor
return entry;
}
- static uint32_t GetEntryForIndexImpl(JSObject* holder,
+ static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
FixedArrayBase* backing_store,
uint32_t index, PropertyFilter filter) {
return index < AccessorClass::GetCapacityImpl(holder, backing_store)
@@ -2186,6 +2248,11 @@ class TypedElementsAccessor
return backing_store->length();
}
+ static uint32_t NumberOfElementsImpl(JSObject* receiver,
+ FixedArrayBase* backing_store) {
+ return AccessorClass::GetCapacityImpl(receiver, backing_store);
+ }
+
static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
KeyAccumulator* accumulator,
AddKeyConversion convert) {
@@ -2321,25 +2388,26 @@ class SloppyArgumentsElementsAccessor
static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver,
KeyAccumulator* accumulator,
AddKeyConversion convert) {
- FixedArrayBase* elements = receiver->elements();
- uint32_t length = GetCapacityImpl(*receiver, elements);
+ Isolate* isolate = accumulator->isolate();
+ Handle<FixedArrayBase> elements(receiver->elements(), isolate);
+ uint32_t length = GetCapacityImpl(*receiver, *elements);
for (uint32_t entry = 0; entry < length; entry++) {
- if (!HasEntryImpl(elements, entry)) continue;
- Handle<Object> value = GetImpl(elements, entry);
+ if (!HasEntryImpl(isolate, *elements, entry)) continue;
+ Handle<Object> value = GetImpl(*elements, entry);
accumulator->AddKey(value, convert);
}
}
- static bool HasEntryImpl(FixedArrayBase* parameters, uint32_t entry) {
+ static bool HasEntryImpl(Isolate* isolate, FixedArrayBase* parameters,
+ uint32_t entry) {
FixedArray* parameter_map = FixedArray::cast(parameters);
uint32_t length = parameter_map->length() - 2;
if (entry < length) {
- return !GetParameterMapArg(parameter_map, entry)
- ->IsTheHole(parameter_map->GetIsolate());
+ return !GetParameterMapArg(parameter_map, entry)->IsTheHole(isolate);
}
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
- return ArgumentsAccessor::HasEntryImpl(arguments, entry - length);
+ return ArgumentsAccessor::HasEntryImpl(isolate, arguments, entry - length);
}
static bool HasAccessorsImpl(JSObject* holder,
@@ -2359,16 +2427,16 @@ class SloppyArgumentsElementsAccessor
return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
}
- static uint32_t GetEntryForIndexImpl(JSObject* holder,
+ static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
FixedArrayBase* parameters,
uint32_t index, PropertyFilter filter) {
FixedArray* parameter_map = FixedArray::cast(parameters);
Object* probe = GetParameterMapArg(parameter_map, index);
- if (!probe->IsTheHole(holder->GetIsolate())) return index;
+ if (!probe->IsTheHole(isolate)) return index;
FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
- uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(holder, arguments,
- index, filter);
+ uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(
+ isolate, holder, arguments, index, filter);
if (entry == kMaxUInt32) return kMaxUInt32;
return (parameter_map->length() - 2) + entry;
}
@@ -2561,9 +2629,9 @@ class FastSloppyArgumentsElementsAccessor
FixedArray* parameters = FixedArray::cast(receiver->elements());
uint32_t insertion_index = 0;
for (uint32_t i = start; i < end; i++) {
- uint32_t entry =
- GetEntryForIndexImpl(*receiver, parameters, i, ALL_PROPERTIES);
- if (entry != kMaxUInt32 && HasEntryImpl(parameters, entry)) {
+ uint32_t entry = GetEntryForIndexImpl(isolate, *receiver, parameters, i,
+ ALL_PROPERTIES);
+ if (entry != kMaxUInt32 && HasEntryImpl(isolate, parameters, entry)) {
elements->set(insertion_index, *GetImpl(parameters, entry));
} else {
elements->set_the_hole(insertion_index);
@@ -2686,13 +2754,13 @@ class StringWrapperElementsAccessor
return BackingStoreAccessor::GetDetailsImpl(holder, entry - length);
}
- static uint32_t GetEntryForIndexImpl(JSObject* holder,
+ static uint32_t GetEntryForIndexImpl(Isolate* isolate, JSObject* holder,
FixedArrayBase* backing_store,
uint32_t index, PropertyFilter filter) {
uint32_t length = static_cast<uint32_t>(GetString(holder)->length());
if (index < length) return index;
uint32_t backing_store_entry = BackingStoreAccessor::GetEntryForIndexImpl(
- holder, backing_store, index, filter);
+ isolate, holder, backing_store, index, filter);
if (backing_store_entry == kMaxUInt32) return kMaxUInt32;
DCHECK(backing_store_entry < kMaxUInt32 - length);
return backing_store_entry + length;
« no previous file with comments | « src/elements.h ('k') | src/lookup.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698