<FeatureManagedEtwChannels>true</FeatureManagedEtwChannels>
<FeatureManagedEtw>true</FeatureManagedEtw>
<FeaturePerfTracing>true</FeaturePerfTracing>
+ <FeatureTypeEquivalence>true</FeatureTypeEquivalence>
<ProfilingSupportedBuild>true</ProfilingSupportedBuild>
</PropertyGroup>
<DefineConstants Condition="'$(FeatureUseLcid)' == 'true'">$(DefineConstants);FEATURE_USE_LCID</DefineConstants>
<DefineConstants Condition="'$(FeatureWin32Registry)' == 'true'">$(DefineConstants);FEATURE_WIN32_REGISTRY</DefineConstants>
<DefineConstants Condition="'$(FeatureDefaultInterfaces)' == 'true'">$(DefineConstants);FEATURE_DEFAULT_INTERFACES</DefineConstants>
+ <DefineConstants Condition="'$(FeatureTypeEquivalence)' == 'true'">$(DefineConstants);FEATURE_TYPEEQUIVALENCE</DefineConstants>
<DefineConstants Condition="'$(ProfilingSupportedBuild)' == 'true'">$(DefineConstants);PROFILING_SUPPORTED</DefineConstants>
<DefineConstants Condition="'$(FeatureProfAttach)' == 'true'">$(DefineConstants);FEATURE_PROFAPI_ATTACH_DETACH</DefineConstants>
add_definitions(-DFEATURE_SVR_GC)
add_definitions(-DFEATURE_SYMDIFF)
add_definitions(-DFEATURE_TIERED_COMPILATION)
+if (WIN32)
+ add_definitions(-DFEATURE_TYPEEQUIVALENCE)
+endif(WIN32)
if (CLR_CMAKE_PLATFORM_ARCH_AMD64)
# Enable the AMD64 Unix struct passing JIT-EE interface for all AMD64 platforms, to enable altjit.
add_definitions(-DUNIX_AMD64_ABI_ITF)
tieredcompilation.cpp
typectxt.cpp
typedesc.cpp
+ typeequivalencehash.cpp
typehandle.cpp
typehash.cpp
typestring.cpp
typectxt.h
typedesc.h
typedesc.inl
+ typeequivalencehash.hpp
typehandle.h
typehandle.inl
typehash.h
#include "rcwrefcache.h"
#include "olecontexthelpers.h"
#endif // FEATURE_COMINTEROP
-#ifdef FEATURE_TYPEEQUIVALENCE
+
#include "typeequivalencehash.hpp"
-#endif
#include "appdomain.inl"
#include "typeparse.h"
#endif
if (m_pTypeEquivalenceTable.Load() == NULL)
{
- m_pTypeEquivalenceTable = TypeEquivalenceHashTable::Create(this, 12, &m_TypeEquivalenceCrst);
+ m_pTypeEquivalenceTable = TypeEquivalenceHashTable::Create(this, /* bucket count */ 12, &m_TypeEquivalenceCrst);
}
}
return m_pTypeEquivalenceTable;
return m_VMFlags & VMFLAG_IS_EQUIVALENT_TYPE;
}
-#ifdef FEATURE_COMINTEROP
+#ifdef FEATURE_TYPEEQUIVALENCE
inline void SetIsEquivalentType()
{
LIMITED_METHOD_CONTRACT;
m_VMFlags |= VMFLAG_IS_EQUIVALENT_TYPE;
}
-#endif
+#endif // FEATURE_TYPEEQUIVALENCE
/*
* Number of static handles allocated
../stublink.cpp
../typectxt.cpp
../typedesc.cpp
+ ../typeequivalencehash.cpp
../typehandle.cpp
../typehash.cpp
../typeparse.cpp
../typectxt.h
../typedesc.h
../typedesc.inl
+ ../typeequivalencehash.hpp
../typehandle.h
../typehandle.inl
../typehash.h
#ifdef FEATURE_TYPEEQUIVALENCE
-void CheckForEquivalenceAndLoadType(Module *pModule, mdToken token, Module *pDefModule, mdToken defToken, const SigParser *ptr, SigTypeContext *pTypeContext, void *pData)
+static void CheckForEquivalenceAndLoadType(Module *pModule, mdToken token, Module *pDefModule, mdToken defToken, const SigParser *ptr, SigTypeContext *pTypeContext, void *pData)
{
CONTRACTL
{
TypeHandle th = sigPtr.GetTypeHandleThrowing(pModule, pTypeContext);
}
}
+#endif // FEATURE_TYPEEQUIVALENCE
BOOL MethodDesc::HasTypeEquivalentStructParameters()
{
+#ifdef FEATURE_TYPEEQUIVALENCE
CONTRACTL
{
THROWS;
SetDoesNotHaveEquivalentValuetypeParameters();
return fHasTypeEquivalentStructParameters;
-}
+
+#else
+ LIMITED_METHOD_CONTRACT;
+ return FALSE;
#endif // FEATURE_TYPEEQUIVALENCE
+}
+
PrecodeType MethodDesc::GetPrecodeType()
{
VOID GetMethodInfoNoSig(SString &namespaceOrClassName, SString &methodName);
VOID GetFullMethodInfo(SString& fullMethodSigName);
- BOOL HasTypeEquivalentStructParameters()
-#ifndef FEATURE_TYPEEQUIVALENCE
- {
- LIMITED_METHOD_CONTRACT;
- return FALSE;
- }
-#else
- ;
-#endif
+ BOOL HasTypeEquivalentStructParameters();
+
typedef void (*WalkValueTypeParameterFnPtr)(Module *pModule, mdToken token, Module *pDefModule, mdToken tkDefToken, const SigParser *ptr, SigTypeContext *pTypeContext, void *pData);
void WalkValueTypeParameters(MethodTable *pMT, WalkValueTypeParameterFnPtr function, void *pData);
WORD InterlockedUpdateFlags3(WORD wMask, BOOL fSet);
-#ifdef FEATURE_COMINTEROP
+#ifdef FEATURE_TYPEEQUIVALENCE
inline BOOL DoesNotHaveEquivalentValuetypeParameters()
{
LIMITED_METHOD_DAC_CONTRACT;
LIMITED_METHOD_CONTRACT;
InterlockedUpdateFlags3(enum_flag3_DoesNotHaveEquivalentValuetypeParameters, TRUE);
}
-#endif //FEATURE_COMINTEROP
+#endif // FEATURE_TYPEEQUIVALENCE
inline BOOL HasForwardedValuetypeParameter()
{
#endif //FEATURE_COMINTEROP
-#ifndef FEATURE_TYPEEQUIVALENCE
-inline BOOL HasTypeEquivalentStructParameters()
-{
- LIMITED_METHOD_CONTRACT;
- return FALSE;
-}
-#endif // FEATURE_TYPEEQUIVALENCE
-
#ifdef FEATURE_CODE_VERSIONING
inline CodeVersionManager * MethodDesc::GetCodeVersionManager()
{
#include "winrttypenameconverter.h"
#endif // FEATURE_COMINTEROP
-#ifdef FEATURE_TYPEEQUIVALENCE
#include "typeequivalencehash.hpp"
-#endif
#include "generics.h"
#include "genericdict.h"
SetFlag(enum_flag_ComObject);
}
-#if defined(FEATURE_TYPEEQUIVALENCE)
-void MethodTable::SetHasTypeEquivalence()
-{
- LIMITED_METHOD_CONTRACT;
- SetFlag(enum_flag_HasTypeEquivalence);
-}
-#endif
-
#ifdef FEATURE_ICASTABLE
void MethodTable::SetICastable()
{
}
CONTRACTL_END;
+ TypeEquivalenceHashTable *typeHashTable = NULL;
AppDomain *pDomain = GetAppDomain();
if (pDomain != NULL)
{
- TypeEquivalenceHashTable::EquivalenceMatch match = pDomain->GetTypeEquivalenceCache()->CheckEquivalence(TypeHandle(this), TypeHandle(pOtherMT));
+ typeHashTable = pDomain->GetTypeEquivalenceCache();
+ TypeEquivalenceHashTable::EquivalenceMatch match = typeHashTable->CheckEquivalence(TypeHandle(this), TypeHandle(pOtherMT));
switch (match)
{
case TypeEquivalenceHashTable::Match:
BOOL fEquivalent = FALSE;
+ // Check if type is generic
if (HasInstantiation())
{
- // we limit variance on generics only to interfaces
+ // Limit variance on generics only to interfaces
if (!IsInterface() || !pOtherMT->IsInterface())
{
fEquivalent = FALSE;
Instantiation inst1 = GetInstantiation();
Instantiation inst2 = pOtherMT->GetInstantiation();
+ // Verify generic argument count
if (inst1.GetNumArgs() != inst2.GetNumArgs())
{
fEquivalent = FALSE;
goto EquivalenceCalculated;
}
+ // Verify each generic argument type
for (DWORD i = 0; i < inst1.GetNumArgs(); i++)
{
if (!inst1[i].IsEquivalentTo(inst2[i] COMMA_INDEBUG(pVisited)))
}
// arrays of structures have their own unshared MTs and will take this path
- fEquivalent = (GetApproxArrayElementTypeHandle().IsEquivalentTo(pOtherMT->GetApproxArrayElementTypeHandle() COMMA_INDEBUG(pVisited)));
+ TypeHandle elementType1 = GetApproxArrayElementTypeHandle();
+ TypeHandle elementType2 = pOtherMT->GetApproxArrayElementTypeHandle();
+ fEquivalent = elementType1.IsEquivalentTo(elementType2 COMMA_INDEBUG(pVisited));
goto EquivalenceCalculated;
}
fEquivalent = CompareTypeDefsForEquivalence(GetCl(), pOtherMT->GetCl(), GetModule(), pOtherMT->GetModule(), NULL);
EquivalenceCalculated:
- // Only record equivalence matches if we are in an AppDomain
- if (pDomain != NULL)
+ // Record equivalence matches if a table exists
+ if (typeHashTable != NULL)
{
// Collectible type results will not get cached.
- if ((!this->Collectible() && !pOtherMT->Collectible()))
+ if ((!Collectible() && !pOtherMT->Collectible()))
{
- TypeEquivalenceHashTable::EquivalenceMatch match;
- match = fEquivalent ? TypeEquivalenceHashTable::Match : TypeEquivalenceHashTable::NoMatch;
- pDomain->GetTypeEquivalenceCache()->RecordEquivalence(TypeHandle(this), TypeHandle(pOtherMT), match);
+ auto match = fEquivalent ? TypeEquivalenceHashTable::Match : TypeEquivalenceHashTable::NoMatch;
+ typeHashTable->RecordEquivalence(TypeHandle(this), TypeHandle(pOtherMT), match);
}
}
// Used so that we can have one valuetype walking algorithm used for type equivalence walking of the parameters of the method.
struct DoFullyLoadLocals
{
- DoFullyLoadLocals(DFLPendingList *pPendingParam, ClassLoadLevel levelParam, MethodTable *pMT, Generics::RecursionGraph *pVisited) :
- newVisited(pVisited, TypeHandle(pMT)),
- pPending(pPendingParam),
- level(levelParam),
- fBailed(FALSE)
-#ifdef FEATURE_COMINTEROP
+ DoFullyLoadLocals(DFLPendingList *pPendingParam, ClassLoadLevel levelParam, MethodTable *pMT, Generics::RecursionGraph *pVisited)
+ : newVisited(pVisited, TypeHandle(pMT))
+ , pPending(pPendingParam)
+ , level(levelParam)
+ , fBailed(FALSE)
+#ifdef FEATURE_TYPEEQUIVALENCE
, fHasEquivalentStructParameter(FALSE)
#endif
, fHasTypeForwarderDependentStructParameter(FALSE)
DFLPendingList * const pPending;
const ClassLoadLevel level;
BOOL fBailed;
-#ifdef FEATURE_COMINTEROP
+#ifdef FEATURE_TYPEEQUIVALENCE
BOOL fHasEquivalentStructParameter;
#endif
BOOL fHasTypeForwarderDependentStructParameter;
#endif // !DACCESS_COMPILE
#endif // FEATURE_COMINTEROP
-#ifdef FEATURE_COMINTEROP
+#ifdef FEATURE_TYPEEQUIVALENCE
#ifndef DACCESS_COMPILE
WORD GetEquivalentMethodSlot(MethodTable * pOldMT, MethodTable * pNewMT, WORD wMTslot, BOOL *pfFound)
GC_NOTRIGGER;
} CONTRACTL_END;
- MethodDesc * pMDRet = NULL;
*pfFound = FALSE;
+ WORD wVTslot = wMTslot;
+
+#ifdef FEATURE_COMINTEROP
// Get the COM vtable slot corresponding to the given MT slot
- WORD wVTslot;
if (pOldMT->IsSparseForCOMInterop())
- {
wVTslot = pOldMT->GetClass()->GetSparseCOMInteropVTableMap()->LookupVTSlot(wMTslot);
- }
- else
- {
- wVTslot = wMTslot;
- }
-
+
// If the other MT is not sparse, we can return the COM slot directly
if (!pNewMT->IsSparseForCOMInterop())
{
_ASSERTE(!*pfFound);
return 0;
+
+#else
+ // No COM means there is no sparse interface
+ if (wVTslot < pNewMT->GetNumVirtuals())
+ *pfFound = TRUE;
+
+ return wVTslot;
+
+#endif // FEATURE_COMINTEROP
}
#endif // #ifdef DACCESS_COMPILE
-#endif // #ifdef FEATURE_COMINTEROP
+#endif // #ifdef FEATURE_TYPEEQUIVALENCE
//==========================================================================================
BOOL
BOOL IsExtensibleRCW();
-#if defined(FEATURE_TYPEEQUIVALENCE)
- // mark the type as opted into type equivalence
- void SetHasTypeEquivalence();
-#endif
-
// Helper to get parent class skipping over COM class in
// the hierarchy
MethodTable* GetComPlusParentMethodTable();
BOOL IsICastable(); // This type implements ICastable interface
#ifdef FEATURE_TYPEEQUIVALENCE
- // type has opted into type equivalence or is instantiated by/derived from a type that is
- BOOL HasTypeEquivalence()
+ // mark the type as opted into type equivalence
+ void SetHasTypeEquivalence()
{
LIMITED_METHOD_CONTRACT;
- return GetFlag(enum_flag_HasTypeEquivalence);
+ SetFlag(enum_flag_HasTypeEquivalence);
}
-#else
+#endif // FEATURE_TYPEEQUIVALENCE
+
+ // type has opted into type equivalence or is instantiated by/derived from a type that is
BOOL HasTypeEquivalence()
{
LIMITED_METHOD_CONTRACT;
+#ifdef FEATURE_TYPEEQUIVALENCE
+ return GetFlag(enum_flag_HasTypeEquivalence);
+#else
return FALSE;
+#endif // FEATURE_TYPEEQUIVALENCE
}
-#endif
//-------------------------------------------------------------------
// DYNAMIC ADDITION OF INTERFACES FOR COM INTEROP
#ifndef DACCESS_COMPILE
FORCEINLINE BOOL IsEquivalentTo(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited = NULL));
-#ifdef FEATURE_COMINTEROP
+#ifdef FEATURE_TYPEEQUIVALENCE
// This method is public so that TypeHandle has direct access to it
BOOL IsEquivalentTo_Worker(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited)); // out-of-line part, SO tolerant
private:
BOOL IsEquivalentTo_WorkerInner(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited)); // out-of-line part, SO intolerant
-#endif // FEATURE_COMINTEROP
+#endif // FEATURE_TYPEEQUIVALENCE
#endif
public:
#ifndef CROSSBITNESS_COMPILE
static_assert_no_msg(sizeof(MethodTable) == SIZEOF__MethodTable_);
#endif
-#if defined(FEATURE_COMINTEROP) && !defined(DACCESS_COMPILE)
+#if defined(FEATURE_TYPEEQUIVALENCE) && !defined(DACCESS_COMPILE)
WORD GetEquivalentMethodSlot(MethodTable * pOldMT, MethodTable * pNewMT, WORD wMTslot, BOOL *pfFound);
-#endif // defined(FEATURE_COMINTEROP) && !defined(DACCESS_COMPILE)
+#endif // defined(FEATURE_TYPEEQUIVALENCE) && !defined(DACCESS_COMPILE)
MethodTable* CreateMinimalMethodTable(Module* pContainingModule,
LoaderHeap* pCreationHeap,
if (bmtProp->fIsTypeEquivalent)
{
- BOOL fTypeEquivalentNotPermittedDueToType = !(((IsComImport() || bmtProp->fComEventItfType) && IsInterface()) || IsValueClass() || IsDelegate());
+ BOOL comImportOrEventInterface = IsComImport();
+#ifdef FEATURE_COMINTEROP
+ comImportOrEventInterface = comImportOrEventInterface || bmtProp->fComEventItfType;
+#endif // FEATURE_COMINTEROP
+
+ BOOL fTypeEquivalentNotPermittedDueToType = !((comImportOrEventInterface && IsInterface()) || IsValueClass() || IsDelegate());
BOOL fTypeEquivalentNotPermittedDueToGenerics = bmtGenerics->HasInstantiation();
if (fTypeEquivalentNotPermittedDueToType || fTypeEquivalentNotPermittedDueToGenerics)
else
{
// no TypeIdentifierAttribute -> the assembly must be a type library
- bool has_eq = !pModule->GetAssembly()->IsDynamic() && pModule->GetAssembly()->IsPIAOrImportedFromTypeLib();
+ bool has_eq = !pModule->GetAssembly()->IsDynamic();
+
+#ifdef FEATURE_COMINTEROP
+ has_eq = has_eq && pModule->GetAssembly()->IsPIAOrImportedFromTypeLib();
+#endif // FEATURE_COMINTEROP
if (!has_eq)
{
(memcmp(m_pchIdentifierName, data.m_pchIdentifierName + m_cbIdentifierNamespace + 1, m_cbIdentifierName) == 0);
}
-#endif //FEATURE_TYPEEQUIVALENCE
-#ifdef FEATURE_COMINTEROP
-
-//---------------------------------------------------------------------------------------
-//
-static CorElementType GetFieldSigElementType(PCCOR_SIGNATURE pSig, DWORD cbSig)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END
-
- SigPointer sigptr(pSig, cbSig);
-
- ULONG data;
- IfFailThrow(sigptr.GetCallingConv(&data));
- _ASSERTE(data == IMAGE_CEE_CS_CALLCONV_FIELD);
-
- CorElementType etype;
- IfFailThrow(sigptr.GetElemType(&etype));
-
- return etype;
-}
-
//---------------------------------------------------------------------------------------
//
static BOOL CompareStructuresForEquivalence(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModule2, BOOL fEnumMode, TokenPairList *pVisited)
return MetaSig::CompareMethodSigs(pSig1, cbSig1, pModule1, NULL, pSig2, cbSig2, pModule2, NULL, pVisited);
}
-#endif // FEATURE_COMINTEROP
+#endif // FEATURE_TYPEEQUIVALENCE
#endif // #ifndef DACCESS_COMPILE
#ifndef DACCESS_COMPILE
// 1. Type is within assembly marked with ImportedFromTypeLibAttribute or PrimaryInteropAssemblyAttribute
if (hr != S_OK)
{
- bool has_eq = !pModule->GetAssembly()->IsDynamic() && pModule->GetAssembly()->IsPIAOrImportedFromTypeLib();
+ // no TypeIdentifierAttribute -> the assembly must be a type library
+ bool has_eq = !pModule->GetAssembly()->IsDynamic();
+
+#ifdef FEATURE_COMINTEROP
+ has_eq = has_eq && pModule->GetAssembly()->IsPIAOrImportedFromTypeLib();
+#endif // FEATURE_COMINTEROP
if (!has_eq)
return FALSE;
}
return TRUE;
-#else //!defined(DACCESS_COMPILE) && defined(FEATURE_COMINTEROP)
+#else //!defined(DACCESS_COMPILE) && defined(FEATURE_TYPEEQUIVALENCE)
#ifdef DACCESS_COMPILE
// We shouldn't execute this code in dac builds.
LoaderHeap *pHeap = pAppDomain->GetLowFrequencyHeap();
TypeEquivalenceHashTable *pThis = (TypeEquivalenceHashTable*)amt.Track(pHeap->AllocMem((S_SIZE_T)sizeof(TypeEquivalenceHashTable)));
- // The base class get initialized through chaining of constructors. We allocated the hash instance via the
- // loader heap instead of new so use an in-place new to call the constructors now.
+ // The base class gets initialized through chaining of constructors.
+ // Use in-place new to create instance.
new (pThis) TypeEquivalenceHashTable(pHeap, dwNumBuckets, pCrst);
amt.SuppressRelease();
#ifndef __TYPEEQUIVALENCE_HASH_INCLUDED
#define __TYPEEQUIVALENCE_HASH_INCLUDED
-#include "ngenhash.h"
-
#ifdef FEATURE_TYPEEQUIVALENCE
+#include "ngenhash.h"
+
// The type of each entry in the hash.
typedef DPTR(struct TypeEquivalenceEntry) PTR_TypeEquivalenceEntry;
-typedef struct TypeEquivalenceEntry
+struct TypeEquivalenceEntry
{
static NgenHashValue HashTypeHandles(TypeHandle thA, TypeHandle thB)
{
{
LIMITED_METHOD_CONTRACT;
- return (((thA == m_thA) && (thB == m_thB)) ||
- ((thB == m_thA) && (thA == m_thB)));
+ return (((thA == m_thA) && (thB == m_thB))
+ || ((thB == m_thA) && (thA == m_thB)));
}
void SetData(TypeHandle thA, TypeHandle thB, bool fEquivalent)
}
private:
-
TypeHandle m_thA;
TypeHandle m_thB;
bool m_fEquivalent;
-} TypeEquivalenceEntry_t;
+};
// The hash type itself. All common logic is provided by the NgenHashTable templated base class. See
// NgenHash.h for details.
#endif
public:
- typedef enum EquivalenceMatch
+ enum EquivalenceMatch
{
MatchUnknown,
Match,
EquivalenceMatch CheckEquivalence(TypeHandle thA, TypeHandle thB);
#ifdef DACCESS_COMPILE
- void EnumMemoryRegionsForEntry(TypeEquivalenceEntry_t *pEntry, CLRDataEnumMemoryFlags flags) { return; }
+ void EnumMemoryRegionsForEntry(TypeEquivalenceEntry *pEntry, CLRDataEnumMemoryFlags flags) { return; }
#endif
#if defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE)
private:
-
- bool ShouldSave(DataImage *pImage, TypeEquivalenceEntry_t *pEntry) { return false; }
- bool IsHotEntry(TypeEquivalenceEntry_t *pEntry, CorProfileData *pProfileData) { return false; }
- bool SaveEntry(DataImage *pImage, CorProfileData *pProfileData, TypeEquivalenceEntry_t *pOldEntry, TypeEquivalenceEntry_t *pNewEntry, EntryMappingTable *pMap) { return true; }
- void FixupEntry(DataImage *pImage, TypeEquivalenceEntry_t *pEntry, void *pFixupBase, DWORD cbFixupOffset) { return; }
+ // Override operations from NgenHashTable - see ngenhash.h
+ bool ShouldSave(DataImage *pImage, TypeEquivalenceEntry *pEntry) { return false; }
+ bool IsHotEntry(TypeEquivalenceEntry *pEntry, CorProfileData *pProfileData) { return false; }
+ bool SaveEntry(DataImage *pImage, CorProfileData *pProfileData, TypeEquivalenceEntry *pOldEntry, TypeEquivalenceEntry *pNewEntry, EntryMappingTable *pMap) { return true; }
+ void FixupEntry(DataImage *pImage, TypeEquivalenceEntry *pEntry, void *pFixupBase, DWORD cbFixupOffset) { return; }
#endif // FEATURE_PREJIT && !DACCESS_COMPILE
private:
#ifndef DACCESS_COMPILE
- TypeEquivalenceHashTable(LoaderHeap *pHeap, DWORD cInitialBuckets, CrstExplicitInit *pCrst) :
- NgenHashTable<TypeEquivalenceHashTable, TypeEquivalenceEntry, 4>(NULL, pHeap, cInitialBuckets),
- m_pHashTableCrst(pCrst)
+ TypeEquivalenceHashTable(LoaderHeap *pHeap, DWORD cInitialBuckets, CrstExplicitInit *pCrst)
+ : NgenHashTable<TypeEquivalenceHashTable, TypeEquivalenceEntry, 4>(NULL, pHeap, cInitialBuckets)
+ , m_pHashTableCrst(pCrst)
{
}
-#endif
- CrstExplicitInit* m_pHashTableCrst;
+#endif // DACCESS_COMPILE
+
+ CrstExplicitInit* m_pHashTableCrst;
};
#endif // FEATURE_TYPEEQUIVALENCE
-
-#endif // !__CLASS_HASH_INCLUDED
+#endif // !__TYPEEQUIVALENCE_HASH_INCLUDED
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <!-- The Type Equivalence feature is unsupported outside of windows -->
+ <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
+ <DisableProjectBuild Condition="'$(TargetsUnix)' == 'true'">true</DisableProjectBuild>
+ </PropertyGroup>
+
+</Project>
\ No newline at end of file
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <Target
+ Name="CreateEmbedResponseFile"
+ AfterTargets="ResolveProjectReferences">
+
+ <!-- Get the output for each project reference -->
+ <Message Text="Generating Response File for embedding type metadata: $(CompilerResponseFile)"/>
+ <MSBuild
+ Projects="@(ProjectReference)"
+ Condition=" '%(ProjectReference.EmbedTypes)' == 'true'"
+ Targets="GetTargetPath">
+ <Output TaskParameter="TargetOutputs" ItemName="ResolvedProjectReferencePaths" />
+ </MSBuild>
+
+ <WriteLinesToFile
+ File="$(CompilerResponseFile)"
+ Lines="@(ResolvedProjectReferencePaths -> '/link:%(fullpath)')"
+ Overwrite="true"
+ Encoding="Unicode" />
+ </Target>
+
+</Project>
\ No newline at end of file
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <Import Project="$([MSBuild]::GetPathOfFileAbove('TypeEquivalence.props', '$(MSBuildThisFileDirectory)../'))" />
+
+ <PropertyGroup>
+ <OutputType>Library</OutputType>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="**/*.cs" />
+ </ItemGroup>
+
+</Project>
\ No newline at end of file
--- /dev/null
+// 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.
+
+using System;
+using System.Runtime.InteropServices;
+
+[assembly:ImportedFromTypeLib("TypeEquivalenceTest")] // Required to support embeddable types
+[assembly:Guid("3B491C47-B176-4CF3-8748-F19E303F1714")]
+
+namespace TypeEquivalenceTypes
+{
+ [ComImport]
+ [Guid("F34D4DE8-B891-4D73-B177-C8F1139A9A67")]
+ public interface IEmptyType
+ {
+ }
+}
--- /dev/null
+// 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.
+
+using System;
+using System.Runtime.InteropServices;
+
+using TypeEquivalenceTypes;
+
+public class EmptyType : IEmptyType
+{
+ /// <summary>
+ /// Create an instance of <see cref="EmptyType" />
+ /// </summary>
+ public static object Create()
+ {
+ return new EmptyType();
+ }
+}
\ No newline at end of file
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <Import Project="$([MSBuild]::GetPathOfFileAbove('TypeEquivalence.props', '$(MSBuildThisFileDirectory)../'))" />
+
+ <PropertyGroup>
+ <OutputType>Library</OutputType>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="**/*.cs" />
+ </ItemGroup>
+
+ <PropertyGroup>
+ <CompilerResponseFile>$(IntermediateOutputPath)TypeImpl.rsp</CompilerResponseFile>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="../contracts/TypeContracts.csproj">
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <EmbedTypes>true</EmbedTypes>
+ </ProjectReference>
+ </ItemGroup>
+
+ <Import Project="$([MSBuild]::GetPathOfFileAbove('TypeEquivalence.targets', '$(MSBuildThisFileDirectory)../'))" />
+
+</Project>
\ No newline at end of file
--- /dev/null
+// 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.
+
+using System;
+using System.Runtime.InteropServices;
+
+using TestLibrary;
+using TypeEquivalenceTypes;
+
+public class Simple
+{
+ private class EmptyType2 : IEmptyType
+ {
+ /// <summary>
+ /// Create an instance of <see cref="EmptyType" />
+ /// </summary>
+ public static object Create()
+ {
+ return new EmptyType2();
+ }
+ }
+
+ private static void InterfaceTypesFromDifferentAssembliesAreEqual()
+ {
+ Console.WriteLine("Interfaces are the same");
+ var inAsm = EmptyType.Create();
+ DisplayType((IEmptyType)inAsm);
+
+ var otherAsm = EmptyType2.Create();
+ DisplayType((IEmptyType)otherAsm);
+
+ void DisplayType(IEmptyType i)
+ {
+ Console.WriteLine(i.GetType());
+ }
+ }
+
+ public static int Main(string[] noArgs)
+ {
+ try
+ {
+ InterfaceTypesFromDifferentAssembliesAreEqual();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"Test Failure: {e}");
+ return 101;
+ }
+
+ return 100;
+ }
+}
\ No newline at end of file
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <Import Project="$([MSBuild]::GetPathOfFileAbove('TypeEquivalence.props', '$(MSBuildThisFileDirectory)../'))" />
+
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <Compile Include="**/*.cs" />
+ </ItemGroup>
+
+ <PropertyGroup>
+ <CompilerResponseFile>$(IntermediateOutputPath)Simple.rsp</CompilerResponseFile>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="../contracts/TypeContracts.csproj">
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ <EmbedTypes>true</EmbedTypes>
+ </ProjectReference>
+ <ProjectReference Include="../impl/TypeImpl.csproj"/>
+ <ProjectReference Include="../../../Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
+ </ItemGroup>
+
+ <Import Project="$([MSBuild]::GetPathOfFileAbove('TypeEquivalence.targets', '$(MSBuildThisFileDirectory)../'))" />
+
+</Project>
\ No newline at end of file