Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/coreclr/vm/methodtable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8937,3 +8937,19 @@ void MethodTable::GetStaticsOffsets(StaticsOffsetType offsetType, bool fGenericS
*dwGCOffset = (uint32_t)sizeof(TADDR) * 2;
}
}

bool Instantiation::EligibleForSpecialMarkerTypeUsage(MethodTable* pOwnerMT)
Comment thread
davidwrighton marked this conversation as resolved.
Outdated
{
LIMITED_METHOD_DAC_CONTRACT;

if (pOwnerMT == NULL)
return false;

if (GetNumArgs() > MethodTable::MaxGenericParametersForSpecialMarkerType)
return false;

if (!ContainsAllOneType(pOwnerMT->GetSpecialInstantiationType()))
return false;

return true;
}
95 changes: 84 additions & 11 deletions src/coreclr/vm/methodtablebuilder.cpp
Comment thread
davidwrighton marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -9805,8 +9805,6 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT)
break;
}

bool uninstGenericCase = !retryWithExactInterfaces && pNewIntfMT->IsSpecialMarkerTypeForGenericCasting();

duplicates |= InsertMethodTable(pNewIntfMT, pExactMTs, nInterfacesCount, &nAssigned);

// We have a special algorithm for interface maps in CoreLib, which doesn't expand interfaces, and assumes no ambiguous
Expand All @@ -9816,23 +9814,98 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT)
MethodTable::InterfaceMapIterator intIt = pNewIntfMT->IterateInterfaceMap();
while (intIt.Next())
{
MethodTable *pItfPossiblyApprox = intIt.GetInterfaceApprox();
if (uninstGenericCase && pItfPossiblyApprox->HasInstantiation() && pItfPossiblyApprox->ContainsGenericVariables())
if (retryWithExactInterfaces)
{
duplicates |= InsertMethodTable(intIt.GetInterface(pNewIntfMT, CLASS_LOAD_EXACTPARENTS), pExactMTs, nInterfacesCount, &nAssigned);
}
else
{
// We allow a limited set of interface generic shapes with type variables. In particular, we require the
// instantiations to be exactly simple type variables, and to have a relatively small number of generic arguments
// so that the fallback instantiating logic works efficiently
if (InstantiationIsAllTypeVariables(pItfPossiblyApprox->GetInstantiation()) && pItfPossiblyApprox->GetInstantiation().GetNumArgs() <= MethodTable::MaxGenericParametersForSpecialMarkerType)
MethodTable *pItfPossiblyApprox = intIt.GetInterfaceApprox();

// pItfPossiblyApprox can be in 4 situations
// 1. It has no instantiation
// 2. It is a special marker type, AND pNewItfMT is a special marker type. Compute the exact instantiation as containing entirely a list of types corresponding to calling GetSpecialInstantiationType on pMT (This rule works based on the current behavior of GetSpecialInstantiationType where it treats all interfaces the same)
// 3. It is a special marker type, but pNewItfMT is NOT a special marker type. Compute the exact instantiation as containing entirely a list of types corresponding to calling GetSpecialInstantiationType on pNewItfMT
// 4. It is an exact instantiation
//
// NOTE: pItfPossiblyApprox must not be considered a special marker type if pNewItfMT has the MayHaveOpenInterfacesInInterfaceMap flag set
//
// Then determine if all of the following conditions hold true.
// 1. All generic arguments are the same (always true for cases 2 and 3 above)
// 2. The first generic argument in the instantiation is exactly the value of calling GetSpecialInstantiationType on pMT (always true for case 2)
//
// If so, then we should insert the special marker type
// Otherwise, we should insert the exact instantiation of the interface
// HOWEVER: If the exact instantiation IS a special marker interface, we need to retry with exact interfaces to avoid ambiguity situations
//
// NOTE: This is also part of the logic which determines if we need to call SetMayHaveOpenInterfacesInInterfaceMap. What will happen is that if we have both an case where we want to insert a special marker type
Comment thread
davidwrighton marked this conversation as resolved.
Outdated
// but it satisfies the condition of also being an EXACT instantiation we want to retry, and use the retryWithExactInterfaces logic.
MethodTable *pItfToInsert = NULL;
bool intendedExactMatch = false;

if (!pItfPossiblyApprox->HasInstantiation())
{
pItfPossiblyApprox = ClassLoader::LoadTypeDefThrowing(pItfPossiblyApprox->GetModule(), pItfPossiblyApprox->GetCl(), ClassLoader::ThrowIfNotFound, ClassLoader::PermitUninstDefOrRef, 0, CLASS_LOAD_EXACTPARENTS).AsMethodTable();
// case 1
pItfToInsert = pItfPossiblyApprox;
intendedExactMatch = true;
}
else if (pItfPossiblyApprox->IsSpecialMarkerTypeForGenericCasting() && !pNewIntfMT->GetAuxiliaryData()->MayHaveOpenInterfacesInInterfaceMap())
{
// We are in case 2 or 3 above
TypeHandle instantiationType;
Comment thread
davidwrighton marked this conversation as resolved.
Outdated
bool pNewIntfMTIsSpecialMarkerType = pNewIntfMT->IsSpecialMarkerTypeForGenericCasting() && !pMT->GetAuxiliaryData()->MayHaveOpenInterfacesInInterfaceMap();
bool mustUseSpecialMarkerType = false;
if (pNewIntfMTIsSpecialMarkerType)
{
// case 2
pItfToInsert = pItfPossiblyApprox; // We have the special marker type already, so this is what we insert
}
else
{
// case 3
bool mustUseSpecialMarkerType = pNewIntfMT->GetSpecialInstantiationType() == pMT->GetSpecialInstantiationType();
Comment thread
davidwrighton marked this conversation as resolved.
Outdated
if (mustUseSpecialMarkerType)
{
pItfToInsert = pItfPossiblyApprox; // We have the special marker type already, so this is what we insert
}
else
{
pItfToInsert = intIt.GetInterface(pNewIntfMT, CLASS_LOAD_EXACTPARENTS);
intendedExactMatch = true;
}
}
}
else
{
// case 4 (We have an exact interface)
if (pItfPossiblyApprox->GetInstantiation().EligibleForSpecialMarkerTypeUsage(pMT))
{
// Validated that all generic arguments are the same, and that the first generic argument in the instantiation is exactly the value of calling GetSpecialInstantiationType on pMT
// Then use the special marker type here
pItfToInsert = ClassLoader::LoadTypeDefThrowing(pItfPossiblyApprox->GetModule(), pItfPossiblyApprox->GetCl(), ClassLoader::ThrowIfNotFound, ClassLoader::PermitUninstDefOrRef, 0, CLASS_LOAD_EXACTPARENTS).AsMethodTable();
}
else
{
pItfToInsert = pItfPossiblyApprox;
intendedExactMatch = true;
}
}

if (pItfToInsert->IsSpecialMarkerTypeForGenericCasting() && intendedExactMatch)
{
// We are trying to insert a special marker type into the interface list, but it is exactly the same as the exact instantiation we should actually want, we need to set the
// MayHaveOpenInterfacesInInterfaceMap flag, so trigger the retry logic.
retry = true;
break;
}

if (!intendedExactMatch)
{
_ASSERTE(pItfToInsert->IsSpecialMarkerTypeForGenericCasting());
}

duplicates |= InsertMethodTable(pItfToInsert, pExactMTs, nInterfacesCount, &nAssigned);
}
duplicates |= InsertMethodTable(intIt.GetInterface(pNewIntfMT, CLASS_LOAD_EXACTPARENTS), pExactMTs, nInterfacesCount, &nAssigned);
}
}

Expand Down Expand Up @@ -9869,7 +9942,7 @@ MethodTableBuilder::LoadExactInterfaceMap(MethodTable *pMT)
_ASSERTE(!duplicates || !(pMT->GetModule()->IsSystem() && (pMT->IsValueType() || pMT->IsInterface())));

CONSISTENCY_CHECK(duplicates || (nAssigned == pMT->GetNumInterfaces()));
if (duplicates)
if (duplicates || (nAssigned != pMT->GetNumInterfaces()))
Comment thread
jkotas marked this conversation as resolved.
{
//#LoadExactInterfaceMap_Algorithm2
// Exact interface instantiation loading TECHNIQUE 2 - The exact instantiation has caused some duplicates to
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/siginfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1618,7 +1618,7 @@ TypeHandle SigPointer::GetTypeHandleThrowing(

Instantiation genericLoadInst(thisinst, ntypars);

if (pMTInterfaceMapOwner != NULL && genericLoadInst.ContainsAllOneType(pMTInterfaceMapOwner->GetSpecialInstantiationType()))
if (genericLoadInst.EligibleForSpecialMarkerTypeUsage(pMTInterfaceMapOwner))
{
thRet = ClassLoader::LoadTypeDefThrowing(pGenericTypeModule, tkGenericType, ClassLoader::ThrowIfNotFound, ClassLoader::PermitUninstDefOrRef, 0, level);
}
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/vm/typehandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,7 @@ class Instantiation

bool ContainsAllOneType(TypeHandle th)
{
LIMITED_METHOD_DAC_CONTRACT;
for (DWORD i = GetNumArgs(); i > 0;)
{
if ((*this)[--i] != th)
Expand All @@ -705,6 +706,8 @@ class Instantiation
return true;
}

bool EligibleForSpecialMarkerTypeUsage(MethodTable* pOwnerMT);

private:
// Note that for DAC builds, m_pArgs may be host allocated buffer, not a copy of an object marshalled by DAC.
TypeHandle* m_pArgs;
Expand Down
8 changes: 8 additions & 0 deletions src/tests/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@
<RuntimeVariant Condition="'$(__MonoFullAot)' == '1'">llvmfullaot</RuntimeVariant>

<MonoBinDir>$(__MonoBinDir)</MonoBinDir>

<!-- The SDK for VB.NET converts the DefineConstants variable to be , delimited instead of ; delimited, and the logic below which appends a ; to the list causes a problem, as it can result in the property having a leading ;. -->
<DefineConstants Condition="'$(DefineConstants)' == ''">UNUSED_CONSTANT</DefineConstants>
</PropertyGroup>

<!-- Setup Default symbol and optimization for Configuration -->
Expand All @@ -122,6 +125,11 @@
<DefineConstants>$(DefineConstants);DEBUG;TRACE;XUNIT_PERF</DefineConstants>
</PropertyGroup>

<PropertyGroup>
<!-- The SDK for VB.NET requires the DefineConstants variable to be , delimited instead of ; -->
<DefineConstants Condition="'$(MSBuildProjectExtension)' == '.vbproj'">$(DefineConstants.Replace(';',','))</DefineConstants>
</PropertyGroup>

<!-- Setup the default output and intermediate paths -->
<PropertyGroup>
<SkipXunitDependencyCopying>true</SkipXunitDependencyCopying>
Expand Down
Loading