summaryrefslogtreecommitdiff
path: root/src/md/compiler/newmerger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/md/compiler/newmerger.cpp')
-rw-r--r--src/md/compiler/newmerger.cpp6303
1 files changed, 6303 insertions, 0 deletions
diff --git a/src/md/compiler/newmerger.cpp b/src/md/compiler/newmerger.cpp
new file mode 100644
index 0000000000..d5199bb570
--- /dev/null
+++ b/src/md/compiler/newmerger.cpp
@@ -0,0 +1,6303 @@
+// 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.
+//*****************************************************************************
+// NewMerger.cpp
+//
+
+//
+// contains utility code to MD directory
+//
+// This file provides Compiler Support functionality in metadata.
+//*****************************************************************************
+#include "stdafx.h"
+
+#include "newmerger.h"
+#include "regmeta.h"
+
+
+#include "importhelper.h"
+#include "rwutil.h"
+#include "mdlog.h"
+#include <posterror.h>
+#include <sstring.h>
+#include "ndpversion.h"
+
+#ifdef FEATURE_METADATA_EMIT_ALL
+
+#define MODULEDEFTOKEN TokenFromRid(1, mdtModule)
+
+#define COR_MSCORLIB_NAME "mscorlib"
+#define COR_MSCORLIB_TYPEREF {0xb7, 0x7a, 0x5c, 0x56,0x19,0x34,0xe0,0x89}
+
+#define COR_CONSTRUCTOR_METADATA_IDENTIFIER W(".ctor")
+
+#define COR_COMPILERSERVICE_NAMESPACE "System.Runtime.CompilerServices"
+#define COR_EXCEPTIONSERVICE_NAMESPACE "System.Runtime.ExceptionServices"
+#define COR_SUPPRESS_MERGE_CHECK_ATTRIBUTE "SuppressMergeCheckAttribute"
+#define COR_HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE "HandleProcessCorruptedStateExceptionsAttribute"
+#define COR_MISCBITS_NAMESPACE "Microsoft.VisualC"
+#define COR_MISCBITS_ATTRIBUTE "Microsoft.VisualC.MiscellaneousBitsAttribute"
+#define COR_NATIVECPPCLASS_ATTRIBUTE "System.Runtime.CompilerServices.NativeCppClassAttribute"
+
+// MODULE_CA_LOCATION W("System.Runtime.CompilerServices.AssemblyAttributesGoHere")
+#define MODULE_CA_TYPENAME "AssemblyAttributesGoHere" // fake assembly type-ref for hanging Assembly-level CAs off of
+
+//*****************************************************************************
+// BEGIN: Security Critical Attributes and Enumeration
+//*****************************************************************************
+#define COR_SECURITYCRITICALSCOPE_ENUM_W W("System.Security.SecurityCriticalScope")
+
+#define COR_SECURITYCRITICAL_ATTRIBUTE_FULL "System.Security.SecurityCriticalAttribute"
+#define COR_SECURITYTRANSPARENT_ATTRIBUTE_FULL "System.Security.SecurityTransparentAttribute"
+#define COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL "System.Security.SecurityTreatAsSafeAttribute"
+
+#define COR_SECURITYCRITICAL_ATTRIBUTE_FULL_W W("System.Security.SecurityCriticalAttribute")
+#define COR_SECURITYTRANSPARENT_ATTRIBUTE_FULL_W W("System.Security.SecurityTransparentAttribute")
+#define COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL_W W("System.Security.SecurityTreatAsSafeAttribute")
+#define COR_SECURITYSAFECRITICAL_ATTRIBUTE_FULL_W W("System.Security.SecuritySafeCriticalAttribute")
+
+ // definitions of enumeration for System.Security.SecurityCriticalScope (Explicit or Everything)
+#define COR_SECURITYCRITICAL_CTOR_ARGCOUNT_NO_SCOPE 0
+#define COR_SECURITYCRITICAL_CTOR_ARGCOUNT_SCOPE_EVERYTHING 1
+#define COR_SECURITYCRITICAL_CTOR_NO_SCOPE_SIG_MAX_SIZE (3)
+#define COR_SECURITYCRITICAL_CTOR_SCOPE_SIG_MAX_SIZE (5 + sizeof(mdTypeRef) * 1)
+
+#define COR_SECURITYCRITICAL_ATTRIBUTE_NAMESPACE "System.Security"
+#define COR_SECURITYCRITICAL_ATTRIBUTE "SecurityCriticalAttribute"
+#define COR_SECURITYTRANSPARENT_ATTRIBUTE_NAMESPACE "System.Security"
+#define COR_SECURITYTRANSPARENT_ATTRIBUTE "SecurityTransparentAttribute"
+#define COR_SECURITYTREATASSAFE_ATTRIBUTE_NAMESPACE "System.Security"
+#define COR_SECURITYTREATASSAFE_ATTRIBUTE "SecurityTreatAsSafeAttribute"
+#define COR_SECURITYSAFECRITICAL_ATTRIBUTE "SecuritySafeCriticalAttribute"
+
+
+#define COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EVERYTHING { 0x01, 0x00 ,0x01, 0x00, 0x00, 0x00 ,0x00, 0x00 }
+#define COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EXPLICIT {0x01, 0x00, 0x00 ,0x00}
+#define COR_SECURITYTREATASSAFE_ATTRIBUTE_VALUE {0x01, 0x00, 0x00 ,0x00}
+
+
+ // if true, then registry has been read for enabling or disabling SecurityCritical support
+static BOOL g_fRefShouldMergeCriticalChecked = FALSE;
+
+// by default, security critical attributes will be merged (e.g. unmarked CRT marked Critical/TAS)
+// - unless registry config explicitly disables merging
+static BOOL g_fRefShouldMergeCritical = TRUE;
+//*****************************************************************************
+// END: Security Critical Attributes and Enumeration
+//*****************************************************************************
+
+//*****************************************************************************
+// Checks to see if the given type is managed or native. We'll key off of the
+// Custom Attribute "Microsoft.VisualC.MiscellaneousBitsAttribute". If the third
+// byte has the 01000000 bit set then it is an unmanaged type.
+// If we can't find the attribute, we will also check for the presence of the
+// "System.Runtime.CompilerServices.NativeCppClassAttribute" Custom Attribute
+// since the CPP compiler stopped emitting MiscellaneousBitsAttribute in Dev11.
+//*****************************************************************************
+HRESULT IsManagedType(CMiniMdRW* pMiniMd,
+ mdTypeDef td,
+ BOOL *fIsManagedType)
+{
+ // First look for the custom attribute
+ HENUMInternal hEnum;
+ HRESULT hr = S_OK;
+
+ IfFailRet(pMiniMd->CommonEnumCustomAttributeByName(td, COR_MISCBITS_ATTRIBUTE, false, &hEnum));
+
+ // If there aren't any custom attributes here, then this must be a managed type
+ if (hEnum.m_ulCount > 0)
+ {
+ // Let's loop through these, and see if any of them have that magical bit set.
+ mdCustomAttribute ca;
+ CustomAttributeRec *pRec;
+ ULONG cbData = 0;
+
+ while(HENUMInternal::EnumNext(&hEnum, &ca))
+ {
+ const BYTE* pData = NULL;
+
+ IfFailGo(pMiniMd->GetCustomAttributeRecord(RidFromToken(ca), &pRec));
+ IfFailGo(pMiniMd->getValueOfCustomAttribute(pRec, &pData, &cbData));
+
+ if (pData != NULL && cbData >=3)
+ {
+ // See if the magical bit is set to make this an unmanaged type
+ if ((*(pData+2)&0x40) > 0)
+ {
+ // Yes, this is an unmanaged type
+ HENUMInternal::ClearEnum(&hEnum);
+ *fIsManagedType = FALSE;
+ return S_OK;
+ }
+ }
+ }
+
+ }
+
+ HENUMInternal::ClearEnum(&hEnum);
+
+ // If this was emitted by a Dev11+ CPP compiler, we only have NativeCppClassAttribute
+ // so let's check for that before calling this a managed class.
+ IfFailRet(pMiniMd->CommonEnumCustomAttributeByName(td, COR_NATIVECPPCLASS_ATTRIBUTE, false, &hEnum));
+ if (hEnum.m_ulCount > 0)
+ {
+ // Yes, this is an unmanaged type
+ HENUMInternal::ClearEnum(&hEnum);
+ *fIsManagedType = FALSE;
+ return S_OK;
+ }
+
+ // Nope, this isn't an unmanaged type.... must be managed
+ HENUMInternal::ClearEnum(&hEnum);
+ *fIsManagedType = TRUE;
+ hr = S_OK;
+ErrExit:
+ return hr;
+}// IsManagedType
+
+
+//*****************************************************************************
+// "Is CustomAttribute from certain namespace and assembly" check helper
+// Returns S_OK and fills **ppTypeRefRec.
+// Returns error code or S_FALSE otherwise as not found and fills **ppTypeRefRec with NULL.
+//*****************************************************************************
+HRESULT IsAttributeFromNamespace(
+ CMiniMdRW *pMiniMd,
+ mdToken tk,
+ LPCSTR szNamespace,
+ LPCSTR szAssembly,
+ TypeRefRec **ppTypeRefRec)
+{
+ HRESULT hr = S_OK;
+ if(TypeFromToken(tk) == mdtMemberRef)
+ {
+ MemberRefRec *pMemRefRec;
+ IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tk), &pMemRefRec));
+ tk = pMiniMd->getClassOfMemberRef(pMemRefRec);
+ }
+ if(TypeFromToken(tk) == mdtTypeRef)
+ {
+ TypeRefRec *pTypeRefRec;
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tk), &pTypeRefRec));
+ LPCSTR szTypeRefNamespace;
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szTypeRefNamespace));
+ if (strcmp(szTypeRefNamespace, szNamespace) == 0)
+ {
+ mdToken tkResTmp = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec);
+ if (TypeFromToken(tkResTmp) == mdtAssemblyRef)
+ {
+ AssemblyRefRec *pAsmRefRec;
+ IfFailGo(pMiniMd->GetAssemblyRefRecord(RidFromToken(tkResTmp), &pAsmRefRec));
+ LPCSTR szAssemblyRefName;
+ IfFailGo(pMiniMd->getNameOfAssemblyRef(pAsmRefRec, &szAssemblyRefName));
+ if(SString::_stricmp(szAssemblyRefName, szAssembly) == 0)
+ {
+ *ppTypeRefRec = pTypeRefRec;
+ return S_OK;
+ }
+ }
+ }
+ }
+ // Record not found
+ hr = S_FALSE;
+ErrExit:
+ *ppTypeRefRec = NULL;
+ return hr;
+}
+
+//*****************************************************************************
+// constructor
+//*****************************************************************************
+NEWMERGER::NEWMERGER()
+ : m_pRegMetaEmit(0),
+ m_pImportDataList(NULL),
+ m_optimizeRefToDef(MDRefToDefDefault),
+ m_isscsSecurityCritical(ISSCS_Unknown),
+ m_isscsSecurityCriticalAllScopes(~ISSCS_Unknown)
+{
+ m_pImportDataTail = &(m_pImportDataList);
+#if _DEBUG
+ m_iImport = 0;
+#endif // _DEBUG
+} // NEWMERGER::NEWMERGER()
+
+//*****************************************************************************
+// initializer
+//*****************************************************************************
+HRESULT NEWMERGER::Init(RegMeta *pRegMeta)
+{
+ HRESULT hr = NOERROR;
+ MergeTypeData * pMTD;
+
+ m_pRegMetaEmit = pRegMeta;
+
+ // burn an entry so that the RID matches the array index
+ IfNullGo(pMTD = m_rMTDs.Append());
+
+ pMTD->m_bSuppressMergeCheck = false;
+ pMTD->m_cMethods = 0;
+ pMTD->m_cFields = 0;
+ pMTD->m_cEvents = 0;
+ pMTD->m_cProperties = 0;
+
+ErrExit:
+ return hr;
+} // NEWMERGER::Init
+
+//*****************************************************************************
+// destructor
+//*****************************************************************************
+NEWMERGER::~NEWMERGER()
+{
+ if (m_pImportDataList)
+ {
+ // delete this list and release all AddRef'ed interfaces!
+ MergeImportData *pNext;
+ for (pNext = m_pImportDataList; pNext != NULL; )
+ {
+ pNext = m_pImportDataList->m_pNextImportData;
+ if (m_pImportDataList->m_pHandler)
+ m_pImportDataList->m_pHandler->Release();
+ if (m_pImportDataList->m_pHostMapToken)
+ m_pImportDataList->m_pHostMapToken->Release();
+ if (m_pImportDataList->m_pMDTokenMap)
+ delete m_pImportDataList->m_pMDTokenMap;
+ m_pImportDataList->m_pRegMetaImport->Release();
+ delete m_pImportDataList;
+ m_pImportDataList = pNext;
+ }
+ }
+} // NEWMERGER::~NEWMERGER
+
+//*****************************************************************************
+CMiniMdRW *NEWMERGER::GetMiniMdEmit()
+{
+ return &(m_pRegMetaEmit->m_pStgdb->m_MiniMd);
+} // CMiniMdRW *NEWMERGER::GetMiniMdEmit()
+
+//*****************************************************************************
+// Adding a new import
+//*****************************************************************************
+HRESULT NEWMERGER::AddImport(
+ IMetaDataImport2 *pImport, // [IN] The scope to be merged.
+ IMapToken *pHostMapToken, // [IN] Host IMapToken interface to receive token remap notification
+ IUnknown *pHandler) // [IN] An object to receive error notification.
+{
+ HRESULT hr = NOERROR;
+ MergeImportData *pData;
+
+ RegMeta *pRM = static_cast<RegMeta*>(pImport);
+
+ // Add a MergeImportData to track the information for this import scope
+ pData = new (nothrow) MergeImportData;
+ IfNullGo( pData );
+ pData->m_pRegMetaImport = pRM;
+ pData->m_pRegMetaImport->AddRef();
+ pData->m_pHostMapToken = pHostMapToken;
+ if (pData->m_pHostMapToken)
+ pData->m_pHostMapToken->AddRef();
+ if (pHandler)
+ {
+ pData->m_pHandler = pHandler;
+ pData->m_pHandler->AddRef();
+ }
+ else
+ {
+ pData->m_pHandler = NULL;
+ }
+
+ pData->m_pMDTokenMap = NULL;
+ pData->m_pNextImportData = NULL;
+#if _DEBUG
+ pData->m_iImport = ++m_iImport;
+#endif // _DEBUG
+
+ pData->m_tkHandleProcessCorruptedStateCtor = mdTokenNil;
+ // add the newly create node to the tail of the list
+ *m_pImportDataTail = pData;
+ m_pImportDataTail = &(pData->m_pNextImportData);
+
+ErrExit:
+
+ return hr;
+} // HRESULT NEWMERGER::AddImport()
+
+HRESULT NEWMERGER::InitMergeTypeData()
+{
+ CMiniMdRW *pMiniMdEmit;
+ ULONG cTypeDefRecs;
+ ULONG i, j;
+ bool bSuppressMergeCheck;
+
+ ULONG ridStart, ridEnd;
+ RID ridMap;
+
+ mdToken tkSuppressMergeCheckCtor = mdTokenNil;
+ mdToken tkCA;
+ mdMethodDef mdEmit;
+ mdFieldDef fdEmit;
+ mdEvent evEmit;
+ mdProperty prEmit;
+
+ TypeDefRec *pTypeDefRec;
+ EventMapRec *pEventMapRec;
+ PropertyMapRec *pPropertyMapRec;
+
+ MergeTypeData *pMTD;
+
+ HRESULT hr = NOERROR;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ // cache the SuppressMergeCheckAttribute.ctor token
+ ImportHelper::FindCustomAttributeCtorByName(
+ pMiniMdEmit, COR_MSCORLIB_NAME,
+ COR_COMPILERSERVICE_NAMESPACE, COR_SUPPRESS_MERGE_CHECK_ATTRIBUTE,
+ &tkSuppressMergeCheckCtor);
+
+ cTypeDefRecs = pMiniMdEmit->getCountTypeDefs();
+ _ASSERTE(m_rMTDs.Count() > 0);
+
+ for (i = m_rMTDs.Count(); i <= cTypeDefRecs; i++)
+ {
+ IfNullGo(pMTD = m_rMTDs.Append());
+
+ pMTD->m_cMethods = 0;
+ pMTD->m_cFields = 0;
+ pMTD->m_cEvents = 0;
+ pMTD->m_cProperties = 0;
+ pMTD->m_bSuppressMergeCheck = (tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit,
+ TokenFromRid(i, mdtTypeDef), tkSuppressMergeCheckCtor,
+ NULL, 0, &tkCA));
+
+ IfFailGo(pMiniMdEmit->GetTypeDefRecord(i, &pTypeDefRec));
+
+ // Count the number methods
+ ridStart = pMiniMdEmit->getMethodListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMdEmit->getEndMethodListOfTypeDef(i, &ridEnd));
+
+ for (j = ridStart; j < ridEnd; j++)
+ {
+ IfFailGo(pMiniMdEmit->GetMethodRid(j, (ULONG *)&mdEmit));
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit,
+ mdEmit, tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck)
+ {
+ pMTD->m_cMethods++;
+ }
+ }
+
+ // Count the number fields
+ ridStart = pMiniMdEmit->getFieldListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMdEmit->getEndFieldListOfTypeDef(i, &ridEnd));
+
+ for (j = ridStart; j < ridEnd; j++)
+ {
+ IfFailGo(pMiniMdEmit->GetFieldRid(j, (ULONG *)&fdEmit));
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit,
+ fdEmit, tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck)
+ {
+ pMTD->m_cFields++;
+ }
+ }
+
+ // Count the number of events
+ IfFailGo(pMiniMdEmit->FindEventMapFor(i, &ridMap));
+ if (!InvalidRid(ridMap))
+ {
+ IfFailGo(pMiniMdEmit->GetEventMapRecord(ridMap, &pEventMapRec));
+ ridStart = pMiniMdEmit->getEventListOfEventMap(pEventMapRec);
+ IfFailGo(pMiniMdEmit->getEndEventListOfEventMap(ridMap, &ridEnd));
+
+ for (j = ridStart; j < ridEnd; j++)
+ {
+ IfFailGo(pMiniMdEmit->GetEventRid(j, (ULONG *)&evEmit));
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit,
+ evEmit, tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck)
+ {
+ pMTD->m_cEvents++;
+ }
+ }
+ }
+
+ // Count the number of properties
+ IfFailGo(pMiniMdEmit->FindPropertyMapFor(i, &ridMap));
+ if (!InvalidRid(ridMap))
+ {
+ IfFailGo(pMiniMdEmit->GetPropertyMapRecord(ridMap, &pPropertyMapRec));
+ ridStart = pMiniMdEmit->getPropertyListOfPropertyMap(pPropertyMapRec);
+ IfFailGo(pMiniMdEmit->getEndPropertyListOfPropertyMap(ridMap, &ridEnd));
+
+ for (j = ridStart; j < ridEnd; j++)
+ {
+ IfFailGo(pMiniMdEmit->GetPropertyRid(j, (ULONG *)&prEmit));
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdEmit,
+ prEmit, tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck)
+ {
+ pMTD->m_cProperties++;
+ }
+ }
+ }
+ }
+
+ErrExit:
+ return hr;
+}
+
+//*****************************************************************************
+// Merge now
+//*****************************************************************************
+HRESULT NEWMERGER::Merge(MergeFlags dwMergeFlags, CorRefToDefCheck optimizeRefToDef)
+{
+ MergeImportData *pImportData = m_pImportDataList;
+ MDTOKENMAP **pPrevMap = NULL;
+ MDTOKENMAP *pMDTokenMap;
+ HRESULT hr = NOERROR;
+ MDTOKENMAP *pCurTKMap;
+ int i;
+
+#if _DEBUG
+ {
+ LOG((LOGMD, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"));
+ LOG((LOGMD, "Merge scope list\n"));
+ i = 0;
+ for (MergeImportData *pID = m_pImportDataList; pID != NULL; pID = pID->m_pNextImportData)
+ {
+ WCHAR szScope[1024], szGuid[40];
+ GUID mvid;
+ ULONG cchScope;
+ pID->m_pRegMetaImport->GetScopeProps(szScope, 1024, &cchScope, &mvid);
+ szScope[1023] = 0;
+ GuidToLPWSTR(mvid, szGuid, 40);
+ ++i; // Counter is 1-based.
+ LOG((LOGMD, "%3d: %ls : %ls\n", i, szGuid, szScope));
+ }
+ LOG((LOGMD, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"));
+ }
+#endif // _DEBUG
+
+ m_dwMergeFlags = dwMergeFlags;
+ m_optimizeRefToDef = optimizeRefToDef;
+
+ // check to see if we need to do dup check
+ m_fDupCheck = ((m_dwMergeFlags & NoDupCheck) != NoDupCheck);
+
+ while (pImportData)
+ {
+ // Verify that we have a filter for each import scope.
+ IfNullGo( pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd.GetFilterTable() );
+
+ // cache the SuppressMergeCheckAttribute.ctor token for each import scope
+ ImportHelper::FindCustomAttributeCtorByName(
+ &pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd, COR_MSCORLIB_NAME,
+ COR_COMPILERSERVICE_NAMESPACE, COR_SUPPRESS_MERGE_CHECK_ATTRIBUTE,
+ &pImportData->m_tkSuppressMergeCheckCtor);
+
+ // cache the HandleProcessCorruptedStateExceptionsAttribute.ctor token for each import scope
+ ImportHelper::FindCustomAttributeCtorByName(
+ &pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd, COR_MSCORLIB_NAME,
+ COR_EXCEPTIONSERVICE_NAMESPACE, COR_HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE,
+ &pImportData->m_tkHandleProcessCorruptedStateCtor);
+
+ // check for security critical attribute in the assembly (i.e. explicit annotations)
+ InputScopeSecurityCriticalStatus isscsTemp = CheckInputScopeIsCritical(pImportData, hr);
+ IfFailGo(hr);
+ // clear the unset flag bits (e.g. if critical, clear transparent bit)
+ // whatever bits remain are bits that have been set in all scopes
+ if (ISSCS_Unknown == (isscsTemp & ISSCS_SECURITYCRITICAL_FLAGS))
+ m_isscsSecurityCriticalAllScopes &= ISSCS_SECURITYCRITICAL_LEGACY;
+ else
+ m_isscsSecurityCriticalAllScopes &= isscsTemp;
+ // set the flag bits (essentially, this allows us to see if _any_ scopes requested a bit)
+ m_isscsSecurityCritical |= isscsTemp;
+
+ // create the tokenmap class to track metadata token remap for each import scope
+ pMDTokenMap = new (nothrow) MDTOKENMAP;
+ IfNullGo(pMDTokenMap);
+ IfFailGo(pMDTokenMap->Init((IMetaDataImport2*)pImportData->m_pRegMetaImport));
+ pImportData->m_pMDTokenMap = pMDTokenMap;
+ pImportData->m_pMDTokenMap->m_pMap = pImportData->m_pHostMapToken;
+ if (pImportData->m_pHostMapToken)
+ pImportData->m_pHostMapToken->AddRef();
+ pImportData->m_pMDTokenMap->m_pNextMap = NULL;
+ if (pPrevMap)
+ *pPrevMap = pImportData->m_pMDTokenMap;
+ pPrevMap = &(pImportData->m_pMDTokenMap->m_pNextMap);
+ pImportData = pImportData->m_pNextImportData;
+ }
+
+ // Populate the m_rMTDs with the type info already defined in the emit scope
+ IfFailGo( InitMergeTypeData() );
+
+ // 1. Merge Module
+ IfFailGo( MergeModule( ) );
+
+ // 2. Merge TypeDef partially (i.e. only name)
+ IfFailGo( MergeTypeDefNamesOnly() );
+
+ // 3. Merge ModuleRef property and do ModuleRef to ModuleDef optimization
+ IfFailGo( MergeModuleRefs() );
+
+ // 4. Merge AssemblyRef.
+ IfFailGo( MergeAssemblyRefs() );
+
+ // 5. Merge TypeRef with TypeRef to TypeDef optimization
+ IfFailGo( MergeTypeRefs() );
+
+ // 6. Merge TypeSpec & MethodSpec
+ IfFailGo( MergeTypeSpecs() );
+
+ // 7. Now Merge the remaining of TypeDef records
+ IfFailGo( CompleteMergeTypeDefs() );
+
+ // 8. Merge Methods and Fields. Such that Signature translation is respecting the TypeRef to TypeDef optimization.
+ IfFailGo( MergeTypeDefChildren() );
+
+ // 9. Merge MemberRef with MemberRef to MethodDef/FieldDef optimization
+ IfFailGo( MergeMemberRefs( ) );
+
+ // 10. Merge InterfaceImpl
+ IfFailGo( MergeInterfaceImpls( ) );
+
+ // merge all of the remaining in metadata ....
+
+ // 11. constant has dependency on property, field, param
+ IfFailGo( MergeConstants() );
+
+ // 12. field marshal has dependency on param and field
+ IfFailGo( MergeFieldMarshals() );
+
+ // 13. in ClassLayout, move over the FieldLayout and deal with FieldLayout as well
+ IfFailGo( MergeClassLayouts() );
+
+ // 14. FieldLayout has dependency on FieldDef.
+ IfFailGo( MergeFieldLayouts() );
+
+ // 15. FieldRVA has dependency on FieldDef.
+ IfFailGo( MergeFieldRVAs() );
+
+ // 16. MethodImpl has dependency on MemberRef, MethodDef, TypeRef and TypeDef.
+ IfFailGo( MergeMethodImpls() );
+
+ // 17. pinvoke depends on MethodDef and ModuleRef
+ IfFailGo( MergePinvoke() );
+
+ IfFailGo( MergeStandAloneSigs() );
+
+ IfFailGo( MergeMethodSpecs() );
+
+ IfFailGo( MergeStrings() );
+
+ if (m_dwMergeFlags & MergeManifest)
+ {
+ // keep the manifest!!
+ IfFailGo( MergeAssembly() );
+ IfFailGo( MergeFiles() );
+ IfFailGo( MergeExportedTypes() );
+ IfFailGo( MergeManifestResources() );
+ }
+ else if (m_dwMergeFlags & ::MergeExportedTypes)
+ {
+ IfFailGo( MergeFiles() );
+ IfFailGo( MergeExportedTypes() );
+ }
+
+ IfFailGo( MergeCustomAttributes() );
+ IfFailGo( MergeDeclSecuritys() );
+
+
+ // Please don't add any MergeXxx() below here. CustomAttributess must be
+ // very late, because custom values are various other types.
+
+ // Fixup list cannot be merged. Linker will need to re-emit them.
+
+ // Now call back to host for the result of token remap
+ //
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // Send token remap information for each import scope
+ pCurTKMap = pImportData->m_pMDTokenMap;
+ TOKENREC *pRec;
+ if (pImportData->m_pHostMapToken)
+ {
+ for (i = 0; i < pCurTKMap->Count(); i++)
+ {
+ pRec = pCurTKMap->Get(i);
+ if (!pRec->IsEmpty())
+ pImportData->m_pHostMapToken->Map(pRec->m_tkFrom, pRec->m_tkTo);
+ }
+ }
+ }
+
+ // And last, but not least, let's do Security critical module-level attribute consolidation
+ // and metadata fixups.
+ IfFailGo( MergeSecurityCriticalAttributes() );
+
+
+
+
+
+#if _DEBUG
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // dump the mapping
+ LOG((LOGMD, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"));
+ LOG((LOGMD, "Dumping token remap for one import scope!\n"));
+ LOG((LOGMD, "This is the %d import scope for merge!\n", pImportData->m_iImport));
+
+ pCurTKMap = pImportData->m_pMDTokenMap;
+ TOKENREC *pRec;
+ for (i = 0; i < pCurTKMap->Count(); i++)
+ {
+ pRec = pCurTKMap->Get(i);
+ if (!pRec->IsEmpty())
+ {
+ LOG((LOGMD, " Token 0x%08x ====>>>> Token 0x%08x\n", pRec->m_tkFrom, pRec->m_tkTo));
+ }
+ }
+ LOG((LOGMD, "End dumping token remap!\n"));
+ LOG((LOGMD, "++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"));
+ }
+#endif // _DEBUG
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::Merge()
+
+
+//*****************************************************************************
+// Merge ModuleDef
+//*****************************************************************************
+HRESULT NEWMERGER::MergeModule()
+{
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+ HRESULT hr = NOERROR;
+ TOKENREC *pTokenRec;
+
+ // we don't really merge Module information but we create a one to one mapping for each module token into the TokenMap
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ // set the current MDTokenMap
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ IfFailGo( pCurTkMap->InsertNotFound(MODULEDEFTOKEN, true, MODULEDEFTOKEN, &pTokenRec) );
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeModule()
+
+
+//*****************************************************************************
+// Merge TypeDef but only Names. This is a partial merge to support TypeRef to TypeDef optimization
+//*****************************************************************************
+HRESULT NEWMERGER::MergeTypeDefNamesOnly()
+{
+ HRESULT hr = NOERROR;
+ TypeDefRec *pRecImport = NULL;
+ TypeDefRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdTypeDef tdEmit;
+ mdTypeDef tdImport;
+ bool bDuplicate;
+ DWORD dwFlags;
+ DWORD dwExportFlags;
+ NestedClassRec *pNestedRec;
+ RID iNestedRec;
+ mdTypeDef tdNester;
+ TOKENREC *pTokenRec;
+
+ LPCUTF8 szNameImp;
+ LPCUTF8 szNamespaceImp;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ iCount = pMiniMdImport->getCountTypeDefs();
+
+ // Merge the typedefs
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those TypeDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsTypeDefMarked(TokenFromRid(i, mdtTypeDef)) == false)
+ continue;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getNameOfTypeDef(pRecImport, &szNameImp));
+ IfFailGo(pMiniMdImport->getNamespaceOfTypeDef(pRecImport, &szNamespaceImp));
+
+ // If the class is a Nested class, get the parent token.
+ dwFlags = pMiniMdImport->getFlagsOfTypeDef(pRecImport);
+ if (IsTdNested(dwFlags))
+ {
+ IfFailGo(pMiniMdImport->FindNestedClassHelper(TokenFromRid(i, mdtTypeDef), &iNestedRec));
+ if (InvalidRid(iNestedRec))
+ {
+ _ASSERTE(!"Bad state!");
+ IfFailGo(META_E_BADMETADATA);
+ }
+ else
+ {
+ IfFailGo(pMiniMdImport->GetNestedClassRecord(iNestedRec, &pNestedRec));
+ tdNester = pMiniMdImport->getEnclosingClassOfNestedClass(pNestedRec);
+ _ASSERTE(!IsNilToken(tdNester));
+ IfFailGo(pCurTkMap->Remap(tdNester, &tdNester));
+ }
+ }
+ else
+ tdNester = mdTokenNil;
+
+ bSuppressMergeCheck = (pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ TokenFromRid(i, mdtTypeDef), pImportData->m_tkSuppressMergeCheckCtor,
+ NULL, 0, &tkCA));
+
+ // does this TypeDef already exist in the emit scope?
+ if ( ImportHelper::FindTypeDefByName(
+ pMiniMdEmit,
+ szNamespaceImp,
+ szNameImp,
+ tdNester,
+ &tdEmit) == S_OK )
+ {
+ // Yes, it does
+ bDuplicate = true;
+
+ // Let's look at their accessiblities.
+ IfFailGo(pMiniMdEmit->GetTypeDefRecord(RidFromToken(tdEmit), &pRecEmit));
+ dwExportFlags = pMiniMdEmit->getFlagsOfTypeDef(pRecEmit);
+
+ // Managed types need to have the same accessiblity
+ BOOL fManagedType = FALSE;
+ IfFailGo(IsManagedType(pMiniMdImport, TokenFromRid(i, mdtTypeDef), &fManagedType));
+ if (fManagedType)
+ {
+ if ((dwFlags&tdVisibilityMask) != (dwExportFlags&tdVisibilityMask))
+ {
+ CheckContinuableErrorEx(META_E_MISMATCHED_VISIBLITY, pImportData, TokenFromRid(i, mdtTypeDef));
+ }
+
+ }
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+ if (pMTD->m_bSuppressMergeCheck != bSuppressMergeCheck)
+ {
+ CheckContinuableErrorEx(META_E_MD_INCONSISTENCY, pImportData, TokenFromRid(i, mdtTypeDef));
+ }
+ }
+ else
+ {
+ // No, it doesn't. Copy it over.
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddTypeDefRecord(&pRecEmit, (RID *)&tdEmit));
+
+ // make sure the index matches
+ _ASSERTE(((mdTypeDef)m_rMTDs.Count()) == tdEmit);
+
+ IfNullGo(pMTD = m_rMTDs.Append());
+
+ pMTD->m_cMethods = 0;
+ pMTD->m_cFields = 0;
+ pMTD->m_cEvents = 0;
+ pMTD->m_cProperties = 0;
+ pMTD->m_bSuppressMergeCheck = bSuppressMergeCheck;
+
+ tdEmit = TokenFromRid( tdEmit, mdtTypeDef );
+
+ // Set Full Qualified Name.
+ IfFailGo( CopyTypeDefPartially( pRecEmit, pMiniMdImport, pRecImport) );
+
+ // Create a NestedClass record if the class is a Nested class.
+ if (! IsNilToken(tdNester))
+ {
+ IfFailGo(pMiniMdEmit->AddNestedClassRecord(&pNestedRec, &iNestedRec));
+
+ // copy over the information
+ IfFailGo( pMiniMdEmit->PutToken(TBL_NestedClass, NestedClassRec::COL_NestedClass,
+ pNestedRec, tdEmit));
+
+ // tdNester has already been remapped above to the Emit scope.
+ IfFailGo( pMiniMdEmit->PutToken(TBL_NestedClass, NestedClassRec::COL_EnclosingClass,
+ pNestedRec, tdNester));
+ IfFailGo( pMiniMdEmit->AddNestedClassToHash(iNestedRec) );
+
+ }
+ }
+
+ // record the token movement
+ tdImport = TokenFromRid(i, mdtTypeDef);
+ IfFailGo( pCurTkMap->InsertNotFound(tdImport, bDuplicate, tdEmit, &pTokenRec) );
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeTypeDefNamesOnly()
+
+
+//*****************************************************************************
+// Merge EnclosingType tables
+//*****************************************************************************
+HRESULT NEWMERGER::CopyTypeDefPartially(
+ TypeDefRec *pRecEmit, // [IN] the emit record to fill
+ CMiniMdRW *pMiniMdImport, // [IN] the importing scope
+ TypeDefRec *pRecImp) // [IN] the record to import
+
+{
+ HRESULT hr;
+ LPCUTF8 szNameImp;
+ LPCUTF8 szNamespaceImp;
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+
+ IfFailGo(pMiniMdImport->getNameOfTypeDef(pRecImp, &szNameImp));
+ IfFailGo(pMiniMdImport->getNamespaceOfTypeDef(pRecImp, &szNamespaceImp));
+
+ IfFailGo( pMiniMdEmit->PutString( TBL_TypeDef, TypeDefRec::COL_Name, pRecEmit, szNameImp) );
+ IfFailGo( pMiniMdEmit->PutString( TBL_TypeDef, TypeDefRec::COL_Namespace, pRecEmit, szNamespaceImp) );
+
+ pRecEmit->SetFlags(pRecImp->GetFlags());
+
+ // Don't copy over the extends until TypeRef's remap is calculated
+
+ErrExit:
+ return hr;
+
+} // HRESULT NEWMERGER::CopyTypeDefPartially()
+
+
+//*****************************************************************************
+// Merge ModuleRef tables including ModuleRef to ModuleDef optimization
+//*****************************************************************************
+HRESULT NEWMERGER::MergeModuleRefs()
+{
+ HRESULT hr = NOERROR;
+ ModuleRefRec *pRecImport = NULL;
+ ModuleRefRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdModuleRef mrEmit;
+ bool bDuplicate = false;
+ TOKENREC *pTokenRec;
+ LPCUTF8 szNameImp;
+ bool isModuleDef;
+
+ MergeImportData *pImportData;
+ MergeImportData *pData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountModuleRefs();
+
+ // loop through all ModuleRef
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those ModuleRefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsModuleRefMarked(TokenFromRid(i, mdtModuleRef)) == false)
+ continue;
+
+ isModuleDef = false;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetModuleRefRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getNameOfModuleRef(pRecImport, &szNameImp));
+
+ // Only do the ModuleRef to ModuleDef optimization if ModuleRef's name is meaningful!
+ if ( szNameImp && szNameImp[0] != '\0')
+ {
+
+ // Check to see if this ModuleRef has become the ModuleDef token
+ for (pData = m_pImportDataList; pData != NULL; pData = pData->m_pNextImportData)
+ {
+ CMiniMdRW *pMiniMd = &(pData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ ModuleRec *pRec;
+ LPCUTF8 szName;
+
+ IfFailGo(pMiniMd->GetModuleRecord(MODULEDEFTOKEN, &pRec));
+ IfFailGo(pMiniMd->getNameOfModule(pRec, &szName));
+ if (szName && szName[0] != '\0' && strcmp(szNameImp, szName) == 0)
+ {
+ // We found an import Module for merging that has the same name as the ModuleRef
+ isModuleDef = true;
+ bDuplicate = true;
+ mrEmit = MODULEDEFTOKEN; // set the resulting token to ModuleDef Token
+ break;
+ }
+ }
+ }
+
+ if (isModuleDef == false)
+ {
+ // does this ModuleRef already exist in the emit scope?
+ hr = ImportHelper::FindModuleRef(pMiniMdEmit,
+ szNameImp,
+ &mrEmit);
+ if (hr == S_OK)
+ {
+ // Yes, it does
+ bDuplicate = true;
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ // No, it doesn't. Copy it over.
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pRecEmit, (RID*)&mrEmit));
+ mrEmit = TokenFromRid(mrEmit, mdtModuleRef);
+
+ // Set ModuleRef Name.
+ IfFailGo( pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name, pRecEmit, szNameImp) );
+ }
+ else
+ IfFailGo(hr);
+ }
+
+ // record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtModuleRef),
+ bDuplicate,
+ mrEmit,
+ &pTokenRec) );
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeModuleRefs()
+
+
+//*****************************************************************************
+// Merge AssemblyRef tables
+//*****************************************************************************
+HRESULT NEWMERGER::MergeAssemblyRefs()
+{
+ HRESULT hr = NOERROR;
+ AssemblyRefRec *pRecImport = NULL;
+ AssemblyRefRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ mdAssemblyRef arEmit;
+ bool bDuplicate = false;
+ LPCUTF8 szTmp;
+ const void *pbTmp;
+ ULONG cbTmp;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord;
+ TOKENREC *pTokenRec;
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountAssemblyRefs();
+
+ // loope through all the AssemblyRefs.
+ for (i = 1; i <= iCount; i++)
+ {
+ // Compare with the emit scope.
+ IfFailGo(pMiniMdImport->GetAssemblyRefRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getPublicKeyOrTokenOfAssemblyRef(pRecImport, (const BYTE **)&pbTmp, &cbTmp));
+ hr = CLDB_E_RECORD_NOTFOUND;
+ if (m_fDupCheck)
+ {
+ LPCSTR szAssemblyRefName;
+ LPCSTR szAssemblyRefLocale;
+ IfFailGo(pMiniMdImport->getNameOfAssemblyRef(pRecImport, &szAssemblyRefName));
+ IfFailGo(pMiniMdImport->getLocaleOfAssemblyRef(pRecImport, &szAssemblyRefLocale));
+ hr = ImportHelper::FindAssemblyRef(
+ pMiniMdEmit,
+ szAssemblyRefName,
+ szAssemblyRefLocale,
+ pbTmp,
+ cbTmp,
+ pRecImport->GetMajorVersion(),
+ pRecImport->GetMinorVersion(),
+ pRecImport->GetBuildNumber(),
+ pRecImport->GetRevisionNumber(),
+ pRecImport->GetFlags(),
+ &arEmit);
+ }
+ if (hr == S_OK)
+ {
+ // Yes, it does
+ bDuplicate = true;
+
+ // <TODO>@FUTURE: more verification?</TODO>
+ }
+ else if (hr == CLDB_E_RECORD_NOTFOUND)
+ {
+ // No, it doesn't. Copy it over.
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddAssemblyRefRecord(&pRecEmit, &iRecord));
+ arEmit = TokenFromRid(iRecord, mdtAssemblyRef);
+
+ pRecEmit->Copy(pRecImport);
+
+ IfFailGo(pMiniMdImport->getPublicKeyOrTokenOfAssemblyRef(pRecImport, (const BYTE **)&pbTmp, &cbTmp));
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_PublicKeyOrToken,
+ pRecEmit, pbTmp, cbTmp));
+
+ IfFailGo(pMiniMdImport->getNameOfAssemblyRef(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Name,
+ pRecEmit, szTmp));
+
+ IfFailGo(pMiniMdImport->getLocaleOfAssemblyRef(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_AssemblyRef, AssemblyRefRec::COL_Locale,
+ pRecEmit, szTmp));
+
+ IfFailGo(pMiniMdImport->getHashValueOfAssemblyRef(pRecImport, (const BYTE **)&pbTmp, &cbTmp));
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_AssemblyRef, AssemblyRefRec::COL_HashValue,
+ pRecEmit, pbTmp, cbTmp));
+
+ }
+ else
+ IfFailGo(hr);
+
+ // record the token movement.
+ IfFailGo(pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtAssemblyRef),
+ bDuplicate,
+ arEmit,
+ &pTokenRec));
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeAssemblyRefs()
+
+
+//*****************************************************************************
+// Merge TypeRef tables also performing TypeRef to TypeDef opitimization. ie.
+// we will not introduce a TypeRef record if we can optimize it to a TypeDef.
+//*****************************************************************************
+HRESULT NEWMERGER::MergeTypeRefs()
+{
+ HRESULT hr = NOERROR;
+ TypeRefRec *pRecImport = NULL;
+ TypeRefRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdTypeRef trEmit;
+ bool bDuplicate = false;
+ TOKENREC *pTokenRec;
+ bool isTypeDef;
+
+ mdToken tkResImp;
+ mdToken tkResEmit;
+ LPCUTF8 szNameImp;
+ LPCUTF8 szNamespaceImp;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountTypeRefs();
+
+ // loop through all TypeRef
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those TypeRefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsTypeRefMarked(TokenFromRid(i, mdtTypeRef)) == false)
+ continue;
+
+ isTypeDef = false;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetTypeRefRecord(i, &pRecImport));
+ tkResImp = pMiniMdImport->getResolutionScopeOfTypeRef(pRecImport);
+ IfFailGo(pMiniMdImport->getNamespaceOfTypeRef(pRecImport, &szNamespaceImp));
+ IfFailGo(pMiniMdImport->getNameOfTypeRef(pRecImport, &szNameImp));
+ if (!IsNilToken(tkResImp))
+ {
+ IfFailGo(pCurTkMap->Remap(tkResImp, &tkResEmit));
+ }
+ else
+ {
+ tkResEmit = tkResImp;
+ }
+
+ // There are some interesting cases to consider here.
+ // 1) If the TypeRef's ResolutionScope is a nil token, or is the MODULEDEFTOKEN (current module),
+ // then the TypeRef refers to a type in the current scope, so we should find a corresponding
+ // TypeDef in the output scope. If we find the TypeDef, we'll remap this TypeRef token
+ // to that TypeDef token.
+ // If we don't find that TypeDef, or if "TypeRef to TypeDef" optimization is turned off, we'll
+ // create the TypeRef in the output scope.
+ // 2) If the TypeRef's ResolutionScope has been resolved to a TypeDef, then this TypeRef was part
+ // of a nested type definition. In that case, we'd better find a corresponding TypeDef
+ // or we have an error.
+ if (IsNilToken(tkResEmit) || tkResEmit == MODULEDEFTOKEN || TypeFromToken(tkResEmit) == mdtTypeDef)
+ {
+ hr = ImportHelper::FindTypeDefByName(
+ pMiniMdEmit,
+ szNamespaceImp,
+ szNameImp,
+ (TypeFromToken(tkResEmit) == mdtTypeDef) ? tkResEmit : mdTokenNil,
+ &trEmit);
+ if (hr == S_OK)
+ {
+ isTypeDef = true;
+
+ // it really does not matter if we set the duplicate to true or false.
+ bDuplicate = true;
+ }
+ }
+
+ // If the ResolutionScope was merged as a TypeDef, and this token wasn't found as TypeDef, send the error.
+ if (TypeFromToken(tkResEmit) == mdtTypeDef && !isTypeDef)
+ {
+ // Send the error notification. Use the "continuable error" callback, but even if linker says it is
+ // ok, don't continue.
+ CheckContinuableErrorEx(META_E_TYPEDEF_MISSING, pImportData, TokenFromRid(i, mdtTypeRef));
+ IfFailGo(META_E_TYPEDEF_MISSING);
+ }
+
+ // If this TypeRef cannot be optmized to a TypeDef or the Ref to Def optimization is turned off, do the following.
+ if (!isTypeDef || !((m_optimizeRefToDef & MDTypeRefToDef) == MDTypeRefToDef))
+ {
+ // does this TypeRef already exist in the emit scope?
+ if ( m_fDupCheck && ImportHelper::FindTypeRefByName(
+ pMiniMdEmit,
+ tkResEmit,
+ szNamespaceImp,
+ szNameImp,
+ &trEmit) == S_OK )
+ {
+ // Yes, it does
+ bDuplicate = true;
+ }
+ else
+ {
+ // No, it doesn't. Copy it over.
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddTypeRefRecord(&pRecEmit, (RID*)&trEmit));
+ trEmit = TokenFromRid(trEmit, mdtTypeRef);
+
+ // Set ResolutionScope. tkResEmit has already been re-mapped.
+ IfFailGo(pMiniMdEmit->PutToken(TBL_TypeRef, TypeRefRec::COL_ResolutionScope,
+ pRecEmit, tkResEmit));
+
+ // Set Name.
+ IfFailGo(pMiniMdEmit->PutString(TBL_TypeRef, TypeRefRec::COL_Name,
+ pRecEmit, szNameImp));
+ IfFailGo(pMiniMdEmit->AddNamedItemToHash(TBL_TypeRef, trEmit, szNameImp, 0));
+
+ // Set Namespace.
+ IfFailGo(pMiniMdEmit->PutString(TBL_TypeRef, TypeRefRec::COL_Namespace,
+ pRecEmit, szNamespaceImp));
+ }
+ }
+
+ // record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtTypeRef),
+ bDuplicate,
+ trEmit,
+ &pTokenRec) );
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeTypeRefs()
+
+
+//*****************************************************************************
+// copy over the remaining information of partially merged TypeDef records. Right now only
+// extends field is delayed to here. The reason that we delay extends field is because we want
+// to optimize TypeRef to TypeDef if possible.
+//*****************************************************************************
+HRESULT NEWMERGER::CompleteMergeTypeDefs()
+{
+ HRESULT hr = NOERROR;
+ TypeDefRec *pRecImport = NULL;
+ TypeDefRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ TOKENREC *pTokenRec;
+ mdToken tkExtendsImp;
+ mdToken tkExtendsEmit;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ iCount = pMiniMdImport->getCountTypeDefs();
+
+ // Merge the typedefs
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those TypeDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsTypeDefMarked(TokenFromRid(i, mdtTypeDef)) == false)
+ continue;
+
+ if ( !pCurTkMap->Find(TokenFromRid(i, mdtTypeDef), &pTokenRec) )
+ {
+ _ASSERTE( !"bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+
+ if (pTokenRec->m_isDuplicate == false)
+ {
+ // get the extends token from the import
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(i, &pRecImport));
+ tkExtendsImp = pMiniMdImport->getExtendsOfTypeDef(pRecImport);
+
+ // map the extends token to an merged token
+ IfFailGo( pCurTkMap->Remap(tkExtendsImp, &tkExtendsEmit) );
+
+ // set the extends to the merged TypeDef records.
+ IfFailGo(pMiniMdEmit->GetTypeDefRecord(RidFromToken(pTokenRec->m_tkTo), &pRecEmit));
+ IfFailGo(pMiniMdEmit->PutToken(TBL_TypeDef, TypeDefRec::COL_Extends, pRecEmit, tkExtendsEmit));
+ }
+ else
+ {
+ // <TODO>@FUTURE: we can check to make sure the import extends maps to the one that is set to the emit scope.
+ // Otherwise, it is a error to report to linker.</TODO>
+ }
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CompleteMergeTypeDefs()
+
+
+//*****************************************************************************
+// merging TypeSpecs
+//*****************************************************************************
+HRESULT NEWMERGER::MergeTypeSpecs()
+{
+ HRESULT hr = NOERROR;
+ TypeSpecRec *pRecImport = NULL;
+ TypeSpecRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ TOKENREC *pTokenRec;
+ mdTypeSpec tsImp;
+ mdTypeSpec tsEmit;
+ bool fDuplicate;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ iCount = pMiniMdImport->getCountTypeSpecs();
+
+ // loop through all TypeSpec
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those TypeSpecs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsTypeSpecMarked(TokenFromRid(i, mdtTypeSpec)) == false)
+ continue;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetTypeSpecRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getSignatureOfTypeSpec(pRecImport, &pbSig, &cbSig));
+
+ // convert tokens contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInFieldSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly information.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ hr = CLDB_E_RECORD_NOTFOUND;
+ if (m_fDupCheck)
+ hr = ImportHelper::FindTypeSpec(
+ pMiniMdEmit,
+ (PCOR_SIGNATURE) qbSig.Ptr(),
+ cbEmit,
+ &tsEmit );
+
+ if ( hr == S_OK )
+ {
+ // find a duplicate
+ fDuplicate = true;
+ }
+ else
+ {
+ // copy over
+ fDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddTypeSpecRecord(&pRecEmit, (ULONG *)&tsEmit));
+ tsEmit = TokenFromRid(tsEmit, mdtTypeSpec);
+ IfFailGo( pMiniMdEmit->PutBlob(
+ TBL_TypeSpec,
+ TypeSpecRec::COL_Signature,
+ pRecEmit,
+ (PCOR_SIGNATURE)qbSig.Ptr(),
+ cbEmit));
+ }
+ tsImp = TokenFromRid(i, mdtTypeSpec);
+
+ // Record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(tsImp, fDuplicate, tsEmit, &pTokenRec) );
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeTypeSpecs()
+
+
+//*****************************************************************************
+// merging Children of TypeDefs. This includes field, method, parameter, property, event
+//*****************************************************************************
+HRESULT NEWMERGER::MergeTypeDefChildren()
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdTypeDef tdEmit;
+ mdTypeDef tdImport;
+ TOKENREC *pTokenRec;
+
+#if _DEBUG
+ TypeDefRec *pRecImport = NULL;
+ LPCUTF8 szNameImp;
+ LPCUTF8 szNamespaceImp;
+#endif // _DEBUG
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountTypeDefs();
+
+ // loop through all TypeDef again to merge/copy Methods, fields, events, and properties
+ //
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those TypeDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsTypeDefMarked(TokenFromRid(i, mdtTypeDef)) == false)
+ continue;
+
+#if _DEBUG
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getNameOfTypeDef(pRecImport, &szNameImp));
+ IfFailGo(pMiniMdImport->getNamespaceOfTypeDef(pRecImport, &szNamespaceImp));
+#endif // _DEBUG
+
+ // check to see if the typedef is duplicate or not
+ tdImport = TokenFromRid(i, mdtTypeDef);
+ if ( pCurTkMap->Find( tdImport, &pTokenRec) == false)
+ {
+ _ASSERTE( !"bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ tdEmit = pTokenRec->m_tkTo;
+ if (pTokenRec->m_isDuplicate == false)
+ {
+ // now move all of the children records over
+ IfFailGo( CopyMethods(pImportData, tdImport, tdEmit) );
+ IfFailGo( CopyFields(pImportData, tdImport, tdEmit) );
+
+ IfFailGo( CopyEvents(pImportData, tdImport, tdEmit) );
+
+ // Property has dependency on events
+ IfFailGo( CopyProperties(pImportData, tdImport, tdEmit) );
+
+ // Generic Params.
+ IfFailGo( CopyGenericParams(pImportData, tdImport, tdEmit) );
+ }
+ else
+ {
+ // verify the children records
+ IfFailGo( VerifyMethods(pImportData, tdImport, tdEmit) );
+ IfFailGo( VerifyFields(pImportData, tdImport, tdEmit) );
+ IfFailGo( VerifyEvents(pImportData, tdImport, tdEmit) );
+
+ // property has dependency on events
+ IfFailGo( VerifyProperties(pImportData, tdImport, tdEmit) );
+
+ IfFailGo( VerifyGenericParams(pImportData, tdImport, tdEmit) );
+ }
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeTypeDefChildren()
+
+
+//*******************************************************************************
+// Helper to copy an Method record
+//*******************************************************************************
+HRESULT NEWMERGER::CopyMethod(
+ MergeImportData *pImportData, // [IN] import scope
+ MethodRec *pRecImp, // [IN] the record to import
+ MethodRec *pRecEmit) // [IN] the emit record to fill
+{
+ HRESULT hr;
+ CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ MDTOKENMAP *pCurTkMap;
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // copy over the fix part of the record
+ pRecEmit->Copy(pRecImp);
+
+ // copy over the name
+ IfFailGo(pMiniMdImp->getNameOfMethod(pRecImp, &szName));
+ IfFailGo(pMiniMdEmit->PutString(TBL_Method, MethodRec::COL_Name, pRecEmit, szName));
+
+ // copy over the signature
+ IfFailGo(pMiniMdImp->getSignatureOfMethod(pRecImp, &pbSig, &cbSig));
+
+ // convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImp, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_Method, MethodRec::COL_Signature, pRecEmit, qbSig.Ptr(), cbEmit));
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyMethod()
+
+
+//*******************************************************************************
+// Helper to copy an field record
+//*******************************************************************************
+HRESULT NEWMERGER::CopyField(
+ MergeImportData *pImportData, // [IN] import scope
+ FieldRec *pRecImp, // [IN] the record to import
+ FieldRec *pRecEmit) // [IN] the emit record to fill
+{
+ HRESULT hr;
+ CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ MDTOKENMAP *pCurTkMap;
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // copy over the fix part of the record
+ pRecEmit->SetFlags(pRecImp->GetFlags());
+
+ // copy over the name
+ IfFailGo(pMiniMdImp->getNameOfField(pRecImp, &szName));
+ IfFailGo(pMiniMdEmit->PutString(TBL_Field, FieldRec::COL_Name, pRecEmit, szName));
+
+ // copy over the signature
+ IfFailGo(pMiniMdImp->getSignatureOfField(pRecImp, &pbSig, &cbSig));
+
+ // convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Emit assembly scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImp, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_Field, FieldRec::COL_Signature, pRecEmit, qbSig.Ptr(), cbEmit));
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyField()
+
+//*******************************************************************************
+// Helper to copy an field record
+//*******************************************************************************
+HRESULT NEWMERGER::CopyParam(
+ MergeImportData *pImportData, // [IN] import scope
+ ParamRec *pRecImp, // [IN] the record to import
+ ParamRec *pRecEmit) // [IN] the emit record to fill
+{
+ HRESULT hr;
+ CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ LPCUTF8 szName;
+ MDTOKENMAP *pCurTkMap;
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // copy over the fix part of the record
+ pRecEmit->Copy(pRecImp);
+
+ // copy over the name
+ IfFailGo(pMiniMdImp->getNameOfParam(pRecImp, &szName));
+ IfFailGo(pMiniMdEmit->PutString(TBL_Param, ParamRec::COL_Name, pRecEmit, szName));
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyParam()
+
+//*******************************************************************************
+// Helper to copy an Event record
+//*******************************************************************************
+HRESULT NEWMERGER::CopyEvent(
+ MergeImportData *pImportData, // [IN] import scope
+ EventRec *pRecImp, // [IN] the record to import
+ EventRec *pRecEmit) // [IN] the emit record to fill
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ mdToken tkEventTypeImp;
+ mdToken tkEventTypeEmit; // could be TypeDef or TypeRef
+ LPCUTF8 szName;
+ MDTOKENMAP *pCurTkMap;
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ pRecEmit->SetEventFlags(pRecImp->GetEventFlags());
+
+ //move over the event name
+ IfFailGo(pMiniMdImp->getNameOfEvent(pRecImp, &szName));
+ IfFailGo( pMiniMdEmit->PutString(TBL_Event, EventRec::COL_Name, pRecEmit, szName) );
+
+ // move over the EventType
+ tkEventTypeImp = pMiniMdImp->getEventTypeOfEvent(pRecImp);
+ if ( !IsNilToken(tkEventTypeImp) )
+ {
+ IfFailGo( pCurTkMap->Remap(tkEventTypeImp, &tkEventTypeEmit) );
+ IfFailGo(pMiniMdEmit->PutToken(TBL_Event, EventRec::COL_EventType, pRecEmit, tkEventTypeEmit));
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyEvent()
+
+
+//*******************************************************************************
+// Helper to copy a property record
+//*******************************************************************************
+HRESULT NEWMERGER::CopyProperty(
+ MergeImportData *pImportData, // [IN] import scope
+ PropertyRec *pRecImp, // [IN] the record to import
+ PropertyRec *pRecEmit) // [IN] the emit record to fill
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ MDTOKENMAP *pCurTkMap;
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // move over the flag value
+ pRecEmit->SetPropFlags(pRecImp->GetPropFlags());
+
+ //move over the property name
+ IfFailGo(pMiniMdImp->getNameOfProperty(pRecImp, &szName));
+ IfFailGo( pMiniMdEmit->PutString(TBL_Property, PropertyRec::COL_Name, pRecEmit, szName) );
+
+ // move over the type of the property
+ IfFailGo(pMiniMdImp->getTypeOfProperty(pRecImp, &pbSig, &cbSig));
+
+ // convert rid contained in signature to new scope
+ IfFailGo( ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImp, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit) ); // number of bytes write to cbEmit
+
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_Property, PropertyRec::COL_Type, pRecEmit, qbSig.Ptr(), cbEmit));
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyProperty()
+
+
+//*****************************************************************************
+// Copy MethodSemantics for an event or a property
+//*****************************************************************************
+HRESULT NEWMERGER::CopyMethodSemantics(
+ MergeImportData *pImportData,
+ mdToken tkImport, // Event or property in the import scope
+ mdToken tkEmit) // corresponding event or property in the emitting scope
+{
+ HRESULT hr = NOERROR;
+ MethodSemanticsRec *pRecImport = NULL;
+ MethodSemanticsRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ ULONG i;
+ ULONG msEmit; // MethodSemantics are just index not tokens
+ mdToken tkMethodImp;
+ mdToken tkMethodEmit;
+ MDTOKENMAP *pCurTkMap;
+ HENUMInternal hEnum;
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // copy over the associates
+ IfFailGo( pMiniMdImport->FindMethodSemanticsHelper(tkImport, &hEnum) );
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *) &i))
+ {
+ IfFailGo(pMiniMdImport->GetMethodSemanticsRecord(i, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddMethodSemanticsRecord(&pRecEmit, &msEmit));
+ pRecEmit->SetSemantic(pRecImport->GetSemantic());
+
+ // set the MethodSemantics
+ tkMethodImp = pMiniMdImport->getMethodOfMethodSemantics(pRecImport);
+ IfFailGo( pCurTkMap->Remap(tkMethodImp, &tkMethodEmit) );
+ IfFailGo( pMiniMdEmit->PutToken(TBL_MethodSemantics, MethodSemanticsRec::COL_Method, pRecEmit, tkMethodEmit));
+
+ // set the associate
+ _ASSERTE( pMiniMdImport->getAssociationOfMethodSemantics(pRecImport) == tkImport );
+ IfFailGo( pMiniMdEmit->PutToken(TBL_MethodSemantics, MethodSemanticsRec::COL_Association, pRecEmit, tkEmit));
+
+ // no need to record the movement since it is not a token
+ IfFailGo( pMiniMdEmit->AddMethodSemanticsToHash(msEmit) );
+ }
+ErrExit:
+ HENUMInternal::ClearEnum(&hEnum);
+ return hr;
+} // HRESULT NEWMERGER::CopyMethodSemantics()
+
+
+//*****************************************************************************
+// Copy Methods given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::CopyMethods(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ MethodRec *pRecImport = NULL;
+ MethodRec *pRecEmit = NULL;
+ TypeDefRec *pTypeDefRec;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG ridStart, ridEnd;
+ ULONG i;
+ mdMethodDef mdEmit;
+ mdMethodDef mdImp;
+ TOKENREC *pTokenRec;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(RidFromToken(tdImport), &pTypeDefRec));
+ ridStart = pMiniMdImport->getMethodListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMdImport->getEndMethodListOfTypeDef(RidFromToken(tdImport), &ridEnd));
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ // make sure we didn't count the methods yet
+ _ASSERTE(pMTD->m_cMethods == 0);
+
+ // loop through all Methods
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetMethodRid(i, (ULONG *)&mdImp));
+
+ // only merge those MethodDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsMethodMarked(TokenFromRid(mdImp, mdtMethodDef)) == false)
+ continue;
+
+ IfFailGo(pMiniMdImport->GetMethodRecord(mdImp, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddMethodRecord(&pRecEmit, (RID *)&mdEmit));
+
+ // copy the method content over
+ IfFailGo( CopyMethod(pImportData, pRecImport, pRecEmit) );
+
+ IfFailGo( pMiniMdEmit->AddMethodToTypeDef(RidFromToken(tdEmit), mdEmit));
+
+ // record the token movement
+ mdImp = TokenFromRid(mdImp, mdtMethodDef);
+ mdEmit = TokenFromRid(mdEmit, mdtMethodDef);
+ IfFailGo( pMiniMdEmit->AddMemberDefToHash(
+ mdEmit,
+ tdEmit) );
+
+ IfFailGo( pCurTkMap->InsertNotFound(mdImp, false, mdEmit, &pTokenRec) );
+
+ // copy over the children
+ IfFailGo( CopyParams(pImportData, mdImp, mdEmit) );
+ IfFailGo( CopyGenericParams(pImportData, mdImp, mdEmit) );
+
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ mdImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+
+ if (!bSuppressMergeCheck) {
+ pMTD->m_cMethods++;
+ }
+ }
+
+ // make sure we don't count any methods if merge check is suppressed on the type
+ _ASSERTE(pMTD->m_cMethods == 0 || !pMTD->m_bSuppressMergeCheck);
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyMethods()
+
+
+//*****************************************************************************
+// Copy Fields given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::CopyFields(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ FieldRec *pRecImport = NULL;
+ FieldRec *pRecEmit = NULL;
+ TypeDefRec *pTypeDefRec;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG ridStart, ridEnd;
+ ULONG i;
+ mdFieldDef fdEmit;
+ mdFieldDef fdImp;
+ bool bDuplicate;
+ TOKENREC *pTokenRec;
+ PCCOR_SIGNATURE pvSigBlob;
+ ULONG cbSigBlob;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(RidFromToken(tdImport), &pTypeDefRec));
+ ridStart = pMiniMdImport->getFieldListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMdImport->getEndFieldListOfTypeDef(RidFromToken(tdImport), &ridEnd));
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ // make sure we didn't count the methods yet
+ _ASSERTE(pMTD->m_cFields == 0);
+
+ // loop through all FieldDef of a TypeDef
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetFieldRid(i, (ULONG *)&fdImp));
+
+ // only merge those FieldDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(TokenFromRid(fdImp, mdtFieldDef)) == false)
+ continue;
+
+
+ IfFailGo(pMiniMdImport->GetFieldRecord(fdImp, &pRecImport));
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddFieldRecord(&pRecEmit, (RID *)&fdEmit));
+
+ // copy the field content over
+ IfFailGo( CopyField(pImportData, pRecImport, pRecEmit) );
+
+ IfFailGo( pMiniMdEmit->AddFieldToTypeDef(RidFromToken(tdEmit), fdEmit));
+
+ // record the token movement
+ fdImp = TokenFromRid(fdImp, mdtFieldDef);
+ fdEmit = TokenFromRid(fdEmit, mdtFieldDef);
+ IfFailGo(pMiniMdEmit->getSignatureOfField(pRecEmit, &pvSigBlob, &cbSigBlob));
+ IfFailGo( pMiniMdEmit->AddMemberDefToHash(
+ fdEmit,
+ tdEmit) );
+
+ IfFailGo( pCurTkMap->InsertNotFound(fdImp, false, fdEmit, &pTokenRec) );
+
+ // count the number of fields that didn't suppress merge check
+ // non-static fields doesn't inherite the suppress merge check attribute from the type
+ bSuppressMergeCheck =
+ (IsFdStatic(pRecEmit->GetFlags()) && pMTD->m_bSuppressMergeCheck) ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ fdImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck) {
+ pMTD->m_cFields++;
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyFields()
+
+
+//*****************************************************************************
+// Copy Events given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::CopyEvents(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ RID ridEventMap;
+ EventMapRec *pEventMapRec;
+ EventRec *pRecImport;
+ EventRec *pRecEmit;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+ mdEvent evImp;
+ mdEvent evEmit;
+ TOKENREC *pTokenRec;
+ ULONG iEventMap;
+ EventMapRec *pEventMap;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ mdCustomAttribute tkCA;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ // make sure we didn't count the events yet
+ _ASSERTE(pMTD->m_cEvents == 0);
+
+ IfFailGo(pMiniMdImport->FindEventMapFor(RidFromToken(tdImport), &ridEventMap));
+ if (!InvalidRid(ridEventMap))
+ {
+ IfFailGo(pMiniMdImport->GetEventMapRecord(ridEventMap, &pEventMapRec));
+ ridStart = pMiniMdImport->getEventListOfEventMap(pEventMapRec);
+ IfFailGo(pMiniMdImport->getEndEventListOfEventMap(ridEventMap, &ridEnd));
+
+ if (ridEnd > ridStart)
+ {
+ // If there is any event, create the eventmap record in the emit scope
+ // Create new record.
+ IfFailGo(pMiniMdEmit->AddEventMapRecord(&pEventMap, &iEventMap));
+
+ // Set parent.
+ IfFailGo(pMiniMdEmit->PutToken(TBL_EventMap, EventMapRec::COL_Parent, pEventMap, tdEmit));
+ }
+
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // get the real event rid
+ IfFailGo(pMiniMdImport->GetEventRid(i, (ULONG *)&evImp));
+
+ // only merge those Events that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsEventMarked(TokenFromRid(evImp, mdtEvent)) == false)
+ continue;
+
+ IfFailGo(pMiniMdImport->GetEventRecord(evImp, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddEventRecord(&pRecEmit, (RID *)&evEmit));
+
+ // copy the event record over
+ IfFailGo( CopyEvent(pImportData, pRecImport, pRecEmit) );
+
+ // Add Event to the EventMap.
+ IfFailGo( pMiniMdEmit->AddEventToEventMap(iEventMap, evEmit) );
+
+ // record the token movement
+ evImp = TokenFromRid(evImp, mdtEvent);
+ evEmit = TokenFromRid(evEmit, mdtEvent);
+
+ IfFailGo( pCurTkMap->InsertNotFound(evImp, false, evEmit, &pTokenRec) );
+
+ // copy over the method semantics
+ IfFailGo( CopyMethodSemantics(pImportData, evImp, evEmit) );
+
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ evImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck) {
+ pMTD->m_cEvents++;
+ }
+ }
+ }
+
+ // make sure we don't count any events if merge check is suppressed on the type
+ _ASSERTE(pMTD->m_cEvents == 0 || !pMTD->m_bSuppressMergeCheck);
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyEvents()
+
+
+//*****************************************************************************
+// Copy Properties given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::CopyProperties(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ RID ridPropertyMap;
+ PropertyMapRec *pPropertyMapRec;
+ PropertyRec *pRecImport;
+ PropertyRec *pRecEmit;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+ mdProperty prImp;
+ mdProperty prEmit;
+ TOKENREC *pTokenRec;
+ ULONG iPropertyMap;
+ PropertyMapRec *pPropertyMap;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ mdCustomAttribute tkCA;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ // make sure we didn't count the properties yet
+ _ASSERTE(pMTD->m_cProperties == 0);
+
+ IfFailGo(pMiniMdImport->FindPropertyMapFor(RidFromToken(tdImport), &ridPropertyMap));
+ if (!InvalidRid(ridPropertyMap))
+ {
+ IfFailGo(pMiniMdImport->GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec));
+ ridStart = pMiniMdImport->getPropertyListOfPropertyMap(pPropertyMapRec);
+ IfFailGo(pMiniMdImport->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd));
+
+ if (ridEnd > ridStart)
+ {
+ // If there is any event, create the PropertyMap record in the emit scope
+ // Create new record.
+ IfFailGo(pMiniMdEmit->AddPropertyMapRecord(&pPropertyMap, &iPropertyMap));
+
+ // Set parent.
+ IfFailGo(pMiniMdEmit->PutToken(TBL_PropertyMap, PropertyMapRec::COL_Parent, pPropertyMap, tdEmit));
+ }
+
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // get the property rid
+ IfFailGo(pMiniMdImport->GetPropertyRid(i, (ULONG *)&prImp));
+
+ // only merge those Properties that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsPropertyMarked(TokenFromRid(prImp, mdtProperty)) == false)
+ continue;
+
+
+ IfFailGo(pMiniMdImport->GetPropertyRecord(prImp, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddPropertyRecord(&pRecEmit, (RID *)&prEmit));
+
+ // copy the property record over
+ IfFailGo( CopyProperty(pImportData, pRecImport, pRecEmit) );
+
+ // Add Property to the PropertyMap.
+ IfFailGo( pMiniMdEmit->AddPropertyToPropertyMap(iPropertyMap, prEmit) );
+
+ // record the token movement
+ prImp = TokenFromRid(prImp, mdtProperty);
+ prEmit = TokenFromRid(prEmit, mdtProperty);
+
+ IfFailGo( pCurTkMap->InsertNotFound(prImp, false, prEmit, &pTokenRec) );
+
+ // copy over the method semantics
+ IfFailGo( CopyMethodSemantics(pImportData, prImp, prEmit) );
+
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ prImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (!bSuppressMergeCheck) {
+ pMTD->m_cProperties++;
+ }
+ }
+ }
+
+ // make sure we don't count any properties if merge check is suppressed on the type
+ _ASSERTE(pMTD->m_cProperties == 0 || !pMTD->m_bSuppressMergeCheck);
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyProperties()
+
+
+//*****************************************************************************
+// Copy Parameters given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::CopyParams(
+ MergeImportData *pImportData,
+ mdMethodDef mdImport,
+ mdMethodDef mdEmit)
+{
+ HRESULT hr = NOERROR;
+ ParamRec *pRecImport = NULL;
+ ParamRec *pRecEmit = NULL;
+ MethodRec *pMethodRec;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG ridStart, ridEnd;
+ ULONG i;
+ mdParamDef pdEmit;
+ mdParamDef pdImp;
+ TOKENREC *pTokenRec;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+
+ IfFailGo(pMiniMdImport->GetMethodRecord(RidFromToken(mdImport), &pMethodRec));
+ ridStart = pMiniMdImport->getParamListOfMethod(pMethodRec);
+ IfFailGo(pMiniMdImport->getEndParamListOfMethod(RidFromToken(mdImport), &ridEnd));
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // loop through all InterfaceImpl
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // Get the param rid
+ IfFailGo(pMiniMdImport->GetParamRid(i, (ULONG *)&pdImp));
+
+ // only merge those Params that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsParamMarked(TokenFromRid(pdImp, mdtParamDef)) == false)
+ continue;
+
+
+ IfFailGo(pMiniMdImport->GetParamRecord(pdImp, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddParamRecord(&pRecEmit, (RID *)&pdEmit));
+
+ // copy the Parameter record over
+ IfFailGo( CopyParam(pImportData, pRecImport, pRecEmit) );
+
+ // warning!! warning!!
+ // We cannot add paramRec to method list until it is fully set.
+ // AddParamToMethod will use the ulSequence in the record
+ IfFailGo( pMiniMdEmit->AddParamToMethod(RidFromToken(mdEmit), pdEmit));
+
+ // record the token movement
+ pdImp = TokenFromRid(pdImp, mdtParamDef);
+ pdEmit = TokenFromRid(pdEmit, mdtParamDef);
+
+ IfFailGo( pCurTkMap->InsertNotFound(pdImp, false, pdEmit, &pTokenRec) );
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyParams()
+
+
+//*****************************************************************************
+// Copy GenericParams given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::CopyGenericParams(
+ MergeImportData *pImportData,
+ mdToken tkImport,
+ mdToken tkEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ TOKENREC *pTokenRec;
+ GenericParamRec *pRecImport = NULL;
+ GenericParamRec *pRecEmit = NULL;
+ MDTOKENMAP *pCurTkMap;
+ HENUMInternal hEnum;
+ mdGenericParam gpImport;
+ mdGenericParam gpEmit;
+ LPCSTR szGenericParamName;
+
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pMiniMdEmit = GetMiniMdEmit();
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ IfFailGo( pMiniMdImport->FindGenericParamHelper(tkImport, &hEnum) );
+
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *) &gpImport))
+ {
+ // Get the import GenericParam record
+ _ASSERTE(TypeFromToken(gpImport) == mdtGenericParam);
+ IfFailGo(pMiniMdImport->GetGenericParamRecord(RidFromToken(gpImport), &pRecImport));
+
+ // Create new emit record.
+ IfFailGo(pMiniMdEmit->AddGenericParamRecord(&pRecEmit, (RID *)&gpEmit));
+
+ // copy the GenericParam content
+ pRecEmit->SetNumber( pRecImport->GetNumber());
+ pRecEmit->SetFlags( pRecImport->GetFlags());
+
+ IfFailGo( pMiniMdEmit->PutToken(TBL_GenericParam, GenericParamRec::COL_Owner, pRecEmit, tkEmit));
+
+ IfFailGo(pMiniMdImport->getNameOfGenericParam(pRecImport, &szGenericParamName));
+ IfFailGo( pMiniMdEmit->PutString(TBL_GenericParam, GenericParamRec::COL_Name, pRecEmit, szGenericParamName));
+
+ // record the token movement
+ gpImport = TokenFromRid(gpImport, mdtGenericParam);
+ gpEmit = TokenFromRid(gpEmit, mdtGenericParam);
+
+ IfFailGo( pCurTkMap->InsertNotFound(gpImport, false, gpEmit, &pTokenRec) );
+
+ // copy over any constraints
+ IfFailGo( CopyGenericParamConstraints(pImportData, gpImport, gpEmit) );
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyGenericParams()
+
+
+//*****************************************************************************
+// Copy GenericParamConstraints given a GenericParam
+//*****************************************************************************
+HRESULT NEWMERGER::CopyGenericParamConstraints(
+ MergeImportData *pImportData,
+ mdGenericParamConstraint tkImport,
+ mdGenericParamConstraint tkEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ TOKENREC *pTokenRec;
+ GenericParamConstraintRec *pRecImport = NULL;
+ GenericParamConstraintRec *pRecEmit = NULL;
+ MDTOKENMAP *pCurTkMap;
+ HENUMInternal hEnum;
+ mdGenericParamConstraint gpImport;
+ mdGenericParamConstraint gpEmit;
+ mdToken tkConstraint;
+
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pMiniMdEmit = GetMiniMdEmit();
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ IfFailGo( pMiniMdImport->FindGenericParamConstraintHelper(tkImport, &hEnum) );
+
+ while (HENUMInternal::EnumNext(&hEnum, (mdToken *) &gpImport))
+ {
+ // Get the import GenericParam record
+ _ASSERTE(TypeFromToken(gpImport) == mdtGenericParamConstraint);
+ IfFailGo(pMiniMdImport->GetGenericParamConstraintRecord(RidFromToken(gpImport), &pRecImport));
+
+ // Translate the constraint before creating new record.
+ tkConstraint = pMiniMdImport->getConstraintOfGenericParamConstraint(pRecImport);
+ if (pCurTkMap->Find(tkConstraint, &pTokenRec) == false)
+ {
+ // This should never fire unless the TypeDefs/Refs weren't merged
+ // before this code runs.
+ _ASSERTE(!"GenericParamConstraint Constraint not found in MERGER::CopyGenericParamConstraints. Bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ tkConstraint = pTokenRec->m_tkTo;
+
+ // Create new emit record.
+ IfFailGo(pMiniMdEmit->AddGenericParamConstraintRecord(&pRecEmit, (RID *)&gpEmit));
+
+ // copy the GenericParamConstraint content
+ IfFailGo( pMiniMdEmit->PutToken(TBL_GenericParamConstraint, GenericParamConstraintRec::COL_Owner, pRecEmit, tkEmit));
+
+ IfFailGo( pMiniMdEmit->PutToken(TBL_GenericParamConstraint, GenericParamConstraintRec::COL_Constraint, pRecEmit, tkConstraint));
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyGenericParamConstraints()
+
+
+//*****************************************************************************
+// Verify GenericParams given a TypeDef
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyGenericParams(
+ MergeImportData *pImportData,
+ mdToken tkImport,
+ mdToken tkEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ TOKENREC *pTokenRec;
+ MDTOKENMAP *pCurTkMap;
+ HENUMInternal hEnumImport; // Enumerator for import scope.
+ HENUMInternal hEnumEmit; // Enumerator for emit scope.
+ ULONG cImport, cEmit; // Count of import & emit records.
+ ULONG i; // Enumerating records in import scope.
+ ULONG iEmit; // Tracking records in emit scope.
+ mdGenericParam gpImport; // Import scope GenericParam token.
+ mdGenericParam gpEmit; // Emit scope GenericParam token.
+ GenericParamRec *pRecImport = NULL;
+ GenericParamRec *pRecEmit = NULL;
+ LPCSTR szNameImport; // Name of param in import scope.
+ LPCSTR szNameEmit; // Name of param in emit scope.
+
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pMiniMdEmit = GetMiniMdEmit();
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // Get enumerators for the input and output scopes.
+ IfFailGo(pMiniMdImport->FindGenericParamHelper(tkImport, &hEnumImport));
+ IfFailGo(pMiniMdEmit->FindGenericParamHelper(tkEmit, &hEnumEmit));
+
+ // The counts should be the same.
+ IfFailGo(HENUMInternal::GetCount(&hEnumImport, &cImport));
+ IfFailGo(HENUMInternal::GetCount(&hEnumEmit, &cEmit));
+
+ if (cImport != cEmit)
+ {
+ CheckContinuableErrorEx(META_E_GENERICPARAM_INCONSISTENT, pImportData, tkImport);
+ // If we are here, the linker says this error is OK.
+ }
+
+ for (i=iEmit=0; i<cImport; ++i)
+ {
+ // Get the import GenericParam record
+ IfFailGo(HENUMInternal::GetElement(&hEnumImport, i, &gpImport));
+ _ASSERTE(TypeFromToken(gpImport) == mdtGenericParam);
+ IfFailGo(pMiniMdImport->GetGenericParamRecord(RidFromToken(gpImport), &pRecImport));
+
+ // Find the emit record. If the import and emit scopes are ordered the same
+ // this is easy; otherwise go looking for it.
+ // Get the "next" emit record.
+ if (iEmit < cEmit)
+ {
+ IfFailGo(HENUMInternal::GetElement(&hEnumEmit, iEmit, &gpEmit));
+ _ASSERTE(TypeFromToken(gpEmit) == mdtGenericParam);
+ IfFailGo(pMiniMdEmit->GetGenericParamRecord(RidFromToken(gpEmit), &pRecEmit));
+ }
+
+ // If the import and emit sequence numbers don't match, go looking.
+ // Also, if we would have walked off end of array, go looking.
+ if (iEmit >= cEmit || pRecImport->GetNumber() != pRecEmit->GetNumber())
+ {
+ for (iEmit=0; iEmit<cEmit; ++iEmit)
+ {
+ IfFailGo( HENUMInternal::GetElement(&hEnumEmit, iEmit, &gpEmit));
+ _ASSERTE(TypeFromToken(gpEmit) == mdtGenericParam);
+ IfFailGo(pMiniMdEmit->GetGenericParamRecord(RidFromToken(gpEmit), &pRecEmit));
+
+ // The one we want?
+ if (pRecImport->GetNumber() == pRecEmit->GetNumber())
+ break;
+ }
+ if (iEmit >= cEmit)
+ goto Error; // Didn't find it
+ }
+
+ // Check that these "n'th" GenericParam records match.
+
+ // Flags.
+ if (pRecImport->GetFlags() != pRecEmit->GetFlags())
+ goto Error;
+
+ // Name.
+ IfFailGo(pMiniMdImport->getNameOfGenericParam(pRecImport, &szNameImport));
+ IfFailGo(pMiniMdEmit->getNameOfGenericParam(pRecEmit, &szNameEmit));
+ if (strcmp(szNameImport, szNameEmit) != 0)
+ goto Error;
+
+ // Verify any constraints.
+ gpImport = TokenFromRid(gpImport, mdtGenericParam);
+ gpEmit = TokenFromRid(gpEmit, mdtGenericParam);
+ hr = VerifyGenericParamConstraints(pImportData, gpImport, gpEmit);
+
+ if (SUCCEEDED(hr))
+ {
+ // record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(gpImport, true, gpEmit, &pTokenRec) );
+ }
+ else
+ {
+Error:
+ // inconsistent in GenericParams
+ hr = S_OK; // discard old error; new error will be returned from CheckContinuableError
+ CheckContinuableErrorEx(META_E_GENERICPARAM_INCONSISTENT, pImportData, tkImport);
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyGenericParams()
+
+
+//*****************************************************************************
+// Verify GenericParamConstraints given a GenericParam
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyGenericParamConstraints(
+ MergeImportData *pImportData, // The import scope.
+ mdGenericParam gpImport, // Import GenericParam.
+ mdGenericParam gpEmit) // Emit GenericParam.
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ TOKENREC *pTokenRec;
+ HENUMInternal hEnumImport; // Enumerator for import scope.
+ HENUMInternal hEnumEmit; // Enumerator for emit scope.
+ ULONG cImport, cEmit; // Count of import & emit records.
+ ULONG i; // Enumerating records in import scope.
+ ULONG iEmit; // Tracking records in emit scope.
+ GenericParamConstraintRec *pRecImport = NULL;
+ GenericParamConstraintRec *pRecEmit = NULL;
+ MDTOKENMAP *pCurTkMap;
+ mdToken tkConstraintImport = mdTokenNil;
+ mdToken tkConstraintEmit = mdTokenNil;
+
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pMiniMdEmit = GetMiniMdEmit();
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // Get enumerators for the input and output scopes.
+ IfFailGo(pMiniMdImport->FindGenericParamConstraintHelper(gpImport, &hEnumImport));
+ IfFailGo(pMiniMdEmit->FindGenericParamConstraintHelper(gpEmit, &hEnumEmit));
+
+ // The counts should be the same.
+ IfFailGo(HENUMInternal::GetCount(&hEnumImport, &cImport));
+ IfFailGo(HENUMInternal::GetCount(&hEnumEmit, &cEmit));
+
+ if (cImport != cEmit)
+ IfFailGo(META_E_GENERICPARAM_INCONSISTENT); // Different numbers of constraints.
+
+ for (i=iEmit=0; i<cImport; ++i)
+ {
+ // Get the import GenericParam record
+ IfFailGo( HENUMInternal::GetElement(&hEnumImport, i, &gpImport));
+ _ASSERTE(TypeFromToken(gpImport) == mdtGenericParamConstraint);
+ IfFailGo(pMiniMdImport->GetGenericParamConstraintRecord(RidFromToken(gpImport), &pRecImport));
+
+ // Get the constraint.
+ tkConstraintImport = pMiniMdImport->getConstraintOfGenericParamConstraint(pRecImport);
+ if (pCurTkMap->Find(tkConstraintImport, &pTokenRec) == false)
+ {
+ // This should never fire unless the TypeDefs/Refs weren't merged
+ // before this code runs.
+ _ASSERTE(!"GenericParamConstraint Constraint not found in MERGER::VerifyGenericParamConstraints. Bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ tkConstraintImport = pTokenRec->m_tkTo;
+
+ // Find the emit record. If the import and emit scopes are ordered the same
+ // this is easy; otherwise go looking for it.
+ // Get the "next" emit record.
+ if (iEmit < cEmit)
+ {
+ IfFailGo( HENUMInternal::GetElement(&hEnumEmit, iEmit, &gpEmit));
+ _ASSERTE(TypeFromToken(gpEmit) == mdtGenericParamConstraint);
+ IfFailGo(pMiniMdEmit->GetGenericParamConstraintRecord(RidFromToken(gpEmit), &pRecEmit));
+ tkConstraintEmit = pMiniMdEmit->getConstraintOfGenericParamConstraint(pRecEmit);
+ }
+
+ // If the import and emit constraints don't match, go looking.
+ if (iEmit >= cEmit || tkConstraintEmit != tkConstraintImport)
+ {
+ for (iEmit=0; iEmit<cEmit; ++iEmit)
+ {
+ IfFailGo( HENUMInternal::GetElement(&hEnumEmit, iEmit, &gpEmit));
+ _ASSERTE(TypeFromToken(gpEmit) == mdtGenericParamConstraint);
+ IfFailGo(pMiniMdEmit->GetGenericParamConstraintRecord(RidFromToken(gpEmit), &pRecEmit));
+ tkConstraintEmit = pMiniMdEmit->getConstraintOfGenericParamConstraint(pRecEmit);
+
+ // The one we want?
+ if (tkConstraintEmit == tkConstraintImport)
+ break;
+ }
+ if (iEmit >= cEmit)
+ {
+ IfFailGo(META_E_GENERICPARAM_INCONSISTENT); // Didn't find the constraint
+ }
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyGenericParamConstraints()
+
+
+//*****************************************************************************
+// Verify Methods
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyMethods(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ MethodRec *pRecImp;
+ MethodRec *pRecEmit;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+
+ TypeDefRec *pTypeDefRec;
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ TOKENREC *pTokenRec;
+ mdMethodDef mdImp;
+ mdMethodDef mdEmit;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ ULONG cImport = 0; // count of non-merge check suppressed methods
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // Get a count of records in the import scope; prepare to enumerate them.
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(RidFromToken(tdImport), &pTypeDefRec));
+ ridStart = pMiniMdImport->getMethodListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMdImport->getEndMethodListOfTypeDef(RidFromToken(tdImport), &ridEnd));
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ // loop through all Methods of the TypeDef
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ IfFailGo(pMiniMdImport->GetMethodRid(i, (ULONG *)&mdImp));
+
+ // only verify those Methods that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsMethodMarked(TokenFromRid(mdImp, mdtMethodDef)) == false)
+ continue;
+
+ IfFailGo(pMiniMdImport->GetMethodRecord(mdImp, &pRecImp));
+
+ if (m_fDupCheck == FALSE && tdImport == pImportData->m_pRegMetaImport->m_tdModule) // TokenFromRid(1, mdtTypeDef))
+ {
+ // No dup check. This is the scenario that we only have one import scope. Just copy over the
+ // globals.
+ goto CopyMethodLabel;
+ }
+
+ IfFailGo(pMiniMdImport->getNameOfMethod(pRecImp, &szName));
+ IfFailGo(pMiniMdImport->getSignatureOfMethod(pRecImp, &pbSig, &cbSig));
+
+ mdImp = TokenFromRid(mdImp, mdtMethodDef);
+
+ if ( IsMdPrivateScope( pRecImp->GetFlags() ) )
+ {
+ // Trigger additive merge
+ goto CopyMethodLabel;
+ }
+
+ // convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ hr = ImportHelper::FindMethod(
+ pMiniMdEmit,
+ tdEmit,
+ szName,
+ (const COR_SIGNATURE *)qbSig.Ptr(),
+ cbEmit,
+ &mdEmit);
+
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ mdImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (bSuppressMergeCheck || (tdImport == pImportData->m_pRegMetaImport->m_tdModule))
+ {
+ // global functions! Make sure that we move over the non-duplicate global function
+ // declaration
+ //
+ if (hr == S_OK)
+ {
+ // found the duplicate
+ IfFailGo( VerifyMethod(pImportData, mdImp, mdEmit) );
+ }
+ else
+ {
+CopyMethodLabel:
+ // not a duplicate! Copy over the
+ IfFailGo(pMiniMdEmit->AddMethodRecord(&pRecEmit, (RID *)&mdEmit));
+
+ // copy the method content over
+ IfFailGo( CopyMethod(pImportData, pRecImp, pRecEmit) );
+
+ IfFailGo( pMiniMdEmit->AddMethodToTypeDef(RidFromToken(tdEmit), mdEmit));
+
+ // record the token movement
+ mdEmit = TokenFromRid(mdEmit, mdtMethodDef);
+ IfFailGo( pMiniMdEmit->AddMemberDefToHash(
+ mdEmit,
+ tdEmit) );
+
+ mdImp = TokenFromRid(mdImp, mdtMethodDef);
+ IfFailGo( pCurTkMap->InsertNotFound(mdImp, false, mdEmit, &pTokenRec) );
+
+ // copy over the children
+ IfFailGo( CopyParams(pImportData, mdImp, mdEmit) );
+ IfFailGo( CopyGenericParams(pImportData, mdImp, mdEmit) );
+
+ }
+ }
+ else
+ {
+ if (hr == S_OK)
+ {
+ // Good! We are supposed to find a duplicate
+ IfFailGo( VerifyMethod(pImportData, mdImp, mdEmit) );
+ }
+ else
+ {
+ // Oops! The typedef is duplicated but the method is not!!
+ hr = S_OK; // discard old error; new error will be returned from CheckContinuableError
+ CheckContinuableErrorEx(META_E_METHD_NOT_FOUND, pImportData, mdImp);
+ }
+
+ cImport++;
+ }
+ }
+
+ // The counts should be the same, unless this is <module>
+ if (cImport != pMTD->m_cMethods && tdImport != pImportData->m_pRegMetaImport->m_tdModule)
+ {
+ CheckContinuableErrorEx(META_E_METHOD_COUNTS, pImportData, tdImport);
+ // If we are here, the linker says this error is OK.
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyMethods()
+
+
+//*****************************************************************************
+// verify a duplicated method
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyMethod(
+ MergeImportData *pImportData,
+ mdMethodDef mdImp, // [IN] the emit record to fill
+ mdMethodDef mdEmit) // [IN] the record to import
+{
+ HRESULT hr;
+ MethodRec *pRecImp;
+ MethodRec *pRecEmit;
+ TOKENREC *pTokenRec;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ IfFailGo( pCurTkMap->InsertNotFound(mdImp, true, mdEmit, &pTokenRec) );
+
+ IfFailGo(pMiniMdImport->GetMethodRecord(RidFromToken(mdImp), &pRecImp));
+
+ // We need to make sure that the impl flags are propagated .
+ // Rules are: if the first method has miForwardRef flag set but the new method does not,
+ // we want to disable the miForwardRef flag. If the one found in the emit scope does not have
+ // miForwardRef set and the second one doesn't either, we want to make sure that the rest of
+ // impl flags are the same.
+ //
+ if ( !IsMiForwardRef( pRecImp->GetImplFlags() ) )
+ {
+ IfFailGo(pMiniMdEmit->GetMethodRecord(RidFromToken(mdEmit), &pRecEmit));
+ if (!IsMiForwardRef(pRecEmit->GetImplFlags()))
+ {
+ // make sure the rest of ImplFlags are the same
+ if (pRecEmit->GetImplFlags() != pRecImp->GetImplFlags())
+ {
+ // inconsistent in implflags
+ CheckContinuableErrorEx(META_E_METHDIMPL_INCONSISTENT, pImportData, mdImp);
+ }
+ }
+ else
+ {
+ // propagate the importing ImplFlags
+ pRecEmit->SetImplFlags(pRecImp->GetImplFlags());
+ }
+ }
+
+ // verify the children
+ IfFailGo( VerifyParams(pImportData, mdImp, mdEmit) );
+ IfFailGo( VerifyGenericParams(pImportData, mdImp, mdEmit) );
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyMethod()
+
+
+//*****************************************************************************
+// Verify Fields
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyFields(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ FieldRec *pRecImp;
+ FieldRec *pRecEmit;
+ mdFieldDef fdImp;
+ mdFieldDef fdEmit;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+
+ TypeDefRec *pTypeDefRec;
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ TOKENREC *pTokenRec;
+ MDTOKENMAP *pCurTkMap;
+
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ ULONG cImport = 0; // count of non-merge check suppressed fields
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // Get a count of records in the import scope; prepare to enumerate them.
+ IfFailGo(pMiniMdImport->GetTypeDefRecord(RidFromToken(tdImport), &pTypeDefRec));
+ ridStart = pMiniMdImport->getFieldListOfTypeDef(pTypeDefRec);
+ IfFailGo(pMiniMdImport->getEndFieldListOfTypeDef(RidFromToken(tdImport), &ridEnd));
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ // loop through all fields of the TypeDef
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ IfFailGo(pMiniMdImport->GetFieldRid(i, (ULONG *)&fdImp));
+
+ // only verify those fields that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(TokenFromRid(fdImp, mdtFieldDef)) == false)
+ continue;
+
+ IfFailGo(pMiniMdImport->GetFieldRecord(fdImp, &pRecImp));
+
+ if (m_fDupCheck == FALSE && tdImport == pImportData->m_pRegMetaImport->m_tdModule)
+ {
+ // No dup check. This is the scenario that we only have one import scope. Just copy over the
+ // globals.
+ goto CopyFieldLabel;
+ }
+
+ IfFailGo(pMiniMdImport->getNameOfField(pRecImp, &szName));
+ IfFailGo(pMiniMdImport->getSignatureOfField(pRecImp, &pbSig, &cbSig));
+
+ if ( IsFdPrivateScope(pRecImp->GetFlags()))
+ {
+ // Trigger additive merge
+ fdImp = TokenFromRid(fdImp, mdtFieldDef);
+ goto CopyFieldLabel;
+ }
+
+ // convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ hr = ImportHelper::FindField(
+ pMiniMdEmit,
+ tdEmit,
+ szName,
+ (const COR_SIGNATURE *)qbSig.Ptr(),
+ cbEmit,
+ &fdEmit);
+
+ fdImp = TokenFromRid(fdImp, mdtFieldDef);
+
+ bSuppressMergeCheck =
+ (IsFdStatic(pRecImp->GetFlags()) && pMTD->m_bSuppressMergeCheck) ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ fdImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (bSuppressMergeCheck || (tdImport == pImportData->m_pRegMetaImport->m_tdModule))
+ {
+ // global data! Make sure that we move over the non-duplicate global function
+ // declaration
+ //
+ if (hr == S_OK)
+ {
+ // found the duplicate
+ IfFailGo( pCurTkMap->InsertNotFound(fdImp, true, fdEmit, &pTokenRec) );
+ }
+ else
+ {
+CopyFieldLabel:
+ // not a duplicate! Copy over the
+ IfFailGo(pMiniMdEmit->AddFieldRecord(&pRecEmit, (RID *)&fdEmit));
+
+ // copy the field record over
+ IfFailGo( CopyField(pImportData, pRecImp, pRecEmit) );
+
+ IfFailGo( pMiniMdEmit->AddFieldToTypeDef(RidFromToken(tdEmit), fdEmit));
+
+ // record the token movement
+ fdEmit = TokenFromRid(fdEmit, mdtFieldDef);
+ IfFailGo( pMiniMdEmit->AddMemberDefToHash(
+ fdEmit,
+ tdEmit) );
+
+ fdImp = TokenFromRid(fdImp, mdtFieldDef);
+ IfFailGo( pCurTkMap->InsertNotFound(fdImp, false, fdEmit, &pTokenRec) );
+ }
+ }
+ else
+ {
+ if (hr == S_OK)
+ {
+ // Good! We are supposed to find a duplicate
+ IfFailGo( pCurTkMap->InsertNotFound(fdImp, true, fdEmit, &pTokenRec) );
+ }
+ else
+ {
+ // Oops! The typedef is duplicated but the field is not!!
+ hr = S_OK; // discard old error; new error will be returned from CheckContinuableError
+ CheckContinuableErrorEx(META_E_FIELD_NOT_FOUND, pImportData, fdImp);
+ }
+
+ cImport++;
+ }
+ }
+
+ // The counts should be the same, unless this is <module>
+ if (cImport != pMTD->m_cFields && tdImport != pImportData->m_pRegMetaImport->m_tdModule)
+ {
+ CheckContinuableErrorEx(META_E_FIELD_COUNTS, pImportData, tdImport);
+ // If we are here, the linker says this error is OK.
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyFields()
+
+
+//*****************************************************************************
+// Verify Events
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyEvents(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ RID ridEventMap, ridEventMapEmit;
+ EventMapRec *pEventMapRec;
+ EventRec *pRecImport;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+ mdEvent evImport;
+ mdEvent evEmit;
+ TOKENREC *pTokenRec;
+ LPCUTF8 szName;
+ mdToken tkType;
+ MDTOKENMAP *pCurTkMap;
+
+ EventMapRec *pEventMapEmit;
+ EventRec *pRecEmit;
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ ULONG cImport = 0; // count of non-merge check suppressed events
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ IfFailGo(pMiniMdImport->FindEventMapFor(RidFromToken(tdImport), &ridEventMap));
+ if (!InvalidRid(ridEventMap))
+ {
+ // Get a count of records already in emit scope.
+ IfFailGo(pMiniMdEmit->FindEventMapFor(RidFromToken(tdEmit), &ridEventMapEmit));
+
+ if (InvalidRid(ridEventMapEmit)) {
+ // If there is any event, create the eventmap record in the emit scope
+ // Create new record.
+ IfFailGo(pMiniMdEmit->AddEventMapRecord(&pEventMapEmit, &ridEventMapEmit));
+
+ // Set parent.
+ IfFailGo(pMiniMdEmit->PutToken(TBL_EventMap, EventMapRec::COL_Parent, pEventMapEmit, tdEmit));
+ }
+
+ // Get a count of records in the import scope; prepare to enumerate them.
+ IfFailGo(pMiniMdImport->GetEventMapRecord(ridEventMap, &pEventMapRec));
+ ridStart = pMiniMdImport->getEventListOfEventMap(pEventMapRec);
+ IfFailGo(pMiniMdImport->getEndEventListOfEventMap(ridEventMap, &ridEnd));
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // get the property rid
+ IfFailGo(pMiniMdImport->GetEventRid(i, (ULONG *)&evImport));
+
+ // only verify those Events that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsEventMarked(TokenFromRid(evImport, mdtEvent)) == false)
+ continue;
+
+ IfFailGo(pMiniMdImport->GetEventRecord(evImport, &pRecImport));
+ IfFailGo(pMiniMdImport->getNameOfEvent(pRecImport, &szName));
+ tkType = pMiniMdImport->getEventTypeOfEvent( pRecImport );
+ IfFailGo( pCurTkMap->Remap(tkType, &tkType) );
+ evImport = TokenFromRid( evImport, mdtEvent);
+
+ hr = ImportHelper::FindEvent(
+ pMiniMdEmit,
+ tdEmit,
+ szName,
+ &evEmit);
+
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ evImport, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (bSuppressMergeCheck)
+ {
+
+ if (hr == S_OK )
+ {
+ // Good. We found the matching event when we have a duplicate typedef
+ IfFailGo( pCurTkMap->InsertNotFound(evImport, true, evEmit, &pTokenRec) );
+ }
+ else
+ {
+ // not a duplicate! Copy over the
+ IfFailGo(pMiniMdEmit->AddEventRecord(&pRecEmit, (RID *)&evEmit));
+
+ // copy the event record over
+ IfFailGo( CopyEvent(pImportData, pRecImport, pRecEmit) );
+
+ // Add Event to the EventMap.
+ IfFailGo( pMiniMdEmit->AddEventToEventMap(ridEventMapEmit, evEmit) );
+
+ // record the token movement
+ evEmit = TokenFromRid(evEmit, mdtEvent);
+
+ IfFailGo( pCurTkMap->InsertNotFound(evImport, false, evEmit, &pTokenRec) );
+
+ // copy over the method semantics
+ IfFailGo( CopyMethodSemantics(pImportData, evImport, evEmit) );
+ }
+ }
+ else
+ {
+ if (hr == S_OK )
+ {
+ // Good. We found the matching event when we have a duplicate typedef
+ IfFailGo( pCurTkMap->InsertNotFound(evImport, true, evEmit, &pTokenRec) );
+ }
+ else
+ {
+ // Oops! The typedef is duplicated but the event is not!!
+ hr = S_OK; // discard old error; new error will be returned from CheckContinuableError
+ CheckContinuableErrorEx(META_E_EVENT_NOT_FOUND, pImportData, evImport);
+
+ }
+
+ cImport++;
+ }
+ }
+
+ // The counts should be the same, unless this is <module>
+ if (cImport != pMTD->m_cEvents && tdImport != pImportData->m_pRegMetaImport->m_tdModule)
+ {
+ CheckContinuableErrorEx(META_E_EVENT_COUNTS, pImportData, tdImport);
+ // If we are here, the linker says this error is OK.
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyEvents()
+
+
+//*****************************************************************************
+// Verify Properties
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyProperties(
+ MergeImportData *pImportData,
+ mdTypeDef tdImport,
+ mdTypeDef tdEmit)
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ RID ridPropertyMap, ridPropertyMapEmit;
+ PropertyMapRec *pPropertyMapRec;
+ PropertyRec *pRecImport;
+ ULONG ridStart;
+ ULONG ridEnd;
+ ULONG i;
+ mdProperty prImp;
+ mdProperty prEmit;
+ TOKENREC *pTokenRec;
+ LPCUTF8 szName;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ MDTOKENMAP *pCurTkMap;
+
+ PropertyMapRec *pPropertyMapEmit;
+ PropertyRec *pRecEmit;
+ MergeTypeData *pMTD;
+ BOOL bSuppressMergeCheck;
+ ULONG cImport = 0; // count of non-merge check suppressed properties
+ mdCustomAttribute tkCA;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ IfFailGo(pMiniMdImport->FindPropertyMapFor(RidFromToken(tdImport), &ridPropertyMap));
+ if (!InvalidRid(ridPropertyMap))
+ {
+ // Get a count of records already in emit scope.
+ IfFailGo(pMiniMdEmit->FindPropertyMapFor(RidFromToken(tdEmit), &ridPropertyMapEmit));
+
+ if (InvalidRid(ridPropertyMapEmit))
+ {
+ // If there is any event, create the PropertyMap record in the emit scope
+ // Create new record.
+ IfFailGo(pMiniMdEmit->AddPropertyMapRecord(&pPropertyMapEmit, &ridPropertyMapEmit));
+
+ // Set parent.
+ IfFailGo(pMiniMdEmit->PutToken(TBL_PropertyMap, PropertyMapRec::COL_Parent, pPropertyMapEmit, tdEmit));
+ }
+
+ // Get a count of records in the import scope; prepare to enumerate them.
+ IfFailGo(pMiniMdImport->GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec));
+ ridStart = pMiniMdImport->getPropertyListOfPropertyMap(pPropertyMapRec);
+ IfFailGo(pMiniMdImport->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd));
+
+ pMTD = m_rMTDs.Get(RidFromToken(tdEmit));
+
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // get the property rid
+ IfFailGo(pMiniMdImport->GetPropertyRid(i, (ULONG *)&prImp));
+
+ // only verify those Properties that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsPropertyMarked(TokenFromRid(prImp, mdtProperty)) == false)
+ continue;
+
+ IfFailGo(pMiniMdImport->GetPropertyRecord(prImp, &pRecImport));
+ IfFailGo(pMiniMdImport->getNameOfProperty(pRecImport, &szName));
+ IfFailGo(pMiniMdImport->getTypeOfProperty(pRecImport, &pbSig, &cbSig));
+ prImp = TokenFromRid( prImp, mdtProperty);
+
+ // convert rid contained in signature to new scope
+ IfFailGo( ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Emit assembly.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit) ); // number of bytes write to cbEmit
+
+ hr = ImportHelper::FindProperty(
+ pMiniMdEmit,
+ tdEmit,
+ szName,
+ (PCCOR_SIGNATURE) qbSig.Ptr(),
+ cbEmit,
+ &prEmit);
+
+ bSuppressMergeCheck = pMTD->m_bSuppressMergeCheck ||
+ ((pImportData->m_tkSuppressMergeCheckCtor != mdTokenNil) &&
+ (S_OK == ImportHelper::FindCustomAttributeByToken(pMiniMdImport,
+ prImp, pImportData->m_tkSuppressMergeCheckCtor, NULL, 0, &tkCA)));
+
+ if (bSuppressMergeCheck)
+ {
+ if (hr == S_OK)
+ {
+ // Good. We found the matching property when we have a duplicate typedef
+ IfFailGo( pCurTkMap->InsertNotFound(prImp, true, prEmit, &pTokenRec) );
+ }
+ else
+ {
+ IfFailGo(pMiniMdEmit->AddPropertyRecord(&pRecEmit, (RID *)&prEmit));
+
+ // copy the property record over
+ IfFailGo( CopyProperty(pImportData, pRecImport, pRecEmit) );
+
+ // Add Property to the PropertyMap.
+ IfFailGo( pMiniMdEmit->AddPropertyToPropertyMap(ridPropertyMapEmit, prEmit) );
+
+ // record the token movement
+ prEmit = TokenFromRid(prEmit, mdtProperty);
+
+ IfFailGo( pCurTkMap->InsertNotFound(prImp, false, prEmit, &pTokenRec) );
+
+ // copy over the method semantics
+ IfFailGo( CopyMethodSemantics(pImportData, prImp, prEmit) );
+ }
+ }
+ else
+ {
+ if (hr == S_OK)
+ {
+ // Good. We found the matching property when we have a duplicate typedef
+ IfFailGo( pCurTkMap->InsertNotFound(prImp, true, prEmit, &pTokenRec) );
+ }
+ else
+ {
+ hr = S_OK; // discard old error; new error will be returned from CheckContinuableError
+ CheckContinuableErrorEx(META_E_PROP_NOT_FOUND, pImportData, prImp);
+ }
+
+ cImport++;
+ }
+ }
+
+ // The counts should be the same, unless this is <module>
+ if (cImport != pMTD->m_cProperties && tdImport != pImportData->m_pRegMetaImport->m_tdModule)
+ {
+ CheckContinuableErrorEx(META_E_PROPERTY_COUNTS, pImportData, tdImport);
+ // If we are here, the linker says this error is OK.
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyProperties()
+
+
+//*****************************************************************************
+// Verify Parameters given a Method
+//*****************************************************************************
+HRESULT NEWMERGER::VerifyParams(
+ MergeImportData *pImportData,
+ mdMethodDef mdImport,
+ mdMethodDef mdEmit)
+{
+ HRESULT hr = NOERROR;
+ ParamRec *pRecImport = NULL;
+ ParamRec *pRecEmit = NULL;
+ MethodRec *pMethodRec;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG ridStart, ridEnd;
+ ULONG ridStartEmit, ridEndEmit;
+ ULONG cImport, cEmit;
+ ULONG i, j;
+ mdParamDef pdEmit = 0;
+ mdParamDef pdImp;
+ TOKENREC *pTokenRec;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // Get count of params in import scope; prepare to enumerate.
+ IfFailGo(pMiniMdImport->GetMethodRecord(RidFromToken(mdImport), &pMethodRec));
+ ridStart = pMiniMdImport->getParamListOfMethod(pMethodRec);
+ IfFailGo(pMiniMdImport->getEndParamListOfMethod(RidFromToken(mdImport), &ridEnd));
+ cImport = ridEnd - ridStart;
+
+ // Get count of params in emit scope; prepare to enumerate.
+ IfFailGo(pMiniMdEmit->GetMethodRecord(RidFromToken(mdEmit), &pMethodRec));
+ ridStartEmit = pMiniMdEmit->getParamListOfMethod(pMethodRec);
+ IfFailGo(pMiniMdEmit->getEndParamListOfMethod(RidFromToken(mdEmit), &ridEndEmit));
+ cEmit = ridEndEmit - ridStartEmit;
+
+ // The counts should be the same.
+ if (cImport != cEmit)
+ {
+ // That is, unless this is <module>, so get the method's parent.
+ mdTypeDef tdImport;
+ IfFailGo(pMiniMdImport->FindParentOfMethodHelper(mdImport, &tdImport));
+ if (tdImport != pImportData->m_pRegMetaImport->m_tdModule)
+ CheckContinuableErrorEx(META_E_PARAM_COUNTS, pImportData, mdImport);
+ // If we are here, the linker says this error is OK.
+ }
+
+ // loop through all Parameters
+ for (i = ridStart; i < ridEnd; i++)
+ {
+ // Get the importing param row
+ IfFailGo(pMiniMdImport->GetParamRid(i, (ULONG *)&pdImp));
+
+ // only verify those Params that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsParamMarked(TokenFromRid(pdImp, mdtParamDef)) == false)
+ continue;
+
+
+ IfFailGo(pMiniMdImport->GetParamRecord(pdImp, &pRecImport));
+ pdImp = TokenFromRid(pdImp, mdtParamDef);
+
+ // It turns out when we merge a typelib with itself, the emit and import scope
+ // has different sequence of parameter
+ //
+ // find the corresponding emit param row
+ for (j = ridStartEmit; j < ridEndEmit; j++)
+ {
+ IfFailGo(pMiniMdEmit->GetParamRid(j, (ULONG *)&pdEmit));
+ IfFailGo(pMiniMdEmit->GetParamRecord(pdEmit, &pRecEmit));
+ if (pRecEmit->GetSequence() == pRecImport->GetSequence())
+ break;
+ }
+
+ if (j == ridEndEmit)
+ {
+ // did not find the corresponding parameter in the emiting scope
+ hr = S_OK; // discard old error; new error will be returned from CheckContinuableError
+ CheckContinuableErrorEx(META_S_PARAM_MISMATCH, pImportData, pdImp);
+ }
+
+ else
+ {
+ _ASSERTE( pRecEmit->GetSequence() == pRecImport->GetSequence() );
+
+ pdEmit = TokenFromRid(pdEmit, mdtParamDef);
+
+ // record the token movement
+#ifdef WE_DONT_NEED_TO_CHECK_NAMES__THEY_DONT_AFFECT_ANYTHING
+ LPCUTF8 szNameImp;
+ LPCUTF8 szNameEmit;
+ IfFailGo(pMiniMdImport->getNameOfParam(pRecImport, &szNameImp));
+ IfFailGo(pMiniMdEmit->getNameOfParam(pRecEmit, &szNameEmit));
+ if (szNameImp && szNameEmit && strcmp(szNameImp, szNameEmit) != 0)
+ {
+ // parameter name doesn't match
+ CheckContinuableErrorEx(META_S_PARAM_MISMATCH, pImportData, pdImp);
+ }
+#endif
+ if (pRecEmit->GetFlags() != pRecImport->GetFlags())
+ {
+ // flags doesn't match
+ CheckContinuableErrorEx(META_S_PARAM_MISMATCH, pImportData, pdImp);
+ }
+
+ // record token movement. This is a duplicate.
+ IfFailGo( pCurTkMap->InsertNotFound(pdImp, true, pdEmit, &pTokenRec) );
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::VerifyParams()
+
+
+//*****************************************************************************
+// merging MemberRef
+//*****************************************************************************
+HRESULT NEWMERGER::MergeMemberRefs( )
+{
+ HRESULT hr = NOERROR;
+ MemberRefRec *pRecImport = NULL;
+ MemberRefRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdMemberRef mrEmit;
+ mdMemberRef mrImp;
+ bool bDuplicate = false;
+ TOKENREC *pTokenRec;
+ mdToken tkParentImp;
+ mdToken tkParentEmit;
+
+ LPCUTF8 szNameImp;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+
+ bool isRefOptimizedToDef;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ iCount = pMiniMdImport->getCountMemberRefs();
+
+ // loop through all MemberRef
+ for (i = 1; i <= iCount; i++)
+ {
+
+ // only merge those MemberRefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsMemberRefMarked(TokenFromRid(i, mdtMemberRef)) == false)
+ continue;
+
+ isRefOptimizedToDef = false;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetMemberRefRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getNameOfMemberRef(pRecImport, &szNameImp));
+ IfFailGo(pMiniMdImport->getSignatureOfMemberRef(pRecImport, &pbSig, &cbSig));
+ tkParentImp = pMiniMdImport->getClassOfMemberRef(pRecImport);
+
+ IfFailGo( pCurTkMap->Remap(tkParentImp, &tkParentEmit) );
+
+ // convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly information.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ // We want to know if we can optimize this MemberRef to a FieldDef or MethodDef
+ if (TypeFromToken(tkParentEmit) == mdtTypeDef && RidFromToken(tkParentEmit) != 0)
+ {
+ // The parent of this MemberRef has been successfully optimized to a TypeDef. Then this MemberRef should be
+ // be able to optimized to a MethodDef or FieldDef unless one of the parent in the inheritance hierachy
+ // is through TypeRef. Then this MemberRef stay as MemberRef. If This is a VarArg calling convention, then
+ // we will remap the MemberRef's parent to a MethodDef or stay as TypeRef.
+ //
+ mdToken tkParent = tkParentEmit;
+ mdToken tkMethDefOrFieldDef;
+ PCCOR_SIGNATURE pbSigTmp = (const COR_SIGNATURE *) qbSig.Ptr();
+
+ while (TypeFromToken(tkParent) == mdtTypeDef && RidFromToken(tkParent) != 0)
+ {
+ TypeDefRec *pRec;
+ hr = ImportHelper::FindMember(pMiniMdEmit, tkParent, szNameImp, pbSigTmp, cbEmit, &tkMethDefOrFieldDef);
+ if (hr == S_OK)
+ {
+ // We have found a match!!
+ if (isCallConv(CorSigUncompressCallingConv(pbSigTmp), IMAGE_CEE_CS_CALLCONV_VARARG))
+ {
+ // The found MethodDef token will replace this MemberRef's parent token
+ _ASSERTE(TypeFromToken(tkMethDefOrFieldDef) == mdtMethodDef);
+ tkParentEmit = tkMethDefOrFieldDef;
+ break;
+ }
+ else
+ {
+ // The found MethodDef/FieldDef token will replace this MemberRef token and we won't introduce a MemberRef
+ // record.
+ //
+ mrEmit = tkMethDefOrFieldDef;
+ isRefOptimizedToDef = true;
+ bDuplicate = true;
+ break;
+ }
+ }
+
+ // now walk up to the parent class of tkParent and try to resolve this MemberRef
+ IfFailGo(pMiniMdEmit->GetTypeDefRecord(RidFromToken(tkParent), &pRec));
+ tkParent = pMiniMdEmit->getExtendsOfTypeDef(pRec);
+ }
+
+ // When we exit the loop, there are several possibilities:
+ // 1. We found a MethodDef/FieldDef to replace the MemberRef
+ // 2. We found a MethodDef matches the MemberRef but the MemberRef is VarArg, thus we want to use the MethodDef in the
+ // parent column but not replacing it.
+ // 3. We exit because we run out the TypeDef on the parent chain. If it is because we encounter a TypeRef, this TypeRef will
+ // replace the parent column of the MemberRef. Or we encounter nil token! (This can be unresolved global MemberRef or
+ // compiler error to put an undefined MemberRef. In this case, we should just use the old tkParentEmit
+ // on the parent column for the MemberRef.
+
+ if (TypeFromToken(tkParent) == mdtTypeRef && RidFromToken(tkParent) != 0)
+ {
+ // we had walked up the parent's chain to resolve it but we have not been successful and got stopped by a TypeRef.
+ // Then we will use this TypeRef as the parent of the emit MemberRef record
+ //
+ tkParentEmit = tkParent;
+ }
+ }
+ else if ((TypeFromToken(tkParentEmit) == mdtMethodDef &&
+ !isCallConv(CorSigUncompressCallingConv(pbSig), IMAGE_CEE_CS_CALLCONV_VARARG)) ||
+ (TypeFromToken(tkParentEmit) == mdtFieldDef))
+ {
+ // If the MemberRef's parent is already a non-vararg MethodDef or FieldDef, we can also
+ // safely drop the MemberRef
+ mrEmit = tkParentEmit;
+ isRefOptimizedToDef = true;
+ bDuplicate = true;
+ }
+
+ // If the Ref cannot be optimized to a Def or MemberRef to Def optmization is turned off, do the following.
+ if (isRefOptimizedToDef == false || !((m_optimizeRefToDef & MDMemberRefToDef) == MDMemberRefToDef))
+ {
+ // does this MemberRef already exist in the emit scope?
+ if ( m_fDupCheck && ImportHelper::FindMemberRef(
+ pMiniMdEmit,
+ tkParentEmit,
+ szNameImp,
+ (const COR_SIGNATURE *) qbSig.Ptr(),
+ cbEmit,
+ &mrEmit) == S_OK )
+ {
+ // Yes, it does
+ bDuplicate = true;
+ }
+ else
+ {
+ // No, it doesn't. Copy it over.
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddMemberRefRecord(&pRecEmit, (RID *)&mrEmit));
+ mrEmit = TokenFromRid( mrEmit, mdtMemberRef );
+
+ // Copy over the MemberRef context
+ IfFailGo(pMiniMdEmit->PutString(TBL_MemberRef, MemberRefRec::COL_Name, pRecEmit, szNameImp));
+ IfFailGo(pMiniMdEmit->PutToken(TBL_MemberRef, MemberRefRec::COL_Class, pRecEmit, tkParentEmit));
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_MemberRef, MemberRefRec::COL_Signature, pRecEmit,
+ qbSig.Ptr(), cbEmit));
+ IfFailGo(pMiniMdEmit->AddMemberRefToHash(mrEmit) );
+ }
+ }
+ // record the token movement
+ mrImp = TokenFromRid(i, mdtMemberRef);
+ IfFailGo( pCurTkMap->InsertNotFound(mrImp, bDuplicate, mrEmit, &pTokenRec) );
+ }
+ }
+
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeMemberRefs()
+
+
+//*****************************************************************************
+// merge interface impl
+//*****************************************************************************
+HRESULT NEWMERGER::MergeInterfaceImpls( )
+{
+ HRESULT hr = NOERROR;
+ InterfaceImplRec *pRecImport = NULL;
+ InterfaceImplRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdTypeDef tkParent;
+ mdInterfaceImpl iiEmit;
+ bool bDuplicate;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountInterfaceImpls();
+
+ // loop through all InterfaceImpl
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those InterfaceImpls that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsInterfaceImplMarked(TokenFromRid(i, mdtInterfaceImpl)) == false)
+ continue;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetInterfaceImplRecord(i, &pRecImport));
+ tkParent = pMiniMdImport->getClassOfInterfaceImpl(pRecImport);
+
+ // does this TypeRef already exist in the emit scope?
+ if ( pCurTkMap->Find(tkParent, &pTokenRec) )
+ {
+ if ( pTokenRec->m_isDuplicate )
+ {
+ // parent in the emit scope
+ mdToken tkParentEmit;
+ mdToken tkInterface;
+
+ // remap the typedef token
+ tkParentEmit = pTokenRec->m_tkTo;
+
+ // remap the implemented interface token
+ tkInterface = pMiniMdImport->getInterfaceOfInterfaceImpl(pRecImport);
+ IfFailGo( pCurTkMap->Remap( tkInterface, &tkInterface) );
+
+ // Set duplicate flag
+ bDuplicate = true;
+
+ // find the corresponding interfaceimpl in the emit scope
+ if ( ImportHelper::FindInterfaceImpl(pMiniMdEmit, tkParentEmit, tkInterface, &iiEmit) != S_OK )
+ {
+ // bad state!! We have a duplicate typedef but the interface impl is not the same!!
+
+ // continuable error
+ CheckContinuableErrorEx(
+ META_E_INTFCEIMPL_NOT_FOUND,
+ pImportData,
+ TokenFromRid(i, mdtInterfaceImpl));
+
+ iiEmit = mdTokenNil;
+ }
+ }
+ else
+ {
+ // No, it doesn't. Copy it over.
+ bDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddInterfaceImplRecord(&pRecEmit, (RID *)&iiEmit));
+
+ // copy the interfaceimp record over
+ IfFailGo( CopyInterfaceImpl( pRecEmit, pImportData, pRecImport) );
+ }
+ }
+ else
+ {
+ _ASSERTE( !"bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+
+ // record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtInterfaceImpl),
+ bDuplicate,
+ TokenFromRid( iiEmit, mdtInterfaceImpl ),
+ &pTokenRec) );
+ }
+ }
+
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeInterfaceImpls()
+
+
+//*****************************************************************************
+// merge all of the constant for field, property, and parameter
+//*****************************************************************************
+HRESULT NEWMERGER::MergeConstants()
+{
+ HRESULT hr = NOERROR;
+ ConstantRec *pRecImport = NULL;
+ ConstantRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ ULONG csEmit; // constant value is not a token
+ mdToken tkParentImp;
+ TOKENREC *pTokenRec;
+ void const *pValue;
+ ULONG cbBlob;
+#if _DEBUG
+ ULONG typeParent;
+#endif // _DEBUG
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountConstants();
+
+ // loop through all Constants
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetConstantRecord(i, &pRecImport));
+ tkParentImp = pMiniMdImport->getParentOfConstant(pRecImport);
+
+ // only move those constant over if their parents are marked
+ // If MDTOKENMAP::Find returns false, we don't need to copy the constant value over
+ if ( pCurTkMap->Find(tkParentImp, &pTokenRec) )
+ {
+ // If the parent is duplicated, no need to move over the constant value
+ if ( !pTokenRec->m_isDuplicate )
+ {
+ IfFailGo(pMiniMdEmit->AddConstantRecord(&pRecEmit, &csEmit));
+ pRecEmit->SetType(pRecImport->GetType());
+
+ // set the parent
+ IfFailGo( pMiniMdEmit->PutToken(TBL_Constant, ConstantRec::COL_Parent, pRecEmit, pTokenRec->m_tkTo) );
+
+ // move over the constant blob value
+ IfFailGo(pMiniMdImport->getValueOfConstant(pRecImport, (const BYTE **)&pValue, &cbBlob));
+ IfFailGo( pMiniMdEmit->PutBlob(TBL_Constant, ConstantRec::COL_Value, pRecEmit, pValue, cbBlob) );
+ IfFailGo( pMiniMdEmit->AddConstantToHash(csEmit) );
+ }
+ else
+ {
+ // <TODO>@FUTURE: more verification on the duplicate??</TODO>
+ }
+ }
+#if _DEBUG
+ // Include this block only under Debug build. The reason is that
+ // the linker chooses all the errors that we report (such as unmatched MethodDef or FieldDef)
+ // as a continuable error. It is likely to hit this else while the tkparentImp is marked if there
+ // is any error reported earlier!!
+ else
+ {
+ typeParent = TypeFromToken(tkParentImp);
+ if (typeParent == mdtFieldDef)
+ {
+ // FieldDef should not be marked.
+ if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(tkParentImp) == false)
+ continue;
+ }
+ else if (typeParent == mdtParamDef)
+ {
+ // ParamDef should not be marked.
+ if ( pMiniMdImport->GetFilterTable()->IsParamMarked(tkParentImp) == false)
+ continue;
+ }
+ else
+ {
+ _ASSERTE(typeParent == mdtProperty);
+ // Property should not be marked.
+ if ( pMiniMdImport->GetFilterTable()->IsPropertyMarked(tkParentImp) == false)
+ continue;
+ }
+
+ // If we come to here, we have a constant whose parent is marked but we could not
+ // find it in the map!! Bad state.
+
+ _ASSERTE(!"Ignore this error if you have seen error reported earlier! Otherwise bad token map or bad metadata!");
+ }
+#endif // _DEBUG
+ // Note that we don't need to record the token movement since constant is not a valid token kind.
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeConstants()
+
+
+//*****************************************************************************
+// Merge field marshal information
+//*****************************************************************************
+HRESULT NEWMERGER::MergeFieldMarshals()
+{
+ HRESULT hr = NOERROR;
+ FieldMarshalRec *pRecImport = NULL;
+ FieldMarshalRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ ULONG fmEmit; // FieldMarhsal is not a token
+ mdToken tkParentImp;
+ TOKENREC *pTokenRec;
+ void const *pValue;
+ ULONG cbBlob;
+#if _DEBUG
+ ULONG typeParent;
+#endif // _DEBUG
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountFieldMarshals();
+
+ // loop through all TypeRef
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetFieldMarshalRecord(i, &pRecImport));
+ tkParentImp = pMiniMdImport->getParentOfFieldMarshal(pRecImport);
+
+ // We want to merge only those field marshals that parents are marked.
+ // Find will return false if the parent is not marked
+ //
+ if ( pCurTkMap->Find(tkParentImp, &pTokenRec) )
+ {
+ // If the parent is duplicated, no need to move over the constant value
+ if ( !pTokenRec->m_isDuplicate )
+ {
+ IfFailGo(pMiniMdEmit->AddFieldMarshalRecord(&pRecEmit, &fmEmit));
+
+ // set the parent
+ IfFailGo( pMiniMdEmit->PutToken(
+ TBL_FieldMarshal,
+ FieldMarshalRec::COL_Parent,
+ pRecEmit,
+ pTokenRec->m_tkTo) );
+
+ // move over the constant blob value
+ IfFailGo(pMiniMdImport->getNativeTypeOfFieldMarshal(pRecImport, (const BYTE **)&pValue, &cbBlob));
+ IfFailGo( pMiniMdEmit->PutBlob(TBL_FieldMarshal, FieldMarshalRec::COL_NativeType, pRecEmit, pValue, cbBlob) );
+ IfFailGo( pMiniMdEmit->AddFieldMarshalToHash(fmEmit) );
+
+ }
+ else
+ {
+ // <TODO>@FUTURE: more verification on the duplicate??</TODO>
+ }
+ }
+#if _DEBUG
+ else
+ {
+ typeParent = TypeFromToken(tkParentImp);
+
+ if (typeParent == mdtFieldDef)
+ {
+ // FieldDefs should not be marked
+ if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(tkParentImp) == false)
+ continue;
+ }
+ else
+ {
+ _ASSERTE(typeParent == mdtParamDef);
+ // ParamDefs should not be marked
+ if ( pMiniMdImport->GetFilterTable()->IsParamMarked(tkParentImp) == false)
+ continue;
+ }
+
+ // If we come to here, that is we have a FieldMarshal whose parent is marked and we don't find it
+ // in the map!!!
+
+ // either bad lookup map or bad metadata
+ _ASSERTE(!"Ignore this assert if you have seen error reported earlier. Otherwise, it is bad state!");
+ }
+#endif // _DEBUG
+ }
+ // Note that we don't need to record the token movement since FieldMarshal is not a valid token kind.
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeFieldMarshals()
+
+
+//*****************************************************************************
+// Merge class layout information
+//*****************************************************************************
+HRESULT NEWMERGER::MergeClassLayouts()
+{
+ HRESULT hr = NOERROR;
+ ClassLayoutRec *pRecImport = NULL;
+ ClassLayoutRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord; // class layout is not a token
+ mdToken tkParentImp;
+ TOKENREC *pTokenRec;
+ RID ridClassLayout;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountClassLayouts();
+
+ // loop through all TypeRef
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetClassLayoutRecord(i, &pRecImport));
+ tkParentImp = pMiniMdImport->getParentOfClassLayout(pRecImport);
+
+ // only merge those TypeDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsTypeDefMarked(tkParentImp) == false)
+ continue;
+
+ if ( pCurTkMap->Find(tkParentImp, &pTokenRec) )
+ {
+ if ( !pTokenRec->m_isDuplicate )
+ {
+ // If the parent is not duplicated, just copy over the classlayout information
+ IfFailGo(pMiniMdEmit->AddClassLayoutRecord(&pRecEmit, &iRecord));
+
+ // copy over the fix part information
+ pRecEmit->Copy(pRecImport);
+ IfFailGo( pMiniMdEmit->PutToken(TBL_ClassLayout, ClassLayoutRec::COL_Parent, pRecEmit, pTokenRec->m_tkTo));
+ IfFailGo( pMiniMdEmit->AddClassLayoutToHash(iRecord) );
+ }
+ else
+ {
+
+ IfFailGo(pMiniMdEmit->FindClassLayoutHelper(pTokenRec->m_tkTo, &ridClassLayout));
+
+ if (InvalidRid(ridClassLayout))
+ {
+ // class is duplicated but not class layout info
+ CheckContinuableErrorEx(META_E_CLASS_LAYOUT_INCONSISTENT, pImportData, tkParentImp);
+ }
+ else
+ {
+ IfFailGo(pMiniMdEmit->GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRecEmit));
+ if (pMiniMdImport->getPackingSizeOfClassLayout(pRecImport) != pMiniMdEmit->getPackingSizeOfClassLayout(pRecEmit) ||
+ pMiniMdImport->getClassSizeOfClassLayout(pRecImport) != pMiniMdEmit->getClassSizeOfClassLayout(pRecEmit) )
+ {
+ CheckContinuableErrorEx(META_E_CLASS_LAYOUT_INCONSISTENT, pImportData, tkParentImp);
+ }
+ }
+ }
+ }
+ else
+ {
+ // bad lookup map
+ _ASSERTE( !"bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ // no need to record the index movement. Classlayout is not a token.
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeClassLayouts()
+
+//*****************************************************************************
+// Merge field layout information
+//*****************************************************************************
+HRESULT NEWMERGER::MergeFieldLayouts()
+{
+ HRESULT hr = NOERROR;
+ FieldLayoutRec *pRecImport = NULL;
+ FieldLayoutRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord; // field layout2 is not a token.
+ mdToken tkFieldImp;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountFieldLayouts();
+
+ // loop through all FieldLayout records.
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetFieldLayoutRecord(i, &pRecImport));
+ tkFieldImp = pMiniMdImport->getFieldOfFieldLayout(pRecImport);
+
+ // only merge those FieldDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(tkFieldImp) == false)
+ continue;
+
+ if ( pCurTkMap->Find(tkFieldImp, &pTokenRec) )
+ {
+ if ( !pTokenRec->m_isDuplicate )
+ {
+ // If the Field is not duplicated, just copy over the FieldLayout information
+ IfFailGo(pMiniMdEmit->AddFieldLayoutRecord(&pRecEmit, &iRecord));
+
+ // copy over the fix part information
+ pRecEmit->Copy(pRecImport);
+ IfFailGo( pMiniMdEmit->PutToken(TBL_FieldLayout, FieldLayoutRec::COL_Field, pRecEmit, pTokenRec->m_tkTo));
+ IfFailGo( pMiniMdEmit->AddFieldLayoutToHash(iRecord) );
+ }
+ else
+ {
+ // <TODO>@FUTURE: more verification??</TODO>
+ }
+ }
+ else
+ {
+ // bad lookup map
+ _ASSERTE( !"bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ // no need to record the index movement. fieldlayout2 is not a token.
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeFieldLayouts()
+
+
+//*****************************************************************************
+// Merge field RVAs
+//*****************************************************************************
+HRESULT NEWMERGER::MergeFieldRVAs()
+{
+ HRESULT hr = NOERROR;
+ FieldRVARec *pRecImport = NULL;
+ FieldRVARec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord; // FieldRVA is not a token.
+ mdToken tkFieldImp;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountFieldRVAs();
+
+ // loop through all FieldRVA records.
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetFieldRVARecord(i, &pRecImport));
+ tkFieldImp = pMiniMdImport->getFieldOfFieldRVA(pRecImport);
+
+ // only merge those FieldDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsFieldMarked(TokenFromRid(tkFieldImp, mdtFieldDef)) == false)
+ continue;
+
+ if ( pCurTkMap->Find(tkFieldImp, &pTokenRec) )
+ {
+ if ( !pTokenRec->m_isDuplicate )
+ {
+ // If the Field is not duplicated, just copy over the FieldRVA information
+ IfFailGo(pMiniMdEmit->AddFieldRVARecord(&pRecEmit, &iRecord));
+
+ // copy over the fix part information
+ pRecEmit->Copy(pRecImport);
+ IfFailGo( pMiniMdEmit->PutToken(TBL_FieldRVA, FieldRVARec::COL_Field, pRecEmit, pTokenRec->m_tkTo));
+ IfFailGo( pMiniMdEmit->AddFieldRVAToHash(iRecord) );
+ }
+ else
+ {
+ // <TODO>@FUTURE: more verification??</TODO>
+ }
+ }
+ else
+ {
+ // bad lookup map
+ _ASSERTE( !"bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ // no need to record the index movement. FieldRVA is not a token.
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeFieldRVAs()
+
+
+//*****************************************************************************
+// Merge MethodImpl information
+//*****************************************************************************
+HRESULT NEWMERGER::MergeMethodImpls()
+{
+ HRESULT hr = NOERROR;
+ MethodImplRec *pRecImport = NULL;
+ MethodImplRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ RID iRecord;
+ mdTypeDef tkClassImp;
+ mdToken tkBodyImp;
+ mdToken tkDeclImp;
+ TOKENREC *pTokenRecClass;
+ mdToken tkBodyEmit;
+ mdToken tkDeclEmit;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountMethodImpls();
+
+ // loop through all the MethodImpls.
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those MethodImpls that are marked.
+ if ( pMiniMdImport->GetFilterTable()->IsMethodImplMarked(i) == false)
+ continue;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetMethodImplRecord(i, &pRecImport));
+ tkClassImp = pMiniMdImport->getClassOfMethodImpl(pRecImport);
+ tkBodyImp = pMiniMdImport->getMethodBodyOfMethodImpl(pRecImport);
+ tkDeclImp = pMiniMdImport->getMethodDeclarationOfMethodImpl(pRecImport);
+
+ if ( pCurTkMap->Find(tkClassImp, &pTokenRecClass))
+ {
+ // If the TypeDef is duplicated, no need to move over the MethodImpl record.
+ if ( !pTokenRecClass->m_isDuplicate )
+ {
+ // Create a new record and set the data.
+
+ // <TODO>@FUTURE: We might want to consider changing the error for the remap into a continuable error.
+ // Because we probably can continue merging for more data...</TODO>
+
+ IfFailGo( pCurTkMap->Remap(tkBodyImp, &tkBodyEmit) );
+ IfFailGo( pCurTkMap->Remap(tkDeclImp, &tkDeclEmit) );
+ IfFailGo(pMiniMdEmit->AddMethodImplRecord(&pRecEmit, &iRecord));
+ IfFailGo( pMiniMdEmit->PutToken(TBL_MethodImpl, MethodImplRec::COL_Class, pRecEmit, pTokenRecClass->m_tkTo) );
+ IfFailGo( pMiniMdEmit->PutToken(TBL_MethodImpl, MethodImplRec::COL_MethodBody, pRecEmit, tkBodyEmit) );
+ IfFailGo( pMiniMdEmit->PutToken(TBL_MethodImpl, MethodImplRec::COL_MethodDeclaration, pRecEmit, tkDeclEmit) );
+ IfFailGo( pMiniMdEmit->AddMethodImplToHash(iRecord) );
+ }
+ else
+ {
+ // <TODO>@FUTURE: more verification on the duplicate??</TODO>
+ }
+ // No need to record the token movement, MethodImpl is not a token.
+ }
+ else
+ {
+ // either bad lookup map or bad metadata
+ _ASSERTE(!"bad state");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeMethodImpls()
+
+
+//*****************************************************************************
+// Merge PInvoke
+//*****************************************************************************
+HRESULT NEWMERGER::MergePinvoke()
+{
+ HRESULT hr = NOERROR;
+ ImplMapRec *pRecImport = NULL;
+ ImplMapRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdModuleRef mrImp;
+ mdModuleRef mrEmit;
+ mdMethodDef mdImp;
+ RID mdImplMap;
+ TOKENREC *pTokenRecMR;
+ TOKENREC *pTokenRecMD;
+
+ USHORT usMappingFlags;
+ LPCUTF8 szImportName;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountImplMaps();
+
+ // loop through all ImplMaps
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetImplMapRecord(i, &pRecImport));
+
+ // Get the MethodDef token in the new space.
+ mdImp = pMiniMdImport->getMemberForwardedOfImplMap(pRecImport);
+
+ // only merge those MethodDefs that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsMethodMarked(mdImp) == false)
+ continue;
+
+ // Get the ModuleRef token in the new space.
+ mrImp = pMiniMdImport->getImportScopeOfImplMap(pRecImport);
+
+ // map the token to the new scope
+ if (pCurTkMap->Find(mrImp, &pTokenRecMR) == false)
+ {
+ // This should never fire unless the module refs weren't merged
+ // before this code ran.
+ _ASSERTE(!"Parent ModuleRef not found in MERGER::MergePinvoke. Bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+
+ // If the ModuleRef has been remapped to the "module token", we need to undo that
+ // for the pinvokeimpl. A pinvoke can only have a ModuleRef for the ImportScope.
+ mrEmit = pTokenRecMR->m_tkTo;
+ if (mrEmit == MODULEDEFTOKEN)
+ { // Yes, the ModuleRef has been remapped to the module token. So,
+ // find the ModuleRef in the output scope; if it is not found, add
+ // it.
+ ModuleRefRec *pModRefImport;
+ LPCUTF8 szNameImp;
+ IfFailGo(pMiniMdImport->GetModuleRefRecord(RidFromToken(mrImp), &pModRefImport));
+ IfFailGo(pMiniMdImport->getNameOfModuleRef(pModRefImport, &szNameImp));
+
+ // does this ModuleRef already exist in the emit scope?
+ hr = ImportHelper::FindModuleRef(pMiniMdEmit,
+ szNameImp,
+ &mrEmit);
+
+ if (hr == CLDB_E_RECORD_NOTFOUND)
+ { // No, it doesn't. Copy it over.
+ ModuleRefRec *pModRefEmit;
+ IfFailGo(pMiniMdEmit->AddModuleRefRecord(&pModRefEmit, (RID*)&mrEmit));
+ mrEmit = TokenFromRid(mrEmit, mdtModuleRef);
+
+ // Set ModuleRef Name.
+ IfFailGo( pMiniMdEmit->PutString(TBL_ModuleRef, ModuleRefRec::COL_Name, pModRefEmit, szNameImp) );
+ }
+ else
+ IfFailGo(hr);
+ }
+
+
+ if (pCurTkMap->Find(mdImp, &pTokenRecMD) == false)
+ {
+ // This should never fire unless the method defs weren't merged
+ // before this code ran.
+ _ASSERTE(!"Parent MethodDef not found in MERGER::MergePinvoke. Bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+
+
+ // Get copy of rest of data.
+ usMappingFlags = pMiniMdImport->getMappingFlagsOfImplMap(pRecImport);
+ IfFailGo(pMiniMdImport->getImportNameOfImplMap(pRecImport, &szImportName));
+
+ // If the method associated with PInvokeMap is not duplicated, then don't bother to look up the
+ // duplicated PInvokeMap information.
+ if (pTokenRecMD->m_isDuplicate == true)
+ {
+ // Does the correct ImplMap entry exist in the emit scope?
+ IfFailGo(pMiniMdEmit->FindImplMapHelper(pTokenRecMD->m_tkTo, &mdImplMap));
+ }
+ else
+ {
+ mdImplMap = mdTokenNil;
+ }
+ if (!InvalidRid(mdImplMap))
+ {
+ // Verify that the rest of the data is identical, else it's an error.
+ IfFailGo(pMiniMdEmit->GetImplMapRecord(mdImplMap, &pRecEmit));
+ _ASSERTE(pMiniMdEmit->getMemberForwardedOfImplMap(pRecEmit) == pTokenRecMD->m_tkTo);
+ LPCSTR szImplMapImportName;
+ IfFailGo(pMiniMdEmit->getImportNameOfImplMap(pRecEmit, &szImplMapImportName));
+ if (pMiniMdEmit->getImportScopeOfImplMap(pRecEmit) != mrEmit ||
+ pMiniMdEmit->getMappingFlagsOfImplMap(pRecEmit) != usMappingFlags ||
+ strcmp(szImplMapImportName, szImportName))
+ {
+ // Mismatched p-invoke entries are found.
+ _ASSERTE(!"Mismatched P-invoke entries during merge. Bad State!");
+ IfFailGo(E_FAIL);
+ }
+ }
+ else
+ {
+ IfFailGo(pMiniMdEmit->AddImplMapRecord(&pRecEmit, &mdImplMap));
+
+ // Copy rest of data.
+ IfFailGo( pMiniMdEmit->PutToken(TBL_ImplMap, ImplMapRec::COL_MemberForwarded, pRecEmit, pTokenRecMD->m_tkTo) );
+ IfFailGo( pMiniMdEmit->PutToken(TBL_ImplMap, ImplMapRec::COL_ImportScope, pRecEmit, mrEmit) );
+ IfFailGo( pMiniMdEmit->PutString(TBL_ImplMap, ImplMapRec::COL_ImportName, pRecEmit, szImportName) );
+ pRecEmit->SetMappingFlags(usMappingFlags);
+ IfFailGo( pMiniMdEmit->AddImplMapToHash(mdImplMap) );
+ }
+ }
+ }
+
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergePinvoke()
+
+
+//*****************************************************************************
+// Merge StandAloneSigs
+//*****************************************************************************
+HRESULT NEWMERGER::MergeStandAloneSigs()
+{
+ HRESULT hr = NOERROR;
+ StandAloneSigRec *pRecImport = NULL;
+ StandAloneSigRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ TOKENREC *pTokenRec;
+ mdSignature saImp;
+ mdSignature saEmit;
+ bool fDuplicate;
+ PCCOR_SIGNATURE pbSig;
+ ULONG cbSig;
+ ULONG cbEmit;
+ CQuickBytes qbSig;
+ PCOR_SIGNATURE rgSig;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountStandAloneSigs();
+
+ // loop through all Signatures
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those Signatures that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsSignatureMarked(TokenFromRid(i, mdtSignature)) == false)
+ continue;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetStandAloneSigRecord(i, &pRecImport));
+ IfFailGo(pMiniMdImport->getSignatureOfStandAloneSig(pRecImport, &pbSig, &cbSig));
+
+ // This is a signature containing the return type after count of args
+ // convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Assembly import scope info.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pbSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+ rgSig = ( PCOR_SIGNATURE ) qbSig.Ptr();
+
+ hr = ImportHelper::FindStandAloneSig(
+ pMiniMdEmit,
+ rgSig,
+ cbEmit,
+ &saEmit );
+ if ( hr == S_OK )
+ {
+ // find a duplicate
+ fDuplicate = true;
+ }
+ else
+ {
+ // copy over
+ fDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddStandAloneSigRecord(&pRecEmit, (ULONG *)&saEmit));
+ saEmit = TokenFromRid(saEmit, mdtSignature);
+ IfFailGo( pMiniMdEmit->PutBlob(TBL_StandAloneSig, StandAloneSigRec::COL_Signature, pRecEmit, rgSig, cbEmit));
+ }
+ saImp = TokenFromRid(i, mdtSignature);
+
+ // Record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(saImp, fDuplicate, saEmit, &pTokenRec) );
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeStandAloneSigs()
+
+//*****************************************************************************
+// Merge MethodSpecs
+//*****************************************************************************
+HRESULT NEWMERGER::MergeMethodSpecs()
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdToken tk;
+ ULONG iRecord;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ // Loop through all MethodSpec
+ iCount = pMiniMdImport->getCountMethodSpecs();
+ for (i=1; i<=iCount; ++i)
+ {
+ MethodSpecRec *pRecImport;
+ MethodSpecRec *pRecEmit;
+ TOKENREC *pTokenRecMethod;
+ TOKENREC *pTokenRecMethodNew;
+ PCCOR_SIGNATURE pvSig;
+ ULONG cbSig;
+ CQuickBytes qbSig;
+ ULONG cbEmit;
+
+ // Only copy marked records.
+ if (!pMiniMdImport->GetFilterTable()->IsMethodSpecMarked(i))
+ continue;
+
+ IfFailGo(pMiniMdImport->GetMethodSpecRecord(i, &pRecImport));
+ tk = pMiniMdImport->getMethodOfMethodSpec(pRecImport);
+
+ // Map the token to the new scope.
+ if (pCurTkMap->Find(tk, &pTokenRecMethod) == false)
+ {
+ // This should never fire unless the TypeDefs/Refs weren't merged
+ // before this code runs.
+ _ASSERTE(!"MethodSpec method not found in MERGER::MergeGenericsInfo. Bad state!");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ // Copy to output scope.
+ IfFailGo(pMiniMdEmit->AddMethodSpecRecord(&pRecEmit, &iRecord));
+ IfFailGo( pMiniMdEmit->PutToken(TBL_MethodSpec, MethodSpecRec::COL_Method, pRecEmit, pTokenRecMethod->m_tkTo));
+
+ // Copy the signature, translating any embedded tokens.
+ IfFailGo(pMiniMdImport->getInstantiationOfMethodSpec(pRecImport, &pvSig, &cbSig));
+
+ // ...convert rid contained in signature to new scope
+ IfFailGo(ImportHelper::MergeUpdateTokenInSig(
+ NULL, // Assembly emit scope.
+ pMiniMdEmit, // The emit scope.
+ NULL, NULL, 0, // Import assembly scope information.
+ pMiniMdImport, // The scope to merge into the emit scope.
+ pvSig, // signature from the imported scope
+ pCurTkMap, // Internal token mapping structure.
+ &qbSig, // [OUT] translated signature
+ 0, // start from first byte of the signature
+ 0, // don't care how many bytes consumed
+ &cbEmit)); // number of bytes write to cbEmit
+
+ // ...persist the converted signature
+ IfFailGo( pMiniMdEmit->PutBlob(TBL_MethodSpec, MethodSpecRec::COL_Instantiation, pRecEmit, qbSig.Ptr(), cbEmit) );
+
+ IfFailGo( pCurTkMap->InsertNotFound(TokenFromRid(i, mdtMethodSpec), false,
+ TokenFromRid(iRecord, mdtMethodSpec), &pTokenRecMethodNew) );
+ }
+ }
+
+ ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeMethodSpecs()
+
+//*****************************************************************************
+// Merge DeclSecuritys
+//*****************************************************************************
+HRESULT NEWMERGER::MergeDeclSecuritys()
+{
+ HRESULT hr = NOERROR;
+ DeclSecurityRec *pRecImport = NULL;
+ DeclSecurityRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdToken tkParentImp;
+ TOKENREC *pTokenRec;
+ void const *pValue;
+ ULONG cbBlob;
+ mdPermission pmImp;
+ mdPermission pmEmit;
+ bool fDuplicate;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountDeclSecuritys();
+
+ // loop through all DeclSecurity
+ for (i = 1; i <= iCount; i++)
+ {
+ // only merge those DeclSecurities that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsDeclSecurityMarked(TokenFromRid(i, mdtPermission)) == false)
+ continue;
+
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetDeclSecurityRecord(i, &pRecImport));
+ tkParentImp = pMiniMdImport->getParentOfDeclSecurity(pRecImport);
+ if ( pCurTkMap->Find(tkParentImp, &pTokenRec) )
+ {
+ if ( !pTokenRec->m_isDuplicate )
+ {
+ // If the parent is not duplicated, just copy over the custom value
+ goto CopyPermission;
+ }
+ else
+ {
+ // Try to see if the Permission is there in the emit scope or not.
+ // If not, move it over still
+ if ( ImportHelper::FindPermission(
+ pMiniMdEmit,
+ pTokenRec->m_tkTo,
+ pRecImport->GetAction(),
+ &pmEmit) == S_OK )
+ {
+ // found a match
+ // <TODO>@FUTURE: more verification??</TODO>
+ fDuplicate = true;
+ }
+ else
+ {
+ // Parent is duplicated but the Permission is not. Still copy over the
+ // Permission.
+CopyPermission:
+ fDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddDeclSecurityRecord(&pRecEmit, (ULONG *)&pmEmit));
+ pmEmit = TokenFromRid(pmEmit, mdtPermission);
+
+ pRecEmit->Copy(pRecImport);
+
+ // set the parent
+ IfFailGo( pMiniMdEmit->PutToken(
+ TBL_DeclSecurity,
+ DeclSecurityRec::COL_Parent,
+ pRecEmit,
+ pTokenRec->m_tkTo) );
+
+ // move over the CustomAttribute blob value
+ IfFailGo(pMiniMdImport->getPermissionSetOfDeclSecurity(pRecImport, (const BYTE **)&pValue, &cbBlob));
+ IfFailGo(pMiniMdEmit->PutBlob(
+ TBL_DeclSecurity,
+ DeclSecurityRec::COL_PermissionSet,
+ pRecEmit,
+ pValue,
+ cbBlob));
+ }
+ }
+ pmEmit = TokenFromRid(pmEmit, mdtPermission);
+ pmImp = TokenFromRid(i, mdtPermission);
+
+ // Record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(pmImp, fDuplicate, pmEmit, &pTokenRec) );
+ }
+ else
+ {
+ // bad lookup map
+ _ASSERTE(!"bad state");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeDeclSecuritys()
+
+
+//*****************************************************************************
+// Merge Strings
+//*****************************************************************************
+HRESULT NEWMERGER::MergeStrings()
+{
+ HRESULT hr = NOERROR;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ for (UINT32 nIndex = 0; ;)
+ {
+ MetaData::DataBlob userString;
+ UINT32 nNextIndex;
+ UINT32 nEmitIndex;
+
+ hr = pMiniMdImport->GetUserStringAndNextIndex(
+ nIndex,
+ &userString,
+ &nNextIndex);
+ IfFailGo(hr);
+ if (hr == S_FALSE)
+ { // We reached the last user string
+ hr = S_OK;
+ break;
+ }
+ _ASSERTE(hr == S_OK);
+
+ // Skip empty strings
+ if (userString.IsEmpty())
+ {
+ nIndex = nNextIndex;
+ continue;
+ }
+
+ if (pMiniMdImport->GetFilterTable()->IsUserStringMarked(TokenFromRid(nIndex, mdtString)) == false)
+ {
+ // Process next user string in the heap
+ nIndex = nNextIndex;
+ continue;
+ }
+
+ IfFailGo(pMiniMdEmit->PutUserString(
+ userString,
+ &nEmitIndex));
+
+ IfFailGo(pCurTkMap->InsertNotFound(
+ TokenFromRid(nIndex, mdtString),
+ false,
+ TokenFromRid(nEmitIndex, mdtString),
+ &pTokenRec));
+
+ // Process next user string in the heap
+ nIndex = nNextIndex;
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeStrings()
+
+// Helper method to merge the module-level security critical attributes
+// Strips all module-level security critical attribute [that won't be ultimately needed]
+// Returns:
+// FAILED(hr): Failure occurred retrieving metadata or parsing scopes
+// S_OK: Attribute should be merged into final output scope
+// S_FALSE: Attribute should be ignored/dropped from output scope
+HRESULT NEWMERGER::MergeSecurityCriticalModuleLevelAttributes(
+ MergeImportData* pImportData, // import scope
+ mdToken tkParentImp, // parent token with attribute
+ TOKENREC* pTypeRec, // token record of attribute ctor
+ mdToken mrSecurityTreatAsSafeAttributeCtor, // 'generic' TAS attribute token
+ mdToken mrSecurityTransparentAttributeCtor, // 'generic' Transparent attribute token
+ mdToken mrSecurityCriticalExplicitAttributeCtor, // 'generic' Critical attribute token
+ mdToken mrSecurityCriticalEverythingAttributeCtor)
+{
+ HRESULT hr = S_OK;
+
+ // if ANY assembly-level critical attributes were specified, then we'll output
+ // one assembly-level Critical(Explicit) attribute only
+ // AND if this scope has tags
+ if (ISSCS_Unknown != pImportData->m_isscsSecurityCriticalStatus)
+ {
+ _ASSERTE(ISSCS_Unknown != m_isscsSecurityCritical);
+ // drop only assembly-level attributes
+ TypeRefRec* pTypeRefRec;
+ // metadata emitter
+ CMiniMdRW* pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // if compiler is generating a module - then this will be a module token
+ LPCSTR szTypeRefName;
+ if (tkParentImp == MODULEDEFTOKEN ||
+ // otherwise, if merging assemblies, we have a fake type ref called MODULE_CA_LOCATION
+ (TypeFromToken(tkParentImp) == mdtTypeRef &&
+ (IsAttributeFromNamespace(pMiniMdImport, tkParentImp,
+ COR_COMPILERSERVICE_NAMESPACE, COR_MSCORLIB_NAME,
+ &pTypeRefRec) == S_OK) &&
+ (pMiniMdImport->getNameOfTypeRef(pTypeRefRec, &szTypeRefName) == S_OK) &&
+ (strcmp(MODULE_CA_TYPENAME, szTypeRefName) == 0)))
+ {
+ // drop the TAS attribute (unless all scopes have TAS)
+ if ( pTypeRec->m_tkTo == mrSecurityTreatAsSafeAttributeCtor )
+ {
+ if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityTreatAsSafe) ==
+ ISSCS_SecurityTreatAsSafe)
+ {
+ _ASSERTE((pImportData->m_isscsSecurityCriticalStatus & ISSCS_SecurityTreatAsSafe) ==
+ ISSCS_SecurityTreatAsSafe);
+ return S_OK;
+ }
+ return S_FALSE;
+ }
+ // drop the Transparent attribute (unless all scopes have Transparent)
+ else if (pTypeRec->m_tkTo == mrSecurityTransparentAttributeCtor)
+ {
+ if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityTransparent) ==
+ ISSCS_SecurityTransparent)
+ {
+ _ASSERTE((pImportData->m_isscsSecurityCriticalStatus & ISSCS_SecurityTransparent) ==
+ ISSCS_SecurityTransparent);
+ return S_OK;
+ }
+ return S_FALSE;
+ }
+ else if (pTypeRec->m_tkTo == mrSecurityCriticalExplicitAttributeCtor)
+ {
+ // if NOT Critical Everything, then leave the Critical.Explicit attribute
+ // the Critical.Explicit attribute will be used as the final global attribute
+ if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityCriticalEverything) !=
+ ISSCS_SecurityCriticalEverything)
+ {
+ _ASSERTE((pImportData->m_isscsSecurityCriticalStatus & ISSCS_SecurityCriticalExplicit) ==
+ ISSCS_SecurityCriticalExplicit);
+ return S_OK;
+ }
+ else
+ {
+ // drop this attribute
+ return S_FALSE;
+ }
+ }
+ else if (pTypeRec->m_tkTo == mrSecurityCriticalEverythingAttributeCtor)
+ {
+ // OPTIMIZATION: if all attributes are Critical.Everything,
+ // then leave the global Critical attribute
+ if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityCriticalEverything) ==
+ ISSCS_SecurityCriticalEverything)
+ {
+ _ASSERTE((pImportData->m_isscsSecurityCriticalStatus & ISSCS_SecurityCriticalEverything) ==
+ ISSCS_SecurityCriticalEverything);
+ return S_OK;
+ }
+ else
+ {
+ // drop this attribute
+ return S_FALSE;
+ }
+ }
+ }
+ }
+
+ return hr;
+} // NEWMERGER::MergeSecurityCriticalModuleLevelAttributes
+
+// HELPER: Retrieve the meta-data info related to SecurityCritical
+HRESULT NEWMERGER::RetrieveStandardSecurityCriticalMetaData(
+ mdAssemblyRef& tkMscorlib,
+ mdTypeRef& securityEnum,
+ BYTE*& rgSigBytesSecurityCriticalEverythingCtor,
+ DWORD& dwSigEverythingSize,
+ BYTE*& rgSigBytesSecurityCriticalExplicitCtor,
+ DWORD& dwSigExplicitSize)
+{
+ HRESULT hr = S_OK;
+
+ CMiniMdRW* emit = GetMiniMdEmit();
+
+ // get typeref for mscorlib
+ BYTE pbMscorlibToken[] = COR_MSCORLIB_TYPEREF;
+ BYTE* pCurr = rgSigBytesSecurityCriticalEverythingCtor;
+
+ IfFailGo(ImportHelper::FindAssemblyRef(emit,
+ COR_MSCORLIB_NAME,
+ NULL,
+ pbMscorlibToken,
+ sizeof(pbMscorlibToken),
+ asm_rmj,
+ asm_rmm,
+ asm_rup,
+ asm_rpt,
+ 0,
+ &tkMscorlib));
+
+ IfFailGo(m_pRegMetaEmit->DefineTypeRefByName(tkMscorlib,
+ COR_SECURITYCRITICALSCOPE_ENUM_W,
+ &securityEnum));
+
+ // build the constructor sig that takes SecurityCriticalScope argument
+ if (rgSigBytesSecurityCriticalEverythingCtor)
+ {
+ *pCurr++ = IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS;
+ *pCurr++ = COR_SECURITYCRITICAL_CTOR_ARGCOUNT_SCOPE_EVERYTHING; // one argument to constructor
+ *pCurr++ = ELEMENT_TYPE_VOID;
+ *pCurr++ = ELEMENT_TYPE_VALUETYPE;
+ pCurr += CorSigCompressToken(securityEnum, pCurr);
+ dwSigEverythingSize = (DWORD)(pCurr - rgSigBytesSecurityCriticalEverythingCtor);
+ _ASSERTE(dwSigEverythingSize <= COR_SECURITYCRITICAL_CTOR_SCOPE_SIG_MAX_SIZE);
+ }
+
+ // if Explicit ctor is requested
+ if (rgSigBytesSecurityCriticalExplicitCtor)
+ {
+ // build the constructor sig that has NO arguments
+ pCurr = rgSigBytesSecurityCriticalExplicitCtor;
+ *pCurr++ = IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS;
+ *pCurr++ = COR_SECURITYCRITICAL_CTOR_ARGCOUNT_NO_SCOPE; // no arguments to constructor
+ *pCurr++ = ELEMENT_TYPE_VOID;
+ dwSigExplicitSize = (DWORD)(pCurr - rgSigBytesSecurityCriticalExplicitCtor);
+ _ASSERTE(dwSigExplicitSize <= COR_SECURITYCRITICAL_CTOR_NO_SCOPE_SIG_MAX_SIZE);
+ }
+
+ErrExit:
+ return hr;
+} // NEWMERGER::RetrieveStandardSecurityCriticalMetaData
+
+//*****************************************************************************
+// Merge CustomAttributes
+//*****************************************************************************
+HRESULT NEWMERGER::MergeCustomAttributes()
+{
+
+ HRESULT hr = NOERROR;
+ CustomAttributeRec *pRecImport = NULL;
+ CustomAttributeRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ ULONG iCount;
+ ULONG i;
+ mdToken tkParentImp; // Token of attributed object (parent).
+ TOKENREC *pTokenRec; // Parent's remap.
+ mdToken tkType; // Token of attribute's type.
+ TOKENREC *pTypeRec; // Type's remap.
+ void const *pValue; // The actual value.
+ ULONG cbBlob; // Size of the value.
+ mdToken cvImp;
+ mdToken cvEmit;
+ bool fDuplicate;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ TypeRefRec *pTypeRefRec;
+ ULONG cTypeRefRecs;
+ mdToken mrSuppressMergeCheckAttributeCtor = mdTokenNil;
+ mdToken mrSecurityCriticalExplicitAttributeCtor = mdTokenNil;
+ mdToken mrSecurityCriticalEverythingAttributeCtor = mdTokenNil;
+ mdToken mrSecurityTransparentAttributeCtor = mdTokenNil;
+ mdToken mrSecurityTreatAsSafeAttributeCtor = mdTokenNil;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ // Find out the TypeRef referring to our library's System.CompilerServices.SuppressMergeCheckAttribute,
+ // System.Security.SecurityCriticalAttribute, System.Security.SecurityTransparentAttribute, and
+ // System.Security.SecurityTreatAsSafeAttibute
+ cTypeRefRecs = pMiniMdEmit->getCountTypeRefs();
+
+ { // retrieve global attribute TypeRefs
+
+ mdAssemblyRef tkMscorlib = mdTokenNil;
+ mdTypeRef securityEnum = mdTokenNil;
+
+ NewArrayHolder<BYTE> rgSigBytesSecurityCriticalEverythingCtor(new (nothrow)BYTE[COR_SECURITYCRITICAL_CTOR_SCOPE_SIG_MAX_SIZE]);
+ BYTE* pSigBytesSecurityCriticalEverythingCtor = rgSigBytesSecurityCriticalEverythingCtor.GetValue();
+ IfFailGo((pSigBytesSecurityCriticalEverythingCtor == NULL)?E_OUTOFMEMORY:S_OK);
+ DWORD dwSigEverythingSize = 0;
+
+ NewArrayHolder<BYTE> rgSigBytesSecurityCriticalExplicitCtor(new (nothrow)BYTE[COR_SECURITYCRITICAL_CTOR_NO_SCOPE_SIG_MAX_SIZE]);
+ BYTE* pSigBytesSecurityCriticalExplicitCtor = rgSigBytesSecurityCriticalExplicitCtor.GetValue();
+ IfFailGo((pSigBytesSecurityCriticalExplicitCtor == NULL)?E_OUTOFMEMORY:S_OK);
+ DWORD dwSigExplicitSize = 0;
+
+ // retrieve security critical metadata info if necessary
+ if(ISSCS_Unknown != m_isscsSecurityCritical)
+ {
+
+ hr = RetrieveStandardSecurityCriticalMetaData(
+ tkMscorlib,
+ securityEnum,
+ pSigBytesSecurityCriticalEverythingCtor,
+ dwSigEverythingSize,
+ pSigBytesSecurityCriticalExplicitCtor,
+ dwSigExplicitSize);
+
+ }
+
+ // Search for the TypeRef.
+ for (i = 1; i <= cTypeRefRecs; i++)
+ {
+ mdToken tkTmp = TokenFromRid(i,mdtTypeRef);
+
+ if (IsAttributeFromNamespace(pMiniMdEmit, tkTmp,
+ COR_COMPILERSERVICE_NAMESPACE, COR_MSCORLIB_NAME,
+ &pTypeRefRec) == S_OK)
+ {
+ LPCSTR szNameOfTypeRef;
+ IfFailGo(pMiniMdEmit->getNameOfTypeRef(pTypeRefRec, &szNameOfTypeRef));
+ if (strcmp(szNameOfTypeRef, COR_SUPPRESS_MERGE_CHECK_ATTRIBUTE) == 0)
+ {
+ hr = ImportHelper::FindMemberRef(
+ pMiniMdEmit, tkTmp,
+ COR_CTOR_METHOD_NAME,
+ NULL, 0,
+ &mrSuppressMergeCheckAttributeCtor);
+ if (S_OK == hr) continue;
+ }
+ }
+ else
+ // if we are merging security critical attributes, then look for transparent-related attributes
+ if ((ISSCS_Unknown != m_isscsSecurityCritical) &&
+ (IsAttributeFromNamespace(pMiniMdEmit, tkTmp,
+ COR_SECURITYCRITICAL_ATTRIBUTE_NAMESPACE, COR_MSCORLIB_NAME,
+ &pTypeRefRec) == S_OK))
+ {
+ LPCSTR szNameOfTypeRef;
+ IfFailGo(pMiniMdEmit->getNameOfTypeRef(pTypeRefRec, &szNameOfTypeRef));
+
+ // look for the SecurityCritical attribute
+ if (strcmp(szNameOfTypeRef, COR_SECURITYCRITICAL_ATTRIBUTE) == 0)
+ {
+ // since the SecurityCritical attribute can be either
+ // parameterless constructor or SecurityCriticalScope constructor, we
+ // look for both
+ hr = ImportHelper::FindMemberRef(
+ pMiniMdEmit, tkTmp,
+ COR_CTOR_METHOD_NAME,
+ rgSigBytesSecurityCriticalEverythingCtor.GetValue(), dwSigEverythingSize,
+ &mrSecurityCriticalEverythingAttributeCtor);
+ if (S_OK == hr) continue;
+ hr = ImportHelper::FindMemberRef(
+ pMiniMdEmit, tkTmp,
+ COR_CTOR_METHOD_NAME,
+ rgSigBytesSecurityCriticalExplicitCtor.GetValue(), dwSigExplicitSize,
+ &mrSecurityCriticalExplicitAttributeCtor);
+ if (S_OK == hr) continue;
+ }
+ else
+ // look for the SecurityTransparent attribute
+ if (strcmp(szNameOfTypeRef, COR_SECURITYTRANSPARENT_ATTRIBUTE) == 0)
+ {
+ hr = ImportHelper::FindMemberRef(
+ pMiniMdEmit, tkTmp,
+ COR_CTOR_METHOD_NAME,
+ NULL, 0,
+ &mrSecurityTransparentAttributeCtor);
+ if (S_OK == hr) continue;
+ }
+ else
+ // look for the SecurityTreatAsSafe attribute
+ if (strcmp(szNameOfTypeRef, COR_SECURITYTREATASSAFE_ATTRIBUTE) == 0)
+ {
+ hr = ImportHelper::FindMemberRef(
+ pMiniMdEmit, tkTmp,
+ COR_CTOR_METHOD_NAME,
+ NULL, 0,
+ &mrSecurityTreatAsSafeAttributeCtor);
+ if (S_OK == hr) continue;
+ }
+ }
+ hr = S_OK; // ignore failures since the attribute may not be used
+ }
+ }
+
+ // Loop over every module scope
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // We know that the filter table is not null here. Tell PREFIX that we know it.
+ PREFIX_ASSUME( pMiniMdImport->GetFilterTable() != NULL );
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountCustomAttributes();
+
+ // loop through all CustomAttribute
+ for (i = 1; i <= iCount; i++)
+ {
+ // compare it with the emit scope
+ IfFailGo(pMiniMdImport->GetCustomAttributeRecord(i, &pRecImport));
+ tkParentImp = pMiniMdImport->getParentOfCustomAttribute(pRecImport);
+ tkType = pMiniMdImport->getTypeOfCustomAttribute(pRecImport);
+ IfFailGo(pMiniMdImport->getValueOfCustomAttribute(pRecImport, (const BYTE **)&pValue, &cbBlob));
+
+ // only merge those CustomAttributes that are marked
+ if ( pMiniMdImport->GetFilterTable()->IsCustomAttributeMarked(TokenFromRid(i, mdtCustomAttribute)) == false)
+ continue;
+
+ // Check the type of the CustomAttribute. If it is not marked, then we don't need to move over the CustomAttributes.
+ // This will only occur for compiler defined discardable CAs during linking.
+ //
+ if ( pMiniMdImport->GetFilterTable()->IsTokenMarked(tkType) == false)
+ continue;
+
+ if ( pCurTkMap->Find(tkParentImp, &pTokenRec) )
+ {
+ // If the From token type is different from the To token's type, we have optimized the ref to def.
+ // In this case, we are dropping the CA associated with the Ref tokens.
+ //
+ if (TypeFromToken(tkParentImp) == TypeFromToken(pTokenRec->m_tkTo))
+ {
+
+ // If tkParentImp is a MemberRef and it is also mapped to a MemberRef in the merged scope with a MethodDef
+ // parent, then it is a MemberRef optimized to a MethodDef. We are keeping the MemberRef because it is a
+ // vararg call. So we can drop CAs on this MemberRef.
+ if (TypeFromToken(tkParentImp) == mdtMemberRef)
+ {
+ MemberRefRec *pTempRec;
+ IfFailGo(pMiniMdEmit->GetMemberRefRecord(RidFromToken(pTokenRec->m_tkTo), &pTempRec));
+ if (TypeFromToken(pMiniMdEmit->getClassOfMemberRef(pTempRec)) == mdtMethodDef)
+ continue;
+ }
+
+
+ if (! pCurTkMap->Find(tkType, &pTypeRec) )
+ {
+ _ASSERTE(!"CustomAttribute Type not found in output scope");
+ IfFailGo(META_E_BADMETADATA);
+ }
+
+ // Determine if we need to copy or ignore security-critical-related attributes
+ hr = MergeSecurityCriticalModuleLevelAttributes(
+ pImportData, tkParentImp, pTypeRec,
+ mrSecurityTreatAsSafeAttributeCtor, mrSecurityTransparentAttributeCtor,
+ mrSecurityCriticalExplicitAttributeCtor,
+ mrSecurityCriticalEverythingAttributeCtor);
+ IfFailGo(hr);
+ // S_FALSE means skip attribute
+ if (hr == S_FALSE) continue;
+ // S_OK means consider copying attribute
+
+ // if it's the SuppressMergeCheckAttribute, don't copy it
+ if ( pTypeRec->m_tkTo == mrSuppressMergeCheckAttributeCtor )
+ {
+ continue;
+ }
+
+ if ( pTokenRec->m_isDuplicate)
+ {
+ // Try to see if the custom value is there in the emit scope or not.
+ // If not, move it over still
+ hr = ImportHelper::FindCustomAttributeByToken(
+ pMiniMdEmit,
+ pTokenRec->m_tkTo,
+ pTypeRec->m_tkTo,
+ pValue,
+ cbBlob,
+ &cvEmit);
+
+ if ( hr == S_OK )
+ {
+ // found a match
+ // <TODO>@FUTURE: more verification??</TODO>
+ fDuplicate = true;
+ }
+ else
+ {
+ TypeRefRec *pAttributeTypeRefRec;
+ // We need to allow additive merge on TypeRef for CustomAttributes because compiler
+ // could build module but not assembly. They are hanging of Assembly level CAs on a bogus
+ // TypeRef.
+ // Also allow additive merge for CAs from CompilerServices and Microsoft.VisualC
+ if (tkParentImp == MODULEDEFTOKEN
+ || TypeFromToken(tkParentImp) == mdtTypeRef
+ || (IsAttributeFromNamespace(pMiniMdImport, tkType,
+ COR_COMPILERSERVICE_NAMESPACE, COR_MSCORLIB_NAME,
+ &pAttributeTypeRefRec) == S_OK)
+ || (IsAttributeFromNamespace(pMiniMdImport, tkType,
+ COR_MISCBITS_NAMESPACE, COR_MISCBITS_NAMESPACE,
+ &pAttributeTypeRefRec) == S_OK))
+ {
+ // clear the error
+ hr = NOERROR;
+
+ // custom value of module token! Copy over the custom value
+ goto CopyCustomAttribute;
+ }
+
+ // another case to support additive merge if the CA on MehtodDef is
+ // HandleProcessCorruptedStateExceptionsAttribute
+ if ( TypeFromToken(tkParentImp) == mdtMethodDef && tkType == pImportData->m_tkHandleProcessCorruptedStateCtor)
+ {
+ // clear the error
+ hr = NOERROR;
+
+ // custom value of module token! Copy over the custom value
+ goto CopyCustomAttribute;
+ }
+ CheckContinuableErrorEx(META_E_MD_INCONSISTENCY, pImportData, TokenFromRid(i, mdtCustomAttribute));
+ }
+ }
+ else
+ {
+CopyCustomAttribute:
+ if ((m_dwMergeFlags & DropMemberRefCAs) && TypeFromToken(pTokenRec->m_tkTo) == mdtMemberRef)
+ {
+ // CustomAttributes associated with MemberRef. If the parent of MemberRef is a MethodDef or FieldDef, drop
+ // the custom attribute.
+ MemberRefRec *pMemberRefRec;
+ IfFailGo(pMiniMdEmit->GetMemberRefRecord(RidFromToken(pTokenRec->m_tkTo), &pMemberRefRec));
+ mdToken mrParent = pMiniMdEmit->getClassOfMemberRef(pMemberRefRec);
+ if (TypeFromToken(mrParent) == mdtMethodDef || TypeFromToken(mrParent) == mdtFieldDef)
+ {
+ // Don't bother to copy over
+ continue;
+ }
+ }
+
+ // Parent is duplicated but the custom value is not. Still copy over the
+ // custom value.
+ fDuplicate = false;
+ IfFailGo(pMiniMdEmit->AddCustomAttributeRecord(&pRecEmit, (ULONG *)&cvEmit));
+ cvEmit = TokenFromRid(cvEmit, mdtCustomAttribute);
+
+ // set the parent
+ IfFailGo( pMiniMdEmit->PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Parent, pRecEmit, pTokenRec->m_tkTo) );
+ // set the type
+ IfFailGo( pMiniMdEmit->PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Type, pRecEmit, pTypeRec->m_tkTo));
+
+ // move over the CustomAttribute blob value
+ IfFailGo(pMiniMdImport->getValueOfCustomAttribute(pRecImport, (const BYTE **)&pValue, &cbBlob));
+
+ IfFailGo( pMiniMdEmit->PutBlob(TBL_CustomAttribute, CustomAttributeRec::COL_Value, pRecEmit, pValue, cbBlob));
+ IfFailGo( pMiniMdEmit->AddCustomAttributesToHash(cvEmit) );
+ }
+ cvEmit = TokenFromRid(cvEmit, mdtCustomAttribute);
+ cvImp = TokenFromRid(i, mdtCustomAttribute);
+
+ // Record the token movement
+ IfFailGo( pCurTkMap->InsertNotFound(cvImp, pTokenRec->m_isDuplicate, cvEmit, &pTokenRec) );
+ }
+ }
+ else
+ {
+
+ // either bad lookup map or bad metadata
+ _ASSERTE(!"Bad state");
+ IfFailGo( META_E_BADMETADATA );
+ }
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeCustomAttributes()
+
+//*******************************************************************************
+// Helper to check if input scope has assembly-level security transparent awareness (either SecurityTransparent or SecurityCritical)
+// SIDE EFFECT: pImportData->m_isscsSecurityCriticalStatus will be explicitly set [same value as return value]
+// SecurityCritical.Explicit attribute injection occurs for all scopes that have tags (e.g. NOT ISSCS_Unknown)
+// If the tagged scopes are all SecurityCritical.Everything, then the final attribute should be SecurityCritical.Everything
+// anyway. Otherwise, at least one SecurityCritical.Explicit tag will be used/injected
+//*******************************************************************************
+InputScopeSecurityCriticalStatus NEWMERGER::CheckInputScopeIsCritical(MergeImportData* pImportData, HRESULT& hr)
+{
+ hr = S_OK;
+
+ // the attribute should be in a known state no matter how we return from this function
+ // default to no attribute explicitly specified
+ pImportData->m_isscsSecurityCriticalStatus = ISSCS_Unknown;
+
+ mdTypeRef fakeModuleTypeRef = mdTokenNil;
+ mdAssemblyRef tkMscorlib = mdTokenNil;
+
+ // TODO: Should we remove the ability to disable merging critical attributes?
+ if (g_fRefShouldMergeCriticalChecked == FALSE)
+ {
+ // shouldn't require thread safety lock
+ g_fRefShouldMergeCritical = (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_MergeCriticalAttributes) != 0);
+ g_fRefShouldMergeCriticalChecked = TRUE;
+ }
+
+ // return no merge needed, if the merge critical attribute setting is not enabled.
+ if (!g_fRefShouldMergeCritical) return ISSCS_Unknown;
+
+ // get typeref for mscorlib
+ BYTE pbMscorlibToken[] = COR_MSCORLIB_TYPEREF;
+
+ CMiniMdRW* pImportedMiniMd = &pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd;
+
+ if (S_OK != ImportHelper::FindAssemblyRef(pImportedMiniMd,
+ COR_MSCORLIB_NAME,
+ NULL,
+ pbMscorlibToken,
+ sizeof(pbMscorlibToken),
+ asm_rmj,
+ asm_rmm,
+ asm_rup,
+ asm_rpt,
+ 0,
+ &tkMscorlib))
+ {
+ // there isn't an mscorlib ref here... we can't have the security critical attribute
+ return ISSCS_Unknown;
+ }
+
+ if (S_OK != ImportHelper::FindTypeRefByName(pImportedMiniMd,
+ tkMscorlib,
+ COR_COMPILERSERVICE_NAMESPACE,
+ MODULE_CA_TYPENAME,
+ &fakeModuleTypeRef))
+ {
+ // for now let use the fake module ref as the assembly def
+ fakeModuleTypeRef = 0x000001;
+ }
+
+ // Check the input scope for TreatAsSafe
+ if (S_OK == ImportHelper::GetCustomAttributeByName(pImportedMiniMd,
+ fakeModuleTypeRef, // This is the assembly def token
+ COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL,
+ NULL,
+ NULL))
+ {
+ pImportData->m_isscsSecurityCriticalStatus |= ISSCS_SecurityTreatAsSafe;
+ }
+
+ // Check the input scope for security transparency awareness
+ // For example, the assembly is marked SecurityTransparent, SecurityCritical(Explicit), or SecurityCritical(Everything)
+
+
+ const void *pbData = NULL; // [OUT] Put pointer to data here.
+ ULONG cbData = 0; // number of bytes in pbData
+
+ // Check if the SecurityTransparent attribute is present
+ if (S_OK == ImportHelper::GetCustomAttributeByName(pImportedMiniMd,
+ fakeModuleTypeRef, // This is the assembly def token
+ COR_SECURITYTRANSPARENT_ATTRIBUTE_FULL,
+ NULL,
+ NULL))
+ {
+ pImportData->m_isscsSecurityCriticalStatus |= ISSCS_SecurityTransparent;
+ }
+ else
+ // Check if the SecurityCritical attribute is present
+ if (S_OK == ImportHelper::GetCustomAttributeByName(pImportedMiniMd,
+ fakeModuleTypeRef, // This is the assembly def token
+ COR_SECURITYCRITICAL_ATTRIBUTE_FULL,
+ &pbData,
+ &cbData))
+ {
+ // find out if critical everything or explicit
+
+ // default to critical
+ pImportData->m_isscsSecurityCriticalStatus = ISSCS_SecurityCritical;
+
+ BYTE rgSecurityCriticalEverythingCtorValue[] = COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EVERYTHING;
+ // if value is non-0 (i.e. 1), then mark as SecurityCritical everything, otherwise, explicit
+ if (NULL != pbData && cbData == 8 &&
+ memcmp(rgSecurityCriticalEverythingCtorValue, pbData, cbData) == 0)
+ {
+ pImportData->m_isscsSecurityCriticalStatus |= ISSCS_SecurityCriticalEverything;
+ }
+ else
+ {
+ pImportData->m_isscsSecurityCriticalStatus |= ISSCS_SecurityCriticalExplicit;
+ }
+ }
+
+ return pImportData->m_isscsSecurityCriticalStatus;
+} // HRESULT NEWMERGER::CheckInputScopeIsCritical()
+
+//*******************************************************************************
+// Helper to merge security critical annotations across assemblies and types
+//*******************************************************************************
+HRESULT NEWMERGER::MergeSecurityCriticalAttributes()
+{
+ // if no assembly-level critical attributes were specified, then none are needed,
+ // and no need to do special attribute merging
+ if (ISSCS_Unknown == m_isscsSecurityCritical)
+ {
+ return S_OK;
+ }
+ // or if the global-scope already has TAS/Critical.Everything, then ignore individual type fixes
+ else if ((ISSCS_SECURITYCRITICAL_LEGACY & m_isscsSecurityCriticalAllScopes) == ISSCS_SECURITYCRITICAL_LEGACY)
+ {
+ return S_OK;
+ }
+
+ HRESULT hr = S_OK;
+
+ CMiniMdRW* emit = GetMiniMdEmit();
+ // The attribute we want to decorate all of the types with has not been defined.
+ mdMemberRef tkSecurityCriticalEverythingAttribute = mdTokenNil;
+ mdMemberRef tkSecurityTreatAsSafeAttribute = mdTokenNil;
+ mdMemberRef tkSecuritySafeCriticalAttribute = mdTokenNil;
+
+ mdAssemblyRef tkMscorlib = mdTokenNil;
+ mdTypeRef fakeModuleTypeRef = mdTokenNil;
+ mdTypeRef securityEnum = mdTokenNil;
+
+ DWORD dwSigSize;
+ BYTE* rgSigBytesSecurityCriticalExplicitCtor = 0;
+ DWORD dwSigSize_TEMP;
+
+ BYTE rgSigBytesTreatAsSafeCtor[] = {IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS, 0x00, ELEMENT_TYPE_VOID};
+
+ BYTE rgSecurityCriticalEverythingCtorValue[] = COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EVERYTHING;
+
+
+ mdTypeRef tkSecurityCriticalEverythingAttributeType = mdTokenNil;
+ mdTypeRef tkSecurityTreatAsSafeAttributeType = mdTokenNil;
+
+ NewArrayHolder<BYTE> rgSigBytesSecurityCriticalEverythingCtor(new (nothrow)BYTE[COR_SECURITYCRITICAL_CTOR_SCOPE_SIG_MAX_SIZE]);
+ BYTE* pSigBytesSecurityCriticalEverythingCtor = rgSigBytesSecurityCriticalEverythingCtor.GetValue();
+ IfFailGo((pSigBytesSecurityCriticalEverythingCtor == NULL)?E_OUTOFMEMORY:S_OK);
+
+ IfFailGo(RetrieveStandardSecurityCriticalMetaData(
+ tkMscorlib,
+ securityEnum,
+ pSigBytesSecurityCriticalEverythingCtor,
+ dwSigSize,
+ rgSigBytesSecurityCriticalExplicitCtor,
+ dwSigSize_TEMP));
+
+ if (S_OK != ImportHelper::FindTypeRefByName(emit,
+ tkMscorlib,
+ COR_COMPILERSERVICE_NAMESPACE,
+ MODULE_CA_TYPENAME,
+ &fakeModuleTypeRef))
+ {
+ // for now let use the fake module ref as the assembly def
+ fakeModuleTypeRef = 0x000001;
+ }
+
+ IfFailGo(m_pRegMetaEmit->DefineTypeRefByName(
+ tkMscorlib, COR_SECURITYCRITICAL_ATTRIBUTE_FULL_W, &tkSecurityCriticalEverythingAttributeType));
+
+ IfFailGo(m_pRegMetaEmit->DefineMemberRef(tkSecurityCriticalEverythingAttributeType,
+ COR_CONSTRUCTOR_METADATA_IDENTIFIER,
+ rgSigBytesSecurityCriticalEverythingCtor.GetValue(),
+ dwSigSize,
+ &tkSecurityCriticalEverythingAttribute));
+
+ IfFailGo(m_pRegMetaEmit->DefineTypeRefByName(
+ tkMscorlib, COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL_W,
+ &tkSecurityTreatAsSafeAttributeType));
+
+ IfFailGo(m_pRegMetaEmit->DefineMemberRef(tkSecurityTreatAsSafeAttributeType,
+ COR_CONSTRUCTOR_METADATA_IDENTIFIER,
+ rgSigBytesTreatAsSafeCtor,
+ sizeof(rgSigBytesTreatAsSafeCtor),
+ &tkSecurityTreatAsSafeAttribute));
+
+
+ // place this block in a new scope so that we can safely goto past it
+ {
+ mdTypeRef tkSecuritySafeCriticalAttributeType = mdTokenNil;
+ if (FAILED (hr = m_pRegMetaEmit->DefineTypeRefByName(tkMscorlib, COR_SECURITYSAFECRITICAL_ATTRIBUTE_FULL_W,
+ &tkSecuritySafeCriticalAttributeType)))
+ {
+ _ASSERTE(!"Couldn't Emit a Typeref for SafeCritical attribute");
+ return hr;
+ }
+
+ BYTE rgSigBytesSafeCriticalCtor[] = {IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS, 0x00, ELEMENT_TYPE_VOID};
+ if (FAILED(hr = m_pRegMetaEmit->DefineMemberRef(tkSecuritySafeCriticalAttributeType,
+ W(".ctor"),
+ rgSigBytesSafeCriticalCtor,
+ sizeof(rgSigBytesSafeCriticalCtor),
+ &tkSecuritySafeCriticalAttribute)))
+ {
+ _ASSERTE(!"Couldn't Emit a MemberRef for SafeCritical attribute .ctor");
+ return hr;
+ }
+ }
+
+
+ for (MergeImportData* pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // if the import is marked TAS, then we need to explicitly mark each type as TAS
+ // if the import is marked Crit/Everything, then we need to explicitly mark each type as Crit
+ // if the import is not marked at all, then we need to explicitly mark each type TAS/Crit
+
+ // if the import is marked ONLY Crit/Explicit or ONLY Transparent then we can ignore it
+ if (ISSCS_SecurityTransparent == pImportData->m_isscsSecurityCriticalStatus ||
+ ISSCS_SecurityCriticalExplicit == pImportData->m_isscsSecurityCriticalStatus) continue;
+
+ // Run through the scopes that need to have their types decorated with this attribute
+ MDTOKENMAP*pCurTKMap = pImportData->m_pMDTokenMap;
+ BYTE rgTreatAsSafeCtorValue[] = COR_SECURITYTREATASSAFE_ATTRIBUTE_VALUE;
+
+ BOOL fMarkEachTokenAsCritical = FALSE;
+ // if the import is unmarked or marked Crit/Everything,
+ // then we need to explicitly mark each token as Crit
+ // Unless the the global scope already has SecurityCritical.Everything
+ if (((ISSCS_SecurityCriticalEverything & m_isscsSecurityCriticalAllScopes) != ISSCS_SecurityCriticalEverything) &&
+ (((ISSCS_SecurityCriticalEverything & pImportData->m_isscsSecurityCriticalStatus) == ISSCS_SecurityCriticalEverything ) ||
+
+ // OR this scope is NOT transparent or critical-explicit
+ (ISSCS_SecurityTransparent & pImportData->m_isscsSecurityCriticalStatus) == 0 ||
+ (ISSCS_SecurityCritical & pImportData->m_isscsSecurityCriticalStatus) == 0 ||
+
+ // OR this scope is UNKNOWN
+ (ISSCS_Unknown == (ISSCS_SECURITYCRITICAL_FLAGS & pImportData->m_isscsSecurityCriticalStatus))))
+ {
+ fMarkEachTokenAsCritical = TRUE;
+ }
+
+ BOOL fMarkEachTokenAsSafe = FALSE;
+ // if the import is unmarked or marked TAS,
+ // then we need to explicitly mark each token as TAS
+ // Unless the the global scope already has SecurityTreatAsSafe
+ if (((ISSCS_SecurityTreatAsSafe & m_isscsSecurityCriticalAllScopes) != ISSCS_SecurityTreatAsSafe) &&
+ ((ISSCS_SecurityTreatAsSafe & pImportData->m_isscsSecurityCriticalStatus) ||
+ ISSCS_Unknown == (pImportData->m_isscsSecurityCriticalStatus & ISSCS_SECURITYCRITICAL_FLAGS)))
+ {
+ fMarkEachTokenAsSafe = TRUE;
+ }
+
+ BYTE rgSafeCriticalCtorValue[] = {0x01, 0x00, 0x00 ,0x00};
+
+ for (int i = 0; i < pCurTKMap->Count(); i++)
+ {
+ TOKENREC* pRec = pCurTKMap->Get(i);
+ BOOL fInjectSecurityAttributes = FALSE;
+
+ // skip empty records
+ if (pRec->IsEmpty()) continue;
+
+ // If this scope contained a typeref that was resolved to a typedef, let's not mark it. We'll let the owner
+ // of the actual typedef decide if that type should be marked.
+ if ((TypeFromToken(pRec->m_tkFrom) == mdtTypeRef) && (TypeFromToken(pRec->m_tkTo) == mdtTypeDef))
+ continue;
+
+ // Same for method refs/method defs
+ if ((TypeFromToken(pRec->m_tkFrom) == mdtMemberRef) && (TypeFromToken(pRec->m_tkTo) == mdtMethodDef))
+ continue;
+
+ // check for typedefs, but don't put this on the global typedef
+ if ((TypeFromToken(pRec->m_tkTo) == mdtTypeDef) && (pRec->m_tkTo != TokenFromRid(1, mdtTypeDef)))
+ {
+ // by default we will inject
+ fInjectSecurityAttributes = TRUE;
+ // except for Enums
+ DWORD dwClassAttrs = 0;
+ mdTypeRef crExtends = mdTokenNil;
+
+ if (FAILED(hr = m_pRegMetaEmit->GetTypeDefProps(pRec->m_tkTo, NULL, NULL, 0 , &dwClassAttrs, &crExtends)))
+ {
+ // TODO: should we fail ??
+ }
+
+ // check for Enum types
+ if (!IsNilToken(crExtends) && (TypeFromToken(crExtends)==mdtTypeRef))
+ {
+ // get the namespace and the name for this token
+ CMiniMdRW *pMiniMd = GetMiniMdEmit();
+ TypeRefRec *pTypeRefRec;
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(crExtends), &pTypeRefRec));
+ LPCSTR szNamespace;
+ LPCSTR szName;
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace));;
+ IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szName));
+ // check for System.Enum
+ BOOL bIsEnum = (!strcmp(szNamespace,"System"))&&(!strcmp(szName,"Enum"));
+ if (bIsEnum)
+ {
+ fInjectSecurityAttributes = FALSE;
+ }
+ }
+ }
+ else // check for global method defs
+ if (TypeFromToken(pRec->m_tkTo) == mdtMethodDef)
+ {
+ int isGlobal = 0;
+ if (!FAILED(m_pRegMetaEmit->IsGlobal(pRec->m_tkTo, &isGlobal)))
+ {
+ // check for global methods
+ if (isGlobal != 0)
+ {
+ fInjectSecurityAttributes = TRUE;
+ }
+ }
+ }
+
+ if (fInjectSecurityAttributes)
+ {
+ // check to see if the token already has a custom attribute
+ const void *pbData = NULL; // [OUT] Put pointer to data here.
+ ULONG cbData = 0;
+
+ if (fMarkEachTokenAsCritical)
+ {
+ // Check if the Type already has SecurityCritical
+ BOOL fInjectSecurityCriticalEverything = TRUE;
+ if (S_OK == m_pRegMetaEmit->GetCustomAttributeByName(pRec->m_tkTo, COR_SECURITYCRITICAL_ATTRIBUTE_FULL_W, &pbData, &cbData))
+ {
+ // if value is non-0 (i.e. 1), then it is SecurityCritical.Everything - so do not inject another
+ fInjectSecurityCriticalEverything = !(NULL != pbData && cbData == 8 &&
+ memcmp(rgSecurityCriticalEverythingCtorValue, pbData, cbData) == 0);
+ }
+
+ // either inject or overwrite SecurityCritical.Everything
+ if (fInjectSecurityCriticalEverything)
+ {
+ IfFailGo(m_pRegMetaEmit->DefineCustomAttribute(
+ pRec->m_tkTo, tkSecurityCriticalEverythingAttribute,
+ rgSecurityCriticalEverythingCtorValue, // Use this if you need specific custom attribute data (presence of the attribute isn't enough)
+ sizeof(rgSecurityCriticalEverythingCtorValue), // Length of your custom attribute data
+ NULL));
+ }
+ }
+
+ // If the Type does NOT already have TAS then add it
+ if (fMarkEachTokenAsSafe &&
+ S_OK != m_pRegMetaEmit->GetCustomAttributeByName(pRec->m_tkTo, COR_SECURITYTREATASSAFE_ATTRIBUTE_FULL_W, &pbData, &cbData))
+ {
+ IfFailGo(m_pRegMetaEmit->DefineCustomAttribute(
+ pRec->m_tkTo, tkSecurityTreatAsSafeAttribute,
+ rgTreatAsSafeCtorValue, // Use this if you need specific custom attribute data (presence of the attribute isn't enough)
+ sizeof(rgTreatAsSafeCtorValue), // Length of your custom attribute data
+ NULL));
+ }
+
+ hr = m_pRegMetaEmit->DefineCustomAttribute(pRec->m_tkTo, tkSecuritySafeCriticalAttribute,
+ rgSafeCriticalCtorValue, // Use this if you need specific custom attribute data (presence of the attribute isn't enough)
+ sizeof(rgSafeCriticalCtorValue), // Length of your custom attribute data
+ NULL);
+
+ }
+ }
+ }
+
+ // If the global scope is not Transparent, we should emit SecurityCritical.Explicit || Everything
+ if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityTransparent) != ISSCS_SecurityTransparent &&
+ (m_isscsSecurityCritical & ISSCS_SecurityCriticalEverything) != ISSCS_SecurityCriticalExplicit)
+ {
+ BOOL fEmitSecurityEverything = FALSE;
+ // in the case of Unmarked and TAS/Unmarked, we need to emit the SecurityCritical.Everything attribute
+ // if it hasn't already been emitted
+ if ((m_isscsSecurityCriticalAllScopes & ISSCS_SecurityCriticalEverything) ==
+ ISSCS_SecurityCriticalEverything)
+ {
+ fEmitSecurityEverything = TRUE;
+ }
+ // otherwise, emit the SecurityCritical.Explicit attribute
+
+ BOOL fSecurityCriticalExists = FALSE;
+ // check to see if the assembly already has the appropriate SecurityCritical attribute
+ // [from one of the input scopes]
+ const void *pbData = NULL;
+ ULONG cbData = 0;
+ if (S_OK == ImportHelper::GetCustomAttributeByName(emit,
+ fakeModuleTypeRef, // This is the assembly def token
+ COR_SECURITYCRITICAL_ATTRIBUTE_FULL,
+ &pbData,
+ &cbData))
+ {
+ // find out if critical everything or explicit
+ // default to critical
+ // if value is non-0 (i.e. 1), then mark as SecurityCritical everything, otherwise, explicit
+ if (NULL != pbData && cbData == 8 &&
+ memcmp(rgSecurityCriticalEverythingCtorValue, pbData, cbData) == 0)
+ {
+ if (!fEmitSecurityEverything)
+ {
+ _ASSERTE(!"Unexpected SecurityCritical.Everything attribute detected");
+ IfFailGo(META_E_BADMETADATA);
+ }
+ }
+ else
+ {
+ if (fEmitSecurityEverything)
+ {
+ _ASSERTE(!"Unexpected SecurityCritical.Explicit attribute detected");
+ IfFailGo(META_E_BADMETADATA);
+ }
+ }
+ fSecurityCriticalExists = TRUE;
+ }
+
+ if (!fSecurityCriticalExists)
+ {
+ // retrieve the type and CustomAttribute
+ mdCustomAttribute tkSecurityCriticalAttributeExplicit;
+
+ mdTypeRef tkSecurityCriticalExplicitAttributeType = mdTokenNil;
+
+ IfFailGo(m_pRegMetaEmit->DefineTypeRefByName(
+ tkMscorlib, COR_SECURITYCRITICAL_ATTRIBUTE_FULL_W,
+ &tkSecurityCriticalExplicitAttributeType));
+
+ BYTE rgSigBytesSecurityCriticalExplicitCtorLocal[] = {IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS, 0x00, ELEMENT_TYPE_VOID};
+ BYTE rgSecurityCriticalExplicitCtorValue[] = COR_SECURITYCRITICAL_ATTRIBUTE_VALUE_EXPLICIT;
+
+ IfFailGo(m_pRegMetaEmit->DefineMemberRef(tkSecurityCriticalExplicitAttributeType,
+ COR_CONSTRUCTOR_METADATA_IDENTIFIER,
+ rgSigBytesSecurityCriticalExplicitCtorLocal,
+ sizeof(rgSigBytesSecurityCriticalExplicitCtorLocal),
+ &tkSecurityCriticalAttributeExplicit));
+
+ IfFailGo(m_pRegMetaEmit->DefineCustomAttribute(
+ fakeModuleTypeRef,
+ fEmitSecurityEverything?tkSecurityCriticalEverythingAttribute:tkSecurityCriticalAttributeExplicit,
+ fEmitSecurityEverything?rgSecurityCriticalEverythingCtorValue:rgSecurityCriticalExplicitCtorValue,
+ fEmitSecurityEverything?sizeof(rgSecurityCriticalEverythingCtorValue):sizeof(rgSecurityCriticalExplicitCtorValue),
+ NULL));
+
+ }
+ }
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeSecurityCriticalAttributes()
+
+//*******************************************************************************
+// Helper to copy an InterfaceImpl record
+//*******************************************************************************
+HRESULT NEWMERGER::CopyInterfaceImpl(
+ InterfaceImplRec *pRecEmit, // [IN] the emit record to fill
+ MergeImportData *pImportData, // [IN] the importing context
+ InterfaceImplRec *pRecImp) // [IN] the record to import
+{
+ HRESULT hr;
+ mdToken tkParent;
+ mdToken tkInterface;
+ CMiniMdRW *pMiniMdEmit = GetMiniMdEmit();
+ CMiniMdRW *pMiniMdImp;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdImp = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+
+ tkParent = pMiniMdImp->getClassOfInterfaceImpl(pRecImp);
+ tkInterface = pMiniMdImp->getInterfaceOfInterfaceImpl(pRecImp);
+
+ IfFailGo( pCurTkMap->Remap(tkParent, &tkParent) );
+ IfFailGo( pCurTkMap->Remap(tkInterface, &tkInterface) );
+
+ IfFailGo( pMiniMdEmit->PutToken( TBL_InterfaceImpl, InterfaceImplRec::COL_Class, pRecEmit, tkParent) );
+ IfFailGo( pMiniMdEmit->PutToken( TBL_InterfaceImpl, InterfaceImplRec::COL_Interface, pRecEmit, tkInterface) );
+
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::CopyInterfaceImpl()
+
+
+//*****************************************************************************
+// Merge Assembly table
+//*****************************************************************************
+HRESULT NEWMERGER::MergeAssembly()
+{
+ HRESULT hr = NOERROR;
+ AssemblyRec *pRecImport = NULL;
+ AssemblyRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ LPCUTF8 szTmp;
+ const BYTE *pbTmp;
+ ULONG cbTmp;
+ ULONG iRecord;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ if (!pMiniMdImport->getCountAssemblys())
+ goto ErrExit; // There is no Assembly in the import scope to merge.
+
+ // Copy the Assembly map record to the Emit scope and send a token remap notifcation
+ // to the client. No duplicate checking needed since the Assembly can be present in
+ // only one scope and there can be atmost one entry.
+ IfFailGo(pMiniMdImport->GetAssemblyRecord(1, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddAssemblyRecord(&pRecEmit, &iRecord));
+
+ pRecEmit->Copy(pRecImport);
+
+ IfFailGo(pMiniMdImport->getPublicKeyOfAssembly(pRecImport, &pbTmp, &cbTmp));
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_Assembly, AssemblyRec::COL_PublicKey, pRecEmit,
+ pbTmp, cbTmp));
+
+ IfFailGo(pMiniMdImport->getNameOfAssembly(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_Assembly, AssemblyRec::COL_Name, pRecEmit, szTmp));
+
+ IfFailGo(pMiniMdImport->getLocaleOfAssembly(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_Assembly, AssemblyRec::COL_Locale, pRecEmit, szTmp));
+
+ // record the token movement.
+ IfFailGo(pCurTkMap->InsertNotFound(
+ TokenFromRid(1, mdtAssembly),
+ false,
+ TokenFromRid(iRecord, mdtAssembly),
+ &pTokenRec));
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeAssembly()
+
+
+
+
+//*****************************************************************************
+// Merge File table
+//*****************************************************************************
+HRESULT NEWMERGER::MergeFiles()
+{
+ HRESULT hr = NOERROR;
+ FileRec *pRecImport = NULL;
+ FileRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ LPCUTF8 szTmp;
+ const void *pbTmp;
+ ULONG cbTmp;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountFiles();
+
+ // Loop through all File records and copy them to the Emit scope.
+ // Since there can only be one File table in all the scopes combined,
+ // there isn't any duplicate checking that needs to be done.
+ for (i = 1; i <= iCount; i++)
+ {
+ IfFailGo(pMiniMdImport->GetFileRecord(i, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddFileRecord(&pRecEmit, &iRecord));
+
+ pRecEmit->Copy(pRecImport);
+
+ IfFailGo(pMiniMdImport->getNameOfFile(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_File, FileRec::COL_Name, pRecEmit, szTmp));
+
+ IfFailGo(pMiniMdImport->getHashValueOfFile(pRecImport, (const BYTE **)&pbTmp, &cbTmp));
+ IfFailGo(pMiniMdEmit->PutBlob(TBL_File, FileRec::COL_HashValue, pRecEmit, pbTmp, cbTmp));
+
+ // record the token movement.
+ IfFailGo(pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtFile),
+ false,
+ TokenFromRid(iRecord, mdtFile),
+ &pTokenRec));
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeFiles()
+
+
+//*****************************************************************************
+// Merge ExportedType table
+//*****************************************************************************
+HRESULT NEWMERGER::MergeExportedTypes()
+{
+ HRESULT hr = NOERROR;
+ ExportedTypeRec *pRecImport = NULL;
+ ExportedTypeRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ LPCUTF8 szTmp;
+ mdToken tkTmp;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountExportedTypes();
+
+ // Loop through all ExportedType records and copy them to the Emit scope.
+ // Since there can only be one ExportedType table in all the scopes combined,
+ // there isn't any duplicate checking that needs to be done.
+ for (i = 1; i <= iCount; i++)
+ {
+ IfFailGo(pMiniMdImport->GetExportedTypeRecord(i, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddExportedTypeRecord(&pRecEmit, &iRecord));
+
+ pRecEmit->Copy(pRecImport);
+
+ IfFailGo(pMiniMdImport->getTypeNameOfExportedType(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_ExportedType, ExportedTypeRec::COL_TypeName, pRecEmit, szTmp));
+
+ IfFailGo(pMiniMdImport->getTypeNamespaceOfExportedType(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_ExportedType, ExportedTypeRec::COL_TypeNamespace, pRecEmit, szTmp));
+
+ tkTmp = pMiniMdImport->getImplementationOfExportedType(pRecImport);
+ IfFailGo(pCurTkMap->Remap(tkTmp, &tkTmp));
+ IfFailGo(pMiniMdEmit->PutToken(TBL_ExportedType, ExportedTypeRec::COL_Implementation,
+ pRecEmit, tkTmp));
+
+
+ // record the token movement.
+ IfFailGo(pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtExportedType),
+ false,
+ TokenFromRid(iRecord, mdtExportedType),
+ &pTokenRec));
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeExportedTypes()
+
+
+//*****************************************************************************
+// Merge ManifestResource table
+//*****************************************************************************
+HRESULT NEWMERGER::MergeManifestResources()
+{
+ HRESULT hr = NOERROR;
+ ManifestResourceRec *pRecImport = NULL;
+ ManifestResourceRec *pRecEmit = NULL;
+ CMiniMdRW *pMiniMdImport;
+ CMiniMdRW *pMiniMdEmit;
+ LPCUTF8 szTmp;
+ mdToken tkTmp;
+ ULONG iCount;
+ ULONG i;
+ ULONG iRecord;
+ TOKENREC *pTokenRec;
+
+ MergeImportData *pImportData;
+ MDTOKENMAP *pCurTkMap;
+
+ pMiniMdEmit = GetMiniMdEmit();
+
+ for (pImportData = m_pImportDataList; pImportData != NULL; pImportData = pImportData->m_pNextImportData)
+ {
+ // for each import scope
+ pMiniMdImport = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+
+ // set the current MDTokenMap
+ pCurTkMap = pImportData->m_pMDTokenMap;
+ iCount = pMiniMdImport->getCountManifestResources();
+
+ // Loop through all ManifestResource records and copy them to the Emit scope.
+ // Since there can only be one ManifestResource table in all the scopes combined,
+ // there isn't any duplicate checking that needs to be done.
+ for (i = 1; i <= iCount; i++)
+ {
+ IfFailGo(pMiniMdImport->GetManifestResourceRecord(i, &pRecImport));
+ IfFailGo(pMiniMdEmit->AddManifestResourceRecord(&pRecEmit, &iRecord));
+
+ pRecEmit->Copy(pRecImport);
+
+ IfFailGo(pMiniMdImport->getNameOfManifestResource(pRecImport, &szTmp));
+ IfFailGo(pMiniMdEmit->PutString(TBL_ManifestResource, ManifestResourceRec::COL_Name,
+ pRecEmit, szTmp));
+
+ tkTmp = pMiniMdImport->getImplementationOfManifestResource(pRecImport);
+ IfFailGo(pCurTkMap->Remap(tkTmp, &tkTmp));
+ IfFailGo(pMiniMdEmit->PutToken(TBL_ManifestResource, ManifestResourceRec::COL_Implementation,
+ pRecEmit, tkTmp));
+
+ // record the token movement.
+ IfFailGo(pCurTkMap->InsertNotFound(
+ TokenFromRid(i, mdtManifestResource),
+ false,
+ TokenFromRid(iRecord, mdtManifestResource),
+ &pTokenRec));
+ }
+ }
+ErrExit:
+ return hr;
+} // HRESULT NEWMERGER::MergeManifestResources()
+
+
+
+
+
+//*****************************************************************************
+// Error handling. Call back to host to see what they want to do.
+//*****************************************************************************
+HRESULT NEWMERGER::OnError(
+ HRESULT hrIn, // The error HR we're reporting.
+ MergeImportData *pImportData, // The input scope with the error.
+ mdToken token) // The token with the error.
+{
+ // This function does a QI and a Release on every call. However, it should be
+ // called very infrequently, and lets the scope just keep a generic handler.
+ IMetaDataError *pIErr = NULL;
+ IUnknown *pHandler = pImportData->m_pHandler;
+ CMiniMdRW *pMiniMd = &(pImportData->m_pRegMetaImport->m_pStgdb->m_MiniMd);
+ CQuickArray<WCHAR> rName; // Name of the TypeDef in unicode.
+ LPCUTF8 szTypeName;
+ LPCUTF8 szNSName;
+ TypeDefRec *pTypeRec;
+ int iLen; // Length of a name.
+ mdToken tkParent;
+ HRESULT hr = NOERROR;
+
+ if (pHandler && pHandler->QueryInterface(IID_IMetaDataError, (void**)&pIErr)==S_OK)
+ {
+ switch (hrIn)
+ {
+
+ case META_E_PARAM_COUNTS:
+ case META_E_METHD_NOT_FOUND:
+ case META_E_METHDIMPL_INCONSISTENT:
+ {
+ LPCUTF8 szMethodName;
+ MethodRec *pMethodRec;
+
+ // Method name.
+ _ASSERTE(TypeFromToken(token) == mdtMethodDef);
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(token), &pMethodRec));
+ IfFailGo(pMiniMd->getNameOfMethod(pMethodRec, &szMethodName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMethodName, szMethodName);
+ IfNullGo(wzMethodName);
+
+ // Type and its name.
+ IfFailGo( pMiniMd->FindParentOfMethodHelper(token, &tkParent) );
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), wzMethodName, token);
+ break;
+ }
+ case META_E_FIELD_NOT_FOUND:
+ {
+ LPCUTF8 szFieldName;
+ FieldRec *pFieldRec;
+
+ // Field name.
+ _ASSERTE(TypeFromToken(token) == mdtFieldDef);
+ IfFailGo(pMiniMd->GetFieldRecord(RidFromToken(token), &pFieldRec));
+ IfFailGo(pMiniMd->getNameOfField(pFieldRec, &szFieldName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzFieldName, szFieldName);
+ IfNullGo(wzFieldName);
+
+ // Type and its name.
+ IfFailGo( pMiniMd->FindParentOfFieldHelper(token, &tkParent) );
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), wzFieldName, token);
+ break;
+ }
+ case META_E_EVENT_NOT_FOUND:
+ {
+ LPCUTF8 szEventName;
+ EventRec *pEventRec;
+
+ // Event name.
+ _ASSERTE(TypeFromToken(token) == mdtEvent);
+ IfFailGo(pMiniMd->GetEventRecord(RidFromToken(token), &pEventRec));
+ IfFailGo(pMiniMd->getNameOfEvent(pEventRec, &szEventName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzEventName, szEventName);
+ IfNullGo(wzEventName);
+
+ // Type and its name.
+ IfFailGo( pMiniMd->FindParentOfEventHelper(token, &tkParent) );
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), wzEventName, token);
+ break;
+ }
+ case META_E_PROP_NOT_FOUND:
+ {
+ LPCUTF8 szPropertyName;
+ PropertyRec *pPropertyRec;
+
+ // Property name.
+ _ASSERTE(TypeFromToken(token) == mdtProperty);
+ IfFailGo(pMiniMd->GetPropertyRecord(RidFromToken(token), &pPropertyRec));
+ IfFailGo(pMiniMd->getNameOfProperty(pPropertyRec, &szPropertyName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzPropertyName, szPropertyName);
+ IfNullGo(wzPropertyName);
+
+ // Type and its name.
+ IfFailGo( pMiniMd->FindParentOfPropertyHelper(token, &tkParent) );
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), wzPropertyName, token);
+ break;
+ }
+ case META_S_PARAM_MISMATCH:
+ {
+ LPCUTF8 szMethodName;
+ MethodRec *pMethodRec;
+ mdToken tkMethod;
+
+ // Method name.
+ _ASSERTE(TypeFromToken(token) == mdtParamDef);
+ IfFailGo( pMiniMd->FindParentOfParamHelper(token, &tkMethod) );
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkMethod), &pMethodRec));
+ IfFailGo(pMiniMd->getNameOfMethod(pMethodRec, &szMethodName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMethodName, szMethodName);
+ IfNullGo(wzMethodName);
+
+ // Type and its name.
+ IfFailGo( pMiniMd->FindParentOfMethodHelper(token, &tkParent) );
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ // use the error hresult so that we can post the correct error.
+ PostError(META_E_PARAM_MISMATCH, wzMethodName, (LPWSTR) rName.Ptr(), token);
+ break;
+ }
+ case META_E_INTFCEIMPL_NOT_FOUND:
+ {
+ InterfaceImplRec *pRec; // The InterfaceImpl
+ mdToken tkIface; // Token of the implemented interface.
+ CQuickArray<WCHAR> rIface; // Name of the Implemented Interface in unicode.
+ TypeRefRec *pRef; // TypeRef record when II is a typeref.
+ InterfaceImplRec *pInterfaceImplRec;
+
+ // Get the record.
+ _ASSERTE(TypeFromToken(token) == mdtInterfaceImpl);
+ IfFailGo(pMiniMd->GetInterfaceImplRecord(RidFromToken(token), &pRec));
+ // Get the name of the class.
+ tkParent = pMiniMd->getClassOfInterfaceImpl(pRec);
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ // Get the name of the implemented interface.
+ IfFailGo(pMiniMd->GetInterfaceImplRecord(RidFromToken(token), &pInterfaceImplRec));
+ tkIface = pMiniMd->getInterfaceOfInterfaceImpl(pInterfaceImplRec);
+ if (TypeFromToken(tkIface) == mdtTypeDef)
+ { // If it is a typedef...
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkIface), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ }
+ else
+ { // If it is a typeref...
+ _ASSERTE(TypeFromToken(tkIface) == mdtTypeRef);
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkIface), &pRef));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pRef, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pRef, &szNSName));
+ }
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rIface.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rIface.Ptr(), iLen+1, szNSName, szTypeName);
+
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), (LPWSTR)rIface.Ptr(), token);
+ break;
+ }
+ case META_E_CLASS_LAYOUT_INCONSISTENT:
+ case META_E_METHOD_COUNTS:
+ case META_E_FIELD_COUNTS:
+ case META_E_EVENT_COUNTS:
+ case META_E_PROPERTY_COUNTS:
+ {
+ // get the type name.
+ _ASSERTE(TypeFromToken(token) == mdtTypeDef);
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(token), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), token);
+ break;
+ }
+ case META_E_GENERICPARAM_INCONSISTENT:
+ {
+ // If token is type, get type name; if method, get method name.
+ LPWSTR wzName;
+ LPCUTF8 szMethodName;
+ MethodRec *pMethodRec;
+
+ if ((TypeFromToken(token) == mdtMethodDef))
+ {
+ // Get the method name.
+ IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(token), &pMethodRec));
+ IfFailGo(pMiniMd->getNameOfMethod(pMethodRec, &szMethodName));
+ MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMethodName, szMethodName);
+ IfNullGo(wzMethodName);
+ wzName = wzMethodName;
+ }
+ else
+ {
+ // Get the type name.
+ _ASSERTE(TypeFromToken(token) == mdtTypeDef);
+ IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(token), &pTypeRec));
+ IfFailGo(pMiniMd->getNameOfTypeDef(pTypeRec, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeRec, &szNSName));
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+ wzName = (LPWSTR)rName.Ptr();
+ }
+
+ PostError(hrIn, wzName, token);
+ break;
+ }
+ case META_E_TYPEDEF_MISSING:
+ {
+ TypeRefRec *pRef; // TypeRef record when II is a typeref.
+
+ // Get the record.
+ _ASSERTE(TypeFromToken(token) == mdtTypeRef);
+ IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(token), &pRef));
+ IfFailGo(pMiniMd->getNameOfTypeRef(pRef, &szTypeName));
+ IfFailGo(pMiniMd->getNamespaceOfTypeRef(pRef, &szNSName));
+
+ // Put namespace + name together.
+ iLen = ns::GetFullLength(szNSName, szTypeName);
+ IfFailGo(rName.ReSizeNoThrow(iLen+1));
+ ns::MakePath(rName.Ptr(), iLen+1, szNSName, szTypeName);
+
+
+ PostError(hrIn, (LPWSTR) rName.Ptr(), token);
+ break;
+ }
+ default:
+ {
+ PostError(hrIn, token);
+ break;
+ }
+ }
+ hr = pIErr->OnError(hrIn, token);
+ }
+ else
+ hr = S_FALSE;
+ErrExit:
+ if (pIErr)
+ pIErr->Release();
+ return (hr);
+} // NEWMERGER::OnError
+
+#endif //FEATURE_METADATA_EMIT_ALL