diff options
Diffstat (limited to 'src/inc/blobfetcher.h')
-rw-r--r-- | src/inc/blobfetcher.h | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/src/inc/blobfetcher.h b/src/inc/blobfetcher.h new file mode 100644 index 0000000000..0c640f0d6d --- /dev/null +++ b/src/inc/blobfetcher.h @@ -0,0 +1,174 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +//***************************************************************************** +// CBlobFetcher - it fetches binary chunks, similar to new, but more controlled +// +// Fast, dynamic, memory management which doesn't relocate blocks +// m_pIndex has array of pillars, where each pillar starts off empty and has +// just-in-time allocation. As each pillar fills up, we move to the next pillar +// If the entire array of pillars fill up, we need to allocate a new array and +// copy the pillars over. But the actual data returned from GetBlock() never +// gets moved. So everyone's happy. +// +//***************************************************************************** + + +#ifndef __BLOB_FETCHER_H_ +#define __BLOB_FETCHER_H_ + +#include <windef.h> + + +class CBlobFetcher +{ +protected: + + class CPillar { + public: + CPillar(); + ~CPillar(); + + void SetAllocateSize(unsigned nSize); + unsigned GetAllocateSize() const; + + char* MakeNewBlock(unsigned len, unsigned pad); + void StealDataFrom(CPillar & src); + unsigned GetDataLen() const; + char* GetRawDataStart(); + BOOL Contains(__in char *ptr); + ULONG32 GetOffset(__in char *ptr); + + protected: + unsigned m_nTargetSize; // when we allocate, make it this large + + // Make these public so CBlobFetcher can do easy manipulation + public: + char* m_dataAlloc; + char* m_dataStart; + char* m_dataCur; + char* m_dataEnd; + }; + + + CPillar * m_pIndex; // array of pillars + + unsigned m_nIndexMax; // actual size of m_ppIndex + unsigned m_nIndexUsed; // current pillar, so start at 0 + + unsigned m_nDataLen; // sum of all pillars' lengths + +// Don't allow these because they'll mess up the ownership + CBlobFetcher(const CBlobFetcher & src); + CBlobFetcher& operator=(const CBlobFetcher & src); + +public: +#if defined(_WIN64) + // needs to be 64 so that we can purposefully cache align code in ngen'd images + enum { maxAlign = 64 }; // maximum alignment we support +#else + enum { maxAlign = 32 }; // maximum alignment we support +#endif + CBlobFetcher(); + ~CBlobFetcher(); + +// get a block to write on (use instead of write to avoid copy) + char * MakeNewBlock(unsigned int nSize, unsigned align=1); + +// Index segment as if this were linear + char * ComputePointer(unsigned offset) const; + +// Determine if pointer came from this fetcher + BOOL ContainsPointer(__in char *ptr) const; + +// Find an offset as if this were linear + unsigned ComputeOffset(__in char *ptr) const; + +// Write out the section to the stream + HRESULT Write(HANDLE file); + +// Write out the section to memory + HRESULT WriteMem(void ** pMem); + +// Get the total length of all our data (sum of all the pillar's data length's) +// cached value, so light weight & no computations + unsigned GetDataLen() const; + + HRESULT Merge(CBlobFetcher *destination); + +// Set the blob fetcher to slow growth mode. This should be done before any allocations + void SetInitialGrowth(unsigned growth); +}; + + +//***************************************************************************** +// Inlines +//***************************************************************************** + +// Set the size that the Pillar will allocate if we call getBlock() +inline void CBlobFetcher::CPillar::SetAllocateSize(unsigned nSize) +{ + LIMITED_METHOD_CONTRACT; + m_nTargetSize = nSize; +} + +// Get the size we will allocate so we can decide if we need to change it +// This is not the same as the GetDataLen() and is only useful +// before we do the allocation +inline unsigned CBlobFetcher::CPillar::GetAllocateSize() const +{ + LIMITED_METHOD_CONTRACT; + return m_nTargetSize; +} + +inline char* CBlobFetcher::CPillar::GetRawDataStart() +{ + LIMITED_METHOD_CONTRACT; + return m_dataStart; +} + +inline BOOL CBlobFetcher::CPillar::Contains(__in char *ptr) +{ + LIMITED_METHOD_CONTRACT; + + return ptr >= m_dataStart && ptr < m_dataCur; +} + +inline ULONG32 CBlobFetcher::CPillar::GetOffset(__in char *ptr) +{ + LIMITED_METHOD_CONTRACT; + _ASSERTE(Contains(ptr)); + + return (ULONG32)(ptr - m_dataStart); +} + +//----------------------------------------------------------------------------- +// Calculate the length of data being used, (not the length allocated) +//----------------------------------------------------------------------------- +inline unsigned CBlobFetcher::CPillar::GetDataLen() const +{ + LIMITED_METHOD_CONTRACT; + + _ASSERTE((m_dataCur >= m_dataStart) && (m_dataCur <= m_dataEnd)); + + return (unsigned)(m_dataCur - m_dataStart); +} + +inline unsigned CBlobFetcher::GetDataLen() const +{ + LIMITED_METHOD_CONTRACT; + + return m_nDataLen; +} + +// Set the blob fetcher to slow growth mode. This should be done before any allocations +inline void CBlobFetcher::SetInitialGrowth(unsigned growth) +{ + _ASSERTE(GetDataLen() == 0); + if (GetDataLen() == 0) + { + m_pIndex[0].SetAllocateSize(growth); + } +} + +#endif // __BLOB_FETCHER_H_ |