| 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 | // CBlobFetcher - it fetches binary chunks, similar to new, but more controlled |
| 6 | // |
| 7 | // Fast, dynamic, memory management which doesn't relocate blocks |
| 8 | // m_pIndex has array of pillars, where each pillar starts off empty and has |
| 9 | // just-in-time allocation. As each pillar fills up, we move to the next pillar |
| 10 | // If the entire array of pillars fill up, we need to allocate a new array and |
| 11 | // copy the pillars over. But the actual data returned from GetBlock() never |
| 12 | // gets moved. So everyone's happy. |
| 13 | // |
| 14 | //***************************************************************************** |
| 15 | |
| 16 | |
| 17 | #ifndef __BLOB_FETCHER_H_ |
| 18 | #define __BLOB_FETCHER_H_ |
| 19 | |
| 20 | #include <windef.h> |
| 21 | |
| 22 | |
| 23 | class CBlobFetcher |
| 24 | { |
| 25 | protected: |
| 26 | |
| 27 | class CPillar { |
| 28 | public: |
| 29 | CPillar(); |
| 30 | ~CPillar(); |
| 31 | |
| 32 | void SetAllocateSize(unsigned nSize); |
| 33 | unsigned GetAllocateSize() const; |
| 34 | |
| 35 | char* MakeNewBlock(unsigned len, unsigned pad); |
| 36 | void StealDataFrom(CPillar & src); |
| 37 | unsigned GetDataLen() const; |
| 38 | char* GetRawDataStart(); |
| 39 | BOOL Contains(__in char *ptr); |
| 40 | ULONG32 GetOffset(__in char *ptr); |
| 41 | |
| 42 | protected: |
| 43 | unsigned m_nTargetSize; // when we allocate, make it this large |
| 44 | |
| 45 | // Make these public so CBlobFetcher can do easy manipulation |
| 46 | public: |
| 47 | char* m_dataAlloc; |
| 48 | char* m_dataStart; |
| 49 | char* m_dataCur; |
| 50 | char* m_dataEnd; |
| 51 | }; |
| 52 | |
| 53 | |
| 54 | CPillar * m_pIndex; // array of pillars |
| 55 | |
| 56 | unsigned m_nIndexMax; // actual size of m_ppIndex |
| 57 | unsigned m_nIndexUsed; // current pillar, so start at 0 |
| 58 | |
| 59 | unsigned m_nDataLen; // sum of all pillars' lengths |
| 60 | |
| 61 | // Don't allow these because they'll mess up the ownership |
| 62 | CBlobFetcher(const CBlobFetcher & src); |
| 63 | CBlobFetcher& operator=(const CBlobFetcher & src); |
| 64 | |
| 65 | public: |
| 66 | #if defined(_WIN64) |
| 67 | // needs to be 64 so that we can purposefully cache align code in ngen'd images |
| 68 | enum { maxAlign = 64 }; // maximum alignment we support |
| 69 | #else |
| 70 | enum { maxAlign = 32 }; // maximum alignment we support |
| 71 | #endif |
| 72 | CBlobFetcher(); |
| 73 | ~CBlobFetcher(); |
| 74 | |
| 75 | // get a block to write on (use instead of write to avoid copy) |
| 76 | char * MakeNewBlock(unsigned int nSize, unsigned align=1); |
| 77 | |
| 78 | // Index segment as if this were linear |
| 79 | char * ComputePointer(unsigned offset) const; |
| 80 | |
| 81 | // Determine if pointer came from this fetcher |
| 82 | BOOL ContainsPointer(__in char *ptr) const; |
| 83 | |
| 84 | // Find an offset as if this were linear |
| 85 | unsigned ComputeOffset(__in char *ptr) const; |
| 86 | |
| 87 | // Write out the section to the stream |
| 88 | HRESULT Write(HANDLE file); |
| 89 | |
| 90 | // Write out the section to memory |
| 91 | HRESULT WriteMem(void ** pMem); |
| 92 | |
| 93 | // Get the total length of all our data (sum of all the pillar's data length's) |
| 94 | // cached value, so light weight & no computations |
| 95 | unsigned GetDataLen() const; |
| 96 | |
| 97 | HRESULT Merge(CBlobFetcher *destination); |
| 98 | |
| 99 | // Set the blob fetcher to slow growth mode. This should be done before any allocations |
| 100 | void SetInitialGrowth(unsigned growth); |
| 101 | }; |
| 102 | |
| 103 | |
| 104 | //***************************************************************************** |
| 105 | // Inlines |
| 106 | //***************************************************************************** |
| 107 | |
| 108 | // Set the size that the Pillar will allocate if we call getBlock() |
| 109 | inline void CBlobFetcher::CPillar::SetAllocateSize(unsigned nSize) |
| 110 | { |
| 111 | LIMITED_METHOD_CONTRACT; |
| 112 | m_nTargetSize = nSize; |
| 113 | } |
| 114 | |
| 115 | // Get the size we will allocate so we can decide if we need to change it |
| 116 | // This is not the same as the GetDataLen() and is only useful |
| 117 | // before we do the allocation |
| 118 | inline unsigned CBlobFetcher::CPillar::GetAllocateSize() const |
| 119 | { |
| 120 | LIMITED_METHOD_CONTRACT; |
| 121 | return m_nTargetSize; |
| 122 | } |
| 123 | |
| 124 | inline char* CBlobFetcher::CPillar::GetRawDataStart() |
| 125 | { |
| 126 | LIMITED_METHOD_CONTRACT; |
| 127 | return m_dataStart; |
| 128 | } |
| 129 | |
| 130 | inline BOOL CBlobFetcher::CPillar::Contains(__in char *ptr) |
| 131 | { |
| 132 | LIMITED_METHOD_CONTRACT; |
| 133 | |
| 134 | return ptr >= m_dataStart && ptr < m_dataCur; |
| 135 | } |
| 136 | |
| 137 | inline ULONG32 CBlobFetcher::CPillar::GetOffset(__in char *ptr) |
| 138 | { |
| 139 | LIMITED_METHOD_CONTRACT; |
| 140 | _ASSERTE(Contains(ptr)); |
| 141 | |
| 142 | return (ULONG32)(ptr - m_dataStart); |
| 143 | } |
| 144 | |
| 145 | //----------------------------------------------------------------------------- |
| 146 | // Calculate the length of data being used, (not the length allocated) |
| 147 | //----------------------------------------------------------------------------- |
| 148 | inline unsigned CBlobFetcher::CPillar::GetDataLen() const |
| 149 | { |
| 150 | LIMITED_METHOD_CONTRACT; |
| 151 | |
| 152 | _ASSERTE((m_dataCur >= m_dataStart) && (m_dataCur <= m_dataEnd)); |
| 153 | |
| 154 | return (unsigned)(m_dataCur - m_dataStart); |
| 155 | } |
| 156 | |
| 157 | inline unsigned CBlobFetcher::GetDataLen() const |
| 158 | { |
| 159 | LIMITED_METHOD_CONTRACT; |
| 160 | |
| 161 | return m_nDataLen; |
| 162 | } |
| 163 | |
| 164 | // Set the blob fetcher to slow growth mode. This should be done before any allocations |
| 165 | inline void CBlobFetcher::SetInitialGrowth(unsigned growth) |
| 166 | { |
| 167 | _ASSERTE(GetDataLen() == 0); |
| 168 | if (GetDataLen() == 0) |
| 169 | { |
| 170 | m_pIndex[0].SetAllocateSize(growth); |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | #endif // __BLOB_FETCHER_H_ |
| 175 | |