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
29struct HENUMInternal;
30#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
31struct IMDCustomDataSource;
32#endif
33
34// ENUM for marking bit
35enum
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 SignatureMarkedBit = 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
60struct FilterUserStringEntry
61{
62 DWORD m_tkString;
63 bool m_fMarked;
64};
65
66class FilterTable : public CDynArray<DWORD>
67{
68public:
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 IsSignatureMarked(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
133private:
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
140class 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//*****************************************************************************
146class VirtualSort
147{
148public:
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();
158private:
159 mdToken m_tkBuf;
160 __checkReturn
161 HRESULT SortRange(int iLeft, int iRight);
162public:
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
169private:
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
183class ReorderData
184{
185public:
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
199typedef CMetaDataHashBase CMemberRefHash;
200typedef CMetaDataHashBase CLookUpHash;
201
202class MDTOKENMAP;
203class MDInternalRW;
204class CorProfileData;
205class UTSemReadWrite;
206
207enum MetaDataReorderingOptions {
208 NoReordering=0x0,
209 ReArrangeStringPool=0x1
210};
211
212#ifdef FEATURE_PREJIT
213
214// {0702E333-8D64-4ca7-B564-4AA56B1FCEA3}
215EXTERN_GUID(IID_IMetaDataCorProfileData, 0x702e333, 0x8d64, 0x4ca7, 0xb5, 0x64, 0x4a, 0xa5, 0x6b, 0x1f, 0xce, 0xa3 );
216
217#undef INTERFACE
218#define INTERFACE IMetaDataCorProfileData
219DECLARE_INTERFACE_(IMetaDataCorProfileData, IUnknown)
220{
221 STDMETHOD(SetCorProfileData)(
222 CorProfileData *pProfileData) PURE; // [IN] Pointer to profile data
223};
224
225// {2B464817-C0F6-454e-99E7-C352D8384D7B}
226EXTERN_GUID(IID_IMDInternalMetadataReorderingOptions, 0x2B464817, 0xC0F6, 0x454e, 0x99, 0xE7, 0xC3, 0x52, 0xD8, 0x38, 0x4D, 0x7B );
227
228#undef INTERFACE
229#define INTERFACE IMDInternalMetadataReorderingOptions
230DECLARE_INTERFACE_(IMDInternalMetadataReorderingOptions, IUnknown)
231{
232 STDMETHOD(SetMetaDataReorderingOptions)(
233 MetaDataReorderingOptions options) PURE; // [IN] metadata reordering options
234};
235
236#endif //FEATURE_PREJIT
237
238template <class MiniMd> class CLiteWeightStgdb;
239//*****************************************************************************
240// Read/Write MiniMd.
241//*****************************************************************************
242class CMiniMdRW : public CMiniMdTemplate<CMiniMdRW>
243{
244public:
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
1040protected:
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
1292protected:
1293 UTSemReadWrite * dbg_m_pLock;
1294
1295public:
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
1306public:
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
1332public:
1333 virtual BOOL IsWritable()
1334 {
1335 return !m_fIsReadOnly;
1336 }
1337
1338
1339 //*************************************************************************
1340 // Delta MetaData (EditAndContinue) functions.
1341public:
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
1353public:
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
1380private:
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
1408public:
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
1426protected:
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
1433protected:
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
1456public:
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