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 | //***************************************************************************** |
6 | // MetaModelRW.h -- header file for Read/Write compressed COM+ metadata. |
7 | // |
8 | |
9 | // |
10 | // Used by Emitters and by E&C. |
11 | // |
12 | //***************************************************************************** |
13 | #ifndef _METAMODELRW_H_ |
14 | #define _METAMODELRW_H_ |
15 | |
16 | #if _MSC_VER >= 1100 |
17 | # pragma once |
18 | #endif |
19 | |
20 | #include "metamodel.h" // Base classes for the MetaModel. |
21 | #include "metadatahash.h" |
22 | #include "rwutil.h" |
23 | #include "shash.h" |
24 | |
25 | #include "../heaps/export.h" |
26 | #include "../hotdata/export.h" |
27 | #include "../tables/export.h" |
28 | |
29 | struct HENUMInternal; |
30 | #ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE |
31 | struct IMDCustomDataSource; |
32 | #endif |
33 | |
34 | // ENUM for marking bit |
35 | enum |
36 | { |
37 | InvalidMarkedBit = 0x00000000, |
38 | ModuleMarkedBit = 0x00000001, |
39 | TypeRefMarkedBit = 0x00000002, |
40 | TypeDefMarkedBit = 0x00000004, |
41 | FieldMarkedBit = 0x00000008, |
42 | MethodMarkedBit = 0x00000010, |
43 | ParamMarkedBit = 0x00000020, |
44 | MemberRefMarkedBit = 0x00000040, |
45 | CustomAttributeMarkedBit = 0x00000080, |
46 | DeclSecurityMarkedBit = 0x00000100, |
47 | = 0x00000200, |
48 | EventMarkedBit = 0x00000400, |
49 | PropertyMarkedBit = 0x00000800, |
50 | MethodImplMarkedBit = 0x00001000, |
51 | ModuleRefMarkedBit = 0x00002000, |
52 | TypeSpecMarkedBit = 0x00004000, |
53 | InterfaceImplMarkedBit = 0x00008000, |
54 | AssemblyRefMarkedBit = 0x00010000, |
55 | MethodSpecMarkedBit = 0x00020000, |
56 | |
57 | }; |
58 | |
59 | // entry for marking UserString |
60 | struct FilterUserStringEntry |
61 | { |
62 | DWORD m_tkString; |
63 | bool m_fMarked; |
64 | }; |
65 | |
66 | class FilterTable : public CDynArray<DWORD> |
67 | { |
68 | public: |
69 | FilterTable() { m_daUserStringMarker = NULL; } |
70 | ~FilterTable(); |
71 | |
72 | __checkReturn FORCEINLINE HRESULT MarkTypeRef(mdToken tk) { return MarkToken(tk, TypeRefMarkedBit); } |
73 | __checkReturn FORCEINLINE HRESULT MarkTypeDef(mdToken tk) { return MarkToken(tk, TypeDefMarkedBit); } |
74 | __checkReturn FORCEINLINE HRESULT MarkField(mdToken tk) { return MarkToken(tk, FieldMarkedBit); } |
75 | __checkReturn FORCEINLINE HRESULT MarkMethod(mdToken tk) { return MarkToken(tk, MethodMarkedBit); } |
76 | __checkReturn FORCEINLINE HRESULT MarkParam(mdToken tk) { return MarkToken(tk, ParamMarkedBit); } |
77 | __checkReturn FORCEINLINE HRESULT MarkMemberRef(mdToken tk) { return MarkToken(tk, MemberRefMarkedBit); } |
78 | __checkReturn FORCEINLINE HRESULT MarkCustomAttribute(mdToken tk) { return MarkToken(tk, CustomAttributeMarkedBit); } |
79 | __checkReturn FORCEINLINE HRESULT MarkDeclSecurity(mdToken tk) { return MarkToken(tk, DeclSecurityMarkedBit); } |
80 | __checkReturn FORCEINLINE HRESULT MarkSignature(mdToken tk) { return MarkToken(tk, SignatureMarkedBit); } |
81 | __checkReturn FORCEINLINE HRESULT MarkEvent(mdToken tk) { return MarkToken(tk, EventMarkedBit); } |
82 | __checkReturn FORCEINLINE HRESULT MarkProperty(mdToken tk) { return MarkToken(tk, PropertyMarkedBit); } |
83 | __checkReturn FORCEINLINE HRESULT MarkMethodImpl(RID rid) |
84 | { |
85 | return MarkToken(TokenFromRid(rid, TBL_MethodImpl << 24), MethodImplMarkedBit); |
86 | } |
87 | __checkReturn FORCEINLINE HRESULT MarkModuleRef(mdToken tk) { return MarkToken(tk, ModuleRefMarkedBit); } |
88 | __checkReturn FORCEINLINE HRESULT MarkTypeSpec(mdToken tk) { return MarkToken(tk, TypeSpecMarkedBit); } |
89 | __checkReturn FORCEINLINE HRESULT MarkInterfaceImpl(mdToken tk) { return MarkToken(tk, InterfaceImplMarkedBit); } |
90 | __checkReturn FORCEINLINE HRESULT MarkAssemblyRef(mdToken tk) { return MarkToken(tk, AssemblyRefMarkedBit); } |
91 | __checkReturn FORCEINLINE HRESULT MarkMethodSpec(mdToken tk) { return MarkToken(tk, MethodSpecMarkedBit); } |
92 | |
93 | // It may look inconsistent but it is because taht UserString an offset to the heap. |
94 | // We don't want to grow the FilterTable to the size of the UserString heap. |
95 | // So we use the heap's marking system instead... |
96 | // |
97 | __checkReturn HRESULT MarkUserString(mdString str); |
98 | |
99 | __checkReturn HRESULT MarkNewUserString(mdString str); |
100 | |
101 | FORCEINLINE bool IsTypeRefMarked(mdToken tk) { return IsTokenMarked(tk, TypeRefMarkedBit); } |
102 | FORCEINLINE bool IsTypeDefMarked(mdToken tk) { return IsTokenMarked(tk, TypeDefMarkedBit); } |
103 | FORCEINLINE bool IsFieldMarked(mdToken tk) { return IsTokenMarked(tk, FieldMarkedBit); } |
104 | FORCEINLINE bool IsMethodMarked(mdToken tk) { return IsTokenMarked(tk, MethodMarkedBit); } |
105 | FORCEINLINE bool IsParamMarked(mdToken tk) { return IsTokenMarked(tk, ParamMarkedBit); } |
106 | FORCEINLINE bool IsMemberRefMarked(mdToken tk) { return IsTokenMarked(tk, MemberRefMarkedBit); } |
107 | FORCEINLINE bool IsCustomAttributeMarked(mdToken tk) { return IsTokenMarked(tk, CustomAttributeMarkedBit); } |
108 | FORCEINLINE bool IsDeclSecurityMarked(mdToken tk) { return IsTokenMarked(tk, DeclSecurityMarkedBit); } |
109 | FORCEINLINE bool (mdToken tk) { return IsTokenMarked(tk, SignatureMarkedBit); } |
110 | FORCEINLINE bool IsEventMarked(mdToken tk) { return IsTokenMarked(tk, EventMarkedBit); } |
111 | FORCEINLINE bool IsPropertyMarked(mdToken tk) { return IsTokenMarked(tk, PropertyMarkedBit); } |
112 | FORCEINLINE bool IsMethodImplMarked(RID rid) |
113 | { |
114 | return IsTokenMarked(TokenFromRid(rid, TBL_MethodImpl << 24), MethodImplMarkedBit); |
115 | } |
116 | FORCEINLINE bool IsModuleRefMarked(mdToken tk) { return IsTokenMarked(tk, ModuleRefMarkedBit); } |
117 | FORCEINLINE bool IsTypeSpecMarked(mdToken tk) { return IsTokenMarked(tk, TypeSpecMarkedBit); } |
118 | FORCEINLINE bool IsInterfaceImplMarked(mdToken tk){ return IsTokenMarked(tk, InterfaceImplMarkedBit); } |
119 | FORCEINLINE bool IsAssemblyRefMarked(mdToken tk){ return IsTokenMarked(tk, AssemblyRefMarkedBit); } |
120 | FORCEINLINE bool IsMethodSpecMarked(mdToken tk){ return IsTokenMarked(tk, MethodSpecMarkedBit); } |
121 | |
122 | bool IsUserStringMarked(mdString str); |
123 | |
124 | __checkReturn HRESULT UnmarkAll(CMiniMdRW *pMiniMd, ULONG ulSize); |
125 | __checkReturn HRESULT MarkAll(CMiniMdRW *pMiniMd, ULONG ulSize); |
126 | bool IsTokenMarked(mdToken); |
127 | |
128 | __checkReturn FORCEINLINE HRESULT UnmarkTypeDef(mdToken tk) { return UnmarkToken(tk, TypeDefMarkedBit); } |
129 | __checkReturn FORCEINLINE HRESULT UnmarkField(mdToken tk) { return UnmarkToken(tk, FieldMarkedBit); } |
130 | __checkReturn FORCEINLINE HRESULT UnmarkMethod(mdToken tk) { return UnmarkToken(tk, MethodMarkedBit); } |
131 | __checkReturn FORCEINLINE HRESULT UnmarkCustomAttribute(mdToken tk) { return UnmarkToken(tk, CustomAttributeMarkedBit); } |
132 | |
133 | private: |
134 | CDynArray<FilterUserStringEntry> *m_daUserStringMarker; |
135 | bool IsTokenMarked(mdToken tk, DWORD bitMarked); |
136 | __checkReturn HRESULT MarkToken(mdToken tk, DWORD bit); |
137 | __checkReturn HRESULT UnmarkToken(mdToken tk, DWORD bit); |
138 | }; // class FilterTable : public CDynArray<DWORD> |
139 | |
140 | class CMiniMdRW; |
141 | |
142 | //***************************************************************************** |
143 | // This class is used to keep a list of RID. This list of RID can be sorted |
144 | // base on the m_ixCol's value of the m_ixTbl table. |
145 | //***************************************************************************** |
146 | class VirtualSort |
147 | { |
148 | public: |
149 | void Init(ULONG ixTbl, ULONG ixCol, CMiniMdRW *pMiniMd); |
150 | void Uninit(); |
151 | TOKENMAP *m_pMap; // RID for m_ixTbl table. Sorted by on the ixCol |
152 | bool m_isMapValid; |
153 | ULONG m_ixTbl; // Table this is a sorter for. |
154 | ULONG m_ixCol; // Key column in the table. |
155 | CMiniMdRW *m_pMiniMd; // The MiniMd with the data. |
156 | __checkReturn |
157 | HRESULT Sort(); |
158 | private: |
159 | mdToken m_tkBuf; |
160 | __checkReturn |
161 | HRESULT SortRange(int iLeft, int iRight); |
162 | public: |
163 | __checkReturn |
164 | HRESULT Compare( |
165 | RID iLeft, // First item to compare. |
166 | RID iRight, // Second item to compare. |
167 | int *pnResult); // -1, 0, or 1 |
168 | |
169 | private: |
170 | FORCEINLINE void Swap( |
171 | RID iFirst, |
172 | RID iSecond) |
173 | { |
174 | if ( iFirst == iSecond ) return; |
175 | m_tkBuf = *(m_pMap->Get(iFirst)); |
176 | *(m_pMap->Get(iFirst)) = *(m_pMap->Get(iSecond)); |
177 | *(m_pMap->Get(iSecond)) = m_tkBuf; |
178 | } |
179 | |
180 | |
181 | }; // class VirtualSort |
182 | |
183 | class ReorderData |
184 | { |
185 | public: |
186 | typedef enum |
187 | { |
188 | MinReorderBucketType=0, // bucket# shouldn't be less than this value |
189 | Undefined=0, // use this for initialization |
190 | Duplicate=1, // duplicate string |
191 | ProfileData=2, // bucket# for IBC data |
192 | PublicData=3, // bucket# for public data |
193 | OtherData=4, // bucket# for other data |
194 | NonPublicData=5, // bucket# for non-public data |
195 | MaxReorderBucketType=255 // bucket# shouldn't exceeed this value |
196 | } ReorderBucketType; |
197 | }; |
198 | |
199 | typedef CMetaDataHashBase CMemberRefHash; |
200 | typedef CMetaDataHashBase CLookUpHash; |
201 | |
202 | class MDTOKENMAP; |
203 | class MDInternalRW; |
204 | class CorProfileData; |
205 | class UTSemReadWrite; |
206 | |
207 | enum MetaDataReorderingOptions { |
208 | NoReordering=0x0, |
209 | ReArrangeStringPool=0x1 |
210 | }; |
211 | |
212 | #ifdef FEATURE_PREJIT |
213 | |
214 | // {0702E333-8D64-4ca7-B564-4AA56B1FCEA3} |
215 | EXTERN_GUID(IID_IMetaDataCorProfileData, 0x702e333, 0x8d64, 0x4ca7, 0xb5, 0x64, 0x4a, 0xa5, 0x6b, 0x1f, 0xce, 0xa3 ); |
216 | |
217 | #undef INTERFACE |
218 | #define INTERFACE IMetaDataCorProfileData |
219 | DECLARE_INTERFACE_(IMetaDataCorProfileData, IUnknown) |
220 | { |
221 | STDMETHOD(SetCorProfileData)( |
222 | CorProfileData *pProfileData) PURE; // [IN] Pointer to profile data |
223 | }; |
224 | |
225 | // {2B464817-C0F6-454e-99E7-C352D8384D7B} |
226 | EXTERN_GUID(IID_IMDInternalMetadataReorderingOptions, 0x2B464817, 0xC0F6, 0x454e, 0x99, 0xE7, 0xC3, 0x52, 0xD8, 0x38, 0x4D, 0x7B ); |
227 | |
228 | #undef INTERFACE |
229 | #define INTERFACE IMDInternalMetadataReorderingOptions |
230 | DECLARE_INTERFACE_(IMDInternalMetadataReorderingOptions, IUnknown) |
231 | { |
232 | STDMETHOD(SetMetaDataReorderingOptions)( |
233 | MetaDataReorderingOptions options) PURE; // [IN] metadata reordering options |
234 | }; |
235 | |
236 | #endif //FEATURE_PREJIT |
237 | |
238 | template <class MiniMd> class CLiteWeightStgdb; |
239 | //***************************************************************************** |
240 | // Read/Write MiniMd. |
241 | //***************************************************************************** |
242 | class CMiniMdRW : public CMiniMdTemplate<CMiniMdRW> |
243 | { |
244 | public: |
245 | friend class CLiteWeightStgdb<CMiniMdRW>; |
246 | friend class CLiteWeightStgdbRW; |
247 | friend class CMiniMdTemplate<CMiniMdRW>; |
248 | friend class CQuickSortMiniMdRW; |
249 | friend class VirtualSort; |
250 | friend class MDInternalRW; |
251 | friend class RegMeta; |
252 | friend class FilterTable; |
253 | friend class ImportHelper; |
254 | friend class VerifyLayoutsMD; |
255 | |
256 | CMiniMdRW(); |
257 | ~CMiniMdRW(); |
258 | |
259 | __checkReturn |
260 | HRESULT InitNew(); |
261 | __checkReturn |
262 | HRESULT InitOnMem(const void *pBuf, ULONG ulBufLen, int bReadOnly); |
263 | __checkReturn |
264 | HRESULT PostInit(int iLevel); |
265 | __checkReturn |
266 | HRESULT InitPoolOnMem(int iPool, void *pbData, ULONG cbData, int bReadOnly); |
267 | __checkReturn |
268 | HRESULT InitOnRO(CMiniMd *pMd, int bReadOnly); |
269 | #ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE |
270 | __checkReturn |
271 | HRESULT InitOnCustomDataSource(IMDCustomDataSource* pDataSouce); |
272 | #endif |
273 | __checkReturn |
274 | HRESULT ConvertToRW(); |
275 | |
276 | __checkReturn |
277 | HRESULT GetSaveSize( |
278 | CorSaveSize fSave, |
279 | UINT32 *pcbSize, |
280 | DWORD *pbCompressed, |
281 | MetaDataReorderingOptions reorderingOptions = NoReordering, |
282 | CorProfileData *pProfileData = NULL); |
283 | int IsPoolEmpty(int iPool); |
284 | __checkReturn |
285 | HRESULT GetPoolSaveSize(int iPool, UINT32 *pcbSize); |
286 | |
287 | __checkReturn |
288 | HRESULT SaveTablesToStream(IStream *pIStream, MetaDataReorderingOptions reorderingOptions, CorProfileData *pProfileData); |
289 | __checkReturn |
290 | HRESULT SavePoolToStream(int iPool, IStream *pIStream); |
291 | __checkReturn |
292 | HRESULT SaveDone(); |
293 | |
294 | __checkReturn |
295 | HRESULT SetHandler(IUnknown *pIUnk); |
296 | |
297 | __checkReturn |
298 | HRESULT SetOption(OptionValue *pOptionValue); |
299 | __checkReturn |
300 | HRESULT GetOption(OptionValue *pOptionValue); |
301 | |
302 | static ULONG GetTableForToken(mdToken tkn); |
303 | static mdToken GetTokenForTable(ULONG ixTbl); |
304 | |
305 | FORCEINLINE static ULONG TblFromRecId(ULONG ul) { return (ul >> 24)&0x7f; } |
306 | FORCEINLINE static ULONG RidFromRecId(ULONG ul) { return ul & 0xffffff; } |
307 | FORCEINLINE static ULONG RecIdFromRid(ULONG rid, ULONG ixTbl) { return rid | ((ixTbl|0x80) << 24); } |
308 | FORCEINLINE static int IsRecId(ULONG ul) { return (ul & 0x80000000) != 0;} |
309 | |
310 | // Place in every API function before doing any allocations. |
311 | __checkReturn |
312 | FORCEINLINE HRESULT PreUpdate() |
313 | { |
314 | if (m_eGrow == eg_grow) |
315 | { |
316 | return ExpandTables(); |
317 | } |
318 | return S_OK; |
319 | } |
320 | |
321 | __checkReturn |
322 | HRESULT AddRecord( |
323 | UINT32 nTableIndex, |
324 | void **ppRow, |
325 | RID *pRid); |
326 | |
327 | __checkReturn |
328 | FORCEINLINE HRESULT PutCol(ULONG ixTbl, ULONG ixCol, void *pRecord, ULONG uVal) |
329 | { _ASSERTE(ixTbl < TBL_COUNT); _ASSERTE(ixCol < m_TableDefs[ixTbl].m_cCols); |
330 | return PutCol(m_TableDefs[ixTbl].m_pColDefs[ixCol], pRecord, uVal); |
331 | } // HRESULT CMiniMdRW::PutCol() |
332 | __checkReturn |
333 | HRESULT PutString(ULONG ixTbl, ULONG ixCol, void *pRecord, LPCSTR szString); |
334 | __checkReturn |
335 | HRESULT PutStringW(ULONG ixTbl, ULONG ixCol, void *pRecord, LPCWSTR wszString); |
336 | __checkReturn |
337 | HRESULT PutGuid(ULONG ixTbl, ULONG ixCol, void *pRecord, REFGUID guid); |
338 | __checkReturn |
339 | HRESULT ChangeMvid(REFGUID newMvid); |
340 | __checkReturn |
341 | HRESULT PutToken(ULONG ixTbl, ULONG ixCol, void *pRecord, mdToken tk); |
342 | __checkReturn |
343 | HRESULT PutBlob(ULONG ixTbl, ULONG ixCol, void *pRecord, const void *pvData, ULONG cbData); |
344 | |
345 | __checkReturn |
346 | HRESULT PutUserString(MetaData::DataBlob data, UINT32 *pnIndex) |
347 | { return m_UserStringHeap.AddBlob(data, pnIndex); } |
348 | |
349 | ULONG GetCol(ULONG ixTbl, ULONG ixCol, void *pRecord); |
350 | mdToken GetToken(ULONG ixTbl, ULONG ixCol, void *pRecord); |
351 | |
352 | // Add a record to a table, and return a typed XXXRec *. |
353 | // #undef AddTblRecord |
354 | #define AddTblRecord(tbl) \ |
355 | __checkReturn HRESULT Add##tbl##Record(tbl##Rec **ppRow, RID *pnRowIndex) \ |
356 | { return AddRecord(TBL_##tbl, reinterpret_cast<void **>(ppRow), pnRowIndex); } |
357 | |
358 | AddTblRecord(Module) |
359 | AddTblRecord(TypeRef) |
360 | __checkReturn HRESULT AddTypeDefRecord( // Specialized implementation. |
361 | TypeDefRec **ppRow, |
362 | RID *pnRowIndex); |
363 | AddTblRecord(Field) |
364 | __checkReturn HRESULT AddMethodRecord( // Specialized implementation. |
365 | MethodRec **ppRow, |
366 | RID *pnRowIndex); |
367 | AddTblRecord(Param) |
368 | AddTblRecord(InterfaceImpl) |
369 | AddTblRecord(MemberRef) |
370 | AddTblRecord(Constant) |
371 | AddTblRecord(CustomAttribute) |
372 | AddTblRecord(FieldMarshal) |
373 | AddTblRecord(DeclSecurity) |
374 | AddTblRecord(ClassLayout) |
375 | AddTblRecord(FieldLayout) |
376 | AddTblRecord(StandAloneSig) |
377 | __checkReturn HRESULT AddEventMapRecord( // Specialized implementation. |
378 | EventMapRec **ppRow, |
379 | RID *pnRowIndex); |
380 | AddTblRecord(Event) |
381 | __checkReturn HRESULT AddPropertyMapRecord( // Specialized implementation. |
382 | PropertyMapRec **ppRow, |
383 | RID *pnRowIndex); |
384 | AddTblRecord(Property) |
385 | AddTblRecord(MethodSemantics) |
386 | AddTblRecord(MethodImpl) |
387 | AddTblRecord(ModuleRef) |
388 | AddTblRecord(FieldPtr) |
389 | AddTblRecord(MethodPtr) |
390 | AddTblRecord(ParamPtr) |
391 | AddTblRecord(PropertyPtr) |
392 | AddTblRecord(EventPtr) |
393 | |
394 | AddTblRecord(ENCLog) |
395 | AddTblRecord(TypeSpec) |
396 | AddTblRecord(ImplMap) |
397 | AddTblRecord(ENCMap) |
398 | AddTblRecord(FieldRVA) |
399 | |
400 | // Assembly Tables. |
401 | AddTblRecord(Assembly) |
402 | AddTblRecord(AssemblyProcessor) |
403 | AddTblRecord(AssemblyOS) |
404 | AddTblRecord(AssemblyRef) |
405 | AddTblRecord(AssemblyRefProcessor) |
406 | AddTblRecord(AssemblyRefOS) |
407 | AddTblRecord(File) |
408 | AddTblRecord(ExportedType) |
409 | AddTblRecord(ManifestResource) |
410 | |
411 | AddTblRecord(NestedClass) |
412 | AddTblRecord(GenericParam) |
413 | AddTblRecord(MethodSpec) |
414 | AddTblRecord(GenericParamConstraint) |
415 | |
416 | // Specialized AddXxxToYyy() functions. |
417 | __checkReturn HRESULT AddMethodToTypeDef(RID td, RID md); |
418 | __checkReturn HRESULT AddFieldToTypeDef(RID td, RID md); |
419 | __checkReturn HRESULT AddParamToMethod(RID md, RID pd); |
420 | __checkReturn HRESULT AddPropertyToPropertyMap(RID pmd, RID pd); |
421 | __checkReturn HRESULT AddEventToEventMap(ULONG emd, RID ed); |
422 | |
423 | // does the MiniMdRW has the indirect tables, such as FieldPtr, MethodPtr |
424 | FORCEINLINE int HasIndirectTable(ULONG ix) |
425 | { if (g_PtrTableIxs[ix].m_ixtbl < TBL_COUNT) return GetCountRecs(g_PtrTableIxs[ix].m_ixtbl); return 0;} |
426 | |
427 | FORCEINLINE int IsVsMapValid(ULONG ixTbl) |
428 | { _ASSERTE(ixTbl<TBL_COUNT); return (m_pVS[ixTbl] && m_pVS[ixTbl]->m_isMapValid); } |
429 | |
430 | // translate index returned by getMethodListOfTypeDef to a rid into Method table |
431 | __checkReturn |
432 | FORCEINLINE HRESULT GetMethodRid(ULONG index, ULONG *pRid) |
433 | { |
434 | HRESULT hr; |
435 | if (HasIndirectTable(TBL_Method)) |
436 | { |
437 | MethodPtrRec *pMethodPtrRecord; |
438 | IfFailGo(GetMethodPtrRecord(index, &pMethodPtrRecord)); |
439 | *pRid = getMethodOfMethodPtr(pMethodPtrRecord); |
440 | } |
441 | else |
442 | { |
443 | *pRid = index; |
444 | } |
445 | return S_OK; |
446 | ErrExit: |
447 | *pRid = 0; |
448 | return hr; |
449 | } |
450 | |
451 | // translate index returned by getFieldListOfTypeDef to a rid into Field table |
452 | __checkReturn |
453 | FORCEINLINE HRESULT GetFieldRid(ULONG index, ULONG *pRid) |
454 | { |
455 | HRESULT hr; |
456 | if (HasIndirectTable(TBL_Field)) |
457 | { |
458 | FieldPtrRec *pFieldPtrRecord; |
459 | IfFailGo(GetFieldPtrRecord(index, &pFieldPtrRecord)); |
460 | *pRid = getFieldOfFieldPtr(pFieldPtrRecord); |
461 | } |
462 | else |
463 | { |
464 | *pRid = index; |
465 | } |
466 | return S_OK; |
467 | ErrExit: |
468 | *pRid = 0; |
469 | return hr; |
470 | } |
471 | |
472 | // translate index returned by getParamListOfMethod to a rid into Param table |
473 | __checkReturn |
474 | FORCEINLINE HRESULT GetParamRid(ULONG index, ULONG *pRid) |
475 | { |
476 | HRESULT hr; |
477 | if (HasIndirectTable(TBL_Param)) |
478 | { |
479 | ParamPtrRec *pParamPtrRecord; |
480 | IfFailGo(GetParamPtrRecord(index, &pParamPtrRecord)); |
481 | *pRid = getParamOfParamPtr(pParamPtrRecord); |
482 | } |
483 | else |
484 | { |
485 | *pRid = index; |
486 | } |
487 | return S_OK; |
488 | ErrExit: |
489 | *pRid = 0; |
490 | return hr; |
491 | } |
492 | |
493 | // translate index returned by getEventListOfEventMap to a rid into Event table |
494 | __checkReturn |
495 | FORCEINLINE HRESULT GetEventRid(ULONG index, ULONG *pRid) |
496 | { |
497 | HRESULT hr; |
498 | if (HasIndirectTable(TBL_Event)) |
499 | { |
500 | EventPtrRec *pEventPtrRecord; |
501 | IfFailGo(GetEventPtrRecord(index, &pEventPtrRecord)); |
502 | *pRid = getEventOfEventPtr(pEventPtrRecord); |
503 | } |
504 | else |
505 | { |
506 | *pRid = index; |
507 | } |
508 | return S_OK; |
509 | ErrExit: |
510 | *pRid = 0; |
511 | return hr; |
512 | } |
513 | |
514 | // translate index returned by getPropertyListOfPropertyMap to a rid into Property table |
515 | __checkReturn |
516 | FORCEINLINE HRESULT GetPropertyRid(ULONG index, ULONG *pRid) |
517 | { |
518 | HRESULT hr; |
519 | if (HasIndirectTable(TBL_Property)) |
520 | { |
521 | PropertyPtrRec *pPropertyPtrRecord; |
522 | IfFailGo(GetPropertyPtrRecord(index, &pPropertyPtrRecord)); |
523 | *pRid = getPropertyOfPropertyPtr(pPropertyPtrRecord); |
524 | } |
525 | else |
526 | { |
527 | *pRid = index; |
528 | } |
529 | return S_OK; |
530 | ErrExit: |
531 | *pRid = 0; |
532 | return hr; |
533 | } |
534 | |
535 | // Convert a pseudo-RID from a Virtual Sort into a real RID. |
536 | FORCEINLINE ULONG GetRidFromVirtualSort(ULONG ixTbl, ULONG index) |
537 | { return IsVsMapValid(ixTbl) ? *(m_pVS[ixTbl]->m_pMap->Get(index)) : index; } |
538 | |
539 | // Index returned by GetInterfaceImplForTypeDef. It could be index to VirtualSort table |
540 | // or directly to InterfaceImpl |
541 | FORCEINLINE ULONG GetInterfaceImplRid(ULONG index) |
542 | { return GetRidFromVirtualSort(TBL_InterfaceImpl, index); } |
543 | |
544 | // Index returned by GetGenericParamForToken. It could be index to VirtualSort table |
545 | // or directly to GenericParam |
546 | FORCEINLINE ULONG GetGenericParamRid(ULONG index) |
547 | { return GetRidFromVirtualSort(TBL_GenericParam, index); } |
548 | |
549 | // Index returned by GetGenericParamConstraintForToken. It could be index to VirtualSort table |
550 | // or directly to GenericParamConstraint |
551 | FORCEINLINE ULONG GetGenericParamConstraintRid(ULONG index) |
552 | { return GetRidFromVirtualSort(TBL_GenericParamConstraint, index); } |
553 | |
554 | // Index returned by GetDeclSecurityForToken. It could be index to VirtualSort table |
555 | // or directly to DeclSecurity |
556 | FORCEINLINE ULONG GetDeclSecurityRid(ULONG index) |
557 | { return GetRidFromVirtualSort(TBL_DeclSecurity, index); } |
558 | |
559 | // Index returned by GetCustomAttributeForToken. It could be index to VirtualSort table |
560 | // or directly to CustomAttribute |
561 | FORCEINLINE ULONG GetCustomAttributeRid(ULONG index) |
562 | { return GetRidFromVirtualSort(TBL_CustomAttribute, index); } |
563 | |
564 | // add method, field, property, event, param to the map table |
565 | __checkReturn HRESULT AddMethodToLookUpTable(mdMethodDef md, mdTypeDef td); |
566 | __checkReturn HRESULT AddFieldToLookUpTable(mdFieldDef fd, mdTypeDef td); |
567 | __checkReturn HRESULT AddPropertyToLookUpTable(mdProperty pr, mdTypeDef td); |
568 | __checkReturn HRESULT AddEventToLookUpTable(mdEvent ev, mdTypeDef td); |
569 | __checkReturn HRESULT AddParamToLookUpTable(mdParamDef pd, mdMethodDef md); |
570 | |
571 | // look up the parent of method, field, property, event, or param |
572 | __checkReturn HRESULT FindParentOfMethodHelper(mdMethodDef md, mdTypeDef *ptd); |
573 | __checkReturn HRESULT FindParentOfFieldHelper(mdFieldDef fd, mdTypeDef *ptd); |
574 | __checkReturn HRESULT FindParentOfPropertyHelper(mdProperty pr, mdTypeDef *ptd); |
575 | __checkReturn HRESULT FindParentOfEventHelper(mdEvent ev, mdTypeDef *ptd); |
576 | __checkReturn HRESULT FindParentOfParamHelper(mdParamDef pd, mdMethodDef *pmd); |
577 | |
578 | bool IsMemberDefHashPresent() { return m_pMemberDefHash != NULL; } |
579 | |
580 | // Function to reorganize the string pool based on IBC profile data (if available) and static analysis. |
581 | // Throws on error. |
582 | VOID OrganizeStringPool(CorProfileData *pProfileData); |
583 | |
584 | // Result of hash search |
585 | enum HashSearchResult |
586 | { |
587 | Found, // Item was found. |
588 | NotFound, // Item not found. |
589 | NoTable // Table hasn't been built. |
590 | }; |
591 | |
592 | // Create MemberRef hash table. |
593 | __checkReturn |
594 | HRESULT CreateMemberRefHash(); |
595 | |
596 | // Add a new MemberRef to the hash table. |
597 | __checkReturn |
598 | HRESULT AddMemberRefToHash( // Return code. |
599 | mdMemberRef mr); // Token of new guy. |
600 | |
601 | // If the hash is built, search for the item. Ignore token *ptkMemberRef. |
602 | HashSearchResult FindMemberRefFromHash( |
603 | mdToken tkParent, // Parent token. |
604 | LPCUTF8 szName, // Name of item. |
605 | PCCOR_SIGNATURE pvSigBlob, // Signature. |
606 | ULONG cbSigBlob, // Size of signature. |
607 | mdMemberRef * ptkMemberRef); // IN: Ignored token. OUT: Return if found. |
608 | |
609 | //************************************************************************* |
610 | // Check a given mr token to see if this one is a match. |
611 | //************************************************************************* |
612 | __checkReturn |
613 | HRESULT CompareMemberRefs( // S_OK match, S_FALSE no match. |
614 | mdMemberRef mr, // Token to check. |
615 | mdToken tkPar, // Parent token. |
616 | LPCUTF8 szNameUtf8, // Name of item. |
617 | PCCOR_SIGNATURE pvSigBlob, // Signature. |
618 | ULONG cbSigBlob); // Size of signature. |
619 | |
620 | // Add a new MemberDef to the hash table. |
621 | __checkReturn |
622 | HRESULT AddMemberDefToHash( |
623 | mdToken tkMember, // Token of new guy. It can be MethodDef or FieldDef |
624 | mdToken tkParent); // Parent token. |
625 | |
626 | // Create MemberDef Hash |
627 | __checkReturn |
628 | HRESULT CreateMemberDefHash(); |
629 | |
630 | // If the hash is built, search for the item. Ignore token *ptkMember. |
631 | HashSearchResult FindMemberDefFromHash( |
632 | mdToken tkParent, // Parent token. |
633 | LPCUTF8 szName, // Name of item. |
634 | PCCOR_SIGNATURE pvSigBlob, // Signature. |
635 | ULONG cbSigBlob, // Size of signature. |
636 | mdToken * ptkMember); // IN: Ignored token. OUT: Return if found. It can be MethodDef or FieldDef |
637 | |
638 | //************************************************************************* |
639 | // Check a given Method/Field token to see if this one is a match. |
640 | //************************************************************************* |
641 | __checkReturn |
642 | HRESULT CompareMemberDefs( // S_OK match, S_FALSE no match. |
643 | mdToken tkMember, // Token to check. It can be MethodDef or FieldDef |
644 | mdToken tkParent, // Parent token recorded in the hash entry |
645 | mdToken tkPar, // Parent token. |
646 | LPCUTF8 szNameUtf8, // Name of item. |
647 | PCCOR_SIGNATURE pvSigBlob, // Signature. |
648 | ULONG cbSigBlob); // Size of signature. |
649 | |
650 | //************************************************************************* |
651 | // Add a new CustomAttributes to the hash table. |
652 | //************************************************************************* |
653 | __checkReturn |
654 | HRESULT AddCustomAttributesToHash( // Return code. |
655 | mdCustomAttribute cv) // Token of new guy. |
656 | { return GenericAddToHash(TBL_CustomAttribute, CustomAttributeRec::COL_Parent, RidFromToken(cv)); } |
657 | |
658 | inline ULONG HashMemberRef(mdToken tkPar, LPCUTF8 szName) |
659 | { |
660 | ULONG l = HashBytes((const BYTE *) &tkPar, sizeof(mdToken)) + HashStringA(szName); |
661 | return (l); |
662 | } |
663 | |
664 | inline ULONG HashMemberDef(mdToken tkPar, LPCUTF8 szName) |
665 | { |
666 | return HashMemberRef(tkPar, szName); |
667 | } |
668 | |
669 | // helper to calculate the hash value given a token |
670 | inline ULONG HashCustomAttribute(mdToken tkObject) |
671 | { |
672 | return HashToken(tkObject); |
673 | } |
674 | |
675 | CMemberRefHash *m_pMemberRefHash; |
676 | |
677 | // Hash table for Methods and Fields |
678 | CMemberDefHash *m_pMemberDefHash; |
679 | |
680 | // helper to calculate the hash value given a pair of tokens |
681 | inline ULONG HashToken(mdToken tkObject) |
682 | { |
683 | ULONG l = HashBytes((const BYTE *) &tkObject, sizeof(mdToken)); |
684 | return (l); |
685 | } |
686 | |
687 | |
688 | //************************************************************************* |
689 | // Add a new FieldMarhsal Rid to the hash table. |
690 | //************************************************************************* |
691 | __checkReturn |
692 | HRESULT AddFieldMarshalToHash( // Return code. |
693 | RID rid) // Token of new guy. |
694 | { return GenericAddToHash(TBL_FieldMarshal, FieldMarshalRec::COL_Parent, rid); } |
695 | |
696 | //************************************************************************* |
697 | // Add a new Constant Rid to the hash table. |
698 | //************************************************************************* |
699 | __checkReturn |
700 | HRESULT AddConstantToHash( // Return code. |
701 | RID rid) // Token of new guy. |
702 | { return GenericAddToHash(TBL_Constant, ConstantRec::COL_Parent, rid); } |
703 | |
704 | //************************************************************************* |
705 | // Add a new MethodSemantics Rid to the hash table. |
706 | //************************************************************************* |
707 | __checkReturn |
708 | HRESULT AddMethodSemanticsToHash( // Return code. |
709 | RID rid) // Token of new guy. |
710 | { return GenericAddToHash(TBL_MethodSemantics, MethodSemanticsRec::COL_Association, rid); } |
711 | |
712 | //************************************************************************* |
713 | // Add a new ClassLayout Rid to the hash table. |
714 | //************************************************************************* |
715 | __checkReturn |
716 | HRESULT AddClassLayoutToHash( // Return code. |
717 | RID rid) // Token of new guy. |
718 | { return GenericAddToHash(TBL_ClassLayout, ClassLayoutRec::COL_Parent, rid); } |
719 | |
720 | //************************************************************************* |
721 | // Add a new FieldLayout Rid to the hash table. |
722 | //************************************************************************* |
723 | __checkReturn |
724 | HRESULT AddFieldLayoutToHash( // Return code. |
725 | RID rid) // Token of new guy. |
726 | { return GenericAddToHash(TBL_FieldLayout, FieldLayoutRec::COL_Field, rid); } |
727 | |
728 | //************************************************************************* |
729 | // Add a new ImplMap Rid to the hash table. |
730 | //************************************************************************* |
731 | __checkReturn |
732 | HRESULT AddImplMapToHash( // Return code. |
733 | RID rid) // Token of new guy. |
734 | { return GenericAddToHash(TBL_ImplMap, ImplMapRec::COL_MemberForwarded, rid); } |
735 | |
736 | //************************************************************************* |
737 | // Add a new FieldRVA Rid to the hash table. |
738 | //************************************************************************* |
739 | __checkReturn |
740 | HRESULT AddFieldRVAToHash( // Return code. |
741 | RID rid) // Token of new guy. |
742 | { return GenericAddToHash(TBL_FieldRVA, FieldRVARec::COL_Field, rid); } |
743 | |
744 | //************************************************************************* |
745 | // Add a new nested class Rid to the hash table. |
746 | //************************************************************************* |
747 | __checkReturn |
748 | HRESULT AddNestedClassToHash( // Return code. |
749 | RID rid) // Token of new guy. |
750 | { return GenericAddToHash(TBL_NestedClass, NestedClassRec::COL_NestedClass, rid); } |
751 | |
752 | //************************************************************************* |
753 | // Add a new MethodImpl Rid to the hash table. |
754 | //************************************************************************* |
755 | __checkReturn |
756 | HRESULT AddMethodImplToHash( // Return code. |
757 | RID rid) // Token of new guy. |
758 | { return GenericAddToHash(TBL_MethodImpl, MethodImplRec::COL_Class, rid); } |
759 | |
760 | |
761 | //************************************************************************* |
762 | // Build a hash table for the specified table if the size exceed the thresholds. |
763 | //************************************************************************* |
764 | __checkReturn |
765 | HRESULT GenericBuildHashTable( // Return code. |
766 | ULONG ixTbl, // Table with hash |
767 | ULONG ixCol); // col that we hash. |
768 | |
769 | //************************************************************************* |
770 | // Add a rid from a table into a hash |
771 | //************************************************************************* |
772 | __checkReturn |
773 | HRESULT GenericAddToHash( // Return code. |
774 | ULONG ixTbl, // Table with hash |
775 | ULONG ixCol, // col that we hash. |
776 | RID rid); // new row of the table. |
777 | |
778 | //************************************************************************* |
779 | // Add a rid from a table into a hash |
780 | //************************************************************************* |
781 | __checkReturn |
782 | HRESULT GenericFindWithHash( // Return code. |
783 | ULONG ixTbl, // Table with hash |
784 | ULONG ixCol, // col that we hash. |
785 | mdToken tkTarget, // token to be find in the hash |
786 | RID *pFoundRid); |
787 | |
788 | |
789 | // look up hash table for tokenless tables. |
790 | // They are constant, FieldMarshal, MethodSemantics, ClassLayout, FieldLayout, ImplMap, FieldRVA, NestedClass, and MethodImpl |
791 | CLookUpHash * m_pLookUpHashs[TBL_COUNT]; |
792 | |
793 | #if defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE) |
794 | MapSHash<UINT32, UINT32> m_StringPoolOffsetHash; |
795 | #endif |
796 | |
797 | //************************************************************************* |
798 | // Hash for named items. |
799 | //************************************************************************* |
800 | __checkReturn |
801 | HRESULT AddNamedItemToHash( // Return code. |
802 | ULONG ixTbl, // Table with the new item. |
803 | mdToken tk, // Token of new guy. |
804 | LPCUTF8 szName, // Name of item. |
805 | mdToken tkParent); // Token of parent, if any. |
806 | |
807 | HashSearchResult FindNamedItemFromHash( |
808 | ULONG ixTbl, // Table with the item. |
809 | LPCUTF8 szName, // Name of item. |
810 | mdToken tkParent, // Token of parent, if any. |
811 | mdToken * ptk); // Return if found. |
812 | |
813 | __checkReturn |
814 | HRESULT CompareNamedItems( // S_OK match, S_FALSE no match. |
815 | ULONG ixTbl, // Table with the item. |
816 | mdToken tk, // Token to check. |
817 | LPCUTF8 szName, // Name of item. |
818 | mdToken tkParent); // Token of parent, if any. |
819 | |
820 | FORCEINLINE ULONG HashNamedItem(mdToken tkPar, LPCUTF8 szName) |
821 | { return HashBytes((const BYTE *) &tkPar, sizeof(mdToken)) + HashStringA(szName); } |
822 | |
823 | CMetaDataHashBase *m_pNamedItemHash; |
824 | |
825 | //***************************************************************************** |
826 | // IMetaModelCommon - RW specific versions for some of the functions. |
827 | //***************************************************************************** |
828 | __checkReturn |
829 | virtual HRESULT CommonGetEnclosingClassOfTypeDef( |
830 | mdTypeDef td, |
831 | mdTypeDef *ptkEnclosingTypeDef) |
832 | { |
833 | _ASSERTE(ptkEnclosingTypeDef != NULL); |
834 | |
835 | HRESULT hr; |
836 | NestedClassRec *pRec; |
837 | RID iRec; |
838 | |
839 | IfFailRet(FindNestedClassHelper(td, &iRec)); |
840 | if (iRec == 0) |
841 | { |
842 | *ptkEnclosingTypeDef = mdTypeDefNil; |
843 | return S_OK; |
844 | } |
845 | |
846 | IfFailRet(GetNestedClassRecord(iRec, &pRec)); |
847 | *ptkEnclosingTypeDef = getEnclosingClassOfNestedClass(pRec); |
848 | return S_OK; |
849 | } |
850 | |
851 | __checkReturn |
852 | HRESULT CommonEnumCustomAttributeByName( // S_OK or error. |
853 | mdToken tkObj, // [IN] Object with Custom Attribute. |
854 | LPCUTF8 szName, // [IN] Name of desired Custom Attribute. |
855 | bool fStopAtFirstFind, // [IN] just find the first one |
856 | HENUMInternal* phEnum); // enumerator to fill up |
857 | |
858 | __checkReturn |
859 | HRESULT CommonGetCustomAttributeByNameEx( // S_OK or error. |
860 | mdToken tkObj, // [IN] Object with Custom Attribute. |
861 | LPCUTF8 szName, // [IN] Name of desired Custom Attribute. |
862 | mdCustomAttribute *ptkCA, // [OUT] put custom attribute token here |
863 | const void **ppData, // [OUT] Put pointer to data here. |
864 | ULONG *pcbData); // [OUT] Put size of data here. |
865 | |
866 | //***************************************************************************** |
867 | // Find helper for a constant. |
868 | //***************************************************************************** |
869 | __checkReturn |
870 | HRESULT FindConstantHelper( // return index to the constant table |
871 | mdToken tkParent, // Parent token. Can be ParamDef, FieldDef, or Property. |
872 | RID *pFoundRid); |
873 | |
874 | //***************************************************************************** |
875 | // Find helper for a FieldMarshal. |
876 | //***************************************************************************** |
877 | __checkReturn |
878 | HRESULT FindFieldMarshalHelper( // return index to the field marshal table |
879 | mdToken tkParent, // Parent token. Can be a FieldDef or ParamDef. |
880 | RID *pFoundRid); |
881 | |
882 | //***************************************************************************** |
883 | // Find helper for a method semantics. |
884 | //***************************************************************************** |
885 | __checkReturn |
886 | HRESULT FindMethodSemanticsHelper( // return HRESULT |
887 | mdToken tkAssociate, // Event or property token |
888 | HENUMInternal *phEnum); // fill in the enum |
889 | |
890 | //***************************************************************************** |
891 | // Find helper for a method semantics given a associate and semantics. |
892 | // This will look up methodsemantics based on its status! |
893 | // Return CLDB_E_RECORD_NOTFOUND if cannot find the matching one |
894 | //***************************************************************************** |
895 | __checkReturn |
896 | HRESULT FindAssociateHelper(// return HRESULT |
897 | mdToken tkAssociate, // Event or property token |
898 | DWORD dwSemantics, // [IN] given a associate semantics(setter, getter, testdefault, reset) |
899 | RID *pRid); // [OUT] return matching row index here |
900 | |
901 | //***************************************************************************** |
902 | // Find helper for a MethodImpl. |
903 | //***************************************************************************** |
904 | __checkReturn |
905 | HRESULT FindMethodImplHelper(// return HRESULT |
906 | mdTypeDef td, // TypeDef token for the Class. |
907 | HENUMInternal *phEnum); // fill in the enum |
908 | |
909 | //***************************************************************************** |
910 | // Find helper for a GenericParams |
911 | //***************************************************************************** |
912 | __checkReturn |
913 | HRESULT FindGenericParamHelper( // Return HRESULT |
914 | mdToken tkOwner, // Token for the GenericParams' owner |
915 | HENUMInternal *phEnum); // Fill in the enum. |
916 | |
917 | //***************************************************************************** |
918 | // Find helper for a Generic Constraints |
919 | //***************************************************************************** |
920 | __checkReturn |
921 | HRESULT FindGenericParamConstraintHelper( // Return HRESULT |
922 | mdGenericParam tkParam, // Token for the GenericParam |
923 | HENUMInternal *phEnum); // Fill in the enum. |
924 | |
925 | //***************************************************************************** |
926 | // Find helper for a ClassLayout. |
927 | //***************************************************************************** |
928 | __checkReturn |
929 | HRESULT FindClassLayoutHelper( // return index to the ClassLayout table |
930 | mdTypeDef tkParent, // Parent token. |
931 | RID *pFoundRid); |
932 | |
933 | //***************************************************************************** |
934 | // Find helper for a FieldLayout. |
935 | //***************************************************************************** |
936 | __checkReturn |
937 | HRESULT FindFieldLayoutHelper( // return index to the FieldLayout table |
938 | mdFieldDef tkField, // Token for the field. |
939 | RID *pFoundRid); |
940 | |
941 | //***************************************************************************** |
942 | // Find helper for a ImplMap. |
943 | //***************************************************************************** |
944 | __checkReturn |
945 | HRESULT FindImplMapHelper( // return index to the constant table |
946 | mdToken tk, // Member forwarded token. |
947 | RID *pFoundRid); |
948 | |
949 | //***************************************************************************** |
950 | // Find helper for a FieldRVA. |
951 | //***************************************************************************** |
952 | __checkReturn |
953 | HRESULT FindFieldRVAHelper( // return index to the FieldRVA table |
954 | mdFieldDef tkField, // Token for the field. |
955 | RID *pFoundRid); |
956 | |
957 | //***************************************************************************** |
958 | // Find helper for a NestedClass. |
959 | //***************************************************************************** |
960 | __checkReturn |
961 | HRESULT FindNestedClassHelper( // return index to the NestedClass table |
962 | mdTypeDef tkClass, // Token for the NestedClass. |
963 | RID *pFoundRid); |
964 | |
965 | //***************************************************************************** |
966 | // IMPORTANT!!!!!!!! Use these set of functions if you are dealing with RW rather |
967 | // getInterfaceImplsForTypeDef, getDeclSecurityForToken, etc. |
968 | // The following functions can deal with these tables when they are not sorted and |
969 | // build the VirtualSort tables for quick lookup. |
970 | //***************************************************************************** |
971 | __checkReturn |
972 | HRESULT GetInterfaceImplsForTypeDef(mdTypeDef td, RID *pRidStart, RID *pRidEnd = 0) |
973 | { |
974 | return LookUpTableByCol( RidFromToken(td), m_pVS[TBL_InterfaceImpl], pRidStart, pRidEnd); |
975 | } |
976 | |
977 | __checkReturn |
978 | HRESULT GetGenericParamsForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0) |
979 | { |
980 | return LookUpTableByCol( |
981 | encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtTypeOrMethodDef, lengthof(mdtTypeOrMethodDef)), |
982 | m_pVS[TBL_GenericParam], pRidStart, pRidEnd); |
983 | } |
984 | |
985 | __checkReturn |
986 | HRESULT GetGenericParamConstraintsForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0) |
987 | { |
988 | return LookUpTableByCol( RidFromToken(tk), |
989 | m_pVS[TBL_GenericParamConstraint], pRidStart, pRidEnd); |
990 | } |
991 | |
992 | __checkReturn |
993 | HRESULT GetMethodSpecsForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0) |
994 | { |
995 | return LookUpTableByCol( |
996 | encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtMethodDefOrRef, lengthof(mdtMethodDefOrRef)), |
997 | m_pVS[TBL_MethodSpec], pRidStart, pRidEnd); |
998 | } |
999 | |
1000 | __checkReturn |
1001 | HRESULT GetDeclSecurityForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0) |
1002 | { |
1003 | return LookUpTableByCol( |
1004 | encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasDeclSecurity, lengthof(mdtHasDeclSecurity)), |
1005 | m_pVS[TBL_DeclSecurity], |
1006 | pRidStart, |
1007 | pRidEnd); |
1008 | } |
1009 | |
1010 | __checkReturn |
1011 | HRESULT GetCustomAttributeForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0) |
1012 | { |
1013 | return LookUpTableByCol( |
1014 | encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasCustomAttribute, lengthof(mdtHasCustomAttribute)), |
1015 | m_pVS[TBL_CustomAttribute], |
1016 | pRidStart, |
1017 | pRidEnd); |
1018 | } |
1019 | |
1020 | __checkReturn |
1021 | FORCEINLINE HRESULT GetUserString(ULONG nIndex, MetaData::DataBlob *pData) |
1022 | { return m_UserStringHeap.GetBlob(nIndex, pData); } |
1023 | // Gets user string (*Data) at index (nIndex) and fills the index (*pnNextIndex) of the next user string |
1024 | // in the heap. |
1025 | // Returns S_OK and fills the string (*pData) and the next index (*pnNextIndex). |
1026 | // Returns S_FALSE if the index (nIndex) is not valid user string index. |
1027 | // Returns error code otherwise. |
1028 | // Clears *pData and sets *pnNextIndex to 0 on error or S_FALSE. |
1029 | __checkReturn |
1030 | HRESULT GetUserStringAndNextIndex( |
1031 | UINT32 nIndex, |
1032 | MetaData::DataBlob *pData, |
1033 | UINT32 *pnNextIndex); |
1034 | |
1035 | FORCEINLINE int IsSorted(ULONG ixTbl) { return m_Schema.IsSorted(ixTbl);} |
1036 | FORCEINLINE int IsSortable(ULONG ixTbl) { return m_bSortable[ixTbl];} |
1037 | FORCEINLINE bool HasDelete() { return ((m_Schema.m_heaps & CMiniMdSchema::HAS_DELETE) ? true : false); } |
1038 | FORCEINLINE int IsPreSaveDone() { return m_bPreSaveDone; } |
1039 | |
1040 | protected: |
1041 | __checkReturn HRESULT PreSave(MetaDataReorderingOptions reorderingOptions=NoReordering, CorProfileData *pProfileData=NULL); |
1042 | __checkReturn HRESULT PostSave(); |
1043 | |
1044 | __checkReturn HRESULT PreSaveFull(); |
1045 | __checkReturn HRESULT PreSaveEnc(); |
1046 | |
1047 | __checkReturn HRESULT GetFullPoolSaveSize(int iPool, UINT32 *pcbSize); |
1048 | __checkReturn HRESULT GetENCPoolSaveSize(int iPool, UINT32 *pcbSize); |
1049 | |
1050 | __checkReturn HRESULT SaveFullPoolToStream(int iPool, IStream *pIStream); |
1051 | __checkReturn HRESULT SaveENCPoolToStream(int iPool, IStream *pIStream); |
1052 | |
1053 | __checkReturn |
1054 | HRESULT GetHotMetadataTokensSearchAware( |
1055 | CorProfileData *pProfileData, |
1056 | ULONG ixTbl, |
1057 | ULONG *pResultCount, |
1058 | mdToken *tokenBuffer, |
1059 | ULONG maxCount); |
1060 | |
1061 | __checkReturn |
1062 | HRESULT GetFullSaveSize( |
1063 | CorSaveSize fSave, |
1064 | UINT32 *pcbSize, |
1065 | DWORD *pbCompressed, |
1066 | MetaDataReorderingOptions reorderingOptions = NoReordering, |
1067 | CorProfileData *pProfileData = NULL); |
1068 | __checkReturn |
1069 | HRESULT GetENCSaveSize(UINT32 *pcbSize); |
1070 | __checkReturn |
1071 | HRESULT GetHotPoolsSaveSize( |
1072 | UINT32 *pcbSize, |
1073 | MetaDataReorderingOptions reorderingOptions, |
1074 | CorProfileData *pProfileData); |
1075 | |
1076 | __checkReturn |
1077 | HRESULT SaveFullTablesToStream(IStream *pIStream, MetaDataReorderingOptions reorderingOptions=NoReordering, CorProfileData *pProfileData = NULL ); |
1078 | __checkReturn |
1079 | HRESULT SaveENCTablesToStream(IStream *pIStream); |
1080 | __checkReturn |
1081 | HRESULT SaveHotPoolsToStream( |
1082 | IStream *pStream, |
1083 | MetaDataReorderingOptions reorderingOptions, |
1084 | CorProfileData *pProfileData, |
1085 | UINT32 *pnPoolDirSize, |
1086 | UINT32 *pnSavedPoolsSize); |
1087 | __checkReturn |
1088 | HRESULT SaveHotPoolToStream( |
1089 | IStream *pStream, |
1090 | CorProfileData *pProfileData, |
1091 | MetaData::HotHeapWriter *pHotHeapWriter, |
1092 | UINT32 *pnSavedSize); |
1093 | |
1094 | // TO ELIMINATE: |
1095 | __checkReturn |
1096 | HRESULT AddGuid(REFGUID pGuid, UINT32 *pnIndex) |
1097 | { return m_GuidHeap.AddGuid(&pGuid, pnIndex); } |
1098 | |
1099 | // Allows putting into tables outside this MiniMd, specifically the temporary |
1100 | // table used on save. |
1101 | __checkReturn |
1102 | HRESULT PutCol(CMiniColDef ColDef, void *pRecord, ULONG uVal); |
1103 | |
1104 | // Returns TRUE if token (tk) is valid. |
1105 | // For user strings, consideres 0 as valid token. |
1106 | BOOL _IsValidToken( |
1107 | mdToken tk) // [IN] token to be checked |
1108 | { |
1109 | if (TypeFromToken(tk) == mdtString) |
1110 | { |
1111 | // need to check the user string heap |
1112 | return m_UserStringHeap.IsValidIndex(RidFromToken(tk)); |
1113 | } |
1114 | // Base type doesn't know about user string blob (yet) |
1115 | return _IsValidTokenBase(tk); |
1116 | } // CMiniMdRW::_IsValidToken |
1117 | |
1118 | #ifdef _DEBUG |
1119 | bool CanHaveCustomAttribute(ULONG ixTbl); |
1120 | #endif |
1121 | |
1122 | __checkReturn |
1123 | HRESULT ExpandTables(); |
1124 | __checkReturn |
1125 | HRESULT ExpandTableColumns(CMiniMdSchema &Schema, ULONG ixTbl); |
1126 | |
1127 | __checkReturn |
1128 | HRESULT InitWithLargeTables(); |
1129 | |
1130 | void ComputeGrowLimits(int bSmall=TRUE); // Set max, lim, based on param. |
1131 | ULONG m_maxRid; // Highest RID so far allocated. |
1132 | ULONG m_limRid; // Limit on RID before growing. |
1133 | ULONG m_maxIx; // Highest pool index so far. |
1134 | ULONG m_limIx; // Limit on pool index before growing. |
1135 | enum {eg_ok, eg_grow, eg_grown} m_eGrow; // Is a grow required? done? |
1136 | #define AUTO_GROW_CODED_TOKEN_PADDING 5 |
1137 | |
1138 | // fix up these tables after PreSave has move the tokens |
1139 | __checkReturn HRESULT FixUpTable(ULONG ixTbl); |
1140 | __checkReturn HRESULT FixUpRefToDef(); |
1141 | |
1142 | // Table info. |
1143 | MetaData::TableRW m_Tables[TBL_COUNT]; |
1144 | VirtualSort *m_pVS[TBL_COUNT]; // Virtual sorters, one per table, but sparse. |
1145 | |
1146 | //***************************************************************************** |
1147 | // look up a table by a col given col value is ulVal. |
1148 | //***************************************************************************** |
1149 | __checkReturn |
1150 | HRESULT LookUpTableByCol( |
1151 | ULONG ulVal, |
1152 | VirtualSort *pVSTable, |
1153 | RID *pRidStart, |
1154 | RID *pRidEnd); |
1155 | |
1156 | __checkReturn |
1157 | HRESULT Impl_SearchTableRW(ULONG ixTbl, ULONG ixCol, ULONG ulTarget, RID *pFoundRid); |
1158 | __checkReturn |
1159 | virtual HRESULT vSearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ulTarget, RID *pRid); |
1160 | __checkReturn |
1161 | virtual HRESULT vSearchTableNotGreater(ULONG ixTbl, CMiniColDef sColumn, ULONG ulTarget, RID *pRid); |
1162 | |
1163 | void SetSorted(ULONG ixTbl, int bSorted) |
1164 | { m_Schema.SetSorted(ixTbl, bSorted); } |
1165 | |
1166 | void SetPreSaveDone(int bPreSaveDone) |
1167 | { m_bPreSaveDone = bPreSaveDone; } |
1168 | |
1169 | // Heaps |
1170 | MetaData::StringHeapRW m_StringHeap; |
1171 | MetaData::BlobHeapRW m_BlobHeap; |
1172 | MetaData::BlobHeapRW m_UserStringHeap; |
1173 | MetaData::GuidHeapRW m_GuidHeap; |
1174 | |
1175 | IMapToken *m_pHandler; // Remap handler. |
1176 | __checkReturn HRESULT MapToken(RID from, RID to, mdToken type); |
1177 | |
1178 | ULONG m_cbSaveSize; // Estimate of save size. |
1179 | |
1180 | int m_fIsReadOnly : 1; // Is this db read-only? |
1181 | int m_bPreSaveDone : 1; // Has save optimization been done? |
1182 | int m_bSaveCompressed : 1; // Can the data be saved as fully compressed? |
1183 | int m_bPostGSSMod : 1; // true if a change was made post GetSaveSize. |
1184 | |
1185 | |
1186 | //************************************************************************* |
1187 | // Overridables -- must be provided in derived classes. |
1188 | __checkReturn |
1189 | FORCEINLINE HRESULT Impl_GetString(UINT32 nIndex, __out LPCSTR *pszString) |
1190 | { return m_StringHeap.GetString(nIndex, pszString); } |
1191 | __checkReturn |
1192 | HRESULT Impl_GetStringW(ULONG ix, __inout_ecount (cchBuffer) LPWSTR szOut, ULONG cchBuffer, ULONG *pcchBuffer); |
1193 | __checkReturn |
1194 | FORCEINLINE HRESULT Impl_GetGuid(UINT32 nIndex, GUID *pTargetGuid) |
1195 | { |
1196 | HRESULT hr; |
1197 | GUID UNALIGNED *pSourceGuid; |
1198 | IfFailRet(m_GuidHeap.GetGuid( |
1199 | nIndex, |
1200 | &pSourceGuid)); |
1201 | // Add void* casts so that the compiler can't make assumptions about alignment. |
1202 | CopyMemory((void *)pTargetGuid, (void *)pSourceGuid, sizeof(GUID)); |
1203 | SwapGuid(pTargetGuid); |
1204 | return S_OK; |
1205 | } |
1206 | |
1207 | __checkReturn |
1208 | FORCEINLINE HRESULT Impl_GetBlob(ULONG nIndex, __out MetaData::DataBlob *pData) |
1209 | { return m_BlobHeap.GetBlob(nIndex, pData); } |
1210 | |
1211 | __checkReturn |
1212 | FORCEINLINE HRESULT Impl_GetRow( |
1213 | UINT32 nTableIndex, |
1214 | UINT32 nRowIndex, |
1215 | __deref_out_opt BYTE **ppRecord) |
1216 | { |
1217 | _ASSERTE(nTableIndex < TBL_COUNT); |
1218 | return m_Tables[nTableIndex].GetRecord(nRowIndex, ppRecord); |
1219 | } |
1220 | |
1221 | // Count of rows in tbl2, pointed to by the column in tbl. |
1222 | __checkReturn |
1223 | HRESULT Impl_GetEndRidForColumn( |
1224 | UINT32 nTableIndex, |
1225 | RID nRowIndex, |
1226 | CMiniColDef &def, // Column containing the RID into other table. |
1227 | UINT32 nTargetTableIndex, // The other table. |
1228 | RID *pEndRid); |
1229 | |
1230 | __checkReturn |
1231 | FORCEINLINE HRESULT Impl_SearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ixCol, ULONG ulTarget, RID *pFoundRid) |
1232 | { return Impl_SearchTableRW(ixTbl, ixCol, ulTarget, pFoundRid); } |
1233 | |
1234 | FORCEINLINE int Impl_IsRo() |
1235 | { return 0; } |
1236 | |
1237 | |
1238 | //************************************************************************* |
1239 | enum {END_OF_TABLE = 0}; |
1240 | FORCEINLINE ULONG NewRecordPointerEndValue(ULONG ixTbl) |
1241 | { if (HasIndirectTable(ixTbl)) return m_Schema.m_cRecs[ixTbl]+1; else return END_OF_TABLE; } |
1242 | |
1243 | __checkReturn HRESULT ConvertMarkerToEndOfTable(ULONG tblParent, ULONG colParent, ULONG ridChild, RID ridParent); |
1244 | |
1245 | // Add a child row, adjust pointers in parent rows. |
1246 | __checkReturn |
1247 | HRESULT AddChildRowIndirectForParent( |
1248 | ULONG tblParent, |
1249 | ULONG colParent, |
1250 | ULONG tblChild, |
1251 | RID ridParent, |
1252 | void **ppRow); |
1253 | |
1254 | // Update pointers in the parent table to reflect the addition of a child, if required |
1255 | // create the indirect table in which case don't update pointers. |
1256 | __checkReturn |
1257 | HRESULT AddChildRowDirectForParent(ULONG tblParent, ULONG colParent, ULONG tblChild, RID ridParent); |
1258 | |
1259 | // Given a table id, create the corresponding indirect table. |
1260 | __checkReturn |
1261 | HRESULT CreateIndirectTable(ULONG ixtbl, BOOL bOneLess = true); |
1262 | |
1263 | // If the last param is not added in the right sequence, fix it up. |
1264 | __checkReturn |
1265 | HRESULT FixParamSequence(RID md); |
1266 | |
1267 | |
1268 | // these are the map tables to map a method, a field, a property, a event, or a param to its parent |
1269 | TOKENMAP *m_pMethodMap; |
1270 | TOKENMAP *m_pFieldMap; |
1271 | TOKENMAP *m_pPropertyMap; |
1272 | TOKENMAP *m_pEventMap; |
1273 | TOKENMAP *m_pParamMap; |
1274 | |
1275 | // This table keep tracks tokens that are marked( or filtered) |
1276 | FilterTable *m_pFilterTable; |
1277 | IHostFilter *m_pHostFilter; |
1278 | |
1279 | // TOKENMAP *m_pTypeRefToTypeDefMap; |
1280 | TokenRemapManager *m_pTokenRemapManager; |
1281 | |
1282 | OptionValue m_OptionValue; |
1283 | |
1284 | CMiniMdSchema m_StartupSchema; // Schema at start time. Keep count of records. |
1285 | BYTE m_bSortable[TBL_COUNT]; // Is a given table sortable? (Can it be reorganized?) |
1286 | #ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE |
1287 | ReleaseHolder<IMDCustomDataSource> m_pCustomDataSource; |
1288 | #endif |
1289 | |
1290 | #ifdef _DEBUG |
1291 | |
1292 | protected: |
1293 | UTSemReadWrite * dbg_m_pLock; |
1294 | |
1295 | public: |
1296 | // Checks that MetaData is locked for write operation (if thread-safety is enabled and the lock exists) |
1297 | void Debug_CheckIsLockedForWrite(); |
1298 | |
1299 | void Debug_SetLock(UTSemReadWrite * pLock) |
1300 | { |
1301 | dbg_m_pLock = pLock; |
1302 | } |
1303 | |
1304 | #endif //_DEBUG |
1305 | |
1306 | public: |
1307 | |
1308 | FilterTable *GetFilterTable(); |
1309 | __checkReturn HRESULT UnmarkAll(); |
1310 | __checkReturn HRESULT MarkAll(); |
1311 | |
1312 | FORCEINLINE IHostFilter *GetHostFilter() { return m_pHostFilter;} |
1313 | |
1314 | __checkReturn HRESULT CalculateTypeRefToTypeDefMap(); |
1315 | |
1316 | FORCEINLINE TOKENMAP *GetTypeRefToTypeDefMap() |
1317 | { return m_pTokenRemapManager ? m_pTokenRemapManager->GetTypeRefToTypeDefMap() : NULL; }; |
1318 | |
1319 | FORCEINLINE TOKENMAP *GetMemberRefToMemberDefMap() |
1320 | { return m_pTokenRemapManager ? m_pTokenRemapManager->GetMemberRefToMemberDefMap() : NULL; }; |
1321 | |
1322 | FORCEINLINE MDTOKENMAP *GetTokenMovementMap() |
1323 | { return m_pTokenRemapManager ? m_pTokenRemapManager->GetTokenMovementMap() : NULL; }; |
1324 | |
1325 | FORCEINLINE TokenRemapManager *GetTokenRemapManager() { return m_pTokenRemapManager; }; |
1326 | |
1327 | __checkReturn HRESULT InitTokenRemapManager(); |
1328 | |
1329 | virtual ULONG vGetCol(ULONG ixTbl, ULONG ixCol, void *pRecord) |
1330 | { return GetCol(ixTbl, ixCol, pRecord);} |
1331 | |
1332 | public: |
1333 | virtual BOOL IsWritable() |
1334 | { |
1335 | return !m_fIsReadOnly; |
1336 | } |
1337 | |
1338 | |
1339 | //************************************************************************* |
1340 | // Delta MetaData (EditAndContinue) functions. |
1341 | public: |
1342 | enum eDeltaFuncs{ |
1343 | eDeltaFuncDefault = 0, |
1344 | eDeltaMethodCreate, |
1345 | eDeltaFieldCreate, |
1346 | eDeltaParamCreate, |
1347 | eDeltaPropertyCreate, |
1348 | eDeltaEventCreate, |
1349 | }; |
1350 | |
1351 | __checkReturn HRESULT ApplyDelta(CMiniMdRW &mdDelta); |
1352 | |
1353 | public: |
1354 | // Functions for updating ENC log tables ENC log. |
1355 | FORCEINLINE BOOL IsENCOn() |
1356 | { |
1357 | return (m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateENC; |
1358 | } |
1359 | |
1360 | __checkReturn |
1361 | FORCEINLINE HRESULT UpdateENCLog(mdToken tk, CMiniMdRW::eDeltaFuncs funccode = CMiniMdRW::eDeltaFuncDefault) |
1362 | { |
1363 | if (IsENCOn()) |
1364 | return UpdateENCLogHelper(tk, funccode); |
1365 | else |
1366 | return S_OK; |
1367 | } |
1368 | |
1369 | __checkReturn |
1370 | FORCEINLINE HRESULT UpdateENCLog2(ULONG ixTbl, ULONG iRid, CMiniMdRW::eDeltaFuncs funccode = CMiniMdRW::eDeltaFuncDefault) |
1371 | { |
1372 | if (IsENCOn()) |
1373 | return UpdateENCLogHelper2(ixTbl, iRid, funccode); |
1374 | else |
1375 | return S_OK; |
1376 | } |
1377 | |
1378 | __checkReturn HRESULT ResetENCLog(); |
1379 | |
1380 | private: |
1381 | BOOL m_fMinimalDelta; |
1382 | |
1383 | // |
1384 | // String heap reorganization |
1385 | // |
1386 | |
1387 | // Check to see if it is safe to reorder the string pool. |
1388 | BOOL IsSafeToReorderStringPool(); |
1389 | // Function to mark hot strings in the marks array based on the token information in profile data. |
1390 | VOID MarkHotStrings(CorProfileData *pProfileData, BYTE * pMarks, ULONG poolSize); |
1391 | // Function to mark hot strings referenced by hot tables based on token information in profile data. |
1392 | VOID MarkStringsInHotTables(CorProfileData *pProfileData, BYTE * pMarks, ULONG poolSize); |
1393 | // Function to mark strings referenced by the different metadata tables. |
1394 | VOID MarkStringsInTables(BYTE * pMarks, ULONG poolSize); |
1395 | // Function to mark duplicate strings in the mark array. |
1396 | // Throws on error. |
1397 | VOID MarkDuplicateStrings(BYTE * pMarks, ULONG poolSize); |
1398 | // Function to update the tables with the modified string offsets. |
1399 | VOID FixStringsInTables(); |
1400 | // Function to fill the given string pool with strings from the existing string pool using the mark array. |
1401 | // Throws on error. |
1402 | VOID CreateReorderedStringPool( |
1403 | MetaData::StringHeapRW *pStringHeap, |
1404 | BYTE *pMarks, |
1405 | ULONG cbHeapSize, |
1406 | CorProfileData *pProfileData); |
1407 | |
1408 | public: |
1409 | BOOL IsMinimalDelta() |
1410 | { |
1411 | return m_fMinimalDelta; |
1412 | } |
1413 | |
1414 | |
1415 | // Turns on/off the ability to emit delta metadatas |
1416 | |
1417 | // Unfortunately, we can't allow this to be set via the SetOption method anymore. In v1.0 and v1.1, this flag |
1418 | // could be set but would still result in generating full metadatas. We can't automatically start generating |
1419 | // true deltas for people... it could break them. |
1420 | void EnableDeltaMetadataGeneration() |
1421 | { |
1422 | _ASSERTE(m_OptionValue.m_UpdateMode == MDUpdateENC); |
1423 | } |
1424 | void DisableDeltaMetadataGeneration() {m_OptionValue.m_UpdateMode = MDUpdateENC;} |
1425 | |
1426 | protected: |
1427 | // Internal Helper functions for ENC log. |
1428 | __checkReturn |
1429 | HRESULT UpdateENCLogHelper(mdToken tk, CMiniMdRW::eDeltaFuncs funccode); |
1430 | __checkReturn |
1431 | HRESULT UpdateENCLogHelper2(ULONG ixTbl, ULONG iRid, CMiniMdRW::eDeltaFuncs funccode); |
1432 | |
1433 | protected: |
1434 | static ULONG m_TruncatedEncTables[]; |
1435 | static ULONG m_SuppressedDeltaColumns[TBL_COUNT]; |
1436 | |
1437 | ULONGARRAY *m_rENCRecs; // Array of RIDs affected by ENC. |
1438 | |
1439 | __checkReturn |
1440 | HRESULT ApplyRecordDelta(CMiniMdRW &mdDelta, ULONG ixTbl, void *pDelta, void *pRecord); |
1441 | __checkReturn |
1442 | HRESULT ApplyTableDelta(CMiniMdRW &mdDelta, ULONG ixTbl, RID iRid, int fc); |
1443 | __checkReturn |
1444 | HRESULT GetDeltaRecord(ULONG ixTbl, ULONG iRid, void **ppRecord); |
1445 | __checkReturn |
1446 | HRESULT ApplyHeapDeltas(CMiniMdRW &mdDelta); |
1447 | __checkReturn |
1448 | HRESULT ApplyHeapDeltasWithMinimalDelta(CMiniMdRW &mdDelta); |
1449 | __checkReturn |
1450 | HRESULT ApplyHeapDeltasWithFullDelta(CMiniMdRW &mdDelta); |
1451 | __checkReturn |
1452 | HRESULT StartENCMap(); // Call, on a delta MD, to prepare to access sparse rows. |
1453 | __checkReturn |
1454 | HRESULT EndENCMap(); // Call, on a delta MD, when done with sparse rows. |
1455 | |
1456 | public: |
1457 | // Workaround for compiler performance issue VSW 584653 for 2.0 RTM. |
1458 | // Get the table's VirtualSort validity state. |
1459 | bool IsTableVirtualSorted(ULONG ixTbl); |
1460 | // Workaround for compiler performance issue VSW 584653 for 2.0 RTM. |
1461 | // Validate table's VirtualSort after adding one record into the table. |
1462 | // Returns new VirtualSort validity state in *pfIsTableVirtualSortValid. |
1463 | // Assumptions: |
1464 | // Table's VirtualSort was valid before adding the record to the table. |
1465 | // The caller must ensure validity of VirtualSort by calling to |
1466 | // IsTableVirtualSorted or by using the returned state from previous |
1467 | // call to this method. |
1468 | __checkReturn |
1469 | HRESULT ValidateVirtualSortAfterAddRecord( |
1470 | ULONG ixTbl, |
1471 | bool * pfIsTableVirtualSortValid); |
1472 | |
1473 | }; // class CMiniMdRW : public CMiniMdTemplate<CMiniMdRW> |
1474 | |
1475 | #endif // _METAMODELRW_H_ |
1476 | |