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 "v8.h" 29 30 #include "api.h" 31 #include "debug.h" 32 #include "execution.h" 33 #include "factory.h" 34 #include "macro-assembler.h" 35 #include "objects.h" 36 #include "global-handles.h" 37 #include "cctest.h" 38 39 using namespace v8::internal; 40 41 42 TEST(ObjectHashTable) { 43 LocalContext context; 44 Isolate* isolate = Isolate::Current(); 45 Factory* factory = isolate->factory(); 46 v8::HandleScope scope(context->GetIsolate()); 47 Handle<ObjectHashTable> table = factory->NewObjectHashTable(23); 48 Handle<JSObject> a = factory->NewJSArray(7); 49 Handle<JSObject> b = factory->NewJSArray(11); 50 table = PutIntoObjectHashTable(table, a, b); 51 CHECK_EQ(table->NumberOfElements(), 1); 52 CHECK_EQ(table->Lookup(*a), *b); 53 CHECK_EQ(table->Lookup(*b), HEAP->the_hole_value()); 54 55 // Keys still have to be valid after objects were moved. 56 HEAP->CollectGarbage(NEW_SPACE); 57 CHECK_EQ(table->NumberOfElements(), 1); 58 CHECK_EQ(table->Lookup(*a), *b); 59 CHECK_EQ(table->Lookup(*b), HEAP->the_hole_value()); 60 61 // Keys that are overwritten should not change number of elements. 62 table = PutIntoObjectHashTable(table, a, factory->NewJSArray(13)); 63 CHECK_EQ(table->NumberOfElements(), 1); 64 CHECK_NE(table->Lookup(*a), *b); 65 66 // Keys mapped to the hole should be removed permanently. 67 table = PutIntoObjectHashTable(table, a, factory->the_hole_value()); 68 CHECK_EQ(table->NumberOfElements(), 0); 69 CHECK_EQ(table->NumberOfDeletedElements(), 1); 70 CHECK_EQ(table->Lookup(*a), HEAP->the_hole_value()); 71 72 // Keys should map back to their respective values and also should get 73 // an identity hash code generated. 74 for (int i = 0; i < 100; i++) { 75 Handle<JSObject> key = factory->NewJSArray(7); 76 Handle<JSObject> value = factory->NewJSArray(11); 77 table = PutIntoObjectHashTable(table, key, value); 78 CHECK_EQ(table->NumberOfElements(), i + 1); 79 CHECK_NE(table->FindEntry(*key), ObjectHashTable::kNotFound); 80 CHECK_EQ(table->Lookup(*key), *value); 81 CHECK(key->GetIdentityHash(OMIT_CREATION)->ToObjectChecked()->IsSmi()); 82 } 83 84 // Keys never added to the map which already have an identity hash 85 // code should not be found. 86 for (int i = 0; i < 100; i++) { 87 Handle<JSObject> key = factory->NewJSArray(7); 88 CHECK(key->GetIdentityHash(ALLOW_CREATION)->ToObjectChecked()->IsSmi()); 89 CHECK_EQ(table->FindEntry(*key), ObjectHashTable::kNotFound); 90 CHECK_EQ(table->Lookup(*key), HEAP->the_hole_value()); 91 CHECK(key->GetIdentityHash(OMIT_CREATION)->ToObjectChecked()->IsSmi()); 92 } 93 94 // Keys that don't have an identity hash should not be found and also 95 // should not get an identity hash code generated. 96 for (int i = 0; i < 100; i++) { 97 Handle<JSObject> key = factory->NewJSArray(7); 98 CHECK_EQ(table->Lookup(*key), HEAP->the_hole_value()); 99 CHECK_EQ(key->GetIdentityHash(OMIT_CREATION), HEAP->undefined_value()); 100 } 101 } 102 103 104 #ifdef DEBUG 105 TEST(ObjectHashSetCausesGC) { 106 i::FLAG_stress_compaction = false; 107 LocalContext context; 108 Isolate* isolate = Isolate::Current(); 109 Factory* factory = isolate->factory(); 110 v8::HandleScope scope(context->GetIsolate()); 111 Handle<ObjectHashSet> table = factory->NewObjectHashSet(1); 112 Handle<JSObject> key = factory->NewJSArray(0); 113 v8::Handle<v8::Object> key_obj = v8::Utils::ToLocal(key); 114 115 // Force allocation of hash table backing store for hidden properties. 116 key_obj->SetHiddenValue(v8_str("key 1"), v8_str("val 1")); 117 key_obj->SetHiddenValue(v8_str("key 2"), v8_str("val 2")); 118 key_obj->SetHiddenValue(v8_str("key 3"), v8_str("val 3")); 119 120 // Simulate a full heap so that generating an identity hash code 121 // in subsequent calls will request GC. 122 SimulateFullSpace(HEAP->new_space()); 123 SimulateFullSpace(HEAP->old_pointer_space()); 124 125 // Calling Contains() should not cause GC ever. 126 CHECK(!table->Contains(*key)); 127 128 // Calling Remove() should not cause GC ever. 129 CHECK(!table->Remove(*key)->IsFailure()); 130 131 // Calling Add() should request GC by returning a failure. 132 CHECK(table->Add(*key)->IsRetryAfterGC()); 133 } 134 #endif 135 136 137 #ifdef DEBUG 138 TEST(ObjectHashTableCausesGC) { 139 i::FLAG_stress_compaction = false; 140 LocalContext context; 141 Isolate* isolate = Isolate::Current(); 142 Factory* factory = isolate->factory(); 143 v8::HandleScope scope(context->GetIsolate()); 144 Handle<ObjectHashTable> table = factory->NewObjectHashTable(1); 145 Handle<JSObject> key = factory->NewJSArray(0); 146 v8::Handle<v8::Object> key_obj = v8::Utils::ToLocal(key); 147 148 // Force allocation of hash table backing store for hidden properties. 149 key_obj->SetHiddenValue(v8_str("key 1"), v8_str("val 1")); 150 key_obj->SetHiddenValue(v8_str("key 2"), v8_str("val 2")); 151 key_obj->SetHiddenValue(v8_str("key 3"), v8_str("val 3")); 152 153 // Simulate a full heap so that generating an identity hash code 154 // in subsequent calls will request GC. 155 SimulateFullSpace(HEAP->new_space()); 156 SimulateFullSpace(HEAP->old_pointer_space()); 157 158 // Calling Lookup() should not cause GC ever. 159 CHECK(table->Lookup(*key)->IsTheHole()); 160 161 // Calling Put() should request GC by returning a failure. 162 CHECK(table->Put(*key, *key)->IsRetryAfterGC()); 163 } 164 #endif 165