Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/heap/spaces.h" | 5 #include "src/heap/spaces.h" |
| 6 | 6 |
| 7 #include "src/base/bits.h" | 7 #include "src/base/bits.h" |
| 8 #include "src/base/platform/platform.h" | 8 #include "src/base/platform/platform.h" |
| 9 #include "src/base/platform/semaphore.h" | 9 #include "src/base/platform/semaphore.h" |
| 10 #include "src/full-codegen/full-codegen.h" | 10 #include "src/full-codegen/full-codegen.h" |
| (...skipping 578 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 589 | 589 |
| 590 void MemoryChunk::Unlink() { | 590 void MemoryChunk::Unlink() { |
| 591 MemoryChunk* next_element = next_chunk(); | 591 MemoryChunk* next_element = next_chunk(); |
| 592 MemoryChunk* prev_element = prev_chunk(); | 592 MemoryChunk* prev_element = prev_chunk(); |
| 593 next_element->set_prev_chunk(prev_element); | 593 next_element->set_prev_chunk(prev_element); |
| 594 prev_element->set_next_chunk(next_element); | 594 prev_element->set_next_chunk(next_element); |
| 595 set_prev_chunk(NULL); | 595 set_prev_chunk(NULL); |
| 596 set_next_chunk(NULL); | 596 set_next_chunk(NULL); |
| 597 } | 597 } |
| 598 | 598 |
| 599 void MemoryAllocator::ShrinkChunk(MemoryChunk* chunk, size_t bytes_to_shrink) { | |
| 600 DCHECK_GE(bytes_to_shrink, static_cast<size_t>(base::OS::CommitPageSize())); | |
| 601 DCHECK_EQ(0, bytes_to_shrink % base::OS::CommitPageSize()); | |
| 602 Address free_start = chunk->area_end_ - bytes_to_shrink; | |
| 603 // Don't adjust the size of the page. The area is just uncomitted but not | |
| 604 // released. | |
| 605 chunk->area_end_ -= bytes_to_shrink; | |
| 606 UncommitBlock(free_start, bytes_to_shrink); | |
| 607 if (chunk->IsFlagSet(MemoryChunk::IS_EXECUTABLE)) { | |
| 608 if (chunk->reservation_.IsReserved()) | |
| 609 chunk->reservation_.Guard(chunk->area_end_); | |
| 610 else | |
| 611 base::OS::Guard(chunk->area_end_, base::OS::CommitPageSize()); | |
| 612 } | |
| 613 } | |
| 599 | 614 |
| 600 MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t reserve_area_size, | 615 MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t reserve_area_size, |
| 601 intptr_t commit_area_size, | 616 intptr_t commit_area_size, |
| 602 Executability executable, | 617 Executability executable, |
| 603 Space* owner) { | 618 Space* owner) { |
| 604 DCHECK(commit_area_size <= reserve_area_size); | 619 DCHECK(commit_area_size <= reserve_area_size); |
| 605 | 620 |
| 606 size_t chunk_size; | 621 size_t chunk_size; |
| 607 Heap* heap = isolate_->heap(); | 622 Heap* heap = isolate_->heap(); |
| 608 Address base = NULL; | 623 Address base = NULL; |
| (...skipping 598 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1207 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) { | 1222 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) { |
| 1208 Address cur = obj->address(); | 1223 Address cur = obj->address(); |
| 1209 Address next = cur + obj->Size(); | 1224 Address next = cur + obj->Size(); |
| 1210 if ((cur <= addr) && (addr < next)) return obj; | 1225 if ((cur <= addr) && (addr < next)) return obj; |
| 1211 } | 1226 } |
| 1212 | 1227 |
| 1213 UNREACHABLE(); | 1228 UNREACHABLE(); |
| 1214 return Smi::FromInt(0); | 1229 return Smi::FromInt(0); |
| 1215 } | 1230 } |
| 1216 | 1231 |
| 1232 void PagedSpace::ShrinkImmortalImmovablePages() { | |
|
Hannes Payer (out of office)
2016/08/11 20:12:23
Add DCHECK that we are currently deserializing.
Michael Lippautz
2016/08/12 06:45:59
Done.
| |
| 1233 MemoryChunk::UpdateHighWaterMark(allocation_info_.top()); | |
| 1234 EmptyAllocationInfo(); | |
| 1235 ResetFreeList(); | |
| 1236 | |
| 1237 for (Page* page : *this) { | |
| 1238 // Only shrink immortal immovable pages after deserialization. | |
| 1239 if (!page->IsFlagSet(Page::NEVER_EVACUATE)) continue; | |
|
Hannes Payer (out of office)
2016/08/11 20:12:23
Why are there non NEVER_EVACUATE pages?
Michael Lippautz
2016/08/12 06:45:59
Not the case anymore. Transformed into a DCHECK.
| |
| 1240 | |
| 1241 // Shrink pages to high water mark. Since those pages are never swept, there | |
| 1242 // should be a filler exactly at the high water mark. | |
| 1243 HeapObject* filler = HeapObject::FromAddress(page->HighWaterMark()); | |
| 1244 if (filler->address() == page->area_end()) continue; | |
|
Hannes Payer (out of office)
2016/08/11 20:12:23
Why do you continue here? Shouldn't each page have
Michael Lippautz
2016/08/12 06:45:59
Not if there were exactly page->area_size() bytes
| |
| 1245 CHECK(filler->IsFiller()); | |
| 1246 if (!filler->IsFreeSpace()) continue; | |
| 1247 | |
| 1248 #ifdef DEBUG | |
| 1249 // Check the the filler is indeed the last filler on the page. | |
| 1250 HeapObjectIterator it(page); | |
| 1251 HeapObject* filler2 = nullptr; | |
| 1252 for (HeapObject* obj = it.Next(); obj != nullptr; obj = it.Next()) { | |
| 1253 filler2 = HeapObject::FromAddress(obj->address() + obj->Size()); | |
| 1254 } | |
| 1255 if (filler2 == nullptr || filler2->address() == page->area_end()) continue; | |
| 1256 DCHECK(filler2->IsFiller()); | |
| 1257 DCHECK_EQ(filler->address(), filler2->address()); | |
| 1258 #endif // DEBUG | |
| 1259 | |
| 1260 size_t unused = | |
| 1261 RoundDown(static_cast<size_t>(page->area_end() - filler->address() - | |
| 1262 FreeSpace::kSize), | |
| 1263 base::OS::CommitPageSize()); | |
| 1264 if (unused > 0) { | |
| 1265 if (FLAG_trace_gc_verbose) { | |
| 1266 PrintIsolate(heap()->isolate(), "Shrinking page %p: end %p -> %p\n", | |
| 1267 reinterpret_cast<void*>(page), | |
| 1268 reinterpret_cast<void*>(page->area_end()), | |
| 1269 reinterpret_cast<void*>(page->area_end() - unused)); | |
| 1270 } | |
| 1271 heap()->CreateFillerObjectAt( | |
| 1272 filler->address(), | |
| 1273 static_cast<int>(page->area_end() - filler->address() - unused), | |
| 1274 ClearRecordedSlots::kNo); | |
| 1275 heap()->memory_allocator()->ShrinkChunk(page, unused); | |
| 1276 CHECK(filler->IsFiller()); | |
| 1277 CHECK_EQ(filler->address() + filler->Size(), page->area_end()); | |
| 1278 accounting_stats_.DecreaseCapacity(static_cast<intptr_t>(unused)); | |
| 1279 AccountUncommitted(unused); | |
| 1280 } | |
| 1281 } | |
| 1282 } | |
| 1283 | |
| 1217 bool PagedSpace::Expand() { | 1284 bool PagedSpace::Expand() { |
| 1218 int size = AreaSize(); | 1285 const int size = AreaSize(); |
| 1219 if (snapshotable() && !HasPages()) { | |
| 1220 size = Snapshot::SizeOfFirstPage(heap()->isolate(), identity()); | |
| 1221 } | |
| 1222 | |
| 1223 if (!heap()->CanExpandOldGeneration(size)) return false; | 1286 if (!heap()->CanExpandOldGeneration(size)) return false; |
| 1224 | |
| 1225 Page* p = heap()->memory_allocator()->AllocatePage(size, this, executable()); | 1287 Page* p = heap()->memory_allocator()->AllocatePage(size, this, executable()); |
| 1226 if (p == nullptr) return false; | 1288 if (p == nullptr) return false; |
| 1227 | |
| 1228 AccountCommitted(static_cast<intptr_t>(p->size())); | 1289 AccountCommitted(static_cast<intptr_t>(p->size())); |
| 1229 | 1290 |
| 1230 // Pages created during bootstrapping may contain immortal immovable objects. | 1291 // Pages created during bootstrapping may contain immortal immovable objects. |
| 1231 if (!heap()->deserialization_complete()) p->MarkNeverEvacuate(); | 1292 if (!heap()->deserialization_complete()) p->MarkNeverEvacuate(); |
| 1232 | 1293 |
| 1233 DCHECK(Capacity() <= heap()->MaxOldGenerationSize()); | 1294 DCHECK(Capacity() <= heap()->MaxOldGenerationSize()); |
| 1234 | 1295 |
| 1235 p->InsertAfter(anchor_.prev_page()); | 1296 p->InsertAfter(anchor_.prev_page()); |
| 1236 | 1297 |
| 1237 return true; | 1298 return true; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1308 SetTopAndLimit(NULL, NULL); | 1369 SetTopAndLimit(NULL, NULL); |
| 1309 Free(current_top, static_cast<int>(current_limit - current_top)); | 1370 Free(current_top, static_cast<int>(current_limit - current_top)); |
| 1310 } | 1371 } |
| 1311 | 1372 |
| 1312 void PagedSpace::IncreaseCapacity(int size) { | 1373 void PagedSpace::IncreaseCapacity(int size) { |
| 1313 accounting_stats_.ExpandSpace(size); | 1374 accounting_stats_.ExpandSpace(size); |
| 1314 } | 1375 } |
| 1315 | 1376 |
| 1316 void PagedSpace::ReleasePage(Page* page) { | 1377 void PagedSpace::ReleasePage(Page* page) { |
| 1317 DCHECK_EQ(page->LiveBytes(), 0); | 1378 DCHECK_EQ(page->LiveBytes(), 0); |
| 1318 DCHECK_EQ(AreaSize(), page->area_size()); | |
| 1319 DCHECK_EQ(page->owner(), this); | 1379 DCHECK_EQ(page->owner(), this); |
| 1320 | 1380 |
| 1321 free_list_.EvictFreeListItems(page); | 1381 free_list_.EvictFreeListItems(page); |
| 1322 DCHECK(!free_list_.ContainsPageFreeListItems(page)); | 1382 DCHECK(!free_list_.ContainsPageFreeListItems(page)); |
| 1323 | 1383 |
| 1324 page->ReleaseBlackAreaEndMarkerMap(); | 1384 page->ReleaseBlackAreaEndMarkerMap(); |
| 1325 | 1385 |
| 1326 if (Page::FromAllocationAreaAddress(allocation_info_.top()) == page) { | 1386 if (Page::FromAllocationAreaAddress(allocation_info_.top()) == page) { |
| 1327 allocation_info_.Reset(nullptr, nullptr); | 1387 allocation_info_.Reset(nullptr, nullptr); |
| 1328 } | 1388 } |
| 1329 | 1389 |
| 1330 // If page is still in a list, unlink it from that list. | 1390 // If page is still in a list, unlink it from that list. |
| 1331 if (page->next_chunk() != NULL) { | 1391 if (page->next_chunk() != NULL) { |
| 1332 DCHECK(page->prev_chunk() != NULL); | 1392 DCHECK(page->prev_chunk() != NULL); |
| 1333 page->Unlink(); | 1393 page->Unlink(); |
| 1334 } | 1394 } |
| 1335 | 1395 |
| 1336 AccountUncommitted(static_cast<intptr_t>(page->size())); | 1396 AccountUncommitted(static_cast<intptr_t>(page->size())); |
| 1397 accounting_stats_.ShrinkSpace(page->area_size()); | |
| 1337 heap()->memory_allocator()->Free<MemoryAllocator::kPreFreeAndQueue>(page); | 1398 heap()->memory_allocator()->Free<MemoryAllocator::kPreFreeAndQueue>(page); |
| 1338 | |
| 1339 DCHECK(Capacity() > 0); | |
| 1340 accounting_stats_.ShrinkSpace(AreaSize()); | |
| 1341 } | 1399 } |
| 1342 | 1400 |
| 1343 #ifdef DEBUG | 1401 #ifdef DEBUG |
| 1344 void PagedSpace::Print() {} | 1402 void PagedSpace::Print() {} |
| 1345 #endif | 1403 #endif |
| 1346 | 1404 |
| 1347 #ifdef VERIFY_HEAP | 1405 #ifdef VERIFY_HEAP |
| 1348 void PagedSpace::Verify(ObjectVisitor* visitor) { | 1406 void PagedSpace::Verify(ObjectVisitor* visitor) { |
| 1349 bool allocation_pointer_found_in_space = | 1407 bool allocation_pointer_found_in_space = |
| 1350 (allocation_info_.top() == allocation_info_.limit()); | 1408 (allocation_info_.top() == allocation_info_.limit()); |
| (...skipping 1794 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3145 object->ShortPrint(); | 3203 object->ShortPrint(); |
| 3146 PrintF("\n"); | 3204 PrintF("\n"); |
| 3147 } | 3205 } |
| 3148 printf(" --------------------------------------\n"); | 3206 printf(" --------------------------------------\n"); |
| 3149 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); | 3207 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); |
| 3150 } | 3208 } |
| 3151 | 3209 |
| 3152 #endif // DEBUG | 3210 #endif // DEBUG |
| 3153 } // namespace internal | 3211 } // namespace internal |
| 3154 } // namespace v8 | 3212 } // namespace v8 |
| OLD | NEW |