From 70c3a714a134ba989fc9e28f8944df3ead95cc02 Mon Sep 17 00:00:00 2001 From: "adamk@chromium.org" Date: Tue, 20 May 2014 14:22:05 +0000 Subject: [PATCH] ES6 Map/Set iterators/forEach improvements This changes how Map/Set interacts with its iterators. When the underlying table is rehashed or cleared, we create a new table (like before) but we add a reference from the old table to the new table. We also add an array describing how to transition the iterator from the old table to the new table. When Next is called on the iterator it checks if there is a newer table that it should transition to. If there is, it updates the index based on the previously recorded changes and finally changes itself to point at the new table. With these changes Map/Set no longer keeps the iterators alive. Also, as before, the iterators keep the underlying table(s) alive but not the actual Map/Set. BUG=v8:1793 LOG=Y R=mstarzinger@chromium.org, rossberg@chromium.org Review URL: https://codereview.chromium.org/289503002 Patch from Erik Arvidsson . git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21389 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/collection.js | 16 +- src/objects-debug.cc | 12 -- src/objects-inl.h | 5 - src/objects-printer.cc | 6 - src/objects.cc | 216 ++++++++++----------------- src/objects.h | 123 +++++++-------- src/runtime.cc | 18 --- src/runtime.h | 2 - test/mjsunit/harmony/collections.js | 135 +++++++++++++++++ test/mjsunit/runtime-gen/mapiteratorclose.js | 5 - test/mjsunit/runtime-gen/setiteratorclose.js | 5 - tools/generate-runtime-tests.py | 4 +- 12 files changed, 280 insertions(+), 267 deletions(-) delete mode 100644 test/mjsunit/runtime-gen/mapiteratorclose.js delete mode 100644 test/mjsunit/runtime-gen/setiteratorclose.js diff --git a/src/collection.js b/src/collection.js index b201d57..fefc7a0 100644 --- a/src/collection.js +++ b/src/collection.js @@ -106,12 +106,8 @@ function SetForEach(f, receiver) { var iterator = %SetCreateIterator(this, ITERATOR_KIND_VALUES); var entry; - try { - while (!(entry = %SetIteratorNext(iterator)).done) { - %_CallFunction(receiver, entry.value, entry.value, this, f); - } - } finally { - %SetIteratorClose(iterator); + while (!(entry = %SetIteratorNext(iterator)).done) { + %_CallFunction(receiver, entry.value, entry.value, this, f); } } @@ -219,12 +215,8 @@ function MapForEach(f, receiver) { var iterator = %MapCreateIterator(this, ITERATOR_KIND_ENTRIES); var entry; - try { - while (!(entry = %MapIteratorNext(iterator)).done) { - %_CallFunction(receiver, entry.value[1], entry.value[0], this, f); - } - } finally { - %MapIteratorClose(iterator); + while (!(entry = %MapIteratorNext(iterator)).done) { + %_CallFunction(receiver, entry.value[1], entry.value[0], this, f); } } diff --git a/src/objects-debug.cc b/src/objects-debug.cc index b72988d..6c0daac 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -702,13 +702,7 @@ void JSSetIterator::JSSetIteratorVerify() { VerifyHeapPointer(table()); CHECK(table()->IsOrderedHashTable() || table()->IsUndefined()); CHECK(index()->IsSmi()); - CHECK(count()->IsSmi()); CHECK(kind()->IsSmi()); - VerifyHeapPointer(next_iterator()); - CHECK(next_iterator()->IsJSSetIterator() || next_iterator()->IsUndefined()); - VerifyHeapPointer(table()); - CHECK(previous_iterator()->IsJSSetIterator() - || previous_iterator()->IsUndefined()); } @@ -718,13 +712,7 @@ void JSMapIterator::JSMapIteratorVerify() { VerifyHeapPointer(table()); CHECK(table()->IsOrderedHashTable() || table()->IsUndefined()); CHECK(index()->IsSmi()); - CHECK(count()->IsSmi()); CHECK(kind()->IsSmi()); - VerifyHeapPointer(next_iterator()); - CHECK(next_iterator()->IsJSMapIterator() || next_iterator()->IsUndefined()); - VerifyHeapPointer(table()); - CHECK(previous_iterator()->IsJSMapIterator() - || previous_iterator()->IsUndefined()); } diff --git a/src/objects-inl.h b/src/objects-inl.h index 0e0c808..dca3eca 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -5683,12 +5683,7 @@ ACCESSORS(JSMap, table, Object, kTableOffset) ORDERED_HASH_TABLE_ITERATOR_ACCESSORS(table, Object, kTableOffset) ORDERED_HASH_TABLE_ITERATOR_ACCESSORS(index, Smi, kIndexOffset) -ORDERED_HASH_TABLE_ITERATOR_ACCESSORS(count, Smi, kCountOffset) ORDERED_HASH_TABLE_ITERATOR_ACCESSORS(kind, Smi, kKindOffset) -ORDERED_HASH_TABLE_ITERATOR_ACCESSORS(next_iterator, Object, - kNextIteratorOffset) -ORDERED_HASH_TABLE_ITERATOR_ACCESSORS(previous_iterator, Object, - kPreviousIteratorOffset) #undef ORDERED_HASH_TABLE_ITERATOR_ACCESSORS diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 4fb5b56..e7c4f95 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -743,14 +743,8 @@ void OrderedHashTableIterator:: table()->ShortPrint(out); PrintF(out, "\n - index = "); index()->ShortPrint(out); - PrintF(out, "\n - count = "); - count()->ShortPrint(out); PrintF(out, "\n - kind = "); kind()->ShortPrint(out); - PrintF(out, "\n - next_iterator = "); - next_iterator()->ShortPrint(out); - PrintF(out, "\n - previous_iterator = "); - previous_iterator()->ShortPrint(out); PrintF(out, "\n"); } diff --git a/src/objects.cc b/src/objects.cc index cdf6bef..8e8830a 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -16222,7 +16222,6 @@ Handle OrderedHashTable::Allocate( table->SetNumberOfBuckets(num_buckets); table->SetNumberOfElements(0); table->SetNumberOfDeletedElements(0); - table->set_iterators(isolate->heap()->undefined_value()); return table; } @@ -16230,6 +16229,8 @@ Handle OrderedHashTable::Allocate( template Handle OrderedHashTable::EnsureGrowable( Handle table) { + ASSERT(!table->IsObsolete()); + int nof = table->NumberOfElements(); int nod = table->NumberOfDeletedElements(); int capacity = table->Capacity(); @@ -16244,9 +16245,11 @@ Handle OrderedHashTable::EnsureGrowable( template Handle OrderedHashTable::Shrink( Handle table) { + ASSERT(!table->IsObsolete()); + int nof = table->NumberOfElements(); int capacity = table->Capacity(); - if (nof > (capacity >> 2)) return table; + if (nof >= (capacity >> 2)) return table; return Rehash(table, capacity / 2); } @@ -16254,21 +16257,15 @@ Handle OrderedHashTable::Shrink( template Handle OrderedHashTable::Clear( Handle table) { + ASSERT(!table->IsObsolete()); + Handle new_table = Allocate(table->GetIsolate(), kMinCapacity, table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED); - new_table->set_iterators(table->iterators()); - table->set_iterators(table->GetHeap()->undefined_value()); - - DisallowHeapAllocation no_allocation; - for (Object* object = new_table->iterators(); - !object->IsUndefined(); - object = Iterator::cast(object)->next_iterator()) { - Iterator::cast(object)->TableCleared(); - Iterator::cast(object)->set_table(*new_table); - } + table->SetNextTable(*new_table); + table->SetNumberOfDeletedElements(-1); return new_table; } @@ -16277,6 +16274,8 @@ Handle OrderedHashTable::Clear( template Handle OrderedHashTable::Rehash( Handle table, int new_capacity) { + ASSERT(!table->IsObsolete()); + Handle new_table = Allocate(table->GetIsolate(), new_capacity, @@ -16285,9 +16284,15 @@ Handle OrderedHashTable::Rehash( int nod = table->NumberOfDeletedElements(); int new_buckets = new_table->NumberOfBuckets(); int new_entry = 0; + int removed_holes_index = 0; + for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) { Object* key = table->KeyAt(old_entry); - if (key->IsTheHole()) continue; + if (key->IsTheHole()) { + table->SetRemovedIndexAt(removed_holes_index++, old_entry); + continue; + } + Object* hash = key->GetHash(); int bucket = Smi::cast(hash)->value() & (new_buckets - 1); Object* chain_entry = new_table->get(kHashTableStartIndex + bucket); @@ -16301,18 +16306,11 @@ Handle OrderedHashTable::Rehash( new_table->set(new_index + kChainOffset, chain_entry); ++new_entry; } - new_table->SetNumberOfElements(nof); - new_table->set_iterators(table->iterators()); - table->set_iterators(table->GetHeap()->undefined_value()); + ASSERT_EQ(nod, removed_holes_index); - DisallowHeapAllocation no_allocation; - for (Object* object = new_table->iterators(); - !object->IsUndefined(); - object = Iterator::cast(object)->next_iterator()) { - Iterator::cast(object)->TableCompacted(); - Iterator::cast(object)->set_table(*new_table); - } + new_table->SetNumberOfElements(nof); + table->SetNextTable(*new_table); return new_table; } @@ -16321,6 +16319,8 @@ Handle OrderedHashTable::Rehash( template int OrderedHashTable::FindEntry( Handle key) { + ASSERT(!IsObsolete()); + DisallowHeapAllocation no_gc; ASSERT(!key->IsTheHole()); Object* hash = key->GetHash(); @@ -16338,6 +16338,8 @@ int OrderedHashTable::FindEntry( template int OrderedHashTable::AddEntry(int hash) { + ASSERT(!IsObsolete()); + int entry = UsedCapacity(); int bucket = HashToBucket(hash); int index = EntryToIndex(entry); @@ -16351,19 +16353,14 @@ int OrderedHashTable::AddEntry(int hash) { template void OrderedHashTable::RemoveEntry(int entry) { + ASSERT(!IsObsolete()); + int index = EntryToIndex(entry); for (int i = 0; i < entrysize; ++i) { set_the_hole(index + i); } SetNumberOfElements(NumberOfElements() - 1); SetNumberOfDeletedElements(NumberOfDeletedElements() + 1); - - DisallowHeapAllocation no_allocation; - for (Object* object = iterators(); - !object->IsUndefined(); - object = Iterator::cast(object)->next_iterator()) { - Iterator::cast(object)->EntryRemoved(entry); - } } @@ -16483,97 +16480,69 @@ Handle OrderedHashMap::Put(Handle table, template -void OrderedHashTableIterator::EntryRemoved(int index) { - int i = this->index()->value(); - if (index < i) { - set_count(Smi::FromInt(count()->value() - 1)); - } - if (index == i) { - Seek(); - } -} - +Handle OrderedHashTableIterator::Next( + Handle iterator) { + Isolate* isolate = iterator->GetIsolate(); + Factory* factory = isolate->factory(); -template -void OrderedHashTableIterator::Close() { - if (Closed()) return; + Handle maybe_table(iterator->table(), isolate); + if (!maybe_table->IsUndefined()) { + iterator->Transition(); - DisallowHeapAllocation no_allocation; + Handle table(TableType::cast(iterator->table()), isolate); + int index = Smi::cast(iterator->index())->value(); + int used_capacity = table->UsedCapacity(); - Object* undefined = GetHeap()->undefined_value(); - TableType* table = TableType::cast(this->table()); - Object* previous = previous_iterator(); - Object* next = next_iterator(); + while (index < used_capacity && table->KeyAt(index)->IsTheHole()) { + index++; + } - if (previous == undefined) { - ASSERT_EQ(table->iterators(), this); - table->set_iterators(next); - } else { - ASSERT_EQ(Derived::cast(previous)->next_iterator(), this); - Derived::cast(previous)->set_next_iterator(next); - } + if (index < used_capacity) { + int entry_index = table->EntryToIndex(index); + Handle value = + Derived::ValueForKind(iterator, entry_index); + iterator->set_index(Smi::FromInt(index + 1)); + return factory->NewIteratorResultObject(value, false); + } - if (!next->IsUndefined()) { - ASSERT_EQ(Derived::cast(next)->previous_iterator(), this); - Derived::cast(next)->set_previous_iterator(previous); + iterator->set_table(iterator->GetHeap()->undefined_value()); } - set_previous_iterator(undefined); - set_next_iterator(undefined); - set_table(undefined); -} - - -template -void OrderedHashTableIterator::Seek() { - ASSERT(!Closed()); - - DisallowHeapAllocation no_allocation; - - int index = this->index()->value(); - - TableType* table = TableType::cast(this->table()); - int used_capacity = table->UsedCapacity(); - - while (index < used_capacity && table->KeyAt(index)->IsTheHole()) { - index++; - } - set_index(Smi::FromInt(index)); + return factory->NewIteratorResultObject(factory->undefined_value(), true); } template -void OrderedHashTableIterator::MoveNext() { - ASSERT(!Closed()); - - set_index(Smi::FromInt(index()->value() + 1)); - set_count(Smi::FromInt(count()->value() + 1)); - Seek(); -} - +void OrderedHashTableIterator::Transition() { + Isolate* isolate = GetIsolate(); + Handle table(TableType::cast(this->table()), isolate); + if (!table->IsObsolete()) return; -template -Handle OrderedHashTableIterator::Next( - Handle iterator) { - Isolate* isolate = iterator->GetIsolate(); - Factory* factory = isolate->factory(); + int index = Smi::cast(this->index())->value(); + while (table->IsObsolete()) { + Handle next_table(table->NextTable(), isolate); - Handle object(iterator->table(), isolate); + if (index > 0) { + int nod = table->NumberOfDeletedElements(); - if (!object->IsUndefined()) { - Handle table = Handle::cast(object); - int index = iterator->index()->value(); - if (index < table->UsedCapacity()) { - int entry_index = table->EntryToIndex(index); - iterator->MoveNext(); - Handle value = Derived::ValueForKind(iterator, entry_index); - return factory->NewIteratorResultObject(value, false); - } else { - iterator->Close(); + // When we clear the table we set the number of deleted elements to -1. + if (nod == -1) { + index = 0; + } else { + int old_index = index; + for (int i = 0; i < nod; ++i) { + int removed_index = table->RemovedIndexAt(i); + if (removed_index >= old_index) break; + --index; + } + } } + + table = next_table; } - return factory->NewIteratorResultObject(factory->undefined_value(), true); + set_table(*table); + set_index(Smi::FromInt(index)); } @@ -16584,60 +16553,37 @@ Handle OrderedHashTableIterator::CreateInternal( int kind) { Isolate* isolate = table->GetIsolate(); - Handle undefined = isolate->factory()->undefined_value(); - Handle new_iterator = Handle::cast( isolate->factory()->NewJSObjectFromMap(map)); - new_iterator->set_previous_iterator(*undefined); new_iterator->set_table(*table); new_iterator->set_index(Smi::FromInt(0)); - new_iterator->set_count(Smi::FromInt(0)); new_iterator->set_kind(Smi::FromInt(kind)); - - Handle old_iterator(table->iterators(), isolate); - if (!old_iterator->IsUndefined()) { - Handle::cast(old_iterator)->set_previous_iterator(*new_iterator); - new_iterator->set_next_iterator(*old_iterator); - } else { - new_iterator->set_next_iterator(*undefined); - } - - table->set_iterators(*new_iterator); - return new_iterator; } -template void -OrderedHashTableIterator::EntryRemoved( - int index); - -template void -OrderedHashTableIterator::Close(); - template Handle OrderedHashTableIterator::Next( Handle iterator); +template void +OrderedHashTableIterator::Transition(); + template Handle OrderedHashTableIterator::CreateInternal( - Handle map, Handle table, int kind); - + Handle map, Handle table, int kind); -template void -OrderedHashTableIterator::EntryRemoved( - int index); - -template void -OrderedHashTableIterator::Close(); template Handle OrderedHashTableIterator::Next( Handle iterator); +template void +OrderedHashTableIterator::Transition(); + template Handle OrderedHashTableIterator::CreateInternal( - Handle map, Handle table, int kind); + Handle map, Handle table, int kind); Handle JSSetIterator::ValueForKind( diff --git a/src/objects.h b/src/objects.h index d642e1e..910c252 100644 --- a/src/objects.h +++ b/src/objects.h @@ -4153,16 +4153,27 @@ class ObjectHashTable: public HashTable class OrderedHashTable: public FixedArray { public: @@ -4199,10 +4210,6 @@ class OrderedHashTable: public FixedArray { return Smi::cast(get(kNumberOfBucketsIndex))->value(); } - Object* iterators() { return get(kIteratorsIndex); } - - void set_iterators(Object* value) { set(kIteratorsIndex, value); } - // Returns the index into the data table where the new entry // should be placed. The table is assumed to have enough space // for a new entry. @@ -4219,6 +4226,20 @@ class OrderedHashTable: public FixedArray { Object* KeyAt(int entry) { return get(EntryToIndex(entry)); } + bool IsObsolete() { + return !get(kNextTableIndex)->IsSmi(); + } + + // The next newer table. This is only valid if the table is obsolete. + Derived* NextTable() { + return Derived::cast(get(kNextTableIndex)); + } + + // When the table is obsolete we store the indexes of the removed holes. + int RemovedIndexAt(int index) { + return Smi::cast(get(kRemovedHolesIndex + index))->value(); + } + static const int kNotFound = -1; static const int kMinCapacity = 4; @@ -4255,11 +4276,21 @@ class OrderedHashTable: public FixedArray { return Smi::cast(get(kHashTableStartIndex + bucket))->value(); } + void SetNextTable(Derived* next_table) { + set(kNextTableIndex, next_table); + } + + void SetRemovedIndexAt(int index, int removed_index) { + return set(kRemovedHolesIndex + index, Smi::FromInt(removed_index)); + } + static const int kNumberOfBucketsIndex = 0; static const int kNumberOfElementsIndex = kNumberOfBucketsIndex + 1; static const int kNumberOfDeletedElementsIndex = kNumberOfElementsIndex + 1; - static const int kIteratorsIndex = kNumberOfDeletedElementsIndex + 1; - static const int kHashTableStartIndex = kIteratorsIndex + 1; + static const int kHashTableStartIndex = kNumberOfDeletedElementsIndex + 1; + + static const int kNextTableIndex = kNumberOfElementsIndex; + static const int kRemovedHolesIndex = kHashTableStartIndex; static const int kEntrySize = entrysize + 1; static const int kChainOffset = entrysize; @@ -9956,17 +9987,15 @@ class JSMap: public JSObject { // OrderedHashTableIterator is an iterator that iterates over the keys and // values of an OrderedHashTable. // -// The hash table has a reference to the iterator and the iterators themselves -// have references to the [next_iterator] and [previous_iterator], thus creating -// a double linked list. +// The iterator has a reference to the underlying OrderedHashTable data, +// [table], as well as the current [index] the iterator is at. // -// When the hash table changes the iterators are called to update their [index] -// and [count]. The hash table calls [EntryRemoved], [TableCompacted] as well -// as [TableCleared]. +// When the OrderedHashTable is rehashed it adds a reference from the old table +// to the new table as well as storing enough data about the changes so that the +// iterator [index] can be adjusted accordingly. // -// When an iterator is done it closes itself. It removes itself from the double -// linked list and it sets its [table] to undefined, no longer keeping the -// [table] alive. +// When the [Next] result from the iterator is requested, the iterator checks if +// there is a newer table that it needs to transition to. template class OrderedHashTableIterator: public JSObject { public: @@ -9976,29 +10005,17 @@ class OrderedHashTableIterator: public JSObject { // [index]: The index into the data table. DECL_ACCESSORS(index, Smi) - // [count]: The logical index into the data table, ignoring the holes. - DECL_ACCESSORS(count, Smi) - // [kind]: The kind of iteration this is. One of the [Kind] enum values. DECL_ACCESSORS(kind, Smi) - // [next_iterator]: Used as a double linked list for the live iterators. - DECL_ACCESSORS(next_iterator, Object) - - // [previous_iterator]: Used as a double linked list for the live iterators. - DECL_ACCESSORS(previous_iterator, Object) - #ifdef OBJECT_PRINT void OrderedHashTableIteratorPrint(FILE* out); #endif static const int kTableOffset = JSObject::kHeaderSize; static const int kIndexOffset = kTableOffset + kPointerSize; - static const int kCountOffset = kIndexOffset + kPointerSize; - static const int kKindOffset = kCountOffset + kPointerSize; - static const int kNextIteratorOffset = kKindOffset + kPointerSize; - static const int kPreviousIteratorOffset = kNextIteratorOffset + kPointerSize; - static const int kSize = kPreviousIteratorOffset + kPointerSize; + static const int kKindOffset = kIndexOffset + kPointerSize; + static const int kSize = kKindOffset + kPointerSize; enum Kind { kKindKeys = 1, @@ -10006,25 +10023,6 @@ class OrderedHashTableIterator: public JSObject { kKindEntries = 3 }; - // Called by the underlying [table] when an entry is removed. - void EntryRemoved(int index); - - // Called by the underlying [table] when it is compacted/rehashed. - void TableCompacted() { - // All holes have been removed so index is now same as count. - set_index(count()); - } - - // Called by the underlying [table] when it is cleared. - void TableCleared() { - set_index(Smi::FromInt(0)); - set_count(Smi::FromInt(0)); - } - - // Removes the iterator from the double linked list and removes its reference - // back to the [table]. - void Close(); - // Returns an iterator result object: {value: any, done: boolean} and moves // the index to the next valid entry. Closes the iterator if moving past the // end. @@ -10035,16 +10033,9 @@ class OrderedHashTableIterator: public JSObject { Handle map, Handle table, int kind); private: - // Ensures [index] is not pointing to a hole. - void Seek(); - - // Moves [index] to next valid entry. Closes the iterator if moving past the - // end. - void MoveNext(); - - bool Closed() { - return table()->IsUndefined(); - } + // Transitions the iterator to the non obsolote backing store. This is a NOP + // if the [table] is not obsolete. + void Transition(); DISALLOW_IMPLICIT_CONSTRUCTORS(OrderedHashTableIterator); }; @@ -10066,7 +10057,8 @@ class JSSetIterator: public OrderedHashTableIterator ValueForKind( - Handle iterator, int entry_index); + Handle iterator, + int entry_index); private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSSetIterator); @@ -10089,7 +10081,8 @@ class JSMapIterator: public OrderedHashTableIterator ValueForKind( - Handle iterator, int entry_index); + Handle iterator, + int entry_index); private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSMapIterator); diff --git a/src/runtime.cc b/src/runtime.cc index 99dc6bf..3e89788 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -1600,15 +1600,6 @@ RUNTIME_FUNCTION(Runtime_SetIteratorNext) { } -RUNTIME_FUNCTION(Runtime_SetIteratorClose) { - HandleScope scope(isolate); - ASSERT(args.length() == 1); - CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0); - holder->Close(); - return isolate->heap()->undefined_value(); -} - - RUNTIME_FUNCTION(Runtime_MapInitialize) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -1709,15 +1700,6 @@ RUNTIME_FUNCTION(Runtime_MapIteratorNext) { } -RUNTIME_FUNCTION(Runtime_MapIteratorClose) { - HandleScope scope(isolate); - ASSERT(args.length() == 1); - CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0); - holder->Close(); - return isolate->heap()->undefined_value(); -} - - static Handle WeakCollectionInitialize( Isolate* isolate, Handle weak_collection) { diff --git a/src/runtime.h b/src/runtime.h index 6565bf5..1a93bf0 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -276,7 +276,6 @@ namespace internal { F(SetCreateIterator, 2, 1) \ \ F(SetIteratorNext, 1, 1) \ - F(SetIteratorClose, 1, 1) \ \ /* Harmony maps */ \ F(MapInitialize, 1, 1) \ @@ -289,7 +288,6 @@ namespace internal { F(MapCreateIterator, 2, 1) \ \ F(MapIteratorNext, 1, 1) \ - F(MapIteratorClose, 1, 1) \ \ /* Harmony weak maps and sets */ \ F(WeakCollectionInitialize, 1, 1) \ diff --git a/test/mjsunit/harmony/collections.js b/test/mjsunit/harmony/collections.js index 7bf7bf7..edbdd41 100644 --- a/test/mjsunit/harmony/collections.js +++ b/test/mjsunit/harmony/collections.js @@ -852,3 +852,138 @@ for (var i = 9; i >= 0; i--) { }); assertEquals(4950, accumulated); })(); + + +(function TestMapForEachAllRemovedTransition() { + var map = new Map; + map.set(0, 0); + + var buffer = []; + map.forEach(function(v) { + buffer.push(v); + if (v === 0) { + for (var i = 1; i < 4; i++) { + map.set(i, i); + } + } + + if (v === 3) { + for (var i = 0; i < 4; i++) { + map.delete(i); + } + for (var i = 4; i < 8; i++) { + map.set(i, i); + } + } + }); + + assertArrayEquals([0, 1, 2, 3, 4, 5, 6, 7], buffer); +})(); + + +(function TestMapForEachClearTransition() { + var map = new Map; + map.set(0, 0); + + var i = 0; + var buffer = []; + map.forEach(function(v) { + buffer.push(v); + if (++i < 5) { + for (var j = 0; j < 5; j++) { + map.clear(); + map.set(i, i); + } + } + }); + + assertArrayEquals([0, 1, 2, 3, 4], buffer); +})(); + + +(function TestMapForEachNestedNonTrivialTransition() { + var map = new Map; + map.set(0, 0); + map.set(1, 1); + map.set(2, 2); + map.set(3, 3); + map.delete(0); + + var i = 0; + var buffer = []; + map.forEach(function(v) { + if (++i > 10) return; + + buffer.push(v); + + if (v == 3) { + map.delete(1); + for (var j = 4; j < 10; j++) { + map.set(j, j); + } + for (var j = 4; j < 10; j += 2) { + map.delete(j); + } + map.delete(2); + + for (var j = 10; j < 20; j++) { + map.set(j, j); + } + for (var j = 10; j < 20; j += 2) { + map.delete(j); + } + + map.delete(3); + } + }); + + assertArrayEquals([1, 2, 3, 5, 7, 9, 11, 13, 15, 17], buffer); +})(); + + +(function TestMapForEachAllRemovedTransitionNoClear() { + var map = new Map; + map.set(0, 0); + + var buffer = []; + map.forEach(function(v) { + buffer.push(v); + if (v === 0) { + for (var i = 1; i < 8; i++) { + map.set(i, i); + } + } + + if (v === 4) { + for (var i = 0; i < 8; i++) { + map.delete(i); + } + } + }); + + assertArrayEquals([0, 1, 2, 3, 4], buffer); +})(); + + +(function TestMapForEachNoMoreElementsAfterTransition() { + var map = new Map; + map.set(0, 0); + + var buffer = []; + map.forEach(function(v) { + buffer.push(v); + if (v === 0) { + for (var i = 1; i < 16; i++) { + map.set(i, i); + } + } + + if (v === 4) { + for (var i = 5; i < 16; i++) { + map.delete(i); + } + } + }); + + assertArrayEquals([0, 1, 2, 3, 4], buffer); +})(); diff --git a/test/mjsunit/runtime-gen/mapiteratorclose.js b/test/mjsunit/runtime-gen/mapiteratorclose.js deleted file mode 100644 index 7102384..0000000 --- a/test/mjsunit/runtime-gen/mapiteratorclose.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2014 the V8 project authors. All rights reserved. -// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY -// Flags: --allow-natives-syntax --harmony -var _holder = %MapCreateIterator(new Map(), 3); -%MapIteratorClose(_holder); diff --git a/test/mjsunit/runtime-gen/setiteratorclose.js b/test/mjsunit/runtime-gen/setiteratorclose.js deleted file mode 100644 index eff3bf6..0000000 --- a/test/mjsunit/runtime-gen/setiteratorclose.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2014 the V8 project authors. All rights reserved. -// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY -// Flags: --allow-natives-syntax --harmony -var _holder = %SetCreateIterator(new Set(), 2); -%SetIteratorClose(_holder); diff --git a/tools/generate-runtime-tests.py b/tools/generate-runtime-tests.py index 7c46281..96d4b35 100755 --- a/tools/generate-runtime-tests.py +++ b/tools/generate-runtime-tests.py @@ -47,8 +47,8 @@ EXPAND_MACROS = [ # that the parser doesn't bit-rot. Change the values as needed when you add, # remove or change runtime functions, but make sure we don't lose our ability # to parse them! -EXPECTED_FUNCTION_COUNT = 361 -EXPECTED_FUZZABLE_COUNT = 328 +EXPECTED_FUNCTION_COUNT = 359 +EXPECTED_FUZZABLE_COUNT = 326 EXPECTED_CCTEST_COUNT = 6 EXPECTED_UNKNOWN_COUNT = 5 EXPECTED_BUILTINS_COUNT = 824 -- 2.7.4