| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 6c9f52b2df89839306e30b8f925f87412fc111f4..8bb924343f8ab2a2393ec45aa703ed8d89f1af7b 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -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()) {
|
| @@ -9954,6 +9980,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();
|
| int nof = NumberOfElements() + n;
|
| @@ -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*);
|
|
|
| @@ -10954,6 +11024,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);
|
|
|
|
|