summaryrefslogtreecommitdiff
path: root/src/inc/blobfetcher.h
blob: 0c640f0d6d9a5834546507cfb92dee01982a4fa9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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_