Commit b652d79b authored by ager@chromium.org's avatar ager@chromium.org

Shrink dictionaries on deletion if number of elements are less than a

quarter of the capacity.

R=vegorov@chromium.org

Review URL: http://codereview.chromium.org/7190032

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8391 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 4bc671c2
......@@ -493,7 +493,16 @@ MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
cell->set_value(cell->heap()->the_hole_value());
dictionary->DetailsAtPut(entry, details.AsDeleted());
} else {
return dictionary->DeleteProperty(entry, mode);
Object* deleted = dictionary->DeleteProperty(entry, mode);
if (deleted == GetHeap()->true_value()) {
FixedArray* new_properties = NULL;
MaybeObject* maybe_properties = dictionary->Shrink(name);
if (!maybe_properties->To(&new_properties)) {
return maybe_properties;
}
set_properties(new_properties);
}
return deleted;
}
}
return GetHeap()->true_value();
......@@ -2955,7 +2964,16 @@ MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index,
NumberDictionary* dictionary = element_dictionary();
int entry = dictionary->FindEntry(index);
if (entry != NumberDictionary::kNotFound) {
return dictionary->DeleteProperty(entry, mode);
Object* deleted = dictionary->DeleteProperty(entry, mode);
if (deleted == GetHeap()->true_value()) {
MaybeObject* maybe_elements = dictionary->Shrink(index);
FixedArray* new_elements = NULL;
if (!maybe_elements->To(&new_elements)) {
return maybe_elements;
}
set_elements(new_elements);
}
return deleted;
}
break;
}
......@@ -3035,6 +3053,14 @@ MaybeObject* JSObject::DeleteDictionaryElement(uint32_t index,
int entry = dictionary->FindEntry(index);
if (entry != NumberDictionary::kNotFound) {
Object* result = dictionary->DeleteProperty(entry, mode);
if (result == heap->true_value()) {
MaybeObject* maybe_elements = dictionary->Shrink(index);
FixedArray* new_elements = NULL;
if (!maybe_elements->To(&new_elements)) {
return maybe_elements;
}
set_elements(new_elements);
}
if (mode == STRICT_DELETION && result == heap->false_value()) {
// In strict mode, attempting to delete a non-configurable property
// throws an exception.
......@@ -8230,7 +8256,7 @@ MaybeObject* JSObject::SetFastElement(uint32_t index,
if (found) return result;
}
// Check whether there is extra space in fixed array..
// Check whether there is extra space in fixed array.
if (index < length) {
backing_store->set(index, value);
if (IsJSArray()) {
......@@ -9953,6 +9979,40 @@ int StringDictionary::FindEntry(String* key) {
}
template<typename Shape, typename Key>
MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
ASSERT(NumberOfElements() < new_table->Capacity());
AssertNoAllocation no_gc;
WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
// Copy prefix to new array.
for (int i = kPrefixStartIndex;
i < kPrefixStartIndex + Shape::kPrefixSize;
i++) {
new_table->set(i, get(i), mode);
}
// Rehash the elements.
int capacity = Capacity();
for (int i = 0; i < capacity; i++) {
uint32_t from_index = EntryToIndex(i);
Object* k = get(from_index);
if (IsKey(k)) {
uint32_t hash = Shape::HashForObject(key, k);
uint32_t insertion_index =
EntryToIndex(new_table->FindInsertionEntry(hash));
for (int j = 0; j < Shape::kEntrySize; j++) {
new_table->set(insertion_index + j, get(from_index + j), mode);
}
}
}
new_table->SetNumberOfElements(NumberOfElements());
new_table->SetNumberOfDeletedElements(0);
return new_table;
}
template<typename Shape, typename Key>
MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
int capacity = Capacity();
......@@ -9975,32 +10035,36 @@ MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
AssertNoAllocation no_gc;
HashTable* table = HashTable::cast(obj);
WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc);
return Rehash(HashTable::cast(obj), key);
}
// Copy prefix to new array.
for (int i = kPrefixStartIndex;
i < kPrefixStartIndex + Shape::kPrefixSize;
i++) {
table->set(i, get(i), mode);
}
// Rehash the elements.
for (int i = 0; i < capacity; i++) {
uint32_t from_index = EntryToIndex(i);
Object* k = get(from_index);
if (IsKey(k)) {
uint32_t hash = Shape::HashForObject(key, k);
uint32_t insertion_index =
EntryToIndex(table->FindInsertionEntry(hash));
for (int j = 0; j < Shape::kEntrySize; j++) {
table->set(insertion_index + j, get(from_index + j), mode);
}
}
template<typename Shape, typename Key>
MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
int capacity = Capacity();
int nof = NumberOfElements();
// Shrink to fit the number of elements if only a quarter of the
// capacity is filled with elements.
if (nof > (capacity >> 2)) return this;
// Allocate a new dictionary with room for at least the current
// number of elements. The allocation method will make sure that
// there is extra room in the dictionary for additions. Don't go
// lower than room for 16 elements.
int at_least_room_for = nof;
if (at_least_room_for < 16) return this;
const int kMinCapacityForPretenure = 256;
bool pretenure =
(at_least_room_for > kMinCapacityForPretenure) &&
!GetHeap()->InNewSpace(this);
Object* obj;
{ MaybeObject* maybe_obj =
Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
table->SetNumberOfElements(NumberOfElements());
table->SetNumberOfDeletedElements(0);
return table;
return Rehash(HashTable::cast(obj), key);
}
......@@ -10055,6 +10119,12 @@ template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
int, JSObject::DeleteMode);
template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
String*);
template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink(
uint32_t);
template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
FixedArray*);
......@@ -10953,6 +11023,12 @@ Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
}
template<typename Shape, typename Key>
MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
return HashTable<Shape, Key>::Shrink(key);
}
template<typename Shape, typename Key>
MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
int entry = this->FindEntry(key);
......
......@@ -2590,6 +2590,12 @@ class HashTable: public FixedArray {
return (last + number) & (size - 1);
}
// Rehashes this hash-table into the new table.
MUST_USE_RESULT MaybeObject* Rehash(HashTable* new_table, Key key);
// Attempt to shrink hash table after removal of key.
MUST_USE_RESULT MaybeObject* Shrink(Key key);
// Ensure enough space for n additional elements.
MUST_USE_RESULT MaybeObject* EnsureCapacity(int n, Key key);
};
......@@ -2754,6 +2760,9 @@ class Dictionary: public HashTable<Shape, Key> {
// Delete a property from the dictionary.
Object* DeleteProperty(int entry, JSObject::DeleteMode mode);
// Attempt to shrink the dictionary after deletion of key.
MUST_USE_RESULT MaybeObject* Shrink(Key key);
// Returns the number of elements in the dictionary filtering out properties
// with the specified attributes.
int NumberOfElementsFilterAttributes(PropertyAttributes filter);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment