diff options
author | Michal Strehovský <MichalStrehovsky@users.noreply.github.com> | 2018-12-14 12:21:45 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-14 12:21:45 +0100 |
commit | 1649da12db73c8c07513c9168cb30ec70c310063 (patch) | |
tree | 7540f498fe66833ede109112be7e5d44e4f7d9a5 /src | |
parent | b093822a4dacfe6bd36970e270f0a6d720732a04 (diff) | |
download | coreclr-1649da12db73c8c07513c9168cb30ec70c310063.tar.gz coreclr-1649da12db73c8c07513c9168cb30ec70c310063.tar.bz2 coreclr-1649da12db73c8c07513c9168cb30ec70c310063.zip |
Implement two pass algorithm for variant interface dispatch (#21355)
Fixes #20452.
Diffstat (limited to 'src')
-rw-r--r-- | src/vm/methodtable.cpp | 39 | ||||
-rw-r--r-- | src/vm/methodtable.h | 1 |
2 files changed, 35 insertions, 5 deletions
diff --git a/src/vm/methodtable.cpp b/src/vm/methodtable.cpp index fe4a18ba4b..91f6edd258 100644 --- a/src/vm/methodtable.cpp +++ b/src/vm/methodtable.cpp @@ -6977,12 +6977,28 @@ MethodTable::FindDispatchImpl( // // See if we can find a default method from one of the implemented interfaces // + + // Try exact match first MethodDesc *pDefaultMethod = NULL; - if (FindDefaultInterfaceImplementation( + BOOL foundDefaultInterfaceImplementation = FindDefaultInterfaceImplementation( pIfcMD, // the interface method being resolved pIfcMT, // the interface being resolved &pDefaultMethod, - throwOnConflict)) + FALSE, // allowVariance + throwOnConflict); + + // If there's no exact match, try a variant match + if (!foundDefaultInterfaceImplementation && pIfcMT->HasVariance()) + { + foundDefaultInterfaceImplementation = FindDefaultInterfaceImplementation( + pIfcMD, // the interface method being resolved + pIfcMT, // the interface being resolved + &pDefaultMethod, + TRUE, // allowVariance + throwOnConflict); + } + + if (foundDefaultInterfaceImplementation) { // Now, construct a DispatchSlot to return in *pImplSlot DispatchSlot ds(pDefaultMethod->GetMethodEntryPoint()); @@ -7062,6 +7078,7 @@ BOOL MethodTable::FindDefaultInterfaceImplementation( MethodDesc *pInterfaceMD, MethodTable *pInterfaceMT, MethodDesc **ppDefaultMethod, + BOOL allowVariance, BOOL throwOnConflict ) { @@ -7120,7 +7137,7 @@ BOOL MethodTable::FindDefaultInterfaceImplementation( { if (pCurMT->HasSameTypeDefAs(pInterfaceMT)) { - if (!pInterfaceMD->IsAbstract()) + if (allowVariance && !pInterfaceMD->IsAbstract()) { // Generic variance match - we'll instantiate pCurMD with the right type arguments later pCurMD = pInterfaceMD; @@ -7178,7 +7195,8 @@ BOOL MethodTable::FindDefaultInterfaceImplementation( // We do CanCastToInterface to also cover variance. // We already know this is a method on the same type definition as the (generic) // interface but we need to make sure the instantiations match. - if (pDeclMT->CanCastToInterface(pInterfaceMT)) + if ((allowVariance && pDeclMT->CanCastToInterface(pInterfaceMT)) + || pDeclMT == pInterfaceMT) { // We have a match pCurMD = pMD; @@ -7234,7 +7252,11 @@ BOOL MethodTable::FindDefaultInterfaceImplementation( break; } - if (pCurMT->CanCastToInterface(pCandidateMT)) + if (allowVariance && pCandidateMT->HasSameTypeDefAs(pCurMT)) + { + // Variant match on the same type - this is a tie + } + else if (pCurMT->CanCastToInterface(pCandidateMT)) { // pCurMT is a more specific choice than IFoo/IBar both overrides IBlah : if (!seenMoreSpecific) @@ -7281,6 +7303,8 @@ BOOL MethodTable::FindDefaultInterfaceImplementation( } // scan to see if there are any conflicts + // If we are doing second pass (allowing variance), we know don't actually look for + // a conflict anymore, but pick the first match. MethodTable *pBestCandidateMT = NULL; MethodDesc *pBestCandidateMD = NULL; for (unsigned i = 0; i < candidatesCount; ++i) @@ -7292,6 +7316,11 @@ BOOL MethodTable::FindDefaultInterfaceImplementation( { pBestCandidateMT = candidates[i].pMT; pBestCandidateMD = candidates[i].pMD; + + // If this is a second pass lookup, we know this is a variant match. As such + // we pick the first result as the winner and don't look for a conflict. + if (allowVariance) + break; } else if (pBestCandidateMT != candidates[i].pMT) { diff --git a/src/vm/methodtable.h b/src/vm/methodtable.h index c80384da79..395d0502f8 100644 --- a/src/vm/methodtable.h +++ b/src/vm/methodtable.h @@ -2459,6 +2459,7 @@ public: MethodDesc *pInterfaceMD, MethodTable *pObjectMT, MethodDesc **ppDefaultMethod, + BOOL allowVariance, BOOL throwOnConflict); #endif // DACCESS_COMPILE |