| 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 | |
| 10 #include "src/allocation.h" | 8 #include "src/allocation.h" |
| 11 #include "src/atomic-utils.h" | 9 #include "src/atomic-utils.h" |
| 12 #include "src/base/atomicops.h" | 10 #include "src/base/atomicops.h" |
| 13 #include "src/base/bits.h" | 11 #include "src/base/bits.h" |
| 14 #include "src/base/platform/mutex.h" | 12 #include "src/base/platform/mutex.h" |
| 15 #include "src/flags.h" | 13 #include "src/flags.h" |
| 16 #include "src/hashmap.h" | 14 #include "src/hashmap.h" |
| 17 #include "src/list.h" | 15 #include "src/list.h" |
| 18 #include "src/objects.h" | 16 #include "src/objects.h" |
| 19 #include "src/utils.h" | 17 #include "src/utils.h" |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 436 // candidates selection cycle. | 434 // candidates selection cycle. |
| 437 FORCE_EVACUATION_CANDIDATE_FOR_TESTING, | 435 FORCE_EVACUATION_CANDIDATE_FOR_TESTING, |
| 438 | 436 |
| 439 // This flag is intended to be used for testing. | 437 // This flag is intended to be used for testing. |
| 440 NEVER_ALLOCATE_ON_PAGE, | 438 NEVER_ALLOCATE_ON_PAGE, |
| 441 | 439 |
| 442 // The memory chunk is already logically freed, however the actual freeing | 440 // The memory chunk is already logically freed, however the actual freeing |
| 443 // still has to be performed. | 441 // still has to be performed. |
| 444 PRE_FREED, | 442 PRE_FREED, |
| 445 | 443 |
| 446 // |POOLED|: When actually freeing this chunk, only uncommit and do not | |
| 447 // give up the reservation as we still reuse the chunk at some point. | |
| 448 POOLED, | |
| 449 | |
| 450 // |COMPACTION_WAS_ABORTED|: Indicates that the compaction in this page | 444 // |COMPACTION_WAS_ABORTED|: Indicates that the compaction in this page |
| 451 // has been aborted and needs special handling by the sweeper. | 445 // has been aborted and needs special handling by the sweeper. |
| 452 COMPACTION_WAS_ABORTED, | 446 COMPACTION_WAS_ABORTED, |
| 453 | 447 |
| 454 // Last flag, keep at bottom. | 448 // Last flag, keep at bottom. |
| 455 NUM_MEMORY_CHUNK_FLAGS | 449 NUM_MEMORY_CHUNK_FLAGS |
| 456 }; | 450 }; |
| 457 | 451 |
| 458 // |kSweepingDone|: The page state when sweeping is complete or sweeping must | 452 // |kSweepingDone|: The page state when sweeping is complete or sweeping must |
| 459 // not be performed on that page. Sweeper threads that are done with their | 453 // not be performed on that page. Sweeper threads that are done with their |
| (...skipping 795 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1255 STATIC_ASSERT(Page::kPageSize % kRegionSize == 0); | 1249 STATIC_ASSERT(Page::kPageSize % kRegionSize == 0); |
| 1256 | 1250 |
| 1257 Address starts_[kSize]; | 1251 Address starts_[kSize]; |
| 1258 }; | 1252 }; |
| 1259 | 1253 |
| 1260 | 1254 |
| 1261 // ---------------------------------------------------------------------------- | 1255 // ---------------------------------------------------------------------------- |
| 1262 // A space acquires chunks of memory from the operating system. The memory | 1256 // A space acquires chunks of memory from the operating system. The memory |
| 1263 // allocator allocated and deallocates pages for the paged heap spaces and large | 1257 // allocator allocated and deallocates pages for the paged heap spaces and large |
| 1264 // pages for large object space. | 1258 // pages for large object space. |
| 1259 // |
| 1260 // Each space has to manage it's own pages. |
| 1261 // |
| 1265 class MemoryAllocator { | 1262 class MemoryAllocator { |
| 1266 public: | 1263 public: |
| 1267 // Unmapper takes care of concurrently unmapping and uncommitting memory | |
| 1268 // chunks. | |
| 1269 class Unmapper { | |
| 1270 public: | |
| 1271 class UnmapFreeMemoryTask; | |
| 1272 | |
| 1273 explicit Unmapper(MemoryAllocator* allocator) | |
| 1274 : allocator_(allocator), | |
| 1275 pending_unmapping_tasks_semaphore_(0), | |
| 1276 concurrent_unmapping_tasks_active_(0) {} | |
| 1277 | |
| 1278 void AddMemoryChunkSafe(MemoryChunk* chunk) { | |
| 1279 if ((chunk->size() == Page::kPageSize) && | |
| 1280 (chunk->executable() == EXECUTABLE)) { | |
| 1281 AddMemoryChunkSafe<kRegular>(chunk); | |
| 1282 } else { | |
| 1283 AddMemoryChunkSafe<kNonRegular>(chunk); | |
| 1284 } | |
| 1285 } | |
| 1286 | |
| 1287 MemoryChunk* TryGetPooledMemoryChunkSafe() { | |
| 1288 // Procedure: | |
| 1289 // (1) Try to get a chunk that was declared as pooled and already has | |
| 1290 // been uncommitted. | |
| 1291 // (2) Try to steal any memory chunk of kPageSize that would've been | |
| 1292 // unmapped. | |
| 1293 MemoryChunk* chunk = GetMemoryChunkSafe<kPooled>(); | |
| 1294 if (chunk == nullptr) { | |
| 1295 chunk = GetMemoryChunkSafe<kRegular>(); | |
| 1296 if (chunk != nullptr) { | |
| 1297 // For stolen chunks we need to manually free any allocated memory. | |
| 1298 chunk->ReleaseAllocatedMemory(); | |
| 1299 } | |
| 1300 } | |
| 1301 return chunk; | |
| 1302 } | |
| 1303 | |
| 1304 void FreeQueuedChunks(); | |
| 1305 bool WaitUntilCompleted(); | |
| 1306 | |
| 1307 private: | |
| 1308 enum ChunkQueueType { | |
| 1309 kRegular, // Pages of kPageSize that do not live in a CodeRange and | |
| 1310 // can thus be used for stealing. | |
| 1311 kNonRegular, // Large chunks and executable chunks. | |
| 1312 kPooled, // Pooled chunks, already uncommited and ready for reuse. | |
| 1313 kNumberOfChunkQueues, | |
| 1314 }; | |
| 1315 | |
| 1316 template <ChunkQueueType type> | |
| 1317 void AddMemoryChunkSafe(MemoryChunk* chunk) { | |
| 1318 base::LockGuard<base::Mutex> guard(&mutex_); | |
| 1319 chunks_[type].push_back(chunk); | |
| 1320 } | |
| 1321 | |
| 1322 template <ChunkQueueType type> | |
| 1323 MemoryChunk* GetMemoryChunkSafe() { | |
| 1324 base::LockGuard<base::Mutex> guard(&mutex_); | |
| 1325 if (chunks_[type].empty()) return nullptr; | |
| 1326 MemoryChunk* chunk = chunks_[type].front(); | |
| 1327 chunks_[type].pop_front(); | |
| 1328 return chunk; | |
| 1329 } | |
| 1330 | |
| 1331 void PerformFreeMemoryOnQueuedChunks(); | |
| 1332 | |
| 1333 base::Mutex mutex_; | |
| 1334 MemoryAllocator* allocator_; | |
| 1335 std::list<MemoryChunk*> chunks_[kNumberOfChunkQueues]; | |
| 1336 base::Semaphore pending_unmapping_tasks_semaphore_; | |
| 1337 intptr_t concurrent_unmapping_tasks_active_; | |
| 1338 | |
| 1339 friend class MemoryAllocator; | |
| 1340 }; | |
| 1341 | |
| 1342 enum AllocationMode { | 1264 enum AllocationMode { |
| 1343 kRegular, | 1265 kRegular, |
| 1344 kPooled, | 1266 kPooled, |
| 1345 }; | 1267 }; |
| 1346 enum FreeMode { | |
| 1347 kFull, | |
| 1348 kPreFreeAndQueue, | |
| 1349 kPooledAndQueue, | |
| 1350 }; | |
| 1351 | 1268 |
| 1352 explicit MemoryAllocator(Isolate* isolate); | 1269 explicit MemoryAllocator(Isolate* isolate); |
| 1353 | 1270 |
| 1354 // Initializes its internal bookkeeping structures. | 1271 // Initializes its internal bookkeeping structures. |
| 1355 // Max capacity of the total space and executable memory limit. | 1272 // Max capacity of the total space and executable memory limit. |
| 1356 bool SetUp(intptr_t max_capacity, intptr_t capacity_executable, | 1273 bool SetUp(intptr_t max_capacity, intptr_t capacity_executable, |
| 1357 intptr_t code_range_size); | 1274 intptr_t code_range_size); |
| 1358 | 1275 |
| 1359 void TearDown(); | 1276 void TearDown(); |
| 1360 | 1277 |
| 1361 // Allocates either Page or NewSpacePage from the allocator. AllocationMode | 1278 // Allocates either Page or NewSpacePage from the allocator. AllocationMode |
| 1362 // is used to indicate whether pooled allocation, which only works for | 1279 // is used to indicate whether pooled allocation, which only works for |
| 1363 // MemoryChunk::kPageSize, should be tried first. | 1280 // MemoryChunk::kPageSize, should be tried first. |
| 1364 template <typename PageType, MemoryAllocator::AllocationMode mode = kRegular, | 1281 template <typename PageType, MemoryAllocator::AllocationMode mode = kRegular, |
| 1365 typename SpaceType> | 1282 typename SpaceType> |
| 1366 PageType* AllocatePage(intptr_t size, SpaceType* owner, | 1283 PageType* AllocatePage(intptr_t size, SpaceType* owner, |
| 1367 Executability executable); | 1284 Executability executable); |
| 1368 | 1285 |
| 1369 template <MemoryAllocator::FreeMode mode = kFull> | 1286 // PreFree logically frees the object, i.e., it takes care of the size |
| 1287 // bookkeeping and calls the allocation callback. |
| 1288 void PreFreeMemory(MemoryChunk* chunk); |
| 1289 |
| 1290 // FreeMemory can be called concurrently when PreFree was executed before. |
| 1291 void PerformFreeMemory(MemoryChunk* chunk); |
| 1292 |
| 1293 // Free is a wrapper method. For kRegular AllocationMode it calls PreFree and |
| 1294 // PerformFreeMemory together. For kPooled it will dispatch to pooled free. |
| 1295 template <MemoryAllocator::AllocationMode mode = kRegular> |
| 1370 void Free(MemoryChunk* chunk); | 1296 void Free(MemoryChunk* chunk); |
| 1371 | 1297 |
| 1372 // Returns allocated spaces in bytes. | 1298 // Returns allocated spaces in bytes. |
| 1373 intptr_t Size() { return size_.Value(); } | 1299 intptr_t Size() { return size_.Value(); } |
| 1374 | 1300 |
| 1375 // Returns allocated executable spaces in bytes. | 1301 // Returns allocated executable spaces in bytes. |
| 1376 intptr_t SizeExecutable() { return size_executable_.Value(); } | 1302 intptr_t SizeExecutable() { return size_executable_.Value(); } |
| 1377 | 1303 |
| 1378 // Returns the maximum available bytes of heaps. | 1304 // Returns the maximum available bytes of heaps. |
| 1379 intptr_t Available() { | 1305 intptr_t Available() { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1465 DCHECK_NE(LO_SPACE, space); | 1391 DCHECK_NE(LO_SPACE, space); |
| 1466 return (space == CODE_SPACE) ? CodePageAreaSize() | 1392 return (space == CODE_SPACE) ? CodePageAreaSize() |
| 1467 : Page::kAllocatableMemory; | 1393 : Page::kAllocatableMemory; |
| 1468 } | 1394 } |
| 1469 | 1395 |
| 1470 MUST_USE_RESULT bool CommitExecutableMemory(base::VirtualMemory* vm, | 1396 MUST_USE_RESULT bool CommitExecutableMemory(base::VirtualMemory* vm, |
| 1471 Address start, size_t commit_size, | 1397 Address start, size_t commit_size, |
| 1472 size_t reserved_size); | 1398 size_t reserved_size); |
| 1473 | 1399 |
| 1474 CodeRange* code_range() { return code_range_; } | 1400 CodeRange* code_range() { return code_range_; } |
| 1475 Unmapper* unmapper() { return &unmapper_; } | |
| 1476 | 1401 |
| 1477 private: | 1402 private: |
| 1478 // PreFree logically frees the object, i.e., it takes care of the size | |
| 1479 // bookkeeping and calls the allocation callback. | |
| 1480 void PreFreeMemory(MemoryChunk* chunk); | |
| 1481 | |
| 1482 // FreeMemory can be called concurrently when PreFree was executed before. | |
| 1483 void PerformFreeMemory(MemoryChunk* chunk); | |
| 1484 | |
| 1485 // See AllocatePage for public interface. Note that currently we only support | 1403 // See AllocatePage for public interface. Note that currently we only support |
| 1486 // pools for NOT_EXECUTABLE pages of size MemoryChunk::kPageSize. | 1404 // pools for NOT_EXECUTABLE pages of size MemoryChunk::kPageSize. |
| 1487 template <typename SpaceType> | 1405 template <typename SpaceType> |
| 1488 MemoryChunk* AllocatePagePooled(SpaceType* owner); | 1406 MemoryChunk* AllocatePagePooled(SpaceType* owner); |
| 1489 | 1407 |
| 1408 // Free that chunk into the pool. |
| 1409 void FreePooled(MemoryChunk* chunk); |
| 1410 |
| 1490 Isolate* isolate_; | 1411 Isolate* isolate_; |
| 1491 | 1412 |
| 1492 CodeRange* code_range_; | 1413 CodeRange* code_range_; |
| 1493 | 1414 |
| 1494 // Maximum space size in bytes. | 1415 // Maximum space size in bytes. |
| 1495 intptr_t capacity_; | 1416 intptr_t capacity_; |
| 1496 // Maximum subset of capacity_ that can be executable | 1417 // Maximum subset of capacity_ that can be executable |
| 1497 intptr_t capacity_executable_; | 1418 intptr_t capacity_executable_; |
| 1498 | 1419 |
| 1499 // Allocated space size in bytes. | 1420 // Allocated space size in bytes. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1535 // values only if they did not change in between. | 1456 // values only if they did not change in between. |
| 1536 void* ptr = nullptr; | 1457 void* ptr = nullptr; |
| 1537 do { | 1458 do { |
| 1538 ptr = lowest_ever_allocated_.Value(); | 1459 ptr = lowest_ever_allocated_.Value(); |
| 1539 } while ((low < ptr) && !lowest_ever_allocated_.TrySetValue(ptr, low)); | 1460 } while ((low < ptr) && !lowest_ever_allocated_.TrySetValue(ptr, low)); |
| 1540 do { | 1461 do { |
| 1541 ptr = highest_ever_allocated_.Value(); | 1462 ptr = highest_ever_allocated_.Value(); |
| 1542 } while ((high > ptr) && !highest_ever_allocated_.TrySetValue(ptr, high)); | 1463 } while ((high > ptr) && !highest_ever_allocated_.TrySetValue(ptr, high)); |
| 1543 } | 1464 } |
| 1544 | 1465 |
| 1466 List<MemoryChunk*> chunk_pool_; |
| 1467 |
| 1545 base::VirtualMemory last_chunk_; | 1468 base::VirtualMemory last_chunk_; |
| 1546 Unmapper unmapper_; | |
| 1547 | 1469 |
| 1548 friend class TestCodeRangeScope; | 1470 friend class TestCodeRangeScope; |
| 1549 | 1471 |
| 1550 DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryAllocator); | 1472 DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryAllocator); |
| 1551 }; | 1473 }; |
| 1552 | 1474 |
| 1553 | 1475 |
| 1554 // ----------------------------------------------------------------------------- | 1476 // ----------------------------------------------------------------------------- |
| 1555 // Interface for heap object iterator to be implemented by all object space | 1477 // Interface for heap object iterator to be implemented by all object space |
| 1556 // object iterators. | 1478 // object iterators. |
| (...skipping 1631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3188 count = 0; | 3110 count = 0; |
| 3189 } | 3111 } |
| 3190 // Must be small, since an iteration is used for lookup. | 3112 // Must be small, since an iteration is used for lookup. |
| 3191 static const int kMaxComments = 64; | 3113 static const int kMaxComments = 64; |
| 3192 }; | 3114 }; |
| 3193 #endif | 3115 #endif |
| 3194 } // namespace internal | 3116 } // namespace internal |
| 3195 } // namespace v8 | 3117 } // namespace v8 |
| 3196 | 3118 |
| 3197 #endif // V8_HEAP_SPACES_H_ | 3119 #endif // V8_HEAP_SPACES_H_ |
| OLD | NEW |