Default Interface Method Prototype (#10505)
authorYi Zhang (CLR) <yizhang82@users.noreply.github.com>
Thu, 6 Apr 2017 04:04:25 +0000 (21:04 -0700)
committerYi Zhang (CLR) <yzha@microsoft.com>
Wed, 19 Jul 2017 18:16:55 +0000 (11:16 -0700)
* allow non-zero RVA on abstract interface method in ilasm

* Revert "allow non-zero RVA on abstract interface method in ilasm"

This reverts commit eecb8024e58f14a20e5e49359f38019f5768ac41.

* add a test case and allow virtual non-abstract method in ilasm

* allow non-abstract methods in the loader

* fixup dispatch map

* support for simple default interface method scenario

* fix a bug with incorrect usage of MethodIterator skpping the first method. add a test case for overriding but it may not be what we want

* add another simple test case for base class

* allow private/internal methods in ilasm and add a explict impl test

* update reference to mscorlib in il test

* add shared generics and variance case

* allow interface dispatch to return instantiating stubs with the right PARAM_TYPE calling conv

* simple factoring and add a valuetype test case

* add a test case for generic virtual methods

* a bit more refactoring by moving the CALLCONV_PARAMTYPE logic inside getMethodSigInternal

* support explicit methodimpl and remove implicit methodimpl test case

* update test cases to give more clear output

* Fix a bug where GetMethodDescForSlot chokes on interface MethodDesc without precode. This is accdentally discovered by methodimpl test case when iterating methods on a default interface method that has already been JITted

* cleanup code after review and add a bit more comments

* update comments

* only use custom ILAsm for default interface methods tests - some tests are choking on CoreCLR ilasm for security related stuff

* address comments and allow instance methods, and add a constraint value type call test scenario

* disable the failing protected method scenario

30 files changed:
src/ilasm/assem.cpp
src/ilasm/assembler.cpp
src/vm/classcompat.cpp
src/vm/jitinterface.cpp
src/vm/jitinterface.h
src/vm/method.cpp
src/vm/method.hpp
src/vm/methodtable.cpp
src/vm/methodtable.h
src/vm/methodtable.inl
src/vm/methodtablebuilder.cpp
tests/src/IL.targets
tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.cs [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.ilproj [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/genericmethods/genericmethods.cs [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/genericmethods/genericmethods.il [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/genericmethods/genericmethods.ilproj [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.cs [new file with mode: 0755]
tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.il [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.ilproj [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/sharedgenerics/sharedgenerics.cs [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/sharedgenerics/sharedgenerics.il [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/sharedgenerics/sharedgenerics.ilproj [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/simple/simple.cs [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/simple/simple.il [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/simple/simple.ilproj [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/valuetypes/valuetypes.cs [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/valuetypes/valuetypes.il [new file with mode: 0644]
tests/src/Loader/classloader/DefaultInterfaceMethods/valuetypes/valuetypes.ilproj [new file with mode: 0644]

index 6416dfe..a3b8daf 100644 (file)
@@ -339,7 +339,6 @@ BOOL Assembler::AddMethod(Method *pMethod)
     {
         char sz[1024];
         sz[0] = 0;
-        if(fIsInterface  && (!IsMdStatic(pMethod->m_Attr))) strcat_s(sz,1024," non-static declared in interface");
         if(fIsImport) strcat_s(sz,1024," imported");
         if(IsMdAbstract(pMethod->m_Attr)) strcat_s(sz,1024," abstract");
         if(IsMdPinvokeImpl(pMethod->m_Attr)) strcat_s(sz,1024," pinvoke");
index be535ab..74190b7 100644 (file)
@@ -705,24 +705,6 @@ void Assembler::StartMethod(__in __nullterminated char* name, BinStr* sig, CorMe
             {
                 flags = (CorMethodAttr)(flags | mdSpecialName);
                 if(IsTdInterface(m_pCurClass->m_Attr)) report->error("Instance constructor in interface\n");
-
-            }
-            if(!IsMdStatic(flags))
-            {
-                if(IsTdInterface(m_pCurClass->m_Attr))
-                {
-                    if(!IsMdPublic(flags)) report->error("Non-public instance method in interface\n");
-                    if((!(IsMdVirtual(flags) && IsMdAbstract(flags))))
-                    {
-                        if(OnErrGo) report->error("Non-virtual, non-abstract instance method in interface\n");
-                        else
-                        {
-                            report->warn("Non-virtual, non-abstract instance method in interface, set to such\n");
-                            flags = (CorMethodAttr)(flags |mdVirtual | mdAbstract);
-                        }
-                    }
-    
-                }
             }
             m_pCurMethod = new Method(this, m_pCurClass, name, sig, flags);
         }
index 91004cd..031604b 100644 (file)
@@ -2619,26 +2619,6 @@ VOID    MethodTableBuilder::EnumerateClassMethods()
             }
         }
 
-        // Some interface checks.
-        if (IsInterface())
-        {
-            if (IsMdVirtual(dwMemberAttrs))
-            {
-                if (!IsMdAbstract(dwMemberAttrs))
-                {
-                    BuildMethodTableThrowException(BFA_VIRTUAL_NONAB_INT_METHOD);
-                }
-            }
-            else
-            {
-                // Instance field/method
-                if (!IsMdStatic(dwMemberAttrs))
-                {
-                    BuildMethodTableThrowException(BFA_NONVIRT_INST_INT_METHOD);
-                }
-            }
-        }
-
         // No synchronized methods in ValueTypes
         if(fIsClassValueType && IsMiSynchronized(dwImplFlags))
         {
@@ -2804,17 +2784,20 @@ VOID    MethodTableBuilder::EnumerateClassMethods()
                 // If the interface is a standard managed interface then allocate space for an FCall method desc.
                 Classification = mcFCall;
             }
-            else
+            else if (IsMdAbstract(dwMemberAttrs))
             {
                 // If COM interop is supported then all other interface MDs may be
                 // accessed via COM interop <TODO> mcComInterop MDs are BIG -
                 // this is very often a waste of space </TODO>
+                // @DIM_TODO - What if default interface method is called through COM interop?
                 Classification = mcComInterop;
             }
-#else // !FEATURE_COMINTEROP
-            // This codepath is used by remoting
-            Classification = mcIL;
+            else
 #endif // !FEATURE_COMINTEROP
+            {
+                // This codepath is used by remoting and default interface methods
+                Classification = mcIL;
+            }
         }
         else
         {
index 2fc5e09..ea10ca7 100644 (file)
@@ -5615,7 +5615,7 @@ void CEEInfo::getCallInfo(
     pResult->classFlags = getClassAttribsInternal(pResolvedToken->hClass);
 
     pResult->methodFlags = getMethodAttribsInternal(pResult->hMethod);
-    getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL);
+    getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL, /* isCallSite = */ TRUE);
 
     if (flags & CORINFO_CALLINFO_VERIFICATION)
     {
@@ -8356,7 +8356,8 @@ void
 CEEInfo::getMethodSigInternal(
     CORINFO_METHOD_HANDLE ftnHnd, 
     CORINFO_SIG_INFO *    sigRet, 
-    CORINFO_CLASS_HANDLE  owner)
+    CORINFO_CLASS_HANDLE  owner,
+    BOOL isCallSite)
 {
     STANDARD_VM_CONTRACT;
 
@@ -8382,7 +8383,15 @@ CEEInfo::getMethodSigInternal(
     // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation
     if (ftn->RequiresInstArg())
     {
-        sigRet->callConv = (CorInfoCallConv) (sigRet->callConv | CORINFO_CALLCONV_PARAMTYPE);
+        //
+        // If we are making an interface call that is a default interface method, we need to lie to the JIT.  
+        // The reason being that we already made sure target is always directly callable (through instantiation stubs), 
+        // JIT should not generate shared generics aware call code and insert the secret argument again at the callsite.
+        // Otherwise we would end up with two secret generic dictionary arguments (since the stub also provides one).
+        //
+        BOOL isDefaultInterfaceMethodCallSite = isCallSite && ftn->IsDefaultInterfaceMethod();
+        if (!isDefaultInterfaceMethodCallSite)
+            sigRet->callConv = (CorInfoCallConv) (sigRet->callConv | CORINFO_CALLCONV_PARAMTYPE);
     }
 
     // We want the calling convention bit to be consistant with the method attribute bit
index e34b859..1dccdb2 100644 (file)
@@ -713,7 +713,8 @@ public:
     void getMethodSigInternal (
             CORINFO_METHOD_HANDLE ftnHnd,
             CORINFO_SIG_INFO* sigInfo,
-            CORINFO_CLASS_HANDLE owner = NULL
+            CORINFO_CLASS_HANDLE owner = NULL,
+            BOOL isCallSite = FALSE
             );
 
     void getEHinfo(
index 241a0cc..5ac5caf 100644 (file)
@@ -1762,7 +1762,11 @@ BOOL MethodDesc::IsSharedByGenericMethodInstantiations()
 // Does this method require an extra MethodTable argument for instantiation information?
 // This is the case for
 // * per-inst static methods in shared-code instantiated generic classes (e.g. static void MyClass<string>::m())
+//     - there is no this pointer providing generic dictionary info
 // * shared-code instance methods in instantiated generic structs (e.g. void MyValueType<string>::m())
+//     - unboxed 'this' pointer in value-type instance methods don't have MethodTable pointer by definition
+// * default interface method called via interface dispatch (e. g. IFoo<string>.Foo calling into IFoo<object>::Foo())
+//     - this pointer is ambiguous as it can implement more than one IFoo<T>
 BOOL MethodDesc::RequiresInstMethodTableArg() 
 {
     LIMITED_METHOD_DAC_CONTRACT;
@@ -1770,7 +1774,7 @@ BOOL MethodDesc::RequiresInstMethodTableArg()
     return
         IsSharedByGenericInstantiations() &&
         !HasMethodInstantiation() &&
-        (IsStatic() || GetMethodTable()->IsValueType());
+        (IsStatic() || GetMethodTable()->IsValueType() || IsDefaultInterfaceMethod());
 }
 
 //*******************************************************************************
@@ -1792,7 +1796,7 @@ BOOL MethodDesc::RequiresInstArg()
     LIMITED_METHOD_DAC_CONTRACT;
 
     BOOL fRet = IsSharedByGenericInstantiations() &&
-        (HasMethodInstantiation() || IsStatic() || GetMethodTable()->IsValueType());
+        (HasMethodInstantiation() || IsStatic() || GetMethodTable()->IsValueType() || IsDefaultInterfaceMethod());
 
     _ASSERT(fRet == (RequiresInstMethodTableArg() || RequiresInstMethodDescArg()));
     return fRet;
@@ -1868,7 +1872,8 @@ BOOL MethodDesc::AcquiresInstMethodTableFromThis() {
         IsSharedByGenericInstantiations()  &&
         !HasMethodInstantiation() &&
         !IsStatic() &&
-        !GetMethodTable()->IsValueType();
+        !GetMethodTable()->IsValueType() &&
+        !IsDefaultInterfaceMethod();
 }
 
 //*******************************************************************************
@@ -2582,7 +2587,10 @@ BOOL MethodDesc::RequiresStableEntryPoint(BOOL fEstimateForChunk /*=FALSE*/)
             return TRUE;
 
         // TODO: Can we avoid early allocation of precodes for interfaces and cominterop?
-        if ((IsInterface() && !IsStatic()) || IsComPlusCall())
+        // Only abstract virtual interface method need precode
+        // @DIM_TODO - We need to decide what is the right approach for precode for default 
+        // interface methods
+        if ((IsInterface() && IsAbstract() && IsVirtual() && !IsStatic()) || IsComPlusCall())
             return TRUE;
     }
 
@@ -2678,7 +2686,7 @@ BOOL MethodDesc::MayHaveNativeCode()
 
     _ASSERTE(IsIL());
 
-    if ((IsInterface() && !IsStatic()) || IsWrapperStub() || ContainsGenericVariables() || IsAbstract())
+    if (IsWrapperStub() || ContainsGenericVariables() || IsAbstract())
     {
         return FALSE;
     }
index 71e838a..336260c 100644 (file)
@@ -1087,6 +1087,14 @@ public:
             && GetSlot() < pMT->GetNumVirtuals();
     }
 
+    // Is this a default interface method (virtual non-abstract instance method)
+    inline BOOL IsDefaultInterfaceMethod()
+    {
+        LIMITED_METHOD_CONTRACT;
+
+        return (GetMethodTable()->IsInterface() && !IsStatic() && IsVirtual() && !IsAbstract());
+    }
+
     inline BOOL HasNonVtableSlot();
 
     void SetHasNonVtableSlot()
index 66a6a2e..474c611 100644 (file)
@@ -1982,7 +1982,7 @@ MethodTable::Debug_DumpInterfaceMap(
     HRESULT hr;
     EX_TRY
     {
-        InterfaceMapIterator it(this, false);
+        InterfaceMapIterator it(this);
         while (it.Next())
         {
             MethodTable *pInterfaceMT = it.GetInterface();
@@ -6850,6 +6850,12 @@ MethodTable::FindDispatchImpl(
         DispatchMapEntry e;
         if (!FindDispatchEntry(typeID, slotNumber, &e))
         {
+            // Figure out the interface being called
+            MethodTable *pIfcMT = GetThread()->GetDomain()->LookupType(typeID);
+
+            // Figure out which method of the interface the caller requested.
+            MethodDesc * pIfcMD = pIfcMT->GetMethodDescForSlot(slotNumber);
+
             // A call to an array thru IList<T> (or IEnumerable<T> or ICollection<T>) has to be handled specially.
             // These interfaces are "magic" (mostly due to working set concerned - they are created on demand internally
             // even though semantically, these are static interfaces.)
@@ -6863,7 +6869,7 @@ MethodTable::FindDispatchImpl(
                 // IList<T> call thru an array.
 
                 // Get the MT of IList<T> or IReadOnlyList<T>
-                MethodTable *pIfcMT = GetThread()->GetDomain()->LookupType(typeID);
+
 
                 // Quick sanity check
                 if (!(pIfcMT->HasInstantiation()))
@@ -6875,9 +6881,6 @@ MethodTable::FindDispatchImpl(
                 // Get the type of T (as in IList<T>)
                 TypeHandle theT = pIfcMT->GetInstantiation()[0];
 
-                // Figure out which method of IList<T> the caller requested.
-                MethodDesc * pIfcMD = pIfcMT->GetMethodDescForSlot(slotNumber);
-
                 // Retrieve the corresponding method of SZArrayHelper. This is the guy that will actually execute.
                 // This method will be an instantiation of a generic method. I.e. if the caller requested
                 // IList<T>.Meth(), he will actually be diverted to SZArrayHelper.Meth<T>().
@@ -6894,11 +6897,34 @@ MethodTable::FindDispatchImpl(
                 RETURN(TRUE);
 
             }
+            else
+            {
+                //
+                // See if we can find a default method from one of the implemented interfaces 
+                //
+                MethodDesc *pDefaultMethod = NULL;
+                if (FindDefaultMethod(
+                    pIfcMD,     // the interface method being resolved
+                    pIfcMT,     // the interface being resolved
+                    &pDefaultMethod))
+                {
+                    // Now, construct a DispatchSlot to return in *pImplSlot
+                    DispatchSlot ds(pDefaultMethod->GetMethodEntryPoint());
+
+                    if (pImplSlot != NULL)
+                    {
+                        *pImplSlot = ds;
+                    }
+
+                    RETURN(TRUE);
+                }
+            }
 
             // This contract is not implemented by this class or any parent class.
             RETURN(FALSE);
         }
 
+
         /////////////////////////////////
         // 1.1. Update the typeID and slotNumber so that the full search can commense below
         typeID = TYPE_ID_THIS_CLASS;
@@ -6916,6 +6942,148 @@ MethodTable::FindDispatchImpl(
     RETURN (TRUE);
 }
 
+#ifndef DACCESS_COMPILE
+BOOL MethodTable::FindDefaultMethod(
+    MethodDesc *pInterfaceMD,
+    MethodTable *pInterfaceMT,
+    MethodDesc **ppDefaultMethod
+)
+{
+    CONTRACT(BOOL) {
+        INSTANCE_CHECK;
+        MODE_ANY;
+        THROWS;
+        GC_TRIGGERS;
+        PRECONDITION(CheckPointer(pInterfaceMD));
+        PRECONDITION(CheckPointer(pInterfaceMT));
+        PRECONDITION(CheckPointer(ppDefaultMethod));
+        POSTCONDITION(!RETVAL || (*ppDefaultMethod) != nullptr);
+    } CONTRACT_END;
+
+    //
+    // Find best candidate
+    //
+    InterfaceMapIterator it = this->IterateInterfaceMap();
+    MethodTable *pBestCandidateMT = NULL;
+    MethodDesc  *pBestCandidateMD = NULL;
+
+
+    //
+    // 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
+    //
+    MethodTable *pMT = this;
+    while (pMT != NULL)
+    {
+        MethodTable *pParentMT = pMT->GetParentMethodTable();
+        unsigned dwParentInterfaces = 0;
+        if (pParentMT)
+            dwParentInterfaces = pParentMT->GetNumInterfaces();
+
+        // Scanning only current class only if the current class have more interface than parent
+        // (parent interface are laid out first in interface map)
+        if (pMT->GetNumInterfaces() > dwParentInterfaces)
+        {    
+            // Only iterate the interfaceimpls on current class
+            MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMapFrom(dwParentInterfaces);
+            while (!it.Finished())
+            {
+                MethodTable *pCurMT = it.GetInterface();
+
+                MethodDesc *pCurMD = NULL;
+                if (pCurMT == pInterfaceMT)
+                {
+                    if (!pInterfaceMD->IsAbstract())
+                    {
+                        // exact match
+                        pCurMD = pInterfaceMD;
+                    }
+                }
+                else if (pCurMT->CanCastToInterface(pInterfaceMT))
+                {
+                    if (pCurMT->HasSameTypeDefAs(pInterfaceMT))
+                    {
+                        // Generic variance match
+                        pCurMD = pInterfaceMD;
+                    }
+                    else
+                    {
+                        //
+                        // Parent 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())
+                            {
+                                MethodImpl *pImpl = pMD->GetMethodImpl();
+                                MethodDesc **pImplMDs = pImpl->GetImplementedMDs();
+                                for (DWORD i = 0; i < pImpl->GetSize(); ++i)
+                                {
+                                    if (pImplMDs[i] == pInterfaceMD)
+                                    {
+                                        pCurMD = pMD;
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+
+                if (pCurMD != NULL)
+                {
+                    //
+                    // Found a match. But is it a more specific match (we want most specific interfaces)
+                    //
+                    if (pCurMD->HasClassOrMethodInstantiation())
+                    {
+                        // Instantiate the MethodDesc
+                        // We don't want generic dictionary from this pointer - we need pass secret type argument
+                        // from instantiating stubs to resolve ambiguity
+                        pCurMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
+                            pCurMD,
+                            pCurMT,
+                            FALSE,                  // forceBoxedEntryPoint
+                            pCurMD->HasMethodInstantiation() ?
+                                pCurMD->AsInstantiatedMethodDesc()->IMD_GetMethodInstantiation() :
+                                Instantiation(),    // for method themselves that are generic
+                            FALSE,                  // allowInstParam
+                            TRUE                    // forceRemoteableMethod
+                        );
+                    }
+
+                    if (pBestCandidateMT == NULL ||                         // first time
+                        pCurMT->CanCastToInterface(pBestCandidateMT))       // Prefer "more specific"" interface
+                    {
+                        // This is a better match
+                        pBestCandidateMT = pCurMT;
+                        pBestCandidateMD = pCurMD;
+                    }
+                }
+
+                it.Next();
+            }
+        }
+
+        pMT = pParentMT;
+    }
+
+    if (pBestCandidateMD != NULL)
+    {
+        *ppDefaultMethod = pBestCandidateMD;
+        RETURN(TRUE);
+    }
+
+    RETURN(FALSE);
+}
+#endif // DACCESS_COMPILE
+
 //==========================================================================================
 DispatchSlot MethodTable::FindDispatchSlot(UINT32 typeID, UINT32 slotNumber)
 {
@@ -9473,79 +9641,79 @@ MethodTable::TryResolveConstraintMethodApprox(
         // we don't have enough exact type information at JIT time
         // even to decide whether we will be able to resolve to an unboxed entry point...
         // To cope with this case we always go via the helper function if there's any
-        // chance of this happening by checking for all interfaces which might possibly
-        // be compatible with the call (verification will have ensured that
-        // at least one of them will be)
-        
-        // Enumerate all potential interface instantiations
-        MethodTable::InterfaceMapIterator it = pCanonMT->IterateInterfaceMap();
-        DWORD cPotentialMatchingInterfaces = 0;
-        while (it.Next())
+// chance of this happening by checking for all interfaces which might possibly
+// be compatible with the call (verification will have ensured that
+// at least one of them will be)
+
+// Enumerate all potential interface instantiations
+MethodTable::InterfaceMapIterator it = pCanonMT->IterateInterfaceMap();
+DWORD cPotentialMatchingInterfaces = 0;
+while (it.Next())
+{
+    TypeHandle thPotentialInterfaceType(it.GetInterface());
+    if (thPotentialInterfaceType.AsMethodTable()->GetCanonicalMethodTable() ==
+        thInterfaceType.AsMethodTable()->GetCanonicalMethodTable())
+    {
+        cPotentialMatchingInterfaces++;
+        pMD = pCanonMT->GetMethodDescForInterfaceMethod(thPotentialInterfaceType, pGenInterfaceMD);
+
+        // See code:#TryResolveConstraintMethodApprox_DoNotReturnParentMethod
+        if ((pMD != NULL) && !pMD->GetMethodTable()->IsValueType())
         {
-            TypeHandle thPotentialInterfaceType(it.GetInterface());
-            if (thPotentialInterfaceType.AsMethodTable()->GetCanonicalMethodTable() == 
-                thInterfaceType.AsMethodTable()->GetCanonicalMethodTable())
-            {
-                cPotentialMatchingInterfaces++;
-                pMD = pCanonMT->GetMethodDescForInterfaceMethod(thPotentialInterfaceType, pGenInterfaceMD);
-                
-                // See code:#TryResolveConstraintMethodApprox_DoNotReturnParentMethod
-                if ((pMD != NULL) && !pMD->GetMethodTable()->IsValueType())
-                {
-                    LOG((LF_JIT, LL_INFO10000, "TryResolveConstraintMethodApprox: %s::%s not a value type method\n",
-                         pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
-                    return NULL;
-                }
-            }
+            LOG((LF_JIT, LL_INFO10000, "TryResolveConstraintMethodApprox: %s::%s not a value type method\n",
+                pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
+            return NULL;
         }
-        
-        _ASSERTE_MSG((cPotentialMatchingInterfaces != 0), 
-            "At least one interface has to implement the method, otherwise there's a bug in JIT/verification.");
+    }
+}
 
-        if (cPotentialMatchingInterfaces > 1)
-        {   // We have more potentially matching interfaces
-            MethodTable * pInterfaceMT = thInterfaceType.GetMethodTable();
-            _ASSERTE(pInterfaceMT->HasInstantiation());
-            
-            BOOL fIsExactMethodResolved = FALSE;
-
-            if (!pInterfaceMT->IsSharedByGenericInstantiations() && 
-                !pInterfaceMT->IsGenericTypeDefinition() && 
-                !this->IsSharedByGenericInstantiations() && 
-                !this->IsGenericTypeDefinition())
-            {   // We have exact interface and type instantiations (no generic variables and __Canon used 
-                // anywhere)
-                if (this->CanCastToInterface(pInterfaceMT))
-                {
-                    // We can resolve to exact method
-                    pMD = this->GetMethodDescForInterfaceMethod(pInterfaceMT, pInterfaceMD);
-                    _ASSERTE(pMD != NULL);
-                    fIsExactMethodResolved = TRUE;
-                }
-            }
-            
-            if (!fIsExactMethodResolved)
-            {   // We couldn't resolve the interface statically
-                _ASSERTE(pfForceUseRuntimeLookup != NULL);
-                // Notify the caller that it should use runtime lookup
-                // Note that we can leave pMD incorrect, because we will use runtime lookup
-                *pfForceUseRuntimeLookup = TRUE;
-            }
+_ASSERTE_MSG((cPotentialMatchingInterfaces != 0),
+    "At least one interface has to implement the method, otherwise there's a bug in JIT/verification.");
+
+if (cPotentialMatchingInterfaces > 1)
+{   // We have more potentially matching interfaces
+    MethodTable * pInterfaceMT = thInterfaceType.GetMethodTable();
+    _ASSERTE(pInterfaceMT->HasInstantiation());
+
+    BOOL fIsExactMethodResolved = FALSE;
+
+    if (!pInterfaceMT->IsSharedByGenericInstantiations() &&
+        !pInterfaceMT->IsGenericTypeDefinition() &&
+        !this->IsSharedByGenericInstantiations() &&
+        !this->IsGenericTypeDefinition())
+    {   // We have exact interface and type instantiations (no generic variables and __Canon used 
+        // anywhere)
+        if (this->CanCastToInterface(pInterfaceMT))
+        {
+            // We can resolve to exact method
+            pMD = this->GetMethodDescForInterfaceMethod(pInterfaceMT, pInterfaceMD);
+            _ASSERTE(pMD != NULL);
+            fIsExactMethodResolved = TRUE;
         }
-        else
+    }
+
+    if (!fIsExactMethodResolved)
+    {   // We couldn't resolve the interface statically
+        _ASSERTE(pfForceUseRuntimeLookup != NULL);
+        // Notify the caller that it should use runtime lookup
+        // Note that we can leave pMD incorrect, because we will use runtime lookup
+        *pfForceUseRuntimeLookup = TRUE;
+    }
+}
+else
+{
+    // If we can resolve the interface exactly then do so (e.g. when doing the exact 
+    // lookup at runtime, or when not sharing generic code).
+    if (pCanonMT->CanCastToInterface(thInterfaceType.GetMethodTable()))
+    {
+        pMD = pCanonMT->GetMethodDescForInterfaceMethod(thInterfaceType, pGenInterfaceMD);
+        if (pMD == NULL)
         {
-            // If we can resolve the interface exactly then do so (e.g. when doing the exact 
-            // lookup at runtime, or when not sharing generic code).
-            if (pCanonMT->CanCastToInterface(thInterfaceType.GetMethodTable()))
-            {
-                pMD = pCanonMT->GetMethodDescForInterfaceMethod(thInterfaceType, pGenInterfaceMD);
-                if (pMD == NULL)
-                {
-                    LOG((LF_JIT, LL_INFO10000, "TryResolveConstraintMethodApprox: failed to find method desc for interface method\n"));
-                }
-            }
+            LOG((LF_JIT, LL_INFO10000, "TryResolveConstraintMethodApprox: failed to find method desc for interface method\n"));
         }
     }
+}
+    }
     else if (pGenInterfaceMD->IsVirtual())
     {
         if (pGenInterfaceMD->HasNonVtableSlot() && pGenInterfaceMD->GetMethodTable()->IsValueType())
@@ -9566,33 +9734,36 @@ MethodTable::TryResolveConstraintMethodApprox(
         // methods on System.Object, i.e. when these are used as a constraint.
         pMD = NULL;
     }
-    
+
     if (pMD == NULL)
     {   // Fall back to VSD
         return NULL;
     }
-    
-    //#TryResolveConstraintMethodApprox_DoNotReturnParentMethod
-    // Only return a method if the value type itself declares the method, 
-    // otherwise we might get a method from Object or System.ValueType
-    if (!pMD->GetMethodTable()->IsValueType())
-    {   // Fall back to VSD
-        return NULL;
+
+    if (!pMD->GetMethodTable()->IsInterface())
+    {
+        //#TryResolveConstraintMethodApprox_DoNotReturnParentMethod
+        // Only return a method if the value type itself declares the method
+        // otherwise we might get a method from Object or System.ValueType
+        if (!pMD->GetMethodTable()->IsValueType())
+        {   // Fall back to VSD
+            return NULL;
+        }
+
+        // We've resolved the method, ignoring its generic method arguments
+        // If the method is a generic method then go and get the instantiated descriptor
+        pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
+            pMD,
+            this,
+            FALSE /* no BoxedEntryPointStub */,
+            pInterfaceMD->GetMethodInstantiation(),
+            FALSE /* no allowInstParam */);
+
+        // FindOrCreateAssociatedMethodDesc won't return an BoxedEntryPointStub.
+        _ASSERTE(pMD != NULL);
+        _ASSERTE(!pMD->IsUnboxingStub());
     }
-    
-    // We've resolved the method, ignoring its generic method arguments
-    // If the method is a generic method then go and get the instantiated descriptor
-    pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(
-        pMD,
-        this,
-        FALSE /* no BoxedEntryPointStub */ ,
-        pInterfaceMD->GetMethodInstantiation(),
-        FALSE /* no allowInstParam */ );
-    
-    // FindOrCreateAssociatedMethodDesc won't return an BoxedEntryPointStub.
-    _ASSERTE(pMD != NULL);
-    _ASSERTE(!pMD->IsUnboxingStub());
-    
+
     return pMD;
 } // MethodTable::TryResolveConstraintMethodApprox
 
index d3eb0ce..11296b0 100644 (file)
@@ -2485,6 +2485,14 @@ public:
         UINT32         slotNumber, 
         DispatchSlot * pImplSlot);
 
+
+#ifndef DACCESS_COMPILE
+    BOOL FindDefaultMethod(
+        MethodDesc *pInterfaceMD,
+        MethodTable *pObjectMT,
+        MethodDesc **ppDefaultMethod);
+#endif // DACCESS_COMPILE
+
     DispatchSlot FindDispatchSlot(UINT32 typeID, UINT32 slotNumber);
 
     DispatchSlot FindDispatchSlot(DispatchToken tok);
index 9b72d24..f8a073f 100644 (file)
@@ -650,12 +650,15 @@ inline MethodDesc* MethodTable::GetMethodDescForSlot(DWORD slot)
 
     PCODE pCode = GetRestoredSlot(slot);
 
-    // This is an optimization that we can take advantage of if we're trying
-    // to get the MethodDesc for an interface virtual, since their slots
-    // always point to the stub.
+    // This is an optimization that we can take advantage of if we're trying to get the MethodDesc 
+    // for an interface virtual, since their slots usually point to stub.
     if (IsInterface() && slot < GetNumVirtuals())
     {
-        return MethodDesc::GetMethodDescFromStubAddr(pCode);
+        // @DIM_TODO - This is not a reliable approach. Need to change MakeJitWorker to not stomp 
+        // over slot and instead set the target of precode to the address. We may need the precode 
+        // there anyway to handle other cases too (such as interop). 
+        MethodDesc *pMD = MethodDesc::GetMethodDescFromStubAddr(pCode, /* fSpeculative = */ TRUE);
+        if (pMD != NULL) return pMD;
     }
 
     return MethodTable::GetMethodDescForSlotAddress(pCode);
index bd9dd24..b3aed49 100644 (file)
@@ -1620,19 +1620,24 @@ MethodTableBuilder::BuildMethodTableThrowing(
     // Allocate MethodDescs (expects methods placed methods)
     AllocAndInitMethodDescs();
 
-    //
-    // If we are a class, then there may be some unplaced vtable methods (which are by definition
-    // interface methods, otherwise they'd already have been placed).  Place as many unplaced methods
-    // as possible, in the order preferred by interfaces.  However, do not allow any duplicates - once
-    // a method has been placed, it cannot be placed again - if we are unable to neatly place an interface,
-    // create duplicate slots for it starting at dwCurrentDuplicateVtableSlot.  Fill out the interface
-    // map for all interfaces as they are placed.
-    //
-    // If we are an interface, then all methods are already placed.  Fill out the interface map for
-    // interfaces as they are placed.
-    //
-    if (!IsInterface())
+    if (IsInterface())
     {
+        ProcessMethodImpls();
+        PlaceMethodImpls();
+    }
+    else
+    {
+        //
+        // If we are a class, then there may be some unplaced vtable methods (which are by definition
+        // interface methods, otherwise they'd already have been placed).  Place as many unplaced methods
+        // as possible, in the order preferred by interfaces.  However, do not allow any duplicates - once
+        // a method has been placed, it cannot be placed again - if we are unable to neatly place an interface,
+        // create duplicate slots for it starting at dwCurrentDuplicateVtableSlot.  Fill out the interface
+        // map for all interfaces as they are placed.
+        //
+        // If we are an interface, then all methods are already placed.  Fill out the interface map for
+        // interfaces as they are placed.
+        //
         ComputeInterfaceMapEquivalenceSet();
 
         PlaceInterfaceMethods();
@@ -2843,16 +2848,16 @@ MethodTableBuilder::EnumerateClassMethods()
                 BuildMethodTableThrowException(BFA_NONVIRT_AB_METHOD);
             }
         }
-        else if(fIsClassInterface)
-        {
-            if (IsMdRTSpecialName(dwMemberAttrs) || IsMdVirtual(dwMemberAttrs))
-            {
-                CONSISTENCY_CHECK(CheckPointer(strMethodName));
-                if (strcmp(strMethodName, COR_CCTOR_METHOD_NAME))
-                {
-                    BuildMethodTableThrowException(BFA_NONAB_NONCCTOR_METHOD_ON_INT);
-                }
-            }
+        else if(fIsClassInterface)             
+        {              
+            if (IsMdRTSpecialName(dwMemberAttrs))
+            {          
+                CONSISTENCY_CHECK(CheckPointer(strMethodName));                
+                if (strcmp(strMethodName, COR_CCTOR_METHOD_NAME))              
+                {              
+                    BuildMethodTableThrowException(BFA_NONAB_NONCCTOR_METHOD_ON_INT);          
+                }              
+            }          
         }
 
         // Virtual / not virtual
@@ -2872,26 +2877,6 @@ MethodTableBuilder::EnumerateClassMethods()
             }
         }
 
-        // Some interface checks.
-        if (IsInterface())
-        {
-            if (IsMdVirtual(dwMemberAttrs))
-            {
-                if (!IsMdAbstract(dwMemberAttrs))
-                {
-                    BuildMethodTableThrowException(BFA_VIRTUAL_NONAB_INT_METHOD);
-                }
-            }
-            else
-            {
-                // Instance field/method
-                if (!IsMdStatic(dwMemberAttrs))
-                {
-                    BuildMethodTableThrowException(BFA_NONVIRT_INST_INT_METHOD);
-                }
-            }
-        }
-
         // No synchronized methods in ValueTypes
         if(fIsClassValueType && IsMiSynchronized(dwImplFlags))
         {
@@ -3114,7 +3099,7 @@ MethodTableBuilder::EnumerateClassMethods()
                 type = METHOD_TYPE_NORMAL;
             }
             else if (bmtGenerics->GetNumGenericArgs() != 0 &&
-                    (bmtGenerics->fSharedByGenericInstantiations || (!bmtProp->fIsRedirectedInterface && !GetHalfBakedClass()->IsProjectedFromWinRT())))
+                (bmtGenerics->fSharedByGenericInstantiations || (!bmtProp->fIsRedirectedInterface && !GetHalfBakedClass()->IsProjectedFromWinRT())))
             {
                 // Methods in instantiated interfaces need nothing special - they are not visible from COM etc.
                 // mcComInterop is only useful for unshared instantiated WinRT interfaces. If the interface is
@@ -3126,7 +3111,7 @@ MethodTableBuilder::EnumerateClassMethods()
                 // If the interface is a standard managed interface then allocate space for an FCall method desc.
                 type = METHOD_TYPE_FCALL;
             }
-            else
+            else if (IsMdAbstract(dwMemberAttrs))
             {
                 // If COM interop is supported then all other interface MDs may be
                 // accessed via COM interop. mcComInterop MDs have an additional
@@ -3134,10 +3119,12 @@ MethodTableBuilder::EnumerateClassMethods()
                 // allocated lazily when/if the MD actually gets used for interop.
                 type = METHOD_TYPE_COMINTEROP;
             }
-#else // !FEATURE_COMINTEROP
-            // This codepath is used by remoting
-            type = METHOD_TYPE_NORMAL;
+            else
 #endif // !FEATURE_COMINTEROP
+            {
+                // This codepath is used by remoting
+                type = METHOD_TYPE_NORMAL;
+            }
         }
         else
         {
@@ -5712,49 +5699,60 @@ MethodTableBuilder::ProcessMethodImpls()
                                     }
                                 }
 
-                                if (pDeclType == NULL)
+                                if (IsInterface())
                                 {
-                                    DWORD equivalenceSet = 0;
-
-                                    for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
-                                    {
-                                        bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
-                                        // Type Equivalence is respected for this comparision as we just need to find an 
-                                        // equivalent interface, the particular interface is unimportant
-                                        if (MetaSig::CompareTypeDefsUnderSubstitutions(
-                                            pCurItf->GetMethodTable(),      pDeclMT,
-                                            &pCurItf->GetSubstitution(),    pDeclSubst,
-                                            NULL))
-                                        {
-                                            equivalenceSet = bmtInterface->pInterfaceMap[i].GetInterfaceEquivalenceSet();
-                                            pItfEntry = &bmtInterface->pInterfaceMap[i];
-                                            break;
-                                        }
-                                    }
-
-                                    if (equivalenceSet == 0)
+                                    if (pDeclType == NULL)
                                     {
                                         // Interface is not implemented by this type.
                                         BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NOTIMPLEMENTED, it.Token());
                                     }
-
-                                    // Interface is not implemented by this type exactly. We need to consider this MethodImpl on non exact interface matches,
-                                    // as the only match may be one of the non-exact matches
-                                    bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing = true;
-                                    bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing = true;
-                                    bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet = equivalenceSet;
-                                    bmtMethod->dwNumberInexactMethodImplCandidates++;
-                                    continue; // Move on to other MethodImpls
                                 }
                                 else
                                 {
-                                    // This method impl may need to match other methods during inexact processing
-                                    if (pItfEntry->InEquivalenceSetWithMultipleEntries())
+                                    if (pDeclType == NULL)
                                     {
+                                        DWORD equivalenceSet = 0;
+
+                                        for (DWORD i = 0; i < bmtInterface->dwInterfaceMapSize; i++)
+                                        {
+                                            bmtRTType * pCurItf = bmtInterface->pInterfaceMap[i].GetInterfaceType();
+                                            // Type Equivalence is respected for this comparision as we just need to find an 
+                                            // equivalent interface, the particular interface is unimportant
+                                            if (MetaSig::CompareTypeDefsUnderSubstitutions(
+                                                pCurItf->GetMethodTable(), pDeclMT,
+                                                &pCurItf->GetSubstitution(), pDeclSubst,
+                                                NULL))
+                                            {
+                                                equivalenceSet = bmtInterface->pInterfaceMap[i].GetInterfaceEquivalenceSet();
+                                                pItfEntry = &bmtInterface->pInterfaceMap[i];
+                                                break;
+                                            }
+                                        }
+
+                                        if (equivalenceSet == 0)
+                                        {
+                                            // Interface is not implemented by this type.
+                                            BuildMethodTableThrowException(IDS_CLASSLOAD_MI_NOTIMPLEMENTED, it.Token());
+                                        }
+
+                                        // Interface is not implemented by this type exactly. We need to consider this MethodImpl on non exact interface matches,
+                                        // as the only match may be one of the non-exact matches
                                         bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing = true;
-                                        bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing = false;
-                                        bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet = pItfEntry->GetInterfaceEquivalenceSet();
+                                        bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing = true;
+                                        bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet = equivalenceSet;
                                         bmtMethod->dwNumberInexactMethodImplCandidates++;
+                                        continue; // Move on to other MethodImpls
+                                    }
+                                    else
+                                    {
+                                        // This method impl may need to match other methods during inexact processing
+                                        if (pItfEntry->InEquivalenceSetWithMultipleEntries())
+                                        {
+                                            bmtMetaData->rgMethodImplTokens[m].fConsiderDuringInexactMethodImplProcessing = true;
+                                            bmtMetaData->rgMethodImplTokens[m].fThrowIfUnmatchedDuringInexactMethodImplProcessing = false;
+                                            bmtMetaData->rgMethodImplTokens[m].interfaceEquivalenceSet = pItfEntry->GetInterfaceEquivalenceSet();
+                                            bmtMethod->dwNumberInexactMethodImplCandidates++;
+                                        }
                                     }
                                 }
 
@@ -5856,7 +5854,7 @@ MethodTableBuilder::ProcessMethodImpls()
                     {   // Method not found, throw.
                         BuildMethodTableThrowException(IDS_CLASSLOAD_MI_DECLARATIONNOTFOUND, it.Token());
                     }
-
+                    
                     if (!IsMdVirtual(declMethod.GetDeclAttrs()))
                     {   // Make sure the decl is virtual
                         BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
@@ -6190,35 +6188,62 @@ MethodTableBuilder::PlaceMethodImpls()
                 BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES, mdef);
             }
 
-            // Throws
-            PlaceLocalDeclaration(pCurDeclMethod,
-                                       pCurImplMethod,
-                                       slots,             // Adds override to the slot and replaced arrays.
-                                       replaced,
-                                       &slotIndex);       // Increments count
+            if (IsInterface())
+            {
+                // We implement this slot, record it
+                slots[slotIndex] = pCurDeclMethod->GetSlotIndex();
+                replaced[slotIndex] = pCurDeclMethod->GetMethodDesc();
+
+                // increment the counter
+                slotIndex++;
+            }
+            else
+            {
+                // Throws
+                PlaceLocalDeclaration(
+                    pCurDeclMethod,
+                    pCurImplMethod,
+                    slots,             // Adds override to the slot and replaced arrays.
+                    replaced,
+                    &slotIndex);       // Increments count
+            }
         }
         else
         {
             bmtRTMethod * pCurDeclMethod = hDeclMethod.AsRTMethod();
 
-            // Do not use pDecl->IsInterface here as that asks the method table and the MT may not yet be set up.
-            if(pCurDeclMethod->GetOwningType()->IsInterface())
+            if (IsInterface())
             {
-                // Throws
-                PlaceInterfaceDeclaration(pCurDeclMethod,
-                                               pCurImplMethod,
-                                               slots,
-                                               replaced,
-                                               &slotIndex);     // Increments count
+                // We implement this slot, record it
+                slots[slotIndex] = pCurDeclMethod->GetSlotIndex();
+                replaced[slotIndex] = pCurDeclMethod->GetMethodDesc();
+
+                // increment the counter
+                slotIndex++;
             }
             else
             {
-                // Throws
-                PlaceParentDeclaration(pCurDeclMethod,
-                                            pCurImplMethod,
-                                            slots,
-                                            replaced,
-                                            &slotIndex);        // Increments count
+                // Do not use pDecl->IsInterface here as that asks the method table and the MT may not yet be set up.
+                if (pCurDeclMethod->GetOwningType()->IsInterface())
+                {
+                    // Throws
+                    PlaceInterfaceDeclaration(
+                        pCurDeclMethod,
+                        pCurImplMethod,
+                        slots,
+                        replaced,
+                        &slotIndex);     // Increments count
+                }
+                else
+                {
+                    // Throws
+                    PlaceParentDeclaration(
+                        pCurDeclMethod,
+                        pCurImplMethod,
+                        slots,
+                        replaced,
+                        &slotIndex);        // Increments count
+                }
             }
         }
 
@@ -6273,20 +6298,30 @@ MethodTableBuilder::WriteMethodImplData(
         // Set the size of the info the MethodImpl needs to keep track of.
         pImpl->SetSize(GetLoaderAllocator()->GetHighFrequencyHeap(), GetMemTracker(), cSlots);
 
-        // Gasp we do a bubble sort. Should change this to a qsort..
-        for (DWORD i = 0; i < cSlots; i++)
+        if (!IsInterface())
         {
-            for (DWORD j = i+1; j < cSlots; j++)
+            // 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
+            for (DWORD i = 0; i < cSlots; i++)
             {
-                if (rgSlots[j] < rgSlots[i])
+                int min = i;
+                for (DWORD j = i + 1; j < cSlots; j++)
+                {
+                    if (rgSlots[j] < rgSlots[min])
+                    {
+                        min = j;
+                    }
+                }
+
+                if (min != i)
                 {
                     MethodDesc * mTmp = rgDeclMD[i].GetValue();
-                    rgDeclMD[i].SetValue(rgDeclMD[j].GetValue());
-                    rgDeclMD[j].SetValue(mTmp);
+                    rgDeclMD[i].SetValue(rgDeclMD[min].GetValue());
+                    rgDeclMD[min].SetValue(mTmp);
 
                     DWORD sTmp = rgSlots[i];
-                    rgSlots[i] = rgSlots[j];
-                    rgSlots[j] = sTmp;
+                    rgSlots[i] = rgSlots[min];
+                    rgSlots[min] = sTmp;
                 }
             }
         }
@@ -6560,8 +6595,8 @@ VOID MethodTableBuilder::ValidateInterfaceMethodConstraints()
             // If pTargetMT is null, this indicates that the target MethodDesc belongs
             // to the current type. Otherwise, the MethodDesc MUST be owned by a parent
             // of the type we're building.
-            BOOL              fTargetIsOwnedByParent = !pTargetMD->GetMethodTablePtr()->IsNull();
-
+            BOOL              fTargetIsOwnedByParent = !pTargetMD->GetMethodTablePtr()->IsNull();        
+            
             // If the method is owned by a parent, we need to use the parent's module,
             // and we must construct the substitution chain all the way up to the parent.
             const Substitution *pSubstTgt = NULL;
@@ -10820,11 +10855,13 @@ void MethodTableBuilder::VerifyVirtualMethodsImplemented(MethodTable::MethodData
             MethodTable::MethodIterator it(hData);
             for (; it.IsValid() && it.IsVirtual(); it.Next())
             {
-                if (it.GetTarget().IsNull())
-                {
-                    MethodDesc *pMD = it.GetDeclMethodDesc();
-                    BuildMethodTableThrowException(IDS_CLASSLOAD_NOTIMPLEMENTED, pMD->GetNameOnNonArrayClass());
-                }
+                // @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());
+                // }
             }
         }
     }
index d1075e5..88bb44e 100644 (file)
       <_IlasmSwitches Condition="'$(DebugType)' == 'Impl'">$(_IlasmSwitches) -DEBUG=IMPL</_IlasmSwitches>
       <_IlasmSwitches Condition="'$(DebugType)' == 'PdbOnly'">$(_IlasmSwitches) -DEBUG=OPT</_IlasmSwitches>
       <_IlasmSwitches Condition="'$(Optimize)' == 'True'">$(_IlasmSwitches) -OPTIMIZE</_IlasmSwitches>
+      <ILAsmExe>ilasm</ILAsmExe>
+      <!-- Unfortunately not every IL test is compatible with CoreCLR ilasm. We are only opt-in those that really requires it -->
+      <ILAsmExe Condition="'$(UseCustomILAsm)'=='True'">$(__BinDir)\$(ILAsmExe)</ILAsmExe>
     </PropertyGroup>
 
-    <Exec Command="$(_ilasm) $(_OutputTypeArgument) $(_ShellKeyMarker)OUTPUT=@(IntermediateAssembly) $(_IlasmSwitches) @(Compile)">
+    <Exec Command="$(ILAsmExe) $(_OutputTypeArgument) $(_ShellKeyMarker)OUTPUT=@(IntermediateAssembly) $(_IlasmSwitches) @(Compile)">
       <Output TaskParameter="ExitCode" PropertyName="_ILAsmExitCode" />
     </Exec>
     <Error Text="ILAsm failed" Condition="'$(_ILAsmExitCode)' != '0'" />
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.cs b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.cs
new file mode 100644 (file)
index 0000000..decd7bd
--- /dev/null
@@ -0,0 +1,185 @@
+using System;
+using System.Collections.Generic;
+
+interface IFoo
+{
+    int Foo(int c);    
+}
+
+interface IAdd 
+{
+    int Add(int c);
+}
+
+// Only needed for writing IFoo.Foo code
+class IFoo_Impl : IFoo
+{
+    public int Foo(int c)
+    {
+        IAdd adder = (IAdd) this;
+        return adder.Add(c);
+    }        
+}
+
+struct FooValue : IFoo, IAdd
+{
+    public int val;
+
+    public int Foo(int c)
+    {
+        val +=c;
+        return val;
+    }
+
+    public int Add(int c)
+    {
+        val +=c;
+        return val;
+    }
+}
+
+interface IHorrible<T>
+{
+    int GetLocalVal();
+    void SetLocalVal(int val);
+    int Horrible();
+}
+
+// Only needed for the default interface implementation
+class IHorrible_Impl<T> : IHorrible<T>
+{
+    public int GetLocalVal() { return 0; }
+    public void SetLocalVal(int val) {}
+    public int Horrible()
+    {
+        int val = GetLocalVal(); 
+        val++; 
+        SetLocalVal(val); 
+        return val;
+    }
+}
+
+struct HorribleCase<Z> : IHorrible<IList<Z>>, IHorrible<IEnumerable<Z>>
+{
+    int localVal;
+    public int GetLocalVal() { return localVal; }
+    public void SetLocalVal(int val) { localVal = val; }
+    int IHorrible<IList<Z>>.Horrible() { return ++localVal; }
+
+    // Remove
+    int IHorrible<IEnumerable<Z>>.Horrible() { return ++localVal; }    
+}
+
+class HorribleTest
+{
+    public static int Horror<T,U>(T t) where T:IHorrible<U>
+    {
+        return t.Horrible() + t.Horrible();
+    }
+
+    public static void RunTest()
+    {
+        Test.Assert(Horror<HorribleCase<object>,IEnumerable<object>>(new HorribleCase<object>())) == 2, "Fail");
+        Test.Assert(Horror<HorribleCase<object>,IList<object>>(default(HorribleCase<object>)) == 3, "Fail");
+    }
+}
+
+/*
+interface IFoo<T>
+{
+    int Foo(int c);    
+}
+
+interface IAdd 
+{
+    int Add(int c);
+}
+
+// Only needed for writing IFoo.Foo code
+class IFoo_Impl<T> : IFoo<T>
+{
+    public int Foo(int c)
+    {
+        IAdd adder = (IAdd) this;
+        return adder.Add(c);
+    }        
+}
+
+struct FooValue<T> : IFoo<T>, IAdd
+{
+    public int val;
+
+    public int Foo(int c)
+    {
+        val +=c;
+        return val;
+    }
+
+    public int Add(int c)
+    {
+        val +=c;
+        return val;
+    }
+}
+*/   
+
+class SimpleConstraintTest
+{
+    public static int CallFoo_WithConstraints<T>(ref T foo, int val) where T : IFoo
+    {
+        return foo.Foo(val);
+    }
+
+    /*
+    public static int CallFoo_WithConstraints<T>(ref T foo, int val) where T : IFoo<object>
+    {
+        return foo.Foo(val);
+    }
+    */
+
+    public static void RunTest()
+    {
+        FooValue foo = new FooValue();
+        foo.val = 10;
+
+        Console.WriteLine("Calling CallFoo_WithConstraints on FooValue - expecting IFoo::Foo");
+        Test.Assert(CallFoo_WithConstraints(ref foo, 10) == 20, "Calling CallFoo_WithConstraints on FooValue");
+
+        Test.Assert(foo.val == 10, "Expecting boxing on CallFoo_WithConstraints");
+    }
+}
+
+class Program
+{
+    public static int Main()
+    {
+        HorribleTest.RunTest();
+        SimpleConstraintTest.RunTest();
+
+        return Test.Ret();
+    }
+}
+
+class Test
+{
+    private static bool Pass = true;
+
+    public static int Ret()
+    {
+        return Pass? 100 : 101;
+    }
+
+    public static void Assert(bool cond, string msg)
+    {
+        if (cond)
+        {
+            Console.WriteLine("PASS");
+        }
+        else
+        {
+            Console.WriteLine("FAIL: " + msg);
+            Pass = false;
+        }
+    }
+}                    
+
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.il
new file mode 100644 (file)
index 0000000..ef39ba5
--- /dev/null
@@ -0,0 +1,456 @@
+
+//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.6.1055.0
+//  Copyright (c) Microsoft Corporation.  All rights reserved.
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
+  .ver 4:0:0:0
+}
+.assembly constrainedcall
+{
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
+                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
+
+  // --- The following custom attribute is added automatically, do not uncomment -------
+  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 
+
+  .hash algorithm 0x00008004
+  .ver 0:0:0:0
+}
+.module constrainedcall.exe
+// MVID: {6171EA0F-1009-482D-8EF6-C944886D5D66}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003       // WINDOWS_CUI
+.corflags 0x00000001    //  ILONLY
+// Image base: 0x01860000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class interface private abstract auto ansi IFoo
+{
+  .method public hidebysig newslot virtual 
+          instance int32  Foo(int32 c) cil managed
+  {
+    // Code size       20 (0x14)
+    .maxstack  2
+    .locals init (class IAdd V_0,
+             int32 V_1)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  castclass  IAdd
+    IL_0007:  stloc.0
+    IL_0008:  ldloc.0
+    IL_0009:  ldarg.1
+    IL_000a:  callvirt   instance int32 IAdd::Add(int32)
+    IL_000f:  stloc.1
+    IL_0010:  br.s       IL_0012
+
+    IL_0012:  ldloc.1
+    IL_0013:  ret
+  } // end of method IFoo::Foo
+
+} // end of class IFoo
+
+.class interface private abstract auto ansi IAdd
+{
+  .method public hidebysig newslot abstract virtual 
+          instance int32  Add(int32 c) cil managed
+  {
+  } // end of method IAdd::Add
+
+} // end of class IAdd
+
+.class private sequential ansi sealed beforefieldinit FooValue
+       extends [mscorlib]System.ValueType
+       implements IFoo,
+                  IAdd
+{
+  .field public int32 val
+
+  .method public hidebysig newslot virtual final 
+          instance int32  Add(int32 c) cil managed
+  {
+    // Code size       26 (0x1a)
+    .maxstack  3
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  ldarg.0
+    IL_0003:  ldfld      int32 FooValue::val
+    IL_0008:  ldarg.1
+    IL_0009:  add
+    IL_000a:  stfld      int32 FooValue::val
+    IL_000f:  ldarg.0
+    IL_0010:  ldfld      int32 FooValue::val
+    IL_0015:  stloc.0
+    IL_0016:  br.s       IL_0018
+
+    IL_0018:  ldloc.0
+    IL_0019:  ret
+  } // end of method FooValue::Add
+
+} // end of class FooValue
+
+.class interface private abstract auto ansi IHorrible`1<T>
+{
+  .method public hidebysig newslot abstract virtual 
+          instance int32  GetLocalVal() cil managed
+  {
+  } // end of method IHorrible`1::GetLocalVal
+
+  .method public hidebysig newslot abstract virtual 
+          instance void  SetLocalVal(int32 val) cil managed
+  {
+  } // end of method IHorrible`1::SetLocalVal
+
+  .method public hidebysig newslot virtual 
+          instance int32  Horrible() cil managed
+  {
+    // Code size       26 (0x1a)
+    .maxstack  2
+    .locals init (int32 V_0,
+             int32 V_1)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  callvirt       instance int32 class IHorrible`1<!T>::GetLocalVal()
+    IL_0007:  stloc.0
+    IL_0008:  ldloc.0
+    IL_0009:  ldc.i4.1
+    IL_000a:  add
+    IL_000b:  stloc.0
+    IL_000c:  ldarg.0
+    IL_000d:  ldloc.0
+    IL_000e:  callvirt       instance void class IHorrible`1<!T>::SetLocalVal(int32)
+    IL_0013:  nop
+    IL_0014:  ldloc.0
+    IL_0015:  stloc.1
+    IL_0016:  br.s       IL_0018
+
+    IL_0018:  ldloc.1
+    IL_0019:  ret
+  } // end of method IHorrible`1::Horrible
+
+} // end of class IHorrible`1
+
+.class private sequential ansi sealed beforefieldinit HorribleCase`1<Z>
+       extends [mscorlib]System.ValueType
+       implements class IHorrible`1<class [mscorlib]System.Collections.Generic.IList`1<!Z>>,
+                  class IHorrible`1<class [mscorlib]System.Collections.Generic.IEnumerable`1<!Z>>
+{
+  .field private int32 localVal
+  .method public hidebysig newslot virtual final 
+          instance int32  GetLocalVal() cil managed
+  {
+    // Code size       12 (0xc)
+    .maxstack  1
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  ldfld      int32 valuetype HorribleCase`1<!Z>::localVal
+    IL_0007:  stloc.0
+    IL_0008:  br.s       IL_000a
+
+    IL_000a:  ldloc.0
+    IL_000b:  ret
+  } // end of method HorribleCase`1::GetLocalVal
+
+  .method public hidebysig newslot virtual final 
+          instance void  SetLocalVal(int32 val) cil managed
+  {
+    // Code size       9 (0x9)
+    .maxstack  8
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  ldarg.1
+    IL_0003:  stfld      int32 valuetype HorribleCase`1<!Z>::localVal
+    IL_0008:  ret
+  } // end of method HorribleCase`1::SetLocalVal
+
+  .method private hidebysig newslot virtual final 
+          instance int32  'IHorrible<System.Collections.Generic.IList<Z>>.Horrible'() cil managed
+  {
+    .override  method instance int32 class IHorrible`1<class [mscorlib]System.Collections.Generic.IList`1<!Z>>::Horrible()
+    // Code size       23 (0x17)
+    .maxstack  3
+    .locals init (int32 V_0,
+             int32 V_1)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  ldarg.0
+    IL_0003:  ldfld      int32 valuetype HorribleCase`1<!Z>::localVal
+    IL_0008:  ldc.i4.1
+    IL_0009:  add
+    IL_000a:  stloc.0
+    IL_000b:  ldloc.0
+    IL_000c:  stfld      int32 valuetype HorribleCase`1<!Z>::localVal
+    IL_0011:  ldloc.0
+    IL_0012:  stloc.1
+    IL_0013:  br.s       IL_0015
+
+    IL_0015:  ldloc.1
+    IL_0016:  ret
+  } // end of method HorribleCase`1::'IHorrible<System.Collections.Generic.IList<Z>>.Horrible'
+} // end of class HorribleCase`1
+
+.class private auto ansi beforefieldinit HorribleTest
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig static int32  Horror<(class IHorrible`1<!!U>) T,U>(!!T t) cil managed
+  {
+    // Code size       33 (0x21)
+    .maxstack  2
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldarga.s   t
+    IL_0003:  constrained. !!T
+    IL_0009:  callvirt   instance int32 class IHorrible`1<!!U>::Horrible()
+    IL_000e:  ldarga.s   t
+    IL_0010:  constrained. !!T
+    IL_0016:  callvirt   instance int32 class IHorrible`1<!!U>::Horrible()
+    IL_001b:  add
+    IL_001c:  stloc.0
+    IL_001d:  br.s       IL_001f
+
+    IL_001f:  ldloc.0
+    IL_0020:  ret
+  } // end of method HorribleTest::Horror
+
+  .method public hidebysig static void  RunTest() cil managed
+  {
+    // Code size       58 (0x3a)
+    .maxstack  2
+    .locals init (valuetype HorribleCase`1<object> V_0)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_0
+    IL_0003:  initobj    valuetype HorribleCase`1<object>
+    IL_0009:  ldloc.0
+    IL_000a:  call       int32 HorribleTest::Horror<valuetype HorribleCase`1<object>,class [mscorlib]System.Collections.Generic.IEnumerable`1<object>>(!!0)
+    IL_000f:  ldc.i4.3
+    IL_0010:  ceq
+    IL_0012:  ldstr      "Fail"
+    IL_0017:  call       void Test::Assert(bool,
+                                           string)
+    IL_001c:  nop
+    IL_001d:  ldloca.s   V_0
+    IL_001f:  initobj    valuetype HorribleCase`1<object>
+    IL_0025:  ldloc.0
+    IL_0026:  call       int32 HorribleTest::Horror<valuetype HorribleCase`1<object>,class [mscorlib]System.Collections.Generic.IList`1<object>>(!!0)
+    IL_002b:  ldc.i4.0
+    IL_002c:  ceq
+    IL_002e:  ldstr      "Fail"
+    IL_0033:  call       void Test::Assert(bool,
+                                           string)
+    IL_0038:  nop
+    IL_0039:  ret
+  } // end of method HorribleTest::RunTest
+
+  .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 HorribleTest::.ctor
+
+} // end of class HorribleTest
+
+.class private auto ansi beforefieldinit SimpleConstraintTest
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig static int32  CallFoo_WithConstraints<(IFoo) T>(!!T& foo,
+                                                                           int32 val) cil managed
+  {
+    // Code size       19 (0x13)
+    .maxstack  2
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  ldarg.1
+    IL_0003:  constrained. !!T
+    IL_0009:  callvirt   instance int32 IFoo::Foo(int32)
+    IL_000e:  stloc.0
+    IL_000f:  br.s       IL_0011
+
+    IL_0011:  ldloc.0
+    IL_0012:  ret
+  } // end of method SimpleConstraintTest::CallFoo_WithConstraints
+
+  .method public hidebysig static void  RunTest() cil managed
+  {
+    // Code size       75 (0x4b)
+    .maxstack  2
+    .locals init (valuetype FooValue V_0)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_0
+    IL_0003:  initobj    FooValue
+    IL_0009:  ldloca.s   V_0
+    IL_000b:  ldc.i4.s   10
+    IL_000d:  stfld      int32 FooValue::val
+    IL_0012:  ldstr      "Calling CallFoo_WithConstraints on FooValue - expe"
+    + "cting IFoo::Foo"
+    IL_0017:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_001c:  nop
+    IL_001d:  ldloca.s   V_0
+    IL_001f:  ldc.i4.s   10
+    IL_0021:  call       int32 SimpleConstraintTest::CallFoo_WithConstraints<valuetype FooValue>(!!0&,
+                                                                                                 int32)
+    IL_0026:  ldc.i4.s   20
+    IL_0028:  ceq
+    IL_002a:  ldstr      "Calling CallFoo_WithConstraints on FooValue"
+    IL_002f:  call       void Test::Assert(bool,
+                                           string)
+    IL_0034:  nop
+    IL_0035:  ldloc.0
+    IL_0036:  ldfld      int32 FooValue::val
+    IL_003b:  ldc.i4.s   10
+    IL_003d:  ceq
+    IL_003f:  ldstr      "Expecting boxing on CallFoo_WithConstraints"
+    IL_0044:  call       void Test::Assert(bool,
+                                           string)
+    IL_0049:  nop
+    IL_004a:  ret
+  } // end of method SimpleConstraintTest::RunTest
+
+  .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 SimpleConstraintTest::.ctor
+
+} // end of class SimpleConstraintTest
+
+.class private auto ansi beforefieldinit Program
+       extends [mscorlib]System.Object
+{
+  .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 HorribleTest::RunTest()
+    IL_0006:  nop
+    IL_0007:  call       void SimpleConstraintTest::RunTest()
+    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 
+          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 Program::.ctor
+
+} // end of class Program
+
+.class private auto ansi beforefieldinit Test
+       extends [mscorlib]System.Object
+{
+  .field private static bool Pass
+  .method public hidebysig static int32  Ret() cil managed
+  {
+    // Code size       19 (0x13)
+    .maxstack  1
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldsfld     bool Test::Pass
+    IL_0006:  brtrue.s   IL_000c
+
+    IL_0008:  ldc.i4.s   101
+    IL_000a:  br.s       IL_000e
+
+    IL_000c:  ldc.i4.s   100
+    IL_000e:  stloc.0
+    IL_000f:  br.s       IL_0011
+
+    IL_0011:  ldloc.0
+    IL_0012:  ret
+  } // end of method Test::Ret
+
+  .method public hidebysig static void  Assert(bool cond,
+                                               string msg) cil managed
+  {
+    // Code size       47 (0x2f)
+    .maxstack  2
+    .locals init (bool V_0)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  stloc.0
+    IL_0003:  ldloc.0
+    IL_0004:  brfalse.s  IL_0015
+
+    IL_0006:  nop
+    IL_0007:  ldstr      "PASS"
+    IL_000c:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0011:  nop
+    IL_0012:  nop
+    IL_0013:  br.s       IL_002e
+
+    IL_0015:  nop
+    IL_0016:  ldstr      "FAIL: "
+    IL_001b:  ldarg.1
+    IL_001c:  call       string [mscorlib]System.String::Concat(string,
+                                                                string)
+    IL_0021:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0026:  nop
+    IL_0027:  ldc.i4.0
+    IL_0028:  stsfld     bool Test::Pass
+    IL_002d:  nop
+    IL_002e:  ret
+  } // end of method Test::Assert
+
+  .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 Test::.ctor
+
+  .method private hidebysig specialname rtspecialname static 
+          void  .cctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldc.i4.1
+    IL_0001:  stsfld     bool Test::Pass
+    IL_0006:  ret
+  } // end of method Test::.cctor
+
+} // end of class Test
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file constrainedcall.res
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.ilproj b/tests/src/Loader/classloader/DefaultInterfaceMethods/constrainedcall/constrainedcall.ilproj
new file mode 100644 (file)
index 0000000..e170b2b
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <AssemblyName>constrainedcall</AssemblyName>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+    <OutputType>Exe</OutputType>
+    <CLRTestKind>BuildAndRun</CLRTestKind>
+    <CLRTestPriority>0</CLRTestPriority>
+    <!-- Use ILAsm that we just built for the new fixes required in default interface methods -->
+    <UseCustomILAsm>True</UseCustomILAsm>    
+  </PropertyGroup>
+
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Include="constrainedcall.il" />
+  </ItemGroup>
+
+
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/genericmethods/genericmethods.cs b/tests/src/Loader/classloader/DefaultInterfaceMethods/genericmethods/genericmethods.cs
new file mode 100644 (file)
index 0000000..ca4936b
--- /dev/null
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+interface IFoo
+{
+    Type Foo<T>();
+}
+
+interface IBar<T>
+{
+    Type Bar1<P>();
+    Type Bar2<K>();
+    void Bar3<P, K>(out Type t, out Type u);
+}
+
+class FooBar<V> : IFoo, IBar<V>
+{
+    public Type Foo<T>()
+    {
+        Console.WriteLine("At IFoo<T>::Foo<T>: TypeOf(T) = {0}", typeof(T));
+        return typeof(T);
+    }
+
+    public Type Bar1<P>()
+    {
+        Console.WriteLine("At IBar<T>::Foo<P>: TypeOf(P) = {0}", typeof(P));
+        return typeof(P);
+    }
+
+    public Type Bar2<K>()
+    {
+        Console.WriteLine("At IBar<T>::Bar2<K>: TypeOf(K) = {0}", typeof(K));
+        return typeof(K);
+    }
+
+    public void Bar3<P, K>(out Type t, out Type u)
+    {
+        Console.WriteLine("At IBar<T>::Bar3<P, K>: TypeOf(P) = {0}, TypeOf(K) = {1}", typeof(P), typeof(K));
+        t = typeof(P);
+        u = typeof(K);
+    }
+}
+
+
+class Program
+{
+    static int Main(string[] args)
+    {
+        FooBar<object> fooBar = new FooBar<object>();
+        IFoo foo = (IFoo) fooBar;
+        IBar<object> bar = (IBar<object>) fooBar;
+
+        Console.WriteLine("Calling IFoo.Foo<String> on FooBar<Object> - expecting IFoo::Foo<string>() returning typeof(string)");
+        Test.Assert(foo.Foo<string>() == typeof(string), "Calling IFoo.Foo<String> on FooBar<Object>");
+
+        Console.WriteLine("Calling IBar.Bar1<String> on FooBar<object> - expecting bar.Bar1<string>() returning typeof(string)");
+        Test.Assert(bar.Bar1<string>() == typeof(string), "Calling IBar.Bar1<String> on FooBar<object>");
+
+        Console.WriteLine("Calling IBar.Bar2<String[]> on FooBar<object> - expecting bar.Bar2<string[]>() returning typeof(string[])");
+        Test.Assert(bar.Bar2<string[]>() == typeof(string[]), "Calling IBar.Bar2<String[]> on FooBar<object>");
+
+        Type p, k;
+        Console.WriteLine("Calling IBar.Bar3<String, String[]> - expecting bar.Bar3<string>() returning typeof(string), typeof(string[])");
+        bar.Bar3<string, string[]>(out p, out k);
+        Test.Assert(p == typeof(string) && k == typeof(string[]), "Calling IBar.Bar3<String, String[]>");
+
+        return Test.Ret();
+    }
+}
+
+class Test
+{
+    private static bool Pass = true;
+
+    public static int Ret()
+    {
+        return Pass ? 100 : 101;
+    }
+
+    public static void Assert(bool cond, string msg)
+    {
+        if (cond)
+        {
+            Console.WriteLine("PASS");
+        }
+        else
+        {
+            Console.WriteLine("FAIL: " + msg);
+            Pass = false;
+        }
+    }
+}
+
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/genericmethods/genericmethods.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/genericmethods/genericmethods.il
new file mode 100644 (file)
index 0000000..3a3204d
--- /dev/null
@@ -0,0 +1,357 @@
+
+//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.6.1055.0
+//  Copyright (c) Microsoft Corporation.  All rights reserved.
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
+  .ver 4:0:0:0
+}
+.assembly genericmethods
+{
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
+                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
+
+  // --- The following custom attribute is added automatically, do not uncomment -------
+  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 
+
+  .hash algorithm 0x00008004
+  .ver 0:0:0:0
+}
+.module genericmethods.exe
+// MVID: {62CAFB9A-4CDB-4A62-8A4F-DC7648609070}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003       // WINDOWS_CUI
+.corflags 0x00000001    //  ILONLY
+// Image base: 0x01790000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class interface private abstract auto ansi IFoo
+{
+  .method public hidebysig newslot virtual 
+          instance class [mscorlib]System.Type 
+          Foo<T>() cil managed
+  {
+    // Code size       37 (0x25)
+    .maxstack  2
+    .locals init (class [mscorlib]System.Type V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IFoo<T>::Foo<T>: TypeOf(T) = {0}"
+    IL_0006:  ldtoken    !!T
+    IL_000b:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_0010:  call       void [mscorlib]System.Console::WriteLine(string,
+                                                                  object)
+    IL_0015:  nop
+    IL_0016:  ldtoken    !!T
+    IL_001b:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_0020:  stloc.0
+    IL_0021:  br.s       IL_0023
+
+    IL_0023:  ldloc.0
+    IL_0024:  ret
+  } // end of method IFoo::Foo
+
+} // end of class IFoo
+
+.class interface private abstract auto ansi IBar`1<T>
+{
+  .method public hidebysig newslot virtual 
+          instance class [mscorlib]System.Type 
+          Bar1<P>() cil managed
+  {
+    // Code size       37 (0x25)
+    .maxstack  2
+    .locals init (class [mscorlib]System.Type V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IBar<T>::Foo<P>: TypeOf(P) = {0}"
+    IL_0006:  ldtoken    !!P
+    IL_000b:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_0010:  call       void [mscorlib]System.Console::WriteLine(string,
+                                                                  object)
+    IL_0015:  nop
+    IL_0016:  ldtoken    !!P
+    IL_001b:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_0020:  stloc.0
+    IL_0021:  br.s       IL_0023
+
+    IL_0023:  ldloc.0
+    IL_0024:  ret    
+  } // end of method IBar`1::Bar1
+
+  .method public hidebysig newslot virtual 
+          instance class [mscorlib]System.Type 
+          Bar2<K>() cil managed
+  {
+    // Code size       37 (0x25)
+    .maxstack  2
+    .locals init (class [mscorlib]System.Type V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IBar<T>::Bar2<K>: TypeOf(K) = {0}"
+    IL_0006:  ldtoken    !!K
+    IL_000b:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_0010:  call       void [mscorlib]System.Console::WriteLine(string,
+                                                                  object)
+    IL_0015:  nop
+    IL_0016:  ldtoken    !!K
+    IL_001b:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_0020:  stloc.0
+    IL_0021:  br.s       IL_0023
+
+    IL_0023:  ldloc.0
+    IL_0024:  ret  
+  } // end of method IBar`1::Bar2
+
+  .method public hidebysig newslot virtual 
+          instance void  Bar3<P,K>([out] class [mscorlib]System.Type& t,
+                                   [out] class [mscorlib]System.Type& u) cil managed
+  {
+    // Code size       57 (0x39)
+    .maxstack  8
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IBar<T>::Bar3<P, K>: TypeOf(P) = {0}, TypeOf(K)"
+    + " = {1}"
+    IL_0006:  ldtoken    !!P
+    IL_000b:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_0010:  ldtoken    !!K
+    IL_0015:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_001a:  call       void [mscorlib]System.Console::WriteLine(string,
+                                                                  object,
+                                                                  object)
+    IL_001f:  nop
+    IL_0020:  ldarg.1
+    IL_0021:  ldtoken    !!P
+    IL_0026:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_002b:  stind.ref
+    IL_002c:  ldarg.2
+    IL_002d:  ldtoken    !!K
+    IL_0032:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_0037:  stind.ref
+    IL_0038:  ret    
+  } // end of method IBar`1::Bar3
+
+} // end of class IBar`1
+
+.class private auto ansi beforefieldinit FooBar`1<V>
+       extends [mscorlib]System.Object
+       implements IFoo,
+                  class IBar`1<!V>
+{
+  .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 FooBar`1::.ctor
+
+} // end of class FooBar`1
+
+.class private auto ansi beforefieldinit Program
+       extends [mscorlib]System.Object
+{
+  .method private hidebysig static int32 
+          Main(string[] args) cil managed
+  {
+    .entrypoint
+    // Code size       223 (0xdf)
+    .maxstack  3
+    .locals init (class FooBar`1<object> V_0,
+             class IFoo V_1,
+             class IBar`1<object> V_2,
+             class [mscorlib]System.Type V_3,
+             class [mscorlib]System.Type V_4,
+             int32 V_5)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void class FooBar`1<object>::.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<String> on FooBar<Object> - expec"
+    + "ting IFoo::Foo<string>() returning typeof(string)"
+    IL_0010:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0015:  nop
+    IL_0016:  ldloc.1
+    IL_0017:  callvirt   instance class [mscorlib]System.Type IFoo::Foo<string>()
+    IL_001c:  ldtoken    [mscorlib]System.String
+    IL_0021:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_0026:  call       bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type,
+                                                                 class [mscorlib]System.Type)
+    IL_002b:  ldstr      "Calling IFoo.Foo<String> on FooBar<Object>"
+    IL_0030:  call       void Test::Assert(bool,
+                                           string)
+    IL_0035:  nop
+    IL_0036:  ldstr      "Calling IBar.Bar1<String> on FooBar<object> - expe"
+    + "cting bar.Bar1<string>() returning typeof(string)"
+    IL_003b:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0040:  nop
+    IL_0041:  ldloc.2
+    IL_0042:  callvirt   instance class [mscorlib]System.Type class IBar`1<object>::Bar1<string>()
+    IL_0047:  ldtoken    [mscorlib]System.String
+    IL_004c:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_0051:  call       bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type,
+                                                                 class [mscorlib]System.Type)
+    IL_0056:  ldstr      "Calling IBar.Bar1<String> on FooBar<object>"
+    IL_005b:  call       void Test::Assert(bool,
+                                           string)
+    IL_0060:  nop
+    IL_0061:  ldstr      "Calling IBar.Bar2<String[]> on FooBar<object> - ex"
+    + "pecting bar.Bar2<string[]>() returning typeof(string[])"
+    IL_0066:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_006b:  nop
+    IL_006c:  ldloc.2
+    IL_006d:  callvirt   instance class [mscorlib]System.Type class IBar`1<object>::Bar2<string[]>()
+    IL_0072:  ldtoken    string[]
+    IL_0077:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_007c:  call       bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type,
+                                                                 class [mscorlib]System.Type)
+    IL_0081:  ldstr      "Calling IBar.Bar2<String[]> on FooBar<object>"
+    IL_0086:  call       void Test::Assert(bool,
+                                           string)
+    IL_008b:  nop
+    IL_008c:  ldstr      "Calling IBar.Bar3<String, String[]> - expecting ba"
+    + "r.Bar3<string>() returning typeof(string), typeof(string[])"
+    IL_0091:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0096:  nop
+    IL_0097:  ldloc.2
+    IL_0098:  ldloca.s   V_3
+    IL_009a:  ldloca.s   V_4
+    IL_009c:  callvirt   instance void class IBar`1<object>::Bar3<string,string[]>(class [mscorlib]System.Type&,
+                                                                                   class [mscorlib]System.Type&)
+    IL_00a1:  nop
+    IL_00a2:  ldloc.3
+    IL_00a3:  ldtoken    [mscorlib]System.String
+    IL_00a8:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_00ad:  call       bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type,
+                                                                 class [mscorlib]System.Type)
+    IL_00b2:  brfalse.s  IL_00c7
+
+    IL_00b4:  ldloc.s    V_4
+    IL_00b6:  ldtoken    string[]
+    IL_00bb:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_00c0:  call       bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type,
+                                                                 class [mscorlib]System.Type)
+    IL_00c5:  br.s       IL_00c8
+
+    IL_00c7:  ldc.i4.0
+    IL_00c8:  ldstr      "Calling IBar.Bar3<String, String[]>"
+    IL_00cd:  call       void Test::Assert(bool,
+                                           string)
+    IL_00d2:  nop
+    IL_00d3:  call       int32 Test::Ret()
+    IL_00d8:  stloc.s    V_5
+    IL_00da:  br.s       IL_00dc
+
+    IL_00dc:  ldloc.s    V_5
+    IL_00de:  ret
+  } // end of method Program::Main
+
+  .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 Program::.ctor
+
+} // end of class Program
+
+.class private auto ansi beforefieldinit Test
+       extends [mscorlib]System.Object
+{
+  .field private static bool Pass
+  .method public hidebysig static int32  Ret() cil managed
+  {
+    // Code size       19 (0x13)
+    .maxstack  1
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldsfld     bool Test::Pass
+    IL_0006:  brtrue.s   IL_000c
+
+    IL_0008:  ldc.i4.s   101
+    IL_000a:  br.s       IL_000e
+
+    IL_000c:  ldc.i4.s   100
+    IL_000e:  stloc.0
+    IL_000f:  br.s       IL_0011
+
+    IL_0011:  ldloc.0
+    IL_0012:  ret
+  } // end of method Test::Ret
+
+  .method public hidebysig static void  Assert(bool cond,
+                                               string msg) cil managed
+  {
+    // Code size       47 (0x2f)
+    .maxstack  2
+    .locals init (bool V_0)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  stloc.0
+    IL_0003:  ldloc.0
+    IL_0004:  brfalse.s  IL_0015
+
+    IL_0006:  nop
+    IL_0007:  ldstr      "PASS"
+    IL_000c:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0011:  nop
+    IL_0012:  nop
+    IL_0013:  br.s       IL_002e
+
+    IL_0015:  nop
+    IL_0016:  ldstr      "FAIL: "
+    IL_001b:  ldarg.1
+    IL_001c:  call       string [mscorlib]System.String::Concat(string,
+                                                                string)
+    IL_0021:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0026:  nop
+    IL_0027:  ldc.i4.0
+    IL_0028:  stsfld     bool Test::Pass
+    IL_002d:  nop
+    IL_002e:  ret
+  } // end of method Test::Assert
+
+  .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 Test::.ctor
+
+  .method private hidebysig specialname rtspecialname static 
+          void  .cctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldc.i4.1
+    IL_0001:  stsfld     bool Test::Pass
+    IL_0006:  ret
+  } // end of method Test::.cctor
+
+} // end of class Test
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file genericmethods.res
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/genericmethods/genericmethods.ilproj b/tests/src/Loader/classloader/DefaultInterfaceMethods/genericmethods/genericmethods.ilproj
new file mode 100644 (file)
index 0000000..909dbe9
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <AssemblyName>genericmethods</AssemblyName>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+    <OutputType>Exe</OutputType>
+    <CLRTestKind>BuildAndRun</CLRTestKind>
+    <CLRTestPriority>0</CLRTestPriority>
+    <!-- Use ILAsm that we just built for the new fixes required in default interface methods -->
+    <UseCustomILAsm>True</UseCustomILAsm>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Include="genericmethods.il" />
+  </ItemGroup>
+
+
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.cs b/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.cs
new file mode 100755 (executable)
index 0000000..8f4b5d1
--- /dev/null
@@ -0,0 +1,83 @@
+using System;
+
+interface IFoo
+{
+    int Foo(int a);
+}
+
+interface IBar
+{
+    int Bar(int b);
+}
+
+interface IFooBar : IFoo, IBar
+{
+    int Foo(int a);
+}
+
+class Temp : IFoo
+{
+    int IFoo.Foo(int a)
+    {
+        Console.WriteLine("At IFooBar::IFoo.Foo explicit methodimpl");
+        return a + 30;
+    }
+}
+
+class FooBar : IFooBar
+{
+    public int Foo(int a)
+    {
+        Console.WriteLine("At IFoo::Foo");
+        return a+10;            
+    }
+
+    public int Bar(int b)
+    {
+        Console.WriteLine("At IBar::Bar");
+        return b+20;
+    }
+}
+
+class Program
+{
+    public static int Main()
+    {
+        FooBar fooBar = new FooBar();
+        IFoo foo = (IFoo) fooBar;
+        IBar bar = (IBar) fooBar;
+
+        Console.WriteLine("Calling IFoo.Foo on FooBar - expecting IFooBar::IFoo.Bar");
+        Test.Assert(foo.Foo(10) == 40, "Calling IFoo.Foo on FooBar");
+
+        Console.WriteLine("Calling IBar.Bar on FooBar - expecting IBar::Bar");
+        Test.Assert(bar.Bar(10) == 30, "Calling IBar.Bar on FooBar");
+
+        return Test.Ret();
+    }
+}
+
+class Test
+{
+    private static bool Pass = true;
+
+    public static int Ret()
+    {
+        return Pass? 100 : 101;
+    }
+
+    public static void Assert(bool cond, string msg)
+    {
+        if (cond)
+        {
+            Console.WriteLine("PASS");
+        }
+        else
+        {
+            Console.WriteLine("FAIL: " + msg);
+            Pass = false;
+        }
+    }
+}                    
+
+
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.il
new file mode 100644 (file)
index 0000000..6ab45f0
--- /dev/null
@@ -0,0 +1,279 @@
+
+//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.6.1055.0
+//  Copyright (c) Microsoft Corporation.  All rights reserved.
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
+  .ver 4:0:0:0
+}
+.assembly methodimpl
+{
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
+                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
+
+  // --- The following custom attribute is added automatically, do not uncomment -------
+  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 
+
+  .hash algorithm 0x00008004
+  .ver 0:0:0:0
+}
+.module methodimpl.exe
+// MVID: {F249A85F-3FD2-488F-B084-97B542AD68D6}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003       // WINDOWS_CUI
+.corflags 0x00000001    //  ILONLY
+// Image base: 0x02FD0000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class interface private abstract auto ansi IFoo
+{
+  .method public hidebysig newslot virtual 
+          instance int32  Foo(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_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  ldarg.1
+    IL_000d:  ldc.i4.s   10
+    IL_000f:  add
+    IL_0010:  stloc.0
+    IL_0011:  br.s       IL_0013
+
+    IL_0013:  ldloc.0
+    IL_0014:  ret
+  } // end of method IFoo::Foo
+
+} // end of class IFoo
+
+.class interface private abstract auto ansi IBar
+{
+  .method public hidebysig newslot virtual 
+          instance int32  Bar(int32 b) cil managed
+  {
+    // Code size       21 (0x15)
+    .maxstack  2
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IBar::Bar"
+    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::Bar
+
+} // end of class IBar
+
+.class interface private abstract auto ansi IFooBar
+       implements IFoo,
+                  IBar
+{
+  .method private hidebysig newslot virtual final 
+          instance int32  IFoo.Foo(int32 a) cil managed
+  {
+    .override IFoo::Foo
+    // Code size       21 (0x15)
+    .maxstack  2
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IFooBar::IFoo.Foo explicit methodimpl"
+    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 Temp::IFoo.Foo
+
+} // end of class IFooBar
+
+.class private auto ansi beforefieldinit FooBar
+       extends [mscorlib]System.Object
+       implements IFooBar,
+                  IFoo,
+                  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 [mscorlib]System.Object::.ctor()
+    IL_0006:  nop
+    IL_0007:  ret
+  } // end of method FooBar::.ctor
+
+} // end of class FooBar
+
+.class private auto ansi beforefieldinit Program
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig static int32  Main() cil managed
+  {
+    .entrypoint
+    // Code size       89 (0x59)
+    .maxstack  2
+    .locals init (class FooBar V_0,
+             class IFoo V_1,
+             class IBar V_2,
+             int32 V_3)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void FooBar::.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_0020:  ceq
+    IL_0022:  ldstr      "Calling IFoo.Foo on FooBar"
+    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
+
+  .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 Program::.ctor
+
+} // end of class Program
+
+.class private auto ansi beforefieldinit Test
+       extends [mscorlib]System.Object
+{
+  .field private static bool Pass
+  .method public hidebysig static int32  Ret() cil managed
+  {
+    // Code size       19 (0x13)
+    .maxstack  1
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldsfld     bool Test::Pass
+    IL_0006:  brtrue.s   IL_000c
+
+    IL_0008:  ldc.i4.s   101
+    IL_000a:  br.s       IL_000e
+
+    IL_000c:  ldc.i4.s   100
+    IL_000e:  stloc.0
+    IL_000f:  br.s       IL_0011
+
+    IL_0011:  ldloc.0
+    IL_0012:  ret
+  } // end of method Test::Ret
+
+  .method public hidebysig static void  Assert(bool cond,
+                                               string msg) cil managed
+  {
+    // Code size       47 (0x2f)
+    .maxstack  2
+    .locals init (bool V_0)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  stloc.0
+    IL_0003:  ldloc.0
+    IL_0004:  brfalse.s  IL_0015
+
+    IL_0006:  nop
+    IL_0007:  ldstr      "PASS"
+    IL_000c:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0011:  nop
+    IL_0012:  nop
+    IL_0013:  br.s       IL_002e
+
+    IL_0015:  nop
+    IL_0016:  ldstr      "FAIL: "
+    IL_001b:  ldarg.1
+    IL_001c:  call       string [mscorlib]System.String::Concat(string,
+                                                                string)
+    IL_0021:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0026:  nop
+    IL_0027:  ldc.i4.0
+    IL_0028:  stsfld     bool Test::Pass
+    IL_002d:  nop
+    IL_002e:  ret
+  } // end of method Test::Assert
+
+  .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 Test::.ctor
+
+  .method private hidebysig specialname rtspecialname static 
+          void  .cctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldc.i4.1
+    IL_0001:  stsfld     bool Test::Pass
+    IL_0006:  ret
+  } // end of method Test::.cctor
+
+} // end of class Test
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file methodimpl.res
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.ilproj b/tests/src/Loader/classloader/DefaultInterfaceMethods/methodimpl/methodimpl.ilproj
new file mode 100644 (file)
index 0000000..16a1cad
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <AssemblyName>methodimpl</AssemblyName>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+    <OutputType>Exe</OutputType>
+    <CLRTestKind>BuildAndRun</CLRTestKind>
+    <CLRTestPriority>0</CLRTestPriority>
+    <!-- Use ILAsm that we just built for the new fixes required in default interface methods -->
+    <UseCustomILAsm>True</UseCustomILAsm>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Include="methodimpl.il" />
+  </ItemGroup>
+
+
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/sharedgenerics/sharedgenerics.cs b/tests/src/Loader/classloader/DefaultInterfaceMethods/sharedgenerics/sharedgenerics.cs
new file mode 100644 (file)
index 0000000..93b214d
--- /dev/null
@@ -0,0 +1,68 @@
+using System;
+
+interface IFoo<T>
+{
+    Type Foo(T a);
+}
+
+interface IBar<in T>
+{
+    Type Bar(T b);
+}
+
+class FooBar<T, U> : IFoo<T>, IBar<U>
+{
+    public Type Foo(T a)
+    {
+        Console.WriteLine("At IFoo.Foo:Arg={0}, TypeOf(T)={1}", a.ToString(), typeof(T));
+        return typeof(T);            
+    }
+
+    public Type Bar(U b)
+    {
+        Console.WriteLine("At IBar.Bar:Arg={0}, TypeOf(T)={1}", b.ToString(), typeof(U));
+        return typeof(U);
+    }
+}
+
+class Program
+{
+    public static int Main()
+    {
+        FooBar<string, object> fooBar = new FooBar<string, object>();
+        IFoo<string> foo = (IFoo<string>) fooBar;
+        IBar<string[]> bar = (IBar<string[]>) fooBar;
+
+        Console.WriteLine("Calling IFoo<string>.Foo on FooBar<string, object> - expecting default method IFoo<string>.Foo");
+        Test.Assert(foo.Foo("ABC") == typeof(string), "Calling IFoo<string>.Foo on FooBar<string, object>");
+
+        Console.WriteLine("Calling IBar<string[]>.Foo on FooBar<string, object> - expecting default method IBar<object>.Foo");
+        Test.Assert(bar.Bar(new string[] { "ABC" }) == typeof(object), "Calling IBar<object>.Bar on FooBar<string, object>");
+
+        return Test.Ret();
+    }
+}
+
+class Test
+{
+    private static bool Pass = true;
+
+    public static int Ret()
+    {
+        return Pass? 100 : 101;
+    }
+
+    public static void Assert(bool cond, string msg)
+    {
+        if (cond)
+        {
+            Console.WriteLine("PASS");
+        }
+        else
+        {
+            Console.WriteLine("FAIL: " + msg);
+            Pass = false;
+        }
+    }
+}                    
+
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/sharedgenerics/sharedgenerics.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/sharedgenerics/sharedgenerics.il
new file mode 100644 (file)
index 0000000..8e9eaec
--- /dev/null
@@ -0,0 +1,275 @@
+
+//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.6.1055.0
+//  Copyright (c) Microsoft Corporation.  All rights reserved.
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
+  .ver 4:0:0:0
+}
+.assembly sharedgenerics
+{
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
+                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
+
+  // --- The following custom attribute is added automatically, do not uncomment -------
+  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 
+
+  .hash algorithm 0x00008004
+  .ver 0:0:0:0
+}
+.module sharedgenerics.exe
+// MVID: {0DEEC74C-30FE-495C-9653-12BE5220327A}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003       // WINDOWS_CUI
+.corflags 0x00000001    //  ILONLY
+// Image base: 0x02D40000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class interface private abstract auto ansi IFoo`1<T>
+{
+  .method public hidebysig newslot virtual 
+          instance class [mscorlib]System.Type 
+          Foo(!T a) cil managed
+  {
+    // Code size       50 (0x32)
+    .maxstack  3
+    .locals init (class [mscorlib]System.Type V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IFoo.Foo:Arg={0}, TypeOf(T)={1}"
+    IL_0006:  ldarga.s   a
+    IL_0008:  constrained. !T
+    IL_000e:  callvirt   instance string [mscorlib]System.Object::ToString()
+    IL_0013:  ldtoken    !T
+    IL_0018:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_001d:  call       void [mscorlib]System.Console::WriteLine(string,
+                                                                  object,
+                                                                  object)
+    IL_0022:  nop
+    IL_0023:  ldtoken    !T
+    IL_0028:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_002d:  stloc.0
+    IL_002e:  br.s       IL_0030
+
+    IL_0030:  ldloc.0
+    IL_0031:  ret
+  } // end of method IFoo`1::Foo
+
+} // end of class IFoo`1
+
+.class interface private abstract auto ansi IBar`1<- T>
+{
+  .method public hidebysig newslot virtual 
+          instance class [mscorlib]System.Type 
+          Bar(!T b) cil managed
+  {
+    // Code size       50 (0x32)
+    .maxstack  3
+    .locals init (class [mscorlib]System.Type V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IBar.Bar:Arg={0}, TypeOf(T)={1}"
+    IL_0006:  ldarga.s   b
+    IL_0008:  constrained. !T
+    IL_000e:  callvirt   instance string [mscorlib]System.Object::ToString()
+    IL_0013:  ldtoken    !T
+    IL_0018:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_001d:  call       void [mscorlib]System.Console::WriteLine(string,
+                                                                  object,
+                                                                  object)
+    IL_0022:  nop
+    IL_0023:  ldtoken    !T
+    IL_0028:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_002d:  stloc.0
+    IL_002e:  br.s       IL_0030
+
+    IL_0030:  ldloc.0
+    IL_0031:  ret
+  } // end of method IBar`1::Bar
+
+} // end of class IBar`1
+
+.class private auto ansi beforefieldinit FooBar`2<T,U>
+       extends [mscorlib]System.Object
+       implements class IFoo`1<!T>,
+                  class IBar`1<!U>
+{
+  .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 FooBar`2::.ctor
+
+} // end of class FooBar`2
+
+.class private auto ansi beforefieldinit Program
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig static int32  Main() cil managed
+  {
+    .entrypoint
+    // Code size       126 (0x7e)
+    .maxstack  5
+    .locals init (class FooBar`2<string,object> V_0,
+             class IFoo`1<string> V_1,
+             class IBar`1<string[]> V_2,
+             int32 V_3)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void class FooBar`2<string,object>::.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<string>.Foo on FooBar<string, object>"
+    + " - expecting default method IFoo<string>.Foo"
+    IL_0010:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0015:  nop
+    IL_0016:  ldloc.1
+    IL_0017:  ldstr      "ABC"
+    IL_001c:  callvirt   instance class [mscorlib]System.Type class IFoo`1<string>::Foo(!0)
+    IL_0021:  ldtoken    [mscorlib]System.String
+    IL_0026:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_002b:  call       bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type,
+                                                                 class [mscorlib]System.Type)
+    IL_0030:  ldstr      "Calling IFoo<string>.Foo on FooBar<string, object>"
+    IL_0035:  call       void Test::Assert(bool,
+                                           string)
+    IL_003a:  nop
+    IL_003b:  ldstr      "Calling IBar<string[]>.Foo on FooBar<string, objec"
+    + "t> - expecting default method IBar<object>.Foo"
+    IL_0040:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0045:  nop
+    IL_0046:  ldloc.2
+    IL_0047:  ldc.i4.1
+    IL_0048:  newarr     [mscorlib]System.String
+    IL_004d:  dup
+    IL_004e:  ldc.i4.0
+    IL_004f:  ldstr      "ABC"
+    IL_0054:  stelem.ref
+    IL_0055:  callvirt   instance class [mscorlib]System.Type class IBar`1<string[]>::Bar(!0)
+    IL_005a:  ldtoken    [mscorlib]System.Object
+    IL_005f:  call       class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
+    IL_0064:  call       bool [mscorlib]System.Type::op_Equality(class [mscorlib]System.Type,
+                                                                 class [mscorlib]System.Type)
+    IL_0069:  ldstr      "Calling IBar<object>.Bar on FooBar<string, object>"
+    IL_006e:  call       void Test::Assert(bool,
+                                           string)
+    IL_0073:  nop
+    IL_0074:  call       int32 Test::Ret()
+    IL_0079:  stloc.3
+    IL_007a:  br.s       IL_007c
+
+    IL_007c:  ldloc.3
+    IL_007d:  ret
+  } // end of method Program::Main
+
+  .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 Program::.ctor
+
+} // end of class Program
+
+.class private auto ansi beforefieldinit Test
+       extends [mscorlib]System.Object
+{
+  .field private static bool Pass
+  .method public hidebysig static int32  Ret() cil managed
+  {
+    // Code size       19 (0x13)
+    .maxstack  1
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldsfld     bool Test::Pass
+    IL_0006:  brtrue.s   IL_000c
+
+    IL_0008:  ldc.i4.s   101
+    IL_000a:  br.s       IL_000e
+
+    IL_000c:  ldc.i4.s   100
+    IL_000e:  stloc.0
+    IL_000f:  br.s       IL_0011
+
+    IL_0011:  ldloc.0
+    IL_0012:  ret
+  } // end of method Test::Ret
+
+  .method public hidebysig static void  Assert(bool cond,
+                                               string msg) cil managed
+  {
+    // Code size       47 (0x2f)
+    .maxstack  2
+    .locals init (bool V_0)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  stloc.0
+    IL_0003:  ldloc.0
+    IL_0004:  brfalse.s  IL_0015
+
+    IL_0006:  nop
+    IL_0007:  ldstr      "PASS"
+    IL_000c:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0011:  nop
+    IL_0012:  nop
+    IL_0013:  br.s       IL_002e
+
+    IL_0015:  nop
+    IL_0016:  ldstr      "FAIL: "
+    IL_001b:  ldarg.1
+    IL_001c:  call       string [mscorlib]System.String::Concat(string,
+                                                                string)
+    IL_0021:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0026:  nop
+    IL_0027:  ldc.i4.0
+    IL_0028:  stsfld     bool Test::Pass
+    IL_002d:  nop
+    IL_002e:  ret
+  } // end of method Test::Assert
+
+  .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 Test::.ctor
+
+  .method private hidebysig specialname rtspecialname static 
+          void  .cctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldc.i4.1
+    IL_0001:  stsfld     bool Test::Pass
+    IL_0006:  ret
+  } // end of method Test::.cctor
+
+} // end of class Test
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file sharedgenerics.res
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/sharedgenerics/sharedgenerics.ilproj b/tests/src/Loader/classloader/DefaultInterfaceMethods/sharedgenerics/sharedgenerics.ilproj
new file mode 100644 (file)
index 0000000..be40d20
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <AssemblyName>sharedgenerics</AssemblyName>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+    <OutputType>Exe</OutputType>
+    <CLRTestKind>BuildAndRun</CLRTestKind>
+    <CLRTestPriority>0</CLRTestPriority>
+    <!-- Use ILAsm that we just built for the new fixes required in default interface methods -->
+    <UseCustomILAsm>True</UseCustomILAsm>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Include="sharedgenerics.il" />
+  </ItemGroup>
+
+
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/simple/simple.cs b/tests/src/Loader/classloader/DefaultInterfaceMethods/simple/simple.cs
new file mode 100644 (file)
index 0000000..5936363
--- /dev/null
@@ -0,0 +1,124 @@
+using System;
+
+interface IBlah
+{
+    int Blah(int c);    
+}
+
+// All methods go into IBlah
+class IBlah_Impl
+{
+    public int Blah(int c)
+    {
+        Console.WriteLine("At IBlah.Blah"); 
+        return c + Blah_Private_GetA() + Blah_Internal_GetB() + Blah_Protected_GetC();        
+    }
+
+    private int Blah_Private_GetA()
+    {
+        Console.WriteLine("At IBlah.Blah_Private_GetA");
+        return 1;
+    }
+
+    internal int Blah_Internal_GetB()
+    {
+        Console.WriteLine("At IBlah.Blah_Internal_GetB"); 
+        return 2;
+    }
+
+    protected int Blah_Protected_GetC()
+    {
+        Console.WriteLine("At IBlah.Blah_Protected_GetC"); 
+        return 3;
+    }
+}
+
+interface IFoo
+{
+    int Foo(int a);
+}
+
+interface IBar
+{
+    int Bar(int b);
+}
+
+class Base : IBlah
+{
+    public int Blah(int c)
+    {
+        // Dummy
+        return 0;    
+    }
+}
+
+class FooBar : Base, IFoo, IBar
+{
+    public int Foo(int a)
+    {
+        Console.WriteLine("At IFoo.Foo");
+        return a+1;            
+    }
+
+    public int Bar(int b)
+    {
+        Console.WriteLine("At IBar.Bar");
+        return b+10;
+    }
+
+    public int CallBlahProtected()
+    {
+        // change to IBlah.Blah_Protected_GetC();        
+        return CallBlahProtected();
+    }
+}
+
+class Program
+{
+    public static int Main()
+    {
+        FooBar fooBar = new FooBar();
+        IFoo foo = (IFoo) fooBar;
+        IBar bar = (IBar) fooBar;
+        IBlah blah = (IBlah) fooBar;
+
+        Console.WriteLine("Calling IFoo.Foo on FooBar - expecting default method on IFoo.Foo. ");
+        Test.Assert(foo.Foo(10) == 11, "Calling IFoo.Foo on FooBar");
+
+        Console.WriteLine("Calling IBar.Bar on FooBar - expecting default method on IBar.Bar. ");
+        Test.Assert(bar.Bar(10) == 20, "Calling IBar.Bar on FooBar");
+
+        Console.WriteLine("Calling IBlah.Blah on FooBar - expecting default method on IBlah.Blah from Base. ");
+        Test.Assert(blah.Blah(10) == 16, "Calling IBlah.Blah on FooBar");
+
+        // Doesn't work yet
+        // Console.WriteLine("Calling FooBar.CallBlahProtected - expecting protected methods on interface can be called");
+        // Test.Assert(fooBar.CallBlahProtected() == 3, "Calling FooBar.CallBlahProtected");
+
+        return Test.Ret();
+    }
+}
+
+class Test
+{
+    private static bool Pass = true;
+
+    public static int Ret()
+    {
+        return Pass? 100 : 101;
+    }
+
+    public static void Assert(bool cond, string msg)
+    {
+        if (cond)
+        {
+            Console.WriteLine("PASS");
+        }
+        else
+        {
+            Console.WriteLine("FAIL: " + msg);
+            Pass = false;
+        }
+    }
+}                    
+
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/simple/simple.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/simple/simple.il
new file mode 100644 (file)
index 0000000..c78aaf4
--- /dev/null
@@ -0,0 +1,401 @@
+
+//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.6.1055.0
+//  Copyright (c) Microsoft Corporation.  All rights reserved.
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
+  .ver 4:0:0:0
+}
+.assembly simple
+{
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
+                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
+
+  // --- The following custom attribute is added automatically, do not uncomment -------
+  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 
+
+  .hash algorithm 0x00008004
+  .ver 0:0:0:0
+}
+.module simple.exe
+// MVID: {0B8FCFD0-673A-4DEB-90CC-B96749DE09C8}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003       // WINDOWS_CUI
+.corflags 0x00000001    //  ILONLY
+// Image base: 0x01A80000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class interface private abstract auto ansi IBlah
+{
+  .method public hidebysig newslot virtual 
+          instance int32  Blah(int32 c) cil managed
+  {
+    // Code size       39 (0x27)
+    .maxstack  2
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IBlah.Blah"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  ldarg.1
+    IL_000d:  ldarg.0
+    IL_000e:  call       instance int32 IBlah::Blah_Private_GetA()
+    IL_0013:  add
+    IL_0014:  ldarg.0
+    IL_0015:  call       instance int32 IBlah::Blah_Internal_GetB()
+    IL_001a:  add
+    IL_001b:  ldarg.0
+    IL_001c:  call       instance int32 IBlah::Blah_Protected_GetC()
+    IL_0021:  add
+    IL_0022:  stloc.0
+    IL_0023:  br.s       IL_0025
+
+    IL_0025:  ldloc.0
+    IL_0026:  ret 
+  } // end of method IBlah::Blah
+
+  .method private hidebysig instance int32 
+          Blah_Private_GetA() cil managed
+  {
+    // Code size       18 (0x12)
+    .maxstack  1
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IBlah.Blah_Private_GetA"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  ldc.i4.1
+    IL_000d:  stloc.0
+    IL_000e:  br.s       IL_0010
+
+    IL_0010:  ldloc.0
+    IL_0011:  ret
+  } // end of method IBlah_Impl::Blah_Private_GetA
+
+  .method assembly hidebysig instance int32 
+          Blah_Internal_GetB() cil managed
+  {
+    // Code size       18 (0x12)
+    .maxstack  1
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IBlah.Blah_Internal_GetB"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  ldc.i4.2
+    IL_000d:  stloc.0
+    IL_000e:  br.s       IL_0010
+
+    IL_0010:  ldloc.0
+    IL_0011:  ret
+  } // end of method IBlah_Impl::Blah_Internal_GetB
+
+  .method family hidebysig instance int32 
+          Blah_Protected_GetC() cil managed
+  {
+    // Code size       18 (0x12)
+    .maxstack  1
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IBlah.Blah_Protected_GetC"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  ldc.i4.3
+    IL_000d:  stloc.0
+    IL_000e:  br.s       IL_0010
+
+    IL_0010:  ldloc.0
+    IL_0011:  ret
+  } // end of method IBlah_Impl::Blah_Protected_GetC
+} // end of class IBlah
+
+.class interface private abstract auto ansi IFoo
+{
+  .method public hidebysig newslot virtual 
+          instance int32  Foo(int32 a) cil managed
+  {
+    // Code size       20 (0x14)
+    .maxstack  2
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IFoo.Foo"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  ldarg.1
+    IL_000d:  ldc.i4.1
+    IL_000e:  add
+    IL_000f:  stloc.0
+    IL_0010:  br.s       IL_0012
+
+    IL_0012:  ldloc.0
+    IL_0013:  ret
+  } // end of method IFoo::Foo
+
+} // end of class IFoo
+
+.class interface private abstract auto ansi IBar
+{
+  .method public hidebysig newslot virtual 
+          instance int32  Bar(int32 b) cil managed
+  {
+    // Code size       21 (0x15)
+    .maxstack  2
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldstr      "At IBar.Bar"
+    IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_000b:  nop
+    IL_000c:  ldarg.1
+    IL_000d:  ldc.i4.s   10
+    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 class IBar
+
+.class private auto ansi beforefieldinit Base
+       extends [mscorlib]System.Object
+       implements IBlah
+{
+  .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 Base::.ctor
+
+} // end of class Base
+
+.class private auto ansi beforefieldinit FooBar
+       extends Base
+       implements IFoo,
+                  IBar
+{
+  .method public hidebysig instance int32 
+          CallBlahProtected() cil managed
+  {
+    // Code size       12 (0xc)
+    .maxstack  1
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  call       instance int32 IBlah::Blah_Protected_GetC()
+    IL_0007:  stloc.0
+    IL_0008:  br.s       IL_000a
+
+    IL_000a:  ldloc.0
+    IL_000b:  ret
+  } // end of method FooBar::CallBlahProtected
+
+  .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 Base::.ctor()
+    IL_0006:  nop
+    IL_0007:  ret
+  } // end of method FooBar::.ctor
+
+} // end of class FooBar
+
+.class private auto ansi beforefieldinit Program
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig static int32  Main() cil managed
+  {
+    .entrypoint
+    // Code size       158 (0x9e)
+    .maxstack  2
+    .locals init (class FooBar V_0,
+             class IFoo V_1,
+             class IBar V_2,
+             class IBlah V_3,
+             int32 V_4)
+    IL_0000:  nop
+    IL_0001:  newobj     instance void FooBar::.ctor()
+    IL_0006:  stloc.0
+    IL_0007:  ldloc.0
+    IL_0008:  stloc.1
+    IL_0009:  ldloc.0
+    IL_000a:  stloc.2
+    IL_000b:  ldloc.0
+    IL_000c:  stloc.3
+    IL_000d:  ldstr      "Calling IFoo.Foo on FooBar - expecting default met"
+    + "hod on IFoo.Foo. "
+    IL_0012:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0017:  nop
+    IL_0018:  ldloc.1
+    IL_0019:  ldc.i4.s   10
+    IL_001b:  callvirt   instance int32 IFoo::Foo(int32)
+    IL_0020:  ldc.i4.s   11
+    IL_0022:  ceq
+    IL_0024:  ldstr      "Calling IFoo.Foo on FooBar"
+    IL_0029:  call       void Test::Assert(bool,
+                                           string)
+    IL_002e:  nop
+    IL_002f:  ldstr      "Calling IBar.Bar on FooBar - expecting default met"
+    + "hod on IBar.Bar. "
+    IL_0034:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0039:  nop
+    IL_003a:  ldloc.2
+    IL_003b:  ldc.i4.s   10
+    IL_003d:  callvirt   instance int32 IBar::Bar(int32)
+    IL_0042:  ldc.i4.s   20
+    IL_0044:  ceq
+    IL_0046:  ldstr      "Calling IBar.Bar on FooBar"
+    IL_004b:  call       void Test::Assert(bool,
+                                           string)
+    IL_0050:  nop
+    IL_0051:  ldstr      "Calling IBlah.Blah on FooBar - expecting default m"
+    + "ethod on IBlah.Blah from Base. "
+    IL_0056:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_005b:  nop
+    IL_005c:  ldloc.3
+    IL_005d:  ldc.i4.s   10
+    IL_005f:  callvirt   instance int32 IBlah::Blah(int32)
+    IL_0064:  ldc.i4.s   16
+    IL_0066:  ceq
+    IL_0068:  ldstr      "Calling IBlah.Blah on FooBar"
+    IL_006d:  call       void Test::Assert(bool,
+                                           string)
+    IL_0072:  nop
+    IL_0073:  ldstr      "Calling FooBar.CallBlahProtected - expecting prote"
+    + "cted methods on interface can be called"
+    IL_0078:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_007d:  nop
+
+/* THIS DOESN"T WORK YET
+    IL_007e:  ldloc.0
+    IL_007f:  callvirt   instance int32 FooBar::CallBlahProtected()
+    IL_0084:  ldc.i4.3
+    IL_0085:  ceq
+    IL_0087:  ldstr      "Calling FooBar.CallBlahProtected"
+    IL_008c:  call       void Test::Assert(bool,
+                                           string)
+    IL_0091:  nop
+*/
+    IL_0092:  call       int32 Test::Ret()
+    IL_0097:  stloc.s    V_4
+    IL_0099:  br.s       IL_009b
+
+    IL_009b:  ldloc.s    V_4
+    IL_009d:  ret
+  } // end of method Program::Main
+
+  .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 Program::.ctor
+
+} // end of class Program
+
+.class private auto ansi beforefieldinit Test
+       extends [mscorlib]System.Object
+{
+  .field private static bool Pass
+  .method public hidebysig static int32  Ret() cil managed
+  {
+    // Code size       19 (0x13)
+    .maxstack  1
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldsfld     bool Test::Pass
+    IL_0006:  brtrue.s   IL_000c
+
+    IL_0008:  ldc.i4.s   101
+    IL_000a:  br.s       IL_000e
+
+    IL_000c:  ldc.i4.s   100
+    IL_000e:  stloc.0
+    IL_000f:  br.s       IL_0011
+
+    IL_0011:  ldloc.0
+    IL_0012:  ret
+  } // end of method Test::Ret
+
+  .method public hidebysig static void  Assert(bool cond,
+                                               string msg) cil managed
+  {
+    // Code size       47 (0x2f)
+    .maxstack  2
+    .locals init (bool V_0)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  stloc.0
+    IL_0003:  ldloc.0
+    IL_0004:  brfalse.s  IL_0015
+
+    IL_0006:  nop
+    IL_0007:  ldstr      "PASS"
+    IL_000c:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0011:  nop
+    IL_0012:  nop
+    IL_0013:  br.s       IL_002e
+
+    IL_0015:  nop
+    IL_0016:  ldstr      "FAIL: "
+    IL_001b:  ldarg.1
+    IL_001c:  call       string [mscorlib]System.String::Concat(string,
+                                                                string)
+    IL_0021:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0026:  nop
+    IL_0027:  ldc.i4.0
+    IL_0028:  stsfld     bool Test::Pass
+    IL_002d:  nop
+    IL_002e:  ret
+  } // end of method Test::Assert
+
+  .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 Test::.ctor
+
+  .method private hidebysig specialname rtspecialname static 
+          void  .cctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldc.i4.1
+    IL_0001:  stsfld     bool Test::Pass
+    IL_0006:  ret
+  } // end of method Test::.cctor
+
+} // end of class Test
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file simple.res
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/simple/simple.ilproj b/tests/src/Loader/classloader/DefaultInterfaceMethods/simple/simple.ilproj
new file mode 100644 (file)
index 0000000..0bf910b
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <AssemblyName>simple</AssemblyName>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+    <OutputType>Exe</OutputType>
+    <CLRTestKind>BuildAndRun</CLRTestKind>
+    <CLRTestPriority>0</CLRTestPriority>
+    <!-- Use ILAsm that we just built for the new fixes required in default interface methods -->
+    <UseCustomILAsm>True</UseCustomILAsm>    
+  </PropertyGroup>
+
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Include="simple.il" />
+  </ItemGroup>
+
+
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/valuetypes/valuetypes.cs b/tests/src/Loader/classloader/DefaultInterfaceMethods/valuetypes/valuetypes.cs
new file mode 100644 (file)
index 0000000..0cf1be9
--- /dev/null
@@ -0,0 +1,94 @@
+using System;
+
+interface IValue
+{
+    int GetValue();
+    void SetValue(int a);
+    int Add(int a);
+}
+
+// This class is only needed to spit out IL that assumes 'this' is an object (and therefore don't box)
+struct FooBarStruct_ : IValue
+{
+    public int GetValue()
+    {
+        return 0;
+    }
+
+    public void SetValue(int val)
+    {
+    }
+
+    public int Add(int a)
+    {
+        // Force cast and boxing
+        IValue valueIntf = this as IValue; 
+        int val = valueIntf.GetValue();
+        val += a;
+        valueIntf.SetValue(val);
+        return val;
+    }
+}
+
+struct FooBarStruct : IValue
+{
+    public int _val;
+
+    public int GetValue()
+    {
+        return _val;
+    }
+
+    public void SetValue(int val)
+    {
+        _val = val;
+    }
+
+    public int Add(int a)
+    {
+        // Dummy
+        return 0;
+    }   
+}
+
+class Program
+{
+    public static int Main()
+    {
+        FooBarStruct fooBar = new FooBarStruct();
+
+        fooBar._val = 10;
+
+        IValue foo = (IValue) fooBar;
+
+        Console.WriteLine("Calling IFoo.Foo on FooBarStruct");
+        Test.Assert(foo.Add(10) == 20, "Calling default method IValue.Add on FooBarStruct failed");
+        Test.Assert(fooBar.GetValue() == 10, "FooBarStruct value should remain unchanged");
+
+        return Test.Ret();
+    }
+}
+
+class Test
+{
+    private static bool Pass = true;
+
+    public static int Ret()
+    {
+        return Pass? 100 : 101;
+    }
+
+    public static void Assert(bool cond, string msg)
+    {
+        if (cond)
+        {
+            Console.WriteLine("PASS");
+        }
+        else
+        {
+            Console.WriteLine("FAIL: " + msg);
+            Pass = false;
+        }
+    }
+}                    
+
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/valuetypes/valuetypes.il b/tests/src/Loader/classloader/DefaultInterfaceMethods/valuetypes/valuetypes.il
new file mode 100644 (file)
index 0000000..56c23f1
--- /dev/null
@@ -0,0 +1,252 @@
+
+//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.6.1055.0
+//  Copyright (c) Microsoft Corporation.  All rights reserved.
+
+
+
+// Metadata version: v4.0.30319
+.assembly extern mscorlib
+{
+  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
+  .ver 4:0:0:0
+}
+.assembly valuetypes
+{
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
+  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
+                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
+
+  // --- The following custom attribute is added automatically, do not uncomment -------
+  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 
+
+  .hash algorithm 0x00008004
+  .ver 0:0:0:0
+}
+.module valuetypes.exe
+// MVID: {E191F723-B724-4D70-B3A8-CEA89FD033D3}
+.imagebase 0x00400000
+.file alignment 0x00000200
+.stackreserve 0x00100000
+.subsystem 0x0003       // WINDOWS_CUI
+.corflags 0x00000001    //  ILONLY
+// Image base: 0x01170000
+
+
+// =============== CLASS MEMBERS DECLARATION ===================
+
+.class interface private abstract auto ansi IValue
+{
+  .method public hidebysig newslot abstract virtual 
+          instance int32  GetValue() cil managed
+  {
+  } // end of method IValue::GetValue
+
+  .method public hidebysig newslot abstract virtual 
+          instance void  SetValue(int32 a) cil managed
+  {
+  } // end of method IValue::SetValue
+
+  .method public hidebysig newslot virtual 
+          instance int32  Add(int32 a) cil managed
+  {
+    // Code size       26 (0x1a)
+    .maxstack  2
+    .locals init (int32 V_0,
+             int32 V_1)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  call       instance int32 IValue::GetValue()
+    IL_0007:  stloc.0
+    IL_0008:  ldloc.0
+    IL_0009:  ldarg.1
+    IL_000a:  add
+    IL_000b:  stloc.0
+    IL_000c:  ldarg.0
+    IL_000d:  ldloc.0
+    IL_000e:  call       instance void IValue::SetValue(int32)
+    IL_0013:  nop
+    IL_0014:  ldloc.0
+    IL_0015:  stloc.1
+    IL_0016:  br.s       IL_0018
+
+    IL_0018:  ldloc.1
+    IL_0019:  ret
+  } // end of method IValue::Add
+
+} // end of class IValue
+
+.class private sequential ansi sealed beforefieldinit FooBarStruct
+       extends [mscorlib]System.ValueType
+       implements IValue
+{
+  .field public int32 _val
+  .method public hidebysig newslot virtual final 
+          instance int32  GetValue() cil managed
+  {
+    // Code size       12 (0xc)
+    .maxstack  1
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  ldfld      int32 FooBarStruct::_val
+    IL_0007:  stloc.0
+    IL_0008:  br.s       IL_000a
+
+    IL_000a:  ldloc.0
+    IL_000b:  ret
+  } // end of method FooBarStruct::GetValue
+
+  .method public hidebysig newslot virtual final 
+          instance void  SetValue(int32 val) cil managed
+  {
+    // Code size       9 (0x9)
+    .maxstack  8
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  ldarg.1
+    IL_0003:  stfld      int32 FooBarStruct::_val
+    IL_0008:  ret
+  } // end of method FooBarStruct::SetValue
+} // end of class FooBarStruct
+
+.class private auto ansi beforefieldinit Program
+       extends [mscorlib]System.Object
+{
+  .method public hidebysig static int32  Main() cil managed
+  {
+    .entrypoint
+    .maxstack  2
+    .locals init (valuetype FooBarStruct V_0,
+             class IValue V_1,
+             int32 V_2)
+    IL_0000:  nop
+    IL_0001:  ldloca.s   V_0
+    IL_0003:  initobj    FooBarStruct
+    IL_0009:  ldloca.s   V_0
+    IL_000b:  ldc.i4.s   10
+    IL_000d:  stfld      int32 FooBarStruct::_val
+    IL_0012:  ldloc.0
+    IL_0013:  box        FooBarStruct
+    IL_0018:  stloc.1
+    IL_0019:  ldstr      "Calling IFoo.Foo on FooBarStruct"
+    IL_001e:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0023:  nop
+    IL_0024:  ldloc.1
+    IL_0025:  ldc.i4.s   10
+    IL_0027:  callvirt   instance int32 IValue::Add(int32)
+    IL_002c:  ldc.i4.s   20
+    IL_002e:  ceq
+    IL_0030:  ldstr      "Calling default method IValue.Add on FooBarStruct "
+    + "failed"
+    IL_0035:  call       void Test::Assert(bool,
+                                           string)
+    IL_003a:  nop
+    IL_003b:  ldloca     V_0
+              callvirt   instance int32 FooBarStruct::GetValue()
+              ldc.i4.s   10
+              ceq
+              ldstr      "FooBarStruct value should remain unchanged"
+              call       void Test::Assert(bool,
+                                           string)
+              nop
+              call       int32 Test::Ret()
+              ret
+  } // end of method Program::Main
+
+  .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 Program::.ctor
+
+} // end of class Program
+
+.class private auto ansi beforefieldinit Test
+       extends [mscorlib]System.Object
+{
+  .field private static bool Pass
+  .method public hidebysig static int32  Ret() cil managed
+  {
+    // Code size       19 (0x13)
+    .maxstack  1
+    .locals init (int32 V_0)
+    IL_0000:  nop
+    IL_0001:  ldsfld     bool Test::Pass
+    IL_0006:  brtrue.s   IL_000c
+
+    IL_0008:  ldc.i4.s   101
+    IL_000a:  br.s       IL_000e
+
+    IL_000c:  ldc.i4.s   100
+    IL_000e:  stloc.0
+    IL_000f:  br.s       IL_0011
+
+    IL_0011:  ldloc.0
+    IL_0012:  ret
+  } // end of method Test::Ret
+
+  .method public hidebysig static void  Assert(bool cond,
+                                               string msg) cil managed
+  {
+    // Code size       47 (0x2f)
+    .maxstack  2
+    .locals init (bool V_0)
+    IL_0000:  nop
+    IL_0001:  ldarg.0
+    IL_0002:  stloc.0
+    IL_0003:  ldloc.0
+    IL_0004:  brfalse.s  IL_0015
+
+    IL_0006:  nop
+    IL_0007:  ldstr      "PASS"
+    IL_000c:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0011:  nop
+    IL_0012:  nop
+    IL_0013:  br.s       IL_002e
+
+    IL_0015:  nop
+    IL_0016:  ldstr      "FAIL: "
+    IL_001b:  ldarg.1
+    IL_001c:  call       string [mscorlib]System.String::Concat(string,
+                                                                string)
+    IL_0021:  call       void [mscorlib]System.Console::WriteLine(string)
+    IL_0026:  nop
+    IL_0027:  ldc.i4.0
+    IL_0028:  stsfld     bool Test::Pass
+    IL_002d:  nop
+    IL_002e:  ret
+  } // end of method Test::Assert
+
+  .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 Test::.ctor
+
+  .method private hidebysig specialname rtspecialname static 
+          void  .cctor() cil managed
+  {
+    // Code size       7 (0x7)
+    .maxstack  8
+    IL_0000:  ldc.i4.1
+    IL_0001:  stsfld     bool Test::Pass
+    IL_0006:  ret
+  } // end of method Test::.cctor
+
+} // end of class Test
+
+
+// =============================================================
+
+// *********** DISASSEMBLY COMPLETE ***********************
+// WARNING: Created Win32 resource file valuetypes.res
diff --git a/tests/src/Loader/classloader/DefaultInterfaceMethods/valuetypes/valuetypes.ilproj b/tests/src/Loader/classloader/DefaultInterfaceMethods/valuetypes/valuetypes.ilproj
new file mode 100644 (file)
index 0000000..12973e7
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <AssemblyName>valuetypes</AssemblyName>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <ReferenceLocalMscorlib>true</ReferenceLocalMscorlib>
+    <OutputType>Exe</OutputType>
+    <CLRTestKind>BuildAndRun</CLRTestKind>
+    <CLRTestPriority>0</CLRTestPriority>
+    <!-- Use ILAsm that we just built for the new fixes required in default interface methods -->
+    <UseCustomILAsm>True</UseCustomILAsm>    
+  </PropertyGroup>
+
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Include="valuetypes.il" />
+  </ItemGroup>
+
+
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>