LCOV - code coverage report
Current view: top level - test/cctest - test-dictionary.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 107 107 100.0 %
Date: 2017-10-20 Functions: 10 10 100.0 %

          Line data    Source code
       1             : // Copyright 2011 the V8 project authors. All rights reserved.
       2             : // Redistribution and use in source and binary forms, with or without
       3             : // modification, are permitted provided that the following conditions are
       4             : // met:
       5             : //
       6             : //     * Redistributions of source code must retain the above copyright
       7             : //       notice, this list of conditions and the following disclaimer.
       8             : //     * Redistributions in binary form must reproduce the above
       9             : //       copyright notice, this list of conditions and the following
      10             : //       disclaimer in the documentation and/or other materials provided
      11             : //       with the distribution.
      12             : //     * Neither the name of Google Inc. nor the names of its
      13             : //       contributors may be used to endorse or promote products derived
      14             : //       from this software without specific prior written permission.
      15             : //
      16             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      17             : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      18             : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      19             : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      20             : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      21             : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      22             : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      23             : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      24             : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      25             : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      26             : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             : 
      28             : #include "src/v8.h"
      29             : #include "test/cctest/cctest.h"
      30             : 
      31             : #include "src/api.h"
      32             : #include "src/builtins/builtins-constructor.h"
      33             : #include "src/debug/debug.h"
      34             : #include "src/execution.h"
      35             : #include "src/factory.h"
      36             : #include "src/global-handles.h"
      37             : #include "src/heap/spaces.h"
      38             : #include "src/macro-assembler.h"
      39             : #include "src/objects-inl.h"
      40             : #include "test/cctest/heap/heap-utils.h"
      41             : 
      42             : namespace v8 {
      43             : namespace internal {
      44             : 
      45             : namespace {
      46             : 
      47             : 
      48             : template<typename HashMap>
      49           6 : static void TestHashMap(Handle<HashMap> table) {
      50             :   Isolate* isolate = CcTest::i_isolate();
      51             :   Factory* factory = isolate->factory();
      52             : 
      53           6 :   Handle<JSObject> a = factory->NewJSArray(7);
      54           6 :   Handle<JSObject> b = factory->NewJSArray(11);
      55           6 :   table = HashMap::Put(table, a, b);
      56           6 :   CHECK_EQ(1, table->NumberOfElements());
      57           6 :   CHECK_EQ(table->Lookup(a), *b);
      58             :   // When the key does not exist in the map, Lookup returns the hole.
      59          12 :   CHECK_EQ(table->Lookup(b), CcTest::heap()->the_hole_value());
      60             : 
      61             :   // Keys still have to be valid after objects were moved.
      62           6 :   CcTest::CollectGarbage(NEW_SPACE);
      63           6 :   CHECK_EQ(1, table->NumberOfElements());
      64           6 :   CHECK_EQ(table->Lookup(a), *b);
      65          12 :   CHECK_EQ(table->Lookup(b), CcTest::heap()->the_hole_value());
      66             : 
      67             :   // Keys that are overwritten should not change number of elements.
      68          12 :   table = HashMap::Put(table, a, factory->NewJSArray(13));
      69           6 :   CHECK_EQ(1, table->NumberOfElements());
      70           6 :   CHECK_NE(table->Lookup(a), *b);
      71             : 
      72             :   // Keys that have been removed are mapped to the hole.
      73           6 :   bool was_present = false;
      74           6 :   table = HashMap::Remove(table, a, &was_present);
      75           6 :   CHECK(was_present);
      76           6 :   CHECK_EQ(0, table->NumberOfElements());
      77          12 :   CHECK_EQ(table->Lookup(a), CcTest::heap()->the_hole_value());
      78             : 
      79             :   // Keys should map back to their respective values and also should get
      80             :   // an identity hash code generated.
      81         606 :   for (int i = 0; i < 100; i++) {
      82         600 :     Handle<JSReceiver> key = factory->NewJSArray(7);
      83         600 :     Handle<JSObject> value = factory->NewJSArray(11);
      84         600 :     table = HashMap::Put(table, key, value);
      85        1200 :     CHECK_EQ(table->NumberOfElements(), i + 1);
      86         600 :     CHECK_NE(table->FindEntry(key), HashMap::kNotFound);
      87         600 :     CHECK_EQ(table->Lookup(key), *value);
      88        1200 :     CHECK(key->GetIdentityHash(isolate)->IsSmi());
      89             :   }
      90             : 
      91             :   // Keys never added to the map which already have an identity hash
      92             :   // code should not be found.
      93         600 :   for (int i = 0; i < 100; i++) {
      94         600 :     Handle<JSReceiver> key = factory->NewJSArray(7);
      95        1200 :     CHECK(key->GetOrCreateIdentityHash(isolate)->IsSmi());
      96         600 :     CHECK_EQ(table->FindEntry(key), HashMap::kNotFound);
      97        1200 :     CHECK_EQ(table->Lookup(key), CcTest::heap()->the_hole_value());
      98        1200 :     CHECK(key->GetIdentityHash(isolate)->IsSmi());
      99             :   }
     100             : 
     101             :   // Keys that don't have an identity hash should not be found and also
     102             :   // should not get an identity hash code generated.
     103         600 :   for (int i = 0; i < 100; i++) {
     104         600 :     Handle<JSReceiver> key = factory->NewJSArray(7);
     105        1200 :     CHECK_EQ(table->Lookup(key), CcTest::heap()->the_hole_value());
     106         600 :     Object* identity_hash = key->GetIdentityHash(isolate);
     107         600 :     CHECK_EQ(CcTest::heap()->undefined_value(), identity_hash);
     108             :   }
     109           6 : }
     110             : 
     111             : 
     112       23724 : TEST(HashMap) {
     113           6 :   LocalContext context;
     114          12 :   v8::HandleScope scope(context->GetIsolate());
     115             :   Isolate* isolate = CcTest::i_isolate();
     116          12 :   TestHashMap(ObjectHashTable::New(isolate, 23));
     117           6 : }
     118             : 
     119             : template <typename HashSet>
     120           6 : static void TestHashSet(Handle<HashSet> table) {
     121             :   Isolate* isolate = CcTest::i_isolate();
     122             :   Factory* factory = isolate->factory();
     123             : 
     124           6 :   Handle<JSObject> a = factory->NewJSArray(7);
     125           6 :   Handle<JSObject> b = factory->NewJSArray(11);
     126           6 :   table = HashSet::Add(table, a);
     127           6 :   CHECK_EQ(1, table->NumberOfElements());
     128           6 :   CHECK(table->Has(isolate, a));
     129           6 :   CHECK(!table->Has(isolate, b));
     130             : 
     131             :   // Keys still have to be valid after objects were moved.
     132           6 :   CcTest::CollectGarbage(NEW_SPACE);
     133           6 :   CHECK_EQ(1, table->NumberOfElements());
     134           6 :   CHECK(table->Has(isolate, a));
     135           6 :   CHECK(!table->Has(isolate, b));
     136             : 
     137             :   // Keys that are overwritten should not change number of elements.
     138           6 :   table = HashSet::Add(table, a);
     139           6 :   CHECK_EQ(1, table->NumberOfElements());
     140           6 :   CHECK(table->Has(isolate, a));
     141           6 :   CHECK(!table->Has(isolate, b));
     142             : 
     143             :   // Keys that have been removed are mapped to the hole.
     144             :   // TODO(cbruni): not implemented yet.
     145             :   // bool was_present = false;
     146             :   // table = HashSet::Remove(table, a, &was_present);
     147             :   // CHECK(was_present);
     148             :   // CHECK_EQ(0, table->NumberOfElements());
     149             :   // CHECK(!table->Has(a));
     150             :   // CHECK(!table->Has(b));
     151             : 
     152             :   // Keys should map back to their respective values and also should get
     153             :   // an identity hash code generated.
     154         600 :   for (int i = 0; i < 100; i++) {
     155         600 :     Handle<JSReceiver> key = factory->NewJSArray(7);
     156         600 :     table = HashSet::Add(table, key);
     157        1200 :     CHECK_EQ(table->NumberOfElements(), i + 2);
     158         600 :     CHECK(table->Has(isolate, key));
     159        1200 :     CHECK(key->GetIdentityHash(isolate)->IsSmi());
     160             :   }
     161             : 
     162             :   // Keys never added to the map which already have an identity hash
     163             :   // code should not be found.
     164         600 :   for (int i = 0; i < 100; i++) {
     165         600 :     Handle<JSReceiver> key = factory->NewJSArray(7);
     166        1200 :     CHECK(key->GetOrCreateIdentityHash(isolate)->IsSmi());
     167         600 :     CHECK(!table->Has(isolate, key));
     168        1200 :     CHECK(key->GetIdentityHash(isolate)->IsSmi());
     169             :   }
     170             : 
     171             :   // Keys that don't have an identity hash should not be found and also
     172             :   // should not get an identity hash code generated.
     173         600 :   for (int i = 0; i < 100; i++) {
     174         600 :     Handle<JSReceiver> key = factory->NewJSArray(7);
     175         600 :     CHECK(!table->Has(isolate, key));
     176         600 :     Object* identity_hash = key->GetIdentityHash(isolate);
     177         600 :     CHECK_EQ(CcTest::heap()->undefined_value(), identity_hash);
     178             :   }
     179           6 : }
     180             : 
     181       23724 : TEST(HashSet) {
     182           6 :   LocalContext context;
     183          12 :   v8::HandleScope scope(context->GetIsolate());
     184             :   Isolate* isolate = CcTest::i_isolate();
     185          12 :   TestHashSet(ObjectHashSet::New(isolate, 23));
     186           6 : }
     187             : 
     188             : class ObjectHashTableTest: public ObjectHashTable {
     189             :  public:
     190        2298 :   void insert(int entry, int key, int value) {
     191             :     set(EntryToIndex(entry), Smi::FromInt(key));
     192             :     set(EntryToIndex(entry) + 1, Smi::FromInt(value));
     193        2298 :   }
     194             : 
     195        2298 :   int lookup(int key) {
     196             :     Handle<Object> key_obj(Smi::FromInt(key), GetIsolate());
     197        4596 :     return Smi::ToInt(Lookup(key_obj));
     198             :   }
     199             : 
     200             :   int capacity() {
     201             :     return Capacity();
     202             :   }
     203             : };
     204             : 
     205             : 
     206       23724 : TEST(HashTableRehash) {
     207           6 :   LocalContext context;
     208             :   Isolate* isolate = CcTest::i_isolate();
     209          12 :   v8::HandleScope scope(context->GetIsolate());
     210             :   // Test almost filled table.
     211             :   {
     212           6 :     Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 100);
     213             :     ObjectHashTableTest* t = reinterpret_cast<ObjectHashTableTest*>(*table);
     214             :     int capacity = t->capacity();
     215        1536 :     for (int i = 0; i < capacity - 1; i++) {
     216        1530 :       t->insert(i, i * i, i);
     217             :     }
     218           6 :     t->Rehash();
     219        1536 :     for (int i = 0; i < capacity - 1; i++) {
     220        1530 :       CHECK_EQ(i, t->lookup(i * i));
     221             :     }
     222             :   }
     223             :   // Test half-filled table.
     224             :   {
     225           6 :     Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 100);
     226             :     ObjectHashTableTest* t = reinterpret_cast<ObjectHashTableTest*>(*table);
     227             :     int capacity = t->capacity();
     228         774 :     for (int i = 0; i < capacity / 2; i++) {
     229         768 :       t->insert(i, i * i, i);
     230             :     }
     231           6 :     t->Rehash();
     232         774 :     for (int i = 0; i < capacity / 2; i++) {
     233         768 :       CHECK_EQ(i, t->lookup(i * i));
     234             :     }
     235           6 :   }
     236           6 : }
     237             : 
     238             : 
     239             : #ifdef DEBUG
     240             : template<class HashSet>
     241             : static void TestHashSetCausesGC(Handle<HashSet> table) {
     242             :   Isolate* isolate = CcTest::i_isolate();
     243             :   Factory* factory = isolate->factory();
     244             : 
     245             :   Handle<JSObject> key = factory->NewJSArray(0);
     246             : 
     247             :   // Simulate a full heap so that generating an identity hash code
     248             :   // in subsequent calls will request GC.
     249             :   heap::SimulateFullSpace(CcTest::heap()->new_space());
     250             :   heap::SimulateFullSpace(CcTest::heap()->old_space());
     251             : 
     252             :   // Calling Contains() should not cause GC ever.
     253             :   int gc_count = isolate->heap()->gc_count();
     254             :   CHECK(!table->Contains(key));
     255             :   CHECK(gc_count == isolate->heap()->gc_count());
     256             : 
     257             :   // Calling Remove() will not cause GC in this case.
     258             :   bool was_present = false;
     259             :   table = HashSet::Remove(table, key, &was_present);
     260             :   CHECK(!was_present);
     261             :   CHECK(gc_count == isolate->heap()->gc_count());
     262             : 
     263             :   // Calling Add() should cause GC.
     264             :   table = HashSet::Add(table, key);
     265             :   CHECK(gc_count < isolate->heap()->gc_count());
     266             : }
     267             : #endif
     268             : 
     269             : 
     270             : #ifdef DEBUG
     271             : template <class HashMap>
     272             : static void TestHashMapDoesNotCauseGC(Handle<HashMap> table) {
     273             :   Isolate* isolate = CcTest::i_isolate();
     274             :   Factory* factory = isolate->factory();
     275             : 
     276             :   Handle<JSObject> key = factory->NewJSArray(0);
     277             : 
     278             :   // Even though we simulate a full heap, generating an identity hash
     279             :   // code in subsequent calls will not request GC.
     280             :   heap::SimulateFullSpace(CcTest::heap()->new_space());
     281             :   heap::SimulateFullSpace(CcTest::heap()->old_space());
     282             : 
     283             :   // Calling Lookup() should not cause GC ever.
     284             :   CHECK(table->Lookup(key)->IsTheHole(isolate));
     285             : 
     286             :   // Calling Put() should request GC by returning a failure.
     287             :   int gc_count = isolate->heap()->gc_count();
     288             :   HashMap::Put(table, key, key);
     289             :   CHECK(gc_count == isolate->heap()->gc_count());
     290             : }
     291             : 
     292             : 
     293             : TEST(ObjectHashTableCausesGC) {
     294             :   i::FLAG_stress_compaction = false;
     295             :   LocalContext context;
     296             :   v8::HandleScope scope(context->GetIsolate());
     297             :   Isolate* isolate = CcTest::i_isolate();
     298             :   TestHashMapDoesNotCauseGC(ObjectHashTable::New(isolate, 1));
     299             : }
     300             : #endif
     301             : 
     302       23724 : TEST(MaximumClonedShallowObjectProperties) {
     303             :   // Assert that a NameDictionary with kMaximumClonedShallowObjectProperties is
     304             :   // not in large-object space.
     305             :   const int max_capacity = NameDictionary::ComputeCapacity(
     306             :       ConstructorBuiltins::kMaximumClonedShallowObjectProperties);
     307           6 :   const int max_literal_entry = max_capacity / NameDictionary::kEntrySize;
     308             :   const int max_literal_index = NameDictionary::EntryToIndex(max_literal_entry);
     309           6 :   CHECK_LE(NameDictionary::OffsetOfElementAt(max_literal_index),
     310             :            kMaxRegularHeapObjectSize);
     311           6 : }
     312             : 
     313             : }  // namespace
     314             : 
     315             : }  // namespace internal
     316       71154 : }  // namespace v8

Generated by: LCOV version 1.10