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 <vector> 6 7 #include "src/globals.h" 8 #include "src/heap/heap.h" 9 #include "src/heap/spaces.h" 10 #include "src/heap/spaces-inl.h" 11 #include "test/cctest/cctest.h" 12 13 namespace v8 { 14 namespace internal { 15 16 static Address AllocateLabBackingStore(Heap* heap, intptr_t size_in_bytes) { 17 AllocationResult result = heap->old_space()->AllocateRaw( 18 static_cast<int>(size_in_bytes), kDoubleAligned); 19 Object* obj = result.ToObjectChecked(); 20 Address adr = HeapObject::cast(obj)->address(); 21 return adr; 22 } 23 24 25 static void VerifyIterable(v8::internal::Address base, 26 v8::internal::Address limit, 27 std::vector<intptr_t> expected_size) { 28 CHECK_LE(reinterpret_cast<intptr_t>(base), reinterpret_cast<intptr_t>(limit)); 29 HeapObject* object = nullptr; 30 size_t counter = 0; 31 while (base < limit) { 32 object = HeapObject::FromAddress(base); 33 CHECK(object->IsFiller()); 34 CHECK_LT(counter, expected_size.size()); 35 CHECK_EQ(expected_size[counter], object->Size()); 36 base += object->Size(); 37 counter++; 38 } 39 } 40 41 42 static bool AllocateFromLab(Heap* heap, LocalAllocationBuffer* lab, 43 intptr_t size_in_bytes, 44 AllocationAlignment alignment = kWordAligned) { 45 HeapObject* obj; 46 AllocationResult result = 47 lab->AllocateRawAligned(static_cast<int>(size_in_bytes), alignment); 48 if (result.To(&obj)) { 49 heap->CreateFillerObjectAt(obj->address(), static_cast<int>(size_in_bytes), 50 ClearRecordedSlots::kNo); 51 return true; 52 } 53 return false; 54 } 55 56 57 TEST(InvalidLab) { 58 LocalAllocationBuffer lab = LocalAllocationBuffer::InvalidBuffer(); 59 CHECK(!lab.IsValid()); 60 } 61 62 63 TEST(UnusedLabImplicitClose) { 64 CcTest::InitializeVM(); 65 Heap* heap = CcTest::heap(); 66 heap->root(Heap::kOnePointerFillerMapRootIndex); 67 const int kLabSize = 4 * KB; 68 Address base = AllocateLabBackingStore(heap, kLabSize); 69 Address limit = base + kLabSize; 70 intptr_t expected_sizes_raw[1] = {kLabSize}; 71 std::vector<intptr_t> expected_sizes(expected_sizes_raw, 72 expected_sizes_raw + 1); 73 { 74 AllocationResult lab_backing_store(HeapObject::FromAddress(base)); 75 LocalAllocationBuffer lab = 76 LocalAllocationBuffer::FromResult(heap, lab_backing_store, kLabSize); 77 CHECK(lab.IsValid()); 78 } 79 VerifyIterable(base, limit, expected_sizes); 80 } 81 82 83 TEST(SimpleAllocate) { 84 CcTest::InitializeVM(); 85 Heap* heap = CcTest::heap(); 86 const int kLabSize = 4 * KB; 87 Address base = AllocateLabBackingStore(heap, kLabSize); 88 Address limit = base + kLabSize; 89 intptr_t sizes_raw[1] = {128}; 90 intptr_t expected_sizes_raw[2] = {128, kLabSize - 128}; 91 std::vector<intptr_t> sizes(sizes_raw, sizes_raw + 1); 92 std::vector<intptr_t> expected_sizes(expected_sizes_raw, 93 expected_sizes_raw + 2); 94 { 95 AllocationResult lab_backing_store(HeapObject::FromAddress(base)); 96 LocalAllocationBuffer lab = 97 LocalAllocationBuffer::FromResult(heap, lab_backing_store, kLabSize); 98 CHECK(lab.IsValid()); 99 intptr_t sum = 0; 100 for (auto size : sizes) { 101 if (AllocateFromLab(heap, &lab, size)) { 102 sum += size; 103 } 104 } 105 } 106 VerifyIterable(base, limit, expected_sizes); 107 } 108 109 110 TEST(AllocateUntilLabOOM) { 111 CcTest::InitializeVM(); 112 Heap* heap = CcTest::heap(); 113 const int kLabSize = 2 * KB; 114 Address base = AllocateLabBackingStore(heap, kLabSize); 115 Address limit = base + kLabSize; 116 // The following objects won't fit in {kLabSize}. 117 intptr_t sizes_raw[5] = {512, 512, 128, 512, 512}; 118 intptr_t expected_sizes_raw[5] = {512, 512, 128, 512, 384 /* left over */}; 119 std::vector<intptr_t> sizes(sizes_raw, sizes_raw + 5); 120 std::vector<intptr_t> expected_sizes(expected_sizes_raw, 121 expected_sizes_raw + 5); 122 intptr_t sum = 0; 123 { 124 AllocationResult lab_backing_store(HeapObject::FromAddress(base)); 125 LocalAllocationBuffer lab = 126 LocalAllocationBuffer::FromResult(heap, lab_backing_store, kLabSize); 127 CHECK(lab.IsValid()); 128 for (auto size : sizes) { 129 if (AllocateFromLab(heap, &lab, size)) { 130 sum += size; 131 } 132 } 133 CHECK_EQ(kLabSize - sum, 384); 134 } 135 VerifyIterable(base, limit, expected_sizes); 136 } 137 138 139 TEST(AllocateExactlyUntilLimit) { 140 CcTest::InitializeVM(); 141 Heap* heap = CcTest::heap(); 142 const int kLabSize = 2 * KB; 143 Address base = AllocateLabBackingStore(heap, kLabSize); 144 Address limit = base + kLabSize; 145 intptr_t sizes_raw[4] = {512, 512, 512, 512}; 146 intptr_t expected_sizes_raw[5] = {512, 512, 512, 512, 0}; 147 std::vector<intptr_t> sizes(sizes_raw, sizes_raw + 4); 148 std::vector<intptr_t> expected_sizes(expected_sizes_raw, 149 expected_sizes_raw + 5); 150 { 151 AllocationResult lab_backing_store(HeapObject::FromAddress(base)); 152 LocalAllocationBuffer lab = 153 LocalAllocationBuffer::FromResult(heap, lab_backing_store, kLabSize); 154 CHECK(lab.IsValid()); 155 intptr_t sum = 0; 156 for (auto size : sizes) { 157 if (AllocateFromLab(heap, &lab, size)) { 158 sum += size; 159 } else { 160 break; 161 } 162 } 163 CHECK_EQ(kLabSize - sum, 0); 164 } 165 VerifyIterable(base, limit, expected_sizes); 166 } 167 168 169 TEST(MergeSuccessful) { 170 CcTest::InitializeVM(); 171 Heap* heap = CcTest::heap(); 172 const int kLabSize = 2 * KB; 173 Address base1 = AllocateLabBackingStore(heap, kLabSize); 174 Address limit1 = base1 + kLabSize; 175 Address base2 = limit1; 176 Address limit2 = base2 + kLabSize; 177 178 intptr_t sizes1_raw[4] = {512, 512, 512, 256}; 179 intptr_t expected_sizes1_raw[5] = {512, 512, 512, 256, 256}; 180 std::vector<intptr_t> sizes1(sizes1_raw, sizes1_raw + 4); 181 std::vector<intptr_t> expected_sizes1(expected_sizes1_raw, 182 expected_sizes1_raw + 5); 183 184 intptr_t sizes2_raw[5] = {256, 512, 512, 512, 512}; 185 intptr_t expected_sizes2_raw[10] = {512, 512, 512, 256, 256, 186 512, 512, 512, 512, 0}; 187 std::vector<intptr_t> sizes2(sizes2_raw, sizes2_raw + 5); 188 std::vector<intptr_t> expected_sizes2(expected_sizes2_raw, 189 expected_sizes2_raw + 10); 190 191 { 192 AllocationResult lab_backing_store1(HeapObject::FromAddress(base1)); 193 LocalAllocationBuffer lab1 = 194 LocalAllocationBuffer::FromResult(heap, lab_backing_store1, kLabSize); 195 CHECK(lab1.IsValid()); 196 intptr_t sum = 0; 197 for (auto size : sizes1) { 198 if (AllocateFromLab(heap, &lab1, size)) { 199 sum += size; 200 } else { 201 break; 202 } 203 } 204 205 AllocationResult lab_backing_store2(HeapObject::FromAddress(base2)); 206 LocalAllocationBuffer lab2 = 207 LocalAllocationBuffer::FromResult(heap, lab_backing_store2, kLabSize); 208 CHECK(lab2.IsValid()); 209 CHECK(lab2.TryMerge(&lab1)); 210 CHECK(!lab1.IsValid()); 211 for (auto size : sizes2) { 212 if (AllocateFromLab(heap, &lab2, size)) { 213 sum += size; 214 } else { 215 break; 216 } 217 } 218 CHECK_EQ(2 * kLabSize - sum, 0); 219 } 220 VerifyIterable(base1, limit1, expected_sizes1); 221 VerifyIterable(base1, limit2, expected_sizes2); 222 } 223 224 225 TEST(MergeFailed) { 226 CcTest::InitializeVM(); 227 Heap* heap = CcTest::heap(); 228 const int kLabSize = 2 * KB; 229 Address base1 = AllocateLabBackingStore(heap, kLabSize); 230 Address base2 = base1 + kLabSize; 231 Address base3 = base2 + kLabSize; 232 233 { 234 AllocationResult lab_backing_store1(HeapObject::FromAddress(base1)); 235 LocalAllocationBuffer lab1 = 236 LocalAllocationBuffer::FromResult(heap, lab_backing_store1, kLabSize); 237 CHECK(lab1.IsValid()); 238 239 AllocationResult lab_backing_store2(HeapObject::FromAddress(base2)); 240 LocalAllocationBuffer lab2 = 241 LocalAllocationBuffer::FromResult(heap, lab_backing_store2, kLabSize); 242 CHECK(lab2.IsValid()); 243 244 AllocationResult lab_backing_store3(HeapObject::FromAddress(base3)); 245 LocalAllocationBuffer lab3 = 246 LocalAllocationBuffer::FromResult(heap, lab_backing_store3, kLabSize); 247 CHECK(lab3.IsValid()); 248 249 CHECK(!lab3.TryMerge(&lab1)); 250 } 251 } 252 253 254 #ifdef V8_HOST_ARCH_32_BIT 255 TEST(AllocateAligned) { 256 CcTest::InitializeVM(); 257 Heap* heap = CcTest::heap(); 258 const int kLabSize = 2 * KB; 259 Address base = AllocateLabBackingStore(heap, kLabSize); 260 Address limit = base + kLabSize; 261 std::pair<intptr_t, AllocationAlignment> sizes_raw[2] = { 262 std::make_pair(116, kWordAligned), std::make_pair(64, kDoubleAligned)}; 263 std::vector<std::pair<intptr_t, AllocationAlignment>> sizes(sizes_raw, 264 sizes_raw + 2); 265 intptr_t expected_sizes_raw[4] = {116, 4, 64, 1864}; 266 std::vector<intptr_t> expected_sizes(expected_sizes_raw, 267 expected_sizes_raw + 4); 268 269 { 270 AllocationResult lab_backing_store(HeapObject::FromAddress(base)); 271 LocalAllocationBuffer lab = 272 LocalAllocationBuffer::FromResult(heap, lab_backing_store, kLabSize); 273 CHECK(lab.IsValid()); 274 for (auto pair : sizes) { 275 if (!AllocateFromLab(heap, &lab, pair.first, pair.second)) { 276 break; 277 } 278 } 279 } 280 VerifyIterable(base, limit, expected_sizes); 281 } 282 #endif // V8_HOST_ARCH_32_BIT 283 284 } // namespace internal 285 } // namespace v8 286