LCOV - code coverage report
Current view: top level - test/cctest - test-identity-map.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 395 395 100.0 %
Date: 2019-04-17 Functions: 50 50 100.0 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <set>
       6             : 
       7             : #include "src/heap/factory-inl.h"
       8             : #include "src/identity-map.h"
       9             : #include "src/isolate.h"
      10             : #include "src/objects.h"
      11             : #include "src/objects/heap-number-inl.h"
      12             : #include "src/zone/zone.h"
      13             : #include "test/cctest/cctest.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18             : // Helper for testing. A "friend" of the IdentityMapBase class, it is able to
      19             : // "move" objects to simulate GC for testing the internals of the map.
      20         740 : class IdentityMapTester : public HandleAndZoneScope {
      21             :  public:
      22             :   IdentityMap<void*, ZoneAllocationPolicy> map;
      23             : 
      24         370 :   IdentityMapTester() : map(heap(), ZoneAllocationPolicy(main_zone())) {}
      25             : 
      26             :   Heap* heap() { return isolate()->heap(); }
      27             :   Isolate* isolate() { return main_isolate(); }
      28             : 
      29        5045 :   void TestGetFind(Handle<Object> key1, void* val1, Handle<Object> key2,
      30             :                    void* val2) {
      31        5045 :     CHECK_NULL(map.Find(key1));
      32        5045 :     CHECK_NULL(map.Find(key2));
      33             : 
      34             :     // Set {key1} the first time.
      35             :     void** entry = map.Get(key1);
      36        5045 :     CHECK_NOT_NULL(entry);
      37        5045 :     *entry = val1;
      38             : 
      39       35315 :     for (int i = 0; i < 3; i++) {  // Get and find {key1} K times.
      40             :       {
      41             :         void** nentry = map.Get(key1);
      42       15135 :         CHECK_EQ(entry, nentry);
      43       15135 :         CHECK_EQ(val1, *nentry);
      44       15135 :         CHECK_NULL(map.Find(key2));
      45             :       }
      46             :       {
      47             :         void** nentry = map.Find(key1);
      48       15135 :         CHECK_EQ(entry, nentry);
      49       15135 :         CHECK_EQ(val1, *nentry);
      50       15135 :         CHECK_NULL(map.Find(key2));
      51             :       }
      52             :     }
      53             : 
      54             :     // Set {key2} the first time.
      55             :     void** entry2 = map.Get(key2);
      56        5045 :     CHECK_NOT_NULL(entry2);
      57        5045 :     *entry2 = val2;
      58             : 
      59       35315 :     for (int i = 0; i < 3; i++) {  // Get and find {key1} and {key2} K times.
      60             :       {
      61             :         void** nentry = map.Get(key2);
      62       15135 :         CHECK_EQ(entry2, nentry);
      63       15135 :         CHECK_EQ(val2, *nentry);
      64             :       }
      65             :       {
      66             :         void** nentry = map.Find(key2);
      67       15135 :         CHECK_EQ(entry2, nentry);
      68       15135 :         CHECK_EQ(val2, *nentry);
      69             :       }
      70             :       {
      71             :         void** nentry = map.Find(key1);
      72       15135 :         CHECK_EQ(val1, *nentry);
      73             :       }
      74             :     }
      75        5045 :   }
      76             : 
      77          10 :   void TestFindDelete(Handle<Object> key1, void* val1, Handle<Object> key2,
      78             :                       void* val2) {
      79          10 :     CHECK_NULL(map.Find(key1));
      80          10 :     CHECK_NULL(map.Find(key2));
      81             : 
      82             :     // Set {key1} and {key2} for the first time.
      83             :     void** entry1 = map.Get(key1);
      84          10 :     CHECK_NOT_NULL(entry1);
      85          10 :     *entry1 = val1;
      86             :     void** entry2 = map.Get(key2);
      87          10 :     CHECK_NOT_NULL(entry2);
      88          10 :     *entry2 = val2;
      89             : 
      90          70 :     for (int i = 0; i < 3; i++) {  // Find {key1} and {key2} 3 times.
      91             :       {
      92             :         void** nentry = map.Find(key2);
      93          30 :         CHECK_EQ(val2, *nentry);
      94             :       }
      95             :       {
      96             :         void** nentry = map.Find(key1);
      97          30 :         CHECK_EQ(val1, *nentry);
      98             :       }
      99             :     }
     100             : 
     101             :     // Delete {key1}
     102             :     void* deleted_entry_1;
     103          10 :     CHECK(map.Delete(key1, &deleted_entry_1));
     104          10 :     CHECK_NOT_NULL(deleted_entry_1);
     105             :     deleted_entry_1 = val1;
     106             : 
     107          70 :     for (int i = 0; i < 3; i++) {  // Find {key1} and not {key2} 3 times.
     108             :       {
     109             :         void** nentry = map.Find(key1);
     110          30 :         CHECK_NULL(nentry);
     111             :       }
     112             :       {
     113             :         void** nentry = map.Find(key2);
     114          30 :         CHECK_EQ(val2, *nentry);
     115             :       }
     116             :     }
     117             : 
     118             :     // Delete {key2}
     119             :     void* deleted_entry_2;
     120          10 :     CHECK(map.Delete(key2, &deleted_entry_2));
     121          10 :     CHECK_NOT_NULL(deleted_entry_2);
     122             :     deleted_entry_2 = val2;
     123             : 
     124          70 :     for (int i = 0; i < 3; i++) {  // Don't find {key1} and {key2} 3 times.
     125             :       {
     126             :         void** nentry = map.Find(key1);
     127          30 :         CHECK_NULL(nentry);
     128             :       }
     129             :       {
     130             :         void** nentry = map.Find(key2);
     131          30 :         CHECK_NULL(nentry);
     132             :       }
     133             :     }
     134          10 :   }
     135             : 
     136       98640 :   Handle<Smi> smi(int value) {
     137       98640 :     return Handle<Smi>(Smi::FromInt(value), isolate());
     138             :   }
     139             : 
     140             :   Handle<Object> num(double value) {
     141        1260 :     return isolate()->factory()->NewNumber(value);
     142             :   }
     143             : 
     144             :   void SimulateGCByIncrementingSmisBy(int shift) {
     145        1101 :     for (int i = 0; i < map.capacity_; i++) {
     146         528 :       Address key = map.keys_[i];
     147         528 :       if (!Internals::HasHeapObjectTag(key)) {
     148         450 :         map.keys_[i] = Internals::IntToSmi(Internals::SmiValue(key) + shift);
     149             :       }
     150             :     }
     151          45 :     map.gc_counter_ = -1;
     152             :   }
     153             : 
     154       27395 :   void CheckFind(Handle<Object> key, void* value) {
     155             :     void** entry = map.Find(key);
     156       27395 :     CHECK_NOT_NULL(entry);
     157       27395 :     CHECK_EQ(value, *entry);
     158       27395 :   }
     159             : 
     160       13730 :   void CheckGet(Handle<Object> key, void* value) {
     161             :     void** entry = map.Get(key);
     162       13730 :     CHECK_NOT_NULL(entry);
     163       13730 :     CHECK_EQ(value, *entry);
     164       13730 :   }
     165             : 
     166        5300 :   void CheckDelete(Handle<Object> key, void* value) {
     167             :     void* entry;
     168        5300 :     CHECK(map.Delete(key, &entry));
     169        5300 :     CHECK_NOT_NULL(entry);
     170        5300 :     CHECK_EQ(value, entry);
     171        5300 :   }
     172             : 
     173             :   void PrintMap() {
     174             :     PrintF("{\n");
     175             :     for (int i = 0; i < map.capacity_; i++) {
     176             :       PrintF("  %3d: %p => %p\n", i, reinterpret_cast<void*>(map.keys_[i]),
     177             :              reinterpret_cast<void*>(map.values_[i]));
     178             :     }
     179             :     PrintF("}\n");
     180             :   }
     181             : 
     182          20 :   void Resize() { map.Resize(map.capacity_ * 4); }
     183             : 
     184          20 :   void Rehash() { map.Rehash(); }
     185             : };
     186             : 
     187       26644 : TEST(Find_smi_not_found) {
     188           5 :   IdentityMapTester t;
     189        1005 :   for (int i = 0; i < 100; i++) {
     190        1000 :     CHECK_NULL(t.map.Find(t.smi(i)));
     191             :   }
     192           5 : }
     193             : 
     194             : 
     195       26644 : TEST(Find_num_not_found) {
     196           5 :   IdentityMapTester t;
     197        1005 :   for (int i = 0; i < 100; i++) {
     198        1000 :     CHECK_NULL(t.map.Find(t.num(i + 0.2)));
     199             :   }
     200           5 : }
     201             : 
     202       26644 : TEST(Delete_smi_not_found) {
     203           5 :   IdentityMapTester t;
     204        1005 :   for (int i = 0; i < 100; i++) {
     205             :     void* deleted_value = &t;
     206        1000 :     CHECK(!t.map.Delete(t.smi(i), &deleted_value));
     207         500 :     CHECK_EQ(&t, deleted_value);
     208             :   }
     209           5 : }
     210             : 
     211       26644 : TEST(Delete_num_not_found) {
     212           5 :   IdentityMapTester t;
     213        1005 :   for (int i = 0; i < 100; i++) {
     214             :     void* deleted_value = &t;
     215        1000 :     CHECK(!t.map.Delete(t.num(i + 0.2), &deleted_value));
     216         500 :     CHECK_EQ(&t, deleted_value);
     217             :   }
     218           5 : }
     219             : 
     220       26644 : TEST(GetFind_smi_0) {
     221           5 :   IdentityMapTester t;
     222          15 :   t.TestGetFind(t.smi(0), t.isolate(), t.smi(1), t.heap());
     223           5 : }
     224             : 
     225       26644 : TEST(GetFind_smi_13) {
     226           5 :   IdentityMapTester t;
     227          15 :   t.TestGetFind(t.smi(13), t.isolate(), t.smi(17), t.heap());
     228           5 : }
     229             : 
     230       26644 : TEST(GetFind_num_13) {
     231           5 :   IdentityMapTester t;
     232           5 :   t.TestGetFind(t.num(13.1), t.isolate(), t.num(17.1), t.heap());
     233           5 : }
     234             : 
     235       26644 : TEST(Delete_smi_13) {
     236           5 :   IdentityMapTester t;
     237          15 :   t.TestFindDelete(t.smi(13), t.isolate(), t.smi(17), t.heap());
     238           5 :   CHECK(t.map.empty());
     239           5 : }
     240             : 
     241       26644 : TEST(Delete_num_13) {
     242           5 :   IdentityMapTester t;
     243           5 :   t.TestFindDelete(t.num(13.1), t.isolate(), t.num(17.1), t.heap());
     244           5 :   CHECK(t.map.empty());
     245           5 : }
     246             : 
     247       26644 : TEST(GetFind_smi_17m) {
     248             :   const int kInterval = 17;
     249             :   const int kShift = 1099;
     250           5 :   IdentityMapTester t;
     251             : 
     252          65 :   for (int i = 1; i < 100; i += kInterval) {
     253          30 :     t.map.Set(t.smi(i), reinterpret_cast<void*>(i + kShift));
     254             :   }
     255             : 
     256          65 :   for (int i = 1; i < 100; i += kInterval) {
     257          60 :     t.CheckFind(t.smi(i), reinterpret_cast<void*>(i + kShift));
     258             :   }
     259             : 
     260          65 :   for (int i = 1; i < 100; i += kInterval) {
     261          60 :     t.CheckGet(t.smi(i), reinterpret_cast<void*>(i + kShift));
     262             :   }
     263             : 
     264         995 :   for (int i = 1; i < 100; i++) {
     265         495 :     void** entry = t.map.Find(t.smi(i));
     266         495 :     if ((i % kInterval) != 1) {
     267         465 :       CHECK_NULL(entry);
     268             :     } else {
     269          30 :       CHECK_NOT_NULL(entry);
     270          30 :       CHECK_EQ(reinterpret_cast<void*>(i + kShift), *entry);
     271             :     }
     272             :   }
     273           5 : }
     274             : 
     275       26644 : TEST(Delete_smi_17m) {
     276             :   const int kInterval = 17;
     277             :   const int kShift = 1099;
     278           5 :   IdentityMapTester t;
     279             : 
     280          65 :   for (int i = 1; i < 100; i += kInterval) {
     281          30 :     t.map.Set(t.smi(i), reinterpret_cast<void*>(i + kShift));
     282             :   }
     283             : 
     284          65 :   for (int i = 1; i < 100; i += kInterval) {
     285          60 :     t.CheckFind(t.smi(i), reinterpret_cast<void*>(i + kShift));
     286             :   }
     287             : 
     288          65 :   for (int i = 1; i < 100; i += kInterval) {
     289          60 :     t.CheckDelete(t.smi(i), reinterpret_cast<void*>(i + kShift));
     290         390 :     for (int j = 1; j < 100; j += kInterval) {
     291         180 :       void** entry = t.map.Find(t.smi(j));
     292         180 :       if (j <= i) {
     293         105 :         CHECK_NULL(entry);
     294             :       } else {
     295          75 :         CHECK_NOT_NULL(entry);
     296          75 :         CHECK_EQ(reinterpret_cast<void*>(j + kShift), *entry);
     297             :       }
     298             :     }
     299             :   }
     300           5 : }
     301             : 
     302       26644 : TEST(GetFind_num_1000) {
     303             :   const int kPrime = 137;
     304           5 :   IdentityMapTester t;
     305             :   int val1;
     306             :   int val2;
     307             : 
     308       10005 :   for (int i = 0; i < 1000; i++) {
     309       15000 :     t.TestGetFind(t.smi(i * kPrime), &val1, t.smi(i * kPrime + 1), &val2);
     310             :   }
     311           5 : }
     312             : 
     313       26644 : TEST(Delete_num_1000) {
     314             :   const int kPrime = 137;
     315           5 :   IdentityMapTester t;
     316             : 
     317       10005 :   for (int i = 0; i < 1000; i++) {
     318        5000 :     t.map.Set(t.smi(i * kPrime), reinterpret_cast<void*>(i * kPrime));
     319             :   }
     320             : 
     321             :   // Delete every second value in reverse.
     322        5005 :   for (int i = 999; i >= 0; i -= 2) {
     323             :     void* entry;
     324        5000 :     CHECK(t.map.Delete(t.smi(i * kPrime), &entry));
     325        2500 :     CHECK_EQ(reinterpret_cast<void*>(i * kPrime), entry);
     326             :   }
     327             : 
     328       10005 :   for (int i = 0; i < 1000; i++) {
     329        5000 :     void** entry = t.map.Find(t.smi(i * kPrime));
     330        5000 :     if (i % 2) {
     331        2500 :       CHECK_NULL(entry);
     332             :     } else {
     333        2500 :       CHECK_NOT_NULL(entry);
     334        2500 :       CHECK_EQ(reinterpret_cast<void*>(i * kPrime), *entry);
     335             :     }
     336             :   }
     337             : 
     338             :   // Delete the rest.
     339        5005 :   for (int i = 0; i < 1000; i += 2) {
     340             :     void* entry;
     341        5000 :     CHECK(t.map.Delete(t.smi(i * kPrime), &entry));
     342        2500 :     CHECK_EQ(reinterpret_cast<void*>(i * kPrime), entry);
     343             :   }
     344             : 
     345       10005 :   for (int i = 0; i < 1000; i++) {
     346        5000 :     void** entry = t.map.Find(t.smi(i * kPrime));
     347        5000 :     CHECK_NULL(entry);
     348             :   }
     349           5 : }
     350             : 
     351       26644 : TEST(GetFind_smi_gc) {
     352             :   const int kKey = 33;
     353             :   const int kShift = 1211;
     354           5 :   IdentityMapTester t;
     355             : 
     356           5 :   t.map.Set(t.smi(kKey), &t);
     357             :   t.SimulateGCByIncrementingSmisBy(kShift);
     358          10 :   t.CheckFind(t.smi(kKey + kShift), &t);
     359          10 :   t.CheckGet(t.smi(kKey + kShift), &t);
     360           5 : }
     361             : 
     362       26644 : TEST(Delete_smi_gc) {
     363             :   const int kKey = 33;
     364             :   const int kShift = 1211;
     365           5 :   IdentityMapTester t;
     366             : 
     367           5 :   t.map.Set(t.smi(kKey), &t);
     368             :   t.SimulateGCByIncrementingSmisBy(kShift);
     369          10 :   t.CheckDelete(t.smi(kKey + kShift), &t);
     370           5 : }
     371             : 
     372       26644 : TEST(GetFind_smi_gc2) {
     373           5 :   int kKey1 = 1;
     374           5 :   int kKey2 = 33;
     375             :   const int kShift = 1211;
     376           5 :   IdentityMapTester t;
     377             : 
     378           5 :   t.map.Set(t.smi(kKey1), &kKey1);
     379           5 :   t.map.Set(t.smi(kKey2), &kKey2);
     380             :   t.SimulateGCByIncrementingSmisBy(kShift);
     381          10 :   t.CheckFind(t.smi(kKey1 + kShift), &kKey1);
     382          10 :   t.CheckGet(t.smi(kKey1 + kShift), &kKey1);
     383          10 :   t.CheckFind(t.smi(kKey2 + kShift), &kKey2);
     384          10 :   t.CheckGet(t.smi(kKey2 + kShift), &kKey2);
     385           5 : }
     386             : 
     387       26644 : TEST(Delete_smi_gc2) {
     388           5 :   int kKey1 = 1;
     389           5 :   int kKey2 = 33;
     390             :   const int kShift = 1211;
     391           5 :   IdentityMapTester t;
     392             : 
     393           5 :   t.map.Set(t.smi(kKey1), &kKey1);
     394           5 :   t.map.Set(t.smi(kKey2), &kKey2);
     395             :   t.SimulateGCByIncrementingSmisBy(kShift);
     396          10 :   t.CheckDelete(t.smi(kKey1 + kShift), &kKey1);
     397          10 :   t.CheckDelete(t.smi(kKey2 + kShift), &kKey2);
     398           5 : }
     399             : 
     400       26644 : TEST(GetFind_smi_gc_n) {
     401             :   const int kShift = 12011;
     402           5 :   IdentityMapTester t;
     403             :   int keys[12] = {1,      2,      7,      8,      15,      23,
     404           5 :                   1 + 32, 2 + 32, 7 + 32, 8 + 32, 15 + 32, 23 + 32};
     405             :   // Initialize the map first.
     406          65 :   for (size_t i = 0; i < arraysize(keys); i += 2) {
     407          90 :     t.TestGetFind(t.smi(keys[i]), &keys[i], t.smi(keys[i + 1]), &keys[i + 1]);
     408             :   }
     409             :   // Check the above initialization.
     410         125 :   for (size_t i = 0; i < arraysize(keys); i++) {
     411         120 :     t.CheckFind(t.smi(keys[i]), &keys[i]);
     412             :   }
     413             :   // Simulate a GC by "moving" the smis in the internal keys array.
     414             :   t.SimulateGCByIncrementingSmisBy(kShift);
     415             :   // Check that searching for the incremented smis finds the same values.
     416         125 :   for (size_t i = 0; i < arraysize(keys); i++) {
     417         120 :     t.CheckFind(t.smi(keys[i] + kShift), &keys[i]);
     418             :   }
     419             :   // Check that searching for the incremented smis gets the same values.
     420         125 :   for (size_t i = 0; i < arraysize(keys); i++) {
     421         120 :     t.CheckGet(t.smi(keys[i] + kShift), &keys[i]);
     422             :   }
     423           5 : }
     424             : 
     425       26644 : TEST(Delete_smi_gc_n) {
     426             :   const int kShift = 12011;
     427           5 :   IdentityMapTester t;
     428             :   int keys[12] = {1,      2,      7,      8,      15,      23,
     429           5 :                   1 + 32, 2 + 32, 7 + 32, 8 + 32, 15 + 32, 23 + 32};
     430             :   // Initialize the map first.
     431         125 :   for (size_t i = 0; i < arraysize(keys); i++) {
     432          60 :     t.map.Set(t.smi(keys[i]), &keys[i]);
     433             :   }
     434             :   // Simulate a GC by "moving" the smis in the internal keys array.
     435             :   t.SimulateGCByIncrementingSmisBy(kShift);
     436             :   // Check that deleting for the incremented smis finds the same values.
     437         125 :   for (size_t i = 0; i < arraysize(keys); i++) {
     438         120 :     t.CheckDelete(t.smi(keys[i] + kShift), &keys[i]);
     439             :   }
     440           5 : }
     441             : 
     442       26644 : TEST(GetFind_smi_num_gc_n) {
     443             :   const int kShift = 12019;
     444           5 :   IdentityMapTester t;
     445           5 :   int smi_keys[] = {1, 2, 7, 15, 23};
     446             :   Handle<Object> num_keys[] = {t.num(1.1), t.num(2.2), t.num(3.3), t.num(4.4),
     447             :                                t.num(5.5), t.num(6.6), t.num(7.7), t.num(8.8),
     448          50 :                                t.num(9.9), t.num(10.1)};
     449             :   // Initialize the map first.
     450          55 :   for (size_t i = 0; i < arraysize(smi_keys); i++) {
     451          25 :     t.map.Set(t.smi(smi_keys[i]), &smi_keys[i]);
     452             :   }
     453         105 :   for (size_t i = 0; i < arraysize(num_keys); i++) {
     454          50 :     t.map.Set(num_keys[i], &num_keys[i]);
     455             :   }
     456             :   // Check the above initialization.
     457          55 :   for (size_t i = 0; i < arraysize(smi_keys); i++) {
     458          50 :     t.CheckFind(t.smi(smi_keys[i]), &smi_keys[i]);
     459             :   }
     460         105 :   for (size_t i = 0; i < arraysize(num_keys); i++) {
     461          50 :     t.CheckFind(num_keys[i], &num_keys[i]);
     462             :   }
     463             : 
     464             :   // Simulate a GC by moving SMIs.
     465             :   // Ironically the SMIs "move", but the heap numbers don't!
     466             :   t.SimulateGCByIncrementingSmisBy(kShift);
     467             : 
     468             :   // Check that searching for the incremented smis finds the same values.
     469          55 :   for (size_t i = 0; i < arraysize(smi_keys); i++) {
     470          50 :     t.CheckFind(t.smi(smi_keys[i] + kShift), &smi_keys[i]);
     471          50 :     t.CheckGet(t.smi(smi_keys[i] + kShift), &smi_keys[i]);
     472             :   }
     473             : 
     474             :   // Check that searching for the numbers finds the same values.
     475         105 :   for (size_t i = 0; i < arraysize(num_keys); i++) {
     476          50 :     t.CheckFind(num_keys[i], &num_keys[i]);
     477          50 :     t.CheckGet(num_keys[i], &num_keys[i]);
     478             :   }
     479           5 : }
     480             : 
     481       26644 : TEST(Delete_smi_num_gc_n) {
     482             :   const int kShift = 12019;
     483           5 :   IdentityMapTester t;
     484           5 :   int smi_keys[] = {1, 2, 7, 15, 23};
     485             :   Handle<Object> num_keys[] = {t.num(1.1), t.num(2.2), t.num(3.3), t.num(4.4),
     486             :                                t.num(5.5), t.num(6.6), t.num(7.7), t.num(8.8),
     487          50 :                                t.num(9.9), t.num(10.1)};
     488             :   // Initialize the map first.
     489          55 :   for (size_t i = 0; i < arraysize(smi_keys); i++) {
     490          25 :     t.map.Set(t.smi(smi_keys[i]), &smi_keys[i]);
     491             :   }
     492         105 :   for (size_t i = 0; i < arraysize(num_keys); i++) {
     493          50 :     t.map.Set(num_keys[i], &num_keys[i]);
     494             :   }
     495             : 
     496             :   // Simulate a GC by moving SMIs.
     497             :   // Ironically the SMIs "move", but the heap numbers don't!
     498             :   t.SimulateGCByIncrementingSmisBy(kShift);
     499             : 
     500             :   // Check that deleting for the incremented smis finds the same values.
     501          55 :   for (size_t i = 0; i < arraysize(smi_keys); i++) {
     502          50 :     t.CheckDelete(t.smi(smi_keys[i] + kShift), &smi_keys[i]);
     503             :   }
     504             : 
     505             :   // Check that deleting the numbers finds the same values.
     506         105 :   for (size_t i = 0; i < arraysize(num_keys); i++) {
     507          50 :     t.CheckDelete(num_keys[i], &num_keys[i]);
     508             :   }
     509           5 : }
     510             : 
     511       26644 : TEST(Delete_smi_resizes) {
     512             :   const int kKeyCount = 1024;
     513             :   const int kValueOffset = 27;
     514           5 :   IdentityMapTester t;
     515             : 
     516             :   // Insert one element to initialize map.
     517           5 :   t.map.Set(t.smi(0), reinterpret_cast<void*>(kValueOffset));
     518             : 
     519             :   int initial_capacity = t.map.capacity();
     520           5 :   CHECK_LT(initial_capacity, kKeyCount);
     521             : 
     522             :   // Insert another kKeyCount - 1 keys.
     523       10235 :   for (int i = 1; i < kKeyCount; i++) {
     524        5115 :     t.map.Set(t.smi(i), reinterpret_cast<void*>(i + kValueOffset));
     525             :   }
     526             : 
     527             :   // Check capacity increased.
     528           5 :   CHECK_GT(t.map.capacity(), initial_capacity);
     529           5 :   CHECK_GE(t.map.capacity(), kKeyCount);
     530             : 
     531             :   // Delete all the keys.
     532       10245 :   for (int i = 0; i < kKeyCount; i++) {
     533       10240 :     t.CheckDelete(t.smi(i), reinterpret_cast<void*>(i + kValueOffset));
     534             :   }
     535             : 
     536             :   // Should resize back to initial capacity.
     537           5 :   CHECK_EQ(t.map.capacity(), initial_capacity);
     538           5 : }
     539             : 
     540       26644 : TEST(Iterator_smi_num) {
     541           5 :   IdentityMapTester t;
     542           5 :   int smi_keys[] = {1, 2, 7, 15, 23};
     543             :   Handle<Object> num_keys[] = {t.num(1.1), t.num(2.2), t.num(3.3), t.num(4.4),
     544             :                                t.num(5.5), t.num(6.6), t.num(7.7), t.num(8.8),
     545          50 :                                t.num(9.9), t.num(10.1)};
     546             :   // Initialize the map.
     547          55 :   for (size_t i = 0; i < arraysize(smi_keys); i++) {
     548          25 :     t.map.Set(t.smi(smi_keys[i]), reinterpret_cast<void*>(i));
     549             :   }
     550         105 :   for (size_t i = 0; i < arraysize(num_keys); i++) {
     551          50 :     t.map.Set(num_keys[i], reinterpret_cast<void*>(i + 5));
     552             :   }
     553             : 
     554             :   // Check iterator sees all values once.
     555             :   std::set<intptr_t> seen;
     556             :   {
     557          10 :     IdentityMap<void*, ZoneAllocationPolicy>::IteratableScope it_scope(&t.map);
     558          80 :     for (auto it = it_scope.begin(); it != it_scope.end(); ++it) {
     559         150 :       CHECK(seen.find(reinterpret_cast<intptr_t>(**it)) == seen.end());
     560         150 :       seen.insert(reinterpret_cast<intptr_t>(**it));
     561             :     }
     562             :   }
     563         155 :   for (intptr_t i = 0; i < 15; i++) {
     564          75 :     CHECK(seen.find(i) != seen.end());
     565             :   }
     566           5 : }
     567             : 
     568       26644 : TEST(Iterator_smi_num_gc) {
     569             :   const int kShift = 16039;
     570           5 :   IdentityMapTester t;
     571           5 :   int smi_keys[] = {1, 2, 7, 15, 23};
     572             :   Handle<Object> num_keys[] = {t.num(1.1), t.num(2.2), t.num(3.3), t.num(4.4),
     573             :                                t.num(5.5), t.num(6.6), t.num(7.7), t.num(8.8),
     574          50 :                                t.num(9.9), t.num(10.1)};
     575             :   // Initialize the map.
     576          55 :   for (size_t i = 0; i < arraysize(smi_keys); i++) {
     577          25 :     t.map.Set(t.smi(smi_keys[i]), reinterpret_cast<void*>(i));
     578             :   }
     579         105 :   for (size_t i = 0; i < arraysize(num_keys); i++) {
     580          50 :     t.map.Set(num_keys[i], reinterpret_cast<void*>(i + 5));
     581             :   }
     582             : 
     583             :   // Simulate GC by moving the SMIs.
     584             :   t.SimulateGCByIncrementingSmisBy(kShift);
     585             : 
     586             :   // Check iterator sees all values.
     587             :   std::set<intptr_t> seen;
     588             :   {
     589          10 :     IdentityMap<void*, ZoneAllocationPolicy>::IteratableScope it_scope(&t.map);
     590          80 :     for (auto it = it_scope.begin(); it != it_scope.end(); ++it) {
     591         150 :       CHECK(seen.find(reinterpret_cast<intptr_t>(**it)) == seen.end());
     592         150 :       seen.insert(reinterpret_cast<intptr_t>(**it));
     593             :     }
     594             :   }
     595         155 :   for (intptr_t i = 0; i < 15; i++) {
     596          75 :     CHECK(seen.find(i) != seen.end());
     597             :   }
     598           5 : }
     599             : 
     600          25 : void IterateCollisionTest(int stride) {
     601         225 :   for (int load = 15; load <= 120; load = load * 2) {
     602         100 :     IdentityMapTester t;
     603             : 
     604             :     {  // Add entries to the map.
     605             :       HandleScope scope(t.isolate());
     606             :       int next = 1;
     607       11350 :       for (int i = 0; i < load; i++) {
     608        5625 :         t.map.Set(t.smi(next), reinterpret_cast<void*>(next));
     609       11250 :         t.CheckFind(t.smi(next), reinterpret_cast<void*>(next));
     610        5625 :         next = next + stride;
     611             :       }
     612             :     }
     613             :     // Iterate through the map and check we see all elements only once.
     614             :     std::set<intptr_t> seen;
     615             :     {
     616             :       IdentityMap<void*, ZoneAllocationPolicy>::IteratableScope it_scope(
     617         200 :           &t.map);
     618        5725 :       for (auto it = it_scope.begin(); it != it_scope.end(); ++it) {
     619       11250 :         CHECK(seen.find(reinterpret_cast<intptr_t>(**it)) == seen.end());
     620       11250 :         seen.insert(reinterpret_cast<intptr_t>(**it));
     621             :       }
     622             :     }
     623             :     // Check get and find on map.
     624             :     {
     625             :       HandleScope scope(t.isolate());
     626             :       int next = 1;
     627       11350 :       for (int i = 0; i < load; i++) {
     628       11250 :         CHECK(seen.find(next) != seen.end());
     629       11250 :         t.CheckFind(t.smi(next), reinterpret_cast<void*>(next));
     630       11250 :         t.CheckGet(t.smi(next), reinterpret_cast<void*>(next));
     631        5625 :         next = next + stride;
     632             :       }
     633             :     }
     634             :   }
     635          25 : }
     636             : 
     637       26644 : TEST(IterateCollisions_1) { IterateCollisionTest(1); }
     638       26644 : TEST(IterateCollisions_2) { IterateCollisionTest(2); }
     639       26644 : TEST(IterateCollisions_3) { IterateCollisionTest(3); }
     640       26644 : TEST(IterateCollisions_5) { IterateCollisionTest(5); }
     641       26644 : TEST(IterateCollisions_7) { IterateCollisionTest(7); }
     642             : 
     643          35 : void CollisionTest(int stride, bool rehash = false, bool resize = false) {
     644         315 :   for (int load = 15; load <= 120; load = load * 2) {
     645         140 :     IdentityMapTester t;
     646             : 
     647             :     {  // Add entries to the map.
     648             :       HandleScope scope(t.isolate());
     649             :       int next = 1;
     650       15890 :       for (int i = 0; i < load; i++) {
     651        7875 :         t.map.Set(t.smi(next), reinterpret_cast<void*>(next));
     652       15750 :         t.CheckFind(t.smi(next), reinterpret_cast<void*>(next));
     653        7875 :         next = next + stride;
     654             :       }
     655             :     }
     656         140 :     if (resize) t.Resize();  // Explicit resize (internal method).
     657         140 :     if (rehash) t.Rehash();  // Explicit rehash (internal method).
     658             :     {                        // Check find and get.
     659             :       HandleScope scope(t.isolate());
     660             :       int next = 1;
     661       15890 :       for (int i = 0; i < load; i++) {
     662       15750 :         t.CheckFind(t.smi(next), reinterpret_cast<void*>(next));
     663       15750 :         t.CheckGet(t.smi(next), reinterpret_cast<void*>(next));
     664        7875 :         next = next + stride;
     665             :       }
     666             :     }
     667             :   }
     668          35 : }
     669             : 
     670       26644 : TEST(Collisions_1) { CollisionTest(1); }
     671       26644 : TEST(Collisions_2) { CollisionTest(2); }
     672       26644 : TEST(Collisions_3) { CollisionTest(3); }
     673       26644 : TEST(Collisions_5) { CollisionTest(5); }
     674       26644 : TEST(Collisions_7) { CollisionTest(7); }
     675       26644 : TEST(Resize) { CollisionTest(9, false, true); }
     676       26644 : TEST(Rehash) { CollisionTest(11, true, false); }
     677             : 
     678       26644 : TEST(ExplicitGC) {
     679           5 :   IdentityMapTester t;
     680             :   Handle<Object> num_keys[] = {t.num(2.1), t.num(2.4), t.num(3.3), t.num(4.3),
     681             :                                t.num(7.5), t.num(6.4), t.num(7.3), t.num(8.3),
     682          50 :                                t.num(8.9), t.num(10.4)};
     683             : 
     684             :   // Insert some objects that should be in new space.
     685         105 :   for (size_t i = 0; i < arraysize(num_keys); i++) {
     686          50 :     t.map.Set(num_keys[i], &num_keys[i]);
     687             :   }
     688             : 
     689             :   // Do an explicit, real GC.
     690           5 :   t.heap()->CollectGarbage(i::NEW_SPACE, i::GarbageCollectionReason::kTesting);
     691             : 
     692             :   // Check that searching for the numbers finds the same values.
     693         105 :   for (size_t i = 0; i < arraysize(num_keys); i++) {
     694          50 :     t.CheckFind(num_keys[i], &num_keys[i]);
     695          50 :     t.CheckGet(num_keys[i], &num_keys[i]);
     696             :   }
     697           5 : }
     698             : 
     699       26644 : TEST(CanonicalHandleScope) {
     700             :   Isolate* isolate = CcTest::i_isolate();
     701           5 :   Heap* heap = CcTest::heap();
     702             :   HandleScope outer(isolate);
     703          10 :   CanonicalHandleScope outer_canonical(isolate);
     704             : 
     705             :   // Deduplicate smi handles.
     706             :   std::vector<Handle<Object>> smi_handles;
     707        1005 :   for (int i = 0; i < 100; i++) {
     708         500 :     smi_handles.push_back(Handle<Object>(Smi::FromInt(i), isolate));
     709             :   }
     710           5 :   Address* next_handle = isolate->handle_scope_data()->next;
     711        1005 :   for (int i = 0; i < 100; i++) {
     712             :     Handle<Object> new_smi = Handle<Object>(Smi::FromInt(i), isolate);
     713         500 :     Handle<Object> old_smi = smi_handles[i];
     714         500 :     CHECK_EQ(new_smi.location(), old_smi.location());
     715             :   }
     716             :   // Check that no new handles have been allocated.
     717           5 :   CHECK_EQ(next_handle, isolate->handle_scope_data()->next);
     718             : 
     719             :   // Deduplicate root list items.
     720             :   Handle<String> empty_string(ReadOnlyRoots(heap).empty_string(), isolate);
     721             :   Handle<Map> free_space_map(ReadOnlyRoots(heap).free_space_map(), isolate);
     722             :   Handle<Symbol> uninitialized_symbol(
     723             :       ReadOnlyRoots(heap).uninitialized_symbol(), isolate);
     724           5 :   CHECK_EQ(isolate->factory()->empty_string().location(),
     725             :            empty_string.location());
     726           5 :   CHECK_EQ(isolate->factory()->free_space_map().location(),
     727             :            free_space_map.location());
     728           5 :   CHECK_EQ(isolate->factory()->uninitialized_symbol().location(),
     729             :            uninitialized_symbol.location());
     730             :   // Check that no new handles have been allocated.
     731           5 :   CHECK_EQ(next_handle, isolate->handle_scope_data()->next);
     732             : 
     733             :   // Test ordinary heap objects.
     734           5 :   Handle<HeapNumber> number1 = isolate->factory()->NewHeapNumber(3.3);
     735             :   Handle<String> string1 =
     736           5 :       isolate->factory()->NewStringFromAsciiChecked("test");
     737           5 :   next_handle = isolate->handle_scope_data()->next;
     738             :   Handle<HeapNumber> number2(*number1, isolate);
     739             :   Handle<String> string2(*string1, isolate);
     740           5 :   CHECK_EQ(number1.location(), number2.location());
     741           5 :   CHECK_EQ(string1.location(), string2.location());
     742           5 :   CcTest::CollectAllGarbage();
     743             :   Handle<HeapNumber> number3(*number2, isolate);
     744             :   Handle<String> string3(*string2, isolate);
     745           5 :   CHECK_EQ(number1.location(), number3.location());
     746           5 :   CHECK_EQ(string1.location(), string3.location());
     747             :   // Check that no new handles have been allocated.
     748           5 :   CHECK_EQ(next_handle, isolate->handle_scope_data()->next);
     749             : 
     750             :   // Inner handle scope do not create canonical handles.
     751             :   {
     752             :     HandleScope inner(isolate);
     753             :     Handle<HeapNumber> number4(*number1, isolate);
     754             :     Handle<String> string4(*string1, isolate);
     755           5 :     CHECK_NE(number1.location(), number4.location());
     756           5 :     CHECK_NE(string1.location(), string4.location());
     757             : 
     758             :     // Nested canonical scope does not conflict with outer canonical scope,
     759             :     // but does not canonicalize across scopes.
     760          10 :     CanonicalHandleScope inner_canonical(isolate);
     761             :     Handle<HeapNumber> number5(*number4, isolate);
     762             :     Handle<String> string5(*string4, isolate);
     763           5 :     CHECK_NE(number4.location(), number5.location());
     764           5 :     CHECK_NE(string4.location(), string5.location());
     765           5 :     CHECK_NE(number1.location(), number5.location());
     766           5 :     CHECK_NE(string1.location(), string5.location());
     767             : 
     768             :     Handle<HeapNumber> number6(*number1, isolate);
     769             :     Handle<String> string6(*string1, isolate);
     770           5 :     CHECK_NE(number4.location(), number6.location());
     771           5 :     CHECK_NE(string4.location(), string6.location());
     772           5 :     CHECK_NE(number1.location(), number6.location());
     773           5 :     CHECK_NE(string1.location(), string6.location());
     774           5 :     CHECK_EQ(number5.location(), number6.location());
     775           5 :     CHECK_EQ(string5.location(), string6.location());
     776             :   }
     777           5 : }
     778             : 
     779       26644 : TEST(GCShortCutting) {
     780             :   ManualGCScope manual_gc_scope;
     781           5 :   IdentityMapTester t;
     782             :   Isolate* isolate = CcTest::i_isolate();
     783             :   Factory* factory = isolate->factory();
     784             :   const int kDummyValue = 0;
     785             : 
     786         165 :   for (int i = 0; i < 16; i++) {
     787             :     // Insert a varying number of Smis as padding to ensure some tests straddle
     788             :     // a boundary where the thin string short cutting will cause size_ to be
     789             :     // greater to capacity_ if not corrected by IdentityMap
     790             :     // (see crbug.com/704132).
     791        1280 :     for (int j = 0; j < i; j++) {
     792         600 :       t.map.Set(t.smi(j), reinterpret_cast<void*>(kDummyValue));
     793             :     }
     794             : 
     795             :     Handle<String> thin_string =
     796          80 :         factory->NewStringFromAsciiChecked("thin_string");
     797             :     Handle<String> internalized_string =
     798          80 :         factory->InternalizeString(thin_string);
     799             :     DCHECK_IMPLIES(FLAG_thin_strings, thin_string->IsThinString());
     800             :     DCHECK_NE(*thin_string, *internalized_string);
     801             : 
     802             :     // Insert both keys into the map.
     803             :     t.map.Set(thin_string, &thin_string);
     804             :     t.map.Set(internalized_string, &internalized_string);
     805             : 
     806             :     // Do an explicit, real GC, this should short-cut the thin string to point
     807             :     // to the internalized string.
     808             :     t.heap()->CollectGarbage(i::NEW_SPACE,
     809          80 :                              i::GarbageCollectionReason::kTesting);
     810             :     DCHECK_IMPLIES(FLAG_thin_strings && !FLAG_optimize_for_size,
     811             :                    *thin_string == *internalized_string);
     812             : 
     813             :     // Check that getting the object points to one of the handles.
     814             :     void** thin_string_entry = t.map.Get(thin_string);
     815          80 :     CHECK(*thin_string_entry == &thin_string ||
     816             :           *thin_string_entry == &internalized_string);
     817             :     void** internalized_string_entry = t.map.Get(internalized_string);
     818          80 :     CHECK(*internalized_string_entry == &thin_string ||
     819             :           *internalized_string_entry == &internalized_string);
     820             : 
     821             :     // Trigger resize.
     822        2640 :     for (int j = 0; j < 16; j++) {
     823        1280 :       t.map.Set(t.smi(j + 16), reinterpret_cast<void*>(kDummyValue));
     824             :     }
     825             :     t.map.Clear();
     826             :   }
     827           5 : }
     828             : 
     829             : }  // namespace internal
     830       79917 : }  // namespace v8

Generated by: LCOV version 1.10