summaryrefslogtreecommitdiff
path: root/src/md/inc/metamodelrw.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/md/inc/metamodelrw.h')
-rw-r--r--src/md/inc/metamodelrw.h1479
1 files changed, 1479 insertions, 0 deletions
diff --git a/src/md/inc/metamodelrw.h b/src/md/inc/metamodelrw.h
new file mode 100644
index 0000000000..6e00d3cf3e
--- /dev/null
+++ b/src/md/inc/metamodelrw.h
@@ -0,0 +1,1479 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//*****************************************************************************
+// MetaModelRW.h -- header file for Read/Write compressed COM+ metadata.
+//
+
+//
+// Used by Emitters and by E&C.
+//
+//*****************************************************************************
+#ifndef _METAMODELRW_H_
+#define _METAMODELRW_H_
+
+#if _MSC_VER >= 1100
+ # pragma once
+#endif
+
+#include "metamodel.h" // Base classes for the MetaModel.
+#include "metadatahash.h"
+#include "rwutil.h"
+#include "shash.h"
+
+#include "../heaps/export.h"
+#include "../hotdata/export.h"
+#include "../tables/export.h"
+
+struct HENUMInternal;
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+struct IMDCustomDataSource;
+#endif
+
+// ENUM for marking bit
+enum
+{
+ InvalidMarkedBit = 0x00000000,
+ ModuleMarkedBit = 0x00000001,
+ TypeRefMarkedBit = 0x00000002,
+ TypeDefMarkedBit = 0x00000004,
+ FieldMarkedBit = 0x00000008,
+ MethodMarkedBit = 0x00000010,
+ ParamMarkedBit = 0x00000020,
+ MemberRefMarkedBit = 0x00000040,
+ CustomAttributeMarkedBit = 0x00000080,
+ DeclSecurityMarkedBit = 0x00000100,
+ SignatureMarkedBit = 0x00000200,
+ EventMarkedBit = 0x00000400,
+ PropertyMarkedBit = 0x00000800,
+ MethodImplMarkedBit = 0x00001000,
+ ModuleRefMarkedBit = 0x00002000,
+ TypeSpecMarkedBit = 0x00004000,
+ InterfaceImplMarkedBit = 0x00008000,
+ AssemblyRefMarkedBit = 0x00010000,
+ MethodSpecMarkedBit = 0x00020000,
+
+};
+
+// entry for marking UserString
+struct FilterUserStringEntry
+{
+ DWORD m_tkString;
+ bool m_fMarked;
+};
+
+class FilterTable : public CDynArray<DWORD>
+{
+public:
+ FilterTable() { m_daUserStringMarker = NULL; }
+ ~FilterTable();
+
+ __checkReturn FORCEINLINE HRESULT MarkTypeRef(mdToken tk) { return MarkToken(tk, TypeRefMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkTypeDef(mdToken tk) { return MarkToken(tk, TypeDefMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkField(mdToken tk) { return MarkToken(tk, FieldMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkMethod(mdToken tk) { return MarkToken(tk, MethodMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkParam(mdToken tk) { return MarkToken(tk, ParamMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkMemberRef(mdToken tk) { return MarkToken(tk, MemberRefMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkCustomAttribute(mdToken tk) { return MarkToken(tk, CustomAttributeMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkDeclSecurity(mdToken tk) { return MarkToken(tk, DeclSecurityMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkSignature(mdToken tk) { return MarkToken(tk, SignatureMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkEvent(mdToken tk) { return MarkToken(tk, EventMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkProperty(mdToken tk) { return MarkToken(tk, PropertyMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkMethodImpl(RID rid)
+ {
+ return MarkToken(TokenFromRid(rid, TBL_MethodImpl << 24), MethodImplMarkedBit);
+ }
+ __checkReturn FORCEINLINE HRESULT MarkModuleRef(mdToken tk) { return MarkToken(tk, ModuleRefMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkTypeSpec(mdToken tk) { return MarkToken(tk, TypeSpecMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkInterfaceImpl(mdToken tk) { return MarkToken(tk, InterfaceImplMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkAssemblyRef(mdToken tk) { return MarkToken(tk, AssemblyRefMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT MarkMethodSpec(mdToken tk) { return MarkToken(tk, MethodSpecMarkedBit); }
+
+ // It may look inconsistent but it is because taht UserString an offset to the heap.
+ // We don't want to grow the FilterTable to the size of the UserString heap.
+ // So we use the heap's marking system instead...
+ //
+ __checkReturn HRESULT MarkUserString(mdString str);
+
+ __checkReturn HRESULT MarkNewUserString(mdString str);
+
+ FORCEINLINE bool IsTypeRefMarked(mdToken tk) { return IsTokenMarked(tk, TypeRefMarkedBit); }
+ FORCEINLINE bool IsTypeDefMarked(mdToken tk) { return IsTokenMarked(tk, TypeDefMarkedBit); }
+ FORCEINLINE bool IsFieldMarked(mdToken tk) { return IsTokenMarked(tk, FieldMarkedBit); }
+ FORCEINLINE bool IsMethodMarked(mdToken tk) { return IsTokenMarked(tk, MethodMarkedBit); }
+ FORCEINLINE bool IsParamMarked(mdToken tk) { return IsTokenMarked(tk, ParamMarkedBit); }
+ FORCEINLINE bool IsMemberRefMarked(mdToken tk) { return IsTokenMarked(tk, MemberRefMarkedBit); }
+ FORCEINLINE bool IsCustomAttributeMarked(mdToken tk) { return IsTokenMarked(tk, CustomAttributeMarkedBit); }
+ FORCEINLINE bool IsDeclSecurityMarked(mdToken tk) { return IsTokenMarked(tk, DeclSecurityMarkedBit); }
+ FORCEINLINE bool IsSignatureMarked(mdToken tk) { return IsTokenMarked(tk, SignatureMarkedBit); }
+ FORCEINLINE bool IsEventMarked(mdToken tk) { return IsTokenMarked(tk, EventMarkedBit); }
+ FORCEINLINE bool IsPropertyMarked(mdToken tk) { return IsTokenMarked(tk, PropertyMarkedBit); }
+ FORCEINLINE bool IsMethodImplMarked(RID rid)
+ {
+ return IsTokenMarked(TokenFromRid(rid, TBL_MethodImpl << 24), MethodImplMarkedBit);
+ }
+ FORCEINLINE bool IsModuleRefMarked(mdToken tk) { return IsTokenMarked(tk, ModuleRefMarkedBit); }
+ FORCEINLINE bool IsTypeSpecMarked(mdToken tk) { return IsTokenMarked(tk, TypeSpecMarkedBit); }
+ FORCEINLINE bool IsInterfaceImplMarked(mdToken tk){ return IsTokenMarked(tk, InterfaceImplMarkedBit); }
+ FORCEINLINE bool IsAssemblyRefMarked(mdToken tk){ return IsTokenMarked(tk, AssemblyRefMarkedBit); }
+ FORCEINLINE bool IsMethodSpecMarked(mdToken tk){ return IsTokenMarked(tk, MethodSpecMarkedBit); }
+
+ bool IsUserStringMarked(mdString str);
+
+ __checkReturn HRESULT UnmarkAll(CMiniMdRW *pMiniMd, ULONG ulSize);
+ __checkReturn HRESULT MarkAll(CMiniMdRW *pMiniMd, ULONG ulSize);
+ bool IsTokenMarked(mdToken);
+
+ __checkReturn FORCEINLINE HRESULT UnmarkTypeDef(mdToken tk) { return UnmarkToken(tk, TypeDefMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT UnmarkField(mdToken tk) { return UnmarkToken(tk, FieldMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT UnmarkMethod(mdToken tk) { return UnmarkToken(tk, MethodMarkedBit); }
+ __checkReturn FORCEINLINE HRESULT UnmarkCustomAttribute(mdToken tk) { return UnmarkToken(tk, CustomAttributeMarkedBit); }
+
+private:
+ CDynArray<FilterUserStringEntry> *m_daUserStringMarker;
+ bool IsTokenMarked(mdToken tk, DWORD bitMarked);
+ __checkReturn HRESULT MarkToken(mdToken tk, DWORD bit);
+ __checkReturn HRESULT UnmarkToken(mdToken tk, DWORD bit);
+}; // class FilterTable : public CDynArray<DWORD>
+
+class CMiniMdRW;
+
+//*****************************************************************************
+// This class is used to keep a list of RID. This list of RID can be sorted
+// base on the m_ixCol's value of the m_ixTbl table.
+//*****************************************************************************
+class VirtualSort
+{
+public:
+ void Init(ULONG ixTbl, ULONG ixCol, CMiniMdRW *pMiniMd);
+ void Uninit();
+ TOKENMAP *m_pMap; // RID for m_ixTbl table. Sorted by on the ixCol
+ bool m_isMapValid;
+ ULONG m_ixTbl; // Table this is a sorter for.
+ ULONG m_ixCol; // Key column in the table.
+ CMiniMdRW *m_pMiniMd; // The MiniMd with the data.
+ __checkReturn
+ HRESULT Sort();
+private:
+ mdToken m_tkBuf;
+ __checkReturn
+ HRESULT SortRange(int iLeft, int iRight);
+public:
+ __checkReturn
+ HRESULT Compare(
+ RID iLeft, // First item to compare.
+ RID iRight, // Second item to compare.
+ int *pnResult); // -1, 0, or 1
+
+private:
+ FORCEINLINE void Swap(
+ RID iFirst,
+ RID iSecond)
+ {
+ if ( iFirst == iSecond ) return;
+ m_tkBuf = *(m_pMap->Get(iFirst));
+ *(m_pMap->Get(iFirst)) = *(m_pMap->Get(iSecond));
+ *(m_pMap->Get(iSecond)) = m_tkBuf;
+ }
+
+
+}; // class VirtualSort
+
+class ReorderData
+{
+public:
+ typedef enum
+ {
+ MinReorderBucketType=0, // bucket# shouldn't be less than this value
+ Undefined=0, // use this for initialization
+ Duplicate=1, // duplicate string
+ ProfileData=2, // bucket# for IBC data
+ PublicData=3, // bucket# for public data
+ OtherData=4, // bucket# for other data
+ NonPublicData=5, // bucket# for non-public data
+ MaxReorderBucketType=255 // bucket# shouldn't exceeed this value
+ } ReorderBucketType;
+};
+
+typedef CMetaDataHashBase CMemberRefHash;
+typedef CMetaDataHashBase CLookUpHash;
+
+class MDTOKENMAP;
+class MDInternalRW;
+class CorProfileData;
+class UTSemReadWrite;
+
+enum MetaDataReorderingOptions {
+ NoReordering=0x0,
+ ReArrangeStringPool=0x1
+};
+
+#ifdef FEATURE_PREJIT
+
+// {0702E333-8D64-4ca7-B564-4AA56B1FCEA3}
+EXTERN_GUID(IID_IMetaDataCorProfileData, 0x702e333, 0x8d64, 0x4ca7, 0xb5, 0x64, 0x4a, 0xa5, 0x6b, 0x1f, 0xce, 0xa3 );
+
+#undef INTERFACE
+#define INTERFACE IMetaDataCorProfileData
+DECLARE_INTERFACE_(IMetaDataCorProfileData, IUnknown)
+{
+ STDMETHOD(SetCorProfileData)(
+ CorProfileData *pProfileData) PURE; // [IN] Pointer to profile data
+};
+
+// {2B464817-C0F6-454e-99E7-C352D8384D7B}
+EXTERN_GUID(IID_IMDInternalMetadataReorderingOptions, 0x2B464817, 0xC0F6, 0x454e, 0x99, 0xE7, 0xC3, 0x52, 0xD8, 0x38, 0x4D, 0x7B );
+
+#undef INTERFACE
+#define INTERFACE IMDInternalMetadataReorderingOptions
+DECLARE_INTERFACE_(IMDInternalMetadataReorderingOptions, IUnknown)
+{
+ STDMETHOD(SetMetaDataReorderingOptions)(
+ MetaDataReorderingOptions options) PURE; // [IN] metadata reordering options
+};
+
+#endif //FEATURE_PREJIT
+
+template <class MiniMd> class CLiteWeightStgdb;
+//*****************************************************************************
+// Read/Write MiniMd.
+//*****************************************************************************
+class CMiniMdRW : public CMiniMdTemplate<CMiniMdRW>
+{
+public:
+ friend class CLiteWeightStgdb<CMiniMdRW>;
+ friend class CLiteWeightStgdbRW;
+ friend class CMiniMdTemplate<CMiniMdRW>;
+ friend class CQuickSortMiniMdRW;
+ friend class VirtualSort;
+ friend class MDInternalRW;
+ friend class RegMeta;
+ friend class FilterTable;
+ friend class ImportHelper;
+ friend class VerifyLayoutsMD;
+
+ CMiniMdRW();
+ ~CMiniMdRW();
+
+ __checkReturn
+ HRESULT InitNew();
+ __checkReturn
+ HRESULT InitOnMem(const void *pBuf, ULONG ulBufLen, int bReadOnly);
+ __checkReturn
+ HRESULT PostInit(int iLevel);
+ __checkReturn
+ HRESULT InitPoolOnMem(int iPool, void *pbData, ULONG cbData, int bReadOnly);
+ __checkReturn
+ HRESULT InitOnRO(CMiniMd *pMd, int bReadOnly);
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+ __checkReturn
+ HRESULT InitOnCustomDataSource(IMDCustomDataSource* pDataSouce);
+#endif
+ __checkReturn
+ HRESULT ConvertToRW();
+
+ __checkReturn
+ HRESULT GetSaveSize(
+ CorSaveSize fSave,
+ UINT32 *pcbSize,
+ DWORD *pbCompressed,
+ MetaDataReorderingOptions reorderingOptions = NoReordering,
+ CorProfileData *pProfileData = NULL);
+ int IsPoolEmpty(int iPool);
+ __checkReturn
+ HRESULT GetPoolSaveSize(int iPool, UINT32 *pcbSize);
+
+ __checkReturn
+ HRESULT SaveTablesToStream(IStream *pIStream, MetaDataReorderingOptions reorderingOptions, CorProfileData *pProfileData);
+ __checkReturn
+ HRESULT SavePoolToStream(int iPool, IStream *pIStream);
+ __checkReturn
+ HRESULT SaveDone();
+
+ __checkReturn
+ HRESULT SetHandler(IUnknown *pIUnk);
+
+ __checkReturn
+ HRESULT SetOption(OptionValue *pOptionValue);
+ __checkReturn
+ HRESULT GetOption(OptionValue *pOptionValue);
+
+ static ULONG GetTableForToken(mdToken tkn);
+ static mdToken GetTokenForTable(ULONG ixTbl);
+
+ FORCEINLINE static ULONG TblFromRecId(ULONG ul) { return (ul >> 24)&0x7f; }
+ FORCEINLINE static ULONG RidFromRecId(ULONG ul) { return ul & 0xffffff; }
+ FORCEINLINE static ULONG RecIdFromRid(ULONG rid, ULONG ixTbl) { return rid | ((ixTbl|0x80) << 24); }
+ FORCEINLINE static int IsRecId(ULONG ul) { return (ul & 0x80000000) != 0;}
+
+ // Place in every API function before doing any allocations.
+ __checkReturn
+ FORCEINLINE HRESULT PreUpdate()
+ {
+ if (m_eGrow == eg_grow)
+ {
+ return ExpandTables();
+ }
+ return S_OK;
+ }
+
+ __checkReturn
+ HRESULT AddRecord(
+ UINT32 nTableIndex,
+ void **ppRow,
+ RID *pRid);
+
+ __checkReturn
+ FORCEINLINE HRESULT PutCol(ULONG ixTbl, ULONG ixCol, void *pRecord, ULONG uVal)
+ { _ASSERTE(ixTbl < TBL_COUNT); _ASSERTE(ixCol < m_TableDefs[ixTbl].m_cCols);
+ return PutCol(m_TableDefs[ixTbl].m_pColDefs[ixCol], pRecord, uVal);
+ } // HRESULT CMiniMdRW::PutCol()
+ __checkReturn
+ HRESULT PutString(ULONG ixTbl, ULONG ixCol, void *pRecord, LPCSTR szString);
+ __checkReturn
+ HRESULT PutStringW(ULONG ixTbl, ULONG ixCol, void *pRecord, LPCWSTR wszString);
+ __checkReturn
+ HRESULT PutGuid(ULONG ixTbl, ULONG ixCol, void *pRecord, REFGUID guid);
+ __checkReturn
+ HRESULT ChangeMvid(REFGUID newMvid);
+ __checkReturn
+ HRESULT PutToken(ULONG ixTbl, ULONG ixCol, void *pRecord, mdToken tk);
+ __checkReturn
+ HRESULT PutBlob(ULONG ixTbl, ULONG ixCol, void *pRecord, const void *pvData, ULONG cbData);
+
+ __checkReturn
+ HRESULT PutUserString(MetaData::DataBlob data, UINT32 *pnIndex)
+ { return m_UserStringHeap.AddBlob(data, pnIndex); }
+
+ ULONG GetCol(ULONG ixTbl, ULONG ixCol, void *pRecord);
+ mdToken GetToken(ULONG ixTbl, ULONG ixCol, void *pRecord);
+
+ // Add a record to a table, and return a typed XXXRec *.
+// #undef AddTblRecord
+ #define AddTblRecord(tbl) \
+ __checkReturn HRESULT Add##tbl##Record(tbl##Rec **ppRow, RID *pnRowIndex) \
+ { return AddRecord(TBL_##tbl, reinterpret_cast<void **>(ppRow), pnRowIndex); }
+
+ AddTblRecord(Module)
+ AddTblRecord(TypeRef)
+ __checkReturn HRESULT AddTypeDefRecord( // Specialized implementation.
+ TypeDefRec **ppRow,
+ RID *pnRowIndex);
+ AddTblRecord(Field)
+ __checkReturn HRESULT AddMethodRecord( // Specialized implementation.
+ MethodRec **ppRow,
+ RID *pnRowIndex);
+ AddTblRecord(Param)
+ AddTblRecord(InterfaceImpl)
+ AddTblRecord(MemberRef)
+ AddTblRecord(Constant)
+ AddTblRecord(CustomAttribute)
+ AddTblRecord(FieldMarshal)
+ AddTblRecord(DeclSecurity)
+ AddTblRecord(ClassLayout)
+ AddTblRecord(FieldLayout)
+ AddTblRecord(StandAloneSig)
+ __checkReturn HRESULT AddEventMapRecord( // Specialized implementation.
+ EventMapRec **ppRow,
+ RID *pnRowIndex);
+ AddTblRecord(Event)
+ __checkReturn HRESULT AddPropertyMapRecord( // Specialized implementation.
+ PropertyMapRec **ppRow,
+ RID *pnRowIndex);
+ AddTblRecord(Property)
+ AddTblRecord(MethodSemantics)
+ AddTblRecord(MethodImpl)
+ AddTblRecord(ModuleRef)
+ AddTblRecord(FieldPtr)
+ AddTblRecord(MethodPtr)
+ AddTblRecord(ParamPtr)
+ AddTblRecord(PropertyPtr)
+ AddTblRecord(EventPtr)
+
+ AddTblRecord(ENCLog)
+ AddTblRecord(TypeSpec)
+ AddTblRecord(ImplMap)
+ AddTblRecord(ENCMap)
+ AddTblRecord(FieldRVA)
+
+ // Assembly Tables.
+ AddTblRecord(Assembly)
+ AddTblRecord(AssemblyProcessor)
+ AddTblRecord(AssemblyOS)
+ AddTblRecord(AssemblyRef)
+ AddTblRecord(AssemblyRefProcessor)
+ AddTblRecord(AssemblyRefOS)
+ AddTblRecord(File)
+ AddTblRecord(ExportedType)
+ AddTblRecord(ManifestResource)
+
+ AddTblRecord(NestedClass)
+ AddTblRecord(GenericParam)
+ AddTblRecord(MethodSpec)
+ AddTblRecord(GenericParamConstraint)
+
+ // Specialized AddXxxToYyy() functions.
+ __checkReturn HRESULT AddMethodToTypeDef(RID td, RID md);
+ __checkReturn HRESULT AddFieldToTypeDef(RID td, RID md);
+ __checkReturn HRESULT AddParamToMethod(RID md, RID pd);
+ __checkReturn HRESULT AddPropertyToPropertyMap(RID pmd, RID pd);
+ __checkReturn HRESULT AddEventToEventMap(ULONG emd, RID ed);
+
+ // does the MiniMdRW has the indirect tables, such as FieldPtr, MethodPtr
+ FORCEINLINE int HasIndirectTable(ULONG ix)
+ { if (g_PtrTableIxs[ix].m_ixtbl < TBL_COUNT) return GetCountRecs(g_PtrTableIxs[ix].m_ixtbl); return 0;}
+
+ FORCEINLINE int IsVsMapValid(ULONG ixTbl)
+ { _ASSERTE(ixTbl<TBL_COUNT); return (m_pVS[ixTbl] && m_pVS[ixTbl]->m_isMapValid); }
+
+ // translate index returned by getMethodListOfTypeDef to a rid into Method table
+ __checkReturn
+ FORCEINLINE HRESULT GetMethodRid(ULONG index, ULONG *pRid)
+ {
+ HRESULT hr;
+ if (HasIndirectTable(TBL_Method))
+ {
+ MethodPtrRec *pMethodPtrRecord;
+ IfFailGo(GetMethodPtrRecord(index, &pMethodPtrRecord));
+ *pRid = getMethodOfMethodPtr(pMethodPtrRecord);
+ }
+ else
+ {
+ *pRid = index;
+ }
+ return S_OK;
+ ErrExit:
+ *pRid = 0;
+ return hr;
+ }
+
+ // translate index returned by getFieldListOfTypeDef to a rid into Field table
+ __checkReturn
+ FORCEINLINE HRESULT GetFieldRid(ULONG index, ULONG *pRid)
+ {
+ HRESULT hr;
+ if (HasIndirectTable(TBL_Field))
+ {
+ FieldPtrRec *pFieldPtrRecord;
+ IfFailGo(GetFieldPtrRecord(index, &pFieldPtrRecord));
+ *pRid = getFieldOfFieldPtr(pFieldPtrRecord);
+ }
+ else
+ {
+ *pRid = index;
+ }
+ return S_OK;
+ ErrExit:
+ *pRid = 0;
+ return hr;
+ }
+
+ // translate index returned by getParamListOfMethod to a rid into Param table
+ __checkReturn
+ FORCEINLINE HRESULT GetParamRid(ULONG index, ULONG *pRid)
+ {
+ HRESULT hr;
+ if (HasIndirectTable(TBL_Param))
+ {
+ ParamPtrRec *pParamPtrRecord;
+ IfFailGo(GetParamPtrRecord(index, &pParamPtrRecord));
+ *pRid = getParamOfParamPtr(pParamPtrRecord);
+ }
+ else
+ {
+ *pRid = index;
+ }
+ return S_OK;
+ ErrExit:
+ *pRid = 0;
+ return hr;
+ }
+
+ // translate index returned by getEventListOfEventMap to a rid into Event table
+ __checkReturn
+ FORCEINLINE HRESULT GetEventRid(ULONG index, ULONG *pRid)
+ {
+ HRESULT hr;
+ if (HasIndirectTable(TBL_Event))
+ {
+ EventPtrRec *pEventPtrRecord;
+ IfFailGo(GetEventPtrRecord(index, &pEventPtrRecord));
+ *pRid = getEventOfEventPtr(pEventPtrRecord);
+ }
+ else
+ {
+ *pRid = index;
+ }
+ return S_OK;
+ ErrExit:
+ *pRid = 0;
+ return hr;
+ }
+
+ // translate index returned by getPropertyListOfPropertyMap to a rid into Property table
+ __checkReturn
+ FORCEINLINE HRESULT GetPropertyRid(ULONG index, ULONG *pRid)
+ {
+ HRESULT hr;
+ if (HasIndirectTable(TBL_Property))
+ {
+ PropertyPtrRec *pPropertyPtrRecord;
+ IfFailGo(GetPropertyPtrRecord(index, &pPropertyPtrRecord));
+ *pRid = getPropertyOfPropertyPtr(pPropertyPtrRecord);
+ }
+ else
+ {
+ *pRid = index;
+ }
+ return S_OK;
+ ErrExit:
+ *pRid = 0;
+ return hr;
+ }
+
+ // Convert a pseudo-RID from a Virtual Sort into a real RID.
+ FORCEINLINE ULONG GetRidFromVirtualSort(ULONG ixTbl, ULONG index)
+ { return IsVsMapValid(ixTbl) ? *(m_pVS[ixTbl]->m_pMap->Get(index)) : index; }
+
+ // Index returned by GetInterfaceImplForTypeDef. It could be index to VirtualSort table
+ // or directly to InterfaceImpl
+ FORCEINLINE ULONG GetInterfaceImplRid(ULONG index)
+ { return GetRidFromVirtualSort(TBL_InterfaceImpl, index); }
+
+ // Index returned by GetGenericParamForToken. It could be index to VirtualSort table
+ // or directly to GenericParam
+ FORCEINLINE ULONG GetGenericParamRid(ULONG index)
+ { return GetRidFromVirtualSort(TBL_GenericParam, index); }
+
+ // Index returned by GetGenericParamConstraintForToken. It could be index to VirtualSort table
+ // or directly to GenericParamConstraint
+ FORCEINLINE ULONG GetGenericParamConstraintRid(ULONG index)
+ { return GetRidFromVirtualSort(TBL_GenericParamConstraint, index); }
+
+ // Index returned by GetDeclSecurityForToken. It could be index to VirtualSort table
+ // or directly to DeclSecurity
+ FORCEINLINE ULONG GetDeclSecurityRid(ULONG index)
+ { return GetRidFromVirtualSort(TBL_DeclSecurity, index); }
+
+ // Index returned by GetCustomAttributeForToken. It could be index to VirtualSort table
+ // or directly to CustomAttribute
+ FORCEINLINE ULONG GetCustomAttributeRid(ULONG index)
+ { return GetRidFromVirtualSort(TBL_CustomAttribute, index); }
+
+ // add method, field, property, event, param to the map table
+ __checkReturn HRESULT AddMethodToLookUpTable(mdMethodDef md, mdTypeDef td);
+ __checkReturn HRESULT AddFieldToLookUpTable(mdFieldDef fd, mdTypeDef td);
+ __checkReturn HRESULT AddPropertyToLookUpTable(mdProperty pr, mdTypeDef td);
+ __checkReturn HRESULT AddEventToLookUpTable(mdEvent ev, mdTypeDef td);
+ __checkReturn HRESULT AddParamToLookUpTable(mdParamDef pd, mdMethodDef md);
+
+ // look up the parent of method, field, property, event, or param
+ __checkReturn HRESULT FindParentOfMethodHelper(mdMethodDef md, mdTypeDef *ptd);
+ __checkReturn HRESULT FindParentOfFieldHelper(mdFieldDef fd, mdTypeDef *ptd);
+ __checkReturn HRESULT FindParentOfPropertyHelper(mdProperty pr, mdTypeDef *ptd);
+ __checkReturn HRESULT FindParentOfEventHelper(mdEvent ev, mdTypeDef *ptd);
+ __checkReturn HRESULT FindParentOfParamHelper(mdParamDef pd, mdMethodDef *pmd);
+
+ bool IsMemberDefHashPresent() { return m_pMemberDefHash != NULL; }
+
+ // Function to reorganize the string pool based on IBC profile data (if available) and static analysis.
+ // Throws on error.
+ VOID OrganizeStringPool(CorProfileData *pProfileData);
+
+ // Result of hash search
+ enum HashSearchResult
+ {
+ Found, // Item was found.
+ NotFound, // Item not found.
+ NoTable // Table hasn't been built.
+ };
+
+ // Create MemberRef hash table.
+ __checkReturn
+ HRESULT CreateMemberRefHash();
+
+ // Add a new MemberRef to the hash table.
+ __checkReturn
+ HRESULT AddMemberRefToHash( // Return code.
+ mdMemberRef mr); // Token of new guy.
+
+ // If the hash is built, search for the item. Ignore token *ptkMemberRef.
+ HashSearchResult FindMemberRefFromHash(
+ mdToken tkParent, // Parent token.
+ LPCUTF8 szName, // Name of item.
+ PCCOR_SIGNATURE pvSigBlob, // Signature.
+ ULONG cbSigBlob, // Size of signature.
+ mdMemberRef * ptkMemberRef); // IN: Ignored token. OUT: Return if found.
+
+ //*************************************************************************
+ // Check a given mr token to see if this one is a match.
+ //*************************************************************************
+ __checkReturn
+ HRESULT CompareMemberRefs( // S_OK match, S_FALSE no match.
+ mdMemberRef mr, // Token to check.
+ mdToken tkPar, // Parent token.
+ LPCUTF8 szNameUtf8, // Name of item.
+ PCCOR_SIGNATURE pvSigBlob, // Signature.
+ ULONG cbSigBlob); // Size of signature.
+
+ // Add a new MemberDef to the hash table.
+ __checkReturn
+ HRESULT AddMemberDefToHash(
+ mdToken tkMember, // Token of new guy. It can be MethodDef or FieldDef
+ mdToken tkParent); // Parent token.
+
+ // Create MemberDef Hash
+ __checkReturn
+ HRESULT CreateMemberDefHash();
+
+ // If the hash is built, search for the item. Ignore token *ptkMember.
+ HashSearchResult FindMemberDefFromHash(
+ mdToken tkParent, // Parent token.
+ LPCUTF8 szName, // Name of item.
+ PCCOR_SIGNATURE pvSigBlob, // Signature.
+ ULONG cbSigBlob, // Size of signature.
+ mdToken * ptkMember); // IN: Ignored token. OUT: Return if found. It can be MethodDef or FieldDef
+
+ //*************************************************************************
+ // Check a given Method/Field token to see if this one is a match.
+ //*************************************************************************
+ __checkReturn
+ HRESULT CompareMemberDefs( // S_OK match, S_FALSE no match.
+ mdToken tkMember, // Token to check. It can be MethodDef or FieldDef
+ mdToken tkParent, // Parent token recorded in the hash entry
+ mdToken tkPar, // Parent token.
+ LPCUTF8 szNameUtf8, // Name of item.
+ PCCOR_SIGNATURE pvSigBlob, // Signature.
+ ULONG cbSigBlob); // Size of signature.
+
+ //*************************************************************************
+ // Add a new CustomAttributes to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddCustomAttributesToHash( // Return code.
+ mdCustomAttribute cv) // Token of new guy.
+ { return GenericAddToHash(TBL_CustomAttribute, CustomAttributeRec::COL_Parent, RidFromToken(cv)); }
+
+ inline ULONG HashMemberRef(mdToken tkPar, LPCUTF8 szName)
+ {
+ ULONG l = HashBytes((const BYTE *) &tkPar, sizeof(mdToken)) + HashStringA(szName);
+ return (l);
+ }
+
+ inline ULONG HashMemberDef(mdToken tkPar, LPCUTF8 szName)
+ {
+ return HashMemberRef(tkPar, szName);
+ }
+
+ // helper to calculate the hash value given a token
+ inline ULONG HashCustomAttribute(mdToken tkObject)
+ {
+ return HashToken(tkObject);
+ }
+
+ CMemberRefHash *m_pMemberRefHash;
+
+ // Hash table for Methods and Fields
+ CMemberDefHash *m_pMemberDefHash;
+
+ // helper to calculate the hash value given a pair of tokens
+ inline ULONG HashToken(mdToken tkObject)
+ {
+ ULONG l = HashBytes((const BYTE *) &tkObject, sizeof(mdToken));
+ return (l);
+ }
+
+
+ //*************************************************************************
+ // Add a new FieldMarhsal Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddFieldMarshalToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_FieldMarshal, FieldMarshalRec::COL_Parent, rid); }
+
+ //*************************************************************************
+ // Add a new Constant Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddConstantToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_Constant, ConstantRec::COL_Parent, rid); }
+
+ //*************************************************************************
+ // Add a new MethodSemantics Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddMethodSemanticsToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_MethodSemantics, MethodSemanticsRec::COL_Association, rid); }
+
+ //*************************************************************************
+ // Add a new ClassLayout Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddClassLayoutToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_ClassLayout, ClassLayoutRec::COL_Parent, rid); }
+
+ //*************************************************************************
+ // Add a new FieldLayout Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddFieldLayoutToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_FieldLayout, FieldLayoutRec::COL_Field, rid); }
+
+ //*************************************************************************
+ // Add a new ImplMap Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddImplMapToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_ImplMap, ImplMapRec::COL_MemberForwarded, rid); }
+
+ //*************************************************************************
+ // Add a new FieldRVA Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddFieldRVAToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_FieldRVA, FieldRVARec::COL_Field, rid); }
+
+ //*************************************************************************
+ // Add a new nested class Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddNestedClassToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_NestedClass, NestedClassRec::COL_NestedClass, rid); }
+
+ //*************************************************************************
+ // Add a new MethodImpl Rid to the hash table.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddMethodImplToHash( // Return code.
+ RID rid) // Token of new guy.
+ { return GenericAddToHash(TBL_MethodImpl, MethodImplRec::COL_Class, rid); }
+
+
+ //*************************************************************************
+ // Build a hash table for the specified table if the size exceed the thresholds.
+ //*************************************************************************
+ __checkReturn
+ HRESULT GenericBuildHashTable( // Return code.
+ ULONG ixTbl, // Table with hash
+ ULONG ixCol); // col that we hash.
+
+ //*************************************************************************
+ // Add a rid from a table into a hash
+ //*************************************************************************
+ __checkReturn
+ HRESULT GenericAddToHash( // Return code.
+ ULONG ixTbl, // Table with hash
+ ULONG ixCol, // col that we hash.
+ RID rid); // new row of the table.
+
+ //*************************************************************************
+ // Add a rid from a table into a hash
+ //*************************************************************************
+ __checkReturn
+ HRESULT GenericFindWithHash( // Return code.
+ ULONG ixTbl, // Table with hash
+ ULONG ixCol, // col that we hash.
+ mdToken tkTarget, // token to be find in the hash
+ RID *pFoundRid);
+
+
+ // look up hash table for tokenless tables.
+ // They are constant, FieldMarshal, MethodSemantics, ClassLayout, FieldLayout, ImplMap, FieldRVA, NestedClass, and MethodImpl
+ CLookUpHash * m_pLookUpHashs[TBL_COUNT];
+
+#if defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE)
+ MapSHash<UINT32, UINT32> m_StringPoolOffsetHash;
+#endif
+
+ //*************************************************************************
+ // Hash for named items.
+ //*************************************************************************
+ __checkReturn
+ HRESULT AddNamedItemToHash( // Return code.
+ ULONG ixTbl, // Table with the new item.
+ mdToken tk, // Token of new guy.
+ LPCUTF8 szName, // Name of item.
+ mdToken tkParent); // Token of parent, if any.
+
+ HashSearchResult FindNamedItemFromHash(
+ ULONG ixTbl, // Table with the item.
+ LPCUTF8 szName, // Name of item.
+ mdToken tkParent, // Token of parent, if any.
+ mdToken * ptk); // Return if found.
+
+ __checkReturn
+ HRESULT CompareNamedItems( // S_OK match, S_FALSE no match.
+ ULONG ixTbl, // Table with the item.
+ mdToken tk, // Token to check.
+ LPCUTF8 szName, // Name of item.
+ mdToken tkParent); // Token of parent, if any.
+
+ FORCEINLINE ULONG HashNamedItem(mdToken tkPar, LPCUTF8 szName)
+ { return HashBytes((const BYTE *) &tkPar, sizeof(mdToken)) + HashStringA(szName); }
+
+ CMetaDataHashBase *m_pNamedItemHash;
+
+ //*****************************************************************************
+ // IMetaModelCommon - RW specific versions for some of the functions.
+ //*****************************************************************************
+ __checkReturn
+ virtual HRESULT CommonGetEnclosingClassOfTypeDef(
+ mdTypeDef td,
+ mdTypeDef *ptkEnclosingTypeDef)
+ {
+ _ASSERTE(ptkEnclosingTypeDef != NULL);
+
+ HRESULT hr;
+ NestedClassRec *pRec;
+ RID iRec;
+
+ IfFailRet(FindNestedClassHelper(td, &iRec));
+ if (iRec == 0)
+ {
+ *ptkEnclosingTypeDef = mdTypeDefNil;
+ return S_OK;
+ }
+
+ IfFailRet(GetNestedClassRecord(iRec, &pRec));
+ *ptkEnclosingTypeDef = getEnclosingClassOfNestedClass(pRec);
+ return S_OK;
+ }
+
+ __checkReturn
+ HRESULT CommonEnumCustomAttributeByName( // S_OK or error.
+ mdToken tkObj, // [IN] Object with Custom Attribute.
+ LPCUTF8 szName, // [IN] Name of desired Custom Attribute.
+ bool fStopAtFirstFind, // [IN] just find the first one
+ HENUMInternal* phEnum); // enumerator to fill up
+
+ __checkReturn
+ HRESULT CommonGetCustomAttributeByNameEx( // S_OK or error.
+ mdToken tkObj, // [IN] Object with Custom Attribute.
+ LPCUTF8 szName, // [IN] Name of desired Custom Attribute.
+ mdCustomAttribute *ptkCA, // [OUT] put custom attribute token here
+ const void **ppData, // [OUT] Put pointer to data here.
+ ULONG *pcbData); // [OUT] Put size of data here.
+
+ //*****************************************************************************
+ // Find helper for a constant.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindConstantHelper( // return index to the constant table
+ mdToken tkParent, // Parent token. Can be ParamDef, FieldDef, or Property.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // Find helper for a FieldMarshal.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindFieldMarshalHelper( // return index to the field marshal table
+ mdToken tkParent, // Parent token. Can be a FieldDef or ParamDef.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // Find helper for a method semantics.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindMethodSemanticsHelper( // return HRESULT
+ mdToken tkAssociate, // Event or property token
+ HENUMInternal *phEnum); // fill in the enum
+
+ //*****************************************************************************
+ // Find helper for a method semantics given a associate and semantics.
+ // This will look up methodsemantics based on its status!
+ // Return CLDB_E_RECORD_NOTFOUND if cannot find the matching one
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindAssociateHelper(// return HRESULT
+ mdToken tkAssociate, // Event or property token
+ DWORD dwSemantics, // [IN] given a associate semantics(setter, getter, testdefault, reset)
+ RID *pRid); // [OUT] return matching row index here
+
+ //*****************************************************************************
+ // Find helper for a MethodImpl.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindMethodImplHelper(// return HRESULT
+ mdTypeDef td, // TypeDef token for the Class.
+ HENUMInternal *phEnum); // fill in the enum
+
+ //*****************************************************************************
+ // Find helper for a GenericParams
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindGenericParamHelper( // Return HRESULT
+ mdToken tkOwner, // Token for the GenericParams' owner
+ HENUMInternal *phEnum); // Fill in the enum.
+
+ //*****************************************************************************
+ // Find helper for a Generic Constraints
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindGenericParamConstraintHelper( // Return HRESULT
+ mdGenericParam tkParam, // Token for the GenericParam
+ HENUMInternal *phEnum); // Fill in the enum.
+
+ //*****************************************************************************
+ // Find helper for a ClassLayout.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindClassLayoutHelper( // return index to the ClassLayout table
+ mdTypeDef tkParent, // Parent token.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // Find helper for a FieldLayout.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindFieldLayoutHelper( // return index to the FieldLayout table
+ mdFieldDef tkField, // Token for the field.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // Find helper for a ImplMap.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindImplMapHelper( // return index to the constant table
+ mdToken tk, // Member forwarded token.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // Find helper for a FieldRVA.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindFieldRVAHelper( // return index to the FieldRVA table
+ mdFieldDef tkField, // Token for the field.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // Find helper for a NestedClass.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT FindNestedClassHelper( // return index to the NestedClass table
+ mdTypeDef tkClass, // Token for the NestedClass.
+ RID *pFoundRid);
+
+ //*****************************************************************************
+ // IMPORTANT!!!!!!!! Use these set of functions if you are dealing with RW rather
+ // getInterfaceImplsForTypeDef, getDeclSecurityForToken, etc.
+ // The following functions can deal with these tables when they are not sorted and
+ // build the VirtualSort tables for quick lookup.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT GetInterfaceImplsForTypeDef(mdTypeDef td, RID *pRidStart, RID *pRidEnd = 0)
+ {
+ return LookUpTableByCol( RidFromToken(td), m_pVS[TBL_InterfaceImpl], pRidStart, pRidEnd);
+ }
+
+ __checkReturn
+ HRESULT GetGenericParamsForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0)
+ {
+ return LookUpTableByCol(
+ encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtTypeOrMethodDef, lengthof(mdtTypeOrMethodDef)),
+ m_pVS[TBL_GenericParam], pRidStart, pRidEnd);
+ }
+
+ __checkReturn
+ HRESULT GetGenericParamConstraintsForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0)
+ {
+ return LookUpTableByCol( RidFromToken(tk),
+ m_pVS[TBL_GenericParamConstraint], pRidStart, pRidEnd);
+ }
+
+ __checkReturn
+ HRESULT GetMethodSpecsForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0)
+ {
+ return LookUpTableByCol(
+ encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtMethodDefOrRef, lengthof(mdtMethodDefOrRef)),
+ m_pVS[TBL_MethodSpec], pRidStart, pRidEnd);
+ }
+
+ __checkReturn
+ HRESULT GetDeclSecurityForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0)
+ {
+ return LookUpTableByCol(
+ encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasDeclSecurity, lengthof(mdtHasDeclSecurity)),
+ m_pVS[TBL_DeclSecurity],
+ pRidStart,
+ pRidEnd);
+ }
+
+ __checkReturn
+ HRESULT GetCustomAttributeForToken(mdToken tk, RID *pRidStart, RID *pRidEnd = 0)
+ {
+ return LookUpTableByCol(
+ encodeToken(RidFromToken(tk), TypeFromToken(tk), mdtHasCustomAttribute, lengthof(mdtHasCustomAttribute)),
+ m_pVS[TBL_CustomAttribute],
+ pRidStart,
+ pRidEnd);
+ }
+
+ __checkReturn
+ FORCEINLINE HRESULT GetUserString(ULONG nIndex, MetaData::DataBlob *pData)
+ { return m_UserStringHeap.GetBlob(nIndex, pData); }
+ // Gets user string (*Data) at index (nIndex) and fills the index (*pnNextIndex) of the next user string
+ // in the heap.
+ // Returns S_OK and fills the string (*pData) and the next index (*pnNextIndex).
+ // Returns S_FALSE if the index (nIndex) is not valid user string index.
+ // Returns error code otherwise.
+ // Clears *pData and sets *pnNextIndex to 0 on error or S_FALSE.
+ __checkReturn
+ HRESULT GetUserStringAndNextIndex(
+ UINT32 nIndex,
+ MetaData::DataBlob *pData,
+ UINT32 *pnNextIndex);
+
+ FORCEINLINE int IsSorted(ULONG ixTbl) { return m_Schema.IsSorted(ixTbl);}
+ FORCEINLINE int IsSortable(ULONG ixTbl) { return m_bSortable[ixTbl];}
+ FORCEINLINE bool HasDelete() { return ((m_Schema.m_heaps & CMiniMdSchema::HAS_DELETE) ? true : false); }
+ FORCEINLINE int IsPreSaveDone() { return m_bPreSaveDone; }
+
+protected:
+ __checkReturn HRESULT PreSave(MetaDataReorderingOptions reorderingOptions=NoReordering, CorProfileData *pProfileData=NULL);
+ __checkReturn HRESULT PostSave();
+
+ __checkReturn HRESULT PreSaveFull();
+ __checkReturn HRESULT PreSaveEnc();
+
+ __checkReturn HRESULT GetFullPoolSaveSize(int iPool, UINT32 *pcbSize);
+ __checkReturn HRESULT GetENCPoolSaveSize(int iPool, UINT32 *pcbSize);
+
+ __checkReturn HRESULT SaveFullPoolToStream(int iPool, IStream *pIStream);
+ __checkReturn HRESULT SaveENCPoolToStream(int iPool, IStream *pIStream);
+
+ __checkReturn
+ HRESULT GetHotMetadataTokensSearchAware(
+ CorProfileData *pProfileData,
+ ULONG ixTbl,
+ ULONG *pResultCount,
+ mdToken *tokenBuffer,
+ ULONG maxCount);
+
+ __checkReturn
+ HRESULT GetFullSaveSize(
+ CorSaveSize fSave,
+ UINT32 *pcbSize,
+ DWORD *pbCompressed,
+ MetaDataReorderingOptions reorderingOptions = NoReordering,
+ CorProfileData *pProfileData = NULL);
+ __checkReturn
+ HRESULT GetENCSaveSize(UINT32 *pcbSize);
+ __checkReturn
+ HRESULT GetHotPoolsSaveSize(
+ UINT32 *pcbSize,
+ MetaDataReorderingOptions reorderingOptions,
+ CorProfileData *pProfileData);
+
+ __checkReturn
+ HRESULT SaveFullTablesToStream(IStream *pIStream, MetaDataReorderingOptions reorderingOptions=NoReordering, CorProfileData *pProfileData = NULL );
+ __checkReturn
+ HRESULT SaveENCTablesToStream(IStream *pIStream);
+ __checkReturn
+ HRESULT SaveHotPoolsToStream(
+ IStream *pStream,
+ MetaDataReorderingOptions reorderingOptions,
+ CorProfileData *pProfileData,
+ UINT32 *pnPoolDirSize,
+ UINT32 *pnSavedPoolsSize);
+ __checkReturn
+ HRESULT SaveHotPoolToStream(
+ IStream *pStream,
+ CorProfileData *pProfileData,
+ MetaData::HotHeapWriter *pHotHeapWriter,
+ UINT32 *pnSavedSize);
+
+ // TO ELIMINATE:
+ __checkReturn
+ HRESULT AddGuid(REFGUID pGuid, UINT32 *pnIndex)
+ { return m_GuidHeap.AddGuid(&pGuid, pnIndex); }
+
+ // Allows putting into tables outside this MiniMd, specifically the temporary
+ // table used on save.
+ __checkReturn
+ HRESULT PutCol(CMiniColDef ColDef, void *pRecord, ULONG uVal);
+
+ // Returns TRUE if token (tk) is valid.
+ // For user strings, consideres 0 as valid token.
+ BOOL _IsValidToken(
+ mdToken tk) // [IN] token to be checked
+ {
+ if (TypeFromToken(tk) == mdtString)
+ {
+ // need to check the user string heap
+ return m_UserStringHeap.IsValidIndex(RidFromToken(tk));
+ }
+ // Base type doesn't know about user string blob (yet)
+ return _IsValidTokenBase(tk);
+ } // CMiniMdRW::_IsValidToken
+
+#ifdef _DEBUG
+ bool CanHaveCustomAttribute(ULONG ixTbl);
+#endif
+
+ __checkReturn
+ HRESULT ExpandTables();
+ __checkReturn
+ HRESULT ExpandTableColumns(CMiniMdSchema &Schema, ULONG ixTbl);
+
+ __checkReturn
+ HRESULT InitWithLargeTables();
+
+ void ComputeGrowLimits(int bSmall=TRUE); // Set max, lim, based on param.
+ ULONG m_maxRid; // Highest RID so far allocated.
+ ULONG m_limRid; // Limit on RID before growing.
+ ULONG m_maxIx; // Highest pool index so far.
+ ULONG m_limIx; // Limit on pool index before growing.
+ enum {eg_ok, eg_grow, eg_grown} m_eGrow; // Is a grow required? done?
+ #define AUTO_GROW_CODED_TOKEN_PADDING 5
+
+ // fix up these tables after PreSave has move the tokens
+ __checkReturn HRESULT FixUpTable(ULONG ixTbl);
+ __checkReturn HRESULT FixUpRefToDef();
+
+ // Table info.
+ MetaData::TableRW m_Tables[TBL_COUNT];
+ VirtualSort *m_pVS[TBL_COUNT]; // Virtual sorters, one per table, but sparse.
+
+ //*****************************************************************************
+ // look up a table by a col given col value is ulVal.
+ //*****************************************************************************
+ __checkReturn
+ HRESULT LookUpTableByCol(
+ ULONG ulVal,
+ VirtualSort *pVSTable,
+ RID *pRidStart,
+ RID *pRidEnd);
+
+ __checkReturn
+ HRESULT Impl_SearchTableRW(ULONG ixTbl, ULONG ixCol, ULONG ulTarget, RID *pFoundRid);
+ __checkReturn
+ virtual HRESULT vSearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ulTarget, RID *pRid);
+ __checkReturn
+ virtual HRESULT vSearchTableNotGreater(ULONG ixTbl, CMiniColDef sColumn, ULONG ulTarget, RID *pRid);
+
+ void SetSorted(ULONG ixTbl, int bSorted)
+ { m_Schema.SetSorted(ixTbl, bSorted); }
+
+ void SetPreSaveDone(int bPreSaveDone)
+ { m_bPreSaveDone = bPreSaveDone; }
+
+ // Heaps
+ MetaData::StringHeapRW m_StringHeap;
+ MetaData::BlobHeapRW m_BlobHeap;
+ MetaData::BlobHeapRW m_UserStringHeap;
+ MetaData::GuidHeapRW m_GuidHeap;
+
+ IMapToken *m_pHandler; // Remap handler.
+ __checkReturn HRESULT MapToken(RID from, RID to, mdToken type);
+
+ ULONG m_cbSaveSize; // Estimate of save size.
+
+ int m_fIsReadOnly : 1; // Is this db read-only?
+ int m_bPreSaveDone : 1; // Has save optimization been done?
+ int m_bSaveCompressed : 1; // Can the data be saved as fully compressed?
+ int m_bPostGSSMod : 1; // true if a change was made post GetSaveSize.
+
+
+ //*************************************************************************
+ // Overridables -- must be provided in derived classes.
+ __checkReturn
+ FORCEINLINE HRESULT Impl_GetString(UINT32 nIndex, __out LPCSTR *pszString)
+ { return m_StringHeap.GetString(nIndex, pszString); }
+ __checkReturn
+ HRESULT Impl_GetStringW(ULONG ix, __inout_ecount (cchBuffer) LPWSTR szOut, ULONG cchBuffer, ULONG *pcchBuffer);
+ __checkReturn
+ FORCEINLINE HRESULT Impl_GetGuid(UINT32 nIndex, GUID *pTargetGuid)
+ {
+ HRESULT hr;
+ GUID UNALIGNED *pSourceGuid;
+ IfFailRet(m_GuidHeap.GetGuid(
+ nIndex,
+ &pSourceGuid));
+ // Add void* casts so that the compiler can't make assumptions about alignment.
+ CopyMemory((void *)pTargetGuid, (void *)pSourceGuid, sizeof(GUID));
+ SwapGuid(pTargetGuid);
+ return S_OK;
+ }
+
+ __checkReturn
+ FORCEINLINE HRESULT Impl_GetBlob(ULONG nIndex, __out MetaData::DataBlob *pData)
+ { return m_BlobHeap.GetBlob(nIndex, pData); }
+
+ __checkReturn
+ FORCEINLINE HRESULT Impl_GetRow(
+ UINT32 nTableIndex,
+ UINT32 nRowIndex,
+ __deref_out_opt BYTE **ppRecord)
+ {
+ _ASSERTE(nTableIndex < TBL_COUNT);
+ return m_Tables[nTableIndex].GetRecord(nRowIndex, ppRecord);
+ }
+
+ // Count of rows in tbl2, pointed to by the column in tbl.
+ __checkReturn
+ HRESULT Impl_GetEndRidForColumn(
+ UINT32 nTableIndex,
+ RID nRowIndex,
+ CMiniColDef &def, // Column containing the RID into other table.
+ UINT32 nTargetTableIndex, // The other table.
+ RID *pEndRid);
+
+ __checkReturn
+ FORCEINLINE HRESULT Impl_SearchTable(ULONG ixTbl, CMiniColDef sColumn, ULONG ixCol, ULONG ulTarget, RID *pFoundRid)
+ { return Impl_SearchTableRW(ixTbl, ixCol, ulTarget, pFoundRid); }
+
+ FORCEINLINE int Impl_IsRo()
+ { return 0; }
+
+
+ //*************************************************************************
+ enum {END_OF_TABLE = 0};
+ FORCEINLINE ULONG NewRecordPointerEndValue(ULONG ixTbl)
+ { if (HasIndirectTable(ixTbl)) return m_Schema.m_cRecs[ixTbl]+1; else return END_OF_TABLE; }
+
+ __checkReturn HRESULT ConvertMarkerToEndOfTable(ULONG tblParent, ULONG colParent, ULONG ridChild, RID ridParent);
+
+ // Add a child row, adjust pointers in parent rows.
+ __checkReturn
+ HRESULT AddChildRowIndirectForParent(
+ ULONG tblParent,
+ ULONG colParent,
+ ULONG tblChild,
+ RID ridParent,
+ void **ppRow);
+
+ // Update pointers in the parent table to reflect the addition of a child, if required
+ // create the indirect table in which case don't update pointers.
+ __checkReturn
+ HRESULT AddChildRowDirectForParent(ULONG tblParent, ULONG colParent, ULONG tblChild, RID ridParent);
+
+ // Given a table id, create the corresponding indirect table.
+ __checkReturn
+ HRESULT CreateIndirectTable(ULONG ixtbl, BOOL bOneLess = true);
+
+ // If the last param is not added in the right sequence, fix it up.
+ __checkReturn
+ HRESULT FixParamSequence(RID md);
+
+
+ // these are the map tables to map a method, a field, a property, a event, or a param to its parent
+ TOKENMAP *m_pMethodMap;
+ TOKENMAP *m_pFieldMap;
+ TOKENMAP *m_pPropertyMap;
+ TOKENMAP *m_pEventMap;
+ TOKENMAP *m_pParamMap;
+
+ // This table keep tracks tokens that are marked( or filtered)
+ FilterTable *m_pFilterTable;
+ IHostFilter *m_pHostFilter;
+
+ // TOKENMAP *m_pTypeRefToTypeDefMap;
+ TokenRemapManager *m_pTokenRemapManager;
+
+ OptionValue m_OptionValue;
+
+ CMiniMdSchema m_StartupSchema; // Schema at start time. Keep count of records.
+ BYTE m_bSortable[TBL_COUNT]; // Is a given table sortable? (Can it be reorganized?)
+#ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE
+ ReleaseHolder<IMDCustomDataSource> m_pCustomDataSource;
+#endif
+
+#ifdef _DEBUG
+
+protected:
+ UTSemReadWrite * dbg_m_pLock;
+
+public:
+ // Checks that MetaData is locked for write operation (if thread-safety is enabled and the lock exists)
+ void Debug_CheckIsLockedForWrite();
+
+ void Debug_SetLock(UTSemReadWrite * pLock)
+ {
+ dbg_m_pLock = pLock;
+ }
+
+#endif //_DEBUG
+
+public:
+
+ FilterTable *GetFilterTable();
+ __checkReturn HRESULT UnmarkAll();
+ __checkReturn HRESULT MarkAll();
+
+ FORCEINLINE IHostFilter *GetHostFilter() { return m_pHostFilter;}
+
+ __checkReturn HRESULT CalculateTypeRefToTypeDefMap();
+
+ FORCEINLINE TOKENMAP *GetTypeRefToTypeDefMap()
+ { return m_pTokenRemapManager ? m_pTokenRemapManager->GetTypeRefToTypeDefMap() : NULL; };
+
+ FORCEINLINE TOKENMAP *GetMemberRefToMemberDefMap()
+ { return m_pTokenRemapManager ? m_pTokenRemapManager->GetMemberRefToMemberDefMap() : NULL; };
+
+ FORCEINLINE MDTOKENMAP *GetTokenMovementMap()
+ { return m_pTokenRemapManager ? m_pTokenRemapManager->GetTokenMovementMap() : NULL; };
+
+ FORCEINLINE TokenRemapManager *GetTokenRemapManager() { return m_pTokenRemapManager; };
+
+ __checkReturn HRESULT InitTokenRemapManager();
+
+ virtual ULONG vGetCol(ULONG ixTbl, ULONG ixCol, void *pRecord)
+ { return GetCol(ixTbl, ixCol, pRecord);}
+
+public:
+ virtual BOOL IsWritable()
+ {
+ return !m_fIsReadOnly;
+ }
+
+
+ //*************************************************************************
+ // Delta MetaData (EditAndContinue) functions.
+public:
+ enum eDeltaFuncs{
+ eDeltaFuncDefault = 0,
+ eDeltaMethodCreate,
+ eDeltaFieldCreate,
+ eDeltaParamCreate,
+ eDeltaPropertyCreate,
+ eDeltaEventCreate,
+ };
+
+ __checkReturn HRESULT ApplyDelta(CMiniMdRW &mdDelta);
+
+public:
+ // Functions for updating ENC log tables ENC log.
+ FORCEINLINE BOOL IsENCOn()
+ {
+ return (m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateENC;
+ }
+
+ __checkReturn
+ FORCEINLINE HRESULT UpdateENCLog(mdToken tk, CMiniMdRW::eDeltaFuncs funccode = CMiniMdRW::eDeltaFuncDefault)
+ {
+ if (IsENCOn())
+ return UpdateENCLogHelper(tk, funccode);
+ else
+ return S_OK;
+ }
+
+ __checkReturn
+ FORCEINLINE HRESULT UpdateENCLog2(ULONG ixTbl, ULONG iRid, CMiniMdRW::eDeltaFuncs funccode = CMiniMdRW::eDeltaFuncDefault)
+ {
+ if (IsENCOn())
+ return UpdateENCLogHelper2(ixTbl, iRid, funccode);
+ else
+ return S_OK;
+ }
+
+ __checkReturn HRESULT ResetENCLog();
+
+private:
+ BOOL m_fMinimalDelta;
+
+ //
+ // String heap reorganization
+ //
+
+ // Check to see if it is safe to reorder the string pool.
+ BOOL IsSafeToReorderStringPool();
+ // Function to mark hot strings in the marks array based on the token information in profile data.
+ VOID MarkHotStrings(CorProfileData *pProfileData, BYTE * pMarks, ULONG poolSize);
+ // Function to mark hot strings referenced by hot tables based on token information in profile data.
+ VOID MarkStringsInHotTables(CorProfileData *pProfileData, BYTE * pMarks, ULONG poolSize);
+ // Function to mark strings referenced by the different metadata tables.
+ VOID MarkStringsInTables(BYTE * pMarks, ULONG poolSize);
+ // Function to mark duplicate strings in the mark array.
+ // Throws on error.
+ VOID MarkDuplicateStrings(BYTE * pMarks, ULONG poolSize);
+ // Function to update the tables with the modified string offsets.
+ VOID FixStringsInTables();
+ // Function to fill the given string pool with strings from the existing string pool using the mark array.
+ // Throws on error.
+ VOID CreateReorderedStringPool(
+ MetaData::StringHeapRW *pStringHeap,
+ BYTE *pMarks,
+ ULONG cbHeapSize,
+ CorProfileData *pProfileData);
+
+public:
+ BOOL IsMinimalDelta()
+ {
+ return m_fMinimalDelta;
+ }
+
+
+ // Turns on/off the ability to emit delta metadatas
+
+ // Unfortunately, we can't allow this to be set via the SetOption method anymore. In v1.0 and v1.1, this flag
+ // could be set but would still result in generating full metadatas. We can't automatically start generating
+ // true deltas for people... it could break them.
+ void EnableDeltaMetadataGeneration()
+ {
+ _ASSERTE(m_OptionValue.m_UpdateMode == MDUpdateENC);
+#ifndef FEATURE_CORECLR
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_UseMinimalDeltas))
+ m_OptionValue.m_UpdateMode = MDUpdateDelta;
+#endif //!FEATURE_CORECLR
+ }
+ void DisableDeltaMetadataGeneration() {m_OptionValue.m_UpdateMode = MDUpdateENC;}
+
+protected:
+ // Internal Helper functions for ENC log.
+ __checkReturn
+ HRESULT UpdateENCLogHelper(mdToken tk, CMiniMdRW::eDeltaFuncs funccode);
+ __checkReturn
+ HRESULT UpdateENCLogHelper2(ULONG ixTbl, ULONG iRid, CMiniMdRW::eDeltaFuncs funccode);
+
+protected:
+ static ULONG m_TruncatedEncTables[];
+ static ULONG m_SuppressedDeltaColumns[TBL_COUNT];
+
+ ULONGARRAY *m_rENCRecs; // Array of RIDs affected by ENC.
+
+ __checkReturn
+ HRESULT ApplyRecordDelta(CMiniMdRW &mdDelta, ULONG ixTbl, void *pDelta, void *pRecord);
+ __checkReturn
+ HRESULT ApplyTableDelta(CMiniMdRW &mdDelta, ULONG ixTbl, RID iRid, int fc);
+ __checkReturn
+ HRESULT GetDeltaRecord(ULONG ixTbl, ULONG iRid, void **ppRecord);
+ __checkReturn
+ HRESULT ApplyHeapDeltas(CMiniMdRW &mdDelta);
+ __checkReturn
+ HRESULT ApplyHeapDeltasWithMinimalDelta(CMiniMdRW &mdDelta);
+ __checkReturn
+ HRESULT ApplyHeapDeltasWithFullDelta(CMiniMdRW &mdDelta);
+ __checkReturn
+ HRESULT StartENCMap(); // Call, on a delta MD, to prepare to access sparse rows.
+ __checkReturn
+ HRESULT EndENCMap(); // Call, on a delta MD, when done with sparse rows.
+
+public:
+ // Workaround for compiler performance issue VSW 584653 for 2.0 RTM.
+ // Get the table's VirtualSort validity state.
+ bool IsTableVirtualSorted(ULONG ixTbl);
+ // Workaround for compiler performance issue VSW 584653 for 2.0 RTM.
+ // Validate table's VirtualSort after adding one record into the table.
+ // Returns new VirtualSort validity state in *pfIsTableVirtualSortValid.
+ // Assumptions:
+ // Table's VirtualSort was valid before adding the record to the table.
+ // The caller must ensure validity of VirtualSort by calling to
+ // IsTableVirtualSorted or by using the returned state from previous
+ // call to this method.
+ __checkReturn
+ HRESULT ValidateVirtualSortAfterAddRecord(
+ ULONG ixTbl,
+ bool * pfIsTableVirtualSortValid);
+
+}; // class CMiniMdRW : public CMiniMdTemplate<CMiniMdRW>
+
+#endif // _METAMODELRW_H_