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 | |