| OLD | NEW | 
|    1 // Copyright 2011 the V8 project authors. All rights reserved. |    1 // Copyright 2011 the V8 project authors. All rights reserved. | 
|    2 // Redistribution and use in source and binary forms, with or without |    2 // Redistribution and use in source and binary forms, with or without | 
|    3 // modification, are permitted provided that the following conditions are |    3 // modification, are permitted provided that the following conditions are | 
|    4 // met: |    4 // met: | 
|    5 // |    5 // | 
|    6 //     * Redistributions of source code must retain the above copyright |    6 //     * Redistributions of source code must retain the above copyright | 
|    7 //       notice, this list of conditions and the following disclaimer. |    7 //       notice, this list of conditions and the following disclaimer. | 
|    8 //     * Redistributions in binary form must reproduce the above |    8 //     * Redistributions in binary form must reproduce the above | 
|    9 //       copyright notice, this list of conditions and the following |    9 //       copyright notice, this list of conditions and the following | 
|   10 //       disclaimer in the documentation and/or other materials provided |   10 //       disclaimer in the documentation and/or other materials provided | 
| (...skipping 20 matching lines...) Expand all  Loading... | 
|   31 #include "debug.h" |   31 #include "debug.h" | 
|   32 #include "execution.h" |   32 #include "execution.h" | 
|   33 #include "factory.h" |   33 #include "factory.h" | 
|   34 #include "macro-assembler.h" |   34 #include "macro-assembler.h" | 
|   35 #include "objects.h" |   35 #include "objects.h" | 
|   36 #include "global-handles.h" |   36 #include "global-handles.h" | 
|   37 #include "cctest.h" |   37 #include "cctest.h" | 
|   38  |   38  | 
|   39 using namespace v8::internal; |   39 using namespace v8::internal; | 
|   40  |   40  | 
 |   41 namespace { | 
|   41  |   42  | 
|   42 TEST(ObjectHashTable) { |   43  | 
|   43   LocalContext context; |   44 template<typename HashMap> | 
 |   45 static void TestHashMap(Handle<HashMap> table) { | 
|   44   Isolate* isolate = CcTest::i_isolate(); |   46   Isolate* isolate = CcTest::i_isolate(); | 
|   45   Factory* factory = isolate->factory(); |   47   Factory* factory = isolate->factory(); | 
|   46   v8::HandleScope scope(context->GetIsolate()); |   48  | 
|   47   Handle<ObjectHashTable> table = factory->NewObjectHashTable(23); |  | 
|   48   Handle<JSObject> a = factory->NewJSArray(7); |   49   Handle<JSObject> a = factory->NewJSArray(7); | 
|   49   Handle<JSObject> b = factory->NewJSArray(11); |   50   Handle<JSObject> b = factory->NewJSArray(11); | 
|   50   table = ObjectHashTable::Put(table, a, b); |   51   table = HashMap::Put(table, a, b); | 
|   51   CHECK_EQ(table->NumberOfElements(), 1); |   52   CHECK_EQ(table->NumberOfElements(), 1); | 
|   52   CHECK_EQ(table->Lookup(*a), *b); |   53   CHECK_EQ(table->Lookup(*a), *b); | 
|   53   CHECK_EQ(table->Lookup(*b), CcTest::heap()->the_hole_value()); |   54   CHECK_EQ(table->Lookup(*b), CcTest::heap()->the_hole_value()); | 
|   54  |   55  | 
|   55   // Keys still have to be valid after objects were moved. |   56   // Keys still have to be valid after objects were moved. | 
|   56   CcTest::heap()->CollectGarbage(NEW_SPACE); |   57   CcTest::heap()->CollectGarbage(NEW_SPACE); | 
|   57   CHECK_EQ(table->NumberOfElements(), 1); |   58   CHECK_EQ(table->NumberOfElements(), 1); | 
|   58   CHECK_EQ(table->Lookup(*a), *b); |   59   CHECK_EQ(table->Lookup(*a), *b); | 
|   59   CHECK_EQ(table->Lookup(*b), CcTest::heap()->the_hole_value()); |   60   CHECK_EQ(table->Lookup(*b), CcTest::heap()->the_hole_value()); | 
|   60  |   61  | 
|   61   // Keys that are overwritten should not change number of elements. |   62   // Keys that are overwritten should not change number of elements. | 
|   62   table = ObjectHashTable::Put(table, a, factory->NewJSArray(13)); |   63   table = HashMap::Put(table, a, factory->NewJSArray(13)); | 
|   63   CHECK_EQ(table->NumberOfElements(), 1); |   64   CHECK_EQ(table->NumberOfElements(), 1); | 
|   64   CHECK_NE(table->Lookup(*a), *b); |   65   CHECK_NE(table->Lookup(*a), *b); | 
|   65  |   66  | 
|   66   // Keys mapped to the hole should be removed permanently. |   67   // Keys mapped to the hole should be removed permanently. | 
|   67   table = ObjectHashTable::Put(table, a, factory->the_hole_value()); |   68   table = HashMap::Put(table, a, factory->the_hole_value()); | 
|   68   CHECK_EQ(table->NumberOfElements(), 0); |   69   CHECK_EQ(table->NumberOfElements(), 0); | 
|   69   CHECK_EQ(table->NumberOfDeletedElements(), 1); |  | 
|   70   CHECK_EQ(table->Lookup(*a), CcTest::heap()->the_hole_value()); |   70   CHECK_EQ(table->Lookup(*a), CcTest::heap()->the_hole_value()); | 
|   71  |   71  | 
|   72   // Keys should map back to their respective values and also should get |   72   // Keys should map back to their respective values and also should get | 
|   73   // an identity hash code generated. |   73   // an identity hash code generated. | 
|   74   for (int i = 0; i < 100; i++) { |   74   for (int i = 0; i < 100; i++) { | 
|   75     Handle<JSReceiver> key = factory->NewJSArray(7); |   75     Handle<JSReceiver> key = factory->NewJSArray(7); | 
|   76     Handle<JSObject> value = factory->NewJSArray(11); |   76     Handle<JSObject> value = factory->NewJSArray(11); | 
|   77     table = ObjectHashTable::Put(table, key, value); |   77     table = HashMap::Put(table, key, value); | 
|   78     CHECK_EQ(table->NumberOfElements(), i + 1); |   78     CHECK_EQ(table->NumberOfElements(), i + 1); | 
|   79     CHECK_NE(table->FindEntry(*key), ObjectHashTable::kNotFound); |   79     CHECK_NE(table->FindEntry(*key), HashMap::kNotFound); | 
|   80     CHECK_EQ(table->Lookup(*key), *value); |   80     CHECK_EQ(table->Lookup(*key), *value); | 
|   81     CHECK(key->GetIdentityHash()->IsSmi()); |   81     CHECK(key->GetIdentityHash()->IsSmi()); | 
|   82   } |   82   } | 
|   83  |   83  | 
|   84   // Keys never added to the map which already have an identity hash |   84   // Keys never added to the map which already have an identity hash | 
|   85   // code should not be found. |   85   // code should not be found. | 
|   86   for (int i = 0; i < 100; i++) { |   86   for (int i = 0; i < 100; i++) { | 
|   87     Handle<JSReceiver> key = factory->NewJSArray(7); |   87     Handle<JSReceiver> key = factory->NewJSArray(7); | 
|   88     CHECK(JSReceiver::GetOrCreateIdentityHash(key)->IsSmi()); |   88     CHECK(JSReceiver::GetOrCreateIdentityHash(key)->IsSmi()); | 
|   89     CHECK_EQ(table->FindEntry(*key), ObjectHashTable::kNotFound); |   89     CHECK_EQ(table->FindEntry(*key), HashMap::kNotFound); | 
|   90     CHECK_EQ(table->Lookup(*key), CcTest::heap()->the_hole_value()); |   90     CHECK_EQ(table->Lookup(*key), CcTest::heap()->the_hole_value()); | 
|   91     CHECK(key->GetIdentityHash()->IsSmi()); |   91     CHECK(key->GetIdentityHash()->IsSmi()); | 
|   92   } |   92   } | 
|   93  |   93  | 
|   94   // Keys that don't have an identity hash should not be found and also |   94   // Keys that don't have an identity hash should not be found and also | 
|   95   // should not get an identity hash code generated. |   95   // should not get an identity hash code generated. | 
|   96   for (int i = 0; i < 100; i++) { |   96   for (int i = 0; i < 100; i++) { | 
|   97     Handle<JSReceiver> key = factory->NewJSArray(7); |   97     Handle<JSReceiver> key = factory->NewJSArray(7); | 
|   98     CHECK_EQ(table->Lookup(*key), CcTest::heap()->the_hole_value()); |   98     CHECK_EQ(table->Lookup(*key), CcTest::heap()->the_hole_value()); | 
|   99     CHECK_EQ(key->GetIdentityHash(), |   99     CHECK_EQ(key->GetIdentityHash(), | 
|  100              CcTest::heap()->undefined_value()); |  100              CcTest::heap()->undefined_value()); | 
|  101   } |  101   } | 
|  102 } |  102 } | 
|  103  |  103  | 
|  104  |  104  | 
 |  105 TEST(HashMap) { | 
 |  106   LocalContext context; | 
 |  107   v8::HandleScope scope(context->GetIsolate()); | 
 |  108   Isolate* isolate = CcTest::i_isolate(); | 
 |  109   TestHashMap(isolate->factory()->NewObjectHashTable(23)); | 
 |  110   TestHashMap(isolate->factory()->NewOrderedHashMap()); | 
 |  111 } | 
 |  112  | 
 |  113  | 
|  105 class ObjectHashTableTest: public ObjectHashTable { |  114 class ObjectHashTableTest: public ObjectHashTable { | 
|  106  public: |  115  public: | 
|  107   void insert(int entry, int key, int value) { |  116   void insert(int entry, int key, int value) { | 
|  108     set(EntryToIndex(entry), Smi::FromInt(key)); |  117     set(EntryToIndex(entry), Smi::FromInt(key)); | 
|  109     set(EntryToIndex(entry) + 1, Smi::FromInt(value)); |  118     set(EntryToIndex(entry) + 1, Smi::FromInt(value)); | 
|  110   } |  119   } | 
|  111  |  120  | 
|  112   int lookup(int key) { |  121   int lookup(int key) { | 
|  113     return Smi::cast(Lookup(Smi::FromInt(key)))->value(); |  122     return Smi::cast(Lookup(Smi::FromInt(key)))->value(); | 
|  114   } |  123   } | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  147     } |  156     } | 
|  148     t->Rehash(Smi::FromInt(0)); |  157     t->Rehash(Smi::FromInt(0)); | 
|  149     for (int i = 0; i < capacity / 2; i++) { |  158     for (int i = 0; i < capacity / 2; i++) { | 
|  150       CHECK_EQ(i, t->lookup(i * i)); |  159       CHECK_EQ(i, t->lookup(i * i)); | 
|  151     } |  160     } | 
|  152   } |  161   } | 
|  153 } |  162 } | 
|  154  |  163  | 
|  155  |  164  | 
|  156 #ifdef DEBUG |  165 #ifdef DEBUG | 
|  157 TEST(ObjectHashSetCausesGC) { |  166 template<class HashSet> | 
|  158   i::FLAG_stress_compaction = false; |  167 static void TestHashSetCausesGC(Handle<HashSet> table) { | 
|  159   LocalContext context; |  | 
|  160   Isolate* isolate = CcTest::i_isolate(); |  168   Isolate* isolate = CcTest::i_isolate(); | 
|  161   Factory* factory = isolate->factory(); |  169   Factory* factory = isolate->factory(); | 
|  162   v8::HandleScope scope(context->GetIsolate()); |  170  | 
|  163   Handle<ObjectHashSet> table = factory->NewObjectHashSet(1); |  | 
|  164   Handle<JSObject> key = factory->NewJSArray(0); |  171   Handle<JSObject> key = factory->NewJSArray(0); | 
|  165   v8::Handle<v8::Object> key_obj = v8::Utils::ToLocal(key); |  172   v8::Handle<v8::Object> key_obj = v8::Utils::ToLocal(key); | 
|  166  |  173  | 
|  167   // Force allocation of hash table backing store for hidden properties. |  174   // Force allocation of hash table backing store for hidden properties. | 
|  168   key_obj->SetHiddenValue(v8_str("key 1"), v8_str("val 1")); |  175   key_obj->SetHiddenValue(v8_str("key 1"), v8_str("val 1")); | 
|  169   key_obj->SetHiddenValue(v8_str("key 2"), v8_str("val 2")); |  176   key_obj->SetHiddenValue(v8_str("key 2"), v8_str("val 2")); | 
|  170   key_obj->SetHiddenValue(v8_str("key 3"), v8_str("val 3")); |  177   key_obj->SetHiddenValue(v8_str("key 3"), v8_str("val 3")); | 
|  171  |  178  | 
|  172   // Simulate a full heap so that generating an identity hash code |  179   // Simulate a full heap so that generating an identity hash code | 
|  173   // in subsequent calls will request GC. |  180   // in subsequent calls will request GC. | 
|  174   SimulateFullSpace(CcTest::heap()->new_space()); |  181   SimulateFullSpace(CcTest::heap()->new_space()); | 
|  175   SimulateFullSpace(CcTest::heap()->old_pointer_space()); |  182   SimulateFullSpace(CcTest::heap()->old_pointer_space()); | 
|  176  |  183  | 
|  177   // Calling Contains() should not cause GC ever. |  184   // Calling Contains() should not cause GC ever. | 
|  178   int gc_count = isolate->heap()->gc_count(); |  185   int gc_count = isolate->heap()->gc_count(); | 
|  179   CHECK(!table->Contains(*key)); |  186   CHECK(!table->Contains(*key)); | 
|  180   CHECK(gc_count == isolate->heap()->gc_count()); |  187   CHECK(gc_count == isolate->heap()->gc_count()); | 
|  181  |  188  | 
|  182   // Calling Remove() will not cause GC in this case. |  189   // Calling Remove() will not cause GC in this case. | 
|  183   table = ObjectHashSet::Remove(table, key); |  190   table = HashSet::Remove(table, key); | 
|  184   CHECK(gc_count == isolate->heap()->gc_count()); |  191   CHECK(gc_count == isolate->heap()->gc_count()); | 
|  185  |  192  | 
|  186   // Calling Add() should cause GC. |  193   // Calling Add() should cause GC. | 
|  187   table = ObjectHashSet::Add(table, key); |  194   table = HashSet::Add(table, key); | 
|  188   CHECK(gc_count < isolate->heap()->gc_count()); |  195   CHECK(gc_count < isolate->heap()->gc_count()); | 
|  189 } |  196 } | 
 |  197  | 
 |  198  | 
 |  199 TEST(ObjectHashSetCausesGC) { | 
 |  200   i::FLAG_stress_compaction = false; | 
 |  201   LocalContext context; | 
 |  202   v8::HandleScope scope(context->GetIsolate()); | 
 |  203   Isolate* isolate = CcTest::i_isolate(); | 
 |  204   TestHashSetCausesGC(isolate->factory()->NewObjectHashSet(1)); | 
 |  205   TestHashSetCausesGC(isolate->factory()->NewOrderedHashSet()); | 
 |  206 } | 
|  190 #endif |  207 #endif | 
|  191  |  208  | 
|  192  |  209  | 
|  193 #ifdef DEBUG |  210 #ifdef DEBUG | 
|  194 TEST(ObjectHashTableCausesGC) { |  211 template<class HashMap> | 
|  195   i::FLAG_stress_compaction = false; |  212 static void TestHashMapCausesGC(Handle<HashMap> table) { | 
|  196   LocalContext context; |  | 
|  197   Isolate* isolate = CcTest::i_isolate(); |  213   Isolate* isolate = CcTest::i_isolate(); | 
|  198   Factory* factory = isolate->factory(); |  214   Factory* factory = isolate->factory(); | 
|  199   v8::HandleScope scope(context->GetIsolate()); |  215  | 
|  200   Handle<ObjectHashTable> table = factory->NewObjectHashTable(1); |  | 
|  201   Handle<JSObject> key = factory->NewJSArray(0); |  216   Handle<JSObject> key = factory->NewJSArray(0); | 
|  202   v8::Handle<v8::Object> key_obj = v8::Utils::ToLocal(key); |  217   v8::Handle<v8::Object> key_obj = v8::Utils::ToLocal(key); | 
|  203  |  218  | 
|  204   // Force allocation of hash table backing store for hidden properties. |  219   // Force allocation of hash table backing store for hidden properties. | 
|  205   key_obj->SetHiddenValue(v8_str("key 1"), v8_str("val 1")); |  220   key_obj->SetHiddenValue(v8_str("key 1"), v8_str("val 1")); | 
|  206   key_obj->SetHiddenValue(v8_str("key 2"), v8_str("val 2")); |  221   key_obj->SetHiddenValue(v8_str("key 2"), v8_str("val 2")); | 
|  207   key_obj->SetHiddenValue(v8_str("key 3"), v8_str("val 3")); |  222   key_obj->SetHiddenValue(v8_str("key 3"), v8_str("val 3")); | 
|  208  |  223  | 
|  209   // Simulate a full heap so that generating an identity hash code |  224   // Simulate a full heap so that generating an identity hash code | 
|  210   // in subsequent calls will request GC. |  225   // in subsequent calls will request GC. | 
|  211   SimulateFullSpace(CcTest::heap()->new_space()); |  226   SimulateFullSpace(CcTest::heap()->new_space()); | 
|  212   SimulateFullSpace(CcTest::heap()->old_pointer_space()); |  227   SimulateFullSpace(CcTest::heap()->old_pointer_space()); | 
|  213  |  228  | 
|  214   // Calling Lookup() should not cause GC ever. |  229   // Calling Lookup() should not cause GC ever. | 
|  215   CHECK(table->Lookup(*key)->IsTheHole()); |  230   CHECK(table->Lookup(*key)->IsTheHole()); | 
|  216  |  231  | 
|  217   // Calling Put() should request GC by returning a failure. |  232   // Calling Put() should request GC by returning a failure. | 
|  218   int gc_count = isolate->heap()->gc_count(); |  233   int gc_count = isolate->heap()->gc_count(); | 
|  219   ObjectHashTable::Put(table, key, key); |  234   HashMap::Put(table, key, key); | 
|  220   CHECK(gc_count < isolate->heap()->gc_count()); |  235   CHECK(gc_count < isolate->heap()->gc_count()); | 
|  221 } |  236 } | 
 |  237  | 
 |  238  | 
 |  239 TEST(ObjectHashTableCausesGC) { | 
 |  240   i::FLAG_stress_compaction = false; | 
 |  241   LocalContext context; | 
 |  242   v8::HandleScope scope(context->GetIsolate()); | 
 |  243   Isolate* isolate = CcTest::i_isolate(); | 
 |  244   TestHashMapCausesGC(isolate->factory()->NewObjectHashTable(1)); | 
 |  245   TestHashMapCausesGC(isolate->factory()->NewOrderedHashMap()); | 
 |  246 } | 
|  222 #endif |  247 #endif | 
 |  248  | 
 |  249  | 
 |  250 } | 
| OLD | NEW |