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/v8.h" | 5 #include "src/v8.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/full-codegen.h" | 9 #include "src/full-codegen.h" |
10 #include "src/heap/mark-compact.h" | 10 #include "src/heap/mark-compact.h" |
(...skipping 1177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1188 | 1188 |
1189 | 1189 |
1190 bool NewSpace::SetUp(int reserved_semispace_capacity, | 1190 bool NewSpace::SetUp(int reserved_semispace_capacity, |
1191 int maximum_semispace_capacity) { | 1191 int maximum_semispace_capacity) { |
1192 // Set up new space based on the preallocated memory block defined by | 1192 // Set up new space based on the preallocated memory block defined by |
1193 // start and size. The provided space is divided into two semi-spaces. | 1193 // start and size. The provided space is divided into two semi-spaces. |
1194 // To support fast containment testing in the new space, the size of | 1194 // To support fast containment testing in the new space, the size of |
1195 // this chunk must be a power of two and it must be aligned to its size. | 1195 // this chunk must be a power of two and it must be aligned to its size. |
1196 int initial_semispace_capacity = heap()->InitialSemiSpaceSize(); | 1196 int initial_semispace_capacity = heap()->InitialSemiSpaceSize(); |
1197 | 1197 |
| 1198 int target_semispace_capacity = heap()->TargetSemiSpaceSize(); |
| 1199 |
1198 size_t size = 2 * reserved_semispace_capacity; | 1200 size_t size = 2 * reserved_semispace_capacity; |
1199 Address base = heap()->isolate()->memory_allocator()->ReserveAlignedMemory( | 1201 Address base = heap()->isolate()->memory_allocator()->ReserveAlignedMemory( |
1200 size, size, &reservation_); | 1202 size, size, &reservation_); |
1201 if (base == NULL) return false; | 1203 if (base == NULL) return false; |
1202 | 1204 |
1203 chunk_base_ = base; | 1205 chunk_base_ = base; |
1204 chunk_size_ = static_cast<uintptr_t>(size); | 1206 chunk_size_ = static_cast<uintptr_t>(size); |
1205 LOG(heap()->isolate(), NewEvent("InitialChunk", chunk_base_, chunk_size_)); | 1207 LOG(heap()->isolate(), NewEvent("InitialChunk", chunk_base_, chunk_size_)); |
1206 | 1208 |
1207 DCHECK(initial_semispace_capacity <= maximum_semispace_capacity); | 1209 DCHECK(initial_semispace_capacity <= maximum_semispace_capacity); |
1208 DCHECK(base::bits::IsPowerOfTwo32(maximum_semispace_capacity)); | 1210 DCHECK(base::bits::IsPowerOfTwo32(maximum_semispace_capacity)); |
1209 | 1211 |
1210 // Allocate and set up the histogram arrays if necessary. | 1212 // Allocate and set up the histogram arrays if necessary. |
1211 allocated_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1); | 1213 allocated_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1); |
1212 promoted_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1); | 1214 promoted_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1); |
1213 | 1215 |
1214 #define SET_NAME(name) \ | 1216 #define SET_NAME(name) \ |
1215 allocated_histogram_[name].set_name(#name); \ | 1217 allocated_histogram_[name].set_name(#name); \ |
1216 promoted_histogram_[name].set_name(#name); | 1218 promoted_histogram_[name].set_name(#name); |
1217 INSTANCE_TYPE_LIST(SET_NAME) | 1219 INSTANCE_TYPE_LIST(SET_NAME) |
1218 #undef SET_NAME | 1220 #undef SET_NAME |
1219 | 1221 |
1220 DCHECK(reserved_semispace_capacity == heap()->ReservedSemiSpaceSize()); | 1222 DCHECK(reserved_semispace_capacity == heap()->ReservedSemiSpaceSize()); |
1221 DCHECK(static_cast<intptr_t>(chunk_size_) >= | 1223 DCHECK(static_cast<intptr_t>(chunk_size_) >= |
1222 2 * heap()->ReservedSemiSpaceSize()); | 1224 2 * heap()->ReservedSemiSpaceSize()); |
1223 DCHECK(IsAddressAligned(chunk_base_, 2 * reserved_semispace_capacity, 0)); | 1225 DCHECK(IsAddressAligned(chunk_base_, 2 * reserved_semispace_capacity, 0)); |
1224 | 1226 |
1225 to_space_.SetUp(chunk_base_, initial_semispace_capacity, | 1227 to_space_.SetUp(chunk_base_, initial_semispace_capacity, |
1226 maximum_semispace_capacity); | 1228 target_semispace_capacity, maximum_semispace_capacity); |
1227 from_space_.SetUp(chunk_base_ + reserved_semispace_capacity, | 1229 from_space_.SetUp(chunk_base_ + reserved_semispace_capacity, |
1228 initial_semispace_capacity, maximum_semispace_capacity); | 1230 initial_semispace_capacity, target_semispace_capacity, |
| 1231 maximum_semispace_capacity); |
1229 if (!to_space_.Commit()) { | 1232 if (!to_space_.Commit()) { |
1230 return false; | 1233 return false; |
1231 } | 1234 } |
1232 DCHECK(!from_space_.is_committed()); // No need to use memory yet. | 1235 DCHECK(!from_space_.is_committed()); // No need to use memory yet. |
1233 | 1236 |
1234 start_ = chunk_base_; | 1237 start_ = chunk_base_; |
1235 address_mask_ = ~(2 * reserved_semispace_capacity - 1); | 1238 address_mask_ = ~(2 * reserved_semispace_capacity - 1); |
1236 object_mask_ = address_mask_ | kHeapObjectTagMask; | 1239 object_mask_ = address_mask_ | kHeapObjectTagMask; |
1237 object_expected_ = reinterpret_cast<uintptr_t>(start_) | kHeapObjectTag; | 1240 object_expected_ = reinterpret_cast<uintptr_t>(start_) | kHeapObjectTag; |
1238 | 1241 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1278 int new_capacity = | 1281 int new_capacity = |
1279 Min(MaximumCapacity(), 2 * static_cast<int>(TotalCapacity())); | 1282 Min(MaximumCapacity(), 2 * static_cast<int>(TotalCapacity())); |
1280 if (to_space_.GrowTo(new_capacity)) { | 1283 if (to_space_.GrowTo(new_capacity)) { |
1281 // Only grow from space if we managed to grow to-space. | 1284 // Only grow from space if we managed to grow to-space. |
1282 if (!from_space_.GrowTo(new_capacity)) { | 1285 if (!from_space_.GrowTo(new_capacity)) { |
1283 // If we managed to grow to-space but couldn't grow from-space, | 1286 // If we managed to grow to-space but couldn't grow from-space, |
1284 // attempt to shrink to-space. | 1287 // attempt to shrink to-space. |
1285 if (!to_space_.ShrinkTo(from_space_.TotalCapacity())) { | 1288 if (!to_space_.ShrinkTo(from_space_.TotalCapacity())) { |
1286 // We are in an inconsistent state because we could not | 1289 // We are in an inconsistent state because we could not |
1287 // commit/uncommit memory from new space. | 1290 // commit/uncommit memory from new space. |
1288 V8::FatalProcessOutOfMemory("Failed to grow new space."); | 1291 CHECK(false); |
1289 } | 1292 } |
1290 } | 1293 } |
1291 } | 1294 } |
1292 DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_); | 1295 DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_); |
1293 } | 1296 } |
1294 | 1297 |
1295 | 1298 |
| 1299 bool NewSpace::GrowOnePage() { |
| 1300 if (TotalCapacity() == MaximumCapacity()) return false; |
| 1301 int new_capacity = static_cast<int>(TotalCapacity()) + Page::kPageSize; |
| 1302 if (to_space_.GrowTo(new_capacity)) { |
| 1303 // Only grow from space if we managed to grow to-space and the from space |
| 1304 // is actually committed. |
| 1305 if (from_space_.is_committed()) { |
| 1306 if (!from_space_.GrowTo(new_capacity)) { |
| 1307 // If we managed to grow to-space but couldn't grow from-space, |
| 1308 // attempt to shrink to-space. |
| 1309 if (!to_space_.ShrinkTo(from_space_.TotalCapacity())) { |
| 1310 // We are in an inconsistent state because we could not |
| 1311 // commit/uncommit memory from new space. |
| 1312 CHECK(false); |
| 1313 } |
| 1314 return false; |
| 1315 } |
| 1316 } else { |
| 1317 if (!from_space_.SetTotalCapacity(new_capacity)) { |
| 1318 // Can't really happen, but better safe than sorry. |
| 1319 CHECK(false); |
| 1320 } |
| 1321 } |
| 1322 DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_); |
| 1323 return true; |
| 1324 } |
| 1325 return false; |
| 1326 } |
| 1327 |
| 1328 |
1296 void NewSpace::Shrink() { | 1329 void NewSpace::Shrink() { |
1297 int new_capacity = Max(InitialTotalCapacity(), 2 * SizeAsInt()); | 1330 int new_capacity = Max(InitialTotalCapacity(), 2 * SizeAsInt()); |
1298 int rounded_new_capacity = RoundUp(new_capacity, Page::kPageSize); | 1331 int rounded_new_capacity = RoundUp(new_capacity, Page::kPageSize); |
1299 if (rounded_new_capacity < TotalCapacity() && | 1332 if (rounded_new_capacity < TotalCapacity() && |
1300 to_space_.ShrinkTo(rounded_new_capacity)) { | 1333 to_space_.ShrinkTo(rounded_new_capacity)) { |
1301 // Only shrink from-space if we managed to shrink to-space. | 1334 // Only shrink from-space if we managed to shrink to-space. |
1302 from_space_.Reset(); | 1335 from_space_.Reset(); |
1303 if (!from_space_.ShrinkTo(rounded_new_capacity)) { | 1336 if (!from_space_.ShrinkTo(rounded_new_capacity)) { |
1304 // If we managed to shrink to-space but couldn't shrink from | 1337 // If we managed to shrink to-space but couldn't shrink from |
1305 // space, attempt to grow to-space again. | 1338 // space, attempt to grow to-space again. |
1306 if (!to_space_.GrowTo(from_space_.TotalCapacity())) { | 1339 if (!to_space_.GrowTo(from_space_.TotalCapacity())) { |
1307 // We are in an inconsistent state because we could not | 1340 // We are in an inconsistent state because we could not |
1308 // commit/uncommit memory from new space. | 1341 // commit/uncommit memory from new space. |
1309 V8::FatalProcessOutOfMemory("Failed to shrink new space."); | 1342 CHECK(false); |
1310 } | 1343 } |
1311 } | 1344 } |
1312 } | 1345 } |
1313 DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_); | 1346 DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_); |
1314 } | 1347 } |
1315 | 1348 |
1316 | 1349 |
1317 void NewSpace::UpdateAllocationInfo() { | 1350 void NewSpace::UpdateAllocationInfo() { |
1318 MemoryChunk::UpdateHighWaterMark(allocation_info_.top()); | 1351 MemoryChunk::UpdateHighWaterMark(allocation_info_.top()); |
1319 allocation_info_.set_top(to_space_.page_low()); | 1352 allocation_info_.set_top(to_space_.page_low()); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1360 if (NewSpacePage::IsAtStart(top)) { | 1393 if (NewSpacePage::IsAtStart(top)) { |
1361 // The current page is already empty. Don't try to make another. | 1394 // The current page is already empty. Don't try to make another. |
1362 | 1395 |
1363 // We should only get here if someone asks to allocate more | 1396 // We should only get here if someone asks to allocate more |
1364 // than what can be stored in a single page. | 1397 // than what can be stored in a single page. |
1365 // TODO(gc): Change the limit on new-space allocation to prevent this | 1398 // TODO(gc): Change the limit on new-space allocation to prevent this |
1366 // from happening (all such allocations should go directly to LOSpace). | 1399 // from happening (all such allocations should go directly to LOSpace). |
1367 return false; | 1400 return false; |
1368 } | 1401 } |
1369 if (!to_space_.AdvancePage()) { | 1402 if (!to_space_.AdvancePage()) { |
1370 // Failed to get a new page in to-space. | 1403 // Check if we reached the target capacity yet. If not, try to commit a page |
1371 return false; | 1404 // and continue. |
| 1405 if ((to_space_.TotalCapacity() < to_space_.TargetCapacity()) && |
| 1406 GrowOnePage()) { |
| 1407 if (!to_space_.AdvancePage()) { |
| 1408 // It doesn't make sense that we managed to commit a page, but can't use |
| 1409 // it. |
| 1410 CHECK(false); |
| 1411 } |
| 1412 } else { |
| 1413 // Failed to get a new page in to-space. |
| 1414 return false; |
| 1415 } |
1372 } | 1416 } |
1373 | 1417 |
1374 // Clear remainder of current page. | 1418 // Clear remainder of current page. |
1375 Address limit = NewSpacePage::FromLimit(top)->area_end(); | 1419 Address limit = NewSpacePage::FromLimit(top)->area_end(); |
1376 if (heap()->gc_state() == Heap::SCAVENGE) { | 1420 if (heap()->gc_state() == Heap::SCAVENGE) { |
1377 heap()->promotion_queue()->SetNewLimit(limit); | 1421 heap()->promotion_queue()->SetNewLimit(limit); |
1378 } | 1422 } |
1379 | 1423 |
1380 int remaining_in_page = static_cast<int>(limit - top); | 1424 int remaining_in_page = static_cast<int>(limit - top); |
1381 heap()->CreateFillerObjectAt(top, remaining_in_page); | 1425 heap()->CreateFillerObjectAt(top, remaining_in_page); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1465 CHECK_EQ(from_space_.id(), kFromSpace); | 1509 CHECK_EQ(from_space_.id(), kFromSpace); |
1466 CHECK_EQ(to_space_.id(), kToSpace); | 1510 CHECK_EQ(to_space_.id(), kToSpace); |
1467 from_space_.Verify(); | 1511 from_space_.Verify(); |
1468 to_space_.Verify(); | 1512 to_space_.Verify(); |
1469 } | 1513 } |
1470 #endif | 1514 #endif |
1471 | 1515 |
1472 // ----------------------------------------------------------------------------- | 1516 // ----------------------------------------------------------------------------- |
1473 // SemiSpace implementation | 1517 // SemiSpace implementation |
1474 | 1518 |
1475 void SemiSpace::SetUp(Address start, int initial_capacity, | 1519 void SemiSpace::SetUp(Address start, int initial_capacity, int target_capacity, |
1476 int maximum_capacity) { | 1520 int maximum_capacity) { |
1477 // Creates a space in the young generation. The constructor does not | 1521 // Creates a space in the young generation. The constructor does not |
1478 // allocate memory from the OS. A SemiSpace is given a contiguous chunk of | 1522 // allocate memory from the OS. A SemiSpace is given a contiguous chunk of |
1479 // memory of size 'capacity' when set up, and does not grow or shrink | 1523 // memory of size 'capacity' when set up, and does not grow or shrink |
1480 // otherwise. In the mark-compact collector, the memory region of the from | 1524 // otherwise. In the mark-compact collector, the memory region of the from |
1481 // space is used as the marking stack. It requires contiguous memory | 1525 // space is used as the marking stack. It requires contiguous memory |
1482 // addresses. | 1526 // addresses. |
1483 DCHECK(maximum_capacity >= Page::kPageSize); | 1527 DCHECK(maximum_capacity >= Page::kPageSize); |
| 1528 DCHECK(initial_capacity <= target_capacity); |
| 1529 DCHECK(target_capacity <= maximum_capacity); |
1484 initial_total_capacity_ = RoundDown(initial_capacity, Page::kPageSize); | 1530 initial_total_capacity_ = RoundDown(initial_capacity, Page::kPageSize); |
1485 total_capacity_ = initial_capacity; | 1531 total_capacity_ = initial_capacity; |
| 1532 target_capacity_ = RoundDown(target_capacity, Page::kPageSize); |
1486 maximum_total_capacity_ = RoundDown(maximum_capacity, Page::kPageSize); | 1533 maximum_total_capacity_ = RoundDown(maximum_capacity, Page::kPageSize); |
1487 maximum_committed_ = 0; | 1534 maximum_committed_ = 0; |
1488 committed_ = false; | 1535 committed_ = false; |
1489 start_ = start; | 1536 start_ = start; |
1490 address_mask_ = ~(maximum_capacity - 1); | 1537 address_mask_ = ~(maximum_capacity - 1); |
1491 object_mask_ = address_mask_ | kHeapObjectTagMask; | 1538 object_mask_ = address_mask_ | kHeapObjectTagMask; |
1492 object_expected_ = reinterpret_cast<uintptr_t>(start) | kHeapObjectTag; | 1539 object_expected_ = reinterpret_cast<uintptr_t>(start) | kHeapObjectTag; |
1493 age_mark_ = start_; | 1540 age_mark_ = start_; |
1494 } | 1541 } |
1495 | 1542 |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1604 anchor()->set_prev_page(new_last_page); | 1651 anchor()->set_prev_page(new_last_page); |
1605 DCHECK((current_page_ >= first_page()) && (current_page_ <= new_last_page)); | 1652 DCHECK((current_page_ >= first_page()) && (current_page_ <= new_last_page)); |
1606 } | 1653 } |
1607 | 1654 |
1608 SetCapacity(new_capacity); | 1655 SetCapacity(new_capacity); |
1609 | 1656 |
1610 return true; | 1657 return true; |
1611 } | 1658 } |
1612 | 1659 |
1613 | 1660 |
| 1661 bool SemiSpace::SetTotalCapacity(int new_capacity) { |
| 1662 CHECK(!is_committed()); |
| 1663 if (new_capacity >= initial_total_capacity_ && |
| 1664 new_capacity <= maximum_total_capacity_) { |
| 1665 total_capacity_ = new_capacity; |
| 1666 return true; |
| 1667 } |
| 1668 return false; |
| 1669 } |
| 1670 |
| 1671 |
1614 void SemiSpace::FlipPages(intptr_t flags, intptr_t mask) { | 1672 void SemiSpace::FlipPages(intptr_t flags, intptr_t mask) { |
1615 anchor_.set_owner(this); | 1673 anchor_.set_owner(this); |
1616 // Fixup back-pointers to anchor. Address of anchor changes | 1674 // Fixup back-pointers to anchor. Address of anchor changes |
1617 // when we swap. | 1675 // when we swap. |
1618 anchor_.prev_page()->set_next_page(&anchor_); | 1676 anchor_.prev_page()->set_next_page(&anchor_); |
1619 anchor_.next_page()->set_prev_page(&anchor_); | 1677 anchor_.next_page()->set_prev_page(&anchor_); |
1620 | 1678 |
1621 bool becomes_to_space = (id_ == kFromSpace); | 1679 bool becomes_to_space = (id_ == kFromSpace); |
1622 id_ = becomes_to_space ? kToSpace : kFromSpace; | 1680 id_ = becomes_to_space ? kToSpace : kFromSpace; |
1623 NewSpacePage* page = anchor_.next_page(); | 1681 NewSpacePage* page = anchor_.next_page(); |
(...skipping 1487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3111 object->ShortPrint(); | 3169 object->ShortPrint(); |
3112 PrintF("\n"); | 3170 PrintF("\n"); |
3113 } | 3171 } |
3114 printf(" --------------------------------------\n"); | 3172 printf(" --------------------------------------\n"); |
3115 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); | 3173 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); |
3116 } | 3174 } |
3117 | 3175 |
3118 #endif // DEBUG | 3176 #endif // DEBUG |
3119 } | 3177 } |
3120 } // namespace v8::internal | 3178 } // namespace v8::internal |
OLD | NEW |