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 | // File: HotHeapWriter.cpp |
6 | // |
7 | |
8 | // |
9 | // Class code:HotHeapWriter represents a writer of hot heap into MetaData hot stream (collected by IBC). |
10 | // |
11 | // ====================================================================================== |
12 | |
13 | #include "external.h" |
14 | |
15 | #include "hotheapwriter.h" |
16 | #include "../heaps/export.h" |
17 | |
18 | #include <stgpool.h> |
19 | #include <metamodelpub.h> |
20 | #include <utilcode.h> |
21 | #include "../inc/streamutil.h" |
22 | |
23 | #include "hotdataformat.h" |
24 | |
25 | #ifdef FEATURE_PREJIT |
26 | // Cannot be included without FEATURE_PREJIT: |
27 | #include <corcompile.h> |
28 | #endif //FEATURE_PREJIT |
29 | |
30 | namespace MetaData |
31 | { |
32 | |
33 | // -------------------------------------------------------------------------------------- |
34 | // |
35 | // Creates writer for #String heap. |
36 | // |
37 | HotHeapWriter::HotHeapWriter( |
38 | const StringHeapRW *pStringHeap) |
39 | { |
40 | m_HeapIndex = HeapIndex::StringHeapIndex; |
41 | m_pStringHeap = pStringHeap; |
42 | } // HotHeapWriter::HotHeapWriter |
43 | |
44 | // -------------------------------------------------------------------------------------- |
45 | // |
46 | // Creates writer for #Blob or #US heap (if fUserStringHeap is TRUE). |
47 | // |
48 | HotHeapWriter::HotHeapWriter( |
49 | const BlobHeapRW *pBlobHeap, |
50 | BOOL fUserStringHeap) |
51 | { |
52 | m_HeapIndex = fUserStringHeap ? HeapIndex::UserStringHeapIndex : HeapIndex::BlobHeapIndex; |
53 | m_pBlobHeap = pBlobHeap; |
54 | } // HotHeapWriter::HotHeapWriter |
55 | |
56 | // -------------------------------------------------------------------------------------- |
57 | // |
58 | // Creates writer for #GUID heap. |
59 | // |
60 | HotHeapWriter::HotHeapWriter( |
61 | const GuidHeapRW *pGuidHeap) |
62 | { |
63 | m_HeapIndex = HeapIndex::GuidHeapIndex; |
64 | m_pGuidHeap = pGuidHeap; |
65 | } // HotHeapWriter::HotHeapWriter |
66 | |
67 | // -------------------------------------------------------------------------------------- |
68 | // |
69 | // Destroys the writer of hot heap. |
70 | // |
71 | void |
72 | HotHeapWriter::Delete() |
73 | { |
74 | } // HotHeapWriter::Delete |
75 | |
76 | typedef struct _RidOffsetPair |
77 | { |
78 | ULONG rid; |
79 | ULONG offset; |
80 | // compare function for qsort |
81 | static int __cdecl Compare(void const *_x, void const *_y); |
82 | } RidOffsetPair; |
83 | |
84 | // static |
85 | int __cdecl |
86 | RidOffsetPair::Compare(void const *_x, void const *_y) |
87 | { |
88 | RidOffsetPair const *x = reinterpret_cast<RidOffsetPair const *>(_x); |
89 | RidOffsetPair const *y = reinterpret_cast<RidOffsetPair const *>(_y); |
90 | |
91 | return x->rid - y->rid; |
92 | } |
93 | |
94 | // -------------------------------------------------------------------------------------- |
95 | // |
96 | // Stores hot data reported by IBC in profile data (code:CorProfileData) to a stream. |
97 | // Aligns output stream to 4-bytes. |
98 | // |
99 | __checkReturn |
100 | HRESULT |
101 | HotHeapWriter::SaveToStream( |
102 | IStream *pStream, |
103 | CorProfileData *pProfileData, |
104 | UINT32 *pnSavedSize) const |
105 | { |
106 | _ASSERTE(pStream != NULL); |
107 | _ASSERTE(pProfileData != NULL); |
108 | _ASSERTE(pnSavedSize != NULL); |
109 | |
110 | #ifdef FEATURE_PREJIT |
111 | HRESULT hr = S_OK; |
112 | UINT32 nOffset = 0; |
113 | UINT32 nValueHeapStart_PositiveOffset; |
114 | UINT32 nValueOffsetTableStart_PositiveOffset; |
115 | UINT32 nIndexTableStart_PositiveOffset; |
116 | |
117 | // data |
118 | // |
119 | |
120 | // number of hot tokens |
121 | UINT32 nHotItemsCount = pProfileData->GetHotTokens( |
122 | GetTableIndex(), |
123 | 1 << ProfilingFlags_MetaData, |
124 | 1 << ProfilingFlags_MetaData, |
125 | NULL, |
126 | 0); |
127 | CONSISTENCY_CHECK(nHotItemsCount != 0); |
128 | |
129 | NewArrayHolder<UINT32> hotItemArr = new (nothrow) UINT32[nHotItemsCount]; |
130 | IfNullRet(hotItemArr); |
131 | |
132 | // get hot tokens |
133 | static_assert_no_msg(sizeof(UINT32) == sizeof(mdToken)); |
134 | pProfileData->GetHotTokens( |
135 | GetTableIndex(), |
136 | 1 << ProfilingFlags_MetaData, |
137 | 1 << ProfilingFlags_MetaData, |
138 | reinterpret_cast<mdToken *>(&hotItemArr[0]), |
139 | nHotItemsCount); |
140 | |
141 | // convert tokens to rids |
142 | for (UINT32 i = 0; i < nHotItemsCount; i++) |
143 | { |
144 | hotItemArr[i] = RidFromToken(hotItemArr[i]); |
145 | } |
146 | |
147 | NewArrayHolder<RidOffsetPair> offsetMapping = new (nothrow) RidOffsetPair[nHotItemsCount]; |
148 | IfNullRet(offsetMapping); |
149 | |
150 | // write data |
151 | nValueHeapStart_PositiveOffset = nOffset; |
152 | |
153 | // note that we write hot items in the order they appear in pProfileData->GetHotTokens |
154 | // this is so that we preserve the ordering optimizations done by IbcMerge |
155 | for (UINT32 i = 0; i < nHotItemsCount; i++) |
156 | { |
157 | DataBlob data; |
158 | IfFailRet(GetData( |
159 | hotItemArr[i], |
160 | &data)); |
161 | |
162 | // keep track of the offset at which each hot item is written |
163 | offsetMapping[i].rid = hotItemArr[i]; |
164 | offsetMapping[i].offset = nOffset; |
165 | |
166 | IfFailRet(StreamUtil::WriteToStream( |
167 | pStream, |
168 | data.GetDataPointer(), |
169 | data.GetSize(), |
170 | &nOffset)); |
171 | } |
172 | |
173 | IfFailRet(StreamUtil::AlignDWORD(pStream, &nOffset)); |
174 | |
175 | // sort by rid so that a hot rid can be looked up by binary search |
176 | qsort(offsetMapping, nHotItemsCount, sizeof(RidOffsetPair), RidOffsetPair::Compare); |
177 | |
178 | // initialize table of offsets to data |
179 | NewArrayHolder<UINT32> dataIndices = new (nothrow) UINT32[nHotItemsCount]; |
180 | IfNullRet(dataIndices); |
181 | |
182 | // fill in the hotItemArr (now sorted by rid) and dataIndices array with each offset |
183 | for (UINT32 i = 0; i < nHotItemsCount; i++) |
184 | { |
185 | hotItemArr[i] = offsetMapping[i].rid; |
186 | dataIndices[i] = offsetMapping[i].offset; |
187 | } |
188 | |
189 | // table of offsets to data |
190 | // |
191 | |
192 | nValueOffsetTableStart_PositiveOffset = nOffset; |
193 | IfFailRet(StreamUtil::WriteToStream(pStream, &dataIndices[0], sizeof(UINT32) * nHotItemsCount, &nOffset)); |
194 | |
195 | // rid table (sorted) |
196 | // |
197 | |
198 | nIndexTableStart_PositiveOffset = nOffset; |
199 | |
200 | IfFailRet(StreamUtil::WriteToStream(pStream, &hotItemArr[0], nHotItemsCount * sizeof(UINT32), &nOffset)); |
201 | IfFailRet(StreamUtil::AlignDWORD(pStream, &nOffset)); |
202 | |
203 | { |
204 | // hot pool header |
205 | struct HotHeapHeader ; |
206 | |
207 | // fix offsets |
208 | header.m_nIndexTableStart_NegativeOffset = nOffset - nIndexTableStart_PositiveOffset; |
209 | header.m_nValueOffsetTableStart_NegativeOffset = nOffset - nValueOffsetTableStart_PositiveOffset; |
210 | header.m_nValueHeapStart_NegativeOffset = nOffset - nValueHeapStart_PositiveOffset; |
211 | |
212 | // write header |
213 | IfFailRet(StreamUtil::WriteToStream(pStream, &header, sizeof(header), &nOffset)); |
214 | } |
215 | |
216 | *pnSavedSize = nOffset; |
217 | |
218 | #endif //FEATURE_PREJIT |
219 | |
220 | return S_OK; |
221 | } // HotHeapWriter::PersistHotToStream |
222 | |
223 | // -------------------------------------------------------------------------------------- |
224 | // |
225 | // Returns index of the heap as table index used by IBC (code:CorProfileData). |
226 | // |
227 | UINT32 |
228 | HotHeapWriter::GetTableIndex() const |
229 | { |
230 | return TBL_COUNT + m_HeapIndex.Get(); |
231 | } // HotHeapWriter::GetTableIndex |
232 | |
233 | // -------------------------------------------------------------------------------------- |
234 | // |
235 | // Returns heap data at index (nIndex). |
236 | // |
237 | __checkReturn |
238 | HRESULT |
239 | HotHeapWriter::GetData( |
240 | UINT32 nIndex, |
241 | DataBlob *pData) const |
242 | { |
243 | HRESULT hr; |
244 | |
245 | switch (m_HeapIndex.Get()) |
246 | { |
247 | case HeapIndex::StringHeapIndex: |
248 | { |
249 | LPCSTR szString; |
250 | IfFailGo(m_pStringHeap->GetString( |
251 | nIndex, |
252 | &szString)); |
253 | _ASSERTE(hr == S_OK); |
254 | |
255 | // This should not overflow, because we checked it before, but it doesn't hurt |
256 | S_UINT32 cbStringSize = S_UINT32(strlen(szString)) + S_UINT32(1); |
257 | if (cbStringSize.IsOverflow()) |
258 | { |
259 | Debug_ReportInternalError("There's a bug in the string heap consistency - string is too long." ); |
260 | IfFailGo(METADATA_E_INTERNAL_ERROR); |
261 | } |
262 | |
263 | pData->Init((BYTE *)szString, cbStringSize.Value()); |
264 | return S_OK; |
265 | } |
266 | case HeapIndex::GuidHeapIndex: |
267 | { |
268 | // The nIndex is in fact 0-based offset into GUID heap (0, 16, 32, ...), convert it to 1-based element index (1, 2, 3, ...) for GetGuid method |
269 | if ((nIndex % sizeof(GUID)) != 0) |
270 | { |
271 | Debug_ReportInternalError("There's a bug in the caller/IBC - this should be GUID offset aligned to 16-B." ); |
272 | IfFailGo(METADATA_E_INTERNAL_ERROR); |
273 | } |
274 | nIndex = (nIndex / sizeof(GUID)) + 1; |
275 | |
276 | GUID UNALIGNED *pGuid; |
277 | IfFailGo(const_cast<GuidHeapRW *>(m_pGuidHeap)->GetGuid( |
278 | nIndex, |
279 | &pGuid)); |
280 | _ASSERTE(hr == S_OK); |
281 | pData->Init((BYTE *)pGuid, sizeof(GUID)); |
282 | return S_OK; |
283 | } |
284 | case HeapIndex::BlobHeapIndex: |
285 | case HeapIndex::UserStringHeapIndex: |
286 | { |
287 | IfFailGo(const_cast<BlobHeapRW *>(m_pBlobHeap)->GetBlobWithSizePrefix( |
288 | nIndex, |
289 | pData)); |
290 | _ASSERTE(hr == S_OK); |
291 | |
292 | return S_OK; |
293 | } |
294 | default: |
295 | Debug_ReportInternalError("There's a bug in the caller - this is wrong heap index." ); |
296 | IfFailGo(METADATA_E_INTERNAL_ERROR); |
297 | } |
298 | return S_OK; |
299 | |
300 | ErrExit: |
301 | pData->Clear(); |
302 | return hr; |
303 | } // HotHeapWriter::GetData |
304 | |
305 | }; // namespace MetaData |
306 | |