| 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 #ifndef V8_HEAP_SPACES_H_ | 5 #ifndef V8_HEAP_SPACES_H_ |
| 6 #define V8_HEAP_SPACES_H_ | 6 #define V8_HEAP_SPACES_H_ |
| 7 | 7 |
| 8 #include <list> |
| 9 |
| 8 #include "src/allocation.h" | 10 #include "src/allocation.h" |
| 9 #include "src/atomic-utils.h" | 11 #include "src/atomic-utils.h" |
| 10 #include "src/base/atomicops.h" | 12 #include "src/base/atomicops.h" |
| 11 #include "src/base/bits.h" | 13 #include "src/base/bits.h" |
| 12 #include "src/base/platform/mutex.h" | 14 #include "src/base/platform/mutex.h" |
| 13 #include "src/flags.h" | 15 #include "src/flags.h" |
| 14 #include "src/hashmap.h" | 16 #include "src/hashmap.h" |
| 15 #include "src/list.h" | 17 #include "src/list.h" |
| 16 #include "src/objects.h" | 18 #include "src/objects.h" |
| 17 #include "src/utils.h" | 19 #include "src/utils.h" |
| (...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 // candidates selection cycle. | 435 // candidates selection cycle. |
| 434 FORCE_EVACUATION_CANDIDATE_FOR_TESTING, | 436 FORCE_EVACUATION_CANDIDATE_FOR_TESTING, |
| 435 | 437 |
| 436 // This flag is intended to be used for testing. | 438 // This flag is intended to be used for testing. |
| 437 NEVER_ALLOCATE_ON_PAGE, | 439 NEVER_ALLOCATE_ON_PAGE, |
| 438 | 440 |
| 439 // The memory chunk is already logically freed, however the actual freeing | 441 // The memory chunk is already logically freed, however the actual freeing |
| 440 // still has to be performed. | 442 // still has to be performed. |
| 441 PRE_FREED, | 443 PRE_FREED, |
| 442 | 444 |
| 445 // |POOLED|: When actually freeing this chunk, only uncommit and do not |
| 446 // give up the reservation as we still reuse the chunk at some point. |
| 447 POOLED, |
| 448 |
| 443 // |COMPACTION_WAS_ABORTED|: Indicates that the compaction in this page | 449 // |COMPACTION_WAS_ABORTED|: Indicates that the compaction in this page |
| 444 // has been aborted and needs special handling by the sweeper. | 450 // has been aborted and needs special handling by the sweeper. |
| 445 COMPACTION_WAS_ABORTED, | 451 COMPACTION_WAS_ABORTED, |
| 446 | 452 |
| 447 // |ANCHOR|: Flag is set if page is an anchor. | 453 // |ANCHOR|: Flag is set if page is an anchor. |
| 448 ANCHOR, | 454 ANCHOR, |
| 449 | 455 |
| 450 // Last flag, keep at bottom. | 456 // Last flag, keep at bottom. |
| 451 NUM_MEMORY_CHUNK_FLAGS | 457 NUM_MEMORY_CHUNK_FLAGS |
| 452 }; | 458 }; |
| (...skipping 805 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1258 STATIC_ASSERT(Page::kPageSize % kRegionSize == 0); | 1264 STATIC_ASSERT(Page::kPageSize % kRegionSize == 0); |
| 1259 | 1265 |
| 1260 Address starts_[kSize]; | 1266 Address starts_[kSize]; |
| 1261 }; | 1267 }; |
| 1262 | 1268 |
| 1263 | 1269 |
| 1264 // ---------------------------------------------------------------------------- | 1270 // ---------------------------------------------------------------------------- |
| 1265 // A space acquires chunks of memory from the operating system. The memory | 1271 // A space acquires chunks of memory from the operating system. The memory |
| 1266 // allocator allocated and deallocates pages for the paged heap spaces and large | 1272 // allocator allocated and deallocates pages for the paged heap spaces and large |
| 1267 // pages for large object space. | 1273 // pages for large object space. |
| 1268 // | |
| 1269 // Each space has to manage it's own pages. | |
| 1270 // | |
| 1271 class MemoryAllocator { | 1274 class MemoryAllocator { |
| 1272 public: | 1275 public: |
| 1276 // Unmapper takes care of concurrently unmapping and uncommitting memory |
| 1277 // chunks. |
| 1278 class Unmapper { |
| 1279 public: |
| 1280 class UnmapFreeMemoryTask; |
| 1281 |
| 1282 explicit Unmapper(MemoryAllocator* allocator) |
| 1283 : allocator_(allocator), |
| 1284 pending_unmapping_tasks_semaphore_(0), |
| 1285 concurrent_unmapping_tasks_active_(0) {} |
| 1286 |
| 1287 void AddMemoryChunkSafe(MemoryChunk* chunk) { |
| 1288 if ((chunk->size() == Page::kPageSize) && |
| 1289 (chunk->executable() != EXECUTABLE)) { |
| 1290 AddMemoryChunkSafe<kRegular>(chunk); |
| 1291 } else { |
| 1292 AddMemoryChunkSafe<kNonRegular>(chunk); |
| 1293 } |
| 1294 } |
| 1295 |
| 1296 MemoryChunk* TryGetPooledMemoryChunkSafe() { |
| 1297 // Procedure: |
| 1298 // (1) Try to get a chunk that was declared as pooled and already has |
| 1299 // been uncommitted. |
| 1300 // (2) Try to steal any memory chunk of kPageSize that would've been |
| 1301 // unmapped. |
| 1302 MemoryChunk* chunk = GetMemoryChunkSafe<kPooled>(); |
| 1303 if (chunk == nullptr) { |
| 1304 chunk = GetMemoryChunkSafe<kRegular>(); |
| 1305 if (chunk != nullptr) { |
| 1306 // For stolen chunks we need to manually free any allocated memory. |
| 1307 chunk->ReleaseAllocatedMemory(); |
| 1308 } |
| 1309 } |
| 1310 return chunk; |
| 1311 } |
| 1312 |
| 1313 void FreeQueuedChunks(); |
| 1314 bool WaitUntilCompleted(); |
| 1315 |
| 1316 private: |
| 1317 enum ChunkQueueType { |
| 1318 kRegular, // Pages of kPageSize that do not live in a CodeRange and |
| 1319 // can thus be used for stealing. |
| 1320 kNonRegular, // Large chunks and executable chunks. |
| 1321 kPooled, // Pooled chunks, already uncommited and ready for reuse. |
| 1322 kNumberOfChunkQueues, |
| 1323 }; |
| 1324 |
| 1325 template <ChunkQueueType type> |
| 1326 void AddMemoryChunkSafe(MemoryChunk* chunk) { |
| 1327 base::LockGuard<base::Mutex> guard(&mutex_); |
| 1328 chunks_[type].push_back(chunk); |
| 1329 } |
| 1330 |
| 1331 template <ChunkQueueType type> |
| 1332 MemoryChunk* GetMemoryChunkSafe() { |
| 1333 base::LockGuard<base::Mutex> guard(&mutex_); |
| 1334 if (chunks_[type].empty()) return nullptr; |
| 1335 MemoryChunk* chunk = chunks_[type].front(); |
| 1336 chunks_[type].pop_front(); |
| 1337 return chunk; |
| 1338 } |
| 1339 |
| 1340 void PerformFreeMemoryOnQueuedChunks(); |
| 1341 |
| 1342 base::Mutex mutex_; |
| 1343 MemoryAllocator* allocator_; |
| 1344 std::list<MemoryChunk*> chunks_[kNumberOfChunkQueues]; |
| 1345 base::Semaphore pending_unmapping_tasks_semaphore_; |
| 1346 intptr_t concurrent_unmapping_tasks_active_; |
| 1347 |
| 1348 friend class MemoryAllocator; |
| 1349 }; |
| 1350 |
| 1273 enum AllocationMode { | 1351 enum AllocationMode { |
| 1274 kRegular, | 1352 kRegular, |
| 1275 kPooled, | 1353 kPooled, |
| 1276 }; | 1354 }; |
| 1355 enum FreeMode { |
| 1356 kFull, |
| 1357 kPreFreeAndQueue, |
| 1358 kPooledAndQueue, |
| 1359 }; |
| 1277 | 1360 |
| 1278 explicit MemoryAllocator(Isolate* isolate); | 1361 explicit MemoryAllocator(Isolate* isolate); |
| 1279 | 1362 |
| 1280 // Initializes its internal bookkeeping structures. | 1363 // Initializes its internal bookkeeping structures. |
| 1281 // Max capacity of the total space and executable memory limit. | 1364 // Max capacity of the total space and executable memory limit. |
| 1282 bool SetUp(intptr_t max_capacity, intptr_t capacity_executable, | 1365 bool SetUp(intptr_t max_capacity, intptr_t capacity_executable, |
| 1283 intptr_t code_range_size); | 1366 intptr_t code_range_size); |
| 1284 | 1367 |
| 1285 void TearDown(); | 1368 void TearDown(); |
| 1286 | 1369 |
| 1287 // Allocates a Page from the allocator. AllocationMode is used to indicate | 1370 // Allocates a Page from the allocator. AllocationMode is used to indicate |
| 1288 // whether pooled allocation, which only works for MemoryChunk::kPageSize, | 1371 // whether pooled allocation, which only works for MemoryChunk::kPageSize, |
| 1289 // should be tried first. | 1372 // should be tried first. |
| 1290 template <MemoryAllocator::AllocationMode alloc_mode = kRegular, | 1373 template <MemoryAllocator::AllocationMode alloc_mode = kRegular, |
| 1291 typename SpaceType> | 1374 typename SpaceType> |
| 1292 Page* AllocatePage(intptr_t size, SpaceType* owner, Executability executable); | 1375 Page* AllocatePage(intptr_t size, SpaceType* owner, Executability executable); |
| 1293 | 1376 |
| 1294 LargePage* AllocateLargePage(intptr_t size, LargeObjectSpace* owner, | 1377 LargePage* AllocateLargePage(intptr_t size, LargeObjectSpace* owner, |
| 1295 Executability executable); | 1378 Executability executable); |
| 1296 | 1379 |
| 1297 // PreFree logically frees the object, i.e., it takes care of the size | 1380 template <MemoryAllocator::FreeMode mode = kFull> |
| 1298 // bookkeeping and calls the allocation callback. | |
| 1299 void PreFreeMemory(MemoryChunk* chunk); | |
| 1300 | |
| 1301 // FreeMemory can be called concurrently when PreFree was executed before. | |
| 1302 void PerformFreeMemory(MemoryChunk* chunk); | |
| 1303 | |
| 1304 // Free is a wrapper method. For kRegular AllocationMode it calls PreFree and | |
| 1305 // PerformFreeMemory together. For kPooled it will dispatch to pooled free. | |
| 1306 template <MemoryAllocator::AllocationMode mode = kRegular> | |
| 1307 void Free(MemoryChunk* chunk); | 1381 void Free(MemoryChunk* chunk); |
| 1308 | 1382 |
| 1309 // Returns allocated spaces in bytes. | 1383 // Returns allocated spaces in bytes. |
| 1310 intptr_t Size() { return size_.Value(); } | 1384 intptr_t Size() { return size_.Value(); } |
| 1311 | 1385 |
| 1312 // Returns allocated executable spaces in bytes. | 1386 // Returns allocated executable spaces in bytes. |
| 1313 intptr_t SizeExecutable() { return size_executable_.Value(); } | 1387 intptr_t SizeExecutable() { return size_executable_.Value(); } |
| 1314 | 1388 |
| 1315 // Returns the maximum available bytes of heaps. | 1389 // Returns the maximum available bytes of heaps. |
| 1316 intptr_t Available() { | 1390 intptr_t Available() { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1402 DCHECK_NE(LO_SPACE, space); | 1476 DCHECK_NE(LO_SPACE, space); |
| 1403 return (space == CODE_SPACE) ? CodePageAreaSize() | 1477 return (space == CODE_SPACE) ? CodePageAreaSize() |
| 1404 : Page::kAllocatableMemory; | 1478 : Page::kAllocatableMemory; |
| 1405 } | 1479 } |
| 1406 | 1480 |
| 1407 MUST_USE_RESULT bool CommitExecutableMemory(base::VirtualMemory* vm, | 1481 MUST_USE_RESULT bool CommitExecutableMemory(base::VirtualMemory* vm, |
| 1408 Address start, size_t commit_size, | 1482 Address start, size_t commit_size, |
| 1409 size_t reserved_size); | 1483 size_t reserved_size); |
| 1410 | 1484 |
| 1411 CodeRange* code_range() { return code_range_; } | 1485 CodeRange* code_range() { return code_range_; } |
| 1486 Unmapper* unmapper() { return &unmapper_; } |
| 1412 | 1487 |
| 1413 private: | 1488 private: |
| 1489 // PreFree logically frees the object, i.e., it takes care of the size |
| 1490 // bookkeeping and calls the allocation callback. |
| 1491 void PreFreeMemory(MemoryChunk* chunk); |
| 1492 |
| 1493 // FreeMemory can be called concurrently when PreFree was executed before. |
| 1494 void PerformFreeMemory(MemoryChunk* chunk); |
| 1495 |
| 1414 // See AllocatePage for public interface. Note that currently we only support | 1496 // See AllocatePage for public interface. Note that currently we only support |
| 1415 // pools for NOT_EXECUTABLE pages of size MemoryChunk::kPageSize. | 1497 // pools for NOT_EXECUTABLE pages of size MemoryChunk::kPageSize. |
| 1416 template <typename SpaceType> | 1498 template <typename SpaceType> |
| 1417 MemoryChunk* AllocatePagePooled(SpaceType* owner); | 1499 MemoryChunk* AllocatePagePooled(SpaceType* owner); |
| 1418 | 1500 |
| 1419 // Free that chunk into the pool. | |
| 1420 void FreePooled(MemoryChunk* chunk); | |
| 1421 | |
| 1422 Isolate* isolate_; | 1501 Isolate* isolate_; |
| 1423 | 1502 |
| 1424 CodeRange* code_range_; | 1503 CodeRange* code_range_; |
| 1425 | 1504 |
| 1426 // Maximum space size in bytes. | 1505 // Maximum space size in bytes. |
| 1427 intptr_t capacity_; | 1506 intptr_t capacity_; |
| 1428 // Maximum subset of capacity_ that can be executable | 1507 // Maximum subset of capacity_ that can be executable |
| 1429 intptr_t capacity_executable_; | 1508 intptr_t capacity_executable_; |
| 1430 | 1509 |
| 1431 // Allocated space size in bytes. | 1510 // Allocated space size in bytes. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1467 // values only if they did not change in between. | 1546 // values only if they did not change in between. |
| 1468 void* ptr = nullptr; | 1547 void* ptr = nullptr; |
| 1469 do { | 1548 do { |
| 1470 ptr = lowest_ever_allocated_.Value(); | 1549 ptr = lowest_ever_allocated_.Value(); |
| 1471 } while ((low < ptr) && !lowest_ever_allocated_.TrySetValue(ptr, low)); | 1550 } while ((low < ptr) && !lowest_ever_allocated_.TrySetValue(ptr, low)); |
| 1472 do { | 1551 do { |
| 1473 ptr = highest_ever_allocated_.Value(); | 1552 ptr = highest_ever_allocated_.Value(); |
| 1474 } while ((high > ptr) && !highest_ever_allocated_.TrySetValue(ptr, high)); | 1553 } while ((high > ptr) && !highest_ever_allocated_.TrySetValue(ptr, high)); |
| 1475 } | 1554 } |
| 1476 | 1555 |
| 1477 List<MemoryChunk*> chunk_pool_; | |
| 1478 | |
| 1479 base::VirtualMemory last_chunk_; | 1556 base::VirtualMemory last_chunk_; |
| 1557 Unmapper unmapper_; |
| 1480 | 1558 |
| 1481 friend class TestCodeRangeScope; | 1559 friend class TestCodeRangeScope; |
| 1482 | 1560 |
| 1483 DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryAllocator); | 1561 DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryAllocator); |
| 1484 }; | 1562 }; |
| 1485 | 1563 |
| 1486 | 1564 |
| 1487 // ----------------------------------------------------------------------------- | 1565 // ----------------------------------------------------------------------------- |
| 1488 // Interface for heap object iterator to be implemented by all object space | 1566 // Interface for heap object iterator to be implemented by all object space |
| 1489 // object iterators. | 1567 // object iterators. |
| (...skipping 1548 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3038 count = 0; | 3116 count = 0; |
| 3039 } | 3117 } |
| 3040 // Must be small, since an iteration is used for lookup. | 3118 // Must be small, since an iteration is used for lookup. |
| 3041 static const int kMaxComments = 64; | 3119 static const int kMaxComments = 64; |
| 3042 }; | 3120 }; |
| 3043 #endif | 3121 #endif |
| 3044 } // namespace internal | 3122 } // namespace internal |
| 3045 } // namespace v8 | 3123 } // namespace v8 |
| 3046 | 3124 |
| 3047 #endif // V8_HEAP_SPACES_H_ | 3125 #endif // V8_HEAP_SPACES_H_ |
| OLD | NEW |