Remove relocations for MethodTable's vtable-1st-level-indirection
[platform/upstream/dotnet/runtime.git] / src / coreclr / src / vm / generics.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //
5 // File: generics.cpp
6 //
7
8
9 //
10 // Helper functions for generics prototype
11 //
12
13 //
14 // ============================================================================
15
16 #include "common.h"
17 #include "method.hpp"
18 #include "field.h"
19 #include "eeconfig.h"
20 #include "generics.h"
21 #include "genericdict.h"
22 #include "stackprobe.h"
23 #include "typestring.h"
24 #include "typekey.h"
25 #include "dumpcommon.h"
26 #include "array.h"
27
28 #include "generics.inl"
29 #ifdef FEATURE_COMINTEROP
30 #include "winrttypenameconverter.h"
31 #endif // FEATURE_COMINTEROP
32
33 /* static */
34 TypeHandle ClassLoader::CanonicalizeGenericArg(TypeHandle thGenericArg)
35 {
36     CONTRACT(TypeHandle)
37     {
38         NOTHROW;
39         GC_NOTRIGGER;
40         POSTCONDITION(CheckPointer(RETVAL));
41     }
42     CONTRACT_END
43
44 #if defined(FEATURE_SHARE_GENERIC_CODE)  
45     CorElementType et = thGenericArg.GetSignatureCorElementType();
46
47     // Note that generic variables do not share
48
49     if (CorTypeInfo::IsObjRef_NoThrow(et))
50         RETURN(TypeHandle(g_pCanonMethodTableClass));
51
52     if (et == ELEMENT_TYPE_VALUETYPE)
53     {
54         // Don't share structs. But sharability must be propagated through 
55         // them (i.e. struct<object> * shares with struct<string> *)
56         RETURN(TypeHandle(thGenericArg.GetCanonicalMethodTable()));
57     }
58
59     _ASSERTE(et != ELEMENT_TYPE_PTR && et != ELEMENT_TYPE_FNPTR);
60     RETURN(thGenericArg);
61 #else
62     RETURN (thGenericArg);
63 #endif // FEATURE_SHARE_GENERIC_CODE
64 }
65
66  // Given the build-time ShareGenericCode setting, is the specified type 
67 // representation-sharable as a type parameter to a generic type or method ?
68 /* static */ BOOL ClassLoader::IsSharableInstantiation(Instantiation inst) 
69 {
70     CONTRACTL
71     {
72         NOTHROW;
73         GC_NOTRIGGER;
74         FORBID_FAULT;
75     }
76     CONTRACTL_END
77
78     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
79     {
80         if (CanonicalizeGenericArg(inst[i]).IsCanonicalSubtype())
81             return TRUE;
82     }
83     return FALSE;
84 }
85
86 /* static */ BOOL ClassLoader::IsCanonicalGenericInstantiation(Instantiation inst)
87 {
88     CONTRACTL
89     {
90         NOTHROW;
91         GC_NOTRIGGER;
92         FORBID_FAULT;
93     }
94     CONTRACTL_END
95
96     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
97     {
98         if (CanonicalizeGenericArg(inst[i]) != inst[i])
99             return FALSE;
100     }
101     return TRUE;
102 }
103
104 /* static */ BOOL ClassLoader::IsTypicalSharedInstantiation(Instantiation inst)
105 {
106     CONTRACTL
107     {
108         NOTHROW;
109         GC_NOTRIGGER;
110         FORBID_FAULT;
111     }
112     CONTRACTL_END
113
114     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
115     {
116         if (inst[i] != TypeHandle(g_pCanonMethodTableClass))
117             return FALSE;
118     }
119     return TRUE;
120 }
121
122 #ifndef DACCESS_COMPILE 
123
124 TypeHandle ClassLoader::LoadCanonicalGenericInstantiation(TypeKey *pTypeKey,
125                                                           LoadTypesFlag fLoadTypes/*=LoadTypes*/,
126                                                           ClassLoadLevel level/*=CLASS_LOADED*/)
127 {
128     CONTRACT(TypeHandle)
129     {
130         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
131         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
132         if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
133         POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == LoadTypes) ? NULL_NOT_OK : NULL_OK)));
134         POSTCONDITION(RETVAL.IsNull() || RETVAL.CheckLoadLevel(level));
135     }
136     CONTRACT_END
137
138     Instantiation inst = pTypeKey->GetInstantiation();
139     DWORD ntypars = inst.GetNumArgs();
140
141     // Canonicalize the type arguments.
142     DWORD dwAllocSize = 0;
143     if (!ClrSafeInt<DWORD>::multiply(ntypars, sizeof(TypeHandle), dwAllocSize))
144         ThrowHR(COR_E_OVERFLOW);
145
146     TypeHandle ret = TypeHandle();
147     DECLARE_INTERIOR_STACK_PROBE;
148 #ifndef DACCESS_COMPILE
149     if ((dwAllocSize/GetOsPageSize()+1) >= 2)
150     {
151         DO_INTERIOR_STACK_PROBE_FOR_NOTHROW_CHECK_THREAD((10+dwAllocSize/GetOsPageSize()+1), NO_FORBIDGC_LOADER_USE_ThrowSO(););
152     }
153 #endif // DACCESS_COMPILE
154     TypeHandle *repInst = (TypeHandle*) _alloca(dwAllocSize);
155
156     for (DWORD i = 0; i < ntypars; i++)
157     {
158         repInst[i] = ClassLoader::CanonicalizeGenericArg(inst[i]);
159     }
160
161     // Load the canonical instantiation
162     TypeKey canonKey(pTypeKey->GetModule(), pTypeKey->GetTypeToken(), Instantiation(repInst, ntypars));
163     ret = ClassLoader::LoadConstructedTypeThrowing(&canonKey, fLoadTypes, level);
164
165     END_INTERIOR_STACK_PROBE;
166     RETURN(ret);
167 }
168
169 // Create a non-canonical instantiation of a generic type, by
170 // copying the method table of the canonical instantiation
171 //
172 /* static */
173 TypeHandle 
174 ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation(
175     TypeKey         *pTypeKey, 
176     AllocMemTracker *pamTracker)
177 {
178     CONTRACT(TypeHandle)
179     {
180         STANDARD_VM_CHECK;
181         PRECONDITION(CheckPointer(pTypeKey));
182         PRECONDITION(CheckPointer(pamTracker));
183         PRECONDITION(pTypeKey->HasInstantiation());
184         PRECONDITION(ClassLoader::IsSharableInstantiation(pTypeKey->GetInstantiation()));
185         PRECONDITION(!TypeHandle::IsCanonicalSubtypeInstantiation(pTypeKey->GetInstantiation()));
186         POSTCONDITION(CheckPointer(RETVAL));
187         POSTCONDITION(RETVAL.CheckMatchesKey(pTypeKey));
188     }
189     CONTRACT_END
190
191     Module *pLoaderModule = ClassLoader::ComputeLoaderModule(pTypeKey);
192     LoaderAllocator* pAllocator=pLoaderModule->GetLoaderAllocator();
193
194     Instantiation inst = pTypeKey->GetInstantiation();
195     pAllocator->EnsureInstantiation(pTypeKey->GetModule(), inst);
196     DWORD ntypars = inst.GetNumArgs();
197
198 #ifdef _DEBUG
199     if (LoggingOn(LF_CLASSLOADER, LL_INFO1000) || g_pConfig->BreakOnInstantiationEnabled())
200     {
201         StackSString debugTypeKeyName;
202         TypeString::AppendTypeKeyDebug(debugTypeKeyName, pTypeKey);
203         LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: New instantiation requested: %S\n", debugTypeKeyName.GetUnicode()));
204         
205         StackScratchBuffer buf;
206         if (g_pConfig->ShouldBreakOnInstantiation(debugTypeKeyName.GetUTF8(buf)))
207             CONSISTENCY_CHECK_MSGF(false, ("BreakOnInstantiation: typename '%s' ", debugTypeKeyName.GetUTF8(buf)));
208     }
209 #endif // _DEBUG
210
211     TypeHandle canonType;
212     {
213         OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
214         canonType = ClassLoader::LoadCanonicalGenericInstantiation(pTypeKey, ClassLoader::LoadTypes, CLASS_LOAD_APPROXPARENTS);
215     }
216
217     // Now fabricate a method table
218     MethodTable* pOldMT = canonType.AsMethodTable();
219
220     // We only need true vtable entries as the rest can be found in the representative method table
221     WORD cSlots = static_cast<WORD>(pOldMT->GetNumVirtuals());
222
223     BOOL fContainsGenericVariables = MethodTable::ComputeContainsGenericVariables(inst);
224
225     // These are all copied across from the old MT, i.e. don't depend on the
226     // instantiation.
227     BOOL fHasRemotingVtsInfo = FALSE;
228     BOOL fHasContextStatics = FALSE;
229     BOOL fHasGenericsStaticsInfo = pOldMT->HasGenericsStaticsInfo();
230     BOOL fHasThreadStatics = (pOldMT->GetNumThreadStaticFields() > 0);
231
232 #ifdef FEATURE_COMINTEROP
233     BOOL fHasDynamicInterfaceMap = pOldMT->HasDynamicInterfaceMap();
234     BOOL fHasRCWPerTypeData = pOldMT->HasRCWPerTypeData();
235 #else // FEATURE_COMINTEROP
236     BOOL fHasDynamicInterfaceMap = FALSE;
237     BOOL fHasRCWPerTypeData = FALSE;
238 #endif // FEATURE_COMINTEROP
239
240     // Collectible types have some special restrictions
241     if (pAllocator->IsCollectible())
242     {
243         if (fHasThreadStatics || fHasContextStatics)
244         {
245             ClassLoader::ThrowTypeLoadException(pTypeKey, IDS_CLASSLOAD_COLLECTIBLESPECIALSTATICS);
246         }
247         else if (pOldMT->HasFixedAddressVTStatics())
248         {
249             ClassLoader::ThrowTypeLoadException(pTypeKey, IDS_CLASSLOAD_COLLECTIBLEFIXEDVTATTR);
250         }
251     }
252
253     // The number of bytes used for GC info
254     size_t cbGC = pOldMT->ContainsPointers() ? ((CGCDesc*) pOldMT)->GetSize() : 0;
255
256     // Bytes are required for the vtable itself
257     S_SIZE_T safe_cbMT = S_SIZE_T( cbGC ) + S_SIZE_T( sizeof(MethodTable) );
258     safe_cbMT += MethodTable::GetNumVtableIndirections(cSlots) * sizeof(MethodTable::VTableIndir_t);
259     if (safe_cbMT.IsOverflow())
260     {
261         ThrowHR(COR_E_OVERFLOW);
262     }
263     const size_t cbMT = safe_cbMT.Value();
264
265     // After the optional members (see below) comes the duplicated interface map.
266     // For dynamic interfaces the interface map area begins one word
267     // before the location returned by GetInterfaceMap()
268     WORD wNumInterfaces = static_cast<WORD>(pOldMT->GetNumInterfaces());
269     DWORD cbIMap = pOldMT->GetInterfaceMapSize();
270     InterfaceInfo_t * pOldIMap = (InterfaceInfo_t *)pOldMT->GetInterfaceMap();
271
272     BOOL fHasGuidInfo = FALSE;
273     BOOL fHasCCWTemplate = FALSE;
274
275     Generics::DetermineCCWTemplateAndGUIDPresenceOnNonCanonicalMethodTable(pOldMT, fContainsGenericVariables, &fHasGuidInfo, &fHasCCWTemplate);
276
277     DWORD dwMultipurposeSlotsMask = 0;
278     dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasPerInstInfo;
279     if (wNumInterfaces != 0)
280         dwMultipurposeSlotsMask |= MethodTable::enum_flag_HasInterfaceMap;
281
282     // NonVirtualSlots, DispatchMap and ModuleOverride multipurpose slots are used 
283     // from the canonical methodtable, so we do not need to store them here.
284
285     // We need space for the optional members.
286     DWORD cbOptional = MethodTable::GetOptionalMembersAllocationSize(dwMultipurposeSlotsMask,
287                                                       FALSE, // fHasRemotableMethodInfo
288                                                       fHasGenericsStaticsInfo,
289                                                       fHasGuidInfo,
290                                                       fHasCCWTemplate,
291                                                       fHasRCWPerTypeData,
292                                                       fHasRemotingVtsInfo,
293                                                       fHasContextStatics,
294                                                       pOldMT->HasTokenOverflow());
295
296     // We need space for the PerInstInfo, i.e. the generic dictionary pointers...
297     DWORD cbPerInst = sizeof(GenericsDictInfo) + pOldMT->GetPerInstInfoSize();
298
299     // Finally we need space for the instantiation/dictionary for this type
300     DWORD cbInstAndDict = pOldMT->GetInstAndDictSize();
301
302     // Allocate from the high frequence heap of the correct domain
303     S_SIZE_T allocSize = safe_cbMT;
304     allocSize += cbOptional;
305     allocSize += cbIMap;
306     allocSize += cbPerInst;
307     allocSize += cbInstAndDict;
308
309     if (allocSize.IsOverflow())
310     {
311         ThrowHR(COR_E_OVERFLOW);
312     }
313
314 #ifdef FEATURE_PREJIT
315     Module *pComputedPZM = Module::ComputePreferredZapModule(pTypeKey);
316     BOOL canShareVtableChunks = MethodTable::CanShareVtableChunksFrom(pOldMT, pLoaderModule, pComputedPZM);
317 #else
318     BOOL canShareVtableChunks = MethodTable::CanShareVtableChunksFrom(pOldMT, pLoaderModule);
319 #endif // FEATURE_PREJIT
320
321     SIZE_T offsetOfUnsharedVtableChunks = allocSize.Value();
322
323     // We either share all of the canonical's virtual slots or none of them
324     // If none, we need to allocate space for the slots
325     if (!canShareVtableChunks)
326     {
327         allocSize += S_SIZE_T( cSlots ) * S_SIZE_T( sizeof(PCODE) );
328     }
329
330     if (allocSize.IsOverflow())
331     {
332         ThrowHR(COR_E_OVERFLOW);
333     }
334
335     BYTE* pMemory = (BYTE *) pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem( allocSize ));
336     
337     // Head of MethodTable memory
338     MethodTable *pMT = (MethodTable*) (pMemory + cbGC);
339
340     // Copy of GC
341     memcpy((BYTE*)pMT - cbGC, (BYTE*) pOldMT - cbGC, cbGC);
342
343     // Allocate the private data block ("private" during runtime in the ngen'ed case)
344     MethodTableWriteableData * pMTWriteableData = (MethodTableWriteableData *) (BYTE *)
345         pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(MethodTableWriteableData))));
346     // Note: Memory allocated on loader heap is zero filled
347     pMT->SetWriteableData(pMTWriteableData);
348
349     // This also disables IBC logging until the type is sufficiently intitialized so
350     // it needs to be done early
351     pMTWriteableData->SetIsNotFullyLoadedForBuildMethodTable();
352
353     // <TODO> this is incredibly fragile.  We should just construct the MT all over agin. </TODO>
354     pMT->CopyFlags(pOldMT);
355
356     pMT->ClearFlag(MethodTable::enum_flag_MultipurposeSlotsMask);
357     pMT->SetMultipurposeSlotsMask(dwMultipurposeSlotsMask);
358
359     // Set generics flags
360     pMT->ClearFlag(MethodTable::enum_flag_GenericsMask);
361     pMT->SetFlag(MethodTable::enum_flag_GenericsMask_GenericInst);
362
363     // Freshly allocated - does not need restore
364     pMT->ClearFlag(MethodTable::enum_flag_IsZapped);
365     pMT->ClearFlag(MethodTable::enum_flag_IsPreRestored);
366
367     pMT->m_pParentMethodTable.SetValueMaybeNull(NULL);
368
369     // Non non-virtual slots
370     pMT->ClearFlag(MethodTable::enum_flag_HasSingleNonVirtualSlot);
371
372     pMT->SetBaseSize(pOldMT->GetBaseSize());
373     pMT->SetParentMethodTable(pOldMT->GetParentMethodTable());
374     pMT->SetCanonicalMethodTable(pOldMT);
375
376     pMT->m_wNumInterfaces = pOldMT->m_wNumInterfaces;
377
378 #ifdef FEATURE_TYPEEQUIVALENCE 
379     if (pMT->IsInterface() && !pMT->HasTypeEquivalence())
380     {
381         // fHasTypeEquivalence flag is "inherited" from generic arguments so we can quickly detect
382         // types like IList<IFoo> where IFoo is an interface with the TypeIdentifierAttribute.
383         for (DWORD i = 0; i < ntypars; i++) 
384         {
385             if (inst[i].HasTypeEquivalence())
386             {
387                 pMT->SetHasTypeEquivalence();
388                 break;
389             }
390         }
391     }
392 #endif // FEATURE_TYPEEQUIVALENCE
393
394     if (pOldMT->IsInterface() && IsImplicitInterfaceOfSZArray(pOldMT))
395     {
396         // Determine if we are creating an interface methodtable that may be used to dispatch through VSD
397         // on an array object using a generic interface (such as IList<T>).
398         // Please read comments in IsArray block of code:MethodTable::FindDispatchImpl. 
399         // 
400         // Arrays are special because we use the same method table (object[]) for all arrays of reference
401         // classes (eg string[]). This means that the method table for an array is not a complete description of 
402         // the type of the array and thus the target of if something list IList<T>::IndexOf can not be determined 
403         // simply by looking at the method table of T[] (which might be the method table of object[], if T is a
404         // reference type).   
405         //
406         // This is done to minimize MethodTables, but as a side-effect of this optimization,
407         // we end up using a domain-shared type (object[]) with a domain-specific dispatch token.
408         // This is a problem because the same domain-specific dispatch token value can appear in
409         // multiple unshared domains (VSD takes advantage of the fact that in general a shared type
410         // cannot implement an unshared interface). This means that the same <token, object[]> pair
411         // value can mean different things in different domains (since the token could represent
412         // IList<Foo> in one domain and IEnumerable<Bar> in another). This is a problem because the
413         // VSD polymorphic lookup mechanism relies on a process-wide cache table, and as a result
414         // these duplicate values would collide if we didn't use fat dispatch token to ensure uniqueness
415         // and the interface methodtable is not in the shared domain.
416         //
417         // Of note: there is also some interesting array-specific behaviour where if B inherits from A
418         // and you have an array of B (B[]) then B[] implements IList<B> and IList<A>, but a dispatch
419         // on an IList<A> reference results in a dispatch to SZArrayHelper<A> rather than
420         // SZArrayHelper<B> (i.e., the variance implemention is not done like virtual methods).
421         //    
422         // For example If Sub inherits from Super inherits from Object, then 
423         //     * Sub[] implements IList<Super>
424         //     * Sub[] implements IList<Sub>
425         // 
426         // And as a result we have the following mappings:
427         //     * IList<Super>::IndexOf for Sub[] goes to SZArrayHelper<Super>::IndexOf
428         //     * IList<Sub>::IndexOf for Sub[] goes to SZArrayHelper<Sub>::IndexOf
429         //
430         pMT->SetRequiresFatDispatchTokens();
431     }
432
433     // Number of slots only includes vtable slots
434     pMT->SetNumVirtuals(cSlots);
435
436     // Fill out the vtable indirection slots
437     MethodTable::VtableIndirectionSlotIterator it = pMT->IterateVtableIndirectionSlots();
438     while (it.Next())
439     {
440         if (canShareVtableChunks)
441         {
442             // Share the canonical chunk
443             it.SetIndirectionSlot(pOldMT->GetVtableIndirections()[it.GetIndex()].GetValueMaybeNull());
444         }
445         else
446         {
447             // Use the locally allocated chunk
448             it.SetIndirectionSlot((PTR_PCODE)(pMemory+offsetOfUnsharedVtableChunks));
449             offsetOfUnsharedVtableChunks += it.GetSize();
450         }
451     }
452
453     // If we are not sharing parent chunks, copy down the slot contents
454     if (!canShareVtableChunks)
455     {
456         // Need to assign the slots one by one to filter out jump thunks
457         for (DWORD i = 0; i < cSlots; i++)
458         {
459             pMT->SetSlot(i, pOldMT->GetRestoredSlot(i));
460         }
461     }
462
463     // All flags on m_pNgenPrivateData data apart
464     // are initially false for a dynamically generated instantiation.
465     //
466     // Last time this was checked this included
467     //    enum_flag_RemotingConfigChecked
468     //    enum_flag_RequiresManagedActivation
469     //    enum_flag_Unrestored
470     //    enum_flag_CriticalTypePrepared
471 #ifdef FEATURE_PREJIT
472     //    enum_flag_NGEN_IsFixedUp
473     //    enum_flag_NGEN_NeedsRestoreCached
474     //    enum_flag_NGEN_NeedsRestore
475 #endif // FEATURE_PREJIT
476
477     if (pOldMT->RequiresManagedActivation())
478     {
479         // Will also set enum_flag_RemotingConfigChecked
480         pMT->SetRequiresManagedActivation();
481     }
482
483     if (fContainsGenericVariables)
484         pMT->SetContainsGenericVariables();
485
486     if (fHasGenericsStaticsInfo)
487         pMT->SetDynamicStatics(TRUE);
488
489
490 #ifdef FEATURE_COMINTEROP
491     if (fHasCCWTemplate)
492         pMT->SetHasCCWTemplate();
493     if (fHasGuidInfo)
494         pMT->SetHasGuidInfo();
495 #endif 
496
497     // Since we are fabricating a new MT based on an existing one, the per-inst info should
498     // be non-null
499     _ASSERTE(pOldMT->HasPerInstInfo());
500
501     // Fill in per-inst map pointer (which points to the array of generic dictionary pointers)
502     pMT->SetPerInstInfo((MethodTable::PerInstInfoElem_t *) (pMemory + cbMT + cbOptional + cbIMap + sizeof(GenericsDictInfo)));
503     _ASSERTE(FitsIn<WORD>(pOldMT->GetNumDicts()));
504     _ASSERTE(FitsIn<WORD>(pOldMT->GetNumGenericArgs()));
505     pMT->SetDictInfo(static_cast<WORD>(pOldMT->GetNumDicts()), static_cast<WORD>(pOldMT->GetNumGenericArgs()));
506
507     // Fill in the last entry in the array of generic dictionary pointers ("per inst info")
508     // The others are filled in by LoadExactParents which copied down any inherited generic
509     // dictionary pointers.
510     Dictionary * pDict = (Dictionary*) (pMemory + cbMT + cbOptional + cbIMap + cbPerInst);
511     MethodTable::PerInstInfoElem_t *pPInstInfo = (MethodTable::PerInstInfoElem_t *) (pMT->GetPerInstInfo() + (pOldMT->GetNumDicts()-1));
512     pPInstInfo->SetValueMaybeNull(pDict);
513
514     // Fill in the instantiation section of the generic dictionary.  The remainder of the
515     // generic dictionary will be zeroed, which is the correct initial state.
516     TypeHandle * pInstDest = (TypeHandle *)pDict->GetInstantiation();
517     for (DWORD iArg = 0; iArg < ntypars; iArg++)
518     {
519         pInstDest[iArg] = inst[iArg];
520     }
521
522     // Copy interface map across
523     InterfaceInfo_t * pInterfaceMap = (InterfaceInfo_t *)(pMemory + cbMT + cbOptional + (fHasDynamicInterfaceMap ? sizeof(DWORD_PTR) : 0));
524
525 #ifdef FEATURE_COMINTEROP
526     // Extensible RCW's are prefixed with the count of dynamic interfaces.
527     if (fHasDynamicInterfaceMap)
528     {
529         *(((DWORD_PTR *)pInterfaceMap) - 1) = 0;
530     }
531 #endif // FEATURE_COMINTEROP
532
533     for (WORD iItf = 0; iItf < wNumInterfaces; iItf++)
534     {
535         OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
536         pInterfaceMap[iItf].SetMethodTable(pOldIMap[iItf].GetApproxMethodTable(pOldMT->GetLoaderModule()));
537     }
538
539     // Set the interface map pointer stored in the main section of the vtable (actually
540     // an optional member) to point to the correct region within the newly
541     // allocated method table.
542
543     // Fill in interface map pointer
544     pMT->SetInterfaceMap(wNumInterfaces, pInterfaceMap);
545
546     // Copy across extra flags for these interfaces as well. We may need additional memory for this.
547     PVOID pExtraInterfaceInfo = NULL;
548     SIZE_T cbExtraInterfaceInfo = MethodTable::GetExtraInterfaceInfoSize(wNumInterfaces);
549     if (cbExtraInterfaceInfo)
550         pExtraInterfaceInfo = pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(cbExtraInterfaceInfo)));
551
552     // Call this even in the case where pExtraInterfaceInfo == NULL (certain cases are optimized and don't
553     // require extra buffer space).
554     pMT->InitializeExtraInterfaceInfo(pExtraInterfaceInfo);
555
556     for (UINT32 i = 0; i < pOldMT->GetNumInterfaces(); i++)
557     {
558         if (pOldMT->IsInterfaceDeclaredOnClass(i))
559             pMT->SetInterfaceDeclaredOnClass(i);
560     }
561
562     pMT->SetLoaderModule(pLoaderModule);
563     pMT->SetLoaderAllocator(pAllocator);
564     
565     
566 #ifdef _DEBUG 
567     // Name for debugging
568     StackSString debug_ClassNameString;
569     TypeString::AppendTypeKey(debug_ClassNameString, pTypeKey, TypeString::FormatNamespace | TypeString::FormatAngleBrackets | TypeString::FormatFullInst);
570     StackScratchBuffer debug_ClassNameBuffer;
571     const char *debug_szClassNameBuffer = debug_ClassNameString.GetUTF8(debug_ClassNameBuffer);
572     S_SIZE_T safeLen = S_SIZE_T(strlen(debug_szClassNameBuffer)) + S_SIZE_T(1);
573     if (safeLen.IsOverflow()) COMPlusThrowHR(COR_E_OVERFLOW);
574     
575     size_t len = safeLen.Value();
576     char *debug_szClassName = (char *)pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(safeLen));
577     strcpy_s(debug_szClassName, len, debug_szClassNameBuffer);
578     pMT->SetDebugClassName(debug_szClassName);
579     
580     // Debugging information
581     if (pOldMT->Debug_HasInjectedInterfaceDuplicates())
582         pMT->Debug_SetHasInjectedInterfaceDuplicates();
583 #endif // _DEBUG
584     
585     // <NICE>This logic is identical to logic in class.cpp.  Factor these out.</NICE>
586     // No need to generate IDs for open types.   However
587     // we still leave the optional member in the MethodTable holding the value -1 for the ID.
588     if (fHasGenericsStaticsInfo)
589     {
590         FieldDesc* pStaticFieldDescs = NULL;
591
592         if (pOldMT->GetNumStaticFields() != 0)
593         {
594             pStaticFieldDescs = (FieldDesc*) pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(FieldDesc)) * S_SIZE_T(pOldMT->GetNumStaticFields())));
595             FieldDesc* pOldFD = pOldMT->GetGenericsStaticFieldDescs();
596
597             g_IBCLogger.LogFieldDescsAccess(pOldFD);
598
599             for (DWORD i = 0; i < pOldMT->GetNumStaticFields(); i++)
600             {
601                 pStaticFieldDescs[i].InitializeFrom(pOldFD[i], pMT);
602             }
603         }
604         pMT->SetupGenericsStaticsInfo(pStaticFieldDescs);
605     }
606
607
608     // VTS info doesn't depend on the exact instantiation but we make a copy
609     // anyway since we can't currently deal with the possibility of having a
610     // cross module pointer to the data block. Eventually we might be able to
611     // tokenize this reference, but determine first whether there's enough
612     // performance degradation to justify the extra complexity.
613
614     pMT->SetCl(pOldMT->GetCl());
615     
616     // Check we've set up the flags correctly on the new method table
617     _ASSERTE(!fContainsGenericVariables == !pMT->ContainsGenericVariables());
618     _ASSERTE(!fHasGenericsStaticsInfo == !pMT->HasGenericsStaticsInfo());
619     _ASSERTE(!pLoaderModule->GetAssembly()->IsDomainNeutral() == !pMT->IsDomainNeutral());
620 #ifdef FEATURE_COMINTEROP
621     _ASSERTE(!fHasDynamicInterfaceMap == !pMT->HasDynamicInterfaceMap());
622     _ASSERTE(!fHasRCWPerTypeData == !pMT->HasRCWPerTypeData());
623     _ASSERTE(!fHasCCWTemplate == !pMT->HasCCWTemplate());
624     _ASSERTE(!fHasGuidInfo == !pMT->HasGuidInfo());
625 #endif
626
627     LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Replicated methodtable to create type %s\n", pMT->GetDebugClassName()));
628     
629 #ifdef _DEBUG 
630     if (g_pConfig->ShouldDumpOnClassLoad(debug_szClassName))
631     {
632         LOG((LF_ALWAYS, LL_ALWAYS, 
633             "Method table summary for '%s' (instantiation):\n", 
634             pMT->GetDebugClassName()));
635         pMT->Debug_DumpInterfaceMap("Approximate");
636     }
637 #endif //_DEBUG
638     
639 #ifdef FEATURE_PREJIT
640     _ASSERTE(pComputedPZM == Module::GetPreferredZapModuleForMethodTable(pMT));
641 #endif //FEATURE_PREJIT
642     
643     // We never have non-virtual slots in this method table (set SetNumVtableSlots and SetNumVirtuals above)
644     _ASSERTE(!pMT->HasNonVirtualSlots());
645
646     pMTWriteableData->SetIsRestoredForBuildMethodTable();
647     
648     RETURN(TypeHandle(pMT));
649 } // ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation
650
651 namespace Generics
652 {
653
654 BOOL CheckInstantiation(Instantiation inst)
655 {
656     CONTRACTL
657     {
658         NOTHROW;
659         GC_NOTRIGGER;
660     }
661     CONTRACTL_END
662
663     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
664     {
665         TypeHandle th = inst[i];
666         if (th.IsNull())
667         {
668             return FALSE;
669         }
670
671         CorElementType type = th.GetSignatureCorElementType();
672         if (CorTypeInfo::IsGenericVariable_NoThrow(type))
673         {
674             return TRUE;
675         }
676
677         g_IBCLogger.LogTypeMethodTableAccess(&th);
678
679         if (   type == ELEMENT_TYPE_BYREF
680             || type == ELEMENT_TYPE_TYPEDBYREF
681             || type == ELEMENT_TYPE_VOID
682             || type == ELEMENT_TYPE_PTR
683             || type == ELEMENT_TYPE_FNPTR)
684         {
685             return FALSE;
686         }
687
688         MethodTable* pMT = th.GetMethodTable();
689         if (pMT != NULL)
690         {
691             if (pMT->IsByRefLike())
692             {
693                 return FALSE;
694             }
695         }
696     }
697     return TRUE;
698 }
699
700 // Just records the owner and links to the previous graph.
701 RecursionGraph::RecursionGraph(RecursionGraph *pPrev, TypeHandle thOwner)
702 {
703     LIMITED_METHOD_CONTRACT;
704
705     m_pPrev   = pPrev;
706     m_thOwner = thOwner;
707     
708     m_pNodes  = NULL;
709 }
710
711 RecursionGraph::~RecursionGraph()
712 {
713     WRAPPER_NO_CONTRACT;
714     if (m_pNodes != NULL)
715         delete [] m_pNodes;
716 }
717
718 // Adds edges generated by the parent and implemented interfaces; returns TRUE iff
719 // an expanding cycle was found.
720 BOOL RecursionGraph::CheckForIllegalRecursion()
721 {
722     CONTRACTL
723     {
724         THROWS;
725         GC_TRIGGERS;
726         PRECONDITION(!m_thOwner.IsTypeDesc());
727     }
728     CONTRACTL_END;
729
730     MethodTable *pMT = m_thOwner.AsMethodTable();
731
732     Instantiation inst = pMT->GetInstantiation();
733     
734     // Initialize the node array.
735     m_pNodes = new Node[inst.GetNumArgs()];
736
737     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
738     {
739         m_pNodes[i].SetSourceVar(inst[i].AsGenericVariable());
740     }
741
742     // Record edges generated by inheriting from the parent.
743     MethodTable *pParentMT = pMT->GetParentMethodTable();
744     if (pParentMT)
745     {
746         AddDependency(pParentMT);
747     }
748
749     // Record edges generated by implementing interfaces.
750     MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap();
751     while (it.Next())
752     {
753         AddDependency(it.GetInterface());
754     }
755
756     // Check all owned nodes for expanding cycles. The edges recorded above must all
757     // go from owned nodes so it suffices to look only at these.
758     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
759     {
760         if (HasExpandingCycle(&m_pNodes[i], &m_pNodes[i]))
761             return TRUE;
762     }
763
764     return FALSE;
765 }
766
767 // Returns TRUE iff the given type is already on the stack (in fact an analogue of
768 // code:TypeHandleList::Exists).
769 // 
770 // static
771 BOOL RecursionGraph::HasSeenType(RecursionGraph *pDepGraph, TypeHandle thType)
772 {
773     LIMITED_METHOD_CONTRACT;
774
775     while (pDepGraph != NULL)
776     {
777         if (pDepGraph->m_thOwner == thType) return TRUE;
778         pDepGraph = pDepGraph->m_pPrev;
779     }
780     return FALSE;
781 }
782
783 // Adds the specified MT as a dependency (parent or interface) of the owner.
784 void RecursionGraph::AddDependency(MethodTable *pMT, TypeHandleList *pExpansionVars /*= NULL*/)
785 {
786     CONTRACTL
787     {
788         THROWS;
789         GC_TRIGGERS;
790         PRECONDITION(pMT != NULL);
791     }
792     CONTRACTL_END
793
794     // ECMA:
795     // - If T appears as the actual type argument to be substituted for U in some referenced
796     //   type D<..., U, ...> add a non-expanding (->) edge from T to U.
797     // - If T appears somewhere inside (but not as) the actual type argument to be substituted
798     //   for U in referenced type D<..., U, ...> add an expanding (=>) edge from T to U.
799
800     // Non-generic dependencies are not interesting.
801     if (!pMT->HasInstantiation())
802         return;
803
804     // Get the typical instantiation of pMT to figure out its type vars.
805     TypeHandle thTypical = ClassLoader::LoadTypeDefThrowing(
806         pMT->GetModule(), pMT->GetCl(),
807         ClassLoader::ThrowIfNotFound,
808         ClassLoader::PermitUninstDefOrRef, tdNoTypes,
809         CLASS_LOAD_APPROXPARENTS);
810
811     Instantiation inst = pMT->GetInstantiation();
812     Instantiation typicalInst = thTypical.GetInstantiation();
813
814     _ASSERTE(inst.GetNumArgs() == typicalInst.GetNumArgs());
815
816     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
817     {
818         TypeHandle thArg = inst[i];
819         TypeHandle thVar = typicalInst[i];
820         if (thArg.IsGenericVariable())
821         {
822             // Add a non-expanding edge from thArg to i-th generic parameter of pMT.
823             AddEdge(thArg.AsGenericVariable(), thVar.AsGenericVariable(), FALSE);
824
825             // Process the backlog.
826             TypeHandle thTo;
827             TypeHandleList *pList = pExpansionVars;
828             while (TypeHandleList::GetNext(&pList, &thTo))
829             {
830                 AddEdge(thArg.AsGenericVariable(), thTo.AsGenericVariable(), TRUE);
831             }
832         }
833         else
834         {
835             while (thArg.IsTypeDesc())
836             {
837                 _ASSERTE(thArg.HasTypeParam());
838                 thArg = (static_cast<PTR_ParamTypeDesc>(thArg.AsTypeDesc()))->GetModifiedType();
839
840                 if (thArg.IsGenericVariable()) // : A<!T[]>
841                 {
842                     // Add an expanding edge from thArg to i-th parameter of pMT.
843                     AddEdge(thArg.AsGenericVariable(), thVar.AsGenericVariable(), TRUE);
844                     break;
845                 }
846             }
847
848             if (!thArg.IsTypeDesc()) // : A<B<!T>>
849             {
850                 // We will add an expanding edge but we do not yet know from which variable(s).
851                 // Add the to-variable to the list and call recursively to inspect thArg's
852                 // instantiation.
853                 TypeHandleList newExpansionVars(thVar, pExpansionVars);
854                 AddDependency(thArg.AsMethodTable(), &newExpansionVars);
855             }
856         }
857     }
858 }
859
860 // Add an edge from pFromVar to pToVar - either non-expanding or expanding.
861 void RecursionGraph::AddEdge(TypeVarTypeDesc *pFromVar, TypeVarTypeDesc *pToVar, BOOL fExpanding)
862 {
863     CONTRACTL
864     {
865         THROWS;
866         GC_NOTRIGGER;
867         PRECONDITION(pFromVar != NULL);
868         PRECONDITION(pToVar != NULL);
869     }
870     CONTRACTL_END
871
872     LOG((LF_CLASSLOADER, LL_INFO10000, "GENERICS: Adding %s edge: from %x(0x%x) to %x(0x%x) into recursion graph owned by MT: %x\n",
873         (fExpanding ? "EXPANDING" : "NON-EXPANDING"),
874         pFromVar->GetToken(), pFromVar->GetModule(),
875         pToVar->GetToken(), pToVar->GetModule(),
876         m_thOwner.AsMethodTable()));
877
878     // Get the source node.
879     Node *pNode = &m_pNodes[pFromVar->GetIndex()];
880     _ASSERTE(pFromVar == pNode->GetSourceVar());
881
882     // Add the edge.
883     ULONG_PTR edge = (ULONG_PTR)pToVar;
884     if (fExpanding) edge |= Node::EDGE_EXPANDING_FLAG;
885
886     IfFailThrow(pNode->GetEdges()->Append((void *)edge));
887 }
888
889 // Recursive worker that checks whether this node is part of an expanding cycle.
890 BOOL RecursionGraph::HasExpandingCycle(Node *pCurrentNode, Node *pStartNode, BOOL fExpanded /*= FALSE*/)
891 {
892     CONTRACTL
893     {
894         NOTHROW;
895         GC_NOTRIGGER;
896         PRECONDITION(CheckPointer(pCurrentNode));
897         PRECONDITION(CheckPointer(pStartNode));
898     }
899     CONTRACTL_END;
900
901     // This method performs a modified DFS. We are not looking for any cycle but for a cycle
902     // which has at least one expanding edge. Therefore we:
903     // 1) Pass aroung the fExpanded flag to indicate that we've seen an expanding edge.
904     // 2) Explicitly check for returning to the starting point rather an arbitrary visited node.
905
906     // Did we just find the cycle?
907     if (fExpanded && pCurrentNode == pStartNode)
908         return TRUE;
909
910     // Have we been here before or is this a dead end?
911     if (pCurrentNode->IsVisited() || pCurrentNode->GetEdges()->GetCount() == 0)
912         return FALSE;
913
914     pCurrentNode->SetVisited();
915
916     ArrayList::Iterator iter = pCurrentNode->GetEdges()->Iterate();
917     while (iter.Next())  
918     {
919         ULONG_PTR edge = (ULONG_PTR)iter.GetElement();
920
921         BOOL fExpanding = (edge & Node::EDGE_EXPANDING_FLAG);
922         
923         TypeVarTypeDesc *pToVar = (TypeVarTypeDesc *)(edge & ~Node::EDGE_EXPANDING_FLAG);
924         unsigned int dwIndex = pToVar->GetIndex();
925
926         Node *pNode = NULL;
927         RecursionGraph *pGraph = this;
928
929         // Find the destination node.
930         do
931         {
932             if (pGraph->m_pNodes != NULL &&
933                 dwIndex < pGraph->m_thOwner.GetNumGenericArgs() &&
934                 pGraph->m_pNodes[dwIndex].GetSourceVar() == pToVar)
935             {
936                 pNode = &pGraph->m_pNodes[dwIndex];
937                 break;
938             }
939             pGraph = pGraph->m_pPrev;
940         }
941         while (pGraph != NULL);
942
943         if (pNode != NULL)
944         {
945             // The new path is expanding if it was expanding already or if the edge we follow is expanding.
946             if (HasExpandingCycle(pNode, pStartNode, fExpanded || fExpanding))
947                 return TRUE;
948         }
949     }
950     
951     pCurrentNode->ClearVisited();
952
953     return FALSE;
954 }
955
956 } // namespace Generics
957
958 #endif // !DACCESS_COMPILE
959
960 namespace Generics
961 {
962
963 /*
964  * GetExactInstantiationsOfMethodAndItsClassFromCallInformation
965  *
966  * This routine takes in the various pieces of information of a call site to managed code
967  * and returns the exact instatiations for the method and the class on which the method is defined.
968  *
969  * Parameters:
970  *    pRepMethod - A MethodDesc to the representative instantiation method.
971  *    pThis - The OBJECTREF that is being passed to pRepMethod.
972  *    pParamTypeArg - The extra argument passed to pRepMethod when pRepMethod is either
973  *       RequiresInstMethodTableArg() or RequiresInstMethodDescArg().
974  *    pSpecificClass - A pointer to a TypeHandle for storing the exact instantiation
975  *       of the class on which pRepMethod is defined, based on the call information
976  *    pSpecificMethod - A pointer to a MethodDesc* for storing the exact instantiation
977  *       of pRepMethod, based on the call information
978  *
979  * Returns:
980  *    TRUE if successful.
981  *    FALSE if could not get the exact TypeHandle & MethodDesc requested.  In this case,
982  *      the SpecificClass may be correct, iff the class is not a generic class.
983  *
984  */
985 BOOL GetExactInstantiationsOfMethodAndItsClassFromCallInformation(
986     /* in */  MethodDesc *pRepMethod,
987     /* in */  OBJECTREF pThis,
988     /* in */  PTR_VOID pParamTypeArg,
989     /* out*/  TypeHandle *pSpecificClass,
990     /* out*/  MethodDesc** pSpecificMethod
991     )
992 {
993     CONTRACTL
994     {
995         NOTHROW;
996         GC_NOTRIGGER;
997         SO_TOLERANT;
998         CANNOT_TAKE_LOCK;
999         PRECONDITION(CheckPointer(pRepMethod));
1000         SUPPORTS_DAC;
1001     }
1002     CONTRACTL_END;
1003      
1004     PTR_VOID pExactGenericArgsToken = NULL;
1005
1006     if (pRepMethod->AcquiresInstMethodTableFromThis())
1007     {
1008         if (pThis != NULL)
1009         {
1010             // We could be missing the memory from a dump, or the target could have simply been corrupted.
1011             ALLOW_DATATARGET_MISSING_MEMORY(
1012                 pExactGenericArgsToken = dac_cast<PTR_VOID>(pThis->GetMethodTable());
1013             );
1014         }
1015     }
1016     else        
1017     {
1018         pExactGenericArgsToken = pParamTypeArg;
1019     }
1020
1021     return GetExactInstantiationsOfMethodAndItsClassFromCallInformation(pRepMethod, pExactGenericArgsToken, 
1022         pSpecificClass, pSpecificMethod);      
1023 }
1024
1025 BOOL GetExactInstantiationsOfMethodAndItsClassFromCallInformation(
1026     /* in */  MethodDesc *pRepMethod,
1027     /* in */  PTR_VOID pExactGenericArgsToken,
1028     /* out*/  TypeHandle *pSpecificClass,
1029     /* out*/  MethodDesc** pSpecificMethod
1030     )
1031 {
1032     CONTRACTL
1033     {
1034         NOTHROW;
1035         GC_NOTRIGGER;
1036         SO_TOLERANT;
1037         CANNOT_TAKE_LOCK;
1038         PRECONDITION(CheckPointer(pRepMethod));
1039         SUPPORTS_DAC;
1040     }
1041     CONTRACTL_END;
1042
1043     //
1044     // Start with some decent default values.
1045     //
1046     MethodDesc * pMD = pRepMethod;
1047     MethodTable * pMT = pRepMethod->GetMethodTable();
1048
1049     *pSpecificMethod = pMD;
1050     *pSpecificClass = pMT;
1051
1052     if (!pRepMethod->IsSharedByGenericInstantiations())
1053     {
1054         return TRUE;
1055     }
1056
1057     if (pExactGenericArgsToken == NULL)
1058     {
1059         return FALSE;
1060     }
1061
1062     BOOL retVal = FALSE;
1063
1064     // The following target memory reads will not necessarily succeed against dumps, and will throw on failure.
1065     EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY
1066     {
1067         if (pRepMethod->RequiresInstMethodTableArg())
1068         {
1069             pMT = dac_cast<PTR_MethodTable>(pExactGenericArgsToken);
1070             retVal = TRUE;
1071         }
1072         else if (pRepMethod->RequiresInstMethodDescArg())
1073         {
1074             pMD = dac_cast<PTR_MethodDesc>(pExactGenericArgsToken);
1075             pMT = pMD->GetMethodTable();
1076             retVal = TRUE;
1077         }
1078         else if (pRepMethod->AcquiresInstMethodTableFromThis())
1079         {
1080             // The exact token might actually be a child class of the class containing 
1081             // the specified function so walk up the parent chain to make sure we return 
1082             // an exact instantiation of the CORRECT parent class.
1083             pMT = pMD->GetExactDeclaringType(dac_cast<PTR_MethodTable>(pExactGenericArgsToken));
1084             _ASSERTE(pMT != NULL);
1085             retVal = TRUE;
1086         }
1087         else
1088         {
1089             _ASSERTE(!"Should not happen.");
1090         }
1091     }
1092     EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY
1093
1094     *pSpecificMethod = pMD;
1095     *pSpecificClass = pMT;
1096
1097     return retVal;
1098 }
1099
1100 } // namespace Generics;
1101