| 1 | // Licensed to the .NET Foundation under one or more agreements. | 
|---|
| 2 | // The .NET Foundation licenses this file to you under the MIT license. | 
|---|
| 3 | // See the LICENSE file in the project root for more information. | 
|---|
| 4 |  | 
|---|
| 5 | #include <stdint.h> | 
|---|
| 6 | #include <windows.h> | 
|---|
| 7 | #include "debugmacros.h" | 
|---|
| 8 | #include "iallocator.h" | 
|---|
| 9 | #include "gcinfoarraylist.h" | 
|---|
| 10 | #include "safemath.h" | 
|---|
| 11 |  | 
|---|
| 12 | inline size_t roundUp(size_t size, size_t alignment) | 
|---|
| 13 | { | 
|---|
| 14 | // `alignment` must be a power of two | 
|---|
| 15 | assert(alignment != 0); | 
|---|
| 16 | assert((alignment & (alignment - 1)) == 0); | 
|---|
| 17 |  | 
|---|
| 18 | return (size + (alignment - 1)) & ~(alignment - 1); | 
|---|
| 19 | } | 
|---|
| 20 |  | 
|---|
| 21 | GcInfoArrayListBase::GcInfoArrayListBase(IAllocator* allocator) | 
|---|
| 22 | : m_allocator(allocator), | 
|---|
| 23 | m_firstChunk(nullptr), | 
|---|
| 24 | m_lastChunk(nullptr), | 
|---|
| 25 | m_lastChunkCount(0), | 
|---|
| 26 | m_lastChunkCapacity(0), | 
|---|
| 27 | m_itemCount(0) | 
|---|
| 28 | { | 
|---|
| 29 | assert(m_allocator != nullptr); | 
|---|
| 30 | } | 
|---|
| 31 |  | 
|---|
| 32 | GcInfoArrayListBase::~GcInfoArrayListBase() | 
|---|
| 33 | { | 
|---|
| 34 | for (ChunkBase* list = m_firstChunk, *chunk; list != nullptr; list = chunk) | 
|---|
| 35 | { | 
|---|
| 36 | chunk = list->m_next; | 
|---|
| 37 | m_allocator->Free(list); | 
|---|
| 38 | } | 
|---|
| 39 | } | 
|---|
| 40 |  | 
|---|
| 41 | void GcInfoArrayListBase::AppendNewChunk(size_t firstChunkCapacity, size_t elementSize, size_t chunkAlignment) | 
|---|
| 42 | { | 
|---|
| 43 | size_t chunkCapacity = (m_firstChunk == nullptr) ? firstChunkCapacity : (m_lastChunkCapacity * GrowthFactor); | 
|---|
| 44 |  | 
|---|
| 45 | S_SIZE_T chunkSize = S_SIZE_T(roundUp(sizeof(ChunkBase), chunkAlignment)) + (S_SIZE_T(elementSize) * S_SIZE_T(chunkCapacity)); | 
|---|
| 46 | assert(!chunkSize.IsOverflow()); | 
|---|
| 47 |  | 
|---|
| 48 | ChunkBase* chunk = reinterpret_cast<ChunkBase*>(m_allocator->Alloc(chunkSize.Value())); | 
|---|
| 49 | chunk->m_next = nullptr; | 
|---|
| 50 |  | 
|---|
| 51 | if (m_lastChunk != nullptr) | 
|---|
| 52 | { | 
|---|
| 53 | assert(m_firstChunk != nullptr); | 
|---|
| 54 | m_lastChunk->m_next = chunk; | 
|---|
| 55 | } | 
|---|
| 56 | else | 
|---|
| 57 | { | 
|---|
| 58 | assert(m_lastChunk == nullptr); | 
|---|
| 59 | m_firstChunk = chunk; | 
|---|
| 60 | } | 
|---|
| 61 |  | 
|---|
| 62 | m_lastChunk = chunk; | 
|---|
| 63 | m_lastChunkCount = 0; | 
|---|
| 64 | m_lastChunkCapacity = chunkCapacity; | 
|---|
| 65 | } | 
|---|
| 66 |  | 
|---|
| 67 | GcInfoArrayListBase::IteratorBase::IteratorBase(GcInfoArrayListBase* list, size_t firstChunkCapacity) | 
|---|
| 68 | : m_list(list) | 
|---|
| 69 | { | 
|---|
| 70 | assert(m_list != nullptr); | 
|---|
| 71 |  | 
|---|
| 72 | // Note: if the list is empty, m_list->firstChunk == nullptr == m_list->lastChunk and m_lastChunkCount == 0. | 
|---|
| 73 | //       In that case, the next two lines will set m_currentChunk to nullptr and m_currentChunkCount to 0. | 
|---|
| 74 | m_currentChunk = m_list->m_firstChunk; | 
|---|
| 75 | m_currentChunkCount = (m_currentChunk == m_list->m_lastChunk) ? m_list->m_lastChunkCount : firstChunkCapacity; | 
|---|
| 76 | } | 
|---|
| 77 |  | 
|---|
| 78 | GcInfoArrayListBase::ChunkBase* GcInfoArrayListBase::IteratorBase::GetNextChunk(size_t& elementCount) | 
|---|
| 79 | { | 
|---|
| 80 | if (m_currentChunk == nullptr) | 
|---|
| 81 | { | 
|---|
| 82 | elementCount = 0; | 
|---|
| 83 | return nullptr; | 
|---|
| 84 | } | 
|---|
| 85 |  | 
|---|
| 86 | ChunkBase* chunk = m_currentChunk; | 
|---|
| 87 | elementCount = m_currentChunkCount; | 
|---|
| 88 |  | 
|---|
| 89 | m_currentChunk = m_currentChunk->m_next; | 
|---|
| 90 | if (m_currentChunk == nullptr) | 
|---|
| 91 | { | 
|---|
| 92 | m_currentChunkCount = 0; | 
|---|
| 93 | } | 
|---|
| 94 | else if (m_currentChunk == m_list->m_lastChunk) | 
|---|
| 95 | { | 
|---|
| 96 | m_currentChunkCount = m_list->m_lastChunkCount; | 
|---|
| 97 | } | 
|---|
| 98 | else | 
|---|
| 99 | { | 
|---|
| 100 | m_currentChunkCount *= GrowthFactor; | 
|---|
| 101 | } | 
|---|
| 102 |  | 
|---|
| 103 | return chunk; | 
|---|
| 104 | } | 
|---|
| 105 |  | 
|---|