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
23class CBlobFetcher
24{
25protected:
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
65public:
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()
109inline 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
118inline unsigned CBlobFetcher::CPillar::GetAllocateSize() const
119{
120 LIMITED_METHOD_CONTRACT;
121 return m_nTargetSize;
122}
123
124inline char* CBlobFetcher::CPillar::GetRawDataStart()
125{
126 LIMITED_METHOD_CONTRACT;
127 return m_dataStart;
128}
129
130inline BOOL CBlobFetcher::CPillar::Contains(__in char *ptr)
131{
132 LIMITED_METHOD_CONTRACT;
133
134 return ptr >= m_dataStart && ptr < m_dataCur;
135}
136
137inline 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//-----------------------------------------------------------------------------
148inline 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
157inline 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
165inline 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