Remove relocations for vtable chunks (#17147)
[platform/upstream/coreclr.git] / 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(MethodTable::VTableIndir2_t) );
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->ClearFlag(MethodTable::enum_flag_HasIndirectParent);
368     pMT->m_pParentMethodTable.SetValueMaybeNull(NULL);
369
370     // Non non-virtual slots
371     pMT->ClearFlag(MethodTable::enum_flag_HasSingleNonVirtualSlot);
372
373     pMT->SetBaseSize(pOldMT->GetBaseSize());
374     pMT->SetParentMethodTable(pOldMT->GetParentMethodTable());
375     pMT->SetCanonicalMethodTable(pOldMT);
376
377     pMT->m_wNumInterfaces = pOldMT->m_wNumInterfaces;
378
379 #ifdef FEATURE_TYPEEQUIVALENCE 
380     if (pMT->IsInterface() && !pMT->HasTypeEquivalence())
381     {
382         // fHasTypeEquivalence flag is "inherited" from generic arguments so we can quickly detect
383         // types like IList<IFoo> where IFoo is an interface with the TypeIdentifierAttribute.
384         for (DWORD i = 0; i < ntypars; i++) 
385         {
386             if (inst[i].HasTypeEquivalence())
387             {
388                 pMT->SetHasTypeEquivalence();
389                 break;
390             }
391         }
392     }
393 #endif // FEATURE_TYPEEQUIVALENCE
394
395     if (pOldMT->IsInterface() && IsImplicitInterfaceOfSZArray(pOldMT))
396     {
397         // Determine if we are creating an interface methodtable that may be used to dispatch through VSD
398         // on an array object using a generic interface (such as IList<T>).
399         // Please read comments in IsArray block of code:MethodTable::FindDispatchImpl. 
400         // 
401         // Arrays are special because we use the same method table (object[]) for all arrays of reference
402         // classes (eg string[]). This means that the method table for an array is not a complete description of 
403         // the type of the array and thus the target of if something list IList<T>::IndexOf can not be determined 
404         // simply by looking at the method table of T[] (which might be the method table of object[], if T is a
405         // reference type).   
406         //
407         // This is done to minimize MethodTables, but as a side-effect of this optimization,
408         // we end up using a domain-shared type (object[]) with a domain-specific dispatch token.
409         // This is a problem because the same domain-specific dispatch token value can appear in
410         // multiple unshared domains (VSD takes advantage of the fact that in general a shared type
411         // cannot implement an unshared interface). This means that the same <token, object[]> pair
412         // value can mean different things in different domains (since the token could represent
413         // IList<Foo> in one domain and IEnumerable<Bar> in another). This is a problem because the
414         // VSD polymorphic lookup mechanism relies on a process-wide cache table, and as a result
415         // these duplicate values would collide if we didn't use fat dispatch token to ensure uniqueness
416         // and the interface methodtable is not in the shared domain.
417         //
418         // Of note: there is also some interesting array-specific behaviour where if B inherits from A
419         // and you have an array of B (B[]) then B[] implements IList<B> and IList<A>, but a dispatch
420         // on an IList<A> reference results in a dispatch to SZArrayHelper<A> rather than
421         // SZArrayHelper<B> (i.e., the variance implemention is not done like virtual methods).
422         //    
423         // For example If Sub inherits from Super inherits from Object, then 
424         //     * Sub[] implements IList<Super>
425         //     * Sub[] implements IList<Sub>
426         // 
427         // And as a result we have the following mappings:
428         //     * IList<Super>::IndexOf for Sub[] goes to SZArrayHelper<Super>::IndexOf
429         //     * IList<Sub>::IndexOf for Sub[] goes to SZArrayHelper<Sub>::IndexOf
430         //
431         pMT->SetRequiresFatDispatchTokens();
432     }
433
434     // Number of slots only includes vtable slots
435     pMT->SetNumVirtuals(cSlots);
436
437     // Fill out the vtable indirection slots
438     MethodTable::VtableIndirectionSlotIterator it = pMT->IterateVtableIndirectionSlots();
439     while (it.Next())
440     {
441         if (canShareVtableChunks)
442         {
443             // Share the canonical chunk
444             it.SetIndirectionSlot(pOldMT->GetVtableIndirections()[it.GetIndex()].GetValueMaybeNull());
445         }
446         else
447         {
448             // Use the locally allocated chunk
449             it.SetIndirectionSlot((MethodTable::VTableIndir2_t *)(pMemory+offsetOfUnsharedVtableChunks));
450             offsetOfUnsharedVtableChunks += it.GetSize();
451         }
452     }
453
454     // If we are not sharing parent chunks, copy down the slot contents
455     if (!canShareVtableChunks)
456     {
457         // Need to assign the slots one by one to filter out jump thunks
458         for (DWORD i = 0; i < cSlots; i++)
459         {
460             pMT->SetSlot(i, pOldMT->GetRestoredSlot(i));
461         }
462     }
463
464     // All flags on m_pNgenPrivateData data apart
465     // are initially false for a dynamically generated instantiation.
466     //
467     // Last time this was checked this included
468     //    enum_flag_RemotingConfigChecked
469     //    enum_flag_RequiresManagedActivation
470     //    enum_flag_Unrestored
471     //    enum_flag_CriticalTypePrepared
472 #ifdef FEATURE_PREJIT
473     //    enum_flag_NGEN_IsFixedUp
474     //    enum_flag_NGEN_NeedsRestoreCached
475     //    enum_flag_NGEN_NeedsRestore
476 #endif // FEATURE_PREJIT
477
478     if (pOldMT->RequiresManagedActivation())
479     {
480         // Will also set enum_flag_RemotingConfigChecked
481         pMT->SetRequiresManagedActivation();
482     }
483
484     if (fContainsGenericVariables)
485         pMT->SetContainsGenericVariables();
486
487     if (fHasGenericsStaticsInfo)
488         pMT->SetDynamicStatics(TRUE);
489
490
491 #ifdef FEATURE_COMINTEROP
492     if (fHasCCWTemplate)
493         pMT->SetHasCCWTemplate();
494     if (fHasGuidInfo)
495         pMT->SetHasGuidInfo();
496 #endif 
497
498     // Since we are fabricating a new MT based on an existing one, the per-inst info should
499     // be non-null
500     _ASSERTE(pOldMT->HasPerInstInfo());
501
502     // Fill in per-inst map pointer (which points to the array of generic dictionary pointers)
503     pMT->SetPerInstInfo((MethodTable::PerInstInfoElem_t *) (pMemory + cbMT + cbOptional + cbIMap + sizeof(GenericsDictInfo)));
504     _ASSERTE(FitsIn<WORD>(pOldMT->GetNumDicts()));
505     _ASSERTE(FitsIn<WORD>(pOldMT->GetNumGenericArgs()));
506     pMT->SetDictInfo(static_cast<WORD>(pOldMT->GetNumDicts()), static_cast<WORD>(pOldMT->GetNumGenericArgs()));
507
508     // Fill in the last entry in the array of generic dictionary pointers ("per inst info")
509     // The others are filled in by LoadExactParents which copied down any inherited generic
510     // dictionary pointers.
511     Dictionary * pDict = (Dictionary*) (pMemory + cbMT + cbOptional + cbIMap + cbPerInst);
512     MethodTable::PerInstInfoElem_t *pPInstInfo = (MethodTable::PerInstInfoElem_t *) (pMT->GetPerInstInfo() + (pOldMT->GetNumDicts()-1));
513     pPInstInfo->SetValueMaybeNull(pDict);
514
515     // Fill in the instantiation section of the generic dictionary.  The remainder of the
516     // generic dictionary will be zeroed, which is the correct initial state.
517     TypeHandle * pInstDest = (TypeHandle *)pDict->GetInstantiation();
518     for (DWORD iArg = 0; iArg < ntypars; iArg++)
519     {
520         pInstDest[iArg] = inst[iArg];
521     }
522
523     // Copy interface map across
524     InterfaceInfo_t * pInterfaceMap = (InterfaceInfo_t *)(pMemory + cbMT + cbOptional + (fHasDynamicInterfaceMap ? sizeof(DWORD_PTR) : 0));
525
526 #ifdef FEATURE_COMINTEROP
527     // Extensible RCW's are prefixed with the count of dynamic interfaces.
528     if (fHasDynamicInterfaceMap)
529     {
530         *(((DWORD_PTR *)pInterfaceMap) - 1) = 0;
531     }
532 #endif // FEATURE_COMINTEROP
533
534     for (WORD iItf = 0; iItf < wNumInterfaces; iItf++)
535     {
536         OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_APPROXPARENTS);
537         pInterfaceMap[iItf].SetMethodTable(pOldIMap[iItf].GetApproxMethodTable(pOldMT->GetLoaderModule()));
538     }
539
540     // Set the interface map pointer stored in the main section of the vtable (actually
541     // an optional member) to point to the correct region within the newly
542     // allocated method table.
543
544     // Fill in interface map pointer
545     pMT->SetInterfaceMap(wNumInterfaces, pInterfaceMap);
546
547     // Copy across extra flags for these interfaces as well. We may need additional memory for this.
548     PVOID pExtraInterfaceInfo = NULL;
549     SIZE_T cbExtraInterfaceInfo = MethodTable::GetExtraInterfaceInfoSize(wNumInterfaces);
550     if (cbExtraInterfaceInfo)
551         pExtraInterfaceInfo = pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(cbExtraInterfaceInfo)));
552
553     // Call this even in the case where pExtraInterfaceInfo == NULL (certain cases are optimized and don't
554     // require extra buffer space).
555     pMT->InitializeExtraInterfaceInfo(pExtraInterfaceInfo);
556
557     for (UINT32 i = 0; i < pOldMT->GetNumInterfaces(); i++)
558     {
559         if (pOldMT->IsInterfaceDeclaredOnClass(i))
560             pMT->SetInterfaceDeclaredOnClass(i);
561     }
562
563     pMT->SetLoaderModule(pLoaderModule);
564     pMT->SetLoaderAllocator(pAllocator);
565     
566     
567 #ifdef _DEBUG 
568     // Name for debugging
569     StackSString debug_ClassNameString;
570     TypeString::AppendTypeKey(debug_ClassNameString, pTypeKey, TypeString::FormatNamespace | TypeString::FormatAngleBrackets | TypeString::FormatFullInst);
571     StackScratchBuffer debug_ClassNameBuffer;
572     const char *debug_szClassNameBuffer = debug_ClassNameString.GetUTF8(debug_ClassNameBuffer);
573     S_SIZE_T safeLen = S_SIZE_T(strlen(debug_szClassNameBuffer)) + S_SIZE_T(1);
574     if (safeLen.IsOverflow()) COMPlusThrowHR(COR_E_OVERFLOW);
575     
576     size_t len = safeLen.Value();
577     char *debug_szClassName = (char *)pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(safeLen));
578     strcpy_s(debug_szClassName, len, debug_szClassNameBuffer);
579     pMT->SetDebugClassName(debug_szClassName);
580     
581     // Debugging information
582     if (pOldMT->Debug_HasInjectedInterfaceDuplicates())
583         pMT->Debug_SetHasInjectedInterfaceDuplicates();
584 #endif // _DEBUG
585     
586     // <NICE>This logic is identical to logic in class.cpp.  Factor these out.</NICE>
587     // No need to generate IDs for open types.   However
588     // we still leave the optional member in the MethodTable holding the value -1 for the ID.
589     if (fHasGenericsStaticsInfo)
590     {
591         FieldDesc* pStaticFieldDescs = NULL;
592
593         if (pOldMT->GetNumStaticFields() != 0)
594         {
595             pStaticFieldDescs = (FieldDesc*) pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(FieldDesc)) * S_SIZE_T(pOldMT->GetNumStaticFields())));
596             FieldDesc* pOldFD = pOldMT->GetGenericsStaticFieldDescs();
597
598             g_IBCLogger.LogFieldDescsAccess(pOldFD);
599
600             for (DWORD i = 0; i < pOldMT->GetNumStaticFields(); i++)
601             {
602                 pStaticFieldDescs[i].InitializeFrom(pOldFD[i], pMT);
603             }
604         }
605         pMT->SetupGenericsStaticsInfo(pStaticFieldDescs);
606     }
607
608
609     // VTS info doesn't depend on the exact instantiation but we make a copy
610     // anyway since we can't currently deal with the possibility of having a
611     // cross module pointer to the data block. Eventually we might be able to
612     // tokenize this reference, but determine first whether there's enough
613     // performance degradation to justify the extra complexity.
614
615     pMT->SetCl(pOldMT->GetCl());
616     
617     // Check we've set up the flags correctly on the new method table
618     _ASSERTE(!fContainsGenericVariables == !pMT->ContainsGenericVariables());
619     _ASSERTE(!fHasGenericsStaticsInfo == !pMT->HasGenericsStaticsInfo());
620     _ASSERTE(!pLoaderModule->GetAssembly()->IsDomainNeutral() == !pMT->IsDomainNeutral());
621 #ifdef FEATURE_COMINTEROP
622     _ASSERTE(!fHasDynamicInterfaceMap == !pMT->HasDynamicInterfaceMap());
623     _ASSERTE(!fHasRCWPerTypeData == !pMT->HasRCWPerTypeData());
624     _ASSERTE(!fHasCCWTemplate == !pMT->HasCCWTemplate());
625     _ASSERTE(!fHasGuidInfo == !pMT->HasGuidInfo());
626 #endif
627
628     LOG((LF_CLASSLOADER, LL_INFO1000, "GENERICS: Replicated methodtable to create type %s\n", pMT->GetDebugClassName()));
629     
630 #ifdef _DEBUG 
631     if (g_pConfig->ShouldDumpOnClassLoad(debug_szClassName))
632     {
633         LOG((LF_ALWAYS, LL_ALWAYS, 
634             "Method table summary for '%s' (instantiation):\n", 
635             pMT->GetDebugClassName()));
636         pMT->Debug_DumpInterfaceMap("Approximate");
637     }
638 #endif //_DEBUG
639     
640 #ifdef FEATURE_PREJIT
641     _ASSERTE(pComputedPZM == Module::GetPreferredZapModuleForMethodTable(pMT));
642 #endif //FEATURE_PREJIT
643     
644     // We never have non-virtual slots in this method table (set SetNumVtableSlots and SetNumVirtuals above)
645     _ASSERTE(!pMT->HasNonVirtualSlots());
646
647     pMTWriteableData->SetIsRestoredForBuildMethodTable();
648     
649     RETURN(TypeHandle(pMT));
650 } // ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation
651
652 namespace Generics
653 {
654
655 BOOL CheckInstantiation(Instantiation inst)
656 {
657     CONTRACTL
658     {
659         NOTHROW;
660         GC_NOTRIGGER;
661     }
662     CONTRACTL_END
663
664     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
665     {
666         TypeHandle th = inst[i];
667         if (th.IsNull())
668         {
669             return FALSE;
670         }
671
672         CorElementType type = th.GetSignatureCorElementType();
673         if (CorTypeInfo::IsGenericVariable_NoThrow(type))
674         {
675             return TRUE;
676         }
677
678         g_IBCLogger.LogTypeMethodTableAccess(&th);
679
680         if (   type == ELEMENT_TYPE_BYREF
681             || type == ELEMENT_TYPE_TYPEDBYREF
682             || type == ELEMENT_TYPE_VOID
683             || type == ELEMENT_TYPE_PTR
684             || type == ELEMENT_TYPE_FNPTR)
685         {
686             return FALSE;
687         }
688
689         MethodTable* pMT = th.GetMethodTable();
690         if (pMT != NULL)
691         {
692             if (pMT->IsByRefLike())
693             {
694                 return FALSE;
695             }
696         }
697     }
698     return TRUE;
699 }
700
701 // Just records the owner and links to the previous graph.
702 RecursionGraph::RecursionGraph(RecursionGraph *pPrev, TypeHandle thOwner)
703 {
704     LIMITED_METHOD_CONTRACT;
705
706     m_pPrev   = pPrev;
707     m_thOwner = thOwner;
708     
709     m_pNodes  = NULL;
710 }
711
712 RecursionGraph::~RecursionGraph()
713 {
714     WRAPPER_NO_CONTRACT;
715     if (m_pNodes != NULL)
716         delete [] m_pNodes;
717 }
718
719 // Adds edges generated by the parent and implemented interfaces; returns TRUE iff
720 // an expanding cycle was found.
721 BOOL RecursionGraph::CheckForIllegalRecursion()
722 {
723     CONTRACTL
724     {
725         THROWS;
726         GC_TRIGGERS;
727         PRECONDITION(!m_thOwner.IsTypeDesc());
728     }
729     CONTRACTL_END;
730
731     MethodTable *pMT = m_thOwner.AsMethodTable();
732
733     Instantiation inst = pMT->GetInstantiation();
734     
735     // Initialize the node array.
736     m_pNodes = new Node[inst.GetNumArgs()];
737
738     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
739     {
740         m_pNodes[i].SetSourceVar(inst[i].AsGenericVariable());
741     }
742
743     // Record edges generated by inheriting from the parent.
744     MethodTable *pParentMT = pMT->GetParentMethodTable();
745     if (pParentMT)
746     {
747         AddDependency(pParentMT);
748     }
749
750     // Record edges generated by implementing interfaces.
751     MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap();
752     while (it.Next())
753     {
754         AddDependency(it.GetInterface());
755     }
756
757     // Check all owned nodes for expanding cycles. The edges recorded above must all
758     // go from owned nodes so it suffices to look only at these.
759     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
760     {
761         if (HasExpandingCycle(&m_pNodes[i], &m_pNodes[i]))
762             return TRUE;
763     }
764
765     return FALSE;
766 }
767
768 // Returns TRUE iff the given type is already on the stack (in fact an analogue of
769 // code:TypeHandleList::Exists).
770 // 
771 // static
772 BOOL RecursionGraph::HasSeenType(RecursionGraph *pDepGraph, TypeHandle thType)
773 {
774     LIMITED_METHOD_CONTRACT;
775
776     while (pDepGraph != NULL)
777     {
778         if (pDepGraph->m_thOwner == thType) return TRUE;
779         pDepGraph = pDepGraph->m_pPrev;
780     }
781     return FALSE;
782 }
783
784 // Adds the specified MT as a dependency (parent or interface) of the owner.
785 void RecursionGraph::AddDependency(MethodTable *pMT, TypeHandleList *pExpansionVars /*= NULL*/)
786 {
787     CONTRACTL
788     {
789         THROWS;
790         GC_TRIGGERS;
791         PRECONDITION(pMT != NULL);
792     }
793     CONTRACTL_END
794
795     // ECMA:
796     // - If T appears as the actual type argument to be substituted for U in some referenced
797     //   type D<..., U, ...> add a non-expanding (->) edge from T to U.
798     // - If T appears somewhere inside (but not as) the actual type argument to be substituted
799     //   for U in referenced type D<..., U, ...> add an expanding (=>) edge from T to U.
800
801     // Non-generic dependencies are not interesting.
802     if (!pMT->HasInstantiation())
803         return;
804
805     // Get the typical instantiation of pMT to figure out its type vars.
806     TypeHandle thTypical = ClassLoader::LoadTypeDefThrowing(
807         pMT->GetModule(), pMT->GetCl(),
808         ClassLoader::ThrowIfNotFound,
809         ClassLoader::PermitUninstDefOrRef, tdNoTypes,
810         CLASS_LOAD_APPROXPARENTS);
811
812     Instantiation inst = pMT->GetInstantiation();
813     Instantiation typicalInst = thTypical.GetInstantiation();
814
815     _ASSERTE(inst.GetNumArgs() == typicalInst.GetNumArgs());
816
817     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
818     {
819         TypeHandle thArg = inst[i];
820         TypeHandle thVar = typicalInst[i];
821         if (thArg.IsGenericVariable())
822         {
823             // Add a non-expanding edge from thArg to i-th generic parameter of pMT.
824             AddEdge(thArg.AsGenericVariable(), thVar.AsGenericVariable(), FALSE);
825
826             // Process the backlog.
827             TypeHandle thTo;
828             TypeHandleList *pList = pExpansionVars;
829             while (TypeHandleList::GetNext(&pList, &thTo))
830             {
831                 AddEdge(thArg.AsGenericVariable(), thTo.AsGenericVariable(), TRUE);
832             }
833         }
834         else
835         {
836             while (thArg.IsTypeDesc())
837             {
838                 _ASSERTE(thArg.HasTypeParam());
839                 thArg = (static_cast<PTR_ParamTypeDesc>(thArg.AsTypeDesc()))->GetModifiedType();
840
841                 if (thArg.IsGenericVariable()) // : A<!T[]>
842                 {
843                     // Add an expanding edge from thArg to i-th parameter of pMT.
844                     AddEdge(thArg.AsGenericVariable(), thVar.AsGenericVariable(), TRUE);
845                     break;
846                 }
847             }
848
849             if (!thArg.IsTypeDesc()) // : A<B<!T>>
850             {
851                 // We will add an expanding edge but we do not yet know from which variable(s).
852                 // Add the to-variable to the list and call recursively to inspect thArg's
853                 // instantiation.
854                 TypeHandleList newExpansionVars(thVar, pExpansionVars);
855                 AddDependency(thArg.AsMethodTable(), &newExpansionVars);
856             }
857         }
858     }
859 }
860
861 // Add an edge from pFromVar to pToVar - either non-expanding or expanding.
862 void RecursionGraph::AddEdge(TypeVarTypeDesc *pFromVar, TypeVarTypeDesc *pToVar, BOOL fExpanding)
863 {
864     CONTRACTL
865     {
866         THROWS;
867         GC_NOTRIGGER;
868         PRECONDITION(pFromVar != NULL);
869         PRECONDITION(pToVar != NULL);
870     }
871     CONTRACTL_END
872
873     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",
874         (fExpanding ? "EXPANDING" : "NON-EXPANDING"),
875         pFromVar->GetToken(), pFromVar->GetModule(),
876         pToVar->GetToken(), pToVar->GetModule(),
877         m_thOwner.AsMethodTable()));
878
879     // Get the source node.
880     Node *pNode = &m_pNodes[pFromVar->GetIndex()];
881     _ASSERTE(pFromVar == pNode->GetSourceVar());
882
883     // Add the edge.
884     ULONG_PTR edge = (ULONG_PTR)pToVar;
885     if (fExpanding) edge |= Node::EDGE_EXPANDING_FLAG;
886
887     IfFailThrow(pNode->GetEdges()->Append((void *)edge));
888 }
889
890 // Recursive worker that checks whether this node is part of an expanding cycle.
891 BOOL RecursionGraph::HasExpandingCycle(Node *pCurrentNode, Node *pStartNode, BOOL fExpanded /*= FALSE*/)
892 {
893     CONTRACTL
894     {
895         NOTHROW;
896         GC_NOTRIGGER;
897         PRECONDITION(CheckPointer(pCurrentNode));
898         PRECONDITION(CheckPointer(pStartNode));
899     }
900     CONTRACTL_END;
901
902     // This method performs a modified DFS. We are not looking for any cycle but for a cycle
903     // which has at least one expanding edge. Therefore we:
904     // 1) Pass aroung the fExpanded flag to indicate that we've seen an expanding edge.
905     // 2) Explicitly check for returning to the starting point rather an arbitrary visited node.
906
907     // Did we just find the cycle?
908     if (fExpanded && pCurrentNode == pStartNode)
909         return TRUE;
910
911     // Have we been here before or is this a dead end?
912     if (pCurrentNode->IsVisited() || pCurrentNode->GetEdges()->GetCount() == 0)
913         return FALSE;
914
915     pCurrentNode->SetVisited();
916
917     ArrayList::Iterator iter = pCurrentNode->GetEdges()->Iterate();
918     while (iter.Next())  
919     {
920         ULONG_PTR edge = (ULONG_PTR)iter.GetElement();
921
922         BOOL fExpanding = (edge & Node::EDGE_EXPANDING_FLAG);
923         
924         TypeVarTypeDesc *pToVar = (TypeVarTypeDesc *)(edge & ~Node::EDGE_EXPANDING_FLAG);
925         unsigned int dwIndex = pToVar->GetIndex();
926
927         Node *pNode = NULL;
928         RecursionGraph *pGraph = this;
929
930         // Find the destination node.
931         do
932         {
933             if (pGraph->m_pNodes != NULL &&
934                 dwIndex < pGraph->m_thOwner.GetNumGenericArgs() &&
935                 pGraph->m_pNodes[dwIndex].GetSourceVar() == pToVar)
936             {
937                 pNode = &pGraph->m_pNodes[dwIndex];
938                 break;
939             }
940             pGraph = pGraph->m_pPrev;
941         }
942         while (pGraph != NULL);
943
944         if (pNode != NULL)
945         {
946             // The new path is expanding if it was expanding already or if the edge we follow is expanding.
947             if (HasExpandingCycle(pNode, pStartNode, fExpanded || fExpanding))
948                 return TRUE;
949         }
950     }
951     
952     pCurrentNode->ClearVisited();
953
954     return FALSE;
955 }
956
957 } // namespace Generics
958
959 #endif // !DACCESS_COMPILE
960
961 namespace Generics
962 {
963
964 /*
965  * GetExactInstantiationsOfMethodAndItsClassFromCallInformation
966  *
967  * This routine takes in the various pieces of information of a call site to managed code
968  * and returns the exact instatiations for the method and the class on which the method is defined.
969  *
970  * Parameters:
971  *    pRepMethod - A MethodDesc to the representative instantiation method.
972  *    pThis - The OBJECTREF that is being passed to pRepMethod.
973  *    pParamTypeArg - The extra argument passed to pRepMethod when pRepMethod is either
974  *       RequiresInstMethodTableArg() or RequiresInstMethodDescArg().
975  *    pSpecificClass - A pointer to a TypeHandle for storing the exact instantiation
976  *       of the class on which pRepMethod is defined, based on the call information
977  *    pSpecificMethod - A pointer to a MethodDesc* for storing the exact instantiation
978  *       of pRepMethod, based on the call information
979  *
980  * Returns:
981  *    TRUE if successful.
982  *    FALSE if could not get the exact TypeHandle & MethodDesc requested.  In this case,
983  *      the SpecificClass may be correct, iff the class is not a generic class.
984  *
985  */
986 BOOL GetExactInstantiationsOfMethodAndItsClassFromCallInformation(
987     /* in */  MethodDesc *pRepMethod,
988     /* in */  OBJECTREF pThis,
989     /* in */  PTR_VOID pParamTypeArg,
990     /* out*/  TypeHandle *pSpecificClass,
991     /* out*/  MethodDesc** pSpecificMethod
992     )
993 {
994     CONTRACTL
995     {
996         NOTHROW;
997         GC_NOTRIGGER;
998         SO_TOLERANT;
999         CANNOT_TAKE_LOCK;
1000         PRECONDITION(CheckPointer(pRepMethod));
1001         SUPPORTS_DAC;
1002     }
1003     CONTRACTL_END;
1004      
1005     PTR_VOID pExactGenericArgsToken = NULL;
1006
1007     if (pRepMethod->AcquiresInstMethodTableFromThis())
1008     {
1009         if (pThis != NULL)
1010         {
1011             // We could be missing the memory from a dump, or the target could have simply been corrupted.
1012             ALLOW_DATATARGET_MISSING_MEMORY(
1013                 pExactGenericArgsToken = dac_cast<PTR_VOID>(pThis->GetMethodTable());
1014             );
1015         }
1016     }
1017     else        
1018     {
1019         pExactGenericArgsToken = pParamTypeArg;
1020     }
1021
1022     return GetExactInstantiationsOfMethodAndItsClassFromCallInformation(pRepMethod, pExactGenericArgsToken, 
1023         pSpecificClass, pSpecificMethod);      
1024 }
1025
1026 BOOL GetExactInstantiationsOfMethodAndItsClassFromCallInformation(
1027     /* in */  MethodDesc *pRepMethod,
1028     /* in */  PTR_VOID pExactGenericArgsToken,
1029     /* out*/  TypeHandle *pSpecificClass,
1030     /* out*/  MethodDesc** pSpecificMethod
1031     )
1032 {
1033     CONTRACTL
1034     {
1035         NOTHROW;
1036         GC_NOTRIGGER;
1037         SO_TOLERANT;
1038         CANNOT_TAKE_LOCK;
1039         PRECONDITION(CheckPointer(pRepMethod));
1040         SUPPORTS_DAC;
1041     }
1042     CONTRACTL_END;
1043
1044     //
1045     // Start with some decent default values.
1046     //
1047     MethodDesc * pMD = pRepMethod;
1048     MethodTable * pMT = pRepMethod->GetMethodTable();
1049
1050     *pSpecificMethod = pMD;
1051     *pSpecificClass = pMT;
1052
1053     if (!pRepMethod->IsSharedByGenericInstantiations())
1054     {
1055         return TRUE;
1056     }
1057
1058     if (pExactGenericArgsToken == NULL)
1059     {
1060         return FALSE;
1061     }
1062
1063     BOOL retVal = FALSE;
1064
1065     // The following target memory reads will not necessarily succeed against dumps, and will throw on failure.
1066     EX_TRY_ALLOW_DATATARGET_MISSING_MEMORY
1067     {
1068         if (pRepMethod->RequiresInstMethodTableArg())
1069         {
1070             pMT = dac_cast<PTR_MethodTable>(pExactGenericArgsToken);
1071             retVal = TRUE;
1072         }
1073         else if (pRepMethod->RequiresInstMethodDescArg())
1074         {
1075             pMD = dac_cast<PTR_MethodDesc>(pExactGenericArgsToken);
1076             pMT = pMD->GetMethodTable();
1077             retVal = TRUE;
1078         }
1079         else if (pRepMethod->AcquiresInstMethodTableFromThis())
1080         {
1081             // The exact token might actually be a child class of the class containing 
1082             // the specified function so walk up the parent chain to make sure we return 
1083             // an exact instantiation of the CORRECT parent class.
1084             pMT = pMD->GetExactDeclaringType(dac_cast<PTR_MethodTable>(pExactGenericArgsToken));
1085             _ASSERTE(pMT != NULL);
1086             retVal = TRUE;
1087         }
1088         else
1089         {
1090             _ASSERTE(!"Should not happen.");
1091         }
1092     }
1093     EX_END_CATCH_ALLOW_DATATARGET_MISSING_MEMORY
1094
1095     *pSpecificMethod = pMD;
1096     *pSpecificClass = pMT;
1097
1098     return retVal;
1099 }
1100
1101 } // namespace Generics;
1102