1 // Copyright 2013 the V8 project authors. All rights reserved. 2 3 // Test constant pool array code. 4 5 #include "src/v8.h" 6 7 #include "src/factory.h" 8 #include "src/objects.h" 9 #include "test/cctest/cctest.h" 10 11 using namespace v8::internal; 12 13 static ConstantPoolArray::Type kTypes[] = { ConstantPoolArray::INT64, 14 ConstantPoolArray::CODE_PTR, 15 ConstantPoolArray::HEAP_PTR, 16 ConstantPoolArray::INT32 }; 17 static ConstantPoolArray::LayoutSection kSmall = 18 ConstantPoolArray::SMALL_SECTION; 19 static ConstantPoolArray::LayoutSection kExtended = 20 ConstantPoolArray::EXTENDED_SECTION; 21 22 Code* DummyCode(LocalContext* context) { 23 CompileRun("function foo() {};"); 24 i::Handle<i::JSFunction> fun = v8::Utils::OpenHandle( 25 *v8::Local<v8::Function>::Cast( 26 (*context)->Global()->Get(v8_str("foo")))); 27 return fun->code(); 28 } 29 30 31 TEST(ConstantPoolSmall) { 32 LocalContext context; 33 Isolate* isolate = CcTest::i_isolate(); 34 Factory* factory = isolate->factory(); 35 v8::HandleScope scope(context->GetIsolate()); 36 37 // Check construction. 38 ConstantPoolArray::NumberOfEntries small(3, 1, 2, 1); 39 Handle<ConstantPoolArray> array = factory->NewConstantPoolArray(small); 40 41 int expected_counts[] = { 3, 1, 2, 1 }; 42 int expected_first_idx[] = { 0, 3, 4, 6 }; 43 int expected_last_idx[] = { 2, 3, 5, 6 }; 44 for (int i = 0; i < 4; i++) { 45 CHECK_EQ(expected_counts[i], array->number_of_entries(kTypes[i], kSmall)); 46 CHECK_EQ(expected_first_idx[i], array->first_index(kTypes[i], kSmall)); 47 CHECK_EQ(expected_last_idx[i], array->last_index(kTypes[i], kSmall)); 48 } 49 CHECK(!array->is_extended_layout()); 50 51 // Check getters and setters. 52 int64_t big_number = V8_2PART_UINT64_C(0x12345678, 9ABCDEF0); 53 Handle<Object> object = factory->NewHeapNumber(4.0, IMMUTABLE, TENURED); 54 Code* code = DummyCode(&context); 55 array->set(0, big_number); 56 array->set(1, 0.5); 57 array->set(2, 3e-24); 58 array->set(3, code->entry()); 59 array->set(4, code); 60 array->set(5, *object); 61 array->set(6, 50); 62 CHECK_EQ(big_number, array->get_int64_entry(0)); 63 CHECK_EQ(0.5, array->get_int64_entry_as_double(1)); 64 CHECK_EQ(3e-24, array->get_int64_entry_as_double(2)); 65 CHECK_EQ(code->entry(), array->get_code_ptr_entry(3)); 66 CHECK_EQ(code, array->get_heap_ptr_entry(4)); 67 CHECK_EQ(*object, array->get_heap_ptr_entry(5)); 68 CHECK_EQ(50, array->get_int32_entry(6)); 69 } 70 71 72 TEST(ConstantPoolExtended) { 73 LocalContext context; 74 Isolate* isolate = CcTest::i_isolate(); 75 Factory* factory = isolate->factory(); 76 v8::HandleScope scope(context->GetIsolate()); 77 78 // Check construction. 79 ConstantPoolArray::NumberOfEntries small(1, 2, 3, 4); 80 ConstantPoolArray::NumberOfEntries extended(5, 6, 7, 8); 81 Handle<ConstantPoolArray> array = 82 factory->NewExtendedConstantPoolArray(small, extended); 83 84 // Check small section. 85 int small_counts[] = { 1, 2, 3, 4 }; 86 int small_first_idx[] = { 0, 1, 3, 6 }; 87 int small_last_idx[] = { 0, 2, 5, 9 }; 88 for (int i = 0; i < 4; i++) { 89 CHECK_EQ(small_counts[i], array->number_of_entries(kTypes[i], kSmall)); 90 CHECK_EQ(small_first_idx[i], array->first_index(kTypes[i], kSmall)); 91 CHECK_EQ(small_last_idx[i], array->last_index(kTypes[i], kSmall)); 92 } 93 94 // Check extended layout. 95 CHECK(array->is_extended_layout()); 96 int extended_counts[] = { 5, 6, 7, 8 }; 97 int extended_first_idx[] = { 10, 15, 21, 28 }; 98 int extended_last_idx[] = { 14, 20, 27, 35 }; 99 for (int i = 0; i < 4; i++) { 100 CHECK_EQ(extended_counts[i], 101 array->number_of_entries(kTypes[i], kExtended)); 102 CHECK_EQ(extended_first_idx[i], array->first_index(kTypes[i], kExtended)); 103 CHECK_EQ(extended_last_idx[i], array->last_index(kTypes[i], kExtended)); 104 } 105 106 // Check small and large section's don't overlap. 107 int64_t small_section_int64 = V8_2PART_UINT64_C(0x56781234, DEF09ABC); 108 Code* small_section_code_ptr = DummyCode(&context); 109 Handle<Object> small_section_heap_ptr = 110 factory->NewHeapNumber(4.0, IMMUTABLE, TENURED); 111 int32_t small_section_int32 = 0xab12cd45; 112 113 int64_t extended_section_int64 = V8_2PART_UINT64_C(0x12345678, 9ABCDEF0); 114 Code* extended_section_code_ptr = DummyCode(&context); 115 Handle<Object> extended_section_heap_ptr = 116 factory->NewHeapNumber(5.0, IMMUTABLE, TENURED); 117 int32_t extended_section_int32 = 0xef67ab89; 118 119 for (int i = array->first_index(ConstantPoolArray::INT64, kSmall); 120 i <= array->last_index(ConstantPoolArray::INT32, kSmall); i++) { 121 if (i <= array->last_index(ConstantPoolArray::INT64, kSmall)) { 122 array->set(i, small_section_int64); 123 } else if (i <= array->last_index(ConstantPoolArray::CODE_PTR, kSmall)) { 124 array->set(i, small_section_code_ptr->entry()); 125 } else if (i <= array->last_index(ConstantPoolArray::HEAP_PTR, kSmall)) { 126 array->set(i, *small_section_heap_ptr); 127 } else { 128 CHECK(i <= array->last_index(ConstantPoolArray::INT32, kSmall)); 129 array->set(i, small_section_int32); 130 } 131 } 132 for (int i = array->first_index(ConstantPoolArray::INT64, kExtended); 133 i <= array->last_index(ConstantPoolArray::INT32, kExtended); i++) { 134 if (i <= array->last_index(ConstantPoolArray::INT64, kExtended)) { 135 array->set(i, extended_section_int64); 136 } else if (i <= array->last_index(ConstantPoolArray::CODE_PTR, kExtended)) { 137 array->set(i, extended_section_code_ptr->entry()); 138 } else if (i <= array->last_index(ConstantPoolArray::HEAP_PTR, kExtended)) { 139 array->set(i, *extended_section_heap_ptr); 140 } else { 141 CHECK(i <= array->last_index(ConstantPoolArray::INT32, kExtended)); 142 array->set(i, extended_section_int32); 143 } 144 } 145 146 for (int i = array->first_index(ConstantPoolArray::INT64, kSmall); 147 i <= array->last_index(ConstantPoolArray::INT32, kSmall); i++) { 148 if (i <= array->last_index(ConstantPoolArray::INT64, kSmall)) { 149 CHECK_EQ(small_section_int64, array->get_int64_entry(i)); 150 } else if (i <= array->last_index(ConstantPoolArray::CODE_PTR, kSmall)) { 151 CHECK_EQ(small_section_code_ptr->entry(), array->get_code_ptr_entry(i)); 152 } else if (i <= array->last_index(ConstantPoolArray::HEAP_PTR, kSmall)) { 153 CHECK_EQ(*small_section_heap_ptr, array->get_heap_ptr_entry(i)); 154 } else { 155 CHECK(i <= array->last_index(ConstantPoolArray::INT32, kSmall)); 156 CHECK_EQ(small_section_int32, array->get_int32_entry(i)); 157 } 158 } 159 for (int i = array->first_index(ConstantPoolArray::INT64, kExtended); 160 i <= array->last_index(ConstantPoolArray::INT32, kExtended); i++) { 161 if (i <= array->last_index(ConstantPoolArray::INT64, kExtended)) { 162 CHECK_EQ(extended_section_int64, array->get_int64_entry(i)); 163 } else if (i <= array->last_index(ConstantPoolArray::CODE_PTR, kExtended)) { 164 CHECK_EQ(extended_section_code_ptr->entry(), 165 array->get_code_ptr_entry(i)); 166 } else if (i <= array->last_index(ConstantPoolArray::HEAP_PTR, kExtended)) { 167 CHECK_EQ(*extended_section_heap_ptr, array->get_heap_ptr_entry(i)); 168 } else { 169 CHECK(i <= array->last_index(ConstantPoolArray::INT32, kExtended)); 170 CHECK_EQ(extended_section_int32, array->get_int32_entry(i)); 171 } 172 } 173 } 174 175 176 static void CheckIterator(Handle<ConstantPoolArray> array, 177 ConstantPoolArray::Type type, 178 int expected_indexes[], 179 int count) { 180 int i = 0; 181 ConstantPoolArray::Iterator iter(*array, type); 182 while (!iter.is_finished()) { 183 CHECK_EQ(expected_indexes[i++], iter.next_index()); 184 } 185 CHECK_EQ(count, i); 186 } 187 188 189 TEST(ConstantPoolIteratorSmall) { 190 LocalContext context; 191 Isolate* isolate = CcTest::i_isolate(); 192 Factory* factory = isolate->factory(); 193 v8::HandleScope scope(context->GetIsolate()); 194 195 ConstantPoolArray::NumberOfEntries small(1, 5, 2, 0); 196 Handle<ConstantPoolArray> array = factory->NewConstantPoolArray(small); 197 198 int expected_int64_indexs[] = { 0 }; 199 CheckIterator(array, ConstantPoolArray::INT64, expected_int64_indexs, 1); 200 int expected_code_indexs[] = { 1, 2, 3, 4, 5 }; 201 CheckIterator(array, ConstantPoolArray::CODE_PTR, expected_code_indexs, 5); 202 int expected_heap_indexs[] = { 6, 7 }; 203 CheckIterator(array, ConstantPoolArray::HEAP_PTR, expected_heap_indexs, 2); 204 int expected_int32_indexs[1]; 205 CheckIterator(array, ConstantPoolArray::INT32, expected_int32_indexs, 0); 206 } 207 208 209 TEST(ConstantPoolIteratorExtended) { 210 LocalContext context; 211 Isolate* isolate = CcTest::i_isolate(); 212 Factory* factory = isolate->factory(); 213 v8::HandleScope scope(context->GetIsolate()); 214 215 ConstantPoolArray::NumberOfEntries small(1, 0, 0, 4); 216 ConstantPoolArray::NumberOfEntries extended(5, 0, 3, 0); 217 Handle<ConstantPoolArray> array = 218 factory->NewExtendedConstantPoolArray(small, extended); 219 220 int expected_int64_indexs[] = { 0, 5, 6, 7, 8, 9 }; 221 CheckIterator(array, ConstantPoolArray::INT64, expected_int64_indexs, 6); 222 int expected_code_indexs[1]; 223 CheckIterator(array, ConstantPoolArray::CODE_PTR, expected_code_indexs, 0); 224 int expected_heap_indexs[] = { 10, 11, 12 }; 225 CheckIterator(array, ConstantPoolArray::HEAP_PTR, expected_heap_indexs, 3); 226 int expected_int32_indexs[] = { 1, 2, 3, 4 }; 227 CheckIterator(array, ConstantPoolArray::INT32, expected_int32_indexs, 4); 228 } 229 230 231 TEST(ConstantPoolPreciseGC) { 232 LocalContext context; 233 Isolate* isolate = CcTest::i_isolate(); 234 Heap* heap = isolate->heap(); 235 Factory* factory = isolate->factory(); 236 v8::HandleScope scope(context->GetIsolate()); 237 238 ConstantPoolArray::NumberOfEntries small(1, 0, 0, 1); 239 Handle<ConstantPoolArray> array = factory->NewConstantPoolArray(small); 240 241 // Check that the store buffer knows which entries are pointers and which are 242 // not. To do this, make non-pointer entries which look like new space 243 // pointers but are actually invalid and ensure the GC doesn't try to move 244 // them. 245 Handle<HeapObject> object = factory->NewHeapNumber(4.0); 246 Object* raw_ptr = *object; 247 // If interpreted as a pointer, this should be right inside the heap number 248 // which will cause a crash when trying to lookup the 'map' pointer. 249 intptr_t invalid_ptr = reinterpret_cast<intptr_t>(raw_ptr) + kInt32Size; 250 int32_t invalid_ptr_int32 = static_cast<int32_t>(invalid_ptr); 251 int64_t invalid_ptr_int64 = static_cast<int64_t>(invalid_ptr); 252 array->set(0, invalid_ptr_int64); 253 array->set(1, invalid_ptr_int32); 254 255 // Ensure we perform a scan on scavenge for the constant pool's page. 256 MemoryChunk::FromAddress(array->address())->set_scan_on_scavenge(true); 257 heap->CollectGarbage(NEW_SPACE); 258 259 // Check the object was moved by GC. 260 CHECK_NE(*object, raw_ptr); 261 262 // Check the non-pointer entries weren't changed. 263 CHECK_EQ(invalid_ptr_int64, array->get_int64_entry(0)); 264 CHECK_EQ(invalid_ptr_int32, array->get_int32_entry(1)); 265 } 266 267 268 TEST(ConstantPoolCompacting) { 269 if (i::FLAG_never_compact) return; 270 i::FLAG_always_compact = true; 271 LocalContext context; 272 Isolate* isolate = CcTest::i_isolate(); 273 Heap* heap = isolate->heap(); 274 Factory* factory = isolate->factory(); 275 v8::HandleScope scope(context->GetIsolate()); 276 277 ConstantPoolArray::NumberOfEntries small(0, 0, 1, 0); 278 ConstantPoolArray::NumberOfEntries extended(0, 0, 1, 0); 279 Handle<ConstantPoolArray> array = 280 factory->NewExtendedConstantPoolArray(small, extended); 281 282 // Start a second old-space page so that the heap pointer added to the 283 // constant pool array ends up on the an evacuation candidate page. 284 Page* first_page = heap->old_data_space()->anchor()->next_page(); 285 { 286 HandleScope scope(isolate); 287 Handle<HeapObject> temp = 288 factory->NewFixedDoubleArray(900 * KB / kDoubleSize, TENURED); 289 CHECK(heap->InOldDataSpace(temp->address())); 290 Handle<HeapObject> heap_ptr = 291 factory->NewHeapNumber(5.0, IMMUTABLE, TENURED); 292 CHECK(heap->InOldDataSpace(heap_ptr->address())); 293 CHECK(!first_page->Contains(heap_ptr->address())); 294 array->set(0, *heap_ptr); 295 array->set(1, *heap_ptr); 296 } 297 298 // Check heap pointers are correctly updated on GC. 299 Object* old_ptr = array->get_heap_ptr_entry(0); 300 Handle<Object> object(old_ptr, isolate); 301 CHECK_EQ(old_ptr, *object); 302 CHECK_EQ(old_ptr, array->get_heap_ptr_entry(1)); 303 304 // Force compacting garbage collection. 305 CHECK(FLAG_always_compact); 306 heap->CollectAllGarbage(Heap::kNoGCFlags); 307 308 CHECK_NE(old_ptr, *object); 309 CHECK_EQ(*object, array->get_heap_ptr_entry(0)); 310 CHECK_EQ(*object, array->get_heap_ptr_entry(1)); 311 } 312