From 3f0dd78dba6a217f3857a8e8fecf6f81e7bc00b7 Mon Sep 17 00:00:00 2001 From: "Yi Zhang (CLR)" Date: Tue, 15 Aug 2017 15:55:10 -0700 Subject: [PATCH] Finalize override lookup algorithm (#12753) * first cut of multiple candidates * new positive case for diamond shape * Add proper missing implementation detection and positive diamond shape scenario support. Untested * fix bug and get test to pass * Add more diamond shape pos/neg tests * Fix bad I8 * Add GVM tests to diamond shape * GVM working * Change test case to better match diamondshape scenario * Fix MethodImpl::Iterator::GetMethodDesc and optimize no-method impl scenario * Update methodimpl test to include multiple slots and fix a bug * Temporarily disable incremental build in this branch * Update methodimpl to include multiple methodipml overriding scenario. This is triggering some bugs and need to investigate * Fix a buffer overrrun bug with interface methodimpl * Update after self-review * Add proper methodImpl validation for methods * Address feedback. Refactoring pending --- CMakeLists.txt | 4 + src/dlls/mscorrc/mscorrc.rc | 2 + src/dlls/mscorrc/resource.h | 2 + src/vm/methodimpl.cpp | 14 + src/vm/methodimpl.h | 5 +- src/vm/methodtable.cpp | 177 ++- src/vm/methodtable.h | 2 +- src/vm/methodtablebuilder.cpp | 201 ++- src/vm/methodtablebuilder.h | 27 +- .../diamondshape/diamondshape.cs | 167 ++- .../diamondshape/diamondshape.il | 699 ++++++++- .../methodimpl/methodimpl.cs | 279 +++- .../methodimpl/methodimpl.il | 1522 +++++++++++++++++++- 13 files changed, 2912 insertions(+), 189 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 38461ac..ff21c69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -344,6 +344,10 @@ if (WIN32) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG /PDBCOMPRESS") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:1572864") + # Temporarily disable incremental link due to incremental linking CFG bug crashing crossgen. + # See https://github.com/dotnet/coreclr/issues/12592 + set(NO_INCREMENTAL_LINKER_FLAGS "/INCREMENTAL:NO") + # Debug build specific flags set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "/NOVCFEATURE ${NO_INCREMENTAL_LINKER_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${NO_INCREMENTAL_LINKER_FLAGS}") diff --git a/src/dlls/mscorrc/mscorrc.rc b/src/dlls/mscorrc/mscorrc.rc index 8dd29ae..7049c42 100644 --- a/src/dlls/mscorrc/mscorrc.rc +++ b/src/dlls/mscorrc/mscorrc.rc @@ -1252,6 +1252,8 @@ BEGIN IDS_CLASSLOAD_MI_VIRTUALMISMATCH "Method '%3' on type '%1' from assembly '%2' tried to implement a method declaration with a different virtual state." IDS_CLASSLOAD_MI_MUSTBEVIRTUAL "Method '%3' on type '%1' from assembly '%2' must be virtual to implement a method on an interface or super type." IDS_CLASSLOAD_MI_BAD_SIG "Type '%1' from assembly '%2' contains an invalid method implementation signature." + IDS_CLASSLOAD_MI_FINAL_IMPL "Method implementation on an interface '%1' from assembly '%2' must be a final method." + IDS_CLASSLOAD_AMBIGUOUS_OVERRIDE "Could not call method '%1' on interface '%2' with type '%3' from assembly '%4' because there are more than one incompatible interface method overriding this method." IDS_CLASSLOAD_MISSINGMETHODRVA "Could not load type '%1' from assembly '%2' because the method '%3' has no implementation (no RVA)." SECURITY_E_INCOMPATIBLE_EVIDENCE "Assembly '%1' already loaded without additional security evidence." diff --git a/src/dlls/mscorrc/resource.h b/src/dlls/mscorrc/resource.h index 205445a..39bc8fa 100644 --- a/src/dlls/mscorrc/resource.h +++ b/src/dlls/mscorrc/resource.h @@ -613,6 +613,8 @@ #define IDS_EE_SIMD_PARTIAL_TRUST_DISALLOWED 0x1ac4 #define IDS_IBC_MISSING_EXTERNAL_TYPE 0x1ac5 #define IDS_IBC_MISSING_EXTERNAL_METHOD 0x1ac6 +#define IDS_CLASSLOAD_MI_FINAL_IMPL 0x1ac7 +#define IDS_CLASSLOAD_AMBIGUOUS_OVERRIDE 0x1ac8 #define BFA_INVALID_FILE_TOKEN 0x2000 #define BFA_INVALID_TOKEN_TYPE 0x2001 diff --git a/src/vm/methodimpl.cpp b/src/vm/methodimpl.cpp index c685e1c..b3f8451 100644 --- a/src/vm/methodimpl.cpp +++ b/src/vm/methodimpl.cpp @@ -72,6 +72,20 @@ PTR_MethodDesc MethodImpl::FindMethodDesc(DWORD slot, PTR_MethodDesc defaultRetu return defaultReturn; } + return GetMethodDesc(slotIndex, defaultReturn); +} + +PTR_MethodDesc MethodImpl::GetMethodDesc(DWORD slotIndex, PTR_MethodDesc defaultReturn) +{ + CONTRACTL + { + if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS; + if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS; + if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); } + MODE_ANY; + } + CONTRACTL_END + DPTR(RelativePointer) pRelPtrForSlot = GetImpMDsNonNull(); // The method descs are not offset by one TADDR base = dac_cast(pRelPtrForSlot) + slotIndex * sizeof(RelativePointer); diff --git a/src/vm/methodimpl.h b/src/vm/methodimpl.h index 453f4cc..ce915ea 100644 --- a/src/vm/methodimpl.h +++ b/src/vm/methodimpl.h @@ -47,7 +47,7 @@ public: inline WORD GetSlot() { WRAPPER_NO_CONTRACT; CONSISTENCY_CHECK(IsValid()); _ASSERTE(FitsIn(m_pImpl->GetSlots()[m_iCur])); return static_cast(m_pImpl->GetSlots()[m_iCur]); } inline MethodDesc *GetMethodDesc() - { WRAPPER_NO_CONTRACT; return m_pImpl->FindMethodDesc(GetSlot(), (PTR_MethodDesc) m_pMD); } + { WRAPPER_NO_CONTRACT; return m_pImpl->GetMethodDesc(m_iCur, (PTR_MethodDesc) m_pMD); } }; #endif // !DACCESS_COMPILE @@ -129,6 +129,9 @@ public: // Returns the method desc for the replaced slot; PTR_MethodDesc FindMethodDesc(DWORD slot, PTR_MethodDesc defaultReturn); + // Returns the method desc for the slot index; + PTR_MethodDesc GetMethodDesc(DWORD slotIndex, PTR_MethodDesc defaultReturn); + private: static const DWORD INVALID_INDEX = (DWORD)(-1); DWORD FindSlotIndex(DWORD slot); diff --git a/src/vm/methodtable.cpp b/src/vm/methodtable.cpp index 404d903..e27d764 100644 --- a/src/vm/methodtable.cpp +++ b/src/vm/methodtable.cpp @@ -6903,7 +6903,7 @@ MethodTable::FindDispatchImpl( // See if we can find a default method from one of the implemented interfaces // MethodDesc *pDefaultMethod = NULL; - if (FindDefaultMethod( + if (FindDefaultInterfaceImplementation( pIfcMD, // the interface method being resolved pIfcMT, // the interface being resolved &pDefaultMethod)) @@ -6943,7 +6943,46 @@ MethodTable::FindDispatchImpl( } #ifndef DACCESS_COMPILE -BOOL MethodTable::FindDefaultMethod( + +struct MatchCandidate +{ + MethodTable *pMT; + MethodDesc *pMD; +}; + +void ThrowExceptionForConflictingOverride( + MethodTable *pTargetClass, + MethodTable *pInterfaceMT, + MethodDesc *pInterfaceMD) +{ + LIMITED_METHOD_CONTRACT; + + SString assemblyName; + + pTargetClass->GetAssembly()->GetDisplayName(assemblyName); + + SString strInterfaceName; + TypeString::AppendType(strInterfaceName, TypeHandle(pInterfaceMT)); + + SString strMethodName; + TypeString::AppendMethod(strMethodName, pInterfaceMD, pInterfaceMD->GetMethodInstantiation()); + + SString strTargetClassName; + TypeString::AppendType(strTargetClassName, pTargetClass); + + COMPlusThrow( + kNotSupportedException, + IDS_CLASSLOAD_AMBIGUOUS_OVERRIDE, + strInterfaceName, + strMethodName, + strTargetClassName, + assemblyName); +} + +// Find the default interface implementation method for interface dispatch +// It is either the interface method with default interface method implementation, +// or an most specific interface with an explicit methodimpl overriding the method +BOOL MethodTable::FindDefaultInterfaceImplementation( MethodDesc *pInterfaceMD, MethodTable *pInterfaceMT, MethodDesc **ppDefaultMethod @@ -6960,20 +6999,17 @@ BOOL MethodTable::FindDefaultMethod( POSTCONDITION(!RETVAL || (*ppDefaultMethod) != nullptr); } CONTRACT_END; - // - // Find best candidate - // InterfaceMapIterator it = this->IterateInterfaceMap(); - MethodTable *pBestCandidateMT = NULL; - MethodDesc *pBestCandidateMD = NULL; - + CQuickArray candidates; + int candidatesCount = 0; + candidates.AllocThrows(this->GetNumInterfaces()); + // // Walk interface from derived class to parent class - // - // @DIM_TODO - This is a first cut naive implementation for prototyping and flush out other - // implementation issues without worrying too much about ordering/checks - // Once CLR/C# team has agreed on the right order, we'll replace this with the real deal + // We went with a straight-forward implementation as in most cases the number of interfaces are small + // and the result of the interface dispatch are already cached. If there are significant usage of default + // interface methods in highly complex interface hierarchies we can revisit this // MethodTable *pMT = this; while (pMT != NULL) @@ -7006,31 +7042,52 @@ BOOL MethodTable::FindDefaultMethod( { if (pCurMT->HasSameTypeDefAs(pInterfaceMT)) { - // Generic variance match + // Generic variance match - we'll instantiate pCurMD with the right type arguments later pCurMD = pInterfaceMD; } else { // - // Parent interface - search for an methodimpl for explicit override + // A more specific interface - search for an methodimpl for explicit override // Implicit override in default interface methods are not allowed // MethodIterator methodIt(pCurMT); for (; methodIt.IsValid(); methodIt.Next()) { MethodDesc *pMD = methodIt.GetMethodDesc(); - if (pMD->IsVirtual() && !pMD->IsAbstract() && pMD->IsMethodImpl()) + int targetSlot = pInterfaceMD->GetSlot(); + + if (pMD->IsMethodImpl()) { MethodImpl::Iterator it(pMD); - while (it.IsValid()) + for (; it.IsValid(); it.Next()) { - if (it.GetMethodDesc() == pInterfaceMD) + MethodDesc *pDeclMD = it.GetMethodDesc(); + + if (pDeclMD->GetSlot() != targetSlot) + continue; + + MethodTable *pDeclMT = pDeclMD->GetMethodTable(); + if (pDeclMT->ContainsGenericVariables()) { + TypeHandle thInstDeclMT = ClassLoader::LoadGenericInstantiationThrowing( + pDeclMT->GetModule(), + pDeclMT->GetCl(), + pCurMT->GetInstantiation()); + MethodTable *pInstDeclMT = thInstDeclMT.GetMethodTable(); + if (pInstDeclMT == pInterfaceMT) + { + // This is a matching override. We'll instantiate pCurMD later + pCurMD = pMD; + break; + } + } + else if (pDeclMD == pInterfaceMD) + { + // Exact match override pCurMD = pMD; break; } - - it.Next(); } } } @@ -7059,24 +7116,65 @@ BOOL MethodTable::FindDefaultMethod( ); } - if (pBestCandidateMT != pCurMT) - { - if (pBestCandidateMT == NULL || // first time - pCurMT->CanCastToInterface(pBestCandidateMT)) // Prefer "more specific"" interface + bool needToInsert = true; + bool seenMoreSpecific = false; + + // We need to maintain the invariant that the candidates are always the most specific + // in all path scaned so far. There might be multiple incompatible candidates + for (int i = 0; i < candidatesCount; ++i) + { + MethodTable *pCandidateMT = candidates[i].pMT; + if (pCandidateMT == NULL) + continue; + + if (pCandidateMT == pCurMT) { - // This is a better match - pBestCandidateMT = pCurMT; - pBestCandidateMD = pCurMD; + // A dup - we are done + needToInsert = false; + break; } - else + + if (pCurMT->CanCastToInterface(pCandidateMT)) { - if (!pBestCandidateMT->CanCastToInterface(pCurMT)) + // pCurMT is a more specific choice than IFoo/IBar both overrides IBlah : + // /--> IFoo ---\ + // pCurMT - -->IBlah + // \--> IBar ---/ + // Only update first entry IFoo and null out IBar + if (!seenMoreSpecific) + { + seenMoreSpecific = true; + candidates[i].pMT = pCurMT; + candidates[i].pMD = pCurMD; + } + else { - // not good. we have a conflict - COMPlusThrow(kNotSupportedException); + candidates[i].pMT = NULL; + candidates[i].pMD = NULL; } + + needToInsert = false; + } + else if (pCandidateMT->CanCastToInterface(pCurMT)) + { + // pCurMT is less specific - we don't need to scan more entries as this entry can + // represent pCurMT (other entries are incompatible with pCurMT) + needToInsert = false; + break; + } + else + { + // pCurMT is incompatible - keep scanning } } + + if (needToInsert) + { + ASSERT(candidatesCount < candidates.Size()); + candidates[candidatesCount].pMT = pCurMT; + candidates[candidatesCount].pMD = pCurMD; + candidatesCount++; + } } it.Next(); @@ -7086,6 +7184,25 @@ BOOL MethodTable::FindDefaultMethod( pMT = pParentMT; } + // scan to see if there are any conflicts + MethodTable *pBestCandidateMT = NULL; + MethodDesc *pBestCandidateMD = NULL; + for (int i = 0; i < candidatesCount; ++i) + { + if (candidates[i].pMT == NULL) + continue; + + if (pBestCandidateMT == NULL) + { + pBestCandidateMT = candidates[i].pMT; + pBestCandidateMD = candidates[i].pMD; + } + else if (pBestCandidateMT != candidates[i].pMT) + { + ThrowExceptionForConflictingOverride(this, pInterfaceMT, pInterfaceMD); + } + } + if (pBestCandidateMD != NULL) { *ppDefaultMethod = pBestCandidateMD; diff --git a/src/vm/methodtable.h b/src/vm/methodtable.h index 11296b0..118a883 100644 --- a/src/vm/methodtable.h +++ b/src/vm/methodtable.h @@ -2487,7 +2487,7 @@ public: #ifndef DACCESS_COMPILE - BOOL FindDefaultMethod( + BOOL FindDefaultInterfaceImplementation( MethodDesc *pInterfaceMD, MethodTable *pObjectMT, MethodDesc **ppDefaultMethod); diff --git a/src/vm/methodtablebuilder.cpp b/src/vm/methodtablebuilder.cpp index 2f76d7f..3a738df 100644 --- a/src/vm/methodtablebuilder.cpp +++ b/src/vm/methodtablebuilder.cpp @@ -1622,6 +1622,10 @@ MethodTableBuilder::BuildMethodTableThrowing( if (IsInterface()) { + // + // We need to process/place method impls for default interface method overrides. + // We won't build dispatch map for interfaces, though. + // ProcessMethodImpls(); PlaceMethodImpls(); } @@ -4786,6 +4790,12 @@ VOID MethodTableBuilder::TestMethodImpl( BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_DECL); } + // Interface method body that has methodimpl should always be final + if (IsInterface() && !IsMdFinal(dwImplAttrs)) + { + BuildMethodTableThrowException(IDS_CLASSLOAD_MI_FINAL_IMPL); + } + // Since MethodImpl's do not affect the visibility of the Decl method, there's // no need to check. @@ -5568,6 +5578,9 @@ MethodTableBuilder::ProcessMethodImpls() { STANDARD_VM_CONTRACT; + if (bmtMethod->dwNumberMethodImpls == 0) + return; + HRESULT hr = S_OK; DeclaredMethodIterator it(*this); @@ -6159,9 +6172,12 @@ MethodTableBuilder::PlaceMethodImpls() } // Allocate some temporary storage. The number of overrides for a single method impl - // cannot be greater then the number of vtable slots. - DWORD * slots = new (&GetThread()->m_MarshalAlloc) DWORD[bmtVT->cVirtualSlots]; - RelativePointer * replaced = new (&GetThread()->m_MarshalAlloc) RelativePointer[bmtVT->cVirtualSlots]; + // cannot be greater then the number of vtable slots for classes. But for interfaces + // it might contain overrides for other interface methods. + DWORD dwMaxSlotSize = IsInterface() ? bmtMethod->dwNumberMethodImpls : bmtVT->cVirtualSlots; + + DWORD * slots = new (&GetThread()->m_MarshalAlloc) DWORD[dwMaxSlotSize]; + RelativePointer * replaced = new (&GetThread()->m_MarshalAlloc) RelativePointer[dwMaxSlotSize]; DWORD iEntry = 0; bmtMDMethod * pCurImplMethod = bmtMethodImpl->GetImplementationMethod(iEntry); @@ -6179,7 +6195,8 @@ MethodTableBuilder::PlaceMethodImpls() // (declaration is on this type) or a method desc. bmtMethodHandle hDeclMethod = bmtMethodImpl->GetDeclarationMethod(iEntry); if(hDeclMethod.IsMDMethod()) - { // The declaration is on the type being built + { + // The declaration is on the type being built bmtMDMethod * pCurDeclMethod = hDeclMethod.AsMDMethod(); mdToken mdef = pCurDeclMethod->GetMethodSignature().GetToken(); @@ -6190,22 +6207,25 @@ MethodTableBuilder::PlaceMethodImpls() if (IsInterface()) { - // We implement this slot, record it - slots[slotIndex] = pCurDeclMethod->GetSlotIndex(); - replaced[slotIndex].SetValue(pCurDeclMethod->GetMethodDesc()); - - // increment the counter - slotIndex++; + // Throws + PlaceInterfaceDeclarationOnInterface( + hDeclMethod, + pCurImplMethod, + slots, // Adds override to the slot and replaced arrays. + replaced, + &slotIndex, + dwMaxSlotSize); // Increments count } else { // Throws - PlaceLocalDeclaration( + PlaceLocalDeclarationOnClass( pCurDeclMethod, pCurImplMethod, - slots, // Adds override to the slot and replaced arrays. + slots, // Adds override to the slot and replaced arrays. replaced, - &slotIndex); // Increments count + &slotIndex, + dwMaxSlotSize); // Increments count } } else @@ -6214,12 +6234,14 @@ MethodTableBuilder::PlaceMethodImpls() if (IsInterface()) { - // We implement this slot, record it - slots[slotIndex] = pCurDeclMethod->GetSlotIndex(); - replaced[slotIndex].SetValue(pCurDeclMethod->GetMethodDesc()); - - // increment the counter - slotIndex++; + // Throws + PlaceInterfaceDeclarationOnInterface( + hDeclMethod, + pCurImplMethod, + slots, // Adds override to the slot and replaced arrays. + replaced, + &slotIndex, + dwMaxSlotSize); // Increments count } else { @@ -6227,22 +6249,20 @@ MethodTableBuilder::PlaceMethodImpls() if (pCurDeclMethod->GetOwningType()->IsInterface()) { // Throws - PlaceInterfaceDeclaration( + PlaceInterfaceDeclarationOnClass( pCurDeclMethod, - pCurImplMethod, - slots, - replaced, - &slotIndex); // Increments count + pCurImplMethod); } else { // Throws - PlaceParentDeclaration( + PlaceParentDeclarationOnClass( pCurDeclMethod, pCurImplMethod, slots, replaced, - &slotIndex); // Increments count + &slotIndex, + dwMaxSlotSize); // Increments count } } } @@ -6250,7 +6270,8 @@ MethodTableBuilder::PlaceMethodImpls() iEntry++; if(iEntry == bmtMethodImpl->pIndex) - { // We hit the end of the list so dump the current data and leave + { + // We hit the end of the list so dump the current data and leave WriteMethodImplData(pCurImplMethod, slotIndex, slots, replaced); break; } @@ -6259,7 +6280,8 @@ MethodTableBuilder::PlaceMethodImpls() bmtMDMethod * pNextImplMethod = bmtMethodImpl->GetImplementationMethod(iEntry); if (pNextImplMethod != pCurImplMethod) - { // If we're moving on to a new body, dump the current data and reset the counter + { + // If we're moving on to a new body, dump the current data and reset the counter WriteMethodImplData(pCurImplMethod, slotIndex, slots, replaced); slotIndex = 0; } @@ -6302,6 +6324,8 @@ MethodTableBuilder::WriteMethodImplData( { // If we are currently builting an interface, the slots here has no meaning and we can skip it // Sort the two arrays in slot index order + // This is required in MethodImpl::FindSlotIndex and MethodImpl::Iterator as we'll be using + // binary search later for (DWORD i = 0; i < cSlots; i++) { int min = i; @@ -6335,12 +6359,13 @@ MethodTableBuilder::WriteMethodImplData( //******************************************************************************* VOID -MethodTableBuilder::PlaceLocalDeclaration( +MethodTableBuilder::PlaceLocalDeclarationOnClass( bmtMDMethod * pDecl, bmtMDMethod * pImpl, DWORD * slots, RelativePointer * replaced, - DWORD * pSlotIndex) + DWORD * pSlotIndex, + DWORD dwMaxSlotSize) { CONTRACTL { @@ -6395,20 +6420,18 @@ MethodTableBuilder::PlaceLocalDeclaration( pImpl); // We implement this slot, record it + ASSERT(*pSlotIndex < dwMaxSlotSize); slots[*pSlotIndex] = pDecl->GetSlotIndex(); replaced[*pSlotIndex].SetValue(pDecl->GetMethodDesc()); // increment the counter (*pSlotIndex)++; -} // MethodTableBuilder::PlaceLocalDeclaration +} // MethodTableBuilder::PlaceLocalDeclarationOnClass //******************************************************************************* -VOID MethodTableBuilder::PlaceInterfaceDeclaration( +VOID MethodTableBuilder::PlaceInterfaceDeclarationOnClass( bmtRTMethod * pDecl, - bmtMDMethod * pImpl, - DWORD* slots, - RelativePointer * replaced, - DWORD* pSlotIndex) + bmtMDMethod * pImpl) { CONTRACTL { STANDARD_VM_CHECK; @@ -6504,16 +6527,60 @@ VOID MethodTableBuilder::PlaceInterfaceDeclaration( } } #endif //_DEBUG -} // MethodTableBuilder::PlaceInterfaceDeclaration +} // MethodTableBuilder::PlaceInterfaceDeclarationOnClass + +//******************************************************************************* +VOID MethodTableBuilder::PlaceInterfaceDeclarationOnInterface( + bmtMethodHandle hDecl, + bmtMDMethod *pImpl, + DWORD * slots, + RelativePointer * replaced, + DWORD * pSlotIndex, + DWORD dwMaxSlotSize) +{ + CONTRACTL { + STANDARD_VM_CHECK; + PRECONDITION(CheckPointer(pImpl)); + PRECONDITION(IsInterface()); + PRECONDITION(hDecl.GetMethodDesc()->IsInterface()); + } CONTRACTL_END; + + MethodDesc * pDeclMD = hDecl.GetMethodDesc(); + + if (!bmtProp->fNoSanityChecks) + { + /////////////////////////////// + // Verify the signatures match + + MethodImplCompareSignatures( + hDecl, + bmtMethodHandle(pImpl), + IDS_CLASSLOAD_CONSTRAINT_MISMATCH_ON_INTERFACE_METHOD_IMPL); + + /////////////////////////////// + // Validate the method impl. + + TestMethodImpl(hDecl, bmtMethodHandle(pImpl)); + } + + // We implement this slot, record it + ASSERT(*pSlotIndex < dwMaxSlotSize); + slots[*pSlotIndex] = hDecl.GetSlotIndex(); + replaced[*pSlotIndex].SetValue(pDeclMD); + + // increment the counter + (*pSlotIndex)++; +} // MethodTableBuilder::PlaceInterfaceDeclarationOnInterface //******************************************************************************* VOID -MethodTableBuilder::PlaceParentDeclaration( +MethodTableBuilder::PlaceParentDeclarationOnClass( bmtRTMethod * pDecl, bmtMDMethod * pImpl, DWORD * slots, RelativePointer * replaced, - DWORD * pSlotIndex) + DWORD * pSlotIndex, + DWORD dwMaxSlotSize) { CONTRACTL { STANDARD_VM_CHECK; @@ -6556,12 +6623,13 @@ MethodTableBuilder::PlaceParentDeclaration( pImpl); // We implement this slot, record it + ASSERT(*pSlotIndex < dwMaxSlotSize); slots[*pSlotIndex] = pDeclMD->GetSlot(); replaced[*pSlotIndex].SetValue(pDeclMD); // increment the counter (*pSlotIndex)++; -} // MethodTableBuilder::PlaceParentDeclaration +} // MethodTableBuilder::PlaceParentDeclarationOnClass //******************************************************************************* // This will validate that all interface methods that were matched during @@ -10783,6 +10851,45 @@ MethodTableBuilder::SetupMethodTable2( #pragma warning(pop) #endif +// Returns true if there is at least one default implementation for this interface method +// We don't care about conflicts at this stage in order to avoid impact type load performance +BOOL MethodTableBuilder::HasDefaultInterfaceImplementation(MethodDesc *pDeclMD) +{ + STANDARD_VM_CONTRACT; + + // If the interface method is already non-abstract, we are done + if (pDeclMD->IsDefaultInterfaceMethod()) + return TRUE; + + MethodTable *pDeclMT = pDeclMD->GetMethodTable(); + + // Otherwise, traverse the list of interfaces and see if there is at least one override + bmtInterfaceInfo::MapIterator intIt = bmtInterface->IterateInterfaceMap(); + for (; !intIt.AtEnd(); intIt.Next()) + { + MethodTable *pIntfMT = intIt->GetInterfaceType()->GetMethodTable(); + if (pIntfMT->GetClass()->ContainsMethodImpls() && pIntfMT->CanCastToInterface(pDeclMT)) + { + MethodTable::MethodIterator methodIt(pIntfMT); + for (; methodIt.IsValid(); methodIt.Next()) + { + MethodDesc *pMD = methodIt.GetMethodDesc(); + if (pMD->IsMethodImpl()) + { + MethodImpl::Iterator it(pMD); + while (it.IsValid()) + { + if (it.GetMethodDesc() == pDeclMD) + return TRUE; + } + } + } + } + } + + return FALSE; +} + void MethodTableBuilder::VerifyVirtualMethodsImplemented(MethodTable::MethodData * hMTData) { STANDARD_VM_CONTRACT; @@ -10855,13 +10962,13 @@ void MethodTableBuilder::VerifyVirtualMethodsImplemented(MethodTable::MethodData MethodTable::MethodIterator it(hData); for (; it.IsValid() && it.IsVirtual(); it.Next()) { - // @DIM_TODO - What is the right level of check if the interface itself does not have default implementation - // but a derived interface do - // if (it.GetTarget().IsNull()) - // { - // MethodDesc *pMD = it.GetDeclMethodDesc(); - // BuildMethodTableThrowException(IDS_CLASSLOAD_NOTIMPLEMENTED, pMD->GetNameOnNonArrayClass()); - // } + if (it.GetTarget().IsNull()) + { + MethodDesc *pMD = it.GetDeclMethodDesc(); + + if (!HasDefaultInterfaceImplementation(pMD)) + BuildMethodTableThrowException(IDS_CLASSLOAD_NOTIMPLEMENTED, pMD->GetNameOnNonArrayClass()); + } } } } diff --git a/src/vm/methodtablebuilder.h b/src/vm/methodtablebuilder.h index e5043cf..8c838d3 100644 --- a/src/vm/methodtablebuilder.h +++ b/src/vm/methodtablebuilder.h @@ -2739,32 +2739,42 @@ private: // -------------------------------------------------------------------------------------------- // Places a methodImpl pair where the decl is declared by the type being built. VOID - PlaceLocalDeclaration( + PlaceLocalDeclarationOnClass( bmtMDMethod * pDecl, bmtMDMethod * pImpl, DWORD* slots, RelativePointer * replaced, - DWORD* pSlotIndex); + DWORD* pSlotIndex, + DWORD dwMaxSlotSize); // -------------------------------------------------------------------------------------------- // Places a methodImpl pair where the decl is declared by a parent type. VOID - PlaceParentDeclaration( + PlaceParentDeclarationOnClass( bmtRTMethod * pDecl, bmtMDMethod * pImpl, DWORD* slots, RelativePointer * replaced, - DWORD* pSlotIndex); + DWORD* pSlotIndex, + DWORD dwMaxSlotSize); // -------------------------------------------------------------------------------------------- - // Places a methodImpl pair where the decl is declared by an interface. + // Places a methodImpl pair on a class where the decl is declared by an interface. VOID - PlaceInterfaceDeclaration( + PlaceInterfaceDeclarationOnClass( bmtRTMethod * pDecl, - bmtMDMethod * pImpl, + bmtMDMethod * pImpl); + + // -------------------------------------------------------------------------------------------- + // Places a methodImpl pair on an interface where the decl is declared by an interface. + VOID + PlaceInterfaceDeclarationOnInterface( + bmtMethodHandle hDecl, + bmtMDMethod * pImpl, DWORD* slots, RelativePointer * replaced, - DWORD* pSlotIndex); + DWORD* pSlotIndex, + DWORD dwMaxSlotSize); // -------------------------------------------------------------------------------------------- // This will validate that all interface methods that were matched during @@ -2846,6 +2856,7 @@ private: VOID HandleGCForValueClasses( MethodTable **); + BOOL HasDefaultInterfaceImplementation(MethodDesc *pIntfMD); VOID VerifyVirtualMethodsImplemented(MethodTable::MethodData * hMTData); VOID CheckForTypeEquivalence( diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/diamondshape/diamondshape.cs b/tests/src/Loader/classloader/DefaultInterfaceMethods/diamondshape/diamondshape.cs index f6c7786..3ff3760 100644 --- a/tests/src/Loader/classloader/DefaultInterfaceMethods/diamondshape/diamondshape.cs +++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/diamondshape/diamondshape.cs @@ -48,9 +48,113 @@ class FooClass : IFoo2, IFooEx } } +interface I1 +{ + int Func(int a); +} + +interface I2 : I1 +{ + // int I1.Func(int a) { return a + 2; } +} + +interface I3 : I1 +{ + // int I1.Func(int a) { return a + 3; } +} + +interface I4 : I2, I3 +{ + // int I1.Func(int a) { return a + 4; } +} + +class I4Class : I4 +{ + // @REMOVE + int I1.Func(int a) + { + Console.WriteLine("At I4Class.Func"); + return a + 4; + } +} + +interface I5: I1 +{ + // int I1.Func(int a) { return a + 5; } +} + +interface I6: I1 +{ + // int I1.Func(int a) { return a + 6; } +} + +interface I7: I5, I6 +{ + // int I1.Func(int a) { return a + 7; } +} + +interface I8: I4, I7 +{ + // int I1.Func(int a) { return a + 8; } +} + +class I47Class: I4, I7 +{ + // @REMOVE + int I1.Func(int a) + { + Console.WriteLine("At I4Class.Func"); + return a + 8; + } + +} + +class I8Class: I8 +{ + // @REMOVE + int I1.Func(int a) + { + Console.WriteLine("At I4Class.Func"); + return a + 8; + } +} + +interface GI1 +{ + int Func(out Type[] types); +} + +interface GI2 : GI1 +{ + // int GI1.Func(out Type[] types) { Console.WriteLine(typeof(T) + ", "typeof(S) + ", GI1Class"); types = new Type[] { typeof(T), typeof(S) }; return 2; } + +} + +interface GI3 : GI1 +{ + // int GI1.Func(out Type[] types) { Console.WriteLine(typeof(T) + ", "typeof(S) + ", GI1Class"); types = new Type[] { typeof(T), typeof(S) }; return 3; } +} + +interface GI4 : GI2, GI3 +{ + // int GI1.Func(out Type[] types) { Console.WriteLine(typeof(T) + ", "typeof(S) + ", GI1Class"); types = new Type[] { typeof(T), typeof(S) }; return 4; } +} + +class GI23Class: GI2, GI3 +{ + // @REMOVE + int GI1.Func(out Type[] types) { Console.WriteLine(typeof(T) + ", " + typeof(S) + ", GI1Class"); types = new Type[] { typeof(T), typeof(S) }; return 4; } +} + +class GI4Class: GI4 +{ + // @REMOVE + int GI1.Func(out Type[] types) { Console.WriteLine(typeof(T) + ", " + typeof(S) + ", GI1Class"); types = new Type[] { typeof(T), typeof(S) }; return 4; } +} + class Program { - public static int Main() + public static void Negative() { FooClass fooObj = new FooClass(); IFoo foo = (IFoo) fooObj; @@ -59,12 +163,69 @@ class Program try { foo.Foo(10); - Test.Assert(false, "Expecting exception"); + Test.Assert(false, "Expecting exception on Foo"); + } + catch(Exception ex) + { + Console.WriteLine("Exception caught: " + ex.ToString()); } - catch(Exception) + + I47Class i47Class = new I47Class(); + I1 i1 = (I1) i47Class; + Console.WriteLine("Calling I1.Func on I47Class - expecting exception"); + try + { + i1.Func(10); + Test.Assert(false, "Expecting exception on I47Class"); + } + catch(Exception ex) + { + Console.WriteLine("Exception caught: " + ex.ToString()); + } + + var gi23Class = new GI23Class(); + GI1 gi1 = (GI1) gi23Class; + Console.WriteLine("Calling GI1.Func on GI23Class - expecting exception"); + try { + Type[] types; + gi1.Func(out types); + Test.Assert(false, "Expecting exception on GI23Class"); } + catch(Exception ex) + { + Console.WriteLine("Exception caught: " + ex.ToString()); + } + } + public static void Positive() + { + Console.WriteLine("Calling I1.Func on I4Class - expecting I4.Func"); + + I4Class i4Class = new I4Class(); + I1 i1 = (I1) i4Class; + Test.Assert(i1.Func(10) == 14, "Expecting I1.Func to land on I4.Func"); + + Console.WriteLine("Calling I1.Func on I8Class - expecting I8.Func"); + + I8Class i8Class = new I8Class(); + i1 = (I1) i8Class; + Test.Assert(i1.Func(10) == 18, "Expecting I1.Func to land on I8.Func"); + + Console.WriteLine("Calling GI1.Func on GI4Class - expecting GI4.Func"); + + var gi4Class = new GI4Class(); + Type[] types; + var gi1 = (GI1) gi4Class; + Test.Assert(gi1.Func(out types) == 4, "Expecting GI1.Func to land on GII4.Func"); + Test.Assert(types[0] == typeof(object), "T must be object"); + Test.Assert(types[1] == typeof(string), "S must be string"); + } + + public static int Main() + { + Negative(); + Positive(); return Test.Ret(); } } diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/diamondshape/diamondshape.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/diamondshape/diamondshape.il index 82d9fa7..4173bc6 100644 --- a/tests/src/Loader/classloader/DefaultInterfaceMethods/diamondshape/diamondshape.il +++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/diamondshape/diamondshape.il @@ -123,17 +123,505 @@ } // end of class FooClass +.class interface private abstract auto ansi I1 +{ + .method public hidebysig newslot abstract virtual + instance int32 Func(int32 a) cil managed + { + } // end of method I1::Func + +} // end of class I1 + +.class interface private abstract auto ansi I2 + implements I1 +{ + .method private hidebysig newslot virtual final + instance int32 I1.Func(int32 a) cil managed + { + .override I1::Func + // Code size 20 (0x14) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At I2.Func" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.2 + IL_000e: add + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method I2::I1.Func +} // end of class I2 + +.class interface private abstract auto ansi I3 + implements I1 +{ + .method private hidebysig newslot virtual final + instance int32 I1.Func(int32 a) cil managed + { + .override I1::Func + // Code size 20 (0x14) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At I3.Func" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.3 + IL_000e: add + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method I3::I1.Func +} // end of class I3 + +.class interface private abstract auto ansi I4 + implements I2, + I1, + I3 +{ + .method private hidebysig newslot virtual final + instance int32 I1.Func(int32 a) cil managed + { + .override I1::Func + // Code size 20 (0x14) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At I4.Func" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.4 + IL_000e: add + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method I4::I1.Func +} // end of class I4 + +.class private auto ansi beforefieldinit I4Class + extends [mscorlib]System.Object + implements I4, + I2, + I1, + I3 +{ + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method I4Class::.ctor + +} // end of class I4Class + +.class interface private abstract auto ansi I5 + implements I1 +{ + .method private hidebysig newslot virtual final + instance int32 I1.Func(int32 a) cil managed + { + .override I1::Func + // Code size 20 (0x14) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At I5.Func" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.5 + IL_000e: add + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method I5::I1.Func +} // end of class I5 + +.class interface private abstract auto ansi I6 + implements I1 +{ + .method private hidebysig newslot virtual final + instance int32 I1.Func(int32 a) cil managed + { + .override I1::Func + // Code size 20 (0x14) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At I6.Func" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.6 + IL_000e: add + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method I6::I1.Func +} // end of class I6 + +.class interface private abstract auto ansi I7 + implements I5, + I1, + I6 +{ + .method private hidebysig newslot virtual final + instance int32 I1.Func(int32 a) cil managed + { + .override I1::Func + // Code size 20 (0x14) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At I7.Func" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.7 + IL_000e: add + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method I7::I1.Func +} // end of class I7 + +.class interface private abstract auto ansi I8 + implements I4, + I2, + I1, + I3, + I7, + I5, + I6 +{ + .method private hidebysig newslot virtual final + instance int32 I1.Func(int32 a) cil managed + { + .override I1::Func + // Code size 20 (0x14) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At I8.Func" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.8 + IL_000e: add + IL_000f: stloc.0 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.0 + IL_0013: ret + } // end of method I8::I1.Func +} // end of class I8 + +.class private auto ansi beforefieldinit I47Class + extends [mscorlib]System.Object + implements I4, + I2, + I1, + I3, + I7, + I5, + I6 +{ + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method I47Class::.ctor + +} // end of class I47Class + +.class private auto ansi beforefieldinit I8Class + extends [mscorlib]System.Object + implements I8, + I4, + I2, + I1, + I3, + I7, + I5, + I6 +{ + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method I8Class::.ctor + +} // end of class I8Class + +.class interface private abstract auto ansi GI1`1 +{ + .method public hidebysig newslot abstract virtual + instance int32 Func([out] class [mscorlib]System.Type[]& types) cil managed + { + } // end of method GI1`1::'GI1.Func' + +} // end of class GI1`1 + +.class interface private abstract auto ansi GI2`1 + implements class GI1`1 +{ +.method private hidebysig newslot virtual final + instance int32 'GI1.Func'([out] class [mscorlib]System.Type[]& types) cil managed + { + .override method instance int32 class GI1`1::Func<[1]>(class [mscorlib]System.Type[]&) + // Code size 100 (0x64) + .maxstack 5 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldc.i4.4 + IL_0002: newarr [mscorlib]System.Object + IL_0007: dup + IL_0008: ldc.i4.0 + IL_0009: ldtoken !T + IL_000e: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_0013: stelem.ref + IL_0014: dup + IL_0015: ldc.i4.1 + IL_0016: ldstr ", " + IL_001b: stelem.ref + IL_001c: dup + IL_001d: ldc.i4.2 + IL_001e: ldtoken !!S + IL_0023: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_0028: stelem.ref + IL_0029: dup + IL_002a: ldc.i4.3 + IL_002b: ldstr ", GI2" + IL_0030: stelem.ref + IL_0031: call string [mscorlib]System.String::Concat(object[]) + IL_0036: call void [mscorlib]System.Console::WriteLine(string) + IL_003b: nop + IL_003c: ldarg.1 + IL_003d: ldc.i4.2 + IL_003e: newarr [mscorlib]System.Type + IL_0043: dup + IL_0044: ldc.i4.0 + IL_0045: ldtoken !T + IL_004a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_004f: stelem.ref + IL_0050: dup + IL_0051: ldc.i4.1 + IL_0052: ldtoken !!S + IL_0057: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_005c: stelem.ref + IL_005d: stind.ref + IL_005e: ldc.i4.2 + IL_005f: stloc.0 + IL_0060: br.s IL_0062 + + IL_0062: ldloc.0 + IL_0063: ret + } // end of method G2`1::'GI1.Func' +} // end of class GI2`1 + +.class interface private abstract auto ansi GI3`1 + implements class GI1`1 +{ +.method private hidebysig newslot virtual final + instance int32 'GI1.Func'([out] class [mscorlib]System.Type[]& types) cil managed + { + .override method instance int32 class GI1`1::Func<[1]>(class [mscorlib]System.Type[]&) + // Code size 100 (0x64) + .maxstack 5 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldc.i4.4 + IL_0002: newarr [mscorlib]System.Object + IL_0007: dup + IL_0008: ldc.i4.0 + IL_0009: ldtoken !T + IL_000e: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_0013: stelem.ref + IL_0014: dup + IL_0015: ldc.i4.1 + IL_0016: ldstr ", " + IL_001b: stelem.ref + IL_001c: dup + IL_001d: ldc.i4.2 + IL_001e: ldtoken !!S + IL_0023: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_0028: stelem.ref + IL_0029: dup + IL_002a: ldc.i4.3 + IL_002b: ldstr ", GI3" + IL_0030: stelem.ref + IL_0031: call string [mscorlib]System.String::Concat(object[]) + IL_0036: call void [mscorlib]System.Console::WriteLine(string) + IL_003b: nop + IL_003c: ldarg.1 + IL_003d: ldc.i4.2 + IL_003e: newarr [mscorlib]System.Type + IL_0043: dup + IL_0044: ldc.i4.0 + IL_0045: ldtoken !T + IL_004a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_004f: stelem.ref + IL_0050: dup + IL_0051: ldc.i4.1 + IL_0052: ldtoken !!S + IL_0057: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_005c: stelem.ref + IL_005d: stind.ref + IL_005e: ldc.i4.3 + IL_005f: stloc.0 + IL_0060: br.s IL_0062 + + IL_0062: ldloc.0 + IL_0063: ret + } // end of method GI3`1::'GI1.Func' +} // end of class GI3`1 + +.class interface private abstract auto ansi GI4`1 + implements class GI2`1, + class GI1`1, + class GI3`1 +{ + .method private hidebysig newslot virtual final + instance int32 'GI1.Func'([out] class [mscorlib]System.Type[]& types) cil managed + { + .override method instance int32 class GI1`1::Func<[1]>(class [mscorlib]System.Type[]&) + // Code size 100 (0x64) + .maxstack 5 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldc.i4.4 + IL_0002: newarr [mscorlib]System.Object + IL_0007: dup + IL_0008: ldc.i4.0 + IL_0009: ldtoken !T + IL_000e: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_0013: stelem.ref + IL_0014: dup + IL_0015: ldc.i4.1 + IL_0016: ldstr ", " + IL_001b: stelem.ref + IL_001c: dup + IL_001d: ldc.i4.2 + IL_001e: ldtoken !!S + IL_0023: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_0028: stelem.ref + IL_0029: dup + IL_002a: ldc.i4.3 + IL_002b: ldstr ", GI4" + IL_0030: stelem.ref + IL_0031: call string [mscorlib]System.String::Concat(object[]) + IL_0036: call void [mscorlib]System.Console::WriteLine(string) + IL_003b: nop + IL_003c: ldarg.1 + IL_003d: ldc.i4.2 + IL_003e: newarr [mscorlib]System.Type + IL_0043: dup + IL_0044: ldc.i4.0 + IL_0045: ldtoken !T + IL_004a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_004f: stelem.ref + IL_0050: dup + IL_0051: ldc.i4.1 + IL_0052: ldtoken !!S + IL_0057: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_005c: stelem.ref + IL_005d: stind.ref + IL_005e: ldc.i4.4 + IL_005f: stloc.0 + IL_0060: br.s IL_0062 + + IL_0062: ldloc.0 + IL_0063: ret + } // end of method GI4`1::'GI1.Func' +} // end of class GI4`1 + +.class private auto ansi beforefieldinit GI23Class`1 + extends [mscorlib]System.Object + implements class GI2`1, + class GI1`1, + class GI3`1 +{ + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method GI23Class`1::.ctor + +} // end of class GI23Class`1 + +.class private auto ansi beforefieldinit GI4Class`1 + extends [mscorlib]System.Object + implements class GI4`1, + class GI2`1, + class GI1`1, + class GI3`1 +{ + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method GI4Class`1::.ctor + +} // end of class GI4Class`1 + .class private auto ansi beforefieldinit Program extends [mscorlib]System.Object { - .method public hidebysig static int32 Main() cil managed + .method public hidebysig static void Negative() cil managed { - .entrypoint - // Code size 60 (0x3c) + // Code size 225 (0xe1) .maxstack 2 .locals init (class FooClass V_0, class IFoo V_1, - int32 V_2) + class I47Class V_2, + class I1 V_3, + class GI23Class`1 V_4, + class GI1`1 V_5, + class [mscorlib]System.Exception V_6, + class [mscorlib]System.Exception V_7, + class [mscorlib]System.Type[] V_8, + class [mscorlib]System.Exception V_9) IL_0000: nop IL_0001: newobj instance void FooClass::.ctor() IL_0006: stloc.0 @@ -150,28 +638,211 @@ IL_0018: callvirt instance int32 IFoo::Foo(int32) IL_001d: pop IL_001e: ldc.i4.0 - IL_001f: ldstr "Expecting exception" + IL_001f: ldstr "Expecting exception on Foo" IL_0024: call void Test::Assert(bool, string) IL_0029: nop IL_002a: nop - IL_002b: leave.s IL_0032 + IL_002b: leave.s IL_004a } // end .try catch [mscorlib]System.Exception { - IL_002d: pop - IL_002e: nop + IL_002d: stloc.s V_6 IL_002f: nop - IL_0030: leave.s IL_0032 + IL_0030: ldstr "Exception caught: " + IL_0035: ldloc.s V_6 + IL_0037: callvirt instance string [mscorlib]System.Object::ToString() + IL_003c: call string [mscorlib]System.String::Concat(string, + string) + IL_0041: call void [mscorlib]System.Console::WriteLine(string) + IL_0046: nop + IL_0047: nop + IL_0048: leave.s IL_004a } // end handler - IL_0032: call int32 Test::Ret() - IL_0037: stloc.2 - IL_0038: br.s IL_003a + IL_004a: newobj instance void I47Class::.ctor() + IL_004f: stloc.2 + IL_0050: ldloc.2 + IL_0051: stloc.3 + IL_0052: ldstr "Calling I1.Func on I47Class - expecting exception" + IL_0057: call void [mscorlib]System.Console::WriteLine(string) + IL_005c: nop + .try + { + IL_005d: nop + IL_005e: ldloc.3 + IL_005f: ldc.i4.s 10 + IL_0061: callvirt instance int32 I1::Func(int32) + IL_0066: pop + IL_0067: ldc.i4.0 + IL_0068: ldstr "Expecting exception on I47Class" + IL_006d: call void Test::Assert(bool, + string) + IL_0072: nop + IL_0073: nop + IL_0074: leave.s IL_0093 - IL_003a: ldloc.2 - IL_003b: ret + } // end .try + catch [mscorlib]System.Exception + { + IL_0076: stloc.s V_7 + IL_0078: nop + IL_0079: ldstr "Exception caught: " + IL_007e: ldloc.s V_7 + IL_0080: callvirt instance string [mscorlib]System.Object::ToString() + IL_0085: call string [mscorlib]System.String::Concat(string, + string) + IL_008a: call void [mscorlib]System.Console::WriteLine(string) + IL_008f: nop + IL_0090: nop + IL_0091: leave.s IL_0093 + + } // end handler + IL_0093: newobj instance void class GI23Class`1::.ctor() + IL_0098: stloc.s V_4 + IL_009a: ldloc.s V_4 + IL_009c: stloc.s V_5 + IL_009e: ldstr "Calling GI1.Func on GI23Class - expecting ex" + + "ception" + IL_00a3: call void [mscorlib]System.Console::WriteLine(string) + IL_00a8: nop + .try + { + IL_00a9: nop + IL_00aa: ldloc.s V_5 + IL_00ac: ldloca.s V_8 + IL_00ae: callvirt instance int32 class GI1`1::Func(class [mscorlib]System.Type[]&) + IL_00b3: pop + IL_00b4: ldc.i4.0 + IL_00b5: ldstr "Expecting exception on GI23Class" + IL_00ba: call void Test::Assert(bool, + string) + IL_00bf: nop + IL_00c0: nop + IL_00c1: leave.s IL_00e0 + + } // end .try + catch [mscorlib]System.Exception + { + IL_00c3: stloc.s V_9 + IL_00c5: nop + IL_00c6: ldstr "Exception caught: " + IL_00cb: ldloc.s V_9 + IL_00cd: callvirt instance string [mscorlib]System.Object::ToString() + IL_00d2: call string [mscorlib]System.String::Concat(string, + string) + IL_00d7: call void [mscorlib]System.Console::WriteLine(string) + IL_00dc: nop + IL_00dd: nop + IL_00de: leave.s IL_00e0 + + } // end handler + IL_00e0: ret + } // end of method Program::Negative + + .method public hidebysig static void Positive() cil managed + { + // Code size 189 (0xbd) + .maxstack 2 + .locals init (class I4Class V_0, + class I1 V_1, + class I8Class V_2, + class GI4Class`1 V_3, + class [mscorlib]System.Type[] V_4, + class GI1`1 V_5) + IL_0000: nop + IL_0001: ldstr "Calling I1.Func on I4Class - expecting I4.Func" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: newobj instance void I4Class::.ctor() + IL_0011: stloc.0 + IL_0012: ldloc.0 + IL_0013: stloc.1 + IL_0014: ldloc.1 + IL_0015: ldc.i4.s 10 + IL_0017: callvirt instance int32 I1::Func(int32) + IL_001c: ldc.i4.s 14 + IL_001e: ceq + IL_0020: ldstr "Expecting I1.Func to land on I4.Func" + IL_0025: call void Test::Assert(bool, + string) + IL_002a: nop + IL_002b: ldstr "Calling I1.Func on I8Class - expecting I8.Func" + IL_0030: call void [mscorlib]System.Console::WriteLine(string) + IL_0035: nop + IL_0036: newobj instance void I8Class::.ctor() + IL_003b: stloc.2 + IL_003c: ldloc.2 + IL_003d: stloc.1 + IL_003e: ldloc.1 + IL_003f: ldc.i4.s 10 + IL_0041: callvirt instance int32 I1::Func(int32) + IL_0046: ldc.i4.s 18 + IL_0048: ceq + IL_004a: ldstr "Expecting I1.Func to land on I8.Func" + IL_004f: call void Test::Assert(bool, + string) + IL_0054: nop + IL_0055: ldstr "Calling GI1.Func on GI4Class - expecting G" + + "I4.Func" + IL_005a: call void [mscorlib]System.Console::WriteLine(string) + IL_005f: nop + IL_0060: newobj instance void class GI4Class`1::.ctor() + IL_0065: stloc.3 + IL_0066: ldloc.3 + IL_0067: stloc.s V_5 + IL_0069: ldloc.s V_5 + IL_006b: ldloca.s V_4 + IL_006d: callvirt instance int32 class GI1`1::Func(class [mscorlib]System.Type[]&) + IL_0072: ldc.i4.4 + IL_0073: ceq + IL_0075: ldstr "Expecting GI1.Func to land on GII4.Func" + IL_007a: call void Test::Assert(bool, + string) + IL_007f: nop + IL_0080: ldloc.s V_4 + IL_0082: ldc.i4.0 + IL_0083: ldelem.ref + IL_0084: ldtoken [mscorlib]System.Object + IL_0089: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_008e: call bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type, + class [mscorlib]System.Type) + IL_0093: ldstr "T must be object" + IL_0098: call void Test::Assert(bool, + string) + IL_009d: nop + IL_009e: ldloc.s V_4 + IL_00a0: ldc.i4.1 + IL_00a1: ldelem.ref + IL_00a2: ldtoken [mscorlib]System.String + IL_00a7: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) + IL_00ac: call bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type, + class [mscorlib]System.Type) + IL_00b1: ldstr "S must be string" + IL_00b6: call void Test::Assert(bool, + string) + IL_00bb: nop + IL_00bc: ret + } // end of method Program::Positive + + .method public hidebysig static int32 Main() cil managed + { + .entrypoint + // Code size 23 (0x17) + .maxstack 1 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: call void Program::Negative() + IL_0006: nop + IL_0007: call void Program::Positive() + IL_000c: nop + IL_000d: call int32 Test::Ret() + IL_0012: stloc.0 + IL_0013: br.s IL_0015 + + IL_0015: ldloc.0 + IL_0016: ret } // end of method Program::Main .method public hidebysig specialname rtspecialname diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.cs b/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.cs index 8f4b5d1..0d4c119 100755 --- a/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.cs +++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.cs @@ -2,58 +2,291 @@ using System; interface IFoo { - int Foo(int a); + int Foo1(int a); // { return a + 1 }; + int Foo2(int a); // { return a + 2 }; + int Foo3(int a); + int Foo4(int a); + int Foo5(int a); + int Foo6(int a); + int Foo7(int a); + int Foo8(int a); + int Foo9(int a); } -interface IBar +interface IBar : IFoo { - int Bar(int b); + // @OVERRIDE + // IFoo.Foo1/2/3/4/5 + + int Bar1(int b); // { return a + 11; } + int Bar2(int b); // { return a + 22; } + int Bar3(int b); // { return a + 33; } + int Bar4(int b); + int Bar5(int b); + int Bar6(int b); + int Bar7(int b); + int Bar8(int b); + int Bar9(int b); } -interface IFooBar : IFoo, IBar +interface IBlah : IBar { - int Foo(int a); + // @OVERRIDE IFoo.Foo6/7/8/9 + // @OVERRIDE IBar.Bar6/7/8/9 + int Blah1(int c); + int Blah2(int c); + int Blah3(int c); } -class Temp : IFoo +class IBarImpl : IBar { - int IFoo.Foo(int a) + // @REMOVE all implementation + int IFoo.Foo1(int a) { - Console.WriteLine("At IFooBar::IFoo.Foo explicit methodimpl"); + Console.WriteLine("At IIFoo.Foo1"); + return a + 10; + } + + int IFoo.Foo2(int a) + { + Console.WriteLine("At IIFoo.Foo1"); + return a + 20; + } + int IFoo.Foo3(int a) + { + Console.WriteLine("At IIFoo.Foo1"); return a + 30; } + int IFoo.Foo4(int a) + { + Console.WriteLine("At IIFoo.Foo1"); + return a + 40; + } + int IFoo.Foo5(int a) + { + Console.WriteLine("At IIFoo.Foo1"); + return a + 50; + } + int IFoo.Foo6(int a) + { + Console.WriteLine("At IIFoo.Foo1"); + return a + 60; + } + int IFoo.Foo7(int a) + { + Console.WriteLine("At IIFoo.Foo1"); + return a + 70; + } + int IFoo.Foo8(int a) + { + Console.WriteLine("At IIFoo.Foo1"); + return a + 80; + } + int IFoo.Foo9(int a) + { + Console.WriteLine("At IIFoo.Foo1"); + return a + 19; + } + + int IBar.Bar1(int a) + { + Console.WriteLine("At IBar.Bar1"); + return a + 110; + } + + int IBar.Bar2(int a) + { + Console.WriteLine("At IBar.Bar1"); + return a + 220; + } + int IBar.Bar3(int a) + { + Console.WriteLine("At IBar.Bar1"); + return a + 330; + } + int IBar.Bar4(int a) + { + Console.WriteLine("At IBar.Bar1"); + return a + 440; + } + int IBar.Bar5(int a) + { + Console.WriteLine("At IBar.Bar1"); + return a + 550; + } + int IBar.Bar6(int a) + { + Console.WriteLine("At IBar.Bar1"); + return a + 660; + } + int IBar.Bar7(int a) + { + Console.WriteLine("At IBar.Bar1"); + return a + 770; + } + int IBar.Bar8(int a) + { + Console.WriteLine("At IBar.Bar1"); + return a + 880; + } + int IBar.Bar9(int a) + { + Console.WriteLine("At IBar.Bar1"); + return a + 990; + } } -class FooBar : IFooBar +class IBlahImpl : IBarImpl, IBlah { - public int Foo(int a) + // @REMOVE all implementation + // @OVERRIDE IBlah2/3 with + 2220/3330 + int IBlah.Blah1(int c) + { + Console.WriteLine("At IBlah.Blah1"); + return c+111; + } + + int IBlah.Blah2(int c) { - Console.WriteLine("At IFoo::Foo"); - return a+10; + Console.WriteLine("At IBlah.Blah2"); + return c+222; } - public int Bar(int b) + int IBlah.Blah3(int c) { - Console.WriteLine("At IBar::Bar"); - return b+20; + Console.WriteLine("At IBlah.Blah3"); + return c+333; } } +interface IFooBarBlah : IFoo, IBar, IBlah +{ + // FooBarBlah1 .override IFoo.Foo1/IBar.Bar1/IBlah.Blah1 return 1+11111 + // FooBarBlah2 .override IFoo.Foo2/IBar.Bar2/IBlah.Blah2 return i+22222 + // FooBarBLah345 .override IFoo.Foo345/IBar.Bar345/IBlah.Blah3 return i+33333 +} + +class FooBarBlahImpl : + IBlahImpl, // @REMOVE + IFooBarBlah +{ + +} + class Program { public static int Main() { - FooBar fooBar = new FooBar(); - IFoo foo = (IFoo) fooBar; - IBar bar = (IBar) fooBar; + SingleOverride(); + MultiOverride(); + + return Test.Ret(); + } - Console.WriteLine("Calling IFoo.Foo on FooBar - expecting IFooBar::IFoo.Bar"); - Test.Assert(foo.Foo(10) == 40, "Calling IFoo.Foo on FooBar"); + private static void SingleOverride() + { + IBarImpl barImpl = new IBarImpl(); + IFoo foo = (IFoo) barImpl; - Console.WriteLine("Calling IBar.Bar on FooBar - expecting IBar::Bar"); - Test.Assert(bar.Bar(10) == 30, "Calling IBar.Bar on FooBar"); + Console.WriteLine("Calling IFoo.Foo methods on IBarImpl..."); - return Test.Ret(); + Test.Assert(foo.Foo1(1) == 11, "Calling IFoo.Foo1 on IBarImpl"); + Test.Assert(foo.Foo2(2) == 22, "Calling IFoo.Foo2 on IBarImpl"); + Test.Assert(foo.Foo3(3) == 33, "Calling IFoo.Foo3 on IBarImpl"); + Test.Assert(foo.Foo4(4) == 44, "Calling IFoo.Foo4 on IBarImpl"); + Test.Assert(foo.Foo5(5) == 55, "Calling IFoo.Foo5 on IBarImpl"); + Test.Assert(foo.Foo6(0) == 6, "Calling IFoo.Foo6 on IBarImpl"); + Test.Assert(foo.Foo7(0) == 7, "Calling IFoo.Foo7 on IBarImpl"); + Test.Assert(foo.Foo8(0) == 8, "Calling IFoo.Foo8 on IBarImpl"); + Test.Assert(foo.Foo9(0) == 9, "Calling IFoo.Foo9 on IBarImpl"); + + IBar bar = (IBar) barImpl; + + Console.WriteLine("Calling IBar.Bar methods on IBarImpl..."); + + Test.Assert(bar.Bar1(0) == 11, "Calling IBar.Bar1 on IBarImpl"); + Test.Assert(bar.Bar2(0) == 22, "Calling IBar.Bar2 on IBarImpl"); + Test.Assert(bar.Bar3(0) == 33, "Calling IBar.Bar3 on IBarImpl"); + Test.Assert(bar.Bar4(0) == 44, "Calling IBar.Bar4 on IBarImpl"); + Test.Assert(bar.Bar5(0) == 55, "Calling IBar.Bar5 on IBarImpl"); + Test.Assert(bar.Bar6(0) == 66, "Calling IBar.Bar6 on IBarImpl"); + Test.Assert(bar.Bar7(0) == 77, "Calling IBar.Bar7 on IBarImpl"); + Test.Assert(bar.Bar8(0) == 88, "Calling IBar.Bar8 on IBarImpl"); + Test.Assert(bar.Bar9(0) == 99, "Calling IBar.Bar9 on IBarImpl"); + + IBlahImpl blahImpl = new IBlahImpl(); + foo = (IFoo) blahImpl; + + Test.Assert(foo.Foo1(1) == 11, "Calling IFoo.Foo1 on IBlahImpl"); + Test.Assert(foo.Foo2(2) == 22, "Calling IFoo.Foo2 on IBlahImpl"); + Test.Assert(foo.Foo3(3) == 33, "Calling IFoo.Foo3 on IBlahImpl"); + Test.Assert(foo.Foo4(4) == 44, "Calling IFoo.Foo4 on IBlahImpl"); + Test.Assert(foo.Foo5(5) == 55, "Calling IFoo.Foo5 on IBlahImpl"); + Test.Assert(foo.Foo6(6) == 66, "Calling IFoo.Foo6 on IBlahImpl"); + Test.Assert(foo.Foo7(7) == 77, "Calling IFoo.Foo7 on IBlahImpl"); + Test.Assert(foo.Foo8(8) == 88, "Calling IFoo.Foo8 on IBlahImpl"); + Test.Assert(foo.Foo9(9) == 99, "Calling IFoo.Foo9 on IBlahImpl"); + + bar = (IBar) blahImpl; + + Console.WriteLine("Calling IBar.Bar methods on IBlahImpl..."); + + Test.Assert(bar.Bar1(1) == 111, "Calling IBar.Bar1 on IBlahImpl"); + Test.Assert(bar.Bar2(2) == 222, "Calling IBar.Bar2 on IBlahImpl"); + Test.Assert(bar.Bar3(3) == 333, "Calling IBar.Bar3 on IBlahImpl"); + Test.Assert(bar.Bar4(4) == 444, "Calling IBar.Bar4 on IBlahImpl"); + Test.Assert(bar.Bar5(5) == 555, "Calling IBar.Bar5 on IBlahImpl"); + Test.Assert(bar.Bar6(0) == 66, "Calling IBar.Bar6 on IBlahImpl"); + Test.Assert(bar.Bar7(0) == 77, "Calling IBar.Bar7 on IBlahImpl"); + Test.Assert(bar.Bar8(0) == 88, "Calling IBar.Bar8 on IBlahImpl"); + Test.Assert(bar.Bar9(0) == 99, "Calling IBar.Bar9 on IBlahImpl"); + + IBlah blah = (IBlah) blahImpl; + + Console.WriteLine("Calling IBlah.Blah methods on IBlahImpl..."); + + Test.Assert(blah.Blah1(0) == 111, "Calling IBlah.Blah1 on IBlahImpl"); + Test.Assert(blah.Blah2(2) == 2222, "Calling IBlah.Blah1 on IBlahImpl"); + Test.Assert(blah.Blah3(3) == 3333, "Calling IBlah.Blah1 on IBlahImpl"); + } + + private static void MultiOverride() + { + FooBarBlahImpl fooBarBlah = new FooBarBlahImpl(); + IFoo foo = (IFoo) fooBarBlah; + + Console.WriteLine("Calling IFoo.Foo methods on FooBarBlahImpl..."); + Test.Assert(foo.Foo1(0) == 11111, "Calling IFoo.Foo1 on FooBarBlahImpl"); + Test.Assert(foo.Foo2(0) == 22222, "Calling IFoo.Foo2 on FooBarBlahImpl"); + Test.Assert(foo.Foo3(0) == 33333, "Calling IFoo.Foo3 on FooBarBlahImpl"); + Test.Assert(foo.Foo4(0) == 33333, "Calling IFoo.Foo4 on FooBarBlahImpl"); + Test.Assert(foo.Foo5(0) == 33333, "Calling IFoo.Foo5 on FooBarBlahImpl"); + Test.Assert(foo.Foo6(6) == 66, "Calling IFoo.Foo6 on FooBarBlahImpl"); + Test.Assert(foo.Foo7(7) == 77, "Calling IFoo.Foo7 on FooBarBlahImpl"); + Test.Assert(foo.Foo8(8) == 88, "Calling IFoo.Foo8 on FooBarBlahImpl"); + Test.Assert(foo.Foo9(9) == 99, "Calling IFoo.Foo9 on FooBarBlahImpl"); + + IBar bar = (IBar) fooBarBlah; + + Console.WriteLine("Calling IBar.Bar methods on FooBarBlahImpl..."); + + Test.Assert(bar.Bar1(0) == 11111, "Calling IBar.Bar1 on FooBarBlahImpl"); + Test.Assert(bar.Bar2(0) == 22222, "Calling IBar.Bar2 on FooBarBlahImpl"); + Test.Assert(bar.Bar3(0) == 33333, "Calling IBar.Bar3 on FooBarBlahImpl"); + Test.Assert(bar.Bar4(0) == 33333, "Calling IBar.Bar4 on FooBarBlahImpl"); + Test.Assert(bar.Bar5(0) == 33333, "Calling IBar.Bar5 on FooBarBlahImpl"); + Test.Assert(bar.Bar6(0) == 66, "Calling IBar.Bar6 on FooBarBlahImpl"); + Test.Assert(bar.Bar7(0) == 77, "Calling IBar.Bar7 on FooBarBlahImpl"); + Test.Assert(bar.Bar8(0) == 88, "Calling IBar.Bar8 on FooBarBlahImpl"); + Test.Assert(bar.Bar9(0) == 99, "Calling IBar.Bar9 on FooBarBlahImpl"); + + IBlah blah = (IBlah) fooBarBlah; + + Console.WriteLine("Calling IBlah.Blah methods on FooBarBlahImpl..."); + + Test.Assert(blah.Blah1(0) == 11111, "Calling IBlah.Blah1 on FooBarBlahImpl"); + Test.Assert(blah.Blah2(0) == 22222, "Calling IBlah.Blah1 on FooBarBlahImpl"); + Test.Assert(blah.Blah3(0) == 33333, "Calling IBlah.Blah1 on FooBarBlahImpl"); } } diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.il index 6ab45f0..7f94442 100644 --- a/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.il +++ b/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.il @@ -37,13 +37,382 @@ .class interface private abstract auto ansi IFoo { .method public hidebysig newslot virtual - instance int32 Foo(int32 a) cil managed + instance int32 Foo1(int32 a) cil managed { // Code size 21 (0x15) .maxstack 2 .locals init (int32 V_0) IL_0000: nop - IL_0001: ldstr "At IFoo::Foo" + IL_0001: ldstr "At IIFoo.Foo1" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 1 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IFoo::Foo1 + + .method public hidebysig newslot virtual + instance int32 Foo2(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IFoo.Foo2" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 2 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IFoo::Foo2 + + .method public hidebysig newslot virtual + instance int32 Foo3(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IFoo.Foo3" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 3 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IFoo::Foo3 + + .method public hidebysig newslot virtual + instance int32 Foo4(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IFoo.Foo4" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 4 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IFoo::Foo4 + + .method public hidebysig newslot virtual + instance int32 Foo5(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IFoo.Foo5" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 5 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IFoo::Foo5 + + .method public hidebysig newslot virtual + instance int32 Foo6(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IFoo.Foo6" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 6 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IFoo::Foo6 + + .method public hidebysig newslot virtual + instance int32 Foo7(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IFoo.Foo7" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 7 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IFoo::Foo7 + + .method public hidebysig newslot virtual + instance int32 Foo8(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IFoo.Foo8" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 8 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IFoo::Foo8 + + .method public hidebysig newslot virtual + instance int32 Foo9(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IFoo.Foo9" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 9 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IFoo::Foo9 +} // end of class IFoo + +.class interface private abstract auto ansi IBar + implements IFoo +{ + .method public hidebysig newslot virtual + instance int32 Bar1(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IIBar.Bar1" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 11 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::Bar1 + + .method public hidebysig newslot virtual + instance int32 Bar2(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar.Bar2" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 22 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::Bar2 + + .method public hidebysig newslot virtual + instance int32 Bar3(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar.Bar3" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 33 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::Bar3 + + .method public hidebysig newslot virtual + instance int32 Bar4(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar.Bar4" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 44 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::Bar4 + + .method public hidebysig newslot virtual + instance int32 Bar5(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar.Bar5" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 55 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::Bar5 + + .method public hidebysig newslot virtual + instance int32 Bar6(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar.Bar6" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 66 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::Bar6 + + .method public hidebysig newslot virtual + instance int32 Bar7(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar.Bar7" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 77 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::Bar7 + + .method public hidebysig newslot virtual + instance int32 Bar8(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar.Bar8" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 88 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::Bar8 + + .method public hidebysig newslot virtual + instance int32 Bar9(int32 a) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar.Bar9" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 99 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::Bar9 + + ////////////////////////////////////////////////////////////////////////////// + // Overriding IFoo + ////////////////////////////////////////////////////////////////////////////// + + .method private hidebysig newslot virtual final + instance int32 IFoo.Foo1(int32 a) cil managed + { + .override IFoo::Foo1 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar::IFoo.Foo1" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: ldarg.1 @@ -54,66 +423,517 @@ IL_0013: ldloc.0 IL_0014: ret - } // end of method IFoo::Foo + } // end of method IBar::IFoo.Foo1 + + .method private hidebysig newslot virtual final + instance int32 IFoo.Foo2(int32 a) cil managed + { + .override IFoo::Foo2 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar::IFoo.Foo2" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 20 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::IFoo.Foo2 + + .method private hidebysig newslot virtual final + instance int32 IFoo.Foo3(int32 a) cil managed + { + .override IFoo::Foo3 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar::IFoo.Foo3" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 30 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::IFoo.Foo3 + + .method private hidebysig newslot virtual final + instance int32 IFoo.Foo4(int32 a) cil managed + { + .override IFoo::Foo4 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar::IFoo.Foo4" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 40 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::IFoo.Foo4 + + .method private hidebysig newslot virtual final + instance int32 IFoo.Foo5(int32 a) cil managed + { + .override IFoo::Foo5 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBar::IFoo.Foo5" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 50 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBar::IFoo.Foo5 +} // end of class IBar + +.class interface private abstract auto ansi IBlah + implements IBar, + IFoo +{ + .method public hidebysig newslot virtual + instance int32 Blah1(int32 c) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlah.Blah1" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4 111 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlah::Blah1 + + .method public hidebysig newslot virtual + instance int32 Blah2(int32 c) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlah.Blah2" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4 222 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlah::Blah2 + + .method public hidebysig newslot virtual + instance int32 Blah3(int32 c) cil managed + { + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlah.Blah3" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4 333 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlah::Blah3 + + ////////////////////////////////////////////////////////////////////////////// + // Overriding IFoo + ////////////////////////////////////////////////////////////////////////////// + + .method private hidebysig newslot virtual final + instance int32 IFoo.Foo6(int32 a) cil managed + { + .override IFoo::Foo6 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlah::IFoo.Foo6" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 60 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlah::IFoo.Foo6 + + .method private hidebysig newslot virtual final + instance int32 IFoo.Foo7(int32 a) cil managed + { + .override IFoo::Foo7 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlah::IFoo.Foo7" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 70 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlah::IFoo.Foo6 + + .method private hidebysig newslot virtual final + instance int32 IFoo.Foo8(int32 a) cil managed + { + .override IFoo::Foo8 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlah::IFoo.Foo8" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 80 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlah::IFoo.Foo8 -} // end of class IFoo + .method private hidebysig newslot virtual final + instance int32 IFoo.Foo9(int32 a) cil managed + { + .override IFoo::Foo9 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlah::IFoo.Foo9" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 90 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 -.class interface private abstract auto ansi IBar + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlah::IFoo.Foo9 + + ////////////////////////////////////////////////////////////////////////////// + // Overriding IBar + ////////////////////////////////////////////////////////////////////////////// + + .method private hidebysig newslot virtual final + instance int32 IBar.Bar1(int32 a) cil managed + { + .override IBar::Bar1 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlah::IBar.Bar1" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4.s 110 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlah::IBar.Bar1 + + .method private hidebysig newslot virtual final + instance int32 IBar.Bar2(int32 a) cil managed + { + .override IBar::Bar2 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlah::IBar.Bar2" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4 220 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlah::IBar.Bar2 + + .method private hidebysig newslot virtual final + instance int32 IBar.Bar3(int32 a) cil managed + { + .override IBar::Bar3 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlah::IBar.Bar3" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4 330 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlah::IBar.Bar3 + + .method private hidebysig newslot virtual final + instance int32 IBar.Bar4(int32 a) cil managed + { + .override IBar::Bar4 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlah::IBar.Bar4" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4 440 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlah::IBar.Bar4 + + .method private hidebysig newslot virtual final + instance int32 IBar.Bar5(int32 a) cil managed + { + .override IBar::Bar5 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlah::IBar.Bar5" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4 550 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlah::IBar.Bar5 +} // end of class IBlah + +.class private auto ansi beforefieldinit IBarImpl + extends [mscorlib]System.Object + implements IBar, + IFoo { - .method public hidebysig newslot virtual - instance int32 Bar(int32 b) cil managed + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method IBarImpl::.ctor + +} // end of class IBarImpl + +.class private auto ansi beforefieldinit IBlahImpl + extends IBarImpl + implements IBlah, + IBar, + IFoo +{ + .method private hidebysig newslot virtual final + instance int32 IBlah.Blah2(int32 c) cil managed { + .override IBlah::Blah2 // Code size 21 (0x15) .maxstack 2 .locals init (int32 V_0) IL_0000: nop - IL_0001: ldstr "At IBar::Bar" + IL_0001: ldstr "At IBlahImpl::IBlah.Blah2" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: ldarg.1 - IL_000d: ldc.i4.s 20 + IL_000d: ldc.i4 2220 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IBlahImpl::IBlah.Blah2 + + .method private hidebysig newslot virtual final + instance int32 IBlah.Blah3(int32 c) cil managed + { + .override IBlah::Blah3 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IBlahImpl::IBlah.Blah2" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4 3330 IL_000f: add IL_0010: stloc.0 IL_0011: br.s IL_0013 IL_0013: ldloc.0 IL_0014: ret - } // end of method IBar::Bar + } // end of method IBlahImpl::IBlah.Blah3 -} // end of class IBar + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void IBarImpl::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method IBlahImpl::.ctor -.class interface private abstract auto ansi IFooBar +} // end of class IBlahImpl + +.class interface private abstract auto ansi IFooBarBlah implements IFoo, - IBar + IBar, + IBlah { .method private hidebysig newslot virtual final - instance int32 IFoo.Foo(int32 a) cil managed + instance int32 IFooBarBlah.FooBarBlah1(int32 c) cil managed { - .override IFoo::Foo + .override IFoo::Foo1 + .override IBar::Bar1 + .override IBlah::Blah1 // Code size 21 (0x15) .maxstack 2 .locals init (int32 V_0) IL_0000: nop - IL_0001: ldstr "At IFooBar::IFoo.Foo explicit methodimpl" + IL_0001: ldstr "At IFooBarBlah.FooBarBlah1" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: ldarg.1 - IL_000d: ldc.i4.s 30 + IL_000d: ldc.i4 11111 IL_000f: add IL_0010: stloc.0 IL_0011: br.s IL_0013 IL_0013: ldloc.0 - IL_0014: ret - } // end of method Temp::IFoo.Foo + IL_0014: ret + } // end of method IFooBarBlah.FooBarBlah1 + .method private hidebysig newslot virtual final + instance int32 IFooBarBlah.FooBarBlah2(int32 c) cil managed + { + .override IFoo::Foo2 + .override IBar::Bar2 + .override IBlah::Blah2 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IFooBarBlah.FooBarBlah2" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4 22222 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 -} // end of class IFooBar + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IFooBarBlah.FooBarBlah1 -.class private auto ansi beforefieldinit FooBar - extends [mscorlib]System.Object - implements IFooBar, + .method private hidebysig newslot virtual final + instance int32 IFooBarBlah.FooBarBlah3(int32 c) cil managed + { + .override IFoo::Foo3 + .override IFoo::Foo4 + .override IFoo::Foo5 + .override IBar::Bar3 + .override IBar::Bar4 + .override IBar::Bar5 + .override IBlah::Blah3 + // Code size 21 (0x15) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldstr "At IFooBarBlah.FooBarBlah3" + IL_0006: call void [mscorlib]System.Console::WriteLine(string) + IL_000b: nop + IL_000c: ldarg.1 + IL_000d: ldc.i4 33333 + IL_000f: add + IL_0010: stloc.0 + IL_0011: br.s IL_0013 + + IL_0013: ldloc.0 + IL_0014: ret + } // end of method IFooBarBlah.FooBarBlah3 +} // end of class IFooBarBlah + +.class private auto ansi beforefieldinit FooBarBlahImpl + implements IFooBarBlah, IFoo, - IBar + IBar, + IBlah { .method public hidebysig specialname rtspecialname instance void .ctor() cil managed @@ -121,12 +941,12 @@ // Code size 8 (0x8) .maxstack 8 IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0001: call instance void IBlahImpl::.ctor() IL_0006: nop IL_0007: ret - } // end of method FooBar::.ctor + } // end of method FooBarBlahImpl::.ctor -} // end of class FooBar +} // end of class FooBarBlahImpl .class private auto ansi beforefieldinit Program extends [mscorlib]System.Object @@ -134,51 +954,629 @@ .method public hidebysig static int32 Main() cil managed { .entrypoint - // Code size 89 (0x59) + // Code size 23 (0x17) + .maxstack 1 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: call void Program::SingleOverride() + IL_0006: nop + IL_0007: call void Program::MultiOverride() + IL_000c: nop + IL_000d: call int32 Test::Ret() + IL_0012: stloc.0 + IL_0013: br.s IL_0015 + + IL_0015: ldloc.0 + IL_0016: ret + } // end of method Program::Main + + .method private hidebysig static void SingleOverride() cil managed + { + // Code size 946 (0x3b2) .maxstack 2 - .locals init (class FooBar V_0, + .locals init (class IBarImpl V_0, class IFoo V_1, class IBar V_2, - int32 V_3) + class IBlahImpl V_3, + class IBlah V_4) IL_0000: nop - IL_0001: newobj instance void FooBar::.ctor() + IL_0001: newobj instance void IBarImpl::.ctor() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: stloc.1 - IL_0009: ldloc.0 - IL_000a: stloc.2 - IL_000b: ldstr "Calling IFoo.Foo on FooBar - expecting IFooBar::IF" - + "oo.Bar" - IL_0010: call void [mscorlib]System.Console::WriteLine(string) - IL_0015: nop - IL_0016: ldloc.1 - IL_0017: ldc.i4.s 10 - IL_0019: callvirt instance int32 IFoo::Foo(int32) - IL_001e: ldc.i4.s 40 + IL_0009: ldstr "Calling IFoo.Foo methods on IBarImpl..." + IL_000e: call void [mscorlib]System.Console::WriteLine(string) + IL_0013: nop + IL_0014: ldloc.1 + IL_0015: ldc.i4.1 + IL_0016: callvirt instance int32 IFoo::Foo1(int32) + IL_001b: ldc.i4.s 11 + IL_001d: ceq + IL_001f: ldstr "Calling IFoo.Foo1 on IBarImpl" + IL_0024: call void Test::Assert(bool, + string) + IL_0029: nop + IL_002a: ldloc.1 + IL_002b: ldc.i4.2 + IL_002c: callvirt instance int32 IFoo::Foo2(int32) + IL_0031: ldc.i4.s 22 + IL_0033: ceq + IL_0035: ldstr "Calling IFoo.Foo2 on IBarImpl" + IL_003a: call void Test::Assert(bool, + string) + IL_003f: nop + IL_0040: ldloc.1 + IL_0041: ldc.i4.3 + IL_0042: callvirt instance int32 IFoo::Foo3(int32) + IL_0047: ldc.i4.s 33 + IL_0049: ceq + IL_004b: ldstr "Calling IFoo.Foo3 on IBarImpl" + IL_0050: call void Test::Assert(bool, + string) + IL_0055: nop + IL_0056: ldloc.1 + IL_0057: ldc.i4.4 + IL_0058: callvirt instance int32 IFoo::Foo4(int32) + IL_005d: ldc.i4.s 44 + IL_005f: ceq + IL_0061: ldstr "Calling IFoo.Foo4 on IBarImpl" + IL_0066: call void Test::Assert(bool, + string) + IL_006b: nop + IL_006c: ldloc.1 + IL_006d: ldc.i4.5 + IL_006e: callvirt instance int32 IFoo::Foo5(int32) + IL_0073: ldc.i4.s 55 + IL_0075: ceq + IL_0077: ldstr "Calling IFoo.Foo5 on IBarImpl" + IL_007c: call void Test::Assert(bool, + string) + IL_0081: nop + IL_0082: ldloc.1 + IL_0083: ldc.i4.0 + IL_0084: callvirt instance int32 IFoo::Foo6(int32) + IL_0089: ldc.i4.6 + IL_008a: ceq + IL_008c: ldstr "Calling IFoo.Foo6 on IBarImpl" + IL_0091: call void Test::Assert(bool, + string) + IL_0096: nop + IL_0097: ldloc.1 + IL_0098: ldc.i4.0 + IL_0099: callvirt instance int32 IFoo::Foo7(int32) + IL_009e: ldc.i4.7 + IL_009f: ceq + IL_00a1: ldstr "Calling IFoo.Foo7 on IBarImpl" + IL_00a6: call void Test::Assert(bool, + string) + IL_00ab: nop + IL_00ac: ldloc.1 + IL_00ad: ldc.i4.0 + IL_00ae: callvirt instance int32 IFoo::Foo8(int32) + IL_00b3: ldc.i4.8 + IL_00b4: ceq + IL_00b6: ldstr "Calling IFoo.Foo8 on IBarImpl" + IL_00bb: call void Test::Assert(bool, + string) + IL_00c0: nop + IL_00c1: ldloc.1 + IL_00c2: ldc.i4.0 + IL_00c3: callvirt instance int32 IFoo::Foo9(int32) + IL_00c8: ldc.i4.s 9 + IL_00ca: ceq + IL_00cc: ldstr "Calling IFoo.Foo9 on IBarImpl" + IL_00d1: call void Test::Assert(bool, + string) + IL_00d6: nop + IL_00d7: ldloc.0 + IL_00d8: stloc.2 + IL_00d9: ldstr "Calling IBar.Bar methods on IBarImpl..." + IL_00de: call void [mscorlib]System.Console::WriteLine(string) + IL_00e3: nop + IL_00e4: ldloc.2 + IL_00e5: ldc.i4.0 + IL_00e6: callvirt instance int32 IBar::Bar1(int32) + IL_00eb: ldc.i4.s 11 + IL_00ed: ceq + IL_00ef: ldstr "Calling IBar.Bar1 on IBarImpl" + IL_00f4: call void Test::Assert(bool, + string) + IL_00f9: nop + IL_00fa: ldloc.2 + IL_00fb: ldc.i4.0 + IL_00fc: callvirt instance int32 IBar::Bar2(int32) + IL_0101: ldc.i4.s 22 + IL_0103: ceq + IL_0105: ldstr "Calling IBar.Bar2 on IBarImpl" + IL_010a: call void Test::Assert(bool, + string) + IL_010f: nop + IL_0110: ldloc.2 + IL_0111: ldc.i4.0 + IL_0112: callvirt instance int32 IBar::Bar3(int32) + IL_0117: ldc.i4.s 33 + IL_0119: ceq + IL_011b: ldstr "Calling IBar.Bar3 on IBarImpl" + IL_0120: call void Test::Assert(bool, + string) + IL_0125: nop + IL_0126: ldloc.2 + IL_0127: ldc.i4.0 + IL_0128: callvirt instance int32 IBar::Bar4(int32) + IL_012d: ldc.i4.s 44 + IL_012f: ceq + IL_0131: ldstr "Calling IBar.Bar4 on IBarImpl" + IL_0136: call void Test::Assert(bool, + string) + IL_013b: nop + IL_013c: ldloc.2 + IL_013d: ldc.i4.0 + IL_013e: callvirt instance int32 IBar::Bar5(int32) + IL_0143: ldc.i4.s 55 + IL_0145: ceq + IL_0147: ldstr "Calling IBar.Bar5 on IBarImpl" + IL_014c: call void Test::Assert(bool, + string) + IL_0151: nop + IL_0152: ldloc.2 + IL_0153: ldc.i4.0 + IL_0154: callvirt instance int32 IBar::Bar6(int32) + IL_0159: ldc.i4.s 66 + IL_015b: ceq + IL_015d: ldstr "Calling IBar.Bar6 on IBarImpl" + IL_0162: call void Test::Assert(bool, + string) + IL_0167: nop + IL_0168: ldloc.2 + IL_0169: ldc.i4.0 + IL_016a: callvirt instance int32 IBar::Bar7(int32) + IL_016f: ldc.i4.s 77 + IL_0171: ceq + IL_0173: ldstr "Calling IBar.Bar7 on IBarImpl" + IL_0178: call void Test::Assert(bool, + string) + IL_017d: nop + IL_017e: ldloc.2 + IL_017f: ldc.i4.0 + IL_0180: callvirt instance int32 IBar::Bar8(int32) + IL_0185: ldc.i4.s 88 + IL_0187: ceq + IL_0189: ldstr "Calling IBar.Bar8 on IBarImpl" + IL_018e: call void Test::Assert(bool, + string) + IL_0193: nop + IL_0194: ldloc.2 + IL_0195: ldc.i4.0 + IL_0196: callvirt instance int32 IBar::Bar9(int32) + IL_019b: ldc.i4.s 99 + IL_019d: ceq + IL_019f: ldstr "Calling IBar.Bar9 on IBarImpl" + IL_01a4: call void Test::Assert(bool, + string) + IL_01a9: nop + IL_01aa: newobj instance void IBlahImpl::.ctor() + IL_01af: stloc.3 + IL_01b0: ldloc.3 + IL_01b1: stloc.1 + IL_01b2: ldloc.1 + IL_01b3: ldc.i4.1 + IL_01b4: callvirt instance int32 IFoo::Foo1(int32) + IL_01b9: ldc.i4.s 11 + IL_01bb: ceq + IL_01bd: ldstr "Calling IFoo.Foo1 on IBlahImpl" + IL_01c2: call void Test::Assert(bool, + string) + IL_01c7: nop + IL_01c8: ldloc.1 + IL_01c9: ldc.i4.2 + IL_01ca: callvirt instance int32 IFoo::Foo2(int32) + IL_01cf: ldc.i4.s 22 + IL_01d1: ceq + IL_01d3: ldstr "Calling IFoo.Foo2 on IBlahImpl" + IL_01d8: call void Test::Assert(bool, + string) + IL_01dd: nop + IL_01de: ldloc.1 + IL_01df: ldc.i4.3 + IL_01e0: callvirt instance int32 IFoo::Foo3(int32) + IL_01e5: ldc.i4.s 33 + IL_01e7: ceq + IL_01e9: ldstr "Calling IFoo.Foo3 on IBlahImpl" + IL_01ee: call void Test::Assert(bool, + string) + IL_01f3: nop + IL_01f4: ldloc.1 + IL_01f5: ldc.i4.4 + IL_01f6: callvirt instance int32 IFoo::Foo4(int32) + IL_01fb: ldc.i4.s 44 + IL_01fd: ceq + IL_01ff: ldstr "Calling IFoo.Foo4 on IBlahImpl" + IL_0204: call void Test::Assert(bool, + string) + IL_0209: nop + IL_020a: ldloc.1 + IL_020b: ldc.i4.5 + IL_020c: callvirt instance int32 IFoo::Foo5(int32) + IL_0211: ldc.i4.s 55 + IL_0213: ceq + IL_0215: ldstr "Calling IFoo.Foo5 on IBlahImpl" + IL_021a: call void Test::Assert(bool, + string) + IL_021f: nop + IL_0220: ldloc.1 + IL_0221: ldc.i4.6 + IL_0222: callvirt instance int32 IFoo::Foo6(int32) + IL_0227: ldc.i4.s 66 + IL_0229: ceq + IL_022b: ldstr "Calling IFoo.Foo6 on IBlahImpl" + IL_0230: call void Test::Assert(bool, + string) + IL_0235: nop + IL_0236: ldloc.1 + IL_0237: ldc.i4.7 + IL_0238: callvirt instance int32 IFoo::Foo7(int32) + IL_023d: ldc.i4.s 77 + IL_023f: ceq + IL_0241: ldstr "Calling IFoo.Foo7 on IBlahImpl" + IL_0246: call void Test::Assert(bool, + string) + IL_024b: nop + IL_024c: ldloc.1 + IL_024d: ldc.i4.8 + IL_024e: callvirt instance int32 IFoo::Foo8(int32) + IL_0253: ldc.i4.s 88 + IL_0255: ceq + IL_0257: ldstr "Calling IFoo.Foo8 on IBlahImpl" + IL_025c: call void Test::Assert(bool, + string) + IL_0261: nop + IL_0262: ldloc.1 + IL_0263: ldc.i4.s 9 + IL_0265: callvirt instance int32 IFoo::Foo9(int32) + IL_026a: ldc.i4.s 99 + IL_026c: ceq + IL_026e: ldstr "Calling IFoo.Foo9 on IBlahImpl" + IL_0273: call void Test::Assert(bool, + string) + IL_0278: nop + IL_0279: ldloc.3 + IL_027a: stloc.2 + IL_027b: ldstr "Calling IBar.Bar methods on IBlahImpl..." + IL_0280: call void [mscorlib]System.Console::WriteLine(string) + IL_0285: nop + IL_0286: ldloc.2 + IL_0287: ldc.i4.1 + IL_0288: callvirt instance int32 IBar::Bar1(int32) + IL_028d: ldc.i4.s 111 + IL_028f: ceq + IL_0291: ldstr "Calling IBar.Bar1 on IBlahImpl" + IL_0296: call void Test::Assert(bool, + string) + IL_029b: nop + IL_029c: ldloc.2 + IL_029d: ldc.i4.2 + IL_029e: callvirt instance int32 IBar::Bar2(int32) + IL_02a3: ldc.i4 0xde + IL_02a8: ceq + IL_02aa: ldstr "Calling IBar.Bar2 on IBlahImpl" + IL_02af: call void Test::Assert(bool, + string) + IL_02b4: nop + IL_02b5: ldloc.2 + IL_02b6: ldc.i4.3 + IL_02b7: callvirt instance int32 IBar::Bar3(int32) + IL_02bc: ldc.i4 0x14d + IL_02c1: ceq + IL_02c3: ldstr "Calling IBar.Bar3 on IBlahImpl" + IL_02c8: call void Test::Assert(bool, + string) + IL_02cd: nop + IL_02ce: ldloc.2 + IL_02cf: ldc.i4.4 + IL_02d0: callvirt instance int32 IBar::Bar4(int32) + IL_02d5: ldc.i4 0x1bc + IL_02da: ceq + IL_02dc: ldstr "Calling IBar.Bar4 on IBlahImpl" + IL_02e1: call void Test::Assert(bool, + string) + IL_02e6: nop + IL_02e7: ldloc.2 + IL_02e8: ldc.i4.5 + IL_02e9: callvirt instance int32 IBar::Bar5(int32) + IL_02ee: ldc.i4 0x22b + IL_02f3: ceq + IL_02f5: ldstr "Calling IBar.Bar5 on IBlahImpl" + IL_02fa: call void Test::Assert(bool, + string) + IL_02ff: nop + IL_0300: ldloc.2 + IL_0301: ldc.i4.0 + IL_0302: callvirt instance int32 IBar::Bar6(int32) + IL_0307: ldc.i4.s 66 + IL_0309: ceq + IL_030b: ldstr "Calling IBar.Bar6 on IBlahImpl" + IL_0310: call void Test::Assert(bool, + string) + IL_0315: nop + IL_0316: ldloc.2 + IL_0317: ldc.i4.0 + IL_0318: callvirt instance int32 IBar::Bar7(int32) + IL_031d: ldc.i4.s 77 + IL_031f: ceq + IL_0321: ldstr "Calling IBar.Bar7 on IBlahImpl" + IL_0326: call void Test::Assert(bool, + string) + IL_032b: nop + IL_032c: ldloc.2 + IL_032d: ldc.i4.0 + IL_032e: callvirt instance int32 IBar::Bar8(int32) + IL_0333: ldc.i4.s 88 + IL_0335: ceq + IL_0337: ldstr "Calling IBar.Bar8 on IBlahImpl" + IL_033c: call void Test::Assert(bool, + string) + IL_0341: nop + IL_0342: ldloc.2 + IL_0343: ldc.i4.0 + IL_0344: callvirt instance int32 IBar::Bar9(int32) + IL_0349: ldc.i4.s 99 + IL_034b: ceq + IL_034d: ldstr "Calling IBar.Bar9 on IBlahImpl" + IL_0352: call void Test::Assert(bool, + string) + IL_0357: nop + IL_0358: ldloc.3 + IL_0359: stloc.s V_4 + IL_035b: ldstr "Calling IBlah.Blah methods on IBlahImpl..." + IL_0360: call void [mscorlib]System.Console::WriteLine(string) + IL_0365: nop + IL_0366: ldloc.s V_4 + IL_0368: ldc.i4.0 + IL_0369: callvirt instance int32 IBlah::Blah1(int32) + IL_036e: ldc.i4.s 111 + IL_0370: ceq + IL_0372: ldstr "Calling IBlah.Blah1 on IBlahImpl" + IL_0377: call void Test::Assert(bool, + string) + IL_037c: nop + IL_037d: ldloc.s V_4 + IL_037f: ldc.i4.2 + IL_0380: callvirt instance int32 IBlah::Blah2(int32) + IL_0385: ldc.i4 0x8ae + IL_038a: ceq + IL_038c: ldstr "Calling IBlah.Blah1 on IBlahImpl" + IL_0391: call void Test::Assert(bool, + string) + IL_0396: nop + IL_0397: ldloc.s V_4 + IL_0399: ldc.i4.3 + IL_039a: callvirt instance int32 IBlah::Blah3(int32) + IL_039f: ldc.i4 0xd05 + IL_03a4: ceq + IL_03a6: ldstr "Calling IBlah.Blah1 on IBlahImpl" + IL_03ab: call void Test::Assert(bool, + string) + IL_03b0: nop + IL_03b1: ret + } // end of method Program::SingleOverride + + .method private hidebysig static void MultiOverride() cil managed + { + // Code size 549 (0x225) + .maxstack 2 + .locals init (class FooBarBlahImpl V_0, + class IFoo V_1, + class IBar V_2, + class IBlah V_3) + IL_0000: nop + IL_0001: newobj instance void FooBarBlahImpl::.ctor() + IL_0006: stloc.0 + IL_0007: ldloc.0 + IL_0008: stloc.1 + IL_0009: ldstr "Calling IFoo.Foo methods on FooBarBlahImpl..." + IL_000e: call void [mscorlib]System.Console::WriteLine(string) + IL_0013: nop + IL_0014: ldloc.1 + IL_0015: ldc.i4.0 + IL_0016: callvirt instance int32 IFoo::Foo1(int32) + IL_001b: ldc.i4 0x2b67 IL_0020: ceq - IL_0022: ldstr "Calling IFoo.Foo on FooBar" + IL_0022: ldstr "Calling IFoo.Foo1 on FooBarBlahImpl" IL_0027: call void Test::Assert(bool, string) IL_002c: nop - IL_002d: ldstr "Calling IBar.Bar on FooBar - expecting IBar::Bar" - IL_0032: call void [mscorlib]System.Console::WriteLine(string) - IL_0037: nop - IL_0038: ldloc.2 - IL_0039: ldc.i4.s 10 - IL_003b: callvirt instance int32 IBar::Bar(int32) - IL_0040: ldc.i4.s 30 - IL_0042: ceq - IL_0044: ldstr "Calling IBar.Bar on FooBar" - IL_0049: call void Test::Assert(bool, - string) - IL_004e: nop - IL_004f: call int32 Test::Ret() - IL_0054: stloc.3 - IL_0055: br.s IL_0057 - - IL_0057: ldloc.3 - IL_0058: ret - } // end of method Program::Main + IL_002d: ldloc.1 + IL_002e: ldc.i4.0 + IL_002f: callvirt instance int32 IFoo::Foo2(int32) + IL_0034: ldc.i4 0x56ce + IL_0039: ceq + IL_003b: ldstr "Calling IFoo.Foo2 on FooBarBlahImpl" + IL_0040: call void Test::Assert(bool, + string) + IL_0045: nop + IL_0046: ldloc.1 + IL_0047: ldc.i4.0 + IL_0048: callvirt instance int32 IFoo::Foo3(int32) + IL_004d: ldc.i4 0x8235 + IL_0052: ceq + IL_0054: ldstr "Calling IFoo.Foo3 on FooBarBlahImpl" + IL_0059: call void Test::Assert(bool, + string) + IL_005e: nop + IL_005f: ldloc.1 + IL_0060: ldc.i4.0 + IL_0061: callvirt instance int32 IFoo::Foo4(int32) + IL_0066: ldc.i4 0x8235 + IL_006b: ceq + IL_006d: ldstr "Calling IFoo.Foo4 on FooBarBlahImpl" + IL_0072: call void Test::Assert(bool, + string) + IL_0077: nop + IL_0078: ldloc.1 + IL_0079: ldc.i4.0 + IL_007a: callvirt instance int32 IFoo::Foo5(int32) + IL_007f: ldc.i4 0x8235 + IL_0084: ceq + IL_0086: ldstr "Calling IFoo.Foo5 on FooBarBlahImpl" + IL_008b: call void Test::Assert(bool, + string) + IL_0090: nop + IL_0091: ldloc.1 + IL_0092: ldc.i4.6 + IL_0093: callvirt instance int32 IFoo::Foo6(int32) + IL_0098: ldc.i4.s 66 + IL_009a: ceq + IL_009c: ldstr "Calling IFoo.Foo6 on FooBarBlahImpl" + IL_00a1: call void Test::Assert(bool, + string) + IL_00a6: nop + IL_00a7: ldloc.1 + IL_00a8: ldc.i4.7 + IL_00a9: callvirt instance int32 IFoo::Foo7(int32) + IL_00ae: ldc.i4.s 77 + IL_00b0: ceq + IL_00b2: ldstr "Calling IFoo.Foo7 on FooBarBlahImpl" + IL_00b7: call void Test::Assert(bool, + string) + IL_00bc: nop + IL_00bd: ldloc.1 + IL_00be: ldc.i4.8 + IL_00bf: callvirt instance int32 IFoo::Foo8(int32) + IL_00c4: ldc.i4.s 88 + IL_00c6: ceq + IL_00c8: ldstr "Calling IFoo.Foo8 on FooBarBlahImpl" + IL_00cd: call void Test::Assert(bool, + string) + IL_00d2: nop + IL_00d3: ldloc.1 + IL_00d4: ldc.i4.s 9 + IL_00d6: callvirt instance int32 IFoo::Foo9(int32) + IL_00db: ldc.i4.s 99 + IL_00dd: ceq + IL_00df: ldstr "Calling IFoo.Foo9 on FooBarBlahImpl" + IL_00e4: call void Test::Assert(bool, + string) + IL_00e9: nop + IL_00ea: ldloc.0 + IL_00eb: stloc.2 + IL_00ec: ldstr "Calling IBar.Bar methods on FooBarBlahImpl..." + IL_00f1: call void [mscorlib]System.Console::WriteLine(string) + IL_00f6: nop + IL_00f7: ldloc.2 + IL_00f8: ldc.i4.0 + IL_00f9: callvirt instance int32 IBar::Bar1(int32) + IL_00fe: ldc.i4 0x2b67 + IL_0103: ceq + IL_0105: ldstr "Calling IBar.Bar1 on FooBarBlahImpl" + IL_010a: call void Test::Assert(bool, + string) + IL_010f: nop + IL_0110: ldloc.2 + IL_0111: ldc.i4.0 + IL_0112: callvirt instance int32 IBar::Bar2(int32) + IL_0117: ldc.i4 0x56ce + IL_011c: ceq + IL_011e: ldstr "Calling IBar.Bar2 on FooBarBlahImpl" + IL_0123: call void Test::Assert(bool, + string) + IL_0128: nop + IL_0129: ldloc.2 + IL_012a: ldc.i4.0 + IL_012b: callvirt instance int32 IBar::Bar3(int32) + IL_0130: ldc.i4 0x8235 + IL_0135: ceq + IL_0137: ldstr "Calling IBar.Bar3 on FooBarBlahImpl" + IL_013c: call void Test::Assert(bool, + string) + IL_0141: nop + IL_0142: ldloc.2 + IL_0143: ldc.i4.0 + IL_0144: callvirt instance int32 IBar::Bar4(int32) + IL_0149: ldc.i4 0x8235 + IL_014e: ceq + IL_0150: ldstr "Calling IBar.Bar4 on FooBarBlahImpl" + IL_0155: call void Test::Assert(bool, + string) + IL_015a: nop + IL_015b: ldloc.2 + IL_015c: ldc.i4.0 + IL_015d: callvirt instance int32 IBar::Bar5(int32) + IL_0162: ldc.i4 0x8235 + IL_0167: ceq + IL_0169: ldstr "Calling IBar.Bar5 on FooBarBlahImpl" + IL_016e: call void Test::Assert(bool, + string) + IL_0173: nop + IL_0174: ldloc.2 + IL_0175: ldc.i4.0 + IL_0176: callvirt instance int32 IBar::Bar6(int32) + IL_017b: ldc.i4.s 66 + IL_017d: ceq + IL_017f: ldstr "Calling IBar.Bar6 on FooBarBlahImpl" + IL_0184: call void Test::Assert(bool, + string) + IL_0189: nop + IL_018a: ldloc.2 + IL_018b: ldc.i4.0 + IL_018c: callvirt instance int32 IBar::Bar7(int32) + IL_0191: ldc.i4.s 77 + IL_0193: ceq + IL_0195: ldstr "Calling IBar.Bar7 on FooBarBlahImpl" + IL_019a: call void Test::Assert(bool, + string) + IL_019f: nop + IL_01a0: ldloc.2 + IL_01a1: ldc.i4.0 + IL_01a2: callvirt instance int32 IBar::Bar8(int32) + IL_01a7: ldc.i4.s 88 + IL_01a9: ceq + IL_01ab: ldstr "Calling IBar.Bar8 on FooBarBlahImpl" + IL_01b0: call void Test::Assert(bool, + string) + IL_01b5: nop + IL_01b6: ldloc.2 + IL_01b7: ldc.i4.0 + IL_01b8: callvirt instance int32 IBar::Bar9(int32) + IL_01bd: ldc.i4.s 99 + IL_01bf: ceq + IL_01c1: ldstr "Calling IBar.Bar9 on FooBarBlahImpl" + IL_01c6: call void Test::Assert(bool, + string) + IL_01cb: nop + IL_01cc: ldloc.0 + IL_01cd: stloc.3 + IL_01ce: ldstr "Calling IBlah.Blah methods on FooBarBlahImpl..." + IL_01d3: call void [mscorlib]System.Console::WriteLine(string) + IL_01d8: nop + IL_01d9: ldloc.3 + IL_01da: ldc.i4.0 + IL_01db: callvirt instance int32 IBlah::Blah1(int32) + IL_01e0: ldc.i4 0x2b67 + IL_01e5: ceq + IL_01e7: ldstr "Calling IBlah.Blah1 on FooBarBlahImpl" + IL_01ec: call void Test::Assert(bool, + string) + IL_01f1: nop + IL_01f2: ldloc.3 + IL_01f3: ldc.i4.0 + IL_01f4: callvirt instance int32 IBlah::Blah2(int32) + IL_01f9: ldc.i4 0x56ce + IL_01fe: ceq + IL_0200: ldstr "Calling IBlah.Blah1 on FooBarBlahImpl" + IL_0205: call void Test::Assert(bool, + string) + IL_020a: nop + IL_020b: ldloc.3 + IL_020c: ldc.i4.0 + IL_020d: callvirt instance int32 IBlah::Blah3(int32) + IL_0212: ldc.i4 0x8235 + IL_0217: ceq + IL_0219: ldstr "Calling IBlah.Blah1 on FooBarBlahImpl" + IL_021e: call void Test::Assert(bool, + string) + IL_0223: nop + IL_0224: ret + } // end of method Program::MultiOverride .method public hidebysig specialname rtspecialname instance void .ctor() cil managed @@ -191,7 +1589,7 @@ IL_0007: ret } // end of method Program::.ctor -} // end of class Program +} // end of class Program .class private auto ansi beforefieldinit Test extends [mscorlib]System.Object -- 2.7.4