Optimize vtable calls (#20696)
[platform/upstream/coreclr.git] / src / vm / jitinterface.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: JITinterface.CPP
6 //
7
8 // ===========================================================================
9
10
11 #include "common.h"
12 #include "jitinterface.h"
13 #include "codeman.h"
14 #include "method.hpp"
15 #include "class.h"
16 #include "object.h"
17 #include "field.h"
18 #include "stublink.h"
19 #include "virtualcallstub.h"
20 #include "corjit.h"
21 #include "eeconfig.h"
22 #include "excep.h"
23 #include "log.h"
24 #include "excep.h"
25 #include "float.h"      // for isnan
26 #include "dbginterface.h"
27 #include "dllimport.h"
28 #include "gcheaputilities.h"
29 #include "comdelegate.h"
30 #include "jitperf.h" // to track jit perf
31 #include "corprof.h"
32 #include "eeprofinterfaces.h"
33 #include "perfcounters.h"
34 #ifdef PROFILING_SUPPORTED
35 #include "proftoeeinterfaceimpl.h"
36 #include "eetoprofinterfaceimpl.h"
37 #include "eetoprofinterfaceimpl.inl"
38 #include "profilepriv.h"
39 #endif
40 #include "ecall.h"
41 #include "generics.h"
42 #include "typestring.h"
43 #include "stackprobe.h"
44 #include "typedesc.h"
45 #include "genericdict.h"
46 #include "array.h"
47 #include "debuginfostore.h"
48 #include "safemath.h"
49 #include "runtimehandles.h"
50 #include "sigbuilder.h"
51 #include "openum.h"
52 #ifdef HAVE_GCCOVER
53 #include "gccover.h"
54 #endif // HAVE_GCCOVER
55
56 #include "mdaassistants.h"
57
58 #ifdef FEATURE_PREJIT
59 #include "compile.h"
60 #include "corcompile.h"
61 #endif // FEATURE_PREJIT
62
63
64 #ifdef FEATURE_INTERPRETER
65 #include "interpreter.h"
66 #endif // FEATURE_INTERPRETER
67
68 #ifdef FEATURE_PERFMAP
69 #include "perfmap.h"
70 #endif
71
72 // The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro
73 //
74
75 #define JIT_TO_EE_TRANSITION()          MAKE_CURRENT_THREAD_AVAILABLE_EX(m_pThread);                \
76                                         _ASSERTE(CURRENT_THREAD == GetThread());                    \
77                                         INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE;               \
78                                         COOPERATIVE_TRANSITION_BEGIN();                             \
79                                         START_NON_JIT_PERF();
80
81 #define EE_TO_JIT_TRANSITION()          STOP_NON_JIT_PERF();                                        \
82                                         COOPERATIVE_TRANSITION_END();                               \
83                                         UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE;
84
85 #define JIT_TO_EE_TRANSITION_LEAF()
86 #define EE_TO_JIT_TRANSITION_LEAF()
87
88
89 #if defined(CROSSGEN_COMPILE)
90 static const char *const hlpNameTable[CORINFO_HELP_COUNT] = {
91 #define JITHELPER(code, pfnHelper, sig) #code,
92 #include "jithelpers.h"
93 };
94 #endif
95
96 #ifdef DACCESS_COMPILE
97
98 // The real definitions are in jithelpers.cpp. However, those files are not included in the DAC build.
99 // Hence, we add them here.
100 GARY_IMPL(VMHELPDEF, hlpFuncTable, CORINFO_HELP_COUNT);
101 GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);
102
103 #else // DACCESS_COMPILE
104
105 /*********************************************************************/
106
107 #if defined(ENABLE_PERF_COUNTERS)
108 LARGE_INTEGER g_lastTimeInJitCompilation;
109 #endif
110
111 /*********************************************************************/
112
113 inline CORINFO_MODULE_HANDLE GetScopeHandle(MethodDesc* method) 
114 {
115     LIMITED_METHOD_CONTRACT;
116     if (method->IsDynamicMethod())
117     {
118         return MakeDynamicScope(method->AsDynamicMethodDesc()->GetResolver());
119     }
120     else
121     {
122         return GetScopeHandle(method->GetModule());
123     }
124 }
125
126 //This is common refactored code from within several of the access check functions.
127 BOOL ModifyCheckForDynamicMethod(DynamicResolver *pResolver,
128                                  TypeHandle *pOwnerTypeForSecurity,
129                                  AccessCheckOptions::AccessCheckType *pAccessCheckType,
130                                  DynamicResolver** ppAccessContext)
131 {
132     CONTRACTL {
133         STANDARD_VM_CHECK;
134         PRECONDITION(CheckPointer(pResolver));
135         PRECONDITION(CheckPointer(pOwnerTypeForSecurity));
136         PRECONDITION(CheckPointer(pAccessCheckType));
137         PRECONDITION(CheckPointer(ppAccessContext));
138         PRECONDITION(*pAccessCheckType == AccessCheckOptions::kNormalAccessibilityChecks);
139     } CONTRACTL_END;
140
141     BOOL doAccessCheck = TRUE;
142
143     //Do not blindly initialize fields, since they've already got important values.
144     DynamicResolver::SecurityControlFlags dwSecurityFlags = DynamicResolver::Default;
145         
146     TypeHandle dynamicOwner;
147     pResolver->GetJitContext(&dwSecurityFlags, &dynamicOwner);
148     if (!dynamicOwner.IsNull())
149         *pOwnerTypeForSecurity = dynamicOwner;
150
151     if (dwSecurityFlags & DynamicResolver::SkipVisibilityChecks)
152     {
153         doAccessCheck = FALSE;
154     }
155     else if (dwSecurityFlags & DynamicResolver::RestrictedSkipVisibilityChecks)
156     {
157         *pAccessCheckType = AccessCheckOptions::kRestrictedMemberAccessNoTransparency;
158     }
159     else
160     {
161         *pAccessCheckType = AccessCheckOptions::kNormalAccessNoTransparency;
162     }
163
164     return doAccessCheck;
165 }
166
167 /*****************************************************************************/
168
169 // Initialize from data we passed across to the JIT
170 inline static void GetTypeContext(const CORINFO_SIG_INST *info, SigTypeContext *pTypeContext)
171 {
172     LIMITED_METHOD_CONTRACT;
173     SigTypeContext::InitTypeContext(
174         Instantiation((TypeHandle *) info->classInst, info->classInstCount), 
175         Instantiation((TypeHandle *) info->methInst, info->methInstCount), 
176         pTypeContext);
177 }
178
179 static MethodDesc* GetMethodFromContext(CORINFO_CONTEXT_HANDLE context)
180 {
181     LIMITED_METHOD_CONTRACT;
182     if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
183     {
184         return NULL;
185     }
186     else
187     {
188         return GetMethod((CORINFO_METHOD_HANDLE)((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
189     }
190 }
191
192 static TypeHandle GetTypeFromContext(CORINFO_CONTEXT_HANDLE context)
193 {
194     LIMITED_METHOD_CONTRACT;
195     if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
196     {
197         return TypeHandle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
198     }
199     else
200     {
201         MethodTable * pMT = GetMethodFromContext(context)->GetMethodTable();
202         return TypeHandle(pMT);
203     }
204 }
205
206 // Initialize from a context parameter passed to the JIT and back.  This is a parameter
207 // that indicates which method is being jitted.
208
209 inline static void GetTypeContext(CORINFO_CONTEXT_HANDLE context, SigTypeContext *pTypeContext)
210 {
211     CONTRACTL
212     {
213         NOTHROW;
214         GC_NOTRIGGER;
215         SO_TOLERANT;
216         MODE_ANY;
217         PRECONDITION(context != NULL);
218     }
219     CONTRACTL_END;
220     if (GetMethodFromContext(context))
221     {
222         SigTypeContext::InitTypeContext(GetMethodFromContext(context), pTypeContext);
223     }
224     else
225     {
226         SigTypeContext::InitTypeContext(GetTypeFromContext(context), pTypeContext);
227     }
228 }
229
230 static BOOL ContextIsShared(CORINFO_CONTEXT_HANDLE context)
231 {
232     LIMITED_METHOD_CONTRACT;
233     MethodDesc *pContextMD = GetMethodFromContext(context);
234     if (pContextMD != NULL)
235     {
236         return pContextMD->IsSharedByGenericInstantiations();
237     }
238     else
239     {
240         // Type handle contexts are non-shared and are used for inlining of
241         // non-generic methods in generic classes
242         return FALSE;
243     }
244 }
245
246 // Returns true if context is providing any generic variables
247 static BOOL ContextIsInstantiated(CORINFO_CONTEXT_HANDLE context)
248 {
249     LIMITED_METHOD_CONTRACT;
250     if (GetMethodFromContext(context))
251     {
252         return GetMethodFromContext(context)->HasClassOrMethodInstantiation();
253     }
254     else
255     {
256         return GetTypeFromContext(context).HasInstantiation();
257     }
258 }
259
260 /*********************************************************************/
261 // This normalizes EE type information into the form expected by the JIT.
262 //
263 // If typeHnd contains exact type information, then *clsRet will contain
264 // the normalized CORINFO_CLASS_HANDLE information on return.
265
266 // Static
267 CorInfoType CEEInfo::asCorInfoType(CorElementType eeType,
268                                    TypeHandle typeHnd, /* optional in */
269                                    CORINFO_CLASS_HANDLE *clsRet/* optional out */ ) {
270     CONTRACT(CorInfoType) {
271         THROWS;
272         GC_TRIGGERS;
273         PRECONDITION((CorTypeInfo::IsGenericVariable(eeType)) == 
274                      (!typeHnd.IsNull() && typeHnd.IsGenericVariable()));
275         PRECONDITION(eeType != ELEMENT_TYPE_GENERICINST);
276     } CONTRACT_END;
277
278     TypeHandle typeHndUpdated = typeHnd;
279
280     if (!typeHnd.IsNull())
281     {
282         CorElementType normType = typeHnd.GetInternalCorElementType();
283         // If we have a type handle, then it has the better type
284         // in some cases
285         if (eeType == ELEMENT_TYPE_VALUETYPE && !CorTypeInfo::IsObjRef(normType))
286             eeType = normType;
287
288         // Zap the typeHnd when the type _really_ is a primitive
289         // as far as verification is concerned. Returning a null class
290         // handle means it is is a primitive.
291         //
292         // Enums are exactly like primitives, even from a verification standpoint,
293         // so we zap the type handle in this case.
294         //
295         // However RuntimeTypeHandle etc. are reported as E_T_INT (or something like that)
296         // but don't count as primitives as far as verification is concerned...
297         //
298         // To make things stranger, TypedReference returns true for "IsTruePrimitive".
299         // However the JIT likes us to report the type handle in that case.
300         if (!typeHnd.IsTypeDesc() && (
301                 (typeHnd.AsMethodTable()->IsTruePrimitive() && typeHnd != TypeHandle(g_TypedReferenceMT))
302                     || typeHnd.AsMethodTable()->IsEnum()) )
303         {
304             typeHndUpdated = TypeHandle();
305         }
306
307     }
308
309     static const BYTE map[] = {
310         CORINFO_TYPE_UNDEF,
311         CORINFO_TYPE_VOID,
312         CORINFO_TYPE_BOOL,
313         CORINFO_TYPE_CHAR,
314         CORINFO_TYPE_BYTE,
315         CORINFO_TYPE_UBYTE,
316         CORINFO_TYPE_SHORT,
317         CORINFO_TYPE_USHORT,
318         CORINFO_TYPE_INT,
319         CORINFO_TYPE_UINT,
320         CORINFO_TYPE_LONG,
321         CORINFO_TYPE_ULONG,
322         CORINFO_TYPE_FLOAT,
323         CORINFO_TYPE_DOUBLE,
324         CORINFO_TYPE_STRING,
325         CORINFO_TYPE_PTR,            // PTR
326         CORINFO_TYPE_BYREF,
327         CORINFO_TYPE_VALUECLASS,
328         CORINFO_TYPE_CLASS,
329         CORINFO_TYPE_VAR,            // VAR (type variable)
330         CORINFO_TYPE_CLASS,          // ARRAY
331         CORINFO_TYPE_CLASS,          // WITH
332         CORINFO_TYPE_REFANY,
333         CORINFO_TYPE_UNDEF,          // VALUEARRAY_UNSUPPORTED
334         CORINFO_TYPE_NATIVEINT,      // I
335         CORINFO_TYPE_NATIVEUINT,     // U
336         CORINFO_TYPE_UNDEF,          // R_UNSUPPORTED
337
338         // put the correct type when we know our implementation
339         CORINFO_TYPE_PTR,            // FNPTR
340         CORINFO_TYPE_CLASS,          // OBJECT
341         CORINFO_TYPE_CLASS,          // SZARRAY
342         CORINFO_TYPE_VAR,            // MVAR
343
344         CORINFO_TYPE_UNDEF,          // CMOD_REQD
345         CORINFO_TYPE_UNDEF,          // CMOD_OPT
346         CORINFO_TYPE_UNDEF,          // INTERNAL
347         };
348
349     _ASSERTE(sizeof(map) == ELEMENT_TYPE_MAX);
350     _ASSERTE(eeType < (CorElementType) sizeof(map));
351         // spot check of the map
352     _ASSERTE((CorInfoType) map[ELEMENT_TYPE_I4] == CORINFO_TYPE_INT);
353     _ASSERTE((CorInfoType) map[ELEMENT_TYPE_PTR] == CORINFO_TYPE_PTR);
354     _ASSERTE((CorInfoType) map[ELEMENT_TYPE_TYPEDBYREF] == CORINFO_TYPE_REFANY);
355
356     CorInfoType res = ((unsigned)eeType < ELEMENT_TYPE_MAX) ? ((CorInfoType) map[(unsigned)eeType]) : CORINFO_TYPE_UNDEF;
357
358     if (clsRet)
359         *clsRet = CORINFO_CLASS_HANDLE(typeHndUpdated.AsPtr());
360
361     RETURN res;
362 }
363
364
365 inline static CorInfoType toJitType(TypeHandle typeHnd, CORINFO_CLASS_HANDLE *clsRet = NULL)
366 {
367     WRAPPER_NO_CONTRACT;
368     return CEEInfo::asCorInfoType(typeHnd.GetInternalCorElementType(), typeHnd, clsRet);
369 }
370
371 void CheckForEquivalenceAndLoadTypeBeforeCodeIsRun(Module *pModule, mdToken token, Module *pDefModule, mdToken defToken, const SigParser *ptr, SigTypeContext *pTypeContext, void *pData)
372 {
373     CONTRACTL
374     {
375         THROWS;
376         GC_TRIGGERS;
377         SO_INTOLERANT;
378     }
379     CONTRACTL_END;
380
381     if (IsTypeDefEquivalent(defToken, pDefModule))
382     {
383         SigPointer sigPtr(*ptr);
384         TypeHandle th = sigPtr.GetTypeHandleThrowing(pModule, pTypeContext);
385         ((ICorDynamicInfo *)pData)->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(th.AsPtr()));
386     }
387 }
388
389 inline static void TypeEquivalenceFixupSpecificationHelper(ICorDynamicInfo * pCorInfo, MethodDesc *pMD)
390 {
391     STANDARD_VM_CONTRACT;
392
393     // A fixup is necessary to ensure that the parameters to the method are loaded before the method
394     // is called. In these cases we will not perform the appropriate loading when we load parameter
395     // types because with type equivalence, the parameter types at the call site do not necessarily
396     // match that those in the actual function. (They must be equivalent, but not necessarily the same.)
397     // In non-ngen scenarios this code here will force the types to be loaded directly by the call to
398     // HasTypeEquivalentStructParameters.
399     if (!pMD->IsVirtual())
400     {
401         if (pMD->HasTypeEquivalentStructParameters())
402         {
403             if (IsCompilationProcess())
404                 pMD->WalkValueTypeParameters(pMD->GetMethodTable(), CheckForEquivalenceAndLoadTypeBeforeCodeIsRun, pCorInfo);
405         }
406     }
407     else
408     {
409         if (pMD->GetMethodTable()->DependsOnEquivalentOrForwardedStructs())
410         {
411             if (pMD->HasTypeEquivalentStructParameters())
412                 pCorInfo->classMustBeLoadedBeforeCodeIsRun((CORINFO_CLASS_HANDLE)pMD->GetMethodTable());
413         }
414     }
415 }
416
417 //---------------------------------------------------------------------------------------
418 // 
419 //@GENERICS:
420 // The method handle is used to instantiate method and class type parameters
421 // It's also used to determine whether an extra dictionary parameter is required
422 //
423 // sig          - Input metadata signature
424 // scopeHnd     - The signature is to be interpreted in the context of this scope (module)
425 // token        - Metadata token used to refer to the signature (may be mdTokenNil for dynamic methods)
426 // sigRet       - Resulting output signature in a format that is understood by native compilers
427 // pContextMD   - The method with any instantiation information (may be NULL)
428 // localSig     - Is it a local variables declaration, or a method signature (with return type, etc).
429 // contextType  - The type with any instantiaton information
430 // 
431 //static
432 void 
433 CEEInfo::ConvToJitSig(
434     PCCOR_SIGNATURE       pSig, 
435     DWORD                 cbSig, 
436     CORINFO_MODULE_HANDLE scopeHnd, 
437     mdToken               token, 
438     CORINFO_SIG_INFO *    sigRet,
439     MethodDesc *          pContextMD,
440     bool                  localSig,
441     TypeHandle            contextType)
442 {
443     CONTRACTL {
444         THROWS;
445         GC_TRIGGERS;
446     } CONTRACTL_END;
447
448     SigTypeContext typeContext;
449
450     if (pContextMD)
451     {
452         SigTypeContext::InitTypeContext(pContextMD, contextType, &typeContext);
453     }
454     else
455     {
456         SigTypeContext::InitTypeContext(contextType, &typeContext);
457     }
458
459     _ASSERTE(CORINFO_CALLCONV_DEFAULT == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_DEFAULT);
460     _ASSERTE(CORINFO_CALLCONV_VARARG == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_VARARG);
461     _ASSERTE(CORINFO_CALLCONV_MASK == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_MASK);
462     _ASSERTE(CORINFO_CALLCONV_HASTHIS == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_HASTHIS);
463
464     TypeHandle typeHnd = TypeHandle();
465
466     sigRet->pSig = pSig;
467     sigRet->cbSig = cbSig;
468     sigRet->retTypeClass = 0;
469     sigRet->retTypeSigClass = 0;
470     sigRet->scope = scopeHnd;
471     sigRet->token = token;
472     sigRet->sigInst.classInst = (CORINFO_CLASS_HANDLE *) typeContext.m_classInst.GetRawArgs();
473     sigRet->sigInst.classInstCount = (unsigned) typeContext.m_classInst.GetNumArgs();
474     sigRet->sigInst.methInst = (CORINFO_CLASS_HANDLE *) typeContext.m_methodInst.GetRawArgs();
475     sigRet->sigInst.methInstCount = (unsigned) typeContext.m_methodInst.GetNumArgs();
476
477     SigPointer sig(pSig, cbSig);
478
479     if (!localSig)
480     {
481         // This is a method signature which includes calling convention, return type, 
482         // arguments, etc
483
484         _ASSERTE(!sig.IsNull());
485         Module * module = GetModule(scopeHnd);
486         sigRet->flags = 0;
487
488         ULONG data;
489         IfFailThrow(sig.GetCallingConvInfo(&data));
490         sigRet->callConv = (CorInfoCallConv) data;
491
492 #ifdef PLATFORM_UNIX
493         if ((isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_VARARG)) ||
494             (isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_NATIVEVARARG)))
495         {
496             // This signature corresponds to a method that uses varargs, which are not supported.
497              COMPlusThrow(kInvalidProgramException, IDS_EE_VARARG_NOT_SUPPORTED);
498         }
499 #endif // PLATFORM_UNIX
500
501         // Skip number of type arguments
502         if (sigRet->callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
503           IfFailThrow(sig.GetData(NULL));
504
505         ULONG numArgs;
506         IfFailThrow(sig.GetData(&numArgs));
507         if (numArgs != (unsigned short) numArgs)
508             COMPlusThrowHR(COR_E_INVALIDPROGRAM);
509
510         sigRet->numArgs = (unsigned short) numArgs;
511
512         CorElementType type = sig.PeekElemTypeClosed(module, &typeContext);
513
514         if (!CorTypeInfo::IsPrimitiveType(type))
515         {
516             typeHnd = sig.GetTypeHandleThrowing(module, &typeContext);
517             _ASSERTE(!typeHnd.IsNull());
518
519             // I believe it doesn't make any diff. if this is
520             // GetInternalCorElementType or GetSignatureCorElementType
521             type = typeHnd.GetSignatureCorElementType();
522
523         }
524         sigRet->retType = CEEInfo::asCorInfoType(type, typeHnd, &sigRet->retTypeClass);
525         sigRet->retTypeSigClass = CORINFO_CLASS_HANDLE(typeHnd.AsPtr());
526
527         IfFailThrow(sig.SkipExactlyOne());  // must to a skip so we skip any class tokens associated with the return type
528         _ASSERTE(sigRet->retType < CORINFO_TYPE_COUNT);
529
530         sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
531     } 
532     else
533     {
534         // This is local variables declaration
535
536         sigRet->callConv = CORINFO_CALLCONV_DEFAULT;
537         sigRet->retType = CORINFO_TYPE_VOID;
538         sigRet->flags   = CORINFO_SIGFLAG_IS_LOCAL_SIG;
539         sigRet->numArgs = 0;
540         if (!sig.IsNull())
541         {
542             ULONG callConv;
543             IfFailThrow(sig.GetCallingConvInfo(&callConv));
544             if (callConv != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG)
545             {
546                 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_CALLCONV_NOT_LOCAL_SIG);
547             }
548
549             ULONG numArgs;
550             IfFailThrow(sig.GetData(&numArgs));
551             
552             if (numArgs != (unsigned short) numArgs)
553                 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
554
555             sigRet->numArgs = (unsigned short) numArgs;
556         }
557
558         sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
559     }
560
561     _ASSERTE(SigInfoFlagsAreValid(sigRet));
562 } // CEEInfo::ConvToJitSig
563
564 //---------------------------------------------------------------------------------------
565 // 
566 CORINFO_CLASS_HANDLE CEEInfo::getTokenTypeAsHandle (CORINFO_RESOLVED_TOKEN * pResolvedToken)
567 {
568     CONTRACTL {
569         SO_TOLERANT;
570         THROWS;
571         GC_TRIGGERS;
572         MODE_PREEMPTIVE;
573     } CONTRACTL_END;
574
575     CORINFO_CLASS_HANDLE tokenType = NULL;
576
577     JIT_TO_EE_TRANSITION();
578
579     _ASSERTE((pResolvedToken->hMethod == NULL) || (pResolvedToken->hField == NULL));
580
581     BinderClassID classID = CLASS__TYPE_HANDLE;
582
583     if (pResolvedToken->hMethod != NULL)
584     {
585         classID = CLASS__METHOD_HANDLE;
586     }
587     else
588     if (pResolvedToken->hField != NULL)
589     {
590         classID = CLASS__FIELD_HANDLE;
591     }
592
593     tokenType = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(classID));
594
595     EE_TO_JIT_TRANSITION();
596
597     return tokenType;
598 }
599
600 /*********************************************************************/
601 size_t CEEInfo::findNameOfToken (
602             CORINFO_MODULE_HANDLE       scopeHnd,
603             mdToken                     metaTOK,
604             __out_ecount (FQNameCapacity)  char * szFQName,
605             size_t FQNameCapacity)
606 {
607     CONTRACTL {
608         SO_TOLERANT;
609         THROWS;
610         GC_TRIGGERS;
611         MODE_PREEMPTIVE;
612     } CONTRACTL_END;
613
614     size_t NameLen = 0;
615
616     JIT_TO_EE_TRANSITION();
617
618     if (IsDynamicScope(scopeHnd))
619     {
620         strncpy_s (szFQName, FQNameCapacity, "DynamicToken", FQNameCapacity - 1);
621         NameLen = strlen (szFQName);
622     }
623     else
624     {
625         Module* module = (Module *)scopeHnd;
626         NameLen = findNameOfToken(module, metaTOK, szFQName, FQNameCapacity);
627     }
628         
629     EE_TO_JIT_TRANSITION();
630
631     return NameLen;
632 }
633
634 CorInfoCanSkipVerificationResult CEEInfo::canSkipMethodVerification(CORINFO_METHOD_HANDLE ftnHnd)
635 {
636     CONTRACTL {
637         SO_TOLERANT;
638         THROWS;
639         GC_TRIGGERS;
640         MODE_PREEMPTIVE;
641     } CONTRACTL_END;
642
643     return CORINFO_VERIFICATION_CAN_SKIP;
644 }
645
646 /*********************************************************************/
647 BOOL CEEInfo::shouldEnforceCallvirtRestriction(
648         CORINFO_MODULE_HANDLE scopeHnd)
649 {
650     LIMITED_METHOD_CONTRACT;
651     return TRUE;       
652 }
653
654 #ifdef FEATURE_READYTORUN_COMPILER
655
656 // Returns true if assemblies are in the same version bubble
657 // Right now each assembly is in its own version bubble.
658 // If the need arises (i.e. performance issues) we will define sets of assemblies (e.g. all app assemblies)
659 // The main point is that all this logic is concentrated in one place.
660
661 // NOTICE: If you change this logic to allow multi-assembly version bubbles you
662 // need to consider the impact on diagnostic tools. Currently there is an inlining
663 // table which tracks inliner/inlinee relationships in R2R images but it is not
664 // yet capable of encoding cross-assembly inlines. The scenario where this
665 // may show are instrumenting profilers that want to instrument a given method A
666 // using the ReJit APIs. If method A happens to inlined within method B in another 
667 // assembly then the profiler needs to know that so it can rejit B too.
668 // The recommended approach is to upgrade the inlining table (vm\inlinetracking.h\.cpp)
669 // now that presumably R2R images have some way to refer to methods in other
670 // assemblies in their version bubble. Chat with the diagnostics team if you need more 
671 // details.
672 //
673 // There already is a case where cross-assembly inlining occurs in an
674 // unreported fashion for methods marked NonVersionable. There is a specific 
675 // exemption called out for this on ICorProfilerInfo6::EnumNgenModuleMethodsInliningThisMethod
676 // and the impact of the cut was vetted with partners. It would not be appropriate 
677 // to increase that unreported set without additional review.
678
679
680 bool IsInSameVersionBubble(Assembly * current, Assembly * target)
681 {
682     LIMITED_METHOD_CONTRACT;
683
684     // trivial case: current and target are identical
685     // DO NOT change this without reading the notice above
686     if (current == target)
687         return true;
688
689     return false;
690 }
691
692 // Returns true if the assemblies defining current and target are in the same version bubble
693 static bool IsInSameVersionBubble(MethodDesc* pCurMD, MethodDesc *pTargetMD)
694 {
695     LIMITED_METHOD_CONTRACT;
696     // DO NOT change this without reading the notice above
697     if (IsInSameVersionBubble(pCurMD->GetModule()->GetAssembly(),
698                               pTargetMD->GetModule()->GetAssembly()))
699     {
700         return true;
701     }
702     if (IsReadyToRunCompilation())
703     {
704         if (pTargetMD->GetModule()->GetMDImport()->GetCustomAttributeByName(pTargetMD->GetMemberDef(),
705                 NONVERSIONABLE_TYPE, NULL, NULL) == S_OK)
706         {
707             return true;
708         }
709     }
710     return false;
711
712 }
713
714 #endif // FEATURE_READYTORUN_COMPILER
715
716 static bool CallerAndCalleeInSystemVersionBubble(MethodDesc* pCaller, MethodDesc* pCallee)
717 {
718     LIMITED_METHOD_CONTRACT;
719
720 #ifdef FEATURE_READYTORUN_COMPILER
721     if (IsReadyToRunCompilation())
722         return pCallee->GetModule()->IsSystem() && IsInSameVersionBubble(pCaller, pCallee);
723 #endif
724
725     return false;
726 }
727
728
729 /*********************************************************************/
730 CorInfoCanSkipVerificationResult CEEInfo::canSkipVerification(
731         CORINFO_MODULE_HANDLE moduleHnd)
732 {
733     CONTRACTL {
734         SO_TOLERANT;
735         THROWS;
736         GC_TRIGGERS;
737         MODE_PREEMPTIVE;
738     } CONTRACTL_END;
739
740     return CORINFO_VERIFICATION_CAN_SKIP;
741 }
742
743 /*********************************************************************/
744 // Checks if the given metadata token is valid
745 BOOL CEEInfo::isValidToken (
746         CORINFO_MODULE_HANDLE       module,
747         mdToken                     metaTOK)
748 {
749     CONTRACTL {
750         SO_TOLERANT;
751         NOTHROW;
752         GC_NOTRIGGER;
753         MODE_ANY;
754     } CONTRACTL_END;
755
756     BOOL result = FALSE;
757
758     JIT_TO_EE_TRANSITION_LEAF();
759
760     if (IsDynamicScope(module))
761     {
762         // No explicit token validation for dynamic code. Validation is
763         // side-effect of token resolution.
764         result = TRUE;
765     }
766     else
767     {
768         result = ((Module *)module)->GetMDImport()->IsValidToken(metaTOK);
769     }
770
771     EE_TO_JIT_TRANSITION_LEAF();
772
773     return result;
774 }
775
776 /*********************************************************************/
777 // Checks if the given metadata token is valid StringRef
778 BOOL CEEInfo::isValidStringRef (
779         CORINFO_MODULE_HANDLE       module,
780         mdToken                     metaTOK)
781 {
782     CONTRACTL {
783         SO_TOLERANT;
784         THROWS;
785         GC_TRIGGERS;
786         MODE_PREEMPTIVE;
787     } CONTRACTL_END;
788
789     BOOL result = FALSE;
790
791     JIT_TO_EE_TRANSITION();
792
793     if (IsDynamicScope(module))
794     {
795         result = GetDynamicResolver(module)->IsValidStringRef(metaTOK);
796     }
797     else
798     {
799         result = ((Module *)module)->CheckStringRef(metaTOK);
800         if (result)
801         {
802             DWORD dwCharCount;    
803             LPCWSTR pString;
804             result = (!FAILED(((Module *)module)->GetMDImport()->GetUserString(metaTOK, &dwCharCount, NULL, &pString)) &&
805                      pString != NULL);
806         }
807     }
808
809     EE_TO_JIT_TRANSITION();
810
811     return result;
812 }
813
814 /* static */
815 size_t CEEInfo::findNameOfToken (Module* module,
816                                                  mdToken metaTOK,
817                                                  __out_ecount (FQNameCapacity) char * szFQName,
818                                                  size_t FQNameCapacity)
819 {
820     CONTRACTL {
821         NOTHROW;
822         GC_TRIGGERS;
823     } CONTRACTL_END;
824
825 #ifdef _DEBUG
826     PCCOR_SIGNATURE sig = NULL;
827     DWORD           cSig;
828     LPCUTF8         pszNamespace = NULL;
829     LPCUTF8         pszClassName = NULL;
830     
831     mdToken tokType = TypeFromToken(metaTOK);
832     switch(tokType)
833     {
834         case mdtTypeRef:
835             {
836                 if (FAILED(module->GetMDImport()->GetNameOfTypeRef(metaTOK, &pszNamespace, &pszClassName)))
837                 {
838                     pszNamespace = pszClassName = "Invalid TypeRef record";
839                 }
840                 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
841                 break;
842             }
843         case mdtTypeDef:
844             {
845                 if (FAILED(module->GetMDImport()->GetNameOfTypeDef(metaTOK, &pszClassName, &pszNamespace)))
846                 {
847                     pszClassName = pszNamespace = "Invalid TypeDef record";
848                 }
849                 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
850                 break;
851             }
852         case mdtFieldDef:
853             {
854                 LPCSTR szFieldName;
855                 if (FAILED(module->GetMDImport()->GetNameOfFieldDef(metaTOK, &szFieldName)))
856                 {
857                     szFieldName = "Invalid FieldDef record";
858                 }
859                 strncpy_s(szFQName,  FQNameCapacity,  (char*)szFieldName, FQNameCapacity - 1);
860                 break;
861             }
862         case mdtMethodDef:
863             {
864                 LPCSTR szMethodName;
865                 if (FAILED(module->GetMDImport()->GetNameOfMethodDef(metaTOK, &szMethodName)))
866                 {
867                     szMethodName = "Invalid MethodDef record";
868                 }
869                 strncpy_s(szFQName, FQNameCapacity, (char*)szMethodName, FQNameCapacity - 1);
870                 break;
871             }
872         case mdtMemberRef:
873             {
874                 LPCSTR szName;
875                 if (FAILED(module->GetMDImport()->GetNameAndSigOfMemberRef((mdMemberRef)metaTOK, &sig, &cSig, &szName)))
876                 {
877                     szName = "Invalid MemberRef record";
878                 }
879                 strncpy_s(szFQName, FQNameCapacity, (char *)szName, FQNameCapacity - 1);
880                 break;
881             }
882         default:
883             sprintf_s(szFQName, FQNameCapacity, "!TK_%x", metaTOK);
884             break;
885     }
886
887 #else // !_DEBUG
888     strncpy_s (szFQName, FQNameCapacity, "<UNKNOWN>", FQNameCapacity - 1);
889 #endif // _DEBUG
890
891
892     return strlen (szFQName);
893 }
894
895 CorInfoHelpFunc CEEInfo::getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle)
896
897     CONTRACTL {
898         SO_TOLERANT;
899         NOTHROW;
900         GC_NOTRIGGER;
901         MODE_PREEMPTIVE;
902     } CONTRACTL_END;
903
904     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
905
906     JIT_TO_EE_TRANSITION_LEAF();
907
908     result = IsDynamicScope(handle) ? CORINFO_HELP_UNDEF : CORINFO_HELP_STRCNS;
909
910     EE_TO_JIT_TRANSITION_LEAF();
911
912     return result;
913 }
914
915
916 CHECK CheckContext(CORINFO_MODULE_HANDLE scopeHnd, CORINFO_CONTEXT_HANDLE context)
917 {
918     CHECK_MSG(scopeHnd != NULL, "Illegal null scope");
919     CHECK_MSG(((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK) != NULL, "Illegal null context");
920     if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
921     {
922         TypeHandle handle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
923         CHECK_MSG(handle.GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
924     }
925     else
926     {
927         MethodDesc* handle = (MethodDesc*) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK);
928         CHECK_MSG(handle->GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
929     }
930
931     CHECK_OK;
932 }
933
934
935 static DECLSPEC_NORETURN void ThrowBadTokenException(CORINFO_RESOLVED_TOKEN * pResolvedToken)
936 {
937     switch (pResolvedToken->tokenType & CORINFO_TOKENKIND_Mask)
938     {
939     case CORINFO_TOKENKIND_Class:
940         COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_CLASS_TOKEN);
941     case CORINFO_TOKENKIND_Method:
942         COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN);
943     case CORINFO_TOKENKIND_Field:
944         COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN);
945     default:
946         COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
947     }
948 }
949
950 /*********************************************************************/
951 void CEEInfo::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken)
952 {
953     CONTRACTL {
954         SO_TOLERANT;
955         THROWS;
956         GC_TRIGGERS;
957         MODE_PREEMPTIVE;
958     } CONTRACTL_END;
959
960     JIT_TO_EE_TRANSITION();
961
962     _ASSERTE(CheckContext(pResolvedToken->tokenScope, pResolvedToken->tokenContext));
963
964     pResolvedToken->pTypeSpec = NULL;
965     pResolvedToken->cbTypeSpec = NULL;
966     pResolvedToken->pMethodSpec = NULL;
967     pResolvedToken->cbMethodSpec = NULL;
968
969     TypeHandle th;
970     MethodDesc * pMD = NULL;
971     FieldDesc * pFD = NULL;
972
973     CorInfoTokenKind tokenType = pResolvedToken->tokenType;
974
975     if (IsDynamicScope(pResolvedToken->tokenScope))
976     {
977         GetDynamicResolver(pResolvedToken->tokenScope)->ResolveToken(pResolvedToken->token, &th, &pMD, &pFD);
978
979         //
980         // Check that we got the expected handles and fill in missing data if necessary
981         //
982
983         CorTokenType tkType = (CorTokenType)TypeFromToken(pResolvedToken->token);
984
985         if (pMD != NULL)
986         {
987             if ((tkType != mdtMethodDef) && (tkType != mdtMemberRef))
988                 ThrowBadTokenException(pResolvedToken);
989             if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
990                 ThrowBadTokenException(pResolvedToken);
991             if (th.IsNull())
992                 th = pMD->GetMethodTable();
993
994             // "PermitUninstDefOrRef" check
995             if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && pMD->ContainsGenericVariables())
996             {
997                 COMPlusThrow(kInvalidProgramException);
998             }
999
1000             // if this is a BoxedEntryPointStub get the UnboxedEntryPoint one
1001             if (pMD->IsUnboxingStub())
1002             {
1003                 pMD = pMD->GetMethodTable()->GetUnboxedEntryPointMD(pMD);
1004             }
1005
1006             // Activate target if required
1007             if (tokenType != CORINFO_TOKENKIND_Ldtoken)
1008             {
1009                 ScanTokenForDynamicScope(pResolvedToken, th, pMD);
1010             }
1011         }
1012         else
1013         if (pFD != NULL)
1014         {
1015             if ((tkType != mdtFieldDef) && (tkType != mdtMemberRef))
1016                 ThrowBadTokenException(pResolvedToken);
1017             if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1018                 ThrowBadTokenException(pResolvedToken);
1019             if (th.IsNull())
1020                 th = pFD->GetApproxEnclosingMethodTable();
1021
1022             if (pFD->IsStatic() && (tokenType != CORINFO_TOKENKIND_Ldtoken))
1023             {
1024                 ScanTokenForDynamicScope(pResolvedToken, th);
1025             }
1026         }
1027         else
1028         {
1029             if ((tkType != mdtTypeDef) && (tkType != mdtTypeRef))
1030                 ThrowBadTokenException(pResolvedToken);
1031             if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1032                 ThrowBadTokenException(pResolvedToken);
1033             if (th.IsNull())
1034                 ThrowBadTokenException(pResolvedToken);
1035
1036             if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained)
1037             {
1038                 ScanTokenForDynamicScope(pResolvedToken, th);
1039             }
1040         }
1041
1042         _ASSERTE((pMD == NULL) || (pFD == NULL));
1043         _ASSERTE(!th.IsNull());
1044
1045         // "PermitUninstDefOrRef" check
1046         if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && th.ContainsGenericVariables())
1047         {
1048             COMPlusThrow(kInvalidProgramException);
1049         }
1050
1051         // The JIT always wants to see normalized typedescs for arrays
1052         if (!th.IsTypeDesc() && th.AsMethodTable()->IsArray())
1053         {
1054             MethodTable * pMT = th.AsMethodTable();
1055         
1056             // Load the TypeDesc for the array type.
1057             DWORD rank = pMT->GetRank();
1058             TypeHandle elemType = pMT->GetApproxArrayElementTypeHandle();
1059             th = ClassLoader::LoadArrayTypeThrowing(elemType, pMT->GetInternalCorElementType(), rank);
1060         }
1061     }
1062     else
1063     {
1064         unsigned metaTOK = pResolvedToken->token;
1065         Module * pModule = (Module *)pResolvedToken->tokenScope;
1066
1067         switch (TypeFromToken(metaTOK))
1068         {
1069         case mdtModuleRef:
1070             if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1071                 ThrowBadTokenException(pResolvedToken);
1072         
1073             {
1074                 DomainFile *pTargetModule = pModule->LoadModule(GetAppDomain(), metaTOK, FALSE /* loadResources */);
1075                 if (pTargetModule == NULL)
1076                     COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1077                 th = TypeHandle(pTargetModule->GetModule()->GetGlobalMethodTable());
1078                 if (th.IsNull())
1079                     COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1080             }
1081             break;
1082
1083         case mdtTypeDef:
1084         case mdtTypeRef:
1085             if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1086                 ThrowBadTokenException(pResolvedToken);
1087
1088             th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, metaTOK, 
1089                                          ClassLoader::ThrowIfNotFound, 
1090                                          (tokenType == CORINFO_TOKENKIND_Ldtoken) ? 
1091                                             ClassLoader::PermitUninstDefOrRef : ClassLoader::FailIfUninstDefOrRef);
1092             break;
1093
1094         case mdtTypeSpec:
1095             {
1096                 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1097                     ThrowBadTokenException(pResolvedToken);
1098
1099                 IfFailThrow(pModule->GetMDImport()->GetTypeSpecFromToken(metaTOK, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec));
1100                 
1101                 SigTypeContext typeContext;
1102                 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1103
1104                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1105                 th = sigptr.GetTypeHandleThrowing(pModule, &typeContext);
1106             }
1107             break;
1108
1109         case mdtMethodDef:
1110             if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1111                 ThrowBadTokenException(pResolvedToken);
1112
1113             pMD = MemberLoader::GetMethodDescFromMethodDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1114
1115             th = pMD->GetMethodTable();
1116             break;
1117
1118         case mdtFieldDef:
1119             if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1120                 ThrowBadTokenException(pResolvedToken);
1121
1122             pFD = MemberLoader::GetFieldDescFromFieldDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1123
1124             th = pFD->GetEnclosingMethodTable();
1125             break;
1126
1127         case mdtMemberRef:
1128             {
1129                 SigTypeContext typeContext;
1130                 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1131
1132                 MemberLoader::GetDescFromMemberRef(pModule, metaTOK, &pMD, &pFD, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken),
1133                     &th, TRUE, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec);
1134
1135                 _ASSERTE((pMD != NULL) ^ (pFD != NULL));
1136                 _ASSERTE(!th.IsNull());
1137
1138                 if (pMD != NULL)
1139                 {
1140                     if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1141                         ThrowBadTokenException(pResolvedToken);
1142                 }
1143                 else
1144                 {
1145                     if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1146                         ThrowBadTokenException(pResolvedToken);
1147                 }
1148             }
1149             break;
1150
1151         case mdtMethodSpec:
1152             {
1153                 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1154                     ThrowBadTokenException(pResolvedToken);
1155
1156                 SigTypeContext typeContext;
1157                 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1158
1159                 // We need the method desc to carry exact instantiation, thus allowInstParam == FALSE.
1160                 pMD = MemberLoader::GetMethodDescFromMethodSpec(pModule, metaTOK, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken), FALSE /* allowInstParam */,
1161                     &th, TRUE, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec, &pResolvedToken->pMethodSpec, &pResolvedToken->cbMethodSpec);
1162             }
1163             break;
1164
1165         default:
1166             ThrowBadTokenException(pResolvedToken);
1167         }
1168
1169         //
1170         // Module dependency tracking
1171         //
1172         if (pMD != NULL)
1173         {
1174             ScanToken(pModule, pResolvedToken, th, pMD);
1175         }
1176         else
1177         if (pFD != NULL)
1178         {
1179             if (pFD->IsStatic())
1180                 ScanToken(pModule, pResolvedToken, th);
1181         }
1182         else
1183         {
1184             // It should not be required to trigger the modules cctors for ldtoken, it is done for backward compatibility only.
1185             if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained || tokenType == CORINFO_TOKENKIND_Ldtoken)
1186                 ScanToken(pModule, pResolvedToken, th);
1187         }
1188     }
1189
1190     //
1191     // tokenType specific verification and transformations
1192     //
1193     CorElementType et = th.GetInternalCorElementType();
1194     switch (tokenType)
1195     {            
1196         case CORINFO_TOKENKIND_Ldtoken:
1197             // Allow everything.
1198             break;
1199
1200         case CORINFO_TOKENKIND_Newarr:
1201             // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1202             if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1203                 COMPlusThrow(kInvalidProgramException);
1204
1205             th = ClassLoader::LoadArrayTypeThrowing(th);
1206             break;
1207             
1208         default:
1209             // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1210             if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1211                 COMPlusThrow(kInvalidProgramException);
1212             break;
1213     }
1214
1215     // The JIT interface should always return fully loaded types
1216     _ASSERTE(th.IsFullyLoaded());
1217
1218     pResolvedToken->hClass = CORINFO_CLASS_HANDLE(th.AsPtr());
1219     pResolvedToken->hMethod = CORINFO_METHOD_HANDLE(pMD);
1220     pResolvedToken->hField = CORINFO_FIELD_HANDLE(pFD);
1221
1222     EE_TO_JIT_TRANSITION();
1223 }
1224
1225 /*********************************************************************/
1226 struct TryResolveTokenFilterParam
1227 {
1228     CEEInfo* m_this;
1229     CORINFO_RESOLVED_TOKEN* m_resolvedToken;
1230     EXCEPTION_POINTERS m_exceptionPointers;
1231     bool m_success;
1232 };
1233
1234 bool isValidTokenForTryResolveToken(CEEInfo* info, CORINFO_RESOLVED_TOKEN* resolvedToken)
1235 {
1236     CONTRACTL {
1237         NOTHROW;
1238         GC_NOTRIGGER;
1239         SO_TOLERANT;
1240         MODE_ANY;
1241     } CONTRACTL_END;
1242
1243     if (!info->isValidToken(resolvedToken->tokenScope, resolvedToken->token))
1244     {
1245         return false;
1246     }
1247
1248     CorInfoTokenKind tokenType = resolvedToken->tokenType;
1249     switch (TypeFromToken(resolvedToken->token))
1250     {
1251     case mdtModuleRef:
1252     case mdtTypeDef:
1253     case mdtTypeRef:
1254     case mdtTypeSpec:
1255         if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1256             return false;
1257         break;
1258
1259     case mdtMethodDef:
1260     case mdtMethodSpec:
1261         if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1262             return false;
1263         break;
1264
1265     case mdtFieldDef:
1266         if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1267             return false;
1268         break;
1269
1270     case mdtMemberRef:
1271         if ((tokenType & (CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field)) == 0)
1272             return false;
1273         break;
1274
1275     default:
1276         return false;
1277     }
1278
1279     return true;
1280 }
1281
1282 LONG EEFilterException(struct _EXCEPTION_POINTERS* exceptionPointers, void* unused);
1283
1284 LONG TryResolveTokenFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
1285 {
1286     CONTRACTL {
1287         NOTHROW;
1288         GC_NOTRIGGER;
1289         SO_TOLERANT;
1290         MODE_ANY;
1291     } CONTRACTL_END;
1292
1293     // Backward compatibility: Convert bad image format exceptions thrown while resolving tokens
1294     // to simple true/false successes. This is done for backward compatibility only. Ideally,
1295     // we would always treat bad tokens in the IL  stream as fatal errors.
1296     if (exceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1297     {
1298         auto* param = reinterpret_cast<TryResolveTokenFilterParam*>(theParam);
1299         if (!isValidTokenForTryResolveToken(param->m_this, param->m_resolvedToken))
1300         {
1301             param->m_exceptionPointers = *exceptionPointers;
1302             return EEFilterException(exceptionPointers, nullptr);
1303         }
1304     }
1305
1306     return EXCEPTION_CONTINUE_SEARCH;
1307 }
1308
1309 bool CEEInfo::tryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
1310 {
1311     // No dynamic contract here because SEH is used
1312     STATIC_CONTRACT_SO_TOLERANT;
1313     STATIC_CONTRACT_THROWS;
1314     STATIC_CONTRACT_GC_TRIGGERS;
1315     STATIC_CONTRACT_MODE_PREEMPTIVE;
1316
1317     TryResolveTokenFilterParam param;
1318     param.m_this = this;
1319     param.m_resolvedToken = resolvedToken;
1320     param.m_success = true;
1321
1322     PAL_TRY(TryResolveTokenFilterParam*, pParam, &param)
1323     {
1324         pParam->m_this->resolveToken(pParam->m_resolvedToken);
1325     }
1326     PAL_EXCEPT_FILTER(TryResolveTokenFilter)
1327     {
1328         if (param.m_exceptionPointers.ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1329         {
1330             HandleException(&param.m_exceptionPointers);
1331         }
1332
1333         param.m_success = false;
1334     }
1335     PAL_ENDTRY
1336
1337     return param.m_success;
1338 }
1339
1340 /*********************************************************************/
1341 // We have a few frequently used constants in mscorlib that are defined as 
1342 // readonly static fields for historic reasons. Check for them here and 
1343 // allow them to be treated as actual constants by the JIT.
1344 static CORINFO_FIELD_ACCESSOR getFieldIntrinsic(FieldDesc * field)
1345 {
1346     STANDARD_VM_CONTRACT;
1347
1348     if (MscorlibBinder::GetField(FIELD__STRING__EMPTY) == field)
1349     {
1350         return CORINFO_FIELD_INTRINSIC_EMPTY_STRING;
1351     }
1352     else
1353     if ((MscorlibBinder::GetField(FIELD__INTPTR__ZERO) == field) ||
1354         (MscorlibBinder::GetField(FIELD__UINTPTR__ZERO) == field))
1355     {
1356         return CORINFO_FIELD_INTRINSIC_ZERO;
1357     }
1358     else
1359     if (MscorlibBinder::GetField(FIELD__BITCONVERTER__ISLITTLEENDIAN) == field)
1360     {
1361         return CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN;
1362     }
1363
1364     return (CORINFO_FIELD_ACCESSOR)-1;
1365 }
1366
1367 static CorInfoHelpFunc getGenericStaticsHelper(FieldDesc * pField)
1368 {
1369     STANDARD_VM_CONTRACT;
1370
1371     int helper = CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE;
1372
1373     if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1374         pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1375     {
1376         helper = CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1377     }
1378
1379     if (pField->IsThreadStatic())
1380     {
1381         const int delta = CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1382
1383         static_assert_no_msg(CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE 
1384             == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE + delta);
1385
1386         helper += (CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE);
1387     }
1388
1389     return (CorInfoHelpFunc)helper;
1390 }
1391
1392 CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable * pFieldMT)
1393 {
1394     STANDARD_VM_CONTRACT;
1395
1396     int helper = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
1397
1398     if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1399         pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1400     {
1401         helper = CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1402     }
1403
1404     if (pFieldMT->IsDynamicStatics())
1405     {
1406         const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1407
1408         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS 
1409             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1410
1411         helper += delta;
1412     }
1413     else
1414     if (!pFieldMT->HasClassConstructor() && !pFieldMT->HasBoxedRegularStatics())
1415     {
1416         const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1417
1418         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR 
1419             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1420
1421         helper += delta;
1422     }
1423
1424     if (pField->IsThreadStatic())
1425     {
1426         const int delta = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1427
1428         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE 
1429             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1430         static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR 
1431             == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR + delta);
1432         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR 
1433             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR + delta);
1434         static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS 
1435             == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS + delta);
1436         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS 
1437             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS + delta);
1438
1439         helper += delta;
1440     }
1441
1442     return (CorInfoHelpFunc)helper;
1443 }
1444
1445 static CorInfoHelpFunc getInstanceFieldHelper(FieldDesc * pField, CORINFO_ACCESS_FLAGS flags)
1446 {
1447     STANDARD_VM_CONTRACT;
1448
1449     int helper;
1450
1451     CorElementType type = pField->GetFieldType();
1452
1453     if (CorTypeInfo::IsObjRef(type))
1454         helper = CORINFO_HELP_GETFIELDOBJ;
1455     else
1456     switch (type)
1457     {
1458     case ELEMENT_TYPE_VALUETYPE:
1459         helper = CORINFO_HELP_GETFIELDSTRUCT;
1460         break;
1461     case ELEMENT_TYPE_I1:
1462     case ELEMENT_TYPE_BOOLEAN:
1463     case ELEMENT_TYPE_U1:
1464         helper = CORINFO_HELP_GETFIELD8;
1465         break;
1466     case ELEMENT_TYPE_I2:
1467     case ELEMENT_TYPE_CHAR:
1468     case ELEMENT_TYPE_U2:
1469         helper = CORINFO_HELP_GETFIELD16;
1470         break;
1471     case ELEMENT_TYPE_I4:
1472     case ELEMENT_TYPE_U4:
1473     IN_TARGET_32BIT(default:)
1474         helper = CORINFO_HELP_GETFIELD32;
1475         break;
1476     case ELEMENT_TYPE_I8:
1477     case ELEMENT_TYPE_U8:
1478     IN_TARGET_64BIT(default:)
1479         helper = CORINFO_HELP_GETFIELD64;
1480         break;
1481     case ELEMENT_TYPE_R4:
1482         helper = CORINFO_HELP_GETFIELDFLOAT;
1483         break;
1484     case ELEMENT_TYPE_R8:
1485         helper = CORINFO_HELP_GETFIELDDOUBLE;
1486         break;
1487     }
1488
1489     if (flags & CORINFO_ACCESS_SET)
1490     {
1491         const int delta = CORINFO_HELP_SETFIELDOBJ - CORINFO_HELP_GETFIELDOBJ;
1492
1493         static_assert_no_msg(CORINFO_HELP_SETFIELD8 == CORINFO_HELP_GETFIELD8 + delta);
1494         static_assert_no_msg(CORINFO_HELP_SETFIELD16 == CORINFO_HELP_GETFIELD16 + delta);
1495         static_assert_no_msg(CORINFO_HELP_SETFIELD32 == CORINFO_HELP_GETFIELD32 + delta);
1496         static_assert_no_msg(CORINFO_HELP_SETFIELD64 == CORINFO_HELP_GETFIELD64 + delta);
1497         static_assert_no_msg(CORINFO_HELP_SETFIELDSTRUCT == CORINFO_HELP_GETFIELDSTRUCT + delta);
1498         static_assert_no_msg(CORINFO_HELP_SETFIELDFLOAT == CORINFO_HELP_GETFIELDFLOAT + delta);
1499         static_assert_no_msg(CORINFO_HELP_SETFIELDDOUBLE == CORINFO_HELP_GETFIELDDOUBLE + delta);
1500
1501         helper += delta;
1502     }
1503
1504     return (CorInfoHelpFunc)helper;
1505 }
1506
1507 /*********************************************************************/
1508 void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken,
1509                             CORINFO_METHOD_HANDLE  callerHandle,
1510                             CORINFO_ACCESS_FLAGS   flags, 
1511                             CORINFO_FIELD_INFO    *pResult
1512                            )
1513 {
1514     CONTRACTL {
1515         SO_TOLERANT;
1516         THROWS;
1517         GC_TRIGGERS;
1518         MODE_PREEMPTIVE;
1519     } CONTRACTL_END;
1520
1521     JIT_TO_EE_TRANSITION();
1522
1523     _ASSERTE((flags & (CORINFO_ACCESS_GET | CORINFO_ACCESS_SET | CORINFO_ACCESS_ADDRESS | CORINFO_ACCESS_INIT_ARRAY)) != 0);
1524
1525     INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
1526
1527     FieldDesc * pField = (FieldDesc*)pResolvedToken->hField;
1528     MethodTable * pFieldMT = pField->GetApproxEnclosingMethodTable();
1529
1530     // Helper to use if the field access requires it
1531     CORINFO_FIELD_ACCESSOR fieldAccessor = (CORINFO_FIELD_ACCESSOR)-1;
1532     DWORD fieldFlags = 0;
1533
1534     pResult->offset = pField->GetOffset();
1535     if (pField->IsStatic())
1536     {
1537         fieldFlags |= CORINFO_FLG_FIELD_STATIC;
1538
1539         if (pField->IsRVA())
1540         {
1541             fieldFlags |= CORINFO_FLG_FIELD_UNMANAGED;
1542
1543             Module* module = pFieldMT->GetModule();
1544             if (module->IsRvaFieldTls(pResult->offset))
1545             {
1546                 fieldAccessor = CORINFO_FIELD_STATIC_TLS;
1547
1548                 // Provide helper to use if the JIT is not able to emit the TLS access
1549                 // as intrinsic
1550                 pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR_TLS;
1551
1552                 pResult->offset = module->GetFieldTlsOffset(pResult->offset);
1553             }
1554             else
1555             {
1556                 fieldAccessor = CORINFO_FIELD_STATIC_RVA_ADDRESS;
1557             }
1558
1559             // We are not going through a helper. The constructor has to be triggered explicitly.
1560             if (!pFieldMT->IsClassPreInited())
1561                 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1562         }
1563         else
1564         {
1565             // Regular or thread static
1566             CORINFO_FIELD_ACCESSOR intrinsicAccessor;
1567
1568             if (pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1569                 fieldFlags |= CORINFO_FLG_FIELD_STATIC_IN_HEAP;
1570
1571             if (pFieldMT->IsSharedByGenericInstantiations())
1572             {
1573                 fieldAccessor = CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER;
1574
1575                 pResult->helper = getGenericStaticsHelper(pField);
1576             }
1577             else
1578             if (pFieldMT->GetModule()->IsSystem() && (flags & CORINFO_ACCESS_GET) &&
1579                 (intrinsicAccessor = getFieldIntrinsic(pField)) != (CORINFO_FIELD_ACCESSOR)-1)
1580             {
1581                 // Intrinsics
1582                 fieldAccessor = intrinsicAccessor;
1583             }
1584             else
1585             if (// Domain neutral access.
1586                 m_pMethodBeingCompiled->IsDomainNeutral() || m_pMethodBeingCompiled->IsZapped() || IsCompilingForNGen() ||
1587                 // Static fields are not pinned in collectible types. We will always access 
1588                 // them using a helper since the address cannot be embeded into the code.
1589                 pFieldMT->Collectible() ||
1590                 // We always treat accessing thread statics as if we are in domain neutral code.
1591                 pField->IsThreadStatic()
1592                 )
1593             {
1594                 fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
1595
1596                 pResult->helper = getSharedStaticsHelper(pField, pFieldMT);
1597             }
1598             else
1599             {
1600                 fieldAccessor = CORINFO_FIELD_STATIC_ADDRESS;
1601
1602                 // We are not going through a helper. The constructor has to be triggered explicitly.
1603                 if (!pFieldMT->IsClassPreInited())
1604                     fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1605             }
1606         }
1607
1608         //
1609         // Currently, we only this optimization for regular statics, but it
1610         // looks like it may be permissible to do this optimization for
1611         // thread statics as well.
1612         //
1613         if ((flags & CORINFO_ACCESS_ADDRESS) &&
1614             !pField->IsThreadStatic() &&
1615             (fieldAccessor != CORINFO_FIELD_STATIC_TLS))
1616         {
1617             fieldFlags |= CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN;
1618         }
1619     }
1620     else
1621     {
1622         BOOL fInstanceHelper = FALSE;
1623
1624         if (fInstanceHelper)
1625         {
1626             if (flags & CORINFO_ACCESS_ADDRESS)
1627             {
1628                 fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1629
1630                 pResult->helper = CORINFO_HELP_GETFIELDADDR;
1631             }
1632             else
1633             {
1634                 fieldAccessor = CORINFO_FIELD_INSTANCE_HELPER;
1635
1636                 pResult->helper = getInstanceFieldHelper(pField, flags);
1637             }
1638         }
1639         else
1640         if (pField->IsEnCNew())
1641         {
1642             fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1643
1644             pResult->helper = CORINFO_HELP_GETFIELDADDR;
1645         }
1646         else
1647         {
1648             fieldAccessor = CORINFO_FIELD_INSTANCE;
1649         }
1650
1651         // FieldDesc::GetOffset() does not include the size of Object
1652         if (!pFieldMT->IsValueType())
1653         {
1654             pResult->offset += OBJECT_SIZE;
1655         }
1656     }
1657
1658     // TODO: This is touching metadata. Can we avoid it?
1659     DWORD fieldAttribs = pField->GetAttributes();
1660
1661     if (IsFdFamily(fieldAttribs))
1662         fieldFlags |= CORINFO_FLG_FIELD_PROTECTED;
1663
1664     if (IsFdInitOnly(fieldAttribs))
1665         fieldFlags |= CORINFO_FLG_FIELD_FINAL;
1666
1667     pResult->fieldAccessor = fieldAccessor;
1668     pResult->fieldFlags = fieldFlags;
1669
1670     if (!(flags & CORINFO_ACCESS_INLINECHECK))
1671     {
1672         //get the field's type.  Grab the class for structs.
1673         pResult->fieldType = getFieldTypeInternal(pResolvedToken->hField, &pResult->structType, pResolvedToken->hClass);
1674
1675
1676         MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
1677
1678         //
1679         //Since we can't get the special verify-only instantiated FD like we can with MDs, go back to the parent
1680         //of the memberRef and load that one.  That should give us the open instantiation.
1681         //
1682         //If the field we found is owned by a generic type, you have to go back to the signature and reload.
1683         //Otherwise we filled in !0.
1684         TypeHandle fieldTypeForSecurity = TypeHandle(pResolvedToken->hClass);
1685         if (pResolvedToken->pTypeSpec != NULL)
1686         {
1687             SigTypeContext typeContext;
1688             SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
1689
1690             SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1691             fieldTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
1692
1693             // typeHnd can be a variable type
1694             if (fieldTypeForSecurity.GetMethodTable() == NULL)
1695             {
1696                 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
1697             }
1698         }
1699
1700         BOOL doAccessCheck = TRUE;
1701         AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
1702
1703         DynamicResolver * pAccessContext = NULL;
1704
1705         //More in code:CEEInfo::getCallInfo, but the short version is that the caller and callee Descs do
1706         //not completely describe the type.
1707         TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
1708         if (IsDynamicScope(pResolvedToken->tokenScope))
1709         {
1710             doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope), &callerTypeForSecurity,
1711                 &accessCheckType, &pAccessContext);
1712         }
1713
1714         //Now for some link time checks.
1715         //Um... where are the field link demands?
1716
1717         pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
1718
1719         if (doAccessCheck)
1720         {
1721             //Well, let's check some visibility at least.
1722             AccessCheckOptions accessCheckOptions(accessCheckType,
1723                 pAccessContext,
1724                 FALSE,
1725                 pField);
1726
1727             _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
1728             StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
1729
1730             BOOL canAccess = ClassLoader::CanAccess(
1731                 &accessContext,
1732                 fieldTypeForSecurity.GetMethodTable(),
1733                 fieldTypeForSecurity.GetAssembly(),
1734                 fieldAttribs,
1735                 NULL,
1736                 (flags & CORINFO_ACCESS_INIT_ARRAY) ? NULL : pField, // For InitializeArray, we don't need tocheck the type of the field.
1737                 accessCheckOptions);
1738
1739             if (!canAccess)
1740             {
1741                 //Set up the throw helper
1742                 pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL;
1743
1744                 pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_EXCEPTION;
1745                 pResult->accessCalloutHelper.numArgs = 2;
1746
1747                 pResult->accessCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
1748                 pResult->accessCalloutHelper.args[1].Set(CORINFO_FIELD_HANDLE(pField));
1749
1750                 if (IsCompilingForNGen())
1751                 {
1752                     //see code:CEEInfo::getCallInfo for more information.
1753                     if (pCallerForSecurity->ContainsGenericVariables())
1754                         COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
1755                 }
1756             }
1757         }
1758     }
1759
1760     EE_TO_JIT_TRANSITION();
1761 }
1762
1763 //---------------------------------------------------------------------------------------
1764 // 
1765 bool CEEInfo::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd)
1766 {
1767     CONTRACTL {
1768         SO_TOLERANT;
1769         THROWS;
1770         GC_TRIGGERS;
1771         MODE_PREEMPTIVE;
1772     } CONTRACTL_END;
1773
1774     bool res = false;
1775     JIT_TO_EE_TRANSITION_LEAF();
1776     FieldDesc* field = (FieldDesc*)fldHnd;
1777     res = (field->IsStatic() != 0);
1778     EE_TO_JIT_TRANSITION_LEAF();
1779     return res;
1780 }
1781
1782 //---------------------------------------------------------------------------------------
1783 // 
1784 void 
1785 CEEInfo::findCallSiteSig(
1786     CORINFO_MODULE_HANDLE  scopeHnd, 
1787     unsigned               sigMethTok, 
1788     CORINFO_CONTEXT_HANDLE context, 
1789     CORINFO_SIG_INFO *     sigRet)
1790 {
1791     CONTRACTL {
1792         SO_TOLERANT;
1793         THROWS;
1794         GC_TRIGGERS;
1795         MODE_PREEMPTIVE;
1796     } CONTRACTL_END;
1797
1798     JIT_TO_EE_TRANSITION();
1799
1800     PCCOR_SIGNATURE       pSig = NULL;
1801     DWORD                 cbSig = 0;
1802
1803     if (IsDynamicScope(scopeHnd))
1804     {
1805         DynamicResolver * pResolver = GetDynamicResolver(scopeHnd);
1806         SigPointer sig;
1807
1808         if (TypeFromToken(sigMethTok) == mdtMemberRef)
1809         {
1810             sig = pResolver->ResolveSignatureForVarArg(sigMethTok);
1811         }
1812         else
1813         {
1814             _ASSERTE(TypeFromToken(sigMethTok) == mdtMethodDef);
1815
1816             TypeHandle classHandle;
1817             MethodDesc * pMD = NULL;
1818             FieldDesc * pFD = NULL;
1819
1820             // in this case a method is asked for its sig. Resolve the method token and get the sig
1821             pResolver->ResolveToken(sigMethTok, &classHandle, &pMD, &pFD);
1822             if (pMD == NULL)
1823                 COMPlusThrow(kInvalidProgramException);
1824
1825             PCCOR_SIGNATURE pSig = NULL;
1826             DWORD           cbSig;
1827             pMD->GetSig(&pSig, &cbSig);
1828             sig = SigPointer(pSig, cbSig);
1829
1830             context = MAKE_METHODCONTEXT(pMD);
1831             scopeHnd = GetScopeHandle(pMD->GetModule());
1832         }
1833
1834         sig.GetSignature(&pSig, &cbSig);
1835         sigMethTok = mdTokenNil;
1836     }
1837     else
1838     {
1839         Module * module = (Module *)scopeHnd;
1840         LPCUTF8  szName;
1841
1842         if (TypeFromToken(sigMethTok) == mdtMemberRef)
1843         {
1844             IfFailThrow(module->GetMDImport()->GetNameAndSigOfMemberRef(sigMethTok, &pSig, &cbSig, &szName));
1845         }
1846         else if (TypeFromToken(sigMethTok) == mdtMethodDef)
1847         {
1848             IfFailThrow(module->GetMDImport()->GetSigOfMethodDef(sigMethTok, &cbSig, &pSig));
1849         }
1850     }
1851
1852     CEEInfo::ConvToJitSig(
1853         pSig, 
1854         cbSig, 
1855         scopeHnd, 
1856         sigMethTok, 
1857         sigRet, 
1858         GetMethodFromContext(context), 
1859         false,
1860         GetTypeFromContext(context));
1861     EE_TO_JIT_TRANSITION();
1862 } // CEEInfo::findCallSiteSig
1863
1864 //---------------------------------------------------------------------------------------
1865 // 
1866 void 
1867 CEEInfo::findSig(
1868     CORINFO_MODULE_HANDLE  scopeHnd, 
1869     unsigned               sigTok, 
1870     CORINFO_CONTEXT_HANDLE context, 
1871     CORINFO_SIG_INFO *     sigRet)
1872 {
1873     CONTRACTL {
1874         SO_TOLERANT;
1875         THROWS;
1876         GC_TRIGGERS;
1877         MODE_PREEMPTIVE;
1878     } CONTRACTL_END;
1879
1880     JIT_TO_EE_TRANSITION();
1881
1882     PCCOR_SIGNATURE       pSig = NULL;
1883     DWORD                 cbSig = 0;
1884
1885     if (IsDynamicScope(scopeHnd))
1886     {
1887         SigPointer sig = GetDynamicResolver(scopeHnd)->ResolveSignature(sigTok);
1888         sig.GetSignature(&pSig, &cbSig);
1889         sigTok = mdTokenNil;
1890     }
1891     else
1892     {
1893         Module * module = (Module *)scopeHnd;
1894         
1895         // We need to resolve this stand alone sig
1896         IfFailThrow(module->GetMDImport()->GetSigFromToken(
1897             (mdSignature)sigTok, 
1898             &cbSig, 
1899             &pSig));
1900     }
1901
1902     CEEInfo::ConvToJitSig(
1903         pSig, 
1904         cbSig, 
1905         scopeHnd, 
1906         sigTok, 
1907         sigRet, 
1908         GetMethodFromContext(context), 
1909         false,
1910         GetTypeFromContext(context));
1911     
1912     EE_TO_JIT_TRANSITION();
1913 } // CEEInfo::findSig
1914
1915 //---------------------------------------------------------------------------------------
1916 // 
1917 unsigned 
1918 CEEInfo::getClassSize(
1919     CORINFO_CLASS_HANDLE clsHnd)
1920 {
1921     CONTRACTL {
1922         SO_TOLERANT;
1923         NOTHROW;
1924         GC_NOTRIGGER;
1925         MODE_PREEMPTIVE;
1926     } CONTRACTL_END;
1927
1928     unsigned result = 0;
1929
1930     JIT_TO_EE_TRANSITION_LEAF();
1931
1932     TypeHandle VMClsHnd(clsHnd);
1933     result = VMClsHnd.GetSize();
1934
1935     EE_TO_JIT_TRANSITION_LEAF();
1936
1937     return result;
1938 }
1939
1940 //---------------------------------------------------------------------------------------
1941 //
1942 // Get the size of a reference type as allocated on the heap. This includes the size of the fields
1943 // (and any padding between the fields) and the size of a method table pointer but doesn't include
1944 // object header size or any padding for minimum size.
1945 unsigned
1946 CEEInfo::getHeapClassSize(
1947     CORINFO_CLASS_HANDLE clsHnd)
1948 {
1949     CONTRACTL{
1950         SO_TOLERANT;
1951         NOTHROW;
1952         GC_NOTRIGGER;
1953         MODE_PREEMPTIVE;
1954     } CONTRACTL_END;
1955
1956     unsigned result = 0;
1957
1958     JIT_TO_EE_TRANSITION_LEAF();
1959
1960     TypeHandle VMClsHnd(clsHnd);
1961     MethodTable* pMT = VMClsHnd.GetMethodTable();
1962     _ASSERTE(pMT);
1963     _ASSERTE(!pMT->IsValueType());
1964     _ASSERTE(!pMT->HasComponentSize());
1965 #ifdef FEATURE_READYTORUN_COMPILER
1966     _ASSERTE(!IsReadyToRunCompilation() || pMT->IsInheritanceChainLayoutFixedInCurrentVersionBubble());
1967 #endif
1968
1969     // Add OBJECT_SIZE to account for method table pointer.
1970     result = pMT->GetNumInstanceFieldBytes() + OBJECT_SIZE;
1971
1972     EE_TO_JIT_TRANSITION_LEAF();
1973     return result;
1974 }
1975
1976 //---------------------------------------------------------------------------------------
1977 //
1978 // Return TRUE if an object of this type can be allocated on the stack.
1979 BOOL CEEInfo::canAllocateOnStack(CORINFO_CLASS_HANDLE clsHnd)
1980 {
1981     CONTRACTL{
1982         SO_TOLERANT;
1983         NOTHROW;
1984         GC_NOTRIGGER;
1985         MODE_PREEMPTIVE;
1986     } CONTRACTL_END;
1987
1988     BOOL result = FALSE;
1989
1990     JIT_TO_EE_TRANSITION_LEAF();
1991
1992     TypeHandle VMClsHnd(clsHnd);
1993     MethodTable* pMT = VMClsHnd.GetMethodTable();
1994     _ASSERTE(pMT);
1995     _ASSERTE(!pMT->IsValueType());
1996
1997     result = !pMT->HasFinalizer();
1998
1999 #ifdef FEATURE_READYTORUN_COMPILER
2000     if (IsReadyToRunCompilation() && !pMT->IsInheritanceChainLayoutFixedInCurrentVersionBubble())
2001     {
2002         result = false;
2003     }
2004 #endif
2005
2006     EE_TO_JIT_TRANSITION_LEAF();
2007     return result;
2008 }
2009
2010 unsigned CEEInfo::getClassAlignmentRequirement(CORINFO_CLASS_HANDLE type, BOOL fDoubleAlignHint)
2011 {
2012     CONTRACTL {
2013         SO_TOLERANT;
2014         NOTHROW;
2015         GC_NOTRIGGER;
2016         MODE_PREEMPTIVE;
2017     } CONTRACTL_END;
2018
2019     // Default alignment is sizeof(void*)
2020     unsigned result = TARGET_POINTER_SIZE;
2021
2022     JIT_TO_EE_TRANSITION_LEAF();
2023
2024     TypeHandle clsHnd(type);
2025
2026 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
2027     if (fDoubleAlignHint)
2028     {
2029         MethodTable* pMT = clsHnd.GetMethodTable();
2030         if (pMT != NULL)
2031         {
2032             // Return the size of the double align hint. Ignore the actual alignment info account
2033             // so that structs with 64-bit integer fields do not trigger double aligned frames on x86.
2034             if (pMT->GetClass()->IsAlign8Candidate())
2035                 result = 8;
2036         }
2037     }
2038     else
2039 #endif
2040     {
2041         result = getClassAlignmentRequirementStatic(clsHnd);
2042     }
2043
2044     EE_TO_JIT_TRANSITION_LEAF();
2045
2046     return result;
2047 }
2048
2049 unsigned CEEInfo::getClassAlignmentRequirementStatic(TypeHandle clsHnd)
2050 {
2051     LIMITED_METHOD_CONTRACT;
2052
2053     // Default alignment is sizeof(void*)
2054     unsigned result = TARGET_POINTER_SIZE;
2055
2056     MethodTable * pMT = clsHnd.GetMethodTable();
2057     if (pMT == NULL)
2058         return result;
2059
2060     if (pMT->HasLayout())
2061     {
2062         EEClassLayoutInfo* pInfo = pMT->GetLayoutInfo();
2063
2064         if (clsHnd.IsNativeValueType())
2065         {
2066             // if it's the unmanaged view of the managed type, we always use the unmanaged alignment requirement
2067             result = pInfo->m_LargestAlignmentRequirementOfAllMembers;
2068         }
2069         else
2070         if (pInfo->IsManagedSequential())
2071         {
2072             _ASSERTE(!pMT->ContainsPointers());
2073
2074             // if it's managed sequential, we use the managed alignment requirement
2075             result = pInfo->m_ManagedLargestAlignmentRequirementOfAllMembers;
2076         }
2077         else if (pInfo->IsBlittable())
2078         {
2079             _ASSERTE(!pMT->ContainsPointers());
2080
2081             // if it's blittable, we use the unmanaged alignment requirement
2082             result = pInfo->m_LargestAlignmentRequirementOfAllMembers;
2083         }
2084     }
2085
2086 #ifdef FEATURE_64BIT_ALIGNMENT
2087     if (result < 8 && pMT->RequiresAlign8())
2088     {
2089         // If the structure contains 64-bit primitive fields and the platform requires 8-byte alignment for
2090         // such fields then make sure we return at least 8-byte alignment. Note that it's technically possible
2091         // to create unmanaged APIs that take unaligned structures containing such fields and this
2092         // unconditional alignment bump would cause us to get the calling convention wrong on platforms such
2093         // as ARM. If we see such cases in the future we'd need to add another control (such as an alignment
2094         // property for the StructLayout attribute or a marshaling directive attribute for p/invoke arguments)
2095         // that allows more precise control. For now we'll go with the likely scenario.
2096         result = 8;
2097     }
2098 #endif // FEATURE_64BIT_ALIGNMENT
2099
2100     return result;
2101 }
2102
2103 CORINFO_FIELD_HANDLE
2104 CEEInfo::getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num)
2105 {
2106     CONTRACTL {
2107         SO_TOLERANT;
2108         NOTHROW;
2109         GC_NOTRIGGER;
2110         MODE_PREEMPTIVE;
2111     } CONTRACTL_END;
2112
2113     CORINFO_FIELD_HANDLE result = NULL;
2114
2115     JIT_TO_EE_TRANSITION_LEAF();
2116
2117     TypeHandle VMClsHnd(clsHnd);
2118
2119     MethodTable* pMT= VMClsHnd.AsMethodTable();
2120
2121     result = (CORINFO_FIELD_HANDLE) ((pMT->GetApproxFieldDescListRaw()) + num);
2122
2123     EE_TO_JIT_TRANSITION_LEAF();
2124
2125     return result;
2126 }
2127
2128 mdMethodDef
2129 CEEInfo::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod)
2130 {
2131     CONTRACTL {
2132         SO_TOLERANT;
2133         NOTHROW;
2134         GC_NOTRIGGER;
2135         MODE_PREEMPTIVE;
2136     } CONTRACTL_END;
2137
2138     mdMethodDef result = 0;
2139
2140     JIT_TO_EE_TRANSITION_LEAF();
2141
2142     MethodDesc* pMD = GetMethod(hMethod);
2143
2144     if (pMD->IsDynamicMethod())
2145     {
2146         // Dynamic methods do not have tokens
2147         result = mdMethodDefNil;
2148     }
2149     else
2150     {
2151         result = pMD->GetMemberDef();
2152     }
2153
2154     EE_TO_JIT_TRANSITION_LEAF();
2155
2156     return result;
2157 }
2158
2159 BOOL CEEInfo::checkMethodModifier(CORINFO_METHOD_HANDLE hMethod,
2160                                   LPCSTR modifier,
2161                                   BOOL fOptional)
2162 {
2163     CONTRACTL {
2164         SO_TOLERANT;
2165         THROWS;
2166         GC_TRIGGERS;
2167         MODE_PREEMPTIVE;
2168     } CONTRACTL_END;
2169
2170     BOOL result = FALSE;
2171
2172     JIT_TO_EE_TRANSITION();
2173
2174     MethodDesc* pMD = GetMethod(hMethod);
2175     Module* pModule = pMD->GetModule();
2176     MetaSig sig(pMD);
2177     CorElementType eeType = fOptional ? ELEMENT_TYPE_CMOD_OPT : ELEMENT_TYPE_CMOD_REQD;
2178
2179     // modopts/modreqs for the method are by convention stored on the return type
2180     result = sig.GetReturnProps().HasCustomModifier(pModule, modifier, eeType);
2181
2182     EE_TO_JIT_TRANSITION();
2183
2184     return result;
2185 }
2186
2187 /*********************************************************************/
2188 static unsigned ComputeGCLayout(MethodTable * pMT, BYTE* gcPtrs)
2189 {
2190     STANDARD_VM_CONTRACT;
2191
2192     unsigned result = 0;
2193
2194     _ASSERTE(pMT->IsValueType());
2195
2196     // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in which
2197     // case the check for g_TypedReferenceMT below would not be necessary
2198     if (pMT == g_TypedReferenceMT || pMT->HasSameTypeDefAs(g_pByReferenceClass))
2199     {
2200         if (gcPtrs[0] == TYPE_GC_NONE)
2201         {
2202             gcPtrs[0] = TYPE_GC_BYREF;
2203             result++;
2204         }
2205         else if (gcPtrs[0] != TYPE_GC_BYREF)
2206         {
2207             COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2208         }
2209         return result;
2210     }
2211
2212     ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
2213     for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
2214     {
2215         int fieldStartIndex = pFD->GetOffset() / TARGET_POINTER_SIZE;
2216
2217         if (pFD->GetFieldType() != ELEMENT_TYPE_VALUETYPE)
2218         {
2219             if (pFD->IsObjRef())
2220             {
2221                 if (gcPtrs[fieldStartIndex] == TYPE_GC_NONE)
2222                 {
2223                     gcPtrs[fieldStartIndex] = TYPE_GC_REF;
2224                     result++;
2225                 }
2226                 else if (gcPtrs[fieldStartIndex] != TYPE_GC_REF)
2227                 {
2228                     COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2229                 }
2230             }
2231         }
2232         else
2233         {
2234             MethodTable * pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
2235             result += ComputeGCLayout(pFieldMT, gcPtrs + fieldStartIndex);
2236         }
2237     }
2238     return result;
2239 }
2240
2241 unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
2242 {
2243     CONTRACTL {
2244         SO_TOLERANT;
2245         THROWS;
2246         GC_TRIGGERS;
2247         MODE_PREEMPTIVE;
2248     } CONTRACTL_END;
2249
2250     unsigned result = 0;
2251
2252     JIT_TO_EE_TRANSITION();
2253
2254     TypeHandle VMClsHnd(clsHnd);
2255
2256     MethodTable* pMT = VMClsHnd.GetMethodTable();
2257
2258     if (VMClsHnd.IsNativeValueType())
2259     {
2260         // native value types have no GC pointers
2261         result = 0;
2262         memset(gcPtrs, TYPE_GC_NONE,
2263                (VMClsHnd.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2264     }
2265     else if (pMT->IsByRefLike())
2266     {
2267         // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in
2268         // which case the check for g_TypedReferenceMT below would not be necessary
2269         if (pMT == g_TypedReferenceMT)
2270         {
2271             gcPtrs[0] = TYPE_GC_BYREF;
2272             gcPtrs[1] = TYPE_GC_NONE;
2273             result = 1;
2274         }
2275         else
2276         {
2277             memset(gcPtrs, TYPE_GC_NONE,
2278                 (VMClsHnd.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2279             // Note: This case is more complicated than the TypedReference case
2280             // due to ByRefLike structs being included as fields in other value 
2281             // types (TypedReference can not be.)
2282             result = ComputeGCLayout(VMClsHnd.AsMethodTable(), gcPtrs);
2283         }
2284     }
2285     else
2286     {
2287         _ASSERTE(sizeof(BYTE) == 1);
2288
2289         BOOL isValueClass = pMT->IsValueType();
2290
2291 #ifdef FEATURE_READYTORUN_COMPILER
2292         _ASSERTE(isValueClass || !IsReadyToRunCompilation() || pMT->IsInheritanceChainLayoutFixedInCurrentVersionBubble());
2293 #endif
2294
2295         unsigned int size = isValueClass ? VMClsHnd.GetSize() : pMT->GetNumInstanceFieldBytes() + OBJECT_SIZE;
2296
2297         // assume no GC pointers at first
2298         result = 0;
2299         memset(gcPtrs, TYPE_GC_NONE,
2300                (size + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2301
2302         // walk the GC descriptors, turning on the correct bits
2303         if (pMT->ContainsPointers())
2304         {
2305             CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
2306             CGCDescSeries * pByValueSeries = map->GetLowestSeries();
2307
2308             for (SIZE_T i = 0; i < map->GetNumSeries(); i++)
2309             {
2310                 // Get offset into the value class of the first pointer field (includes a +Object)
2311                 size_t cbSeriesSize = pByValueSeries->GetSeriesSize() + pMT->GetBaseSize();
2312                 size_t cbSeriesOffset = pByValueSeries->GetSeriesOffset();
2313                 size_t cbOffset = isValueClass ? cbSeriesOffset - OBJECT_SIZE : cbSeriesOffset;
2314
2315                 _ASSERTE (cbOffset % TARGET_POINTER_SIZE == 0);
2316                 _ASSERTE (cbSeriesSize % TARGET_POINTER_SIZE == 0);
2317
2318                 result += (unsigned) (cbSeriesSize / TARGET_POINTER_SIZE);
2319                 memset(&gcPtrs[cbOffset / TARGET_POINTER_SIZE], TYPE_GC_REF, cbSeriesSize / TARGET_POINTER_SIZE);
2320
2321                 pByValueSeries++;
2322             }
2323         }
2324     }
2325
2326     EE_TO_JIT_TRANSITION();
2327
2328     return result;
2329 }
2330
2331 // returns the enregister info for a struct based on type of fields, alignment, etc.
2332 bool CEEInfo::getSystemVAmd64PassStructInRegisterDescriptor(
2333                                                 /*IN*/  CORINFO_CLASS_HANDLE structHnd,
2334                                                 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
2335 {
2336     CONTRACTL {
2337         SO_TOLERANT;
2338         THROWS;
2339         GC_TRIGGERS;
2340         MODE_PREEMPTIVE;
2341     } CONTRACTL_END;
2342
2343 #if defined(UNIX_AMD64_ABI_ITF)
2344     JIT_TO_EE_TRANSITION();
2345
2346     _ASSERTE(structPassInRegDescPtr != nullptr);
2347     TypeHandle th(structHnd);
2348
2349     structPassInRegDescPtr->passedInRegisters = false;
2350     
2351     // Make sure this is a value type.
2352     if (th.IsValueType())
2353     {
2354         _ASSERTE((CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeStruct) ||
2355                  (CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeTypedReference));
2356
2357         // The useNativeLayout in this case tracks whether the classification
2358         // is for a native layout of the struct or not.
2359         // If the struct has special marshaling it has a native layout. 
2360         // In such cases the classifier needs to use the native layout.
2361         // For structs with no native layout, the managed layout should be used
2362         // even if classified for the purposes of marshaling/PInvoke passing.
2363         bool useNativeLayout = false;
2364         MethodTable* methodTablePtr = nullptr;
2365         if (!th.IsTypeDesc())
2366         {
2367             methodTablePtr = th.AsMethodTable();
2368         }
2369         else
2370         {
2371             _ASSERTE(th.IsNativeValueType());
2372
2373             useNativeLayout = true;
2374             methodTablePtr = th.AsNativeValueType();
2375         }
2376         _ASSERTE(methodTablePtr != nullptr);
2377
2378         // If we have full support for UNIX_AMD64_ABI, and not just the interface,
2379         // then we've cached whether this is a reg passed struct in the MethodTable, computed during
2380         // MethodTable construction. Otherwise, we are just building in the interface, and we haven't
2381         // computed or cached anything, so we need to compute it now.
2382 #if defined(UNIX_AMD64_ABI)
2383         bool canPassInRegisters = useNativeLayout ? methodTablePtr->GetLayoutInfo()->IsNativeStructPassedInRegisters()
2384                                                   : methodTablePtr->IsRegPassedStruct();
2385 #else // !defined(UNIX_AMD64_ABI)
2386         bool canPassInRegisters = false;
2387         SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2388         if (th.GetSize() <= CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)
2389         {
2390             canPassInRegisters = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2391         }
2392 #endif // !defined(UNIX_AMD64_ABI)
2393
2394         if (canPassInRegisters)
2395         {
2396 #if defined(UNIX_AMD64_ABI)
2397             SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2398             bool result = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2399
2400             // The answer must be true at this point.
2401             _ASSERTE(result);
2402 #endif // UNIX_AMD64_ABI
2403
2404             structPassInRegDescPtr->passedInRegisters = true;
2405
2406             structPassInRegDescPtr->eightByteCount = helper.eightByteCount;
2407             _ASSERTE(structPassInRegDescPtr->eightByteCount <= CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS);
2408
2409             for (unsigned int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++)
2410             {
2411                 structPassInRegDescPtr->eightByteClassifications[i] = helper.eightByteClassifications[i];
2412                 structPassInRegDescPtr->eightByteSizes[i] = helper.eightByteSizes[i];
2413                 structPassInRegDescPtr->eightByteOffsets[i] = helper.eightByteOffsets[i];
2414             }
2415         }
2416
2417         _ASSERTE(structPassInRegDescPtr->passedInRegisters == canPassInRegisters);
2418     }
2419
2420     EE_TO_JIT_TRANSITION();
2421
2422     return true;
2423 #else // !defined(UNIX_AMD64_ABI_ITF)
2424     return false;
2425 #endif // !defined(UNIX_AMD64_ABI_ITF)
2426 }
2427
2428 /*********************************************************************/
2429 unsigned CEEInfo::getClassNumInstanceFields (CORINFO_CLASS_HANDLE clsHnd)
2430 {
2431     CONTRACTL {
2432         SO_TOLERANT;
2433         NOTHROW;
2434         GC_NOTRIGGER;
2435         MODE_PREEMPTIVE;
2436     } CONTRACTL_END;
2437
2438     unsigned result = 0;
2439
2440     JIT_TO_EE_TRANSITION_LEAF();
2441
2442     TypeHandle th(clsHnd);
2443
2444     if (!th.IsTypeDesc())
2445     {
2446         result = th.AsMethodTable()->GetNumInstanceFields();
2447     }
2448     else
2449     {
2450         // native value types are opaque aggregates with explicit size
2451         result = 0;
2452     }
2453
2454     EE_TO_JIT_TRANSITION_LEAF();
2455
2456     return result;
2457 }
2458
2459
2460 CorInfoType CEEInfo::asCorInfoType (CORINFO_CLASS_HANDLE clsHnd)
2461 {
2462     CONTRACTL {
2463         SO_TOLERANT;
2464         THROWS;
2465         GC_TRIGGERS;
2466         MODE_PREEMPTIVE;
2467     } CONTRACTL_END;
2468
2469     CorInfoType result = CORINFO_TYPE_UNDEF;
2470
2471     JIT_TO_EE_TRANSITION();
2472
2473     TypeHandle VMClsHnd(clsHnd);
2474     result = toJitType(VMClsHnd);
2475
2476     EE_TO_JIT_TRANSITION();
2477
2478     return result;
2479 }
2480
2481
2482 CORINFO_LOOKUP_KIND CEEInfo::getLocationOfThisType(CORINFO_METHOD_HANDLE context)
2483 {
2484     CONTRACTL {
2485         SO_TOLERANT;
2486         THROWS;
2487         GC_TRIGGERS;
2488         MODE_PREEMPTIVE;
2489     } CONTRACTL_END;
2490
2491     CORINFO_LOOKUP_KIND result;
2492
2493     /* Initialize fields of result for debug build warning */
2494     result.needsRuntimeLookup = false;
2495     result.runtimeLookupKind  = CORINFO_LOOKUP_THISOBJ;
2496
2497     JIT_TO_EE_TRANSITION();
2498
2499     MethodDesc *pContextMD = GetMethod(context);
2500
2501     // If the method table is not shared, then return CONST
2502     if (!pContextMD->GetMethodTable()->IsSharedByGenericInstantiations())
2503     {
2504         result.needsRuntimeLookup = false;
2505     }
2506     else
2507     {
2508         result.needsRuntimeLookup = true;
2509
2510         // If we've got a vtable extra argument, go through that
2511         if (pContextMD->RequiresInstMethodTableArg())
2512         {
2513             result.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
2514         }
2515         // If we've got an object, go through its vtable
2516         else if (pContextMD->AcquiresInstMethodTableFromThis())
2517         {
2518             result.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
2519         }
2520         // Otherwise go through the method-desc argument
2521         else
2522         {
2523             _ASSERTE(pContextMD->RequiresInstMethodDescArg());
2524             result.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
2525         }
2526     }
2527
2528     EE_TO_JIT_TRANSITION();
2529
2530     return result;
2531 }
2532
2533 CORINFO_METHOD_HANDLE CEEInfo::GetDelegateCtor(
2534                                         CORINFO_METHOD_HANDLE methHnd,
2535                                         CORINFO_CLASS_HANDLE clsHnd,
2536                                         CORINFO_METHOD_HANDLE targetMethodHnd,
2537                                         DelegateCtorArgs *pCtorData)
2538 {
2539     CONTRACTL {
2540         SO_TOLERANT;
2541         THROWS;
2542         GC_TRIGGERS;
2543         MODE_PREEMPTIVE;
2544     } CONTRACTL_END;
2545
2546     if (isVerifyOnly())
2547     {
2548         // No sense going through the optimized case just for verification and it can cause issues parsing
2549         // uninstantiated generic signatures.
2550         return methHnd;
2551     }
2552
2553     CORINFO_METHOD_HANDLE result = NULL;
2554
2555     JIT_TO_EE_TRANSITION();
2556
2557     MethodDesc *pCurrentCtor = (MethodDesc*)methHnd;
2558     if (!pCurrentCtor->IsFCall())
2559     {
2560         result =  methHnd;
2561     }
2562     else
2563     {
2564         MethodDesc *pTargetMethod = (MethodDesc*)targetMethodHnd;
2565         TypeHandle delegateType = (TypeHandle)clsHnd;
2566
2567         MethodDesc *pDelegateCtor = COMDelegate::GetDelegateCtor(delegateType, pTargetMethod, pCtorData);
2568         if (!pDelegateCtor)
2569             pDelegateCtor = pCurrentCtor;
2570         result = (CORINFO_METHOD_HANDLE)pDelegateCtor;
2571     }
2572
2573     EE_TO_JIT_TRANSITION();
2574
2575     return result;
2576 }
2577
2578 void CEEInfo::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd)
2579 {
2580     CONTRACTL {
2581         SO_TOLERANT;
2582         THROWS;
2583         GC_TRIGGERS;
2584         MODE_PREEMPTIVE;
2585     } CONTRACTL_END;
2586
2587     JIT_TO_EE_TRANSITION();
2588
2589     MethodDesc* pMD = GetMethod(methHnd);
2590
2591     if (pMD->IsDynamicMethod())
2592     {
2593         pMD->AsDynamicMethodDesc()->GetResolver()->FreeCompileTimeState();
2594     }
2595
2596     EE_TO_JIT_TRANSITION();
2597 }
2598
2599 // Given a module scope (scopeHnd), a method handle (context) and an metadata token,
2600 // attempt to load the handle (type, field or method) associated with the token.
2601 // If this is not possible at compile-time (because the method code is shared and the token contains type parameters)
2602 // then indicate how the handle should be looked up at run-time.
2603 //
2604 // See corinfo.h for more details
2605 //
2606 void CEEInfo::embedGenericHandle(
2607             CORINFO_RESOLVED_TOKEN * pResolvedToken,
2608             BOOL                     fEmbedParent,
2609             CORINFO_GENERICHANDLE_RESULT *pResult)
2610 {
2611     CONTRACTL {
2612         SO_TOLERANT;
2613         THROWS;
2614         GC_TRIGGERS;
2615         MODE_PREEMPTIVE;
2616     } CONTRACTL_END;
2617
2618     INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
2619
2620     JIT_TO_EE_TRANSITION();
2621
2622     BOOL fRuntimeLookup;
2623     MethodDesc * pTemplateMD = NULL;    
2624
2625     if (!fEmbedParent && pResolvedToken->hMethod != NULL)
2626     {
2627         MethodDesc * pMD = (MethodDesc *)pResolvedToken->hMethod;
2628         TypeHandle th(pResolvedToken->hClass);
2629
2630         pResult->handleType = CORINFO_HANDLETYPE_METHOD;
2631
2632         Instantiation methodInst = pMD->GetMethodInstantiation();
2633
2634         pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, th.GetMethodTable(), FALSE, methodInst, FALSE);
2635
2636         // Normalize the method handle for reflection
2637         if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Ldtoken)
2638             pMD = MethodDesc::FindOrCreateAssociatedMethodDescForReflection(pMD, th, methodInst);
2639
2640         pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pMD;
2641         pTemplateMD = pMD;
2642
2643         // Runtime lookup is only required for stubs. Regular entrypoints are always the same shared MethodDescs.
2644         fRuntimeLookup = pMD->IsWrapperStub() &&
2645             (pMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(methodInst));
2646     }
2647     else
2648     if (!fEmbedParent && pResolvedToken->hField != NULL)
2649     {
2650         FieldDesc * pFD = (FieldDesc *)pResolvedToken->hField;
2651         TypeHandle th(pResolvedToken->hClass);
2652
2653         pResult->handleType = CORINFO_HANDLETYPE_FIELD;
2654
2655         pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pFD;
2656
2657         fRuntimeLookup = th.IsSharedByGenericInstantiations() && pFD->IsStatic();
2658     }
2659     else
2660     {
2661         TypeHandle th(pResolvedToken->hClass);
2662
2663         pResult->handleType = CORINFO_HANDLETYPE_CLASS;
2664
2665         if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
2666         {
2667             pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsArray()->GetTemplateMethodTable();
2668         }
2669         else
2670         {
2671             pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsPtr();
2672         }
2673
2674         if (fEmbedParent && pResolvedToken->hMethod != NULL)
2675         {
2676             MethodDesc * pDeclaringMD = (MethodDesc *)pResolvedToken->hMethod;
2677
2678             if (!pDeclaringMD->GetMethodTable()->HasSameTypeDefAs(th.GetMethodTable()))
2679             {
2680                 //
2681                 // The method type may point to a sub-class of the actual class that declares the method.
2682                 // It is important to embed the declaring type in this case.
2683                 //
2684
2685                 pTemplateMD = pDeclaringMD;
2686
2687                 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pDeclaringMD->GetMethodTable();
2688             }
2689         }
2690
2691         // IsSharedByGenericInstantiations would not work here. The runtime lookup is required
2692         // even for standalone generic variables that show up as __Canon here.
2693         fRuntimeLookup = th.IsCanonicalSubtype();
2694     }
2695
2696     _ASSERTE(pResult->compileTimeHandle);
2697
2698     if (fRuntimeLookup 
2699             // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
2700             && ContextIsShared(pResolvedToken->tokenContext))
2701     {
2702         DictionaryEntryKind entryKind = EmptySlot;
2703         switch (pResult->handleType)
2704         {
2705         case CORINFO_HANDLETYPE_CLASS:
2706             entryKind = (pTemplateMD != NULL) ? DeclaringTypeHandleSlot : TypeHandleSlot;
2707             break;
2708         case CORINFO_HANDLETYPE_METHOD:
2709             entryKind = MethodDescSlot;
2710             break;
2711         case CORINFO_HANDLETYPE_FIELD:
2712             entryKind = FieldDescSlot;
2713             break;
2714         default:
2715             _ASSERTE(false);
2716         }
2717
2718         ComputeRuntimeLookupForSharedGenericToken(entryKind,
2719                                                   pResolvedToken,
2720                                                   NULL,
2721                                                   pTemplateMD,
2722                                                   &pResult->lookup);
2723     }
2724     else
2725     {
2726         // If the target is not shared then we've already got our result and
2727         // can simply do a static look up
2728         pResult->lookup.lookupKind.needsRuntimeLookup = false;
2729
2730         pResult->lookup.constLookup.handle = pResult->compileTimeHandle;
2731         pResult->lookup.constLookup.accessType = IAT_VALUE;
2732     }
2733     
2734     EE_TO_JIT_TRANSITION();
2735 }
2736
2737 void CEEInfo::ScanForModuleDependencies(Module* pModule, SigPointer psig)
2738 {
2739     STANDARD_VM_CONTRACT;
2740
2741     _ASSERTE(pModule && !pModule->IsSystem());
2742
2743     CorElementType eType;
2744     IfFailThrow(psig.GetElemType(&eType));
2745     
2746     switch (eType)
2747     {
2748         case ELEMENT_TYPE_GENERICINST:
2749         {
2750             ScanForModuleDependencies(pModule,psig);
2751             IfFailThrow(psig.SkipExactlyOne());
2752
2753             ULONG ntypars;
2754             IfFailThrow(psig.GetData(&ntypars));
2755             for (ULONG i = 0; i < ntypars; i++)
2756             {
2757               ScanForModuleDependencies(pModule,psig);
2758               IfFailThrow(psig.SkipExactlyOne());
2759             }
2760             break;
2761         }
2762
2763         case ELEMENT_TYPE_VALUETYPE:
2764         case ELEMENT_TYPE_CLASS:
2765         {
2766             mdToken tk;
2767             IfFailThrow(psig.GetToken(&tk));
2768             if (TypeFromToken(tk) ==  mdtTypeRef)
2769             {
2770                 Module * pTypeDefModule;
2771                 mdToken tkTypeDef;
2772
2773                 if  (ClassLoader::ResolveTokenToTypeDefThrowing(pModule, tk, &pTypeDefModule, &tkTypeDef))
2774                     break;
2775
2776                 if (!pTypeDefModule->IsSystem() && (pModule != pTypeDefModule))
2777                 {
2778                     m_pOverride->addActiveDependency((CORINFO_MODULE_HANDLE)pModule, (CORINFO_MODULE_HANDLE)pTypeDefModule);
2779                 }
2780             }
2781             break;
2782         }
2783
2784         default:
2785             break;
2786     }
2787 }
2788
2789 void CEEInfo::ScanMethodSpec(Module * pModule, PCCOR_SIGNATURE pMethodSpec, ULONG cbMethodSpec)
2790 {
2791     STANDARD_VM_CONTRACT;
2792
2793     SigPointer sp(pMethodSpec, cbMethodSpec);
2794
2795     BYTE etype;
2796     IfFailThrow(sp.GetByte(&etype));
2797
2798     _ASSERT(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST);
2799
2800     ULONG nGenericMethodArgs;
2801     IfFailThrow(sp.GetData(&nGenericMethodArgs));
2802
2803     for (ULONG i = 0; i < nGenericMethodArgs; i++)
2804     {
2805         ScanForModuleDependencies(pModule,sp);
2806         IfFailThrow(sp.SkipExactlyOne());
2807     }
2808 }
2809
2810 BOOL CEEInfo::ScanTypeSpec(Module * pModule, PCCOR_SIGNATURE pTypeSpec, ULONG cbTypeSpec)
2811 {
2812     STANDARD_VM_CONTRACT;
2813
2814     SigPointer sp(pTypeSpec, cbTypeSpec);
2815
2816     CorElementType eType;
2817     IfFailThrow(sp.GetElemType(&eType));
2818
2819     // Filter out non-instantiated types and typedescs (typevars, arrays, ...)
2820     if (eType != ELEMENT_TYPE_GENERICINST)
2821     {
2822         // Scanning of the parent chain is required for reference types only.
2823         // Note that the parent chain MUST NOT be scanned for instantiated 
2824         // generic variables because of they are not a real dependencies.
2825         return (eType == ELEMENT_TYPE_CLASS);
2826     }
2827
2828     IfFailThrow(sp.SkipExactlyOne());
2829
2830     ULONG ntypars;
2831     IfFailThrow(sp.GetData(&ntypars));
2832
2833     for (ULONG i = 0; i < ntypars; i++)
2834     {
2835         ScanForModuleDependencies(pModule,sp);
2836         IfFailThrow(sp.SkipExactlyOne());
2837     }
2838
2839     return TRUE;
2840 }
2841
2842 void CEEInfo::ScanInstantiation(Module * pModule, Instantiation inst)
2843 {
2844     STANDARD_VM_CONTRACT;
2845
2846     for (DWORD i = 0; i < inst.GetNumArgs(); i++)
2847     {
2848         TypeHandle th = inst[i];
2849         if (th.IsTypeDesc())
2850             continue;
2851
2852         MethodTable * pMT = th.AsMethodTable();
2853
2854         Module * pDefModule = pMT->GetModule();
2855
2856         if (!pDefModule->IsSystem() && (pModule != pDefModule))
2857         {
2858             m_pOverride->addActiveDependency((CORINFO_MODULE_HANDLE)pModule, (CORINFO_MODULE_HANDLE)pDefModule);
2859         }
2860
2861         if (pMT->HasInstantiation())
2862         {
2863             ScanInstantiation(pModule, pMT->GetInstantiation());
2864         }
2865     }
2866 }
2867
2868 //
2869 // ScanToken is used to track triggers for creation of per-AppDomain state instead, including allocations required for statics and
2870 // triggering of module cctors.
2871 //
2872 // The basic rule is: There should be no possibility of a shared module that is "active" to have a direct call into a  module that 
2873 // is not "active". And we don't want to intercept every call during runtime, so during compile time we track static calls and 
2874 // everything that can result in new virtual calls.
2875 //
2876 // The current algorithm (scan the parent type chain and instantiation variables) is more than enough to maintain this invariant.
2877 // One could come up with a more efficient algorithm that still maintains the invariant, but it may introduce backward compatibility
2878 // issues.
2879 //
2880 // For efficiency, the implementation leverages the loaded types as much as possible. Unfortunately, we still have to go back to
2881 // metadata when the generic variables could have been substituted via generic context.
2882 //
2883 void CEEInfo::ScanToken(Module * pModule, CORINFO_RESOLVED_TOKEN * pResolvedToken, TypeHandle th, MethodDesc * pMD)
2884 {
2885     STANDARD_VM_CONTRACT;
2886
2887     if (pModule->IsSystem())
2888         return;
2889
2890     if (isVerifyOnly())
2891         return;
2892
2893     //
2894     // Scan method instantiation
2895     //
2896     if (pMD != NULL && pResolvedToken->pMethodSpec != NULL)
2897     {
2898         if (ContextIsInstantiated(pResolvedToken->tokenContext))
2899         {
2900             ScanMethodSpec(pModule, pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
2901         }
2902         else
2903         {
2904             ScanInstantiation(pModule, pMD->GetMethodInstantiation());
2905         }
2906     }
2907
2908     if (th.IsTypeDesc())
2909         return;
2910
2911     MethodTable * pMT = th.AsMethodTable();
2912
2913     //
2914     // Scan type instantiation
2915     //
2916     if (pResolvedToken->pTypeSpec != NULL)
2917     {
2918         if (ContextIsInstantiated(pResolvedToken->tokenContext))
2919         {
2920             if (!ScanTypeSpec(pModule, pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec))
2921                 return;
2922         }
2923         else
2924         {
2925             ScanInstantiation(pModule, pMT->GetInstantiation());
2926         }
2927     }
2928
2929     //
2930     // Scan chain of parent types
2931     //
2932     for (;;)
2933     {
2934         Module * pDefModule = pMT->GetModule();
2935         if (pDefModule->IsSystem())
2936             break;
2937
2938         if (pModule != pDefModule)
2939         {
2940             m_pOverride->addActiveDependency((CORINFO_MODULE_HANDLE)pModule, (CORINFO_MODULE_HANDLE)pDefModule);
2941         }
2942
2943         MethodTable * pParentMT = pMT->GetParentMethodTable();
2944         if (pParentMT == NULL)
2945             break;
2946
2947         if (pParentMT->HasInstantiation())
2948         {
2949             IMDInternalImport* pInternalImport = pDefModule->GetMDImport();
2950
2951             mdToken tkParent;
2952             IfFailThrow(pInternalImport->GetTypeDefProps(pMT->GetCl(), NULL, &tkParent));
2953
2954             if (TypeFromToken(tkParent) == mdtTypeSpec)
2955             {
2956                 PCCOR_SIGNATURE pTypeSpec;
2957                 ULONG           cbTypeSpec;
2958                 IfFailThrow(pInternalImport->GetTypeSpecFromToken(tkParent, &pTypeSpec, &cbTypeSpec));
2959
2960                 ScanTypeSpec(pDefModule, pTypeSpec, cbTypeSpec);
2961             }
2962         }
2963
2964         pMT = pParentMT;
2965     }
2966 }
2967
2968 void CEEInfo::ScanTokenForDynamicScope(CORINFO_RESOLVED_TOKEN * pResolvedToken, TypeHandle th, MethodDesc * pMD)
2969 {
2970     STANDARD_VM_CONTRACT;
2971
2972     if (m_pMethodBeingCompiled->IsLCGMethod())
2973     {
2974         // The dependency tracking for LCG is irrelevant. Perform immediate activation.
2975         if (pMD != NULL && pMD->HasMethodInstantiation())
2976             pMD->EnsureActive();
2977         if (!th.IsTypeDesc())
2978             th.AsMethodTable()->EnsureInstanceActive();
2979         return;
2980     }
2981
2982     // Stubs-as-IL have to do regular dependency tracking because they can be shared cross-domain.
2983     Module * pModule = GetDynamicResolver(pResolvedToken->tokenScope)->GetDynamicMethod()->GetModule();
2984     ScanToken(pModule, pResolvedToken, th, pMD);
2985 }
2986
2987 MethodDesc * CEEInfo::GetMethodForSecurity(CORINFO_METHOD_HANDLE callerHandle)
2988 {
2989     STANDARD_VM_CONTRACT;
2990
2991     // Cache the cast lookup
2992     if (callerHandle == m_hMethodForSecurity_Key)
2993     {
2994         return m_pMethodForSecurity_Value;
2995     }
2996
2997     MethodDesc * pCallerMethod = (MethodDesc *)callerHandle;
2998
2999     //If the caller is generic, load the open type and then load the field again,  This allows us to
3000     //differentiate between BadGeneric<T> containing a memberRef for a field of type InaccessibleClass and
3001     //GoodGeneric<T> containing a memberRef for a field of type T instantiated over InaccessibleClass.
3002     MethodDesc * pMethodForSecurity = pCallerMethod->IsILStub() ? 
3003         pCallerMethod : pCallerMethod->LoadTypicalMethodDefinition();
3004
3005     m_hMethodForSecurity_Key = callerHandle;
3006     m_pMethodForSecurity_Value = pMethodForSecurity;
3007
3008     return pMethodForSecurity;
3009 }
3010
3011 // Check that the instantation is <!/!!0, ..., !/!!(n-1)>
3012 static BOOL IsSignatureForTypicalInstantiation(SigPointer sigptr, CorElementType varType, ULONG ntypars)
3013 {
3014     STANDARD_VM_CONTRACT;
3015
3016     for (ULONG i = 0; i < ntypars; i++)
3017     {
3018         CorElementType type;
3019         IfFailThrow(sigptr.GetElemType(&type));
3020         if (type != varType)
3021             return FALSE;
3022
3023         ULONG data;
3024         IfFailThrow(sigptr.GetData(&data));
3025                     
3026         if (data != i)
3027              return FALSE;
3028     }
3029
3030     return TRUE;
3031 }
3032
3033 // Check that methodSpec instantiation is <!!0, ..., !!(n-1)>
3034 static BOOL IsMethodSpecForTypicalInstantation(SigPointer sigptr)
3035 {
3036     STANDARD_VM_CONTRACT;
3037
3038     BYTE etype;
3039     IfFailThrow(sigptr.GetByte(&etype));
3040     _ASSERTE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST);
3041
3042     ULONG ntypars;
3043     IfFailThrow(sigptr.GetData(&ntypars));
3044
3045     return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_MVAR, ntypars);
3046 }
3047
3048 // Check that typeSpec instantiation is <!0, ..., !(n-1)>
3049 static BOOL IsTypeSpecForTypicalInstantiation(SigPointer sigptr)
3050 {
3051     STANDARD_VM_CONTRACT;
3052
3053     CorElementType type;
3054     IfFailThrow(sigptr.GetElemType(&type));
3055     if (type != ELEMENT_TYPE_GENERICINST)
3056         return FALSE;
3057
3058     IfFailThrow(sigptr.SkipExactlyOne());
3059
3060     ULONG ntypars;
3061     IfFailThrow(sigptr.GetData(&ntypars));
3062
3063     return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_VAR, ntypars);
3064 }
3065
3066 void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entryKind,
3067                                                         CORINFO_RESOLVED_TOKEN * pResolvedToken,
3068                                                         CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
3069                                                         MethodDesc * pTemplateMD /* for method-based slots */,
3070                                                         CORINFO_LOOKUP *pResultLookup)
3071 {
3072     CONTRACTL{
3073         STANDARD_VM_CHECK;
3074         PRECONDITION(CheckPointer(pResultLookup));
3075     } CONTRACTL_END;
3076
3077
3078     // We should never get here when we are only verifying
3079     _ASSERTE(!isVerifyOnly());
3080
3081     pResultLookup->lookupKind.needsRuntimeLookup = true;
3082     pResultLookup->lookupKind.runtimeLookupFlags = 0;
3083
3084     CORINFO_RUNTIME_LOOKUP *pResult = &pResultLookup->runtimeLookup;
3085     pResult->signature = NULL;
3086
3087     pResult->indirectFirstOffset = 0;
3088     pResult->indirectSecondOffset = 0;
3089
3090     // Unless we decide otherwise, just do the lookup via a helper function
3091     pResult->indirections = CORINFO_USEHELPER;
3092
3093     MethodDesc *pContextMD = GetMethodFromContext(pResolvedToken->tokenContext);
3094     MethodTable *pContextMT = pContextMD->GetMethodTable();
3095
3096     // Do not bother computing the runtime lookup if we are inlining. The JIT is going
3097     // to abort the inlining attempt anyway.
3098     if (pContextMD != m_pMethodBeingCompiled)
3099     {
3100         return;
3101     }
3102
3103     // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup. 
3104     // All callers of ComputeRuntimeLookupForSharedGenericToken have to filter out this case. We can't do much about it here.
3105     _ASSERTE(pContextMD->IsSharedByGenericInstantiations());
3106
3107     BOOL fInstrument = FALSE;
3108
3109 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
3110     // This will make sure that when IBC logging is turned on we will go through a version
3111     // of JIT_GenericHandle which logs the access. Note that we still want the dictionaries
3112     // to be populated to prepopulate the types at NGen time.
3113     if (IsCompilingForNGen() &&
3114         GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
3115     {
3116         fInstrument = TRUE;
3117     }
3118 #endif // FEATURE_NATIVE_IMAGE_GENERATION
3119
3120     if (pContextMD->RequiresInstMethodDescArg())
3121     {
3122         pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
3123     }
3124     else
3125     {
3126         if (pContextMD->RequiresInstMethodTableArg())
3127             pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
3128         else
3129             pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
3130     }
3131
3132 #ifdef FEATURE_READYTORUN_COMPILER
3133     if (IsReadyToRunCompilation())
3134     {
3135         pResultLookup->lookupKind.runtimeLookupArgs = NULL;
3136
3137         switch (entryKind)
3138         {
3139         case DeclaringTypeHandleSlot:
3140             _ASSERTE(pTemplateMD != NULL);
3141             pResultLookup->lookupKind.runtimeLookupArgs = pTemplateMD->GetMethodTable();
3142             pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_DeclaringTypeHandle;
3143             break;
3144
3145         case TypeHandleSlot:
3146             pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_TypeHandle;
3147             break;
3148
3149         case MethodDescSlot:
3150         case MethodEntrySlot:
3151         case ConstrainedMethodEntrySlot:
3152         case DispatchStubAddrSlot:
3153         {
3154             if (pTemplateMD != (MethodDesc*)pResolvedToken->hMethod)
3155                 ThrowHR(E_NOTIMPL);
3156
3157             if (entryKind == MethodDescSlot)
3158                 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_MethodHandle;
3159             else if (entryKind == MethodEntrySlot || entryKind == ConstrainedMethodEntrySlot)
3160                 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_MethodEntry;
3161             else
3162                 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_VirtualEntry;
3163
3164             pResultLookup->lookupKind.runtimeLookupArgs = pConstrainedResolvedToken;
3165
3166             break;
3167         }
3168
3169         case FieldDescSlot:
3170             pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_FieldHandle;
3171             break;
3172
3173         default:
3174             _ASSERTE(!"Unknown dictionary entry kind!");
3175             IfFailThrow(E_FAIL);
3176         }
3177
3178         // For R2R compilations, we don't generate the dictionary lookup signatures (dictionary lookups are done in a 
3179         // different way that is more version resilient... plus we can't have pointers to existing MTs/MDs in the sigs)
3180         return;
3181     }
3182 #endif
3183     // If we've got a  method type parameter of any kind then we must look in the method desc arg
3184     if (pContextMD->RequiresInstMethodDescArg())
3185     {
3186         pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG : CORINFO_HELP_RUNTIMEHANDLE_METHOD;
3187
3188         if (fInstrument)
3189             goto NoSpecialCase;
3190
3191         // Special cases:
3192         // (1) Naked method type variable: look up directly in instantiation hanging off runtime md
3193         // (2) Reference to method-spec of current method (e.g. a recursive call) i.e. currentmeth<!0,...,!(n-1)>
3194         if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3195         {
3196             SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3197             CorElementType type;
3198             IfFailThrow(sigptr.GetElemType(&type));
3199             if (type == ELEMENT_TYPE_MVAR)
3200             {
3201                 pResult->indirections = 2;
3202                 pResult->testForNull = 0;
3203 #ifdef FEATURE_PREJIT
3204                 pResult->testForFixup = 1;
3205 #else
3206                 pResult->testForFixup = 0;
3207 #endif
3208                 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3209
3210                 if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
3211                 {
3212                     pResult->indirectFirstOffset = 1;
3213                 }
3214
3215                 ULONG data;
3216                 IfFailThrow(sigptr.GetData(&data));
3217                 pResult->offsets[1] = sizeof(TypeHandle) * data;
3218
3219                 return;
3220             }
3221         }
3222         else if (entryKind == MethodDescSlot)
3223         {
3224             // It's the context itself (i.e. a recursive call)
3225             if (!pTemplateMD->HasSameMethodDefAs(pContextMD))
3226                 goto NoSpecialCase;
3227
3228             // Now just check that the instantiation is (!!0, ..., !!(n-1))
3229             if (!IsMethodSpecForTypicalInstantation(SigPointer(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)))
3230                 goto NoSpecialCase;
3231
3232             // Type instantiation has to match too if there is one
3233             if (pContextMT->HasInstantiation())
3234             {
3235                 TypeHandle thTemplate(pResolvedToken->hClass);
3236
3237                 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3238                     goto NoSpecialCase;
3239
3240                 // This check filters out method instantiation on generic type definition, like G::M<!!0>()
3241                 // We may not ever get it here. Filter it out just to be sure...
3242                 if (pResolvedToken->pTypeSpec == NULL)
3243                     goto NoSpecialCase;
3244
3245                 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3246                     goto NoSpecialCase;
3247             }
3248
3249             // Just use the method descriptor that was passed in!
3250             pResult->indirections = 0;
3251             pResult->testForNull = 0;
3252             pResult->testForFixup = 0;
3253
3254             return;
3255         }
3256     }
3257     // Otherwise we must just have class type variables
3258     else
3259     {
3260         _ASSERTE(pContextMT->GetNumGenericArgs() > 0);
3261
3262         if (pContextMD->RequiresInstMethodTableArg())
3263         {
3264             // If we've got a vtable extra argument, go through that
3265             pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3266         }
3267         // If we've got an object, go through its vtable
3268         else
3269         {
3270             _ASSERTE(pContextMD->AcquiresInstMethodTableFromThis());
3271             pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3272         }
3273
3274         if (fInstrument)
3275             goto NoSpecialCase;
3276
3277         // Special cases:
3278         // (1) Naked class type variable: look up directly in instantiation hanging off vtable
3279         // (2) C<!0,...,!(n-1)> where C is the context's class and C is sealed: just return vtable ptr
3280         if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3281         {
3282             SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3283             CorElementType type;
3284             IfFailThrow(sigptr.GetElemType(&type));
3285             if (type == ELEMENT_TYPE_VAR)
3286             {
3287                 pResult->indirections = 3;
3288                 pResult->testForNull = 0;
3289 #ifdef FEATURE_PREJIT
3290                 pResult->testForFixup = 1;
3291 #else
3292                 pResult->testForFixup = 0;
3293 #endif
3294                 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3295                 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3296                 ULONG data;
3297                 IfFailThrow(sigptr.GetData(&data));
3298                 pResult->offsets[2] = sizeof(TypeHandle) * data;
3299
3300                 if (MethodTable::IsPerInstInfoRelative())
3301                 {
3302                     pResult->indirectFirstOffset = 1;
3303                     pResult->indirectSecondOffset = 1;
3304                 }
3305
3306                 return;
3307             }
3308             else if (type == ELEMENT_TYPE_GENERICINST &&
3309                 (pContextMT->IsSealed() || pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM))
3310             {
3311                 TypeHandle thTemplate(pResolvedToken->hClass);
3312
3313                 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3314                     goto NoSpecialCase;
3315
3316                 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3317                     goto NoSpecialCase;
3318
3319                 // Just use the vtable pointer itself!
3320                 pResult->indirections = 0;
3321                 pResult->testForNull = 0;
3322                 pResult->testForFixup = 0;
3323
3324                 return;
3325             }
3326         }
3327     }
3328
3329 NoSpecialCase:
3330
3331     SigBuilder sigBuilder;
3332
3333     sigBuilder.AppendData(entryKind);
3334
3335     if (pResultLookup->lookupKind.runtimeLookupKind != CORINFO_LOOKUP_METHODPARAM)
3336     {
3337         _ASSERTE(pContextMT->GetNumDicts() > 0);
3338         sigBuilder.AppendData(pContextMT->GetNumDicts() - 1);
3339     }
3340
3341     Module * pModule = (Module *)pResolvedToken->tokenScope;
3342
3343     switch (entryKind)
3344     {
3345     case DeclaringTypeHandleSlot:
3346         _ASSERTE(pTemplateMD != NULL);
3347         sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3348         sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3349         // fall through
3350
3351     case TypeHandleSlot:
3352         {
3353             if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
3354             {
3355                 if (!IsReadyToRunCompilation())
3356                 {
3357                     sigBuilder.AppendElementType((CorElementType)ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
3358                 }
3359
3360                 sigBuilder.AppendElementType(ELEMENT_TYPE_SZARRAY);
3361             }
3362
3363             // Note that we can come here with pResolvedToken->pTypeSpec == NULL for invalid IL that 
3364             // directly references __Canon
3365             if (pResolvedToken->pTypeSpec != NULL)
3366             {
3367                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3368                 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3369             }
3370             else
3371             {
3372                 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3373                 sigBuilder.AppendPointer(pResolvedToken->hClass);
3374             }
3375         }
3376         break;
3377
3378     case ConstrainedMethodEntrySlot:
3379         // Encode constrained type token
3380         if (pConstrainedResolvedToken->pTypeSpec != NULL)
3381         {
3382             SigPointer sigptr(pConstrainedResolvedToken->pTypeSpec, pConstrainedResolvedToken->cbTypeSpec);
3383             sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3384         }
3385         else
3386         {
3387             sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3388             sigBuilder.AppendPointer(pConstrainedResolvedToken->hClass);
3389         }
3390         // fall through
3391
3392     case MethodDescSlot:
3393     case MethodEntrySlot:
3394     case DispatchStubAddrSlot:
3395         {
3396             // Encode containing type
3397             if (pResolvedToken->pTypeSpec != NULL)
3398             {
3399                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3400                 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3401             }
3402             else
3403             {
3404                 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3405                 sigBuilder.AppendPointer(pResolvedToken->hClass);
3406             }
3407
3408             // Encode method
3409             _ASSERTE(pTemplateMD != NULL);
3410
3411             mdMethodDef methodToken               = pTemplateMD->GetMemberDef_NoLogging();
3412             DWORD       methodFlags               = 0;
3413
3414             // Check for non-NULL method spec first. We can encode the method instantiation only if we have one in method spec to start with. Note that there are weird cases 
3415             // like instantiating stub for generic method definition that do not have method spec but that won't be caught by the later conditions either.
3416             BOOL fMethodNeedsInstantiation = (pResolvedToken->pMethodSpec != NULL) && pTemplateMD->HasMethodInstantiation() && !pTemplateMD->IsGenericMethodDefinition();
3417
3418             if (pTemplateMD->IsUnboxingStub())
3419                 methodFlags |= ENCODE_METHOD_SIG_UnboxingStub;
3420             // Always create instantiating stub for method entry points even if the template does not ask for it. It saves caller 
3421             // from creating throw-away instantiating stub.
3422             if (pTemplateMD->IsInstantiatingStub() || (entryKind == MethodEntrySlot))
3423                 methodFlags |= ENCODE_METHOD_SIG_InstantiatingStub;
3424             if (fMethodNeedsInstantiation)
3425                 methodFlags |= ENCODE_METHOD_SIG_MethodInstantiation;
3426             if (IsNilToken(methodToken))
3427             {
3428                 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3429             }
3430             else
3431             if (entryKind == DispatchStubAddrSlot && pTemplateMD->IsVtableMethod())
3432             {
3433                 // Encode the method for dispatch stub using slot to avoid touching the interface method MethodDesc at runtime
3434
3435                 // There should be no other flags set if we are encoding the method using slot for virtual stub dispatch
3436                 _ASSERTE(methodFlags == 0);
3437
3438                 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3439             }
3440             else
3441             if (!pTemplateMD->GetModule()->IsInCurrentVersionBubble())
3442             {
3443                 // Using a method defined in another version bubble. We can assume the slot number is stable only for real interface methods.
3444                 if (!pTemplateMD->GetMethodTable()->IsInterface() || pTemplateMD->IsStatic() || pTemplateMD->HasMethodInstantiation())
3445                 {
3446                     _ASSERTE(!"References to non-interface methods not yet supported in version resilient images");
3447                     IfFailThrow(E_FAIL);
3448                 }
3449                 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3450             }
3451
3452             sigBuilder.AppendData(methodFlags);
3453
3454             if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
3455             {
3456                 // Encode method token and its module context (as method's type)
3457                 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3458                 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3459                 
3460                 sigBuilder.AppendData(RidFromToken(methodToken));
3461             }
3462             else
3463             {
3464                 sigBuilder.AppendData(pTemplateMD->GetSlot());
3465             }
3466
3467             if (fMethodNeedsInstantiation)
3468             {
3469                 SigPointer sigptr(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
3470                 
3471                 BYTE etype;
3472                 IfFailThrow(sigptr.GetByte(&etype));
3473
3474                 // Load the generic method instantiation
3475                 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, pModule);
3476                 
3477                 DWORD nGenericMethodArgs;
3478                 IfFailThrow(sigptr.GetData(&nGenericMethodArgs));
3479                 sigBuilder.AppendData(nGenericMethodArgs);
3480                 
3481                 _ASSERTE(nGenericMethodArgs == pTemplateMD->GetNumGenericMethodArgs());
3482                 
3483                 for (DWORD i = 0; i < nGenericMethodArgs; i++)
3484                 {
3485                     sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3486                 }
3487             }
3488         }
3489         break;
3490         
3491     case FieldDescSlot:
3492         {
3493             if (pResolvedToken->pTypeSpec != NULL)
3494             {
3495                  // Encode containing type
3496                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3497                 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3498             }
3499             else
3500             {
3501                 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3502                 sigBuilder.AppendPointer(pResolvedToken->hClass);
3503             }
3504
3505             FieldDesc * pField = (FieldDesc *)pResolvedToken->hField;
3506             _ASSERTE(pField != NULL);
3507
3508             DWORD fieldIndex = pField->GetApproxEnclosingMethodTable()->GetIndexForFieldDesc(pField);
3509             sigBuilder.AppendData(fieldIndex);
3510         }
3511         break;
3512         
3513     default:
3514         _ASSERTE(false);
3515     }
3516
3517     DictionaryEntrySignatureSource signatureSource = (IsCompilationProcess() ? FromZapImage : FromJIT);
3518
3519     // It's a method dictionary lookup
3520     if (pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM)
3521     {
3522         _ASSERTE(pContextMD != NULL);
3523         _ASSERTE(pContextMD->HasMethodInstantiation());
3524
3525         if (DictionaryLayout::FindToken(pContextMD->GetLoaderAllocator(), pContextMD->GetNumGenericMethodArgs(), pContextMD->GetDictionaryLayout(), pResult, &sigBuilder, 1, signatureSource))
3526         {
3527             pResult->testForNull = 1;
3528             pResult->testForFixup = 0;
3529
3530             // Indirect through dictionary table pointer in InstantiatedMethodDesc
3531             pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3532
3533             if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
3534             {
3535                 pResult->indirectFirstOffset = 1;
3536             }
3537         }
3538     }
3539
3540     // It's a class dictionary lookup (CORINFO_LOOKUP_CLASSPARAM or CORINFO_LOOKUP_THISOBJ)
3541     else
3542     {
3543         if (DictionaryLayout::FindToken(pContextMT->GetLoaderAllocator(), pContextMT->GetNumGenericArgs(), pContextMT->GetClass()->GetDictionaryLayout(), pResult, &sigBuilder, 2, signatureSource))
3544         {
3545             pResult->testForNull = 1;
3546             pResult->testForFixup = 0;
3547
3548             // Indirect through dictionary table pointer in vtable
3549             pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3550
3551             // Next indirect through the dictionary appropriate to this instantiated type
3552             pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3553
3554             if (MethodTable::IsPerInstInfoRelative())
3555             {
3556                 pResult->indirectFirstOffset = 1;
3557                 pResult->indirectSecondOffset = 1;
3558             }
3559         }
3560     }
3561 }
3562
3563
3564
3565 /*********************************************************************/
3566 const char* CEEInfo::getClassName (CORINFO_CLASS_HANDLE clsHnd)
3567 {
3568     CONTRACTL {
3569         SO_TOLERANT;
3570         THROWS;
3571         GC_TRIGGERS;
3572         MODE_PREEMPTIVE;
3573     } CONTRACTL_END;
3574
3575     const char* result = NULL;
3576
3577     JIT_TO_EE_TRANSITION();
3578
3579     TypeHandle VMClsHnd(clsHnd);
3580     MethodTable* pMT = VMClsHnd.GetMethodTable();
3581     if (pMT == NULL)
3582     {
3583         result = "";
3584     }
3585     else
3586     {
3587 #ifdef _DEBUG
3588         result = pMT->GetDebugClassName();
3589 #else // !_DEBUG
3590         // since this is for diagnostic purposes only,
3591         // give up on the namespace, as we don't have a buffer to concat it
3592         // also note this won't show array class names.
3593         LPCUTF8 nameSpace;
3594         result = pMT->GetFullyQualifiedNameInfo(&nameSpace);
3595 #endif
3596     }
3597
3598     EE_TO_JIT_TRANSITION();
3599
3600     return result;
3601 }
3602
3603 /***********************************************************************/
3604 const char* CEEInfo::getHelperName (CorInfoHelpFunc ftnNum)
3605 {
3606     CONTRACTL {
3607         SO_TOLERANT;
3608         NOTHROW;
3609         GC_NOTRIGGER;
3610         MODE_PREEMPTIVE;
3611         PRECONDITION(ftnNum >= 0 && ftnNum < CORINFO_HELP_COUNT);
3612     } CONTRACTL_END;
3613
3614     const char* result = NULL;
3615
3616     JIT_TO_EE_TRANSITION_LEAF();
3617
3618 #ifdef CROSSGEN_COMPILE
3619     result = hlpNameTable[ftnNum];
3620 #else
3621 #ifdef _DEBUG
3622     result = hlpFuncTable[ftnNum].name;
3623 #else
3624     result = "AnyJITHelper";
3625 #endif
3626 #endif
3627
3628     EE_TO_JIT_TRANSITION_LEAF();
3629
3630     return result;
3631 }
3632
3633
3634 /*********************************************************************/
3635 int CEEInfo::appendClassName(__deref_inout_ecount(*pnBufLen) WCHAR** ppBuf,
3636                              int* pnBufLen,
3637                              CORINFO_CLASS_HANDLE    clsHnd,
3638                              BOOL fNamespace,
3639                              BOOL fFullInst,
3640                              BOOL fAssembly)
3641 {
3642     CONTRACTL {
3643         SO_TOLERANT;
3644         MODE_PREEMPTIVE;
3645         THROWS;
3646         GC_TRIGGERS;
3647     } CONTRACTL_END;
3648
3649     int nLen = 0;
3650
3651     JIT_TO_EE_TRANSITION();
3652
3653     TypeHandle th(clsHnd);
3654     StackSString ss;
3655     TypeString::AppendType(ss,th,
3656                            (fNamespace ? TypeString::FormatNamespace : 0) |
3657                            (fFullInst ? TypeString::FormatFullInst : 0) |
3658                            (fAssembly ? TypeString::FormatAssembly : 0));
3659     const WCHAR* szString = ss.GetUnicode();
3660     nLen = (int)wcslen(szString);
3661     if (*pnBufLen > 0)
3662     {
3663     wcscpy_s(*ppBuf, *pnBufLen, szString );
3664     (*ppBuf)[(*pnBufLen) - 1] = W('\0');
3665     (*ppBuf) += nLen;
3666     (*pnBufLen) -= nLen;
3667     }
3668
3669     EE_TO_JIT_TRANSITION();
3670
3671     return nLen;
3672 }
3673
3674 /*********************************************************************/
3675 CORINFO_MODULE_HANDLE CEEInfo::getClassModule(CORINFO_CLASS_HANDLE clsHnd)
3676 {
3677     CONTRACTL {
3678         SO_TOLERANT;
3679         NOTHROW;
3680         GC_NOTRIGGER;
3681         MODE_PREEMPTIVE;
3682     } CONTRACTL_END;
3683
3684     CORINFO_MODULE_HANDLE result = NULL;
3685
3686     JIT_TO_EE_TRANSITION_LEAF();
3687
3688     TypeHandle     VMClsHnd(clsHnd);
3689
3690     result = CORINFO_MODULE_HANDLE(VMClsHnd.GetModule());
3691
3692     EE_TO_JIT_TRANSITION_LEAF();
3693
3694     return result;
3695 }
3696
3697 /*********************************************************************/
3698 CORINFO_ASSEMBLY_HANDLE CEEInfo::getModuleAssembly(CORINFO_MODULE_HANDLE modHnd)
3699 {
3700     CONTRACTL {
3701         SO_TOLERANT;
3702         NOTHROW;
3703         GC_NOTRIGGER;
3704         MODE_PREEMPTIVE;
3705     } CONTRACTL_END;
3706
3707     CORINFO_ASSEMBLY_HANDLE result = NULL;
3708
3709     JIT_TO_EE_TRANSITION_LEAF();
3710
3711     result = CORINFO_ASSEMBLY_HANDLE(GetModule(modHnd)->GetAssembly());
3712
3713     EE_TO_JIT_TRANSITION_LEAF();
3714
3715     return result;
3716 }
3717
3718 /*********************************************************************/
3719 const char* CEEInfo::getAssemblyName(CORINFO_ASSEMBLY_HANDLE asmHnd)
3720 {
3721     CONTRACTL {
3722         SO_TOLERANT;
3723         THROWS;
3724         GC_TRIGGERS;
3725         MODE_PREEMPTIVE;
3726     } CONTRACTL_END;
3727
3728     const char*  result = NULL;
3729
3730     JIT_TO_EE_TRANSITION();
3731     result = ((Assembly*)asmHnd)->GetSimpleName();
3732     EE_TO_JIT_TRANSITION();
3733
3734     return result;
3735 }
3736
3737 /*********************************************************************/
3738 void* CEEInfo::LongLifetimeMalloc(size_t sz)
3739 {
3740     CONTRACTL {
3741         SO_TOLERANT;
3742         NOTHROW;
3743         GC_NOTRIGGER;
3744         MODE_PREEMPTIVE;
3745     } CONTRACTL_END;
3746
3747     void*  result = NULL;
3748
3749     JIT_TO_EE_TRANSITION_LEAF();
3750     result = new (nothrow) char[sz];
3751     EE_TO_JIT_TRANSITION_LEAF();
3752
3753     return result;
3754 }
3755
3756 /*********************************************************************/
3757 void CEEInfo::LongLifetimeFree(void* obj)
3758 {
3759     CONTRACTL {
3760         SO_TOLERANT;
3761         NOTHROW;
3762         GC_NOTRIGGER;
3763         MODE_PREEMPTIVE;
3764     } CONTRACTL_END;
3765
3766     JIT_TO_EE_TRANSITION_LEAF();
3767     (operator delete)(obj);
3768     EE_TO_JIT_TRANSITION_LEAF();
3769 }
3770
3771 /*********************************************************************/
3772 size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_MODULE_HANDLE *pModuleHandle, void **ppIndirection)
3773 {
3774     CONTRACTL {
3775         SO_TOLERANT;
3776         NOTHROW;
3777         GC_NOTRIGGER;
3778         MODE_PREEMPTIVE;
3779     } CONTRACTL_END;
3780
3781     size_t result = 0;
3782
3783     JIT_TO_EE_TRANSITION_LEAF();
3784
3785     TypeHandle     VMClsHnd(clsHnd);
3786     Module *pModule = VMClsHnd.AsMethodTable()->GetModuleForStatics();
3787
3788     if (ppIndirection != NULL)
3789         *ppIndirection = NULL;
3790
3791     // The zapper needs the module handle. The jit should not use it at all.
3792     if (pModuleHandle)
3793         *pModuleHandle = CORINFO_MODULE_HANDLE(pModule);
3794
3795     result = pModule->GetModuleID();
3796
3797     _ASSERTE(result);
3798
3799     EE_TO_JIT_TRANSITION_LEAF();
3800
3801     return result;
3802 }
3803
3804 /*********************************************************************/
3805 BOOL CEEInfo::isValueClass(CORINFO_CLASS_HANDLE clsHnd)
3806 {
3807     CONTRACTL {
3808         SO_TOLERANT;
3809         NOTHROW;
3810         GC_NOTRIGGER;
3811         MODE_PREEMPTIVE;
3812     } CONTRACTL_END;
3813
3814     BOOL ret = FALSE;
3815
3816     JIT_TO_EE_TRANSITION_LEAF();
3817
3818     _ASSERTE(clsHnd);
3819
3820     // Note that clsHnd.IsValueType() would not return what the JIT expects
3821     // for corner cases like ELEMENT_TYPE_FNPTR
3822     TypeHandle VMClsHnd(clsHnd);
3823     MethodTable * pMT = VMClsHnd.GetMethodTable();
3824     ret = (pMT != NULL) ? pMT->IsValueType() : 0;
3825
3826     EE_TO_JIT_TRANSITION_LEAF();
3827
3828     return ret;
3829 }
3830
3831 /*********************************************************************/
3832 // If this method returns true, JIT will do optimization to inline the check for
3833 //     GetClassFromHandle(handle) == obj.GetType()
3834 //
3835 // This will enable to use directly the typehandle instead of going through getClassByHandle
3836 BOOL CEEInfo::canInlineTypeCheckWithObjectVTable (CORINFO_CLASS_HANDLE clsHnd)
3837 {
3838     CONTRACTL {
3839         SO_TOLERANT;
3840         NOTHROW;
3841         GC_NOTRIGGER;
3842         MODE_PREEMPTIVE;
3843     } CONTRACTL_END;
3844
3845     BOOL ret = FALSE;
3846
3847     JIT_TO_EE_TRANSITION_LEAF();
3848
3849     _ASSERTE(clsHnd);
3850
3851     TypeHandle VMClsHnd(clsHnd);
3852
3853     if (VMClsHnd.IsTypeDesc())
3854     {
3855         // We can't do this optimization for arrays because of the object methodtable is template methodtable
3856         ret = FALSE;
3857     }
3858     else
3859     if (VMClsHnd.AsMethodTable()->IsMarshaledByRef())
3860     {
3861         // We can't do this optimization for marshalbyrefs because of the object methodtable can be transparent proxy
3862         ret = FALSE;
3863     }
3864     else
3865     if (VMClsHnd.AsMethodTable()->IsInterface())
3866     {
3867         // Object.GetType() should not ever return interface. However, WCF custom remoting proxy does it. Disable this
3868         // optimization for interfaces so that (autogenerated) code that compares Object.GetType() with interface type works 
3869         // as expected for WCF custom remoting proxy. Note that this optimization is still not going to work well for custom
3870         // remoting proxies that are even more broken than the WCF one, e.g. returning random non-marshalbyref types 
3871         // from Object.GetType().
3872         ret = FALSE;
3873     }
3874     else
3875     if (VMClsHnd == TypeHandle(g_pCanonMethodTableClass))   
3876     {
3877         // We can't do this optimization in shared generics code because of we do not know what the actual type is going to be.
3878         // (It can be array, marshalbyref, etc.)
3879         ret = FALSE;
3880     }
3881     else
3882     {
3883         // It is safe to perform this optimization
3884         ret = TRUE;
3885     }
3886
3887     EE_TO_JIT_TRANSITION_LEAF();
3888
3889     return(ret);
3890 }
3891
3892 /*********************************************************************/
3893 DWORD CEEInfo::getClassAttribs (CORINFO_CLASS_HANDLE clsHnd)
3894 {
3895     CONTRACTL {
3896         SO_TOLERANT;
3897         THROWS;
3898         GC_TRIGGERS;
3899         MODE_PREEMPTIVE;
3900     } CONTRACTL_END;
3901
3902     // <REVISIT_TODO>@todo FIX need to really fetch the class atributes.  at present
3903     // we don't need to because the JIT only cares in the case of COM classes</REVISIT_TODO>
3904     DWORD ret = 0;
3905
3906     JIT_TO_EE_TRANSITION();
3907
3908     ret = getClassAttribsInternal(clsHnd);
3909
3910     EE_TO_JIT_TRANSITION();
3911
3912     return ret;
3913 }
3914
3915
3916 /*********************************************************************/
3917 BOOL CEEInfo::isStructRequiringStackAllocRetBuf(CORINFO_CLASS_HANDLE clsHnd)
3918 {
3919     CONTRACTL {
3920         SO_TOLERANT;
3921         THROWS;
3922         GC_TRIGGERS;
3923         MODE_PREEMPTIVE;
3924     } CONTRACTL_END;
3925
3926     BOOL ret = 0;
3927
3928     JIT_TO_EE_TRANSITION_LEAF();
3929
3930     TypeHandle     VMClsHnd(clsHnd);
3931     MethodTable * pMT = VMClsHnd.GetMethodTable();
3932     ret = (pMT != NULL && pMT->IsStructRequiringStackAllocRetBuf());
3933
3934     EE_TO_JIT_TRANSITION_LEAF();
3935
3936     return ret;
3937 }
3938
3939 /*********************************************************************/
3940 DWORD CEEInfo::getClassAttribsInternal (CORINFO_CLASS_HANDLE clsHnd)
3941 {
3942     STANDARD_VM_CONTRACT;
3943
3944     DWORD ret = 0;
3945
3946     _ASSERTE(clsHnd);
3947
3948     TypeHandle     VMClsHnd(clsHnd);
3949
3950     // Byrefs should only occur in method and local signatures, which are accessed
3951     // using ICorClassInfo and ICorClassInfo.getChildType.
3952     // So getClassAttribs() should not be called for byrefs
3953
3954     if (VMClsHnd.IsByRef())
3955     {
3956         _ASSERTE(!"Did findClass() return a Byref?");
3957         COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3958     }
3959     else if (VMClsHnd.IsGenericVariable())
3960     {
3961         //@GENERICSVER: for now, type variables simply report "variable".
3962         ret |= CORINFO_FLG_GENERIC_TYPE_VARIABLE;
3963     }
3964     else
3965     {
3966         MethodTable *pMT = VMClsHnd.GetMethodTable();
3967
3968         if (!pMT)
3969         {
3970             _ASSERTE(!"Did findClass() return a Byref?");
3971             COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3972         }
3973
3974         EEClass * pClass = pMT->GetClass();
3975
3976         // The array flag is used to identify the faked-up methods on
3977         // array types, i.e. .ctor, Get, Set and Address
3978         if (pMT->IsArray())
3979             ret |= CORINFO_FLG_ARRAY;
3980
3981         if (pMT->IsInterface())
3982             ret |= CORINFO_FLG_INTERFACE;
3983
3984         if (pMT->HasComponentSize())
3985             ret |= CORINFO_FLG_VAROBJSIZE;
3986
3987         if (pMT->IsValueType())
3988         {
3989             ret |= CORINFO_FLG_VALUECLASS;
3990
3991             if (pMT->IsByRefLike())
3992                 ret |= CORINFO_FLG_CONTAINS_STACK_PTR;
3993
3994             if ((pClass->IsNotTightlyPacked() && (!pClass->IsManagedSequential() || pClass->HasExplicitSize())) ||
3995                 pMT == g_TypedReferenceMT ||
3996                 VMClsHnd.IsNativeValueType())
3997             {
3998                 ret |= CORINFO_FLG_CUSTOMLAYOUT;
3999             }
4000
4001             if (pClass->IsUnsafeValueClass())
4002                 ret |= CORINFO_FLG_UNSAFE_VALUECLASS;
4003         }
4004         if (pClass->HasExplicitFieldOffsetLayout() && pClass->HasOverLayedField())
4005             ret |= CORINFO_FLG_OVERLAPPING_FIELDS;
4006         if (VMClsHnd.IsCanonicalSubtype())
4007             ret |= CORINFO_FLG_SHAREDINST;
4008
4009         if (pMT->HasVariance())
4010             ret |= CORINFO_FLG_VARIANCE;
4011
4012         if (pMT->IsContextful())
4013             ret |= CORINFO_FLG_CONTEXTFUL;
4014
4015         if (pMT->IsMarshaledByRef())
4016             ret |= CORINFO_FLG_MARSHAL_BYREF;
4017
4018         if (pMT->ContainsPointers() || pMT == g_TypedReferenceMT)
4019             ret |= CORINFO_FLG_CONTAINS_GC_PTR;
4020
4021         if (pMT->IsDelegate())
4022             ret |= CORINFO_FLG_DELEGATE;
4023
4024         if (pClass->IsBeforeFieldInit())
4025         {
4026             if (IsReadyToRunCompilation() && !pMT->GetModule()->IsInCurrentVersionBubble())
4027             {
4028                 // For version resiliency do not allow hoisting static constructors out of loops
4029             }
4030             else
4031             {
4032                 ret |= CORINFO_FLG_BEFOREFIELDINIT;
4033             }
4034         }
4035
4036         if (pClass->IsAbstract())
4037             ret |= CORINFO_FLG_ABSTRACT;
4038
4039         if (pClass->IsSealed())
4040             ret |= CORINFO_FLG_FINAL;
4041
4042         if (pMT->IsIntrinsicType())
4043             ret |= CORINFO_FLG_INTRINSIC_TYPE;
4044     }
4045
4046     return ret;
4047 }
4048
4049 /*********************************************************************/
4050 //
4051 // See code:CorInfoFlag#ClassConstructionFlags  for details.
4052 //
4053 CorInfoInitClassResult CEEInfo::initClass(
4054             CORINFO_FIELD_HANDLE    field,
4055             CORINFO_METHOD_HANDLE   method,
4056             CORINFO_CONTEXT_HANDLE  context,
4057             BOOL                    speculative)
4058 {
4059     CONTRACTL {
4060         SO_TOLERANT;
4061         THROWS;
4062         GC_TRIGGERS;
4063         MODE_PREEMPTIVE;
4064     } CONTRACTL_END;
4065
4066     DWORD result = CORINFO_INITCLASS_NOT_REQUIRED;
4067
4068     JIT_TO_EE_TRANSITION();
4069     {
4070
4071     // Do not bother figuring out the initialization if we are only verifying the method.
4072     if (isVerifyOnly())
4073     {
4074         result = CORINFO_INITCLASS_NOT_REQUIRED;
4075         goto exit;
4076     }
4077
4078     FieldDesc * pFD = (FieldDesc *)field;
4079     _ASSERTE(pFD == NULL || pFD->IsStatic());
4080
4081     MethodDesc * pMD = (MethodDesc *)method;
4082
4083     TypeHandle typeToInitTH = (pFD != NULL) ? pFD->GetEnclosingMethodTable() : GetTypeFromContext(context);
4084
4085     MethodDesc *methodBeingCompiled = m_pMethodBeingCompiled;
4086
4087     BOOL fMethodDomainNeutral = methodBeingCompiled->IsDomainNeutral() || methodBeingCompiled->IsZapped() || IsCompilingForNGen();
4088
4089     MethodTable *pTypeToInitMT = typeToInitTH.AsMethodTable();
4090
4091     // This should be the most common early-out case.
4092     if (fMethodDomainNeutral)
4093     {
4094         if (pTypeToInitMT->IsClassPreInited())
4095         {
4096             result = CORINFO_INITCLASS_NOT_REQUIRED;
4097             goto exit;
4098         }
4099     }
4100     else
4101     {
4102 #ifdef CROSSGEN_COMPILE
4103         _ASSERTE(FALSE);
4104 #else // CROSSGEN_COMPILE
4105         if (pTypeToInitMT->IsClassInited())
4106         {
4107             // If the type is initialized there really is nothing to do.
4108             result = CORINFO_INITCLASS_INITIALIZED;
4109             goto exit;
4110         }
4111 #endif // CROSSGEN_COMPILE
4112     }
4113
4114     if (pTypeToInitMT->IsGlobalClass())
4115     {
4116         // For both jitted and ngen code the global class is always considered initialized
4117         result = CORINFO_INITCLASS_NOT_REQUIRED;
4118         goto exit;
4119     }
4120
4121     bool fIgnoreBeforeFieldInit = false;
4122
4123     if (pFD == NULL)
4124     {
4125         if (!fIgnoreBeforeFieldInit && pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4126         {
4127             // We can wait for field accesses to run .cctor
4128             result = CORINFO_INITCLASS_NOT_REQUIRED;
4129             goto exit;
4130         }
4131
4132         // Run .cctor on statics & constructors
4133         if (pMD->IsStatic())
4134         {
4135             // Except don't class construct on .cctor - it would be circular
4136             if (pMD->IsClassConstructor())
4137             {
4138                 result = CORINFO_INITCLASS_NOT_REQUIRED;
4139                 goto exit;
4140             }
4141         }
4142         else
4143         // According to the spec, we should be able to do this optimization for both reference and valuetypes.
4144         // To maintain backward compatibility, we are doing it for reference types only.
4145         // We don't do this for interfaces though, as those don't have instance constructors.
4146         if (!pMD->IsCtor() && !pTypeToInitMT->IsValueType() && !pTypeToInitMT->IsInterface())
4147         {
4148             // For instance methods of types with precise-initialization
4149             // semantics, we can assume that the .ctor triggerred the
4150             // type initialization.
4151             // This does not hold for NULL "this" object. However, the spec does
4152             // not require that case to work.
4153             result = CORINFO_INITCLASS_NOT_REQUIRED;
4154             goto exit;
4155         }
4156     }
4157
4158     if (pTypeToInitMT->IsSharedByGenericInstantiations())
4159     {
4160         // Shared generic code has to use helper. Moreover, tell JIT not to inline since
4161         // inlining of generic dictionary lookups is not supported.
4162         result = CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE;
4163         goto exit;
4164     }
4165
4166     //
4167     // Try to prove that the initialization is not necessary because of nesting
4168     //
4169
4170     if (pFD == NULL)
4171     {
4172         // Handled above
4173         _ASSERTE(fIgnoreBeforeFieldInit || !pTypeToInitMT->GetClass()->IsBeforeFieldInit());
4174
4175         // Note that jit has both methods the same if asking whether to emit cctor
4176         // for a given method's code (as opposed to inlining codegen).
4177         if (context != MAKE_METHODCONTEXT(methodBeingCompiled) && pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4178         {
4179             // If we're inling a call to a method in our own type, then we should already
4180             // have triggered the .cctor when caller was itself called.
4181             result = CORINFO_INITCLASS_NOT_REQUIRED;
4182             goto exit;
4183         }
4184     }
4185     else
4186     {
4187         // This optimization may cause static fields in reference types to be accessed without cctor being triggered
4188         // for NULL "this" object. It does not conform with what the spec says. However, we have been historically 
4189         // doing it for perf reasons.
4190         if (!pTypeToInitMT->IsValueType() && !pTypeToInitMT->IsInterface() && !pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4191         {
4192             if (pTypeToInitMT == GetTypeFromContext(context).AsMethodTable() || pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4193             {
4194                 // The class will be initialized by the time we access the field.
4195                 result = CORINFO_INITCLASS_NOT_REQUIRED;
4196                 goto exit;
4197             }
4198         }
4199
4200         // If we are currently compiling the class constructor for this static field access then we can skip the initClass 
4201         if (methodBeingCompiled->GetMethodTable() == pTypeToInitMT && methodBeingCompiled->IsStatic() && methodBeingCompiled->IsClassConstructor())
4202         {
4203             // The class will be initialized by the time we access the field.
4204             result = CORINFO_INITCLASS_NOT_REQUIRED;
4205             goto exit;
4206         }
4207     }
4208
4209     if (fMethodDomainNeutral)
4210     {
4211         // Well, because of code sharing we can't do anything at coge generation time.
4212         // We have to do it at runtime.
4213         result = CORINFO_INITCLASS_USE_HELPER;
4214         goto exit;
4215     }
4216
4217 #ifndef CROSSGEN_COMPILE
4218     //
4219     // Optimizations for domain specific code
4220     //
4221
4222     // Allocate space for the local class if necessary, but don't trigger
4223     // class construction.
4224     DomainLocalModule *pModule = pTypeToInitMT->GetDomainLocalModule();
4225     pModule->PopulateClass(pTypeToInitMT);
4226
4227     if (pTypeToInitMT->IsClassInited())
4228     {
4229         result = CORINFO_INITCLASS_INITIALIZED;
4230         goto exit;
4231     }
4232 #endif // CROSSGEN_COMPILE
4233
4234     result = CORINFO_INITCLASS_USE_HELPER;
4235     }
4236 exit: ;
4237     EE_TO_JIT_TRANSITION();
4238
4239     return (CorInfoInitClassResult)result;
4240 }
4241
4242
4243
4244 void CEEInfo::classMustBeLoadedBeforeCodeIsRun (CORINFO_CLASS_HANDLE typeToLoadHnd)
4245 {
4246     CONTRACTL {
4247         SO_TOLERANT;
4248         NOTHROW;
4249         GC_NOTRIGGER;
4250         MODE_PREEMPTIVE;
4251     } CONTRACTL_END;
4252
4253     JIT_TO_EE_TRANSITION_LEAF();
4254
4255     TypeHandle th = TypeHandle(typeToLoadHnd);
4256
4257     // Type handles returned to JIT at runtime are always fully loaded. Verify that it is the case.
4258     _ASSERTE(th.IsFullyLoaded());
4259
4260     EE_TO_JIT_TRANSITION_LEAF();
4261 }
4262
4263 /*********************************************************************/
4264 void CEEInfo::methodMustBeLoadedBeforeCodeIsRun (CORINFO_METHOD_HANDLE methHnd)
4265 {
4266     CONTRACTL {
4267         SO_TOLERANT;
4268         NOTHROW;
4269         GC_NOTRIGGER;
4270         MODE_PREEMPTIVE;
4271     } CONTRACTL_END;
4272
4273     JIT_TO_EE_TRANSITION_LEAF();
4274
4275     MethodDesc *pMD = (MethodDesc*) methHnd;
4276
4277     // MethodDescs returned to JIT at runtime are always fully loaded. Verify that it is the case.
4278     _ASSERTE(pMD->IsRestored() && pMD->GetMethodTable()->IsFullyLoaded());
4279
4280     EE_TO_JIT_TRANSITION_LEAF();
4281 }
4282
4283 /*********************************************************************/
4284 CORINFO_METHOD_HANDLE CEEInfo::mapMethodDeclToMethodImpl(CORINFO_METHOD_HANDLE methHnd)
4285 {
4286     CONTRACTL {
4287         SO_TOLERANT;
4288         THROWS;
4289         GC_TRIGGERS;
4290         MODE_PREEMPTIVE;
4291     } CONTRACTL_END;
4292
4293     CORINFO_METHOD_HANDLE result = NULL;
4294
4295     JIT_TO_EE_TRANSITION();
4296
4297     MethodDesc *pMD = GetMethod(methHnd);
4298     pMD = MethodTable::MapMethodDeclToMethodImpl(pMD);
4299     result = (CORINFO_METHOD_HANDLE) pMD;
4300
4301     EE_TO_JIT_TRANSITION();
4302
4303     return result;
4304 }
4305
4306 /*********************************************************************/
4307 CORINFO_CLASS_HANDLE CEEInfo::getBuiltinClass(CorInfoClassId classId)
4308 {
4309     CONTRACTL {
4310         SO_TOLERANT;
4311         THROWS;
4312         GC_TRIGGERS;
4313         MODE_PREEMPTIVE;
4314     } CONTRACTL_END;
4315
4316     CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE) 0;
4317
4318     JIT_TO_EE_TRANSITION();
4319
4320     switch (classId)
4321     {
4322     case CLASSID_SYSTEM_OBJECT:
4323         result = CORINFO_CLASS_HANDLE(g_pObjectClass);
4324         break;
4325     case CLASSID_TYPED_BYREF:
4326         result = CORINFO_CLASS_HANDLE(g_TypedReferenceMT);
4327         break;
4328     case CLASSID_TYPE_HANDLE:
4329         result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__TYPE_HANDLE));
4330         break;
4331     case CLASSID_FIELD_HANDLE:
4332         result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__FIELD_HANDLE));
4333         break;
4334     case CLASSID_METHOD_HANDLE:
4335         result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__METHOD_HANDLE));
4336         break;
4337     case CLASSID_ARGUMENT_HANDLE:
4338         result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__ARGUMENT_HANDLE));
4339         break;
4340     case CLASSID_STRING:
4341         result = CORINFO_CLASS_HANDLE(g_pStringClass);
4342         break;
4343     case CLASSID_RUNTIME_TYPE:
4344         result = CORINFO_CLASS_HANDLE(g_pRuntimeTypeClass);
4345         break;
4346     default:
4347         _ASSERTE(!"NYI: unknown classId");
4348         break;
4349     }
4350
4351     EE_TO_JIT_TRANSITION();
4352
4353     return result;
4354 }
4355
4356
4357
4358 /*********************************************************************/
4359 CorInfoType CEEInfo::getTypeForPrimitiveValueClass(
4360         CORINFO_CLASS_HANDLE clsHnd)
4361 {
4362     CONTRACTL {
4363         SO_TOLERANT;
4364         THROWS;
4365         GC_TRIGGERS;
4366         MODE_PREEMPTIVE;
4367     } CONTRACTL_END;
4368
4369     CorInfoType result = CORINFO_TYPE_UNDEF;
4370
4371     JIT_TO_EE_TRANSITION();
4372
4373     TypeHandle th(clsHnd);
4374     _ASSERTE (!th.IsGenericVariable());
4375
4376     MethodTable    *pMT = th.GetMethodTable();
4377     PREFIX_ASSUME(pMT != NULL);
4378
4379     // Is it a non primitive struct such as
4380     // RuntimeTypeHandle, RuntimeMethodHandle, RuntimeArgHandle?
4381     if (pMT->IsValueType() &&
4382         !pMT->IsTruePrimitive()  &&
4383         !pMT->IsEnum())
4384     {
4385         // default value CORINFO_TYPE_UNDEF is what we want
4386     }
4387     else
4388     {
4389         switch (th.GetInternalCorElementType())
4390         {
4391         case ELEMENT_TYPE_I1:
4392         case ELEMENT_TYPE_U1:
4393         case ELEMENT_TYPE_BOOLEAN:
4394             result = asCorInfoType(ELEMENT_TYPE_I1);
4395             break;
4396
4397         case ELEMENT_TYPE_I2:
4398         case ELEMENT_TYPE_U2:
4399         case ELEMENT_TYPE_CHAR:
4400             result = asCorInfoType(ELEMENT_TYPE_I2);
4401             break;
4402
4403         case ELEMENT_TYPE_I4:
4404         case ELEMENT_TYPE_U4:
4405             result = asCorInfoType(ELEMENT_TYPE_I4);
4406             break;
4407
4408         case ELEMENT_TYPE_I8:
4409         case ELEMENT_TYPE_U8:
4410             result = asCorInfoType(ELEMENT_TYPE_I8);
4411             break;
4412
4413         case ELEMENT_TYPE_I:
4414         case ELEMENT_TYPE_U:
4415             result = asCorInfoType(ELEMENT_TYPE_I);
4416             break;
4417
4418         case ELEMENT_TYPE_R4:
4419             result = asCorInfoType(ELEMENT_TYPE_R4);
4420             break;
4421
4422         case ELEMENT_TYPE_R8:
4423             result = asCorInfoType(ELEMENT_TYPE_R8);
4424             break;
4425
4426         case ELEMENT_TYPE_VOID:
4427             result = asCorInfoType(ELEMENT_TYPE_VOID);
4428             break;
4429
4430         case ELEMENT_TYPE_PTR:
4431         case ELEMENT_TYPE_FNPTR:
4432             result = asCorInfoType(ELEMENT_TYPE_PTR);
4433             break;
4434
4435         default:
4436             break;
4437         }
4438     }
4439
4440     EE_TO_JIT_TRANSITION();
4441
4442     return result;
4443 }
4444
4445 /*********************************************************************/
4446 CorInfoType CEEInfo::getTypeForPrimitiveNumericClass(
4447         CORINFO_CLASS_HANDLE clsHnd)
4448 {
4449     CONTRACTL{
4450         SO_TOLERANT;
4451         NOTHROW;
4452         GC_NOTRIGGER;
4453         MODE_PREEMPTIVE;
4454     } CONTRACTL_END;
4455
4456     CorInfoType result = CORINFO_TYPE_UNDEF;
4457
4458     JIT_TO_EE_TRANSITION_LEAF();
4459
4460     TypeHandle th(clsHnd);
4461     _ASSERTE (!th.IsGenericVariable());
4462
4463     CorElementType ty = th.GetSignatureCorElementType();
4464     switch (ty)
4465     {
4466     case ELEMENT_TYPE_I1:
4467         result = CORINFO_TYPE_BYTE;
4468         break;
4469     case ELEMENT_TYPE_U1:
4470         result = CORINFO_TYPE_UBYTE;
4471         break;
4472     case ELEMENT_TYPE_I2:
4473         result = CORINFO_TYPE_SHORT;
4474         break;
4475     case ELEMENT_TYPE_U2:
4476         result = CORINFO_TYPE_USHORT;
4477         break;
4478     case ELEMENT_TYPE_I4:
4479         result = CORINFO_TYPE_INT;
4480         break;
4481     case ELEMENT_TYPE_U4:
4482         result = CORINFO_TYPE_UINT;
4483         break;
4484     case ELEMENT_TYPE_I8:
4485         result = CORINFO_TYPE_LONG;
4486         break;
4487     case ELEMENT_TYPE_U8:
4488         result = CORINFO_TYPE_ULONG;
4489         break;
4490     case ELEMENT_TYPE_R4:
4491         result = CORINFO_TYPE_FLOAT;
4492         break;
4493     case ELEMENT_TYPE_R8:
4494         result = CORINFO_TYPE_DOUBLE;
4495         break;
4496
4497     default:
4498         // Error case, we will return CORINFO_TYPE_UNDEF
4499         break;
4500     }
4501
4502     JIT_TO_EE_TRANSITION_LEAF();
4503
4504     return result;
4505 }
4506
4507
4508 void CEEInfo::getGSCookie(GSCookie * pCookieVal, GSCookie ** ppCookieVal)
4509 {
4510     CONTRACTL {
4511         SO_TOLERANT;
4512         THROWS;
4513         GC_TRIGGERS;
4514         MODE_PREEMPTIVE;
4515     } CONTRACTL_END;
4516
4517     JIT_TO_EE_TRANSITION();
4518
4519     if (pCookieVal)
4520     {
4521         *pCookieVal = GetProcessGSCookie();
4522         *ppCookieVal = NULL;
4523     }
4524     else
4525     {
4526         *ppCookieVal = GetProcessGSCookiePtr();
4527     }
4528
4529     EE_TO_JIT_TRANSITION();
4530 }
4531
4532
4533 /*********************************************************************/
4534 // TRUE if child is a subtype of parent
4535 // if parent is an interface, then does child implement / extend parent
4536 BOOL CEEInfo::canCast(
4537         CORINFO_CLASS_HANDLE        child,
4538         CORINFO_CLASS_HANDLE        parent)
4539 {
4540     CONTRACTL {
4541         SO_TOLERANT;
4542         THROWS;
4543         GC_TRIGGERS;
4544         MODE_PREEMPTIVE;
4545     } CONTRACTL_END;
4546
4547     BOOL result = FALSE;
4548
4549     JIT_TO_EE_TRANSITION();
4550
4551     result = ((TypeHandle)child).CanCastTo((TypeHandle)parent);
4552
4553     EE_TO_JIT_TRANSITION();
4554
4555     return result;
4556 }
4557
4558 /*********************************************************************/
4559 // TRUE if cls1 and cls2 are considered equivalent types.
4560 BOOL CEEInfo::areTypesEquivalent(
4561         CORINFO_CLASS_HANDLE        cls1,
4562         CORINFO_CLASS_HANDLE        cls2)
4563 {
4564     CONTRACTL {
4565         SO_TOLERANT;
4566         THROWS;
4567         GC_TRIGGERS;
4568         MODE_PREEMPTIVE;
4569     } CONTRACTL_END;
4570
4571     BOOL result = FALSE;
4572
4573     JIT_TO_EE_TRANSITION();
4574
4575     result = ((TypeHandle)cls1).IsEquivalentTo((TypeHandle)cls2);
4576
4577     EE_TO_JIT_TRANSITION();
4578
4579     return result;
4580 }
4581
4582 /*********************************************************************/
4583 // See if a cast from fromClass to toClass will succeed, fail, or needs
4584 // to be resolved at runtime.
4585 TypeCompareState CEEInfo::compareTypesForCast(
4586         CORINFO_CLASS_HANDLE        fromClass,
4587         CORINFO_CLASS_HANDLE        toClass)
4588 {
4589     CONTRACTL {
4590         SO_TOLERANT;
4591         THROWS;
4592         GC_TRIGGERS;
4593         MODE_PREEMPTIVE;
4594     } CONTRACTL_END;
4595
4596     TypeCompareState result = TypeCompareState::May;
4597
4598     JIT_TO_EE_TRANSITION();
4599
4600     TypeHandle fromHnd = (TypeHandle) fromClass;
4601     TypeHandle toHnd = (TypeHandle) toClass;
4602
4603 #ifdef FEATURE_COMINTEROP
4604     // If casting from a com object class, don't try to optimize.
4605     if (fromHnd.IsComObjectType())
4606     {
4607         result = TypeCompareState::May;
4608     }
4609     else
4610 #endif // FEATURE_COMINTEROP
4611
4612     // If casting from ICastable, don't try to optimize
4613     if (fromHnd.GetMethodTable()->IsICastable())
4614     {
4615         result = TypeCompareState::May;
4616     }
4617     // If casting to Nullable<T>, don't try to optimize
4618     else if (Nullable::IsNullableType(toHnd))
4619     {
4620         result = TypeCompareState::May;
4621     }
4622     // If the types are not shared, we can check directly.
4623     else if (!fromHnd.IsCanonicalSubtype() && !toHnd.IsCanonicalSubtype())
4624     {
4625         result = fromHnd.CanCastTo(toHnd) ? TypeCompareState::Must : TypeCompareState::MustNot;
4626     }
4627     // Casting from a shared type to an unshared type.
4628     else if (fromHnd.IsCanonicalSubtype() && !toHnd.IsCanonicalSubtype())
4629     {
4630         // Only handle casts to interface types for now
4631         if (toHnd.IsInterface())
4632         {
4633             // Do a preliminary check.
4634             BOOL canCast = fromHnd.CanCastTo(toHnd);
4635
4636             // Pass back positive results unfiltered. The unknown type
4637             // parameters in fromClass did not come into play.
4638             if (canCast)
4639             {
4640                 result = TypeCompareState::Must;
4641             }
4642             // For negative results, the unknown type parameter in
4643             // fromClass might match some instantiated interface,
4644             // either directly or via variance.
4645             //
4646             // However, CanCastTo will report failure in such cases since
4647             // __Canon won't match the instantiated type on the
4648             // interface (which can't be __Canon since we screened out
4649             // canonical subtypes for toClass above). So only report
4650             // failure if the interface is not instantiated.
4651             else if (!toHnd.HasInstantiation())
4652             {
4653                 result = TypeCompareState::MustNot;
4654             }
4655         }
4656     }
4657
4658 #ifdef FEATURE_READYTORUN_COMPILER
4659     // In R2R it is a breaking change for a previously positive
4660     // cast to become negative, but not for a previously negative
4661     // cast to become positive. So in R2R a negative result is
4662     // always reported back as May.
4663     if (IsReadyToRunCompilation() && (result == TypeCompareState::MustNot))
4664     {
4665         result = TypeCompareState::May;
4666     }
4667 #endif // FEATURE_READYTORUN_COMPILER
4668
4669     EE_TO_JIT_TRANSITION();
4670
4671     return result;
4672 }
4673
4674 /*********************************************************************/
4675 // See if types represented by cls1 and cls2 compare equal, not
4676 // equal, or the comparison needs to be resolved at runtime.
4677 TypeCompareState CEEInfo::compareTypesForEquality(
4678         CORINFO_CLASS_HANDLE        cls1,
4679         CORINFO_CLASS_HANDLE        cls2)
4680 {
4681     CONTRACTL {
4682         SO_TOLERANT;
4683         THROWS;
4684         GC_TRIGGERS;
4685         MODE_PREEMPTIVE;
4686     } CONTRACTL_END;
4687
4688     TypeCompareState result = TypeCompareState::May;
4689
4690     JIT_TO_EE_TRANSITION();
4691
4692     TypeHandle hnd1 = (TypeHandle) cls1;
4693     TypeHandle hnd2 = (TypeHandle) cls2;
4694
4695     // If neither type is a canonical subtype, type handle comparison suffices
4696     if (!hnd1.IsCanonicalSubtype() && !hnd2.IsCanonicalSubtype())
4697     {
4698         result = (hnd1 == hnd2 ? TypeCompareState::Must : TypeCompareState::MustNot);
4699     }
4700     // If either or both types are canonical subtypes, we can sometimes prove inequality.
4701     else
4702     {
4703         // If either is a value type then the types cannot
4704         // be equal unless the type defs are the same.
4705         if (hnd1.IsValueType() || hnd2.IsValueType())
4706         {
4707             if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
4708             {
4709                 result = TypeCompareState::MustNot;
4710             }
4711         }
4712         // If we have two ref types that are not __Canon, then the
4713         // types cannot be equal unless the type defs are the same.
4714         else
4715         {
4716             TypeHandle canonHnd = TypeHandle(g_pCanonMethodTableClass);
4717             if ((hnd1 != canonHnd) && (hnd2 != canonHnd))
4718             {
4719                 if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
4720                 {
4721                     result = TypeCompareState::MustNot;
4722                 }
4723             }
4724         }
4725     }
4726
4727     EE_TO_JIT_TRANSITION();
4728
4729     return result;
4730 }
4731
4732 /*********************************************************************/
4733 // returns is the intersection of cls1 and cls2.
4734 CORINFO_CLASS_HANDLE CEEInfo::mergeClasses(
4735         CORINFO_CLASS_HANDLE        cls1,
4736         CORINFO_CLASS_HANDLE        cls2)
4737 {
4738     CONTRACTL {
4739         SO_TOLERANT;
4740         THROWS;
4741         GC_TRIGGERS;
4742         MODE_PREEMPTIVE;
4743     } CONTRACTL_END;
4744
4745     CORINFO_CLASS_HANDLE result = NULL;
4746
4747     JIT_TO_EE_TRANSITION();
4748
4749     TypeHandle merged = TypeHandle::MergeTypeHandlesToCommonParent(TypeHandle(cls1), TypeHandle(cls2));
4750 #ifdef _DEBUG
4751     {
4752         //Make sure the merge is reflexive in the cases we "support".
4753         TypeHandle hnd1 = TypeHandle(cls1);
4754         TypeHandle hnd2 = TypeHandle(cls2);
4755         TypeHandle reflexive = TypeHandle::MergeTypeHandlesToCommonParent(hnd2, hnd1);
4756
4757         //If both sides are classes than either they have a common non-interface parent (in which case it is
4758         //reflexive)
4759         //OR they share a common interface, and it can be order dependent (if they share multiple interfaces
4760         //in common)
4761         if (!hnd1.IsInterface() && !hnd2.IsInterface())
4762         {
4763             if (merged.IsInterface())
4764             {
4765                 _ASSERTE(reflexive.IsInterface());
4766             }
4767             else
4768             {
4769                 _ASSERTE(merged == reflexive);
4770             }
4771         }
4772         //Both results must either be interfaces or classes.  They cannot be mixed.
4773         _ASSERTE((!!merged.IsInterface()) == (!!reflexive.IsInterface()));
4774
4775         //If the result of the merge was a class, then the result of the reflexive merge was the same class.
4776         if (!merged.IsInterface())
4777         {
4778             _ASSERTE(merged == reflexive);
4779         }
4780
4781         //If both sides are arrays, then the result is either an array or g_pArrayClass.  The above is
4782         //actually true about the element type for references types, but I think that that is a little
4783         //excessive for sanity.
4784         if (hnd1.IsArray() && hnd2.IsArray())
4785         {
4786             _ASSERTE((merged.IsArray() && reflexive.IsArray())
4787                      || ((merged == g_pArrayClass) && (reflexive == g_pArrayClass)));
4788         }
4789
4790         //Can I assert anything about generic variables?
4791
4792         //The results must always be assignable
4793         _ASSERTE(hnd1.CanCastTo(merged) && hnd2.CanCastTo(merged) && hnd1.CanCastTo(reflexive)
4794                  && hnd2.CanCastTo(reflexive));
4795     }
4796 #endif
4797     result = CORINFO_CLASS_HANDLE(merged.AsPtr());
4798
4799     EE_TO_JIT_TRANSITION();
4800     return result;
4801 }
4802
4803 /*********************************************************************/
4804 // Given a class handle, returns the Parent type.
4805 // For COMObjectType, it returns Class Handle of System.Object.
4806 // Returns 0 if System.Object is passed in.
4807 CORINFO_CLASS_HANDLE CEEInfo::getParentType(
4808             CORINFO_CLASS_HANDLE    cls)
4809 {
4810     CONTRACTL {
4811         SO_TOLERANT;
4812         THROWS;
4813         GC_TRIGGERS;
4814         MODE_PREEMPTIVE;
4815     } CONTRACTL_END;
4816
4817     CORINFO_CLASS_HANDLE result = NULL;
4818
4819     JIT_TO_EE_TRANSITION();
4820
4821     TypeHandle th(cls);
4822
4823     _ASSERTE(!th.IsNull());
4824     _ASSERTE(!th.IsGenericVariable());
4825
4826     TypeHandle thParent = th.GetParent();
4827
4828 #ifdef FEATURE_COMINTEROP
4829     // If we encounter __ComObject in the hierarchy, we need to skip it
4830     // since this hierarchy is introduced by the EE, but won't be present
4831     // in the metadata.
4832     if (!thParent.IsNull() && IsComObjectClass(thParent))
4833     {
4834         result = (CORINFO_CLASS_HANDLE) g_pObjectClass;
4835     }
4836     else
4837 #endif // FEATURE_COMINTEROP
4838     {
4839         result = CORINFO_CLASS_HANDLE(thParent.AsPtr());
4840     }
4841
4842     EE_TO_JIT_TRANSITION();
4843
4844     return result;
4845 }
4846
4847
4848 /*********************************************************************/
4849 // Returns the CorInfoType of the "child type". If the child type is
4850 // not a primitive type, *clsRet will be set.
4851 // Given an Array of Type Foo, returns Foo.
4852 // Given BYREF Foo, returns Foo
4853 CorInfoType CEEInfo::getChildType (
4854         CORINFO_CLASS_HANDLE       clsHnd,
4855         CORINFO_CLASS_HANDLE       *clsRet
4856         )
4857 {
4858     CONTRACTL {
4859         SO_TOLERANT;
4860         THROWS;
4861         GC_TRIGGERS;
4862         MODE_PREEMPTIVE;
4863     } CONTRACTL_END;
4864
4865     CorInfoType ret = CORINFO_TYPE_UNDEF;
4866     *clsRet = 0;
4867     TypeHandle  retType = TypeHandle();
4868
4869     JIT_TO_EE_TRANSITION();
4870
4871     TypeHandle th(clsHnd);
4872
4873     _ASSERTE(!th.IsNull());
4874
4875     // BYREF, ARRAY types
4876     if (th.IsTypeDesc())
4877     {
4878         retType = th.AsTypeDesc()->GetTypeParam();
4879     }
4880     else
4881     {
4882         // <REVISIT_TODO> we really should not have this case.  arrays type handles
4883         // used in the JIT interface should never be ordinary method tables,
4884         // indeed array type handles should really never be ordinary MTs
4885         // at all.  Perhaps we should assert !th.IsTypeDesc() && th.AsMethodTable().IsArray()? </REVISIT_TODO>
4886         MethodTable* pMT= th.AsMethodTable();
4887         if (pMT->IsArray())
4888             retType = pMT->GetApproxArrayElementTypeHandle();
4889     }
4890
4891     if (!retType.IsNull()) {
4892         CorElementType type = retType.GetInternalCorElementType();
4893         ret = CEEInfo::asCorInfoType(type,retType, clsRet);
4894
4895         // <REVISIT_TODO>What if this one is a value array ?</REVISIT_TODO>
4896     }
4897
4898     EE_TO_JIT_TRANSITION();
4899
4900     return ret;
4901 }
4902
4903 /*********************************************************************/
4904 // Check any constraints on class type arguments
4905 BOOL CEEInfo::satisfiesClassConstraints(CORINFO_CLASS_HANDLE cls)
4906 {
4907     CONTRACTL {
4908         SO_TOLERANT;
4909         THROWS;
4910         GC_TRIGGERS;
4911         MODE_PREEMPTIVE;
4912     } CONTRACTL_END;
4913
4914     BOOL result = FALSE;
4915
4916     JIT_TO_EE_TRANSITION();
4917
4918     _ASSERTE(cls != NULL);
4919     result = TypeHandle(cls).SatisfiesClassConstraints();
4920
4921     EE_TO_JIT_TRANSITION();
4922
4923     return result;
4924 }
4925
4926 /*********************************************************************/
4927 // Check if this is a single dimensional array type
4928 BOOL CEEInfo::isSDArray(CORINFO_CLASS_HANDLE  cls)
4929 {
4930     CONTRACTL {
4931         SO_TOLERANT;
4932         THROWS;
4933         GC_TRIGGERS;
4934         MODE_PREEMPTIVE;
4935     } CONTRACTL_END;
4936
4937     BOOL result = FALSE;
4938
4939     JIT_TO_EE_TRANSITION();
4940
4941     TypeHandle th(cls);
4942
4943     _ASSERTE(!th.IsNull());
4944
4945     if (th.IsArrayType())
4946     {
4947         // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4948         _ASSERTE(th != TypeHandle(g_pArrayClass));
4949
4950         result = (th.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
4951     }
4952
4953     EE_TO_JIT_TRANSITION();
4954
4955     return result;
4956 }
4957
4958 /*********************************************************************/
4959 // Get the number of dimensions in an array
4960 unsigned CEEInfo::getArrayRank(CORINFO_CLASS_HANDLE  cls)
4961 {
4962     CONTRACTL {
4963         SO_TOLERANT;
4964         THROWS;
4965         GC_TRIGGERS;
4966         MODE_PREEMPTIVE;
4967     } CONTRACTL_END;
4968
4969     unsigned result = 0;
4970
4971     JIT_TO_EE_TRANSITION();
4972
4973     TypeHandle th(cls);
4974
4975     _ASSERTE(!th.IsNull());
4976
4977     if (th.IsArrayType())
4978     {
4979         // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4980         _ASSERTE(th != TypeHandle(g_pArrayClass));
4981
4982         result = th.GetPossiblySharedArrayMethodTable()->GetRank();
4983     }
4984
4985     EE_TO_JIT_TRANSITION();
4986
4987     return result;
4988 }
4989
4990 /*********************************************************************/
4991 // Get static field data for an array
4992 // Note that it's OK to return NULL from this method.  This will cause
4993 // the JIT to make a runtime call to InitializeArray instead of doing
4994 // the inline optimization (thus preserving the original behavior).
4995 void * CEEInfo::getArrayInitializationData(
4996             CORINFO_FIELD_HANDLE        field,
4997             DWORD                       size
4998             )
4999 {
5000     CONTRACTL {
5001         SO_TOLERANT;
5002         THROWS;
5003         GC_TRIGGERS;
5004         MODE_PREEMPTIVE;
5005     } CONTRACTL_END;
5006
5007     void * result = NULL;
5008
5009     JIT_TO_EE_TRANSITION();
5010
5011     FieldDesc* pField = (FieldDesc*) field;
5012
5013     if (!pField                    ||
5014         !pField->IsRVA()           ||
5015         (pField->LoadSize() < size)
5016 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
5017         // This will make sure that when IBC logging is on, the array initialization happens thru 
5018         // COMArrayInfo::InitializeArray. This gives a place to put the IBC probe that can help
5019         // separate hold and cold RVA blobs.
5020         || (IsCompilingForNGen() &&
5021             GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
5022 #endif // FEATURE_NATIVE_IMAGE_GENERATION
5023         )
5024     {
5025         result = NULL;
5026     }
5027     else
5028     {
5029         result = pField->GetStaticAddressHandle(NULL);
5030     }
5031
5032     EE_TO_JIT_TRANSITION();
5033
5034     return result;
5035 }
5036
5037 CorInfoIsAccessAllowedResult CEEInfo::canAccessClass(
5038             CORINFO_RESOLVED_TOKEN * pResolvedToken,
5039             CORINFO_METHOD_HANDLE   callerHandle,
5040             CORINFO_HELPER_DESC    *pAccessHelper
5041             )
5042 {
5043     CONTRACTL {
5044         SO_TOLERANT;
5045         THROWS;
5046         GC_TRIGGERS;
5047         MODE_PREEMPTIVE;
5048     } CONTRACTL_END;
5049
5050     CorInfoIsAccessAllowedResult isAccessAllowed = CORINFO_ACCESS_ALLOWED;
5051
5052     JIT_TO_EE_TRANSITION();
5053
5054     INDEBUG(memset(pAccessHelper, 0xCC, sizeof(*pAccessHelper)));
5055
5056     BOOL doAccessCheck = TRUE;
5057     AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
5058     DynamicResolver * pAccessContext = NULL;
5059
5060     //All access checks must be done on the open instantiation.
5061     MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
5062     TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5063
5064     TypeHandle pCalleeForSecurity = TypeHandle(pResolvedToken->hClass);
5065     if (pResolvedToken->pTypeSpec != NULL)
5066     {
5067         SigTypeContext typeContext;
5068         SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
5069
5070         SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
5071         pCalleeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5072     }
5073
5074     while (pCalleeForSecurity.HasTypeParam())
5075     {
5076         pCalleeForSecurity = pCalleeForSecurity.GetTypeParam();
5077     }
5078
5079     if (IsDynamicScope(pResolvedToken->tokenScope))
5080     {
5081         doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope),
5082                                                     &callerTypeForSecurity, &accessCheckType,
5083                                                     &pAccessContext);
5084     }
5085
5086     //Since this is a check against a TypeHandle, there are some things we can stick in a TypeHandle that
5087     //don't require access checks.
5088     if (pCalleeForSecurity.IsGenericVariable())
5089     {
5090         //I don't need to check for access against !!0.
5091         doAccessCheck = FALSE;
5092     }
5093
5094     //Now do the visibility checks
5095     if (doAccessCheck)
5096     {
5097         AccessCheckOptions accessCheckOptions(accessCheckType,
5098                                               pAccessContext,
5099                                               FALSE /*throw on error*/,
5100                                               pCalleeForSecurity.GetMethodTable());
5101
5102         _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5103         StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5104
5105         BOOL canAccessType = ClassLoader::CanAccessClass(&accessContext,
5106                                                          pCalleeForSecurity.GetMethodTable(),
5107                                                          pCalleeForSecurity.GetAssembly(),
5108                                                          accessCheckOptions);
5109
5110         isAccessAllowed = canAccessType ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
5111     }
5112
5113
5114     if (isAccessAllowed != CORINFO_ACCESS_ALLOWED)
5115     {
5116         //These all get the throw helper
5117         pAccessHelper->helperNum = CORINFO_HELP_CLASS_ACCESS_EXCEPTION;
5118         pAccessHelper->numArgs = 2;
5119
5120         pAccessHelper->args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5121         pAccessHelper->args[1].Set(CORINFO_CLASS_HANDLE(pCalleeForSecurity.AsPtr()));
5122
5123         if (IsCompilingForNGen())
5124         {
5125             //see code:CEEInfo::getCallInfo for more information.
5126             if (pCallerForSecurity->ContainsGenericVariables() || pCalleeForSecurity.ContainsGenericVariables())
5127                 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic TypeHandle"));
5128         }
5129     }
5130
5131     EE_TO_JIT_TRANSITION();
5132     return isAccessAllowed;
5133 }
5134
5135 /***********************************************************************/
5136 // return the address of a pointer to a callable stub that will do the
5137 // virtual or interface call
5138 void CEEInfo::getCallInfo(
5139             CORINFO_RESOLVED_TOKEN * pResolvedToken,
5140             CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
5141             CORINFO_METHOD_HANDLE   callerHandle,
5142             CORINFO_CALLINFO_FLAGS  flags,
5143             CORINFO_CALL_INFO      *pResult /*out */)
5144 {
5145     CONTRACTL {
5146         SO_TOLERANT;
5147         THROWS;
5148         GC_TRIGGERS;
5149         MODE_PREEMPTIVE;
5150     } CONTRACTL_END;
5151
5152     JIT_TO_EE_TRANSITION();
5153
5154     _ASSERTE(CheckPointer(pResult));
5155
5156     INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
5157
5158     pResult->stubLookup.lookupKind.needsRuntimeLookup = false;
5159
5160     MethodDesc* pMD = (MethodDesc *)pResolvedToken->hMethod;
5161     TypeHandle th(pResolvedToken->hClass);
5162
5163     _ASSERTE(pMD);
5164     _ASSERTE((size_t(pMD) & 0x1) == 0);
5165
5166     // Spec says that a callvirt lookup ignores static methods. Since static methods
5167     // can't have the exact same signature as instance methods, a lookup that found
5168     // a static method would have never found an instance method.
5169     if (pMD->IsStatic() && (flags & CORINFO_CALLINFO_CALLVIRT))
5170     {
5171         EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, W("?")));
5172     }
5173
5174     TypeHandle exactType = TypeHandle(pResolvedToken->hClass);
5175
5176     TypeHandle constrainedType;
5177     if ((flags & CORINFO_CALLINFO_CALLVIRT) && (pConstrainedResolvedToken != NULL))
5178     {
5179         constrainedType = TypeHandle(pConstrainedResolvedToken->hClass);
5180     }
5181
5182     BOOL fResolvedConstraint = FALSE;
5183     BOOL fForceUseRuntimeLookup = FALSE;
5184
5185     MethodDesc * pMDAfterConstraintResolution = pMD;
5186     if (constrainedType.IsNull())
5187     {
5188         pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5189     }
5190     // <NICE> Things go wrong when this code path is used when verifying generic code.
5191     // It would be nice if we didn't go down this sort of code path when verifying but
5192     // not generating code. </NICE>
5193     else if (constrainedType.ContainsGenericVariables() || exactType.ContainsGenericVariables())
5194     {
5195         // <NICE> It shouldn't really matter what we do here - but the x86 JIT is annoyingly sensitive
5196         // about what we do, since it pretend generic variables are reference types and generates
5197         // an internal JIT tree even when just verifying generic code. </NICE>
5198         if (constrainedType.IsGenericVariable())
5199         {
5200             pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &T --> T
5201         }
5202         else if (constrainedType.IsValueType())
5203         {
5204             pResult->thisTransform = CORINFO_BOX_THIS; // convert 'this' of type &VC<T> --> boxed(VC<T>)
5205         }
5206         else
5207         {
5208             pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &C<T> --> C<T>
5209         }
5210     }
5211     else
5212     {
5213         // We have a "constrained." call.  Try a partial resolve of the constraint call.  Note that this
5214         // will not necessarily resolve the call exactly, since we might be compiling
5215         // shared generic code - it may just resolve it to a candidate suitable for
5216         // JIT compilation, and require a runtime lookup for the actual code pointer
5217         // to call.
5218         if (constrainedType.IsEnum())
5219         {
5220             // Optimize constrained calls to enum's GetHashCode method. TryResolveConstraintMethodApprox would return
5221             // null since the virtual method resolves to System.Enum's implementation and that's a reference type.
5222             // We can't do this for any other method since ToString and Equals have different semantics for enums
5223             // and their underlying type.
5224             if (pMD->GetSlot() == MscorlibBinder::GetMethod(METHOD__OBJECT__GET_HASH_CODE)->GetSlot())
5225             {
5226                 // Pretend this was a "constrained. UnderlyingType" instruction prefix
5227                 constrainedType = TypeHandle(MscorlibBinder::GetElementType(constrainedType.GetVerifierCorElementType()));
5228
5229                 // Native image signature encoder will use this field. It needs to match that pretended type, a bogus signature
5230                 // would be produced otherwise.
5231                 pConstrainedResolvedToken->hClass = (CORINFO_CLASS_HANDLE)constrainedType.AsPtr();
5232
5233                 // Clear the token and typespec because of they do not match hClass anymore.
5234                 pConstrainedResolvedToken->token = mdTokenNil;
5235                 pConstrainedResolvedToken->pTypeSpec = NULL;
5236             }
5237         }
5238
5239         MethodDesc * directMethod = constrainedType.GetMethodTable()->TryResolveConstraintMethodApprox(
5240             exactType, 
5241             pMD, 
5242             &fForceUseRuntimeLookup);
5243         if (directMethod)
5244         {
5245             // Either
5246             //    1. no constraint resolution at compile time (!directMethod)
5247             // OR 2. no code sharing lookup in call
5248             // OR 3. we have have resolved to an instantiating stub
5249
5250             pMDAfterConstraintResolution = directMethod;
5251             _ASSERTE(!pMDAfterConstraintResolution->IsInterface());
5252             fResolvedConstraint = TRUE;
5253             pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5254
5255             exactType = constrainedType;
5256         }
5257         else  if (constrainedType.IsValueType())
5258         {
5259             pResult->thisTransform = CORINFO_BOX_THIS;
5260         }
5261         else
5262         {
5263             pResult->thisTransform = CORINFO_DEREF_THIS;
5264         }
5265     }
5266
5267     //
5268     // Initialize callee context used for inlining and instantiation arguments
5269     //
5270
5271     MethodDesc * pTargetMD = pMDAfterConstraintResolution;
5272
5273     if (pTargetMD->HasMethodInstantiation())
5274     {
5275         pResult->contextHandle = MAKE_METHODCONTEXT(pTargetMD);
5276         pResult->exactContextNeedsRuntimeLookup = pTargetMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(pTargetMD->GetMethodInstantiation());
5277     }
5278     else
5279     {
5280         if (!exactType.IsTypeDesc())
5281         {
5282             // Because of .NET's notion of base calls, exactType may point to a sub-class
5283             // of the actual class that defines pTargetMD.  If the JIT decides to inline, it is
5284             // important that they 'match', so we fix exactType here.
5285 #ifdef FEATURE_READYTORUN_COMPILER
5286             if (IsReadyToRunCompilation() &&
5287                 !isVerifyOnly() && 
5288                 !IsInSameVersionBubble((MethodDesc*)callerHandle, pTargetMD))
5289             {
5290                 // For version resilient code we can only inline within the same version bubble;
5291                 // we "repair" the precise types only for those callees.
5292                 // The above condition needs to stay in sync with CEEInfo::canInline
5293             }
5294             else
5295 #endif
5296             {
5297          
5298                 exactType = pTargetMD->GetExactDeclaringType(exactType.AsMethodTable());
5299                 _ASSERTE(!exactType.IsNull());
5300             }
5301         }
5302
5303         pResult->contextHandle = MAKE_CLASSCONTEXT(exactType.AsPtr());
5304         pResult->exactContextNeedsRuntimeLookup = exactType.IsSharedByGenericInstantiations();
5305     }
5306
5307     //
5308     // Determine whether to perform direct call
5309     //
5310
5311     bool directCall = false;
5312     bool resolvedCallVirt = false;
5313     bool callVirtCrossingVersionBubble = false;
5314
5315     // Delegate targets are always treated as direct calls here. (It would be nice to clean it up...).
5316     if (flags & CORINFO_CALLINFO_LDFTN)
5317     {
5318         if (m_pOverride != NULL)
5319             TypeEquivalenceFixupSpecificationHelper(m_pOverride, pTargetMD);
5320         directCall = true;
5321     }
5322     else
5323     // Static methods are always direct calls
5324     if (pTargetMD->IsStatic())
5325     {
5326         directCall = true;
5327     }
5328     else
5329     // Backwards compat: calls to abstract interface methods are treated as callvirt
5330     if (pTargetMD->GetMethodTable()->IsInterface() && pTargetMD->IsAbstract())
5331     {
5332         directCall = false;
5333     }
5334     else
5335     if (!(flags & CORINFO_CALLINFO_CALLVIRT) || fResolvedConstraint)
5336     {
5337         directCall = true;
5338     }
5339     else
5340     {
5341         bool devirt;
5342
5343 #ifdef FEATURE_READYTORUN_COMPILER
5344
5345         // if we are generating version resilient code
5346         // AND
5347         //    caller/callee are in different version bubbles
5348         // we have to apply more restrictive rules
5349         // These rules are related to the "inlining rules" as far as the
5350         // boundaries of a version bubble are concerned.
5351
5352         if (IsReadyToRunCompilation() &&
5353             !isVerifyOnly() &&
5354             !IsInSameVersionBubble((MethodDesc*)callerHandle, pTargetMD)
5355            )
5356         {
5357             // For version resiliency we won't de-virtualize all final/sealed method calls.  Because during a 
5358             // servicing event it is legal to unseal a method or type.
5359             //
5360             // Note that it is safe to devirtualize in the following cases, since a servicing event cannot later modify it
5361             //  1) Callvirt on a virtual final method of a value type - since value types are sealed types as per ECMA spec
5362             //  2) Delegate.Invoke() - since a Delegate is a sealed class as per ECMA spec
5363             //  3) JIT intrinsics - since they have pre-defined behavior
5364             devirt = pTargetMD->GetMethodTable()->IsValueType() ||
5365                      (pTargetMD->GetMethodTable()->IsDelegate() && ((DelegateEEClass*)(pTargetMD->GetMethodTable()->GetClass()))->GetInvokeMethod() == pMD) ||
5366                      (pTargetMD->IsFCall() && ECall::GetIntrinsicID(pTargetMD) != CORINFO_INTRINSIC_Illegal);
5367
5368             callVirtCrossingVersionBubble = true;
5369         }
5370         else
5371 #endif
5372         if (pTargetMD->GetMethodTable()->IsInterface())
5373         {
5374             // Handle interface methods specially because the Sealed bit has no meaning on interfaces.
5375             devirt = !IsMdVirtual(pTargetMD->GetAttrs());
5376         }
5377         else
5378         {
5379             DWORD dwMethodAttrs = pTargetMD->GetAttrs();
5380             devirt = !IsMdVirtual(dwMethodAttrs) || IsMdFinal(dwMethodAttrs) || pTargetMD->GetMethodTable()->IsSealed();
5381         }
5382
5383         if (devirt)
5384         {
5385             resolvedCallVirt = true;
5386             directCall = true;
5387         }
5388     }
5389
5390     if (directCall)
5391     {
5392         bool allowInstParam = (flags & CORINFO_CALLINFO_ALLOWINSTPARAM);
5393
5394         // Create instantiating stub if necesary
5395         if (!allowInstParam && pTargetMD->RequiresInstArg())
5396         {
5397             pTargetMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pTargetMD, 
5398                 exactType.AsMethodTable(), 
5399                 FALSE /* forceBoxedEntryPoint */, 
5400                 pTargetMD->GetMethodInstantiation(),
5401                 FALSE /* allowInstParam */);
5402         }
5403
5404         // We don't allow a JIT to call the code directly if a runtime lookup is
5405         // needed. This is the case if
5406         //     1. the scan of the call token indicated that it involves code sharing
5407         // AND 2. the method is an instantiating stub
5408         //
5409         // In these cases the correct instantiating stub is only found via a runtime lookup.
5410         //
5411         // Note that most JITs don't call instantiating stubs directly if they can help it -
5412         // they call the underlying shared code and provide the type context parameter
5413         // explicitly. However
5414         //    (a) some JITs may call instantiating stubs (it makes the JIT simpler) and
5415         //    (b) if the method is a remote stub then the EE will force the
5416         //        call through an instantiating stub and
5417         //    (c) constraint calls that require runtime context lookup are never resolved 
5418         //        to underlying shared generic code
5419
5420         if (((pResult->exactContextNeedsRuntimeLookup && pTargetMD->IsInstantiatingStub() && (!allowInstParam || fResolvedConstraint)) || fForceUseRuntimeLookup)
5421                 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
5422                 && ContextIsShared(pResolvedToken->tokenContext))
5423         {
5424             _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5425             pResult->kind = CORINFO_CALL_CODE_POINTER;
5426
5427             // For reference types, the constrained type does not affect method resolution
5428             DictionaryEntryKind entryKind = (!constrainedType.IsNull() && constrainedType.IsValueType()) ? ConstrainedMethodEntrySlot : MethodEntrySlot;
5429
5430             ComputeRuntimeLookupForSharedGenericToken(entryKind,
5431                                                       pResolvedToken,
5432                                                       pConstrainedResolvedToken,
5433                                                       pMD,
5434                                                       &pResult->codePointerLookup);
5435         }
5436         else
5437         {
5438             if (allowInstParam && pTargetMD->IsInstantiatingStub())
5439             {
5440                 pTargetMD = pTargetMD->GetWrappedMethodDesc();
5441             }
5442
5443             pResult->kind = CORINFO_CALL;
5444
5445             if (IsReadyToRunCompilation())
5446             {
5447                 // Compensate for always treating delegates as direct calls above
5448                 if ((flags & CORINFO_CALLINFO_LDFTN) && (flags & CORINFO_CALLINFO_CALLVIRT) && !resolvedCallVirt)
5449                 {
5450                    pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5451                 }
5452             }
5453         }
5454         pResult->nullInstanceCheck = resolvedCallVirt;
5455     }
5456     // All virtual calls which take method instantiations must
5457     // currently be implemented by an indirect call via a runtime-lookup
5458     // function pointer
5459     else if (pTargetMD->HasMethodInstantiation())
5460     {
5461         pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;  // stub dispatch can't handle generic method calls yet
5462         pResult->nullInstanceCheck = TRUE;
5463     }
5464     // Non-interface dispatches go through the vtable.
5465     else if (!pTargetMD->IsInterface())
5466     {
5467         pResult->kind = CORINFO_VIRTUALCALL_VTABLE;
5468         pResult->nullInstanceCheck = TRUE;
5469
5470         // We'll special virtual calls to target methods in the corelib assembly when compiling in R2R mode, and generate fragile-NI-like callsites for improved performance. We
5471         // can do that because today we'll always service the corelib assembly and the runtime in one bundle. Any caller in the corelib version bubble can benefit from this
5472         // performance optimization.
5473         if (IsReadyToRunCompilation() && !CallerAndCalleeInSystemVersionBubble((MethodDesc*)callerHandle, pTargetMD))
5474         {
5475             pResult->kind = CORINFO_VIRTUALCALL_STUB;
5476         }
5477     }
5478     else
5479     {
5480         if (IsReadyToRunCompilation())
5481         {
5482             // Insert explicit null checks for cross-version bubble non-interface calls. 
5483             // It is required to handle null checks properly for non-virtual <-> virtual change between versions
5484             pResult->nullInstanceCheck = !!(callVirtCrossingVersionBubble && !pTargetMD->IsInterface());
5485         }
5486         else
5487         {
5488             // No need to null check - the dispatch code will deal with null this.
5489             pResult->nullInstanceCheck = FALSE;
5490         }
5491 #ifdef STUB_DISPATCH_PORTABLE
5492         pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5493 #else // STUB_DISPATCH_PORTABLE
5494         pResult->kind = CORINFO_VIRTUALCALL_STUB;
5495
5496         // We can't make stub calls when we need exact information
5497         // for interface calls from shared code.
5498
5499         if (// If the token is not shared then we don't need a runtime lookup
5500             pResult->exactContextNeedsRuntimeLookup
5501             // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
5502             && ContextIsShared(pResolvedToken->tokenContext))
5503         {
5504             _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5505             
5506             ComputeRuntimeLookupForSharedGenericToken(DispatchStubAddrSlot,
5507                                                         pResolvedToken,
5508                                                         NULL,
5509                                                         pMD,
5510                                                         &pResult->stubLookup);
5511         }
5512         else
5513         {
5514             BYTE * indcell = NULL;
5515
5516             if (!(flags & CORINFO_CALLINFO_KINDONLY) && !isVerifyOnly())
5517             {
5518 #ifndef CROSSGEN_COMPILE
5519                 // We shouldn't be using GetLoaderAllocator here because for LCG, we need to get the 
5520                 // VirtualCallStubManager from where the stub will be used. 
5521                 // For normal methods there is no difference.
5522                 LoaderAllocator *pLoaderAllocator = m_pMethodBeingCompiled->GetLoaderAllocatorForCode();
5523                 VirtualCallStubManager *pMgr = pLoaderAllocator->GetVirtualCallStubManager();
5524
5525                 PCODE addr = pMgr->GetCallStub(exactType, pTargetMD);
5526                 _ASSERTE(pMgr->isStub(addr));
5527                 
5528                 // Now we want to indirect through a cell so that updates can take place atomically.
5529                 if (m_pMethodBeingCompiled->IsLCGMethod())
5530                 {
5531                     // LCG methods should use recycled indcells to prevent leaks.
5532                     indcell = pMgr->GenerateStubIndirection(addr, TRUE);
5533
5534                     // Add it to the per DM list so that we can recycle them when the resolver is finalized
5535                     LCGMethodResolver *pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetLCGMethodResolver();
5536                     pResolver->AddToUsedIndCellList(indcell);
5537                 }
5538                 else
5539                 {
5540                     // Normal methods should avoid recycled cells to preserve the locality of all indcells
5541                     // used by one method.
5542                     indcell = pMgr->GenerateStubIndirection(addr, FALSE);
5543                 }
5544 #else // CROSSGEN_COMPILE
5545                 // This path should be unreachable during crossgen
5546                 _ASSERTE(false);
5547 #endif // CROSSGEN_COMPILE
5548             }
5549
5550             // We use an indirect call
5551             pResult->stubLookup.constLookup.accessType = IAT_PVALUE;
5552             pResult->stubLookup.constLookup.addr = indcell;
5553         }
5554 #endif // STUB_DISPATCH_PORTABLE
5555     }
5556
5557     pResult->hMethod = CORINFO_METHOD_HANDLE(pTargetMD);
5558
5559     pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5560     if ((flags & CORINFO_CALLINFO_SECURITYCHECKS) &&
5561         !((MethodDesc *)callerHandle)->IsILStub()) // IL stubs can access everything, don't bother doing access checks
5562     {
5563         //Our type system doesn't always represent the target exactly with the MethodDesc.  In all cases,
5564         //carry around the parent MethodTable for both Caller and Callee.
5565         TypeHandle calleeTypeForSecurity = TypeHandle(pResolvedToken->hClass);
5566         MethodDesc * pCalleeForSecurity = pMD;
5567
5568         MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle); //Should this be the open MD?
5569
5570         if (pCallerForSecurity->HasClassOrMethodInstantiation())
5571         {
5572             _ASSERTE(!IsDynamicScope(pResolvedToken->tokenScope));
5573
5574             SigTypeContext typeContext;
5575             SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
5576             _ASSERTE(!typeContext.IsEmpty());
5577
5578             //If the caller is generic, load the open type and resolve the token again.  Use that for the access
5579             //checks.  If we don't do this then we can't tell the difference between:
5580             //
5581             //BadGeneric<T> containing a methodspec for InaccessibleType::member (illegal)
5582             //and
5583             //BadGeneric<T> containing a methodspec for !!0::member instantiated over InaccessibleType (legal)
5584
5585             if (pResolvedToken->pTypeSpec != NULL)
5586             {
5587                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
5588                 calleeTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5589
5590                 // typeHnd can be a variable type
5591                 if (calleeTypeForSecurity.GetMethodTable() == NULL)
5592                 {
5593                     COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
5594                 }
5595             }
5596
5597             if (pCalleeForSecurity->IsArray())
5598             {
5599                 // FindOrCreateAssociatedMethodDesc won't remap array method desc because of array base type 
5600                 // is not part of instantiation. We have to special case it.
5601                 pCalleeForSecurity = calleeTypeForSecurity.GetMethodTable()->GetParallelMethodDesc(pCalleeForSecurity);
5602             }
5603             else
5604             if (pResolvedToken->pMethodSpec != NULL)
5605             {
5606                 DWORD nGenericMethodArgs = 0;
5607                 CQuickBytes qbGenericMethodArgs;
5608                 TypeHandle *genericMethodArgs = NULL;
5609
5610                 SigPointer sp(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
5611
5612                 BYTE etype;
5613                 IfFailThrow(sp.GetByte(&etype));
5614
5615                 // Load the generic method instantiation
5616                 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, (Module *)pResolvedToken->tokenScope);
5617
5618                 IfFailThrow(sp.GetData(&nGenericMethodArgs));
5619
5620                 DWORD cbAllocSize = 0;
5621                 if (!ClrSafeInt<DWORD>::multiply(nGenericMethodArgs, sizeof(TypeHandle), cbAllocSize))
5622                 {
5623                     COMPlusThrowHR(COR_E_OVERFLOW);
5624                 }
5625
5626                 genericMethodArgs = reinterpret_cast<TypeHandle *>(qbGenericMethodArgs.AllocThrows(cbAllocSize));
5627
5628                 for (DWORD i = 0; i < nGenericMethodArgs; i++)
5629                 {
5630                     genericMethodArgs[i] = sp.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5631                     _ASSERTE (!genericMethodArgs[i].IsNull());
5632                     IfFailThrow(sp.SkipExactlyOne());
5633                 }
5634
5635                 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(genericMethodArgs, nGenericMethodArgs), FALSE);
5636             }
5637             else
5638             if (pResolvedToken->pTypeSpec != NULL)
5639             {
5640                 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(), TRUE);
5641             }
5642         }
5643
5644         TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5645
5646         //Passed various link-time checks.  Now do access checks.
5647
5648         BOOL doAccessCheck = TRUE;
5649         BOOL canAccessMethod = TRUE;
5650         AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
5651         DynamicResolver * pAccessContext = NULL;
5652
5653         callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5654         if (pCallerForSecurity->IsDynamicMethod())
5655         {
5656             doAccessCheck = ModifyCheckForDynamicMethod(pCallerForSecurity->AsDynamicMethodDesc()->GetResolver(),
5657                                                         &callerTypeForSecurity,
5658                                                         &accessCheckType, &pAccessContext);
5659         }
5660     
5661         pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5662
5663         if (doAccessCheck)
5664         {
5665             AccessCheckOptions accessCheckOptions(accessCheckType,
5666                                                   pAccessContext,
5667                                                   FALSE,
5668                                                   pCalleeForSecurity);
5669
5670             _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5671             StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5672
5673             canAccessMethod = ClassLoader::CanAccess(&accessContext,
5674                                                      calleeTypeForSecurity.GetMethodTable(),
5675                                                      calleeTypeForSecurity.GetAssembly(),
5676                                                      pCalleeForSecurity->GetAttrs(),
5677                                                      pCalleeForSecurity,
5678                                                      NULL,
5679                                                      accessCheckOptions
5680                                                     );
5681
5682             // If we were allowed access to the exact method, but it is on a type that has a type parameter
5683             // (for instance an array), we need to ensure that we also have access to the type parameter.
5684             if (canAccessMethod && calleeTypeForSecurity.HasTypeParam())
5685             {
5686                 TypeHandle typeParam = calleeTypeForSecurity.GetTypeParam();
5687                 while (typeParam.HasTypeParam())
5688                 {
5689                     typeParam = typeParam.GetTypeParam();
5690                 }
5691
5692                 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5693                 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5694
5695                 MethodTable* pTypeParamMT = typeParam.GetMethodTable();
5696
5697                 // No access check is need for Var, MVar, or FnPtr.
5698                 if (pTypeParamMT != NULL)
5699                     canAccessMethod = ClassLoader::CanAccessClass(&accessContext,
5700                                                                   pTypeParamMT,
5701                                                                   typeParam.GetAssembly(),
5702                                                                   accessCheckOptions);
5703             }
5704
5705             pResult->accessAllowed = canAccessMethod ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
5706             if (!canAccessMethod)
5707             {
5708                 //Check failed, fill in the throw exception helper.
5709                 pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_METHOD_ACCESS_EXCEPTION;
5710                 pResult->callsiteCalloutHelper.numArgs = 2;
5711
5712                 pResult->callsiteCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5713                 pResult->callsiteCalloutHelper.args[1].Set(CORINFO_METHOD_HANDLE(pCalleeForSecurity));
5714
5715                 //We now embed open instantiations in a few places for security callouts (since you can only
5716                 //do the security check on the open instantiation).  We throw these methods out in
5717                 //TriageMethodForZap.  In addition, NGen has problems referencing them properly.  Just throw out the whole
5718                 //method and rejit at runtime.
5719                 if (IsCompilingForNGen())
5720                 {
5721                     if (pCallerForSecurity->ContainsGenericVariables()
5722                         || pCalleeForSecurity->ContainsGenericVariables())
5723                     {
5724                         COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
5725                     }
5726                 }
5727             }
5728         }
5729     }
5730
5731     //We're pretty much done at this point.  Let's grab the rest of the information that the jit is going to
5732     //need.
5733     pResult->classFlags = getClassAttribsInternal(pResolvedToken->hClass);
5734
5735     pResult->methodFlags = getMethodAttribsInternal(pResult->hMethod);
5736
5737     SignatureKind signatureKind = flags & CORINFO_CALLINFO_CALLVIRT ? SK_VIRTUAL_CALLSITE : SK_CALLSITE;
5738     getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL, signatureKind);
5739
5740     if (flags & CORINFO_CALLINFO_VERIFICATION)
5741     {
5742         if (pResult->hMethod != pResolvedToken->hMethod)
5743         {
5744             pResult->verMethodFlags = getMethodAttribsInternal(pResolvedToken->hMethod);
5745             getMethodSigInternal(pResolvedToken->hMethod, &pResult->verSig, pResolvedToken->hClass);
5746         }
5747         else
5748         {
5749             pResult->verMethodFlags = pResult->methodFlags;
5750             pResult->verSig = pResult->sig;
5751         }
5752     }
5753
5754     pResult->secureDelegateInvoke = FALSE;
5755
5756 #ifdef FEATURE_STUBS_AS_IL
5757     if (m_pMethodBeingCompiled->IsDynamicMethod())
5758     {
5759         auto pMD = m_pMethodBeingCompiled->AsDynamicMethodDesc();
5760         if (pMD->IsILStub() && pMD->IsSecureDelegateStub())
5761         {
5762             pResult->secureDelegateInvoke = TRUE;
5763         }
5764     }
5765 #endif
5766
5767     EE_TO_JIT_TRANSITION();
5768 }
5769
5770 BOOL CEEInfo::canAccessFamily(CORINFO_METHOD_HANDLE hCaller,
5771                               CORINFO_CLASS_HANDLE hInstanceType)
5772 {
5773     WRAPPER_NO_CONTRACT;
5774
5775     BOOL ret = FALSE;
5776
5777     //Since this is only for verification, I don't need to do the demand.
5778     JIT_TO_EE_TRANSITION();
5779
5780     TypeHandle targetType = TypeHandle(hInstanceType);
5781     TypeHandle accessingType = TypeHandle(GetMethod(hCaller)->GetMethodTable());
5782     AccessCheckOptions::AccessCheckType accessCheckOptions = AccessCheckOptions::kNormalAccessibilityChecks;
5783     DynamicResolver* pIgnored;
5784     BOOL doCheck = TRUE;
5785     if (GetMethod(hCaller)->IsDynamicMethod())
5786     {
5787         //If this is a DynamicMethod, perform the check from the type to which the DynamicMethod was
5788         //attached.
5789         //
5790         //If this is a dynamic method, don't do this check.  If they specified SkipVisibilityChecks
5791         //(ModifyCheckForDynamicMethod returned false), we should obviously skip the check for the C++
5792         //protected rule (since we skipped all the other visibility checks).  If they specified
5793         //RestrictedSkipVisibilityChecks, then they're a "free" DynamicMethod.  This check is meaningless
5794         //(i.e.  it would always fail).  We've already done a demand for access to the member.  Let that be
5795         //enough.
5796         doCheck = ModifyCheckForDynamicMethod(GetMethod(hCaller)->AsDynamicMethodDesc()->GetResolver(),
5797                                               &accessingType, &accessCheckOptions, &pIgnored);
5798         if (accessCheckOptions == AccessCheckOptions::kRestrictedMemberAccess 
5799             || accessCheckOptions == AccessCheckOptions::kRestrictedMemberAccessNoTransparency
5800             )
5801             doCheck = FALSE;
5802     }
5803
5804     if (doCheck)
5805     {
5806         ret = ClassLoader::CanAccessFamilyVerification(accessingType, targetType);
5807     }
5808     else
5809     {
5810         ret = TRUE;
5811     }
5812
5813     EE_TO_JIT_TRANSITION();
5814     return ret;
5815 }
5816 void CEEInfo::ThrowExceptionForHelper(const CORINFO_HELPER_DESC * throwHelper)
5817 {
5818     CONTRACTL {
5819         SO_TOLERANT;
5820         THROWS;
5821         GC_TRIGGERS;
5822         MODE_PREEMPTIVE;
5823     } CONTRACTL_END;
5824
5825     JIT_TO_EE_TRANSITION();
5826
5827     _ASSERTE(throwHelper->args[0].argType == CORINFO_HELPER_ARG_TYPE_Method);
5828     MethodDesc *pCallerMD = GetMethod(throwHelper->args[0].methodHandle);
5829
5830     StaticAccessCheckContext accessContext(pCallerMD);
5831
5832     switch (throwHelper->helperNum)
5833     {
5834     case CORINFO_HELP_METHOD_ACCESS_EXCEPTION:
5835         {
5836             _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Method);
5837             ThrowMethodAccessException(&accessContext, GetMethod(throwHelper->args[1].methodHandle));
5838         }
5839         break;
5840     case CORINFO_HELP_FIELD_ACCESS_EXCEPTION:
5841         {
5842             _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Field);
5843             ThrowFieldAccessException(&accessContext, reinterpret_cast<FieldDesc *>(throwHelper->args[1].fieldHandle));
5844         }
5845         break;
5846     case CORINFO_HELP_CLASS_ACCESS_EXCEPTION:
5847         {
5848             _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Class);
5849             TypeHandle typeHnd(throwHelper->args[1].classHandle);
5850             ThrowTypeAccessException(&accessContext, typeHnd.GetMethodTable());
5851         }
5852         break;
5853
5854     default:
5855         _ASSERTE(!"Unknown access exception type");
5856     }
5857     EE_TO_JIT_TRANSITION();
5858 }
5859
5860
5861 BOOL CEEInfo::isRIDClassDomainID(CORINFO_CLASS_HANDLE cls)
5862 {
5863     CONTRACTL {
5864         SO_TOLERANT;
5865         THROWS;
5866         GC_TRIGGERS;
5867         MODE_PREEMPTIVE;
5868     } CONTRACTL_END;
5869
5870     BOOL result = FALSE;
5871
5872     JIT_TO_EE_TRANSITION();
5873
5874     TypeHandle  VMClsHnd(cls);
5875
5876     result = !VMClsHnd.AsMethodTable()->IsDynamicStatics();
5877
5878     EE_TO_JIT_TRANSITION();
5879
5880     return result;
5881 }
5882
5883
5884 /***********************************************************************/
5885 unsigned CEEInfo::getClassDomainID (CORINFO_CLASS_HANDLE clsHnd,
5886                                     void **ppIndirection)
5887 {
5888     CONTRACTL {
5889         SO_TOLERANT;
5890         THROWS;
5891         GC_TRIGGERS;
5892         MODE_PREEMPTIVE;
5893     } CONTRACTL_END;
5894
5895     unsigned result = 0;
5896
5897     if (ppIndirection != NULL)
5898         *ppIndirection = NULL;
5899
5900     JIT_TO_EE_TRANSITION();
5901
5902     TypeHandle  VMClsHnd(clsHnd);
5903
5904     if (VMClsHnd.AsMethodTable()->IsDynamicStatics())
5905     {
5906         result = (unsigned)VMClsHnd.AsMethodTable()->GetModuleDynamicEntryID();
5907     }
5908     else
5909     {
5910         result = (unsigned)VMClsHnd.AsMethodTable()->GetClassIndex();
5911     }
5912
5913     EE_TO_JIT_TRANSITION();
5914
5915     return result;
5916 }
5917
5918 //---------------------------------------------------------------------------------------
5919 //
5920 // Used by the JIT to determine whether the profiler or IBC is tracking object
5921 // allocations
5922 //
5923 // Return Value:
5924 //    bool indicating whether the profiler or IBC is tracking object allocations
5925 //
5926 // Notes:
5927 //    Normally, a profiler would just directly call the inline helper to determine
5928 //    whether the profiler set the relevant event flag (e.g.,
5929 //    CORProfilerTrackAllocationsEnabled). However, this wrapper also asks whether we're
5930 //    running for IBC instrumentation or enabling the object allocated ETW event. If so,
5931 //    we treat that the same as if the profiler requested allocation information, so that
5932 //    the JIT will still use the profiling-friendly object allocation jit helper, so the
5933 //    allocations can be tracked.
5934 //
5935
5936 bool __stdcall TrackAllocationsEnabled()
5937 {
5938     CONTRACTL 
5939     {
5940         NOTHROW;
5941         GC_NOTRIGGER;
5942         MODE_ANY;      
5943     } 
5944     CONTRACTL_END;
5945
5946     return (
5947         (g_IBCLogger.InstrEnabled() != FALSE)
5948 #ifdef PROFILING_SUPPORTED
5949         || CORProfilerTrackAllocationsEnabled()
5950 #endif // PROFILING_SUPPORTED
5951 #ifdef FEATURE_EVENT_TRACE
5952         || ETW::TypeSystemLog::IsHeapAllocEventEnabled()
5953 #endif // FEATURE_EVENT_TRACE
5954         );
5955 }
5956
5957 /***********************************************************************/
5958 CorInfoHelpFunc CEEInfo::getNewHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_METHOD_HANDLE callerHandle)
5959 {
5960     CONTRACTL {
5961         SO_TOLERANT;
5962         THROWS;
5963         GC_TRIGGERS;
5964         MODE_PREEMPTIVE;
5965     } CONTRACTL_END;
5966
5967     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5968
5969     JIT_TO_EE_TRANSITION();
5970
5971     TypeHandle  VMClsHnd(pResolvedToken->hClass);
5972
5973     if(VMClsHnd.IsTypeDesc())
5974     {
5975         COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateFunctionPointer"));
5976     }
5977
5978     if(VMClsHnd.IsAbstract())
5979     {
5980         COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateAbstractClass"));
5981     }
5982
5983     MethodTable* pMT = VMClsHnd.AsMethodTable();
5984     result = getNewHelperStatic(pMT);
5985
5986     _ASSERTE(result != CORINFO_HELP_UNDEF);
5987         
5988     EE_TO_JIT_TRANSITION();
5989
5990     return result;
5991 }
5992
5993 /***********************************************************************/
5994 CorInfoHelpFunc CEEInfo::getNewHelperStatic(MethodTable * pMT)
5995 {
5996     STANDARD_VM_CONTRACT;
5997
5998
5999     // Slow helper is the default
6000     CorInfoHelpFunc helper = CORINFO_HELP_NEWFAST;
6001
6002
6003     if (pMT->IsComObjectType())
6004     {
6005         // Use slow helper
6006         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6007     }
6008     else
6009     if ((pMT->GetBaseSize() >= LARGE_OBJECT_SIZE) || 
6010         pMT->HasFinalizer())
6011     {
6012         // Use slow helper
6013         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6014     }
6015     else
6016     // don't call the super-optimized one since that does not check
6017     // for GCStress
6018     if (GCStress<cfg_alloc>::IsEnabled())
6019     {
6020         // Use slow helper
6021         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6022     }
6023     else
6024 #ifdef _LOGALLOC
6025 #ifdef LOGGING
6026     // Super fast version doesn't do logging
6027     if (LoggingOn(LF_GCALLOC, LL_INFO10))
6028     {
6029         // Use slow helper
6030         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6031     }
6032     else
6033 #endif // LOGGING
6034 #endif // _LOGALLOC
6035     // Don't use the SFAST allocator when tracking object allocations,
6036     // so we don't have to instrument it.
6037     if (TrackAllocationsEnabled())
6038     {
6039         // Use slow helper
6040         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6041     }
6042     else
6043 #ifdef FEATURE_64BIT_ALIGNMENT
6044     // @ARMTODO: Force all 8-byte alignment requiring allocations down one slow path. As performance
6045     // measurements dictate we can spread these out to faster, more specialized helpers later.
6046     if (pMT->RequiresAlign8())
6047     {
6048         // Use slow helper
6049         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6050     }
6051     else
6052 #endif
6053     {
6054         // Use the fast helper when all conditions are met
6055         helper = CORINFO_HELP_NEWSFAST;
6056     }
6057
6058 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
6059     // If we are use the the fast allocator we also may need the 
6060     // specialized varion for align8
6061     if (pMT->GetClass()->IsAlign8Candidate() &&
6062         (helper == CORINFO_HELP_NEWSFAST))
6063     {
6064         helper = CORINFO_HELP_NEWSFAST_ALIGN8;
6065     }
6066 #endif // FEATURE_DOUBLE_ALIGNMENT_HINT
6067
6068     return helper;
6069 }
6070
6071 /***********************************************************************/
6072 // <REVIEW> this only works for shared generic code because all the
6073 // helpers are actually the same. If they were different then things might
6074 // break because the same helper would end up getting used for different but
6075 // representation-compatible arrays (e.g. one with a default constructor
6076 // and one without) </REVIEW>
6077 CorInfoHelpFunc CEEInfo::getNewArrHelper (CORINFO_CLASS_HANDLE arrayClsHnd)
6078 {
6079     CONTRACTL {
6080         SO_TOLERANT;
6081         THROWS;
6082         GC_TRIGGERS;
6083         MODE_PREEMPTIVE;
6084     } CONTRACTL_END;
6085
6086     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6087
6088     JIT_TO_EE_TRANSITION();
6089
6090     TypeHandle arrayType(arrayClsHnd);
6091
6092     result = getNewArrHelperStatic(arrayType);
6093
6094     _ASSERTE(result != CORINFO_HELP_UNDEF);
6095
6096     EE_TO_JIT_TRANSITION();
6097
6098     return result;
6099 }
6100
6101 /***********************************************************************/
6102 CorInfoHelpFunc CEEInfo::getNewArrHelperStatic(TypeHandle clsHnd)
6103 {
6104     STANDARD_VM_CONTRACT;
6105
6106     ArrayTypeDesc* arrayTypeDesc = clsHnd.AsArray();
6107     _ASSERTE(arrayTypeDesc->GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
6108
6109     if (GCStress<cfg_alloc>::IsEnabled())
6110     {
6111         return CORINFO_HELP_NEWARR_1_DIRECT;
6112     }
6113
6114     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6115
6116     TypeHandle thElemType = arrayTypeDesc->GetTypeParam();
6117     CorElementType elemType = thElemType.GetInternalCorElementType();
6118
6119     // This is if we're asked for newarr !0 when verifying generic code
6120     // Of course ideally you wouldn't even be generating code when
6121     // simply doing verification (we run the JIT importer in import-only
6122     // mode), but importing does more than one would like so we try to be
6123     // tolerant when asked for non-sensical helpers.
6124     if (CorTypeInfo::IsGenericVariable(elemType))
6125     {
6126         result = CORINFO_HELP_NEWARR_1_OBJ;
6127     }
6128     else if (CorTypeInfo::IsObjRef(elemType))
6129     {
6130         // It is an array of object refs
6131         result = CORINFO_HELP_NEWARR_1_OBJ;
6132     }
6133     else
6134     {
6135         // These cases always must use the slow helper
6136         if (
6137 #ifdef FEATURE_64BIT_ALIGNMENT
6138             thElemType.RequiresAlign8() ||
6139 #endif
6140             (elemType == ELEMENT_TYPE_VOID) ||
6141             LoggingOn(LF_GCALLOC, LL_INFO10) ||
6142             TrackAllocationsEnabled())
6143         {
6144             // Use the slow helper
6145             result = CORINFO_HELP_NEWARR_1_DIRECT;
6146         }
6147 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
6148         else if (elemType == ELEMENT_TYPE_R8)
6149         {
6150             // Use the Align8 fast helper
6151             result = CORINFO_HELP_NEWARR_1_ALIGN8;
6152         }
6153 #endif
6154         else
6155         {
6156             // Yea, we can do it the fast way!
6157             result = CORINFO_HELP_NEWARR_1_VC;
6158         }
6159     }
6160
6161     return result;
6162 }
6163
6164 /***********************************************************************/
6165 CorInfoHelpFunc CEEInfo::getCastingHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fThrowing)
6166 {
6167     CONTRACTL {
6168         SO_TOLERANT;
6169         THROWS;
6170         GC_TRIGGERS;
6171         MODE_PREEMPTIVE;
6172     } CONTRACTL_END;
6173
6174     if (isVerifyOnly())
6175         return fThrowing ? CORINFO_HELP_CHKCASTANY : CORINFO_HELP_ISINSTANCEOFANY;
6176
6177     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6178
6179     JIT_TO_EE_TRANSITION();
6180
6181     bool fClassMustBeRestored;
6182     result = getCastingHelperStatic(TypeHandle(pResolvedToken->hClass), fThrowing, &fClassMustBeRestored);
6183     if (fClassMustBeRestored && m_pOverride != NULL)
6184         m_pOverride->classMustBeLoadedBeforeCodeIsRun(pResolvedToken->hClass);
6185
6186     EE_TO_JIT_TRANSITION();
6187
6188     return result;
6189 }
6190
6191 /***********************************************************************/
6192 CorInfoHelpFunc CEEInfo::getCastingHelperStatic(TypeHandle clsHnd, bool fThrowing, bool * pfClassMustBeRestored)
6193 {
6194     STANDARD_VM_CONTRACT;
6195
6196     // Slow helper is the default
6197     int helper = CORINFO_HELP_ISINSTANCEOFANY;
6198
6199     *pfClassMustBeRestored = false;
6200
6201     if (clsHnd == TypeHandle(g_pCanonMethodTableClass))
6202     {
6203         // In shared code just use the catch-all helper for type variables, as the same
6204         // code may be used for interface/array/class instantiations
6205         //
6206         // We may be able to take advantage of constraints to select a specialized helper.
6207         // This optimizations does not seem to be warranted at the moment.
6208         _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6209     }
6210     else
6211     if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasVariance())
6212     {
6213         // Casting to variant type requires the type to be fully loaded
6214         *pfClassMustBeRestored = true;
6215
6216         _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6217     }
6218     else
6219     if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasTypeEquivalence())
6220     {
6221         // If the type can be equivalent with something, use the slow helper
6222         // Note: if the type of the instance is the one marked as equivalent, it will be
6223         // caught by the fast helpers in the same way as they catch transparent proxies.
6224         _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6225     }
6226     else
6227     if (clsHnd.IsInterface())
6228     {
6229         // If it is a non-variant interface, use the fast interface helper
6230         helper = CORINFO_HELP_ISINSTANCEOFINTERFACE;
6231     }
6232     else
6233     if (clsHnd.IsArray())
6234     {           
6235         if (clsHnd.AsArray()->GetInternalCorElementType() != ELEMENT_TYPE_SZARRAY)
6236         {
6237             // Casting to multidimensional array type requires restored pointer to EEClass to fetch rank
6238             *pfClassMustBeRestored = true;
6239         }
6240
6241         // If it is an array, use the fast array helper
6242         helper = CORINFO_HELP_ISINSTANCEOFARRAY;
6243     }
6244     else
6245     if (!clsHnd.IsTypeDesc() && !Nullable::IsNullableType(clsHnd))
6246     {
6247         // If it is a non-variant class, use the fast class helper
6248         helper = CORINFO_HELP_ISINSTANCEOFCLASS;
6249     }
6250     else
6251     {
6252         // Otherwise, use the slow helper
6253         _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6254     }
6255
6256 #ifdef FEATURE_PREJIT
6257     BOOL t1, t2, forceInstr;
6258     SystemDomain::GetCompilationOverrides(&t1, &t2, &forceInstr);
6259     if (forceInstr)
6260     {
6261         // If we're compiling for instrumentation, use the slowest but instrumented cast helper
6262         helper = CORINFO_HELP_ISINSTANCEOFANY;
6263     }
6264 #endif
6265
6266     if (fThrowing)
6267     {
6268         const int delta = CORINFO_HELP_CHKCASTANY - CORINFO_HELP_ISINSTANCEOFANY;
6269
6270         static_assert_no_msg(CORINFO_HELP_CHKCASTINTERFACE 
6271             == CORINFO_HELP_ISINSTANCEOFINTERFACE + delta);
6272         static_assert_no_msg(CORINFO_HELP_CHKCASTARRAY 
6273             == CORINFO_HELP_ISINSTANCEOFARRAY + delta);
6274         static_assert_no_msg(CORINFO_HELP_CHKCASTCLASS 
6275             == CORINFO_HELP_ISINSTANCEOFCLASS + delta);
6276
6277         helper += delta;
6278     }
6279
6280     return (CorInfoHelpFunc)helper;
6281 }
6282
6283 /***********************************************************************/
6284 CorInfoHelpFunc CEEInfo::getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd)
6285 {
6286     CONTRACTL {
6287         SO_TOLERANT;
6288         NOTHROW;
6289         GC_NOTRIGGER;
6290         MODE_PREEMPTIVE;
6291     } CONTRACTL_END;
6292
6293     CorInfoHelpFunc result = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
6294
6295     JIT_TO_EE_TRANSITION_LEAF();
6296
6297     TypeHandle cls(clsHnd);
6298     MethodTable* pMT = cls.AsMethodTable();
6299
6300     if (pMT->IsDynamicStatics())
6301     {
6302         _ASSERTE(!cls.ContainsGenericVariables());
6303         _ASSERTE(pMT->GetModuleDynamicEntryID() != (unsigned) -1);
6304
6305         result = CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
6306     }
6307
6308     EE_TO_JIT_TRANSITION_LEAF();
6309
6310     return result;
6311 }
6312
6313 /***********************************************************************/
6314 CorInfoHelpFunc CEEInfo::getUnBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6315 {
6316     LIMITED_METHOD_CONTRACT;
6317
6318     if (m_pOverride != NULL)
6319         m_pOverride->classMustBeLoadedBeforeCodeIsRun(clsHnd);
6320
6321     TypeHandle VMClsHnd(clsHnd);
6322     if (Nullable::IsNullableType(VMClsHnd))
6323         return CORINFO_HELP_UNBOX_NULLABLE;
6324     
6325     return CORINFO_HELP_UNBOX;
6326 }
6327
6328 /***********************************************************************/
6329 bool CEEInfo::getReadyToRunHelper(
6330         CORINFO_RESOLVED_TOKEN *        pResolvedToken,
6331         CORINFO_LOOKUP_KIND *           pGenericLookupKind,
6332         CorInfoHelpFunc                 id,
6333         CORINFO_CONST_LOOKUP *          pLookup
6334         )
6335 {
6336     LIMITED_METHOD_CONTRACT;
6337     UNREACHABLE();      // only called during NGen
6338 }
6339
6340 /***********************************************************************/
6341 void CEEInfo::getReadyToRunDelegateCtorHelper(
6342         CORINFO_RESOLVED_TOKEN * pTargetMethod,
6343         CORINFO_CLASS_HANDLE     delegateType,
6344         CORINFO_LOOKUP *   pLookup
6345         )
6346 {
6347     LIMITED_METHOD_CONTRACT;
6348     UNREACHABLE();      // only called during NGen
6349 }
6350
6351 /***********************************************************************/
6352 // see code:Nullable#NullableVerification
6353
6354 CORINFO_CLASS_HANDLE  CEEInfo::getTypeForBox(CORINFO_CLASS_HANDLE  cls)
6355 {
6356     LIMITED_METHOD_CONTRACT;
6357
6358     TypeHandle VMClsHnd(cls);
6359     if (Nullable::IsNullableType(VMClsHnd)) {
6360         VMClsHnd = VMClsHnd.AsMethodTable()->GetInstantiation()[0];
6361     }    
6362     return static_cast<CORINFO_CLASS_HANDLE>(VMClsHnd.AsPtr());
6363 }
6364
6365 /***********************************************************************/
6366 // see code:Nullable#NullableVerification
6367 CorInfoHelpFunc CEEInfo::getBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6368 {
6369     CONTRACTL {
6370         SO_TOLERANT;
6371         THROWS;
6372         GC_TRIGGERS;
6373         MODE_PREEMPTIVE;
6374     } CONTRACTL_END;
6375
6376     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6377
6378     JIT_TO_EE_TRANSITION();
6379
6380     TypeHandle VMClsHnd(clsHnd);
6381     if (Nullable::IsNullableType(VMClsHnd))
6382     {
6383         result = CORINFO_HELP_BOX_NULLABLE;
6384     }
6385     else 
6386     {
6387         if(VMClsHnd.IsTypeDesc())
6388             COMPlusThrow(kInvalidOperationException,W("InvalidOperation_TypeCannotBeBoxed"));
6389
6390         // we shouldn't allow boxing of types that contains stack pointers
6391         // csc and vbc already disallow it.
6392         if (VMClsHnd.AsMethodTable()->IsByRefLike())
6393             COMPlusThrow(kInvalidProgramException,W("NotSupported_ByRefLike"));
6394
6395         result = CORINFO_HELP_BOX;
6396     }
6397     
6398     EE_TO_JIT_TRANSITION();
6399
6400     return result;
6401 }
6402
6403 /***********************************************************************/
6404 CorInfoHelpFunc CEEInfo::getSecurityPrologHelper(CORINFO_METHOD_HANDLE ftn)
6405 {
6406     CONTRACTL {
6407         SO_TOLERANT;
6408         THROWS;
6409         GC_TRIGGERS;
6410         MODE_PREEMPTIVE;
6411     } CONTRACTL_END;
6412
6413     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6414
6415     JIT_TO_EE_TRANSITION();
6416
6417 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6418     // This will make sure that when IBC logging is on, we call the slow helper with IBC probe
6419     if (IsCompilingForNGen() &&
6420         GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
6421     {
6422         result = CORINFO_HELP_SECURITY_PROLOG_FRAMED;
6423     }
6424 #endif // FEATURE_NATIVE_IMAGE_GENERATION
6425
6426     if (result == CORINFO_HELP_UNDEF)
6427     {
6428         result = CORINFO_HELP_SECURITY_PROLOG;
6429     }
6430
6431     EE_TO_JIT_TRANSITION();
6432
6433     return result;
6434 }
6435
6436 /***********************************************************************/
6437 // registers a vararg sig & returns a class-specific cookie for it.
6438
6439 CORINFO_VARARGS_HANDLE CEEInfo::getVarArgsHandle(CORINFO_SIG_INFO *sig,
6440                                                  void **ppIndirection)
6441 {
6442     CONTRACTL {
6443         SO_TOLERANT;
6444         THROWS;
6445         GC_TRIGGERS;
6446         MODE_PREEMPTIVE;
6447     } CONTRACTL_END;
6448
6449     CORINFO_VARARGS_HANDLE result = NULL;
6450
6451     if (ppIndirection != NULL)
6452         *ppIndirection = NULL;
6453
6454     JIT_TO_EE_TRANSITION();
6455
6456     Module* module = GetModule(sig->scope);
6457
6458     result = CORINFO_VARARGS_HANDLE(module->GetVASigCookie(Signature(sig->pSig, sig->cbSig)));
6459
6460     EE_TO_JIT_TRANSITION();
6461
6462     return result;
6463 }
6464
6465 bool CEEInfo::canGetVarArgsHandle(CORINFO_SIG_INFO *sig)
6466 {
6467     LIMITED_METHOD_CONTRACT;
6468     return true;
6469 }
6470
6471 /***********************************************************************/
6472 unsigned CEEInfo::getMethodHash (CORINFO_METHOD_HANDLE ftnHnd)
6473 {
6474     CONTRACTL {
6475         SO_TOLERANT;
6476         THROWS;
6477         GC_TRIGGERS;
6478         MODE_PREEMPTIVE;
6479     } CONTRACTL_END;
6480
6481     unsigned result = 0;
6482
6483     JIT_TO_EE_TRANSITION();
6484
6485     MethodDesc* ftn = GetMethod(ftnHnd);
6486
6487     result = (unsigned) ftn->GetStableHash();
6488
6489     EE_TO_JIT_TRANSITION();
6490
6491     return result;
6492 }
6493
6494 /***********************************************************************/
6495 const char* CEEInfo::getMethodName (CORINFO_METHOD_HANDLE ftnHnd, const char** scopeName)
6496 {
6497     CONTRACTL {
6498         SO_TOLERANT;
6499         THROWS;
6500         GC_TRIGGERS;
6501         MODE_PREEMPTIVE;
6502     } CONTRACTL_END;
6503
6504     const char* result = NULL;
6505
6506     JIT_TO_EE_TRANSITION();
6507
6508     MethodDesc *ftn;
6509
6510     ftn = GetMethod(ftnHnd);
6511
6512     if (scopeName != 0)
6513     {
6514         if (ftn->IsLCGMethod())
6515         {
6516             *scopeName = "DynamicClass";
6517         }
6518         else if (ftn->IsILStub())
6519         {
6520             *scopeName = ILStubResolver::GetStubClassName(ftn);
6521         }
6522         else
6523         {
6524             MethodTable * pMT = ftn->GetMethodTable();
6525 #if defined(_DEBUG) 
6526 #ifdef FEATURE_SYMDIFF
6527             if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SymDiffDump))
6528             {
6529                 if (pMT->IsArray())
6530                 {
6531                     ssClsNameBuff.Clear();
6532                     ssClsNameBuff.SetUTF8(pMT->GetDebugClassName());
6533                 }
6534                 else
6535                     pMT->_GetFullyQualifiedNameForClassNestedAware(ssClsNameBuff);
6536             }
6537             else
6538             {
6539 #endif
6540                 // Calling _GetFullyQualifiedNameForClass in chk build is very expensive
6541                 // since it construct the class name everytime we call this method. In chk
6542                 // builds we already have a cheaper way to get the class name -
6543                 // GetDebugClassName - which doesn't calculate the class name everytime.
6544                 // This results in huge saving in Ngen time for checked builds. 
6545                 ssClsNameBuff.Clear();
6546                 ssClsNameBuff.SetUTF8(pMT->GetDebugClassName());
6547
6548 #ifdef FEATURE_SYMDIFF
6549             }
6550 #endif            
6551             // Append generic instantiation at the end
6552             Instantiation inst = pMT->GetInstantiation();
6553             if (!inst.IsEmpty())
6554                 TypeString::AppendInst(ssClsNameBuff, inst);
6555                 
6556             *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
6557 #else // !_DEBUG
6558             // since this is for diagnostic purposes only,
6559             // give up on the namespace, as we don't have a buffer to concat it
6560             // also note this won't show array class names.
6561             LPCUTF8 nameSpace;
6562             *scopeName= pMT->GetFullyQualifiedNameInfo(&nameSpace);
6563 #endif // !_DEBUG
6564         }
6565     }
6566
6567     result = ftn->GetName();
6568
6569     EE_TO_JIT_TRANSITION();
6570     
6571     return result;
6572 }
6573
6574 const char* CEEInfo::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftnHnd, const char** className, const char** namespaceName)
6575 {
6576     CONTRACTL {
6577         SO_TOLERANT;
6578         THROWS;
6579         GC_TRIGGERS;
6580         MODE_PREEMPTIVE;
6581     } CONTRACTL_END;
6582
6583     const char* result = NULL;
6584     const char* classResult = NULL;
6585     const char* namespaceResult = NULL;
6586
6587     JIT_TO_EE_TRANSITION();
6588
6589     MethodDesc *ftn = GetMethod(ftnHnd);
6590     mdMethodDef token = ftn->GetMemberDef();
6591
6592     if (!IsNilToken(token))
6593     {
6594         if (!FAILED(ftn->GetMDImport()->GetNameOfMethodDef(token, &result)))
6595         {
6596             MethodTable* pMT = ftn->GetMethodTable();
6597             classResult = pMT->GetFullyQualifiedNameInfo(&namespaceResult);
6598         }
6599     }
6600
6601     if (className != NULL)
6602     {
6603         *className = classResult;
6604     }
6605
6606     if (namespaceName != NULL)
6607     {
6608         *namespaceName = namespaceResult;
6609     }
6610
6611     EE_TO_JIT_TRANSITION();
6612     
6613     return result;
6614 }
6615
6616 /*********************************************************************/
6617 const char* CEEInfo::getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName)
6618 {
6619     CONTRACTL {
6620         SO_TOLERANT;
6621         THROWS;
6622         GC_TRIGGERS;
6623         MODE_PREEMPTIVE;
6624     } CONTRACTL_END;
6625
6626     const char* result = NULL;
6627     const char* namespaceResult = NULL;
6628
6629     JIT_TO_EE_TRANSITION();
6630     TypeHandle VMClsHnd(cls);
6631
6632     if (!VMClsHnd.IsTypeDesc())
6633     {
6634         result = VMClsHnd.AsMethodTable()->GetFullyQualifiedNameInfo(&namespaceResult);
6635     }
6636    
6637     if (namespaceName != NULL)
6638     {
6639         *namespaceName = namespaceResult;
6640     }
6641
6642     EE_TO_JIT_TRANSITION();
6643     
6644     return result;
6645 }
6646
6647 /*********************************************************************/
6648 CORINFO_CLASS_HANDLE CEEInfo::getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index)
6649 {
6650     CONTRACTL {
6651         SO_TOLERANT;
6652         THROWS;
6653         GC_TRIGGERS;
6654         MODE_PREEMPTIVE;
6655     } CONTRACTL_END;
6656
6657     CORINFO_CLASS_HANDLE result = NULL;
6658
6659     JIT_TO_EE_TRANSITION_LEAF();
6660
6661     TypeHandle VMClsHnd(cls);
6662     Instantiation inst = VMClsHnd.GetInstantiation();
6663     TypeHandle typeArg = index < inst.GetNumArgs() ? inst[index] : NULL;
6664     result = CORINFO_CLASS_HANDLE(typeArg.AsPtr());
6665
6666     EE_TO_JIT_TRANSITION_LEAF();
6667     
6668     return result;
6669 }
6670
6671 /*********************************************************************/
6672 DWORD CEEInfo::getMethodAttribs (CORINFO_METHOD_HANDLE ftn)
6673 {
6674     CONTRACTL {
6675         SO_TOLERANT;
6676         THROWS;
6677         GC_TRIGGERS;
6678         MODE_PREEMPTIVE;
6679     } CONTRACTL_END;
6680
6681     DWORD result = 0;
6682
6683     JIT_TO_EE_TRANSITION();
6684
6685     result = getMethodAttribsInternal(ftn);
6686
6687     EE_TO_JIT_TRANSITION();
6688
6689     return result;
6690 }
6691
6692 /*********************************************************************/
6693 DWORD CEEInfo::getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftn)
6694 {
6695     STANDARD_VM_CONTRACT;
6696
6697 /*
6698     returns method attribute flags (defined in corhdr.h)
6699
6700     NOTE: This doesn't return certain method flags
6701     (mdAssem, mdFamANDAssem, mdFamORAssem, mdPrivateScope)
6702 */
6703
6704     MethodDesc* pMD = GetMethod(ftn);
6705
6706     if (pMD->IsLCGMethod()) 
6707     {
6708         return CORINFO_FLG_STATIC | CORINFO_FLG_DONT_INLINE | CORINFO_FLG_NOSECURITYWRAP;
6709     }
6710
6711     DWORD result = CORINFO_FLG_NOSECURITYWRAP;
6712
6713     // <REVISIT_TODO>@todo: can we git rid of CORINFO_FLG_ stuff and just include cor.h?</REVISIT_TODO>
6714
6715     DWORD attribs = pMD->GetAttrs();
6716
6717     if (IsMdFamily(attribs))
6718         result |= CORINFO_FLG_PROTECTED;
6719     if (IsMdStatic(attribs))
6720         result |= CORINFO_FLG_STATIC;
6721     if (pMD->IsSynchronized())
6722         result |= CORINFO_FLG_SYNCH;
6723     if (pMD->IsFCallOrIntrinsic())
6724         result |= CORINFO_FLG_NOGCCHECK | CORINFO_FLG_INTRINSIC;
6725     if (pMD->IsJitIntrinsic())
6726         result |= CORINFO_FLG_JIT_INTRINSIC;
6727     if (IsMdVirtual(attribs))
6728         result |= CORINFO_FLG_VIRTUAL;
6729     if (IsMdAbstract(attribs))
6730         result |= CORINFO_FLG_ABSTRACT;
6731     if (IsMdRTSpecialName(attribs))
6732     {
6733         LPCUTF8 pName = pMD->GetName();
6734         if (IsMdInstanceInitializer(attribs, pName) ||
6735             IsMdClassConstructor(attribs, pName))
6736             result |= CORINFO_FLG_CONSTRUCTOR;
6737     }
6738
6739     //
6740     // See if we need to embed a .cctor call at the head of the
6741     // method body.
6742     //
6743
6744     MethodTable* pMT = pMD->GetMethodTable();
6745
6746     // method or class might have the final bit
6747     if (IsMdFinal(attribs) || pMT->IsSealed())
6748     {
6749         result |= CORINFO_FLG_FINAL;
6750     }
6751
6752     if (pMD->IsEnCAddedMethod())
6753     {
6754         result |= CORINFO_FLG_EnC;
6755     }
6756
6757     if (pMD->IsSharedByGenericInstantiations())
6758     {
6759         result |= CORINFO_FLG_SHAREDINST;
6760     }
6761
6762     if (pMD->IsNDirect())
6763     {
6764         result |= CORINFO_FLG_PINVOKE;
6765     }
6766
6767     if (IsMdRequireSecObject(attribs))
6768     {
6769         // Assume all methods marked as DynamicSecurity are
6770         // marked that way because they use StackCrawlMark to identify
6771         // the caller.
6772         // See comments in canInline or canTailCall
6773         result |= CORINFO_FLG_DONT_INLINE_CALLER;
6774     }
6775
6776     // Check for the aggressive optimization directive. AggressiveOptimization only makes sense for IL methods.
6777     DWORD ilMethodImplAttribs = 0;
6778     if (pMD->IsIL())
6779     {
6780         ilMethodImplAttribs = pMD->GetImplAttrs();
6781         if (IsMiAggressiveOptimization(ilMethodImplAttribs))
6782         {
6783             result |= CORINFO_FLG_AGGRESSIVE_OPT;
6784         }
6785     }
6786
6787     // Check for an inlining directive.
6788     if (pMD->IsNotInline())
6789     {
6790         /* Function marked as not inlineable */
6791         result |= CORINFO_FLG_DONT_INLINE;
6792     }
6793     // AggressiveInlining only makes sense for IL methods.
6794     else if (pMD->IsIL() && IsMiAggressiveInlining(ilMethodImplAttribs))
6795     {
6796         result |= CORINFO_FLG_FORCEINLINE;
6797     }
6798
6799     if (pMT->IsDelegate() && ((DelegateEEClass*)(pMT->GetClass()))->GetInvokeMethod() == pMD)
6800     {
6801         // This is now used to emit efficient invoke code for any delegate invoke,
6802         // including multicast.
6803         result |= CORINFO_FLG_DELEGATE_INVOKE;
6804     }
6805
6806     return result;
6807 }
6808
6809 /*********************************************************************/
6810 void CEEInfo::setMethodAttribs (
6811         CORINFO_METHOD_HANDLE ftnHnd,
6812         CorInfoMethodRuntimeFlags attribs)
6813 {
6814     CONTRACTL {
6815         SO_TOLERANT;
6816         THROWS;
6817         GC_TRIGGERS;
6818         MODE_PREEMPTIVE;
6819     } CONTRACTL_END;
6820
6821     JIT_TO_EE_TRANSITION();
6822
6823     MethodDesc* ftn = GetMethod(ftnHnd);
6824
6825     if (attribs & CORINFO_FLG_BAD_INLINEE)
6826     {
6827         BOOL fCacheInliningHint = TRUE;
6828
6829 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6830         if (IsCompilationProcess())
6831         {
6832             // Since we are running managed code during NGen the inlining hint may be 
6833             // changing underneeth us as the code is JITed. We need to prevent the inlining
6834             // hints from changing once we start to use them to place IL in the image.
6835             if (!g_pCEECompileInfo->IsCachingOfInliningHintsEnabled())
6836             {
6837                 fCacheInliningHint = FALSE;
6838             }
6839             else
6840             {
6841                 // Don't cache inlining hints inside mscorlib during NGen of other assemblies,
6842                 // since mscorlib is loaded domain neutral and will survive worker process recycling,
6843                 // causing determinism problems.
6844                 Module * pModule = ftn->GetModule();
6845                 if (pModule->IsSystem() && pModule->HasNativeImage())
6846                 {
6847                     fCacheInliningHint = FALSE;
6848                 }
6849             }
6850         }
6851 #endif
6852
6853         if (fCacheInliningHint)
6854         {
6855             ftn->SetNotInline(true);
6856         }
6857     }
6858
6859     EE_TO_JIT_TRANSITION();
6860 }
6861
6862 /*********************************************************************/
6863
6864 void getMethodInfoILMethodHeaderHelper(
6865     COR_ILMETHOD_DECODER* header,
6866     CORINFO_METHOD_INFO* methInfo
6867     )
6868 {
6869     LIMITED_METHOD_CONTRACT;
6870     
6871     methInfo->ILCode          = const_cast<BYTE*>(header->Code);
6872     methInfo->ILCodeSize      = header->GetCodeSize();
6873     methInfo->maxStack        = static_cast<unsigned short>(header->GetMaxStack());
6874     methInfo->EHcount         = static_cast<unsigned short>(header->EHCount());
6875
6876     methInfo->options         =
6877         (CorInfoOptions)((header->GetFlags() & CorILMethod_InitLocals) ? CORINFO_OPT_INIT_LOCALS : 0) ;
6878 }
6879
6880 mdToken FindGenericMethodArgTypeSpec(IMDInternalImport* pInternalImport)
6881 {
6882     STANDARD_VM_CONTRACT;
6883
6884     HENUMInternalHolder hEnumTypeSpecs(pInternalImport);
6885     mdToken token;
6886
6887     static const BYTE signature[] = { ELEMENT_TYPE_MVAR, 0 };
6888
6889     hEnumTypeSpecs.EnumAllInit(mdtTypeSpec);
6890     while (hEnumTypeSpecs.EnumNext(&token))
6891     {
6892         PCCOR_SIGNATURE pSig;
6893         ULONG cbSig;
6894         IfFailThrow(pInternalImport->GetTypeSpecFromToken(token, &pSig, &cbSig));
6895         if (cbSig == sizeof(signature) && memcmp(pSig, signature, cbSig) == 0)
6896             return token;
6897     }
6898
6899     COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6900 }
6901
6902 /*********************************************************************
6903
6904 IL is the most efficient and portable way to implement certain low level methods 
6905 in mscorlib.dll. Unfortunately, there is no good way to link IL into mscorlib.dll today.
6906 Until we find a good way to link IL into mscorlib.dll, we will provide the IL implementation here.
6907
6908 - All IL intrinsincs are members of System.Runtime.CompilerServices.JitHelpers class
6909 - All IL intrinsincs should be kept very simple. Implement the minimal reusable version of 
6910 unsafe construct and depend on inlining to do the rest.
6911 - The C# implementation of the IL intrinsic should be good enough for functionalily. Everything should work 
6912 correctly (but slower) if the IL intrinsics are removed.
6913
6914 *********************************************************************/
6915
6916 bool getILIntrinsicImplementation(MethodDesc * ftn,
6917                                   CORINFO_METHOD_INFO * methInfo)
6918 {
6919     STANDARD_VM_CONTRACT;
6920
6921     // Precondition: ftn is a method in mscorlib 
6922     _ASSERTE(ftn->GetModule()->IsSystem());
6923
6924     mdMethodDef tk = ftn->GetMemberDef();
6925
6926     // Compare tokens to cover all generic instantiations
6927     // The body of the first method is simply ret Arg0. The second one first casts the arg to I4.
6928
6929     if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_CAST_TO_STACKPTR)->GetMemberDef())
6930     {
6931         // Return the argument that was passed in converted to IntPtr
6932         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I, CEE_RET };
6933         methInfo->ILCode = const_cast<BYTE*>(ilcode);
6934         methInfo->ILCodeSize = sizeof(ilcode);
6935         methInfo->maxStack = 1;
6936         methInfo->EHcount = 0;
6937         methInfo->options = (CorInfoOptions)0;
6938         return true;
6939     }
6940     else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST)->GetMemberDef()) 
6941     {
6942         // Normally we would follow the above pattern and unconditionally replace the IL,
6943         // relying on generic type constraints to guarantee that it will only ever be instantiated
6944         // on the type/size of argument we expect.
6945         //
6946         // However C#/CLR does not support restricting a generic type to be an Enum, so the best
6947         // we can do is constrain it to be a value type.  This is fine for run time, since we only
6948         // ever create instantiations on 4 byte or less Enums. But during NGen we may compile instantiations
6949         // on other value types (to be specific, every value type instatiation of EqualityComparer
6950         // because of its TypeDependencyAttribute; here again we would like to restrict this to
6951         // 4 byte or less Enums but cannot).
6952         //
6953         // This IL is invalid for those instantiations, and replacing it would lead to all sorts of
6954         // errors at NGen time.  So we only replace it for instantiations where it would be valid, 
6955         // leaving the others, which we should never execute, with the C# implementation of throwing.
6956
6957         _ASSERTE(ftn->HasMethodInstantiation());
6958         Instantiation inst = ftn->GetMethodInstantiation();
6959
6960         _ASSERTE(inst.GetNumArgs() == 1);
6961         CorElementType et = inst[0].GetVerifierCorElementType();
6962         if (et == ELEMENT_TYPE_I4 ||
6963             et == ELEMENT_TYPE_U4 ||
6964             et == ELEMENT_TYPE_I2 ||
6965             et == ELEMENT_TYPE_U2 ||
6966             et == ELEMENT_TYPE_I1 ||
6967             et == ELEMENT_TYPE_U1)
6968         {
6969             // Cast to I4 and return the argument that was passed in.
6970             static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I4, CEE_RET };
6971             methInfo->ILCode = const_cast<BYTE*>(ilcode);
6972             methInfo->ILCodeSize = sizeof(ilcode);
6973             methInfo->maxStack = 1;
6974             methInfo->EHcount = 0;
6975             methInfo->options = (CorInfoOptions)0;
6976             return true;
6977         }
6978     }
6979     else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG)->GetMemberDef()) 
6980     {
6981         // The the comment above on why this is is not an unconditional replacement.  This case handles
6982         // Enums backed by 8 byte values.
6983
6984         _ASSERTE(ftn->HasMethodInstantiation());
6985         Instantiation inst = ftn->GetMethodInstantiation();
6986
6987         _ASSERTE(inst.GetNumArgs() == 1);
6988         CorElementType et = inst[0].GetVerifierCorElementType();
6989         if (et == ELEMENT_TYPE_I8 ||
6990             et == ELEMENT_TYPE_U8)
6991         {
6992             // Cast to I8 and return the argument that was passed in.
6993             static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I8, CEE_RET };
6994             methInfo->ILCode = const_cast<BYTE*>(ilcode);
6995             methInfo->ILCodeSize = sizeof(ilcode);
6996             methInfo->maxStack = 1;
6997             methInfo->EHcount = 0;
6998             methInfo->options = (CorInfoOptions)0;
6999             return true;
7000         }
7001     }
7002     else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__GET_RAW_SZ_ARRAY_DATA)->GetMemberDef())
7003     {
7004         mdToken tokArrayPinningHelper = MscorlibBinder::GetField(FIELD__ARRAY_PINNING_HELPER__M_ARRAY_DATA)->GetMemberDef();
7005
7006         static BYTE ilcode[] = { CEE_LDARG_0,
7007                                  CEE_LDFLDA,0,0,0,0,
7008                                  CEE_RET };
7009
7010         ilcode[2] = (BYTE)(tokArrayPinningHelper);
7011         ilcode[3] = (BYTE)(tokArrayPinningHelper >> 8);
7012         ilcode[4] = (BYTE)(tokArrayPinningHelper >> 16);
7013         ilcode[5] = (BYTE)(tokArrayPinningHelper >> 24);
7014
7015         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7016         methInfo->ILCodeSize = sizeof(ilcode);
7017         methInfo->maxStack = 1;
7018         methInfo->EHcount = 0;
7019         methInfo->options = (CorInfoOptions)0;
7020         return true;
7021     }
7022
7023     return false;
7024 }
7025
7026 bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
7027                                            CORINFO_METHOD_INFO * methInfo)
7028 {
7029     STANDARD_VM_CONTRACT;
7030
7031     // Precondition: ftn is a method in mscorlib 
7032     _ASSERTE(ftn->GetModule()->IsSystem());
7033
7034     mdMethodDef tk = ftn->GetMemberDef();
7035
7036     if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_POINTER)->GetMemberDef())
7037     {
7038         // Return the argument that was passed in.
7039         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_U, CEE_RET };
7040         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7041         methInfo->ILCodeSize = sizeof(ilcode);
7042         methInfo->maxStack = 1;
7043         methInfo->EHcount = 0;
7044         methInfo->options = (CorInfoOptions)0;
7045         return true;
7046     }
7047     if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__SIZEOF)->GetMemberDef())
7048     {
7049         _ASSERTE(ftn->HasMethodInstantiation());
7050         Instantiation inst = ftn->GetMethodInstantiation();
7051
7052         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7053         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7054
7055         static BYTE ilcode[] = { CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0, CEE_RET };
7056
7057         ilcode[2] = (BYTE)(tokGenericArg);
7058         ilcode[3] = (BYTE)(tokGenericArg >> 8);
7059         ilcode[4] = (BYTE)(tokGenericArg >> 16);
7060         ilcode[5] = (BYTE)(tokGenericArg >> 24);
7061
7062         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7063         methInfo->ILCodeSize = sizeof(ilcode);
7064         methInfo->maxStack = 1;
7065         methInfo->EHcount = 0;
7066         methInfo->options = (CorInfoOptions)0;
7067         return true;
7068     }
7069     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef() ||
7070              tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__OBJECT_AS)->GetMemberDef() ||
7071              tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_REF_POINTER)->GetMemberDef() ||
7072              tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_REF_IN)->GetMemberDef())
7073     {
7074         // Return the argument that was passed in.
7075         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
7076         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7077         methInfo->ILCodeSize = sizeof(ilcode);
7078         methInfo->maxStack = 1;
7079         methInfo->EHcount = 0;
7080         methInfo->options = (CorInfoOptions)0;
7081         return true;
7082     }
7083     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD)->GetMemberDef() ||
7084              tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_ADD)->GetMemberDef())
7085     {
7086         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7087
7088         static BYTE ilcode[] = { CEE_LDARG_1,
7089             CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0,
7090             CEE_CONV_I,
7091             CEE_MUL,
7092             CEE_LDARG_0,
7093             CEE_ADD,
7094             CEE_RET };
7095
7096         ilcode[3] = (BYTE)(tokGenericArg);
7097         ilcode[4] = (BYTE)(tokGenericArg >> 8);
7098         ilcode[5] = (BYTE)(tokGenericArg >> 16);
7099         ilcode[6] = (BYTE)(tokGenericArg >> 24);
7100
7101         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7102         methInfo->ILCodeSize = sizeof(ilcode);
7103         methInfo->maxStack = 2;
7104         methInfo->EHcount = 0;
7105         methInfo->options = (CorInfoOptions)0;
7106         return true;
7107     }
7108     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_INTPTR_ADD)->GetMemberDef())
7109     {
7110         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7111
7112         static BYTE ilcode[] = { CEE_LDARG_1,
7113             CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0,
7114             CEE_MUL,
7115             CEE_LDARG_0,
7116             CEE_ADD,
7117             CEE_RET };
7118
7119         ilcode[3] = (BYTE)(tokGenericArg);
7120         ilcode[4] = (BYTE)(tokGenericArg >> 8);
7121         ilcode[5] = (BYTE)(tokGenericArg >> 16);
7122         ilcode[6] = (BYTE)(tokGenericArg >> 24);
7123
7124         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7125         methInfo->ILCodeSize = sizeof(ilcode);
7126         methInfo->maxStack = 2;
7127         methInfo->EHcount = 0;
7128         methInfo->options = (CorInfoOptions)0;
7129         return true;
7130     }
7131     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD_BYTE_OFFSET)->GetMemberDef())
7132     {
7133         static BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_ADD, CEE_RET };
7134
7135         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7136         methInfo->ILCodeSize = sizeof(ilcode);
7137         methInfo->maxStack = 2;
7138         methInfo->EHcount = 0;
7139         methInfo->options = (CorInfoOptions)0;
7140         return true;
7141     }
7142     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ARE_SAME)->GetMemberDef())
7143     {
7144         // Compare the two arguments
7145         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CEQ & 0xFF), CEE_RET };
7146         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7147         methInfo->ILCodeSize = sizeof(ilcode);
7148         methInfo->maxStack = 2;
7149         methInfo->EHcount = 0;
7150         methInfo->options = (CorInfoOptions)0;
7151         return true;
7152     }
7153     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_GREATER_THAN)->GetMemberDef())
7154     {
7155         // Compare the two arguments
7156         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CGT_UN & 0xFF), CEE_RET };
7157         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7158         methInfo->ILCodeSize = sizeof(ilcode);
7159         methInfo->maxStack = 2;
7160         methInfo->EHcount = 0;
7161         methInfo->options = (CorInfoOptions)0;
7162         return true;
7163     }
7164     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_LESS_THAN)->GetMemberDef())
7165     {
7166         // Compare the two arguments
7167         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CLT_UN & 0xFF), CEE_RET };
7168         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7169         methInfo->ILCodeSize = sizeof(ilcode);
7170         methInfo->maxStack = 2;
7171         methInfo->EHcount = 0;
7172         methInfo->options = (CorInfoOptions)0;
7173         return true;
7174     }
7175     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_INIT_BLOCK_UNALIGNED)->GetMemberDef())
7176     {
7177         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_LDARG_2, CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 0x01, CEE_PREFIX1, (CEE_INITBLK & 0xFF), CEE_RET };
7178         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7179         methInfo->ILCodeSize = sizeof(ilcode);
7180         methInfo->maxStack = 3;
7181         methInfo->EHcount = 0;
7182         methInfo->options = (CorInfoOptions)0;
7183         return true;
7184     }
7185     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_BYTE_OFFSET)->GetMemberDef())
7186     {
7187         static const BYTE ilcode[] = 
7188         {
7189             CEE_LDARG_1,
7190             CEE_LDARG_0,
7191             CEE_SUB,
7192             CEE_RET
7193         };
7194
7195         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7196         methInfo->ILCodeSize = sizeof(ilcode);
7197         methInfo->maxStack = 2;
7198         methInfo->EHcount = 0;
7199         methInfo->options = (CorInfoOptions)0;
7200         return true;
7201     }
7202     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_READ_UNALIGNED)->GetMemberDef() ||
7203              tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_READ_UNALIGNED)->GetMemberDef())
7204     {
7205         _ASSERTE(ftn->HasMethodInstantiation());
7206         Instantiation inst = ftn->GetMethodInstantiation();
7207         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7208         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7209
7210         static const BYTE ilcode[]
7211         { 
7212             CEE_LDARG_0,
7213             CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
7214             CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7215             CEE_RET
7216         };
7217
7218         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7219         methInfo->ILCodeSize = sizeof(ilcode);
7220         methInfo->maxStack = 2;
7221         methInfo->EHcount = 0;
7222         methInfo->options = (CorInfoOptions)0;
7223         return true;
7224     }
7225     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_WRITE_UNALIGNED)->GetMemberDef() ||
7226              tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_WRITE_UNALIGNED)->GetMemberDef())
7227     {
7228         _ASSERTE(ftn->HasMethodInstantiation());
7229         Instantiation inst = ftn->GetMethodInstantiation();
7230         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7231         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7232
7233         static const BYTE ilcode[]
7234         {
7235             CEE_LDARG_0,
7236             CEE_LDARG_1,
7237             CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
7238             CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7239             CEE_RET
7240         };
7241
7242         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7243         methInfo->ILCodeSize = sizeof(ilcode);
7244         methInfo->maxStack = 2;
7245         methInfo->EHcount = 0;
7246         methInfo->options = (CorInfoOptions)0;
7247         return true;
7248     }
7249
7250     return false;
7251 }
7252
7253 bool getILIntrinsicImplementationForVolatile(MethodDesc * ftn,
7254                                              CORINFO_METHOD_INFO * methInfo)
7255 {
7256     STANDARD_VM_CONTRACT;
7257
7258     //
7259     // This replaces the implementations of Volatile.* in mscorlib with more efficient ones.
7260     // We do this because we cannot otherwise express these in C#.  What we *want* to do is
7261     // to treat the byref args to these methods as "volatile."  In pseudo-C#, this would look
7262     // like:
7263     //
7264     //   int Read(ref volatile int location)
7265     //   {
7266     //       return location;
7267     //   }
7268     //
7269     // However, C# does not yet provide a way to declare a byref as "volatile."  So instead,
7270     // we substitute raw IL bodies for these methods that use the correct volatile instructions.
7271     //
7272
7273     // Precondition: ftn is a method in mscorlib in the System.Threading.Volatile class
7274     _ASSERTE(ftn->GetModule()->IsSystem());
7275     _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__VOLATILE));
7276     _ASSERTE(strcmp(ftn->GetMethodTable()->GetClass()->GetDebugClassName(), "System.Threading.Volatile") == 0);
7277
7278     const size_t VolatileMethodBodySize = 6;
7279
7280     struct VolatileMethodImpl
7281     {
7282         BinderMethodID methodId;
7283         BYTE body[VolatileMethodBodySize];
7284     };
7285
7286 #define VOLATILE_IMPL(type, loadinst, storeinst) \
7287     { \
7288         METHOD__VOLATILE__READ_##type, \
7289         { \
7290             CEE_LDARG_0, \
7291             CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7292             loadinst, \
7293             CEE_NOP, /*pad to VolatileMethodBodySize bytes*/ \
7294             CEE_RET \
7295         } \
7296     }, \
7297     { \
7298         METHOD__VOLATILE__WRITE_##type, \
7299         { \
7300             CEE_LDARG_0, \
7301             CEE_LDARG_1, \
7302             CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7303             storeinst, \
7304             CEE_RET \
7305         } \
7306     },
7307
7308     static const VolatileMethodImpl volatileImpls[] =
7309     {
7310         VOLATILE_IMPL(T,       CEE_LDIND_REF, CEE_STIND_REF)
7311         VOLATILE_IMPL(Bool,    CEE_LDIND_I1,  CEE_STIND_I1)
7312         VOLATILE_IMPL(Int,     CEE_LDIND_I4,  CEE_STIND_I4)
7313         VOLATILE_IMPL(IntPtr,  CEE_LDIND_I,   CEE_STIND_I)
7314         VOLATILE_IMPL(UInt,    CEE_LDIND_U4,  CEE_STIND_I4)
7315         VOLATILE_IMPL(UIntPtr, CEE_LDIND_I,   CEE_STIND_I)
7316         VOLATILE_IMPL(SByt,    CEE_LDIND_I1,  CEE_STIND_I1)
7317         VOLATILE_IMPL(Byte,    CEE_LDIND_U1,  CEE_STIND_I1)
7318         VOLATILE_IMPL(Shrt,    CEE_LDIND_I2,  CEE_STIND_I2)
7319         VOLATILE_IMPL(UShrt,   CEE_LDIND_U2,  CEE_STIND_I2)
7320         VOLATILE_IMPL(Flt,     CEE_LDIND_R4,  CEE_STIND_R4)
7321
7322         //
7323         // Ordinary volatile loads and stores only guarantee atomicity for pointer-sized (or smaller) data.
7324         // So, on 32-bit platforms we must use Interlocked operations instead for the 64-bit types.
7325         // The implementation in mscorlib already does this, so we will only substitute a new
7326         // IL body if we're running on a 64-bit platform.
7327         //
7328         IN_TARGET_64BIT(VOLATILE_IMPL(Long,  CEE_LDIND_I8, CEE_STIND_I8))
7329         IN_TARGET_64BIT(VOLATILE_IMPL(ULong, CEE_LDIND_I8, CEE_STIND_I8))
7330         IN_TARGET_64BIT(VOLATILE_IMPL(Dbl,   CEE_LDIND_R8, CEE_STIND_R8))
7331     };
7332
7333     mdMethodDef md = ftn->GetMemberDef();
7334     for (unsigned i = 0; i < NumItems(volatileImpls); i++)
7335     {
7336         if (md == MscorlibBinder::GetMethod(volatileImpls[i].methodId)->GetMemberDef())
7337         {
7338             methInfo->ILCode = const_cast<BYTE*>(volatileImpls[i].body);
7339             methInfo->ILCodeSize = VolatileMethodBodySize;
7340             methInfo->maxStack = 2;
7341             methInfo->EHcount = 0;
7342             methInfo->options = (CorInfoOptions)0;
7343             return true;
7344         }
7345     }
7346
7347     return false;
7348 }
7349
7350 bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn,
7351                                                 CORINFO_METHOD_INFO * methInfo)
7352 {
7353     STANDARD_VM_CONTRACT;
7354
7355     // Precondition: ftn is a method in mscorlib in the System.Threading.Interlocked class
7356     _ASSERTE(ftn->GetModule()->IsSystem());
7357     _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__INTERLOCKED));
7358
7359     // We are only interested if ftn's token and CompareExchange<T> token match
7360     if (ftn->GetMemberDef() != MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_T)->GetMemberDef())
7361         return false;       
7362
7363     // Get MethodDesc for System.Threading.Interlocked.CompareExchangeFast()
7364     MethodDesc* cmpxchgFast = MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_OBJECT);
7365
7366     // The MethodDesc lookup must not fail, and it should have the name "CompareExchangeFast"
7367     _ASSERTE(cmpxchgFast != NULL);
7368     _ASSERTE(strcmp(cmpxchgFast->GetName(), "CompareExchange") == 0);
7369
7370     // Setup up the body of the method
7371     static BYTE il[] = {
7372                           CEE_LDARG_0,
7373                           CEE_LDARG_1,
7374                           CEE_LDARG_2,
7375                           CEE_CALL,0,0,0,0, 
7376                           CEE_RET
7377                         };
7378
7379     // Get the token for System.Threading.Interlocked.CompareExchangeFast(), and patch [target]
7380     mdMethodDef cmpxchgFastToken = cmpxchgFast->GetMemberDef();
7381     il[4] = (BYTE)((int)cmpxchgFastToken >> 0);
7382     il[5] = (BYTE)((int)cmpxchgFastToken >> 8);
7383     il[6] = (BYTE)((int)cmpxchgFastToken >> 16);
7384     il[7] = (BYTE)((int)cmpxchgFastToken >> 24);
7385
7386     // Initialize methInfo
7387     methInfo->ILCode = const_cast<BYTE*>(il);
7388     methInfo->ILCodeSize = sizeof(il);
7389     methInfo->maxStack = 3;
7390     methInfo->EHcount = 0;
7391     methInfo->options = (CorInfoOptions)0;
7392
7393     return true;
7394 }
7395
7396 bool getILIntrinsicImplementationForRuntimeHelpers(MethodDesc * ftn,
7397     CORINFO_METHOD_INFO * methInfo)
7398 {
7399     STANDARD_VM_CONTRACT;
7400
7401     // Precondition: ftn is a method in mscorlib 
7402     _ASSERTE(ftn->GetModule()->IsSystem());
7403
7404     mdMethodDef tk = ftn->GetMemberDef();
7405
7406     if (tk == MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_REFERENCE_OR_CONTAINS_REFERENCES)->GetMemberDef())
7407     {
7408         _ASSERTE(ftn->HasMethodInstantiation());
7409         Instantiation inst = ftn->GetMethodInstantiation();
7410
7411         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7412         TypeHandle typeHandle = inst[0];
7413         MethodTable * methodTable = typeHandle.GetMethodTable();
7414
7415         static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
7416         static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };
7417
7418         if (!methodTable->IsValueType() || methodTable->ContainsPointers())
7419         {
7420             methInfo->ILCode = const_cast<BYTE*>(returnTrue);
7421         }
7422         else
7423         {
7424             methInfo->ILCode = const_cast<BYTE*>(returnFalse);
7425         }
7426
7427         methInfo->ILCodeSize = sizeof(returnTrue);
7428         methInfo->maxStack = 1;
7429         methInfo->EHcount = 0;
7430         methInfo->options = (CorInfoOptions)0;
7431         return true;
7432     }
7433
7434     return false;
7435 }
7436
7437 //---------------------------------------------------------------------------------------
7438 // 
7439 //static
7440 void 
7441 getMethodInfoHelper(
7442     MethodDesc *           ftn, 
7443     CORINFO_METHOD_HANDLE  ftnHnd, 
7444     COR_ILMETHOD_DECODER * header, 
7445     CORINFO_METHOD_INFO *  methInfo)
7446 {
7447     STANDARD_VM_CONTRACT;
7448
7449     _ASSERTE(ftn == GetMethod(ftnHnd));
7450
7451     methInfo->ftn             = ftnHnd;
7452     methInfo->scope           = GetScopeHandle(ftn);
7453     methInfo->regionKind      = CORINFO_REGION_JIT;
7454     //
7455     // For Jitted code the regionKind is JIT;
7456     // For Ngen-ed code the zapper will set this to HOT or COLD, if we  
7457     // are using IBC data to partition methods into Hot/Cold regions
7458
7459     /* Grab information from the IL header */
7460
7461     PCCOR_SIGNATURE pLocalSig = NULL;
7462     DWORD           cbLocalSig = 0;
7463
7464     if (NULL != header)
7465     {
7466         bool fILIntrinsic = false;
7467
7468         MethodTable * pMT  = ftn->GetMethodTable();
7469
7470         if (pMT->GetModule()->IsSystem())
7471         {
7472             if (MscorlibBinder::IsClass(pMT, CLASS__JIT_HELPERS))
7473             {
7474                 fILIntrinsic = getILIntrinsicImplementation(ftn, methInfo);
7475             }
7476             else if (MscorlibBinder::IsClass(pMT, CLASS__UNSAFE))
7477             {
7478                 fILIntrinsic = getILIntrinsicImplementationForUnsafe(ftn, methInfo);
7479             }
7480             else if (MscorlibBinder::IsClass(pMT, CLASS__INTERLOCKED))
7481             {
7482                 fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo);
7483             }
7484             else if (MscorlibBinder::IsClass(pMT, CLASS__VOLATILE))
7485             {
7486                 fILIntrinsic = getILIntrinsicImplementationForVolatile(ftn, methInfo);
7487             }
7488             else if (MscorlibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS))
7489             {
7490                 fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo);
7491             }
7492         }
7493
7494         if (!fILIntrinsic)
7495         {
7496             getMethodInfoILMethodHeaderHelper(header, methInfo);
7497             pLocalSig = header->LocalVarSig;
7498             cbLocalSig = header->cbLocalVarSig;
7499         }
7500     }
7501     else
7502     {
7503         _ASSERTE(ftn->IsDynamicMethod());
7504
7505         DynamicResolver * pResolver = ftn->AsDynamicMethodDesc()->GetResolver();        
7506         unsigned int EHCount;
7507         methInfo->ILCode = pResolver->GetCodeInfo(&methInfo->ILCodeSize,
7508                                                   &methInfo->maxStack,
7509                                                   &methInfo->options,
7510                                                   &EHCount);
7511         methInfo->EHcount = (unsigned short)EHCount;
7512         SigPointer localSig = pResolver->GetLocalSig();
7513         localSig.GetSignature(&pLocalSig, &cbLocalSig);
7514     }
7515
7516     methInfo->options = (CorInfoOptions)(((UINT32)methInfo->options) | 
7517                             ((ftn->AcquiresInstMethodTableFromThis() ? CORINFO_GENERICS_CTXT_FROM_THIS : 0) |
7518                              (ftn->RequiresInstMethodTableArg() ? CORINFO_GENERICS_CTXT_FROM_METHODTABLE : 0) |
7519                              (ftn->RequiresInstMethodDescArg() ? CORINFO_GENERICS_CTXT_FROM_METHODDESC : 0)));
7520
7521     // EEJitManager::ResolveEHClause and CrawlFrame::GetExactGenericInstantiations
7522     // need to be able to get to CORINFO_GENERICS_CTXT_MASK if there are any
7523     // catch clauses like "try {} catch(MyException<T> e) {}".
7524     // Such constructs are rare, and having to extend the lifetime of variable
7525     // for such cases is reasonable
7526
7527     if (methInfo->options & CORINFO_GENERICS_CTXT_MASK)
7528     {
7529 #if defined(PROFILING_SUPPORTED)
7530         BOOL fProfilerRequiresGenericsContextForEnterLeave = FALSE;
7531         {
7532             BEGIN_PIN_PROFILER(CORProfilerPresent());
7533             if (g_profControlBlock.pProfInterface->RequiresGenericsContextForEnterLeave())
7534             {
7535                 fProfilerRequiresGenericsContextForEnterLeave = TRUE;
7536             }
7537             END_PIN_PROFILER();
7538         }
7539         if (fProfilerRequiresGenericsContextForEnterLeave)
7540         {
7541             methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7542         }
7543         else
7544 #endif // defined(PROFILING_SUPPORTED)
7545         {
7546             // Check all the exception clauses
7547
7548             if (ftn->IsDynamicMethod())
7549             {
7550                 // @TODO: how do we detect the need to mark this flag?
7551             }
7552             else
7553             {
7554                 COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
7555
7556                 for (unsigned i = 0; i < methInfo->EHcount; i++)
7557                 {
7558                     const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo =
7559                             (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)header->EH->EHClause(i, &ehClause);
7560
7561                     // Is it a typed catch clause?
7562                     if (ehInfo->GetFlags() != COR_ILEXCEPTION_CLAUSE_NONE)
7563                         continue;
7564
7565                     // Check if we catch "C<T>" ?
7566
7567                     DWORD catchTypeToken = ehInfo->GetClassToken();
7568                     if (TypeFromToken(catchTypeToken) != mdtTypeSpec)
7569                         continue;
7570
7571                     PCCOR_SIGNATURE pSig;
7572                     ULONG cSig;
7573                     IfFailThrow(ftn->GetMDImport()->GetTypeSpecFromToken(catchTypeToken, &pSig, &cSig));
7574                     
7575                     SigPointer psig(pSig, cSig);
7576
7577                     SigTypeContext sigTypeContext(ftn);
7578                     if (psig.IsPolyType(&sigTypeContext) & hasSharableVarsMask)
7579                     {
7580                         methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7581                         break;
7582                     }
7583                 }
7584             }
7585         }
7586     }
7587
7588     PCCOR_SIGNATURE pSig = NULL;
7589     DWORD           cbSig = 0;
7590     ftn->GetSig(&pSig, &cbSig);
7591     
7592     /* Fetch the method signature */
7593     // Type parameters in the signature should be instantiated according to the
7594     // class/method/array instantiation of ftnHnd
7595     CEEInfo::ConvToJitSig(
7596         pSig, 
7597         cbSig, 
7598         GetScopeHandle(ftn), 
7599         mdTokenNil, 
7600         &methInfo->args, 
7601         ftn, 
7602         false);
7603
7604     // Shared generic or static per-inst methods and shared methods on generic structs
7605     // take an extra argument representing their instantiation
7606     if (ftn->RequiresInstArg())
7607         methInfo->args.callConv = (CorInfoCallConv)(methInfo->args.callConv | CORINFO_CALLCONV_PARAMTYPE);
7608
7609     _ASSERTE((IsMdStatic(ftn->GetAttrs()) == 0) == ((methInfo->args.callConv & CORINFO_CALLCONV_HASTHIS) != 0));
7610
7611     /* And its local variables */
7612     // Type parameters in the signature should be instantiated according to the
7613     // class/method/array instantiation of ftnHnd
7614     CEEInfo::ConvToJitSig(
7615         pLocalSig, 
7616         cbLocalSig, 
7617         GetScopeHandle(ftn), 
7618         mdTokenNil, 
7619         &methInfo->locals, 
7620         ftn, 
7621         true);
7622 } // getMethodInfoHelper
7623
7624 //---------------------------------------------------------------------------------------
7625 // 
7626 bool 
7627 CEEInfo::getMethodInfo(
7628     CORINFO_METHOD_HANDLE ftnHnd, 
7629     CORINFO_METHOD_INFO * methInfo)
7630 {
7631     CONTRACTL {
7632         SO_TOLERANT;
7633         THROWS;
7634         GC_TRIGGERS;
7635         MODE_PREEMPTIVE;
7636     } CONTRACTL_END;
7637
7638     bool result = false;
7639
7640     JIT_TO_EE_TRANSITION();
7641
7642     MethodDesc * ftn = GetMethod(ftnHnd);
7643
7644     if (!ftn->IsDynamicMethod() && (!ftn->IsIL() || !ftn->GetRVA() || ftn->IsWrapperStub()))
7645     {
7646     /* Return false if not IL or has no code */
7647         result = false;
7648     }
7649     else
7650     {
7651         /* Get the IL header */
7652
7653         if (ftn->IsDynamicMethod())
7654         {
7655             getMethodInfoHelper(ftn, ftnHnd, NULL, methInfo);
7656         }
7657         else
7658         {
7659             COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
7660
7661             getMethodInfoHelper(ftn, ftnHnd, &header, methInfo);
7662         }
7663
7664         LOG((LF_JIT, LL_INFO100000, "Getting method info (possible inline) %s::%s%s\n",
7665             ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
7666
7667         result = true;
7668     }
7669
7670     EE_TO_JIT_TRANSITION();
7671
7672     return result;
7673 }
7674
7675 #ifdef _DEBUG
7676
7677 /************************************************************************
7678     Return true when ftn contains a local of type CLASS__STACKCRAWMARK
7679 */
7680
7681 bool containsStackCrawlMarkLocal(MethodDesc* ftn)
7682 {
7683     STANDARD_VM_CONTRACT;
7684     
7685     COR_ILMETHOD* ilHeader = ftn->GetILHeader();
7686     _ASSERTE(ilHeader);
7687
7688     COR_ILMETHOD_DECODER header(ilHeader, ftn->GetMDImport(), NULL);
7689
7690     if (header.LocalVarSig == NULL)
7691         return NULL;
7692
7693     SigPointer ptr(header.LocalVarSig, header.cbLocalVarSig);
7694
7695     IfFailThrow(ptr.GetData(NULL)); // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
7696
7697     ULONG numLocals;
7698     IfFailThrow(ptr.GetData(&numLocals));
7699
7700     for(ULONG i = 0; i < numLocals; i++)
7701     {
7702         CorElementType eType;
7703         IfFailThrow(ptr.PeekElemType(&eType));
7704         if (eType != ELEMENT_TYPE_VALUETYPE)
7705         {
7706             IfFailThrow(ptr.SkipExactlyOne());
7707             continue;
7708         }
7709
7710         IfFailThrow(ptr.GetElemType(NULL));
7711
7712         mdToken token;
7713         IfFailThrow(ptr.GetToken(&token));
7714
7715         // We are inside mscorlib - simple token match is sufficient
7716         if (token == MscorlibBinder::GetClass(CLASS__STACKCRAWMARK)->GetCl())
7717             return TRUE;
7718     }
7719
7720     return FALSE;
7721 }
7722
7723 #endif
7724
7725 /*************************************************************
7726  * Check if the caller and calle are in the same assembly
7727  * i.e. do not inline across assemblies
7728  *************************************************************/
7729
7730 CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller,
7731                                   CORINFO_METHOD_HANDLE hCallee,
7732                                   DWORD*                pRestrictions)
7733 {
7734     CONTRACTL {
7735         SO_TOLERANT;
7736         THROWS;
7737         GC_TRIGGERS;
7738         MODE_PREEMPTIVE;
7739     } CONTRACTL_END;
7740
7741     CorInfoInline result = INLINE_PASS;  // By default we pass.  
7742                                          // Do not set pass in the rest of the method.
7743     DWORD         dwRestrictions = 0;    // By default, no restrictions
7744     const char *  szFailReason = NULL;   // for reportInlineDecision
7745
7746     JIT_TO_EE_TRANSITION();
7747
7748     // This does not work in the multi-threaded case
7749 #if 0
7750     // Caller should check this condition first
7751     _ASSERTE(!(CORINFO_FLG_DONT_INLINE & getMethodAttribsInternal(hCallee)));
7752 #endif
7753
7754     MethodDesc* pCaller = GetMethod(hCaller);
7755     MethodDesc* pCallee = GetMethod(hCallee);
7756
7757     if (pCallee->IsNoMetadata())
7758     {
7759         result = INLINE_FAIL;
7760         szFailReason = "Inlinee is NoMetadata";
7761         goto exit;
7762     }
7763
7764 #ifdef DEBUGGING_SUPPORTED
7765
7766     // If the callee wants debuggable code, don't allow it to be inlined
7767
7768     {
7769         // Combining the next two lines, and eliminating jitDebuggerFlags, leads to bad codegen in x86 Release builds using Visual C++ 19.00.24215.1.
7770         CORJIT_FLAGS jitDebuggerFlags = GetDebuggerCompileFlags(pCallee->GetModule(), CORJIT_FLAGS());
7771         if (jitDebuggerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE))
7772         {
7773             result = INLINE_NEVER;
7774             szFailReason = "Inlinee is debuggable";
7775             goto exit;
7776         }
7777     }
7778 #endif
7779
7780     // The orginal caller is the current method
7781     MethodDesc *  pOrigCaller;
7782     pOrigCaller = m_pMethodBeingCompiled;
7783     Module *      pOrigCallerModule;
7784     pOrigCallerModule = pOrigCaller->GetLoaderModule();
7785
7786     if (pCallee->IsNotInline()) 
7787     {
7788         result = INLINE_NEVER;
7789         szFailReason = "Inlinee is marked as no inline";
7790         goto exit;
7791     }
7792
7793     // Also check to see if the method requires a security object.  This means they call demand and
7794     // shouldn't be inlined.
7795     if (IsMdRequireSecObject(pCallee->GetAttrs())) 
7796     {
7797         result = INLINE_NEVER;
7798         szFailReason = "Inlinee requires a security object (or contains StackCrawlMark)";
7799         goto exit;
7800     }
7801
7802     // If the method is MethodImpl'd by another method within the same type, then we have
7803     // an issue that the importer will import the wrong body. In this case, we'll just
7804     // disallow inlining because getFunctionEntryPoint will do the right thing.
7805     {
7806         MethodDesc  *pMDDecl = pCallee;
7807         MethodTable *pMT     = pMDDecl->GetMethodTable();
7808         MethodDesc  *pMDImpl = pMT->MapMethodDeclToMethodImpl(pMDDecl);
7809
7810         if (pMDDecl != pMDImpl)
7811         {
7812             result = INLINE_NEVER;
7813             szFailReason = "Inlinee is MethodImpl'd by another method within the same type";
7814             goto exit;
7815         }
7816     }
7817
7818     //
7819     // Perform the Cross-Assembly inlining checks
7820     // 
7821     {
7822         Module *    pCalleeModule   = pCallee->GetModule();
7823
7824 #ifdef FEATURE_PREJIT
7825         Assembly *  pCalleeAssembly = pCalleeModule->GetAssembly();
7826
7827 #ifdef _DEBUG
7828         //
7829         // Make sure that all methods with StackCrawlMark are marked as IsMdRequireSecObject
7830         //
7831         if (pCalleeAssembly->IsSystem())
7832         {
7833             _ASSERTE(!containsStackCrawlMarkLocal(pCallee));
7834         }
7835 #endif
7836
7837         // To allow for servicing of Ngen images we want to disable most 
7838         // Cross-Assembly inlining except for the cases that we explicitly allow.
7839         // 
7840         if (IsCompilingForNGen())
7841         {
7842             // This is an canInline call at Ngen time 
7843             //
7844             //
7845             Assembly *  pOrigCallerAssembly = pOrigCallerModule->GetAssembly();
7846
7847             if (pCalleeAssembly == pOrigCallerAssembly)
7848             {
7849                 // Within the same assembly
7850                 // we can freely inline with no restrictions
7851             }
7852             else
7853             {
7854 #ifdef FEATURE_READYTORUN_COMPILER
7855                 // No inlinining for version resilient code except if in the same version bubble
7856                 // If this condition changes, please make the corresponding change
7857                 // in getCallInfo, too.
7858                 if (IsReadyToRunCompilation() &&
7859                     !isVerifyOnly() &&
7860                     !IsInSameVersionBubble(pCaller, pCallee)
7861                    )
7862                 {
7863                     result = INLINE_NEVER;
7864                     szFailReason = "Cross-module inlining in version resilient code";
7865                     goto exit;
7866                 }
7867 #endif
7868             }
7869         }
7870 #endif  // FEATURE_PREJIT
7871
7872         // TODO: We can probably be smarter here if the caller is jitted, as we will
7873         // know for sure if the inlinee has really no string interning active (currently
7874         // it's only on in the ngen case (besides requiring the attribute)), but this is getting
7875         // too subtle. Will only do if somebody screams about it, as bugs here are going to
7876         // be tough to find
7877         if ((pOrigCallerModule != pCalleeModule) &&  pCalleeModule->IsNoStringInterning())
7878         {
7879             dwRestrictions |= INLINE_NO_CALLEE_LDSTR;
7880         }
7881     }
7882
7883 #ifdef PROFILING_SUPPORTED
7884     if (CORProfilerPresent())
7885     {
7886         // #rejit
7887         // 
7888         // Currently the rejit path is the only path which sets this.
7889         // If we get more reasons to set this then we may need to change
7890         // the failure reason message or disambiguate them.
7891         if (!m_allowInlining)
7892         {
7893             result = INLINE_FAIL;
7894             szFailReason = "ReJIT request disabled inlining from caller";
7895             goto exit;
7896         }
7897
7898         // If the profiler has set a mask preventing inlining, always return
7899         // false to the jit.
7900         if (CORProfilerDisableInlining())
7901         {
7902             result = INLINE_FAIL;
7903             szFailReason = "Profiler disabled inlining globally";
7904             goto exit;
7905         }
7906
7907         // If the profiler wishes to be notified of JIT events and the result from
7908         // the above tests will cause a function to be inlined, we need to tell the
7909         // profiler that this inlining is going to take place, and give them a
7910         // chance to prevent it.
7911         {
7912             BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo());
7913             if (pCaller->IsILStub() || pCallee->IsILStub())
7914             {
7915                 // do nothing
7916             }
7917             else
7918             {
7919                 BOOL fShouldInline;
7920
7921                 HRESULT hr = g_profControlBlock.pProfInterface->JITInlining(
7922                     (FunctionID)pCaller,
7923                     (FunctionID)pCallee,
7924                     &fShouldInline);
7925
7926                 if (SUCCEEDED(hr) && !fShouldInline)
7927                 {
7928                     result = INLINE_FAIL;
7929                     szFailReason = "Profiler disabled inlining locally";
7930                     goto exit;
7931                 }
7932             }
7933             END_PIN_PROFILER();
7934         }
7935     }
7936 #endif // PROFILING_SUPPORTED
7937
7938 exit: ;
7939
7940     EE_TO_JIT_TRANSITION();
7941
7942     if (result == INLINE_PASS && dwRestrictions)
7943     {
7944         if (pRestrictions)
7945         {
7946             *pRestrictions = dwRestrictions;
7947         }
7948         else
7949         {
7950             // If the jitter didn't want to know about restrictions, it shouldn't be inlining
7951             result = INLINE_FAIL;
7952             szFailReason = "Inlinee has restrictions the JIT doesn't want";
7953         }
7954     }
7955     else
7956     {
7957         if (pRestrictions)
7958         {
7959             // Denied inlining, makes no sense to pass out restrictions,
7960             *pRestrictions = 0;
7961         }
7962     }
7963
7964     if (dontInline(result))
7965     {
7966         // If you hit this assert, it means you added a new way to prevent inlining
7967         // without documenting it for ETW!
7968         _ASSERTE(szFailReason != NULL);
7969         reportInliningDecision(hCaller, hCallee, result, szFailReason);
7970     }
7971
7972     return result;
7973 }
7974
7975 void CEEInfo::reportInliningDecision (CORINFO_METHOD_HANDLE inlinerHnd,
7976                                       CORINFO_METHOD_HANDLE inlineeHnd,
7977                                       CorInfoInline inlineResult,
7978                                       const char * reason)
7979 {
7980     STATIC_CONTRACT_THROWS;
7981     STATIC_CONTRACT_GC_TRIGGERS;
7982     STATIC_CONTRACT_SO_TOLERANT;
7983
7984     JIT_TO_EE_TRANSITION();
7985
7986 #ifdef _DEBUG
7987     if (LoggingOn(LF_JIT, LL_INFO100000))
7988     {
7989         SString currentMethodName;
7990         currentMethodName.AppendUTF8(m_pMethodBeingCompiled->GetModule_NoLogging()->GetFile()->GetSimpleName());
7991         currentMethodName.Append(L'/');
7992         TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled, TypeString::FormatBasic);
7993
7994         SString inlineeMethodName;
7995         if (GetMethod(inlineeHnd))
7996         {
7997             inlineeMethodName.AppendUTF8(GetMethod(inlineeHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
7998             inlineeMethodName.Append(L'/');
7999             TypeString::AppendMethodInternal(inlineeMethodName, GetMethod(inlineeHnd), TypeString::FormatBasic);
8000         }
8001         else
8002         {
8003             inlineeMethodName.AppendASCII( "<null>" );
8004         }
8005
8006         SString inlinerMethodName;
8007         if (GetMethod(inlinerHnd))
8008         {
8009             inlinerMethodName.AppendUTF8(GetMethod(inlinerHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
8010             inlinerMethodName.Append(L'/');
8011             TypeString::AppendMethodInternal(inlinerMethodName, GetMethod(inlinerHnd), TypeString::FormatBasic);
8012         }
8013         else
8014         {
8015             inlinerMethodName.AppendASCII("<null>");
8016         }
8017
8018         if (dontInline(inlineResult))
8019         {
8020             LOG((LF_JIT, LL_INFO100000,
8021                  "While compiling '%S', inline of '%S' into '%S' failed because: '%s'.\n",
8022                  currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
8023                  inlinerMethodName.GetUnicode(), reason));
8024         }
8025         else
8026         {
8027             LOG((LF_JIT, LL_INFO100000, "While compiling '%S', inline of '%S' into '%S' succeeded.\n",
8028                  currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
8029                  inlinerMethodName.GetUnicode()));
8030
8031         }
8032     }
8033 #endif //_DEBUG
8034
8035     //I'm gonna duplicate this code because the format is slightly different.  And LoggingOn is debug only.
8036     if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
8037                                      TRACE_LEVEL_VERBOSE,
8038                                      CLR_JITTRACING_KEYWORD))
8039     {
8040         SString methodBeingCompiledNames[3];
8041         SString inlinerNames[3];
8042         SString inlineeNames[3];
8043         MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8044 #define GMI(pMD, strArray) \
8045         do { \
8046             if (pMD) { \
8047                 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8048             } else {  \
8049                 (strArray)[0].Set(W("<null>")); \
8050                 (strArray)[1].Set(W("<null>")); \
8051                 (strArray)[2].Set(W("<null>")); \
8052             } } while (0)
8053
8054         GMI(methodBeingCompiled, methodBeingCompiledNames);
8055         GMI(GetMethod(inlinerHnd), inlinerNames);
8056         GMI(GetMethod(inlineeHnd), inlineeNames);
8057 #undef GMI
8058         if (dontInline(inlineResult))
8059         {
8060             const char * str = (reason ? reason : "");
8061             SString strReason;
8062             strReason.SetANSI(str);
8063
8064
8065             FireEtwMethodJitInliningFailed(methodBeingCompiledNames[0].GetUnicode(),
8066                                            methodBeingCompiledNames[1].GetUnicode(),
8067                                            methodBeingCompiledNames[2].GetUnicode(),
8068                                            inlinerNames[0].GetUnicode(),
8069                                            inlinerNames[1].GetUnicode(),
8070                                            inlinerNames[2].GetUnicode(),
8071                                            inlineeNames[0].GetUnicode(),
8072                                            inlineeNames[1].GetUnicode(),
8073                                            inlineeNames[2].GetUnicode(),
8074                                            inlineResult == INLINE_NEVER,
8075                                            strReason.GetUnicode(),
8076                                            GetClrInstanceId());
8077         }
8078         else
8079         {
8080             FireEtwMethodJitInliningSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8081                                               methodBeingCompiledNames[1].GetUnicode(),
8082                                               methodBeingCompiledNames[2].GetUnicode(),
8083                                               inlinerNames[0].GetUnicode(),
8084                                               inlinerNames[1].GetUnicode(),
8085                                               inlinerNames[2].GetUnicode(),
8086                                               inlineeNames[0].GetUnicode(),
8087                                               inlineeNames[1].GetUnicode(),
8088                                               inlineeNames[2].GetUnicode(),
8089                                               GetClrInstanceId());
8090         }
8091
8092     }
8093
8094     EE_TO_JIT_TRANSITION();
8095 }
8096
8097
8098 /*************************************************************
8099 This loads the (formal) declared constraints on the class and method type parameters, 
8100 and detects (but does not itself reject) circularities among the class type parameters 
8101 and (separately) method type parameters. 
8102
8103 It must be called whenever we verify a typical method, ie any method (generic or
8104 nongeneric) in a typical class. It must be called for non-generic methods too, 
8105 because their bodies may still mention class type parameters which will need to
8106 have their formal constraints loaded in order to perform type compatibility tests.
8107
8108 We have to rule out cycles like "C<U,T> where T:U, U:T" only to avoid looping 
8109 in the verifier (ie the T.CanCast(A) would loop calling U.CanCast(A) then 
8110 T.CanCastTo(A) etc.). Since the JIT only tries to walk the hierarchy from a type
8111 a parameter when verifying, it should be safe to JIT unverified, but trusted, 
8112 instantiations even in the presence of cycle constraints.
8113 @TODO: It should be possible (and easy) to detect cycles much earlier on by
8114 directly inspecting the metadata. All you have to do is check that, for each
8115 of the n type parameters to a class or method there is no path of length n 
8116 obtained by following naked type parameter constraints of the same kind. 
8117 This can be detected by looking directly at metadata, without actually loading
8118 the typehandles for the naked type parameters.
8119  *************************************************************/
8120
8121 void CEEInfo::initConstraintsForVerification(CORINFO_METHOD_HANDLE hMethod,
8122                                              BOOL *pfHasCircularClassConstraints,
8123                                              BOOL *pfHasCircularMethodConstraints)
8124 {
8125     CONTRACTL {
8126         SO_TOLERANT;
8127         THROWS;
8128         GC_TRIGGERS;
8129         MODE_PREEMPTIVE;
8130         PRECONDITION(CheckPointer(pfHasCircularClassConstraints));
8131         PRECONDITION(CheckPointer(pfHasCircularMethodConstraints));
8132     } CONTRACTL_END;
8133
8134     *pfHasCircularClassConstraints  = FALSE;
8135     *pfHasCircularMethodConstraints = FALSE;
8136
8137     JIT_TO_EE_TRANSITION();
8138
8139     MethodDesc* pMethod = GetMethod(hMethod);
8140     if (pMethod->IsTypicalMethodDefinition())
8141     {
8142         // Force a load of the constraints on the type parameters, detecting cyclic bounds
8143         pMethod->LoadConstraintsForTypicalMethodDefinition(pfHasCircularClassConstraints,pfHasCircularMethodConstraints);
8144     }
8145
8146     EE_TO_JIT_TRANSITION();
8147 }
8148
8149 /*************************************************************
8150  * Check if a method to be compiled is an instantiation
8151  * of generic code that has already been verified.
8152  * Three possible return values (see corinfo.h)
8153  *************************************************************/
8154
8155 CorInfoInstantiationVerification  
8156     CEEInfo::isInstantiationOfVerifiedGeneric(CORINFO_METHOD_HANDLE hMethod)
8157 {
8158     CONTRACTL {
8159         SO_TOLERANT;
8160         THROWS;
8161         GC_TRIGGERS;
8162         MODE_PREEMPTIVE;
8163     } CONTRACTL_END;
8164
8165     CorInfoInstantiationVerification result = INSTVER_NOT_INSTANTIATION;
8166
8167     JIT_TO_EE_TRANSITION();
8168
8169     MethodDesc * pMethod = GetMethod(hMethod);
8170
8171     if (!(pMethod->HasClassOrMethodInstantiation()))
8172     {
8173         result = INSTVER_NOT_INSTANTIATION;
8174         goto exit;
8175     }
8176
8177     if (pMethod->IsTypicalMethodDefinition())
8178     {
8179         result = INSTVER_NOT_INSTANTIATION;
8180         goto exit;
8181     }
8182
8183     result = INSTVER_GENERIC_PASSED_VERIFICATION;
8184
8185  exit: ;
8186
8187     EE_TO_JIT_TRANSITION();
8188
8189     return result;
8190 }
8191
8192 /*************************************************************
8193  * Similar to above, but perform check for tail call
8194  * eligibility. The callee can be passed as NULL if not known
8195  * (calli and callvirt).
8196  *************************************************************/
8197
8198 bool CEEInfo::canTailCall (CORINFO_METHOD_HANDLE hCaller,
8199                            CORINFO_METHOD_HANDLE hDeclaredCallee,
8200                            CORINFO_METHOD_HANDLE hExactCallee,
8201                            bool fIsTailPrefix)
8202 {
8203     CONTRACTL {
8204         SO_TOLERANT;
8205         THROWS;
8206         GC_TRIGGERS;
8207         MODE_PREEMPTIVE;
8208     } CONTRACTL_END;
8209
8210     bool result = false;
8211     const char * szFailReason = NULL;
8212
8213     JIT_TO_EE_TRANSITION();
8214
8215     // See comments in canInline above.
8216
8217     MethodDesc* pCaller = GetMethod(hCaller);
8218     MethodDesc* pDeclaredCallee = GetMethod(hDeclaredCallee);
8219     MethodDesc* pExactCallee = GetMethod(hExactCallee);
8220
8221     _ASSERTE(pCaller->GetModule());
8222     _ASSERTE(pCaller->GetModule()->GetClassLoader());
8223
8224     _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule());
8225     _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule()->GetClassLoader());
8226
8227     // If the caller is the static constructor (.cctor) of a class which has a ComImport base class
8228     // somewhere up the class hierarchy, then we cannot make the call into a tailcall.  See
8229     // RegisterObjectCreationCallback() in ExtensibleClassFactory.cpp for more information.
8230     if (pCaller->IsClassConstructor() &&
8231         pCaller->GetMethodTable()->IsComObjectType())
8232     {
8233         result = false;
8234         szFailReason = "Caller is  ComImport .cctor";
8235         goto exit;
8236     }
8237
8238     if (!fIsTailPrefix)        
8239     {
8240         mdMethodDef callerToken = pCaller->GetMemberDef();
8241
8242         // We don't want to tailcall the entrypoint for an application; JIT64 will sometimes
8243         // do this for simple entrypoints and it results in a rather confusing debugging 
8244         // experience.
8245         if (callerToken == pCaller->GetModule()->GetEntryPointToken())
8246         {
8247             result = false;
8248             szFailReason = "Caller is the entry point";
8249             goto exit;
8250         }
8251
8252         if (!pCaller->IsNoMetadata())
8253         {
8254             // Do not tailcall from methods that are marked as noinline (people often use no-inline
8255             // to mean "I want to always see this method in stacktrace")
8256             DWORD dwImplFlags = 0;
8257             IfFailThrow(pCaller->GetMDImport()->GetMethodImplProps(callerToken, NULL, &dwImplFlags));
8258             
8259             if (IsMiNoInlining(dwImplFlags))
8260             {
8261                 result = false;
8262                 szFailReason = "Caller is marked as no inline";
8263                 goto exit;
8264             }
8265         }
8266
8267         // Methods with StackCrawlMark depend on finding their caller on the stack.
8268         // If we tail call one of these guys, they get confused.  For lack of
8269         // a better way of identifying them, we use DynamicSecurity attribute to identify
8270         // them. We have an assert in canInline that ensures all StackCrawlMark
8271         // methods are appropriately marked.
8272         //
8273         if ((pExactCallee != NULL) && IsMdRequireSecObject(pExactCallee->GetAttrs()))
8274         {
8275             result = false;
8276             szFailReason = "Callee might have a StackCrawlMark.LookForMyCaller";
8277             goto exit;
8278         }
8279     }
8280
8281
8282     result = true;
8283
8284 exit: ;
8285
8286     EE_TO_JIT_TRANSITION();
8287
8288     if (!result)
8289     {
8290         // If you hit this assert, it means you added a new way to prevent tail calls
8291         // without documenting it for ETW!
8292         _ASSERTE(szFailReason != NULL);
8293         reportTailCallDecision(hCaller, hExactCallee, fIsTailPrefix, TAILCALL_FAIL, szFailReason);
8294     }
8295
8296     return result;
8297 }
8298
8299 void CEEInfo::reportTailCallDecision (CORINFO_METHOD_HANDLE callerHnd,
8300                                      CORINFO_METHOD_HANDLE calleeHnd,
8301                                      bool fIsTailPrefix,
8302                                      CorInfoTailCall tailCallResult,
8303                                      const char * reason)
8304 {
8305     STATIC_CONTRACT_THROWS;
8306     STATIC_CONTRACT_GC_TRIGGERS;
8307     STATIC_CONTRACT_SO_TOLERANT;
8308
8309     JIT_TO_EE_TRANSITION();
8310
8311     //put code here.  Make sure to report the method being compiled in addition to inliner and inlinee.
8312 #ifdef _DEBUG
8313     if (LoggingOn(LF_JIT, LL_INFO100000))
8314     {
8315         SString currentMethodName;
8316         TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled,
8317                                          TypeString::FormatBasic);
8318
8319         SString calleeMethodName;
8320         if (GetMethod(calleeHnd))
8321         {
8322             TypeString::AppendMethodInternal(calleeMethodName, GetMethod(calleeHnd),
8323                                              TypeString::FormatBasic);
8324         }
8325         else
8326         {
8327             calleeMethodName.AppendASCII( "<null>" );
8328         }
8329
8330         SString callerMethodName;
8331         if (GetMethod(callerHnd))
8332         {
8333             TypeString::AppendMethodInternal(callerMethodName, GetMethod(callerHnd),
8334                                              TypeString::FormatBasic);
8335         }
8336         else
8337         {
8338             callerMethodName.AppendASCII( "<null>" );
8339         }
8340         if (tailCallResult == TAILCALL_FAIL)
8341         {
8342             LOG((LF_JIT, LL_INFO100000,
8343                  "While compiling '%S', %Splicit tail call from '%S' to '%S' failed because: '%s'.\n",
8344                  currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8345                  callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), reason));
8346         }
8347         else
8348         {
8349             static const char * const tailCallType[] = {
8350                 "optimized tail call", "recursive loop", "helper assisted tailcall"
8351             };
8352             _ASSERTE(tailCallResult >= 0 && (size_t)tailCallResult < _countof(tailCallType));
8353             LOG((LF_JIT, LL_INFO100000,
8354                  "While compiling '%S', %Splicit tail call from '%S' to '%S' generated as a %s.\n",
8355                  currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8356                  callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), tailCallType[tailCallResult]));
8357
8358         }
8359     }
8360 #endif //_DEBUG
8361
8362     // I'm gonna duplicate this code because the format is slightly different.  And LoggingOn is debug only.
8363     if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
8364                                      TRACE_LEVEL_VERBOSE,
8365                                      CLR_JITTRACING_KEYWORD))
8366     {
8367         SString methodBeingCompiledNames[3];
8368         SString callerNames[3];
8369         SString calleeNames[3];
8370         MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8371 #define GMI(pMD, strArray) \
8372         do { \
8373             if (pMD) { \
8374                 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8375             } else {  \
8376                 (strArray)[0].Set(W("<null>")); \
8377                 (strArray)[1].Set(W("<null>")); \
8378                 (strArray)[2].Set(W("<null>")); \
8379             } } while (0)
8380
8381         GMI(methodBeingCompiled, methodBeingCompiledNames);
8382         GMI(GetMethod(callerHnd), callerNames);
8383         GMI(GetMethod(calleeHnd), calleeNames);
8384 #undef GMI
8385         if (tailCallResult == TAILCALL_FAIL)
8386         {
8387             const char * str = (reason ? reason : "");
8388             SString strReason;
8389             strReason.SetANSI(str);
8390
8391             FireEtwMethodJitTailCallFailed(methodBeingCompiledNames[0].GetUnicode(),
8392                                            methodBeingCompiledNames[1].GetUnicode(),
8393                                            methodBeingCompiledNames[2].GetUnicode(),
8394                                            callerNames[0].GetUnicode(),
8395                                            callerNames[1].GetUnicode(),
8396                                            callerNames[2].GetUnicode(),
8397                                            calleeNames[0].GetUnicode(),
8398                                            calleeNames[1].GetUnicode(),
8399                                            calleeNames[2].GetUnicode(),
8400                                            fIsTailPrefix,
8401                                            strReason.GetUnicode(),
8402                                            GetClrInstanceId());
8403         }
8404         else
8405         {
8406             FireEtwMethodJitTailCallSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8407                                               methodBeingCompiledNames[1].GetUnicode(),
8408                                               methodBeingCompiledNames[2].GetUnicode(),
8409                                               callerNames[0].GetUnicode(),
8410                                               callerNames[1].GetUnicode(),
8411                                               callerNames[2].GetUnicode(),
8412                                               calleeNames[0].GetUnicode(),
8413                                               calleeNames[1].GetUnicode(),
8414                                               calleeNames[2].GetUnicode(),
8415                                               fIsTailPrefix,
8416                                               tailCallResult,
8417                                               GetClrInstanceId());
8418         }
8419
8420     }
8421
8422
8423     EE_TO_JIT_TRANSITION();
8424 }
8425
8426 void CEEInfo::getEHinfoHelper(
8427     CORINFO_METHOD_HANDLE   ftnHnd,
8428     unsigned                EHnumber,
8429     CORINFO_EH_CLAUSE*      clause,
8430     COR_ILMETHOD_DECODER*   pILHeader)
8431 {
8432     STANDARD_VM_CONTRACT;
8433
8434     _ASSERTE(CheckPointer(pILHeader->EH));
8435     _ASSERTE(EHnumber < pILHeader->EH->EHCount());
8436
8437     COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
8438     const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo;
8439     ehInfo = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)pILHeader->EH->EHClause(EHnumber, &ehClause);
8440
8441     clause->Flags = (CORINFO_EH_CLAUSE_FLAGS)ehInfo->GetFlags();
8442     clause->TryOffset = ehInfo->GetTryOffset();
8443     clause->TryLength = ehInfo->GetTryLength();
8444     clause->HandlerOffset = ehInfo->GetHandlerOffset();
8445     clause->HandlerLength = ehInfo->GetHandlerLength();
8446     if ((clause->Flags & CORINFO_EH_CLAUSE_FILTER) == 0)
8447         clause->ClassToken = ehInfo->GetClassToken();
8448     else
8449         clause->FilterOffset = ehInfo->GetFilterOffset();
8450 }
8451
8452 /*********************************************************************/
8453 // get individual exception handler
8454 void CEEInfo::getEHinfo(
8455             CORINFO_METHOD_HANDLE ftnHnd,
8456             unsigned      EHnumber,
8457             CORINFO_EH_CLAUSE* clause)
8458 {
8459     CONTRACTL {
8460         SO_TOLERANT;
8461         THROWS;
8462         GC_TRIGGERS;
8463         MODE_PREEMPTIVE;
8464     } CONTRACTL_END;
8465
8466     JIT_TO_EE_TRANSITION();
8467
8468     MethodDesc * ftn          = GetMethod(ftnHnd);
8469
8470     if (IsDynamicMethodHandle(ftnHnd))
8471     {
8472         GetMethod(ftnHnd)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
8473     }
8474     else
8475     {
8476         COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
8477         getEHinfoHelper(ftnHnd, EHnumber, clause, &header);
8478     }
8479
8480     EE_TO_JIT_TRANSITION();
8481 }
8482
8483 //---------------------------------------------------------------------------------------
8484 // 
8485 void 
8486 CEEInfo::getMethodSig(
8487     CORINFO_METHOD_HANDLE ftnHnd, 
8488     CORINFO_SIG_INFO *    sigRet, 
8489     CORINFO_CLASS_HANDLE  owner)
8490 {
8491     CONTRACTL {
8492         SO_TOLERANT;
8493         THROWS;
8494         GC_TRIGGERS;
8495         MODE_PREEMPTIVE;
8496     } CONTRACTL_END;
8497
8498     JIT_TO_EE_TRANSITION();
8499
8500     getMethodSigInternal(ftnHnd, sigRet, owner);
8501
8502     EE_TO_JIT_TRANSITION();
8503 }
8504
8505 //---------------------------------------------------------------------------------------
8506 // 
8507 void 
8508 CEEInfo::getMethodSigInternal(
8509     CORINFO_METHOD_HANDLE ftnHnd, 
8510     CORINFO_SIG_INFO *    sigRet, 
8511     CORINFO_CLASS_HANDLE  owner,
8512     SignatureKind signatureKind)
8513 {
8514     STANDARD_VM_CONTRACT;
8515
8516     MethodDesc * ftn = GetMethod(ftnHnd);
8517     
8518     PCCOR_SIGNATURE pSig = NULL;
8519     DWORD           cbSig = 0;
8520     ftn->GetSig(&pSig, &cbSig);
8521
8522     // Type parameters in the signature are instantiated
8523     // according to the class/method/array instantiation of ftnHnd and owner
8524     CEEInfo::ConvToJitSig(
8525         pSig, 
8526         cbSig, 
8527         GetScopeHandle(ftn), 
8528         mdTokenNil, 
8529         sigRet, 
8530         ftn, 
8531         false, 
8532         (TypeHandle)owner);
8533
8534     //@GENERICS:
8535     // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation
8536     if (ftn->RequiresInstArg())
8537     {
8538         //
8539         // If we are making a virtual call to an instance method on an interface, we need to lie to the JIT.  
8540         // The reason being that we already made sure target is always directly callable (through instantiation stubs), 
8541         // JIT should not generate shared generics aware call code and insert the secret argument again at the callsite.
8542         // Otherwise we would end up with two secret generic dictionary arguments (since the stub also provides one).
8543         //
8544         BOOL isCallSiteThatGoesThroughInstantiatingStub =
8545             signatureKind == SK_VIRTUAL_CALLSITE &&
8546             !ftn->IsStatic() &&
8547             ftn->GetMethodTable()->IsInterface();
8548         if (!isCallSiteThatGoesThroughInstantiatingStub)
8549             sigRet->callConv = (CorInfoCallConv) (sigRet->callConv | CORINFO_CALLCONV_PARAMTYPE);
8550     }
8551
8552     // We want the calling convention bit to be consistant with the method attribute bit
8553     _ASSERTE( (IsMdStatic(ftn->GetAttrs()) == 0) == ((sigRet->callConv & CORINFO_CALLCONV_HASTHIS) != 0) );
8554 }
8555
8556 //---------------------------------------------------------------------------------------
8557 // 
8558 //@GENERICSVER: for a method desc in a typical instantiation of a generic class,
8559 // this will return the typical instantiation of the generic class,
8560 // but only provided type variables are never shared.
8561 // The JIT verifier relies on this behaviour to extract the typical class from an instantiated method's typical method handle.
8562 // 
8563 CORINFO_CLASS_HANDLE 
8564 CEEInfo::getMethodClass(
8565     CORINFO_METHOD_HANDLE methodHnd)
8566 {
8567     CONTRACTL {
8568         SO_TOLERANT;
8569         THROWS;
8570         GC_TRIGGERS;
8571         MODE_PREEMPTIVE;
8572     } CONTRACTL_END;
8573
8574     CORINFO_CLASS_HANDLE result = NULL;
8575
8576     JIT_TO_EE_TRANSITION();
8577
8578     MethodDesc* method = GetMethod(methodHnd);
8579
8580     if (method->IsDynamicMethod())
8581     {
8582         DynamicResolver::SecurityControlFlags securityControlFlags = DynamicResolver::Default;
8583         TypeHandle typeOwner;
8584
8585         DynamicResolver* pResolver = method->AsDynamicMethodDesc()->GetResolver();
8586         pResolver->GetJitContext(&securityControlFlags, &typeOwner);
8587             
8588         if (!typeOwner.IsNull() && (method == pResolver->GetDynamicMethod())) 
8589         {
8590             result = CORINFO_CLASS_HANDLE(typeOwner.AsPtr());
8591         }
8592     }
8593
8594     if (result == NULL)
8595     {
8596         TypeHandle th = TypeHandle(method->GetMethodTable());
8597
8598         result = CORINFO_CLASS_HANDLE(th.AsPtr());
8599     }
8600
8601     EE_TO_JIT_TRANSITION();
8602
8603     return result;
8604 }
8605
8606 /***********************************************************************/
8607 CORINFO_MODULE_HANDLE CEEInfo::getMethodModule (CORINFO_METHOD_HANDLE methodHnd)
8608 {
8609     CONTRACTL {
8610         SO_TOLERANT;
8611         NOTHROW;
8612         GC_NOTRIGGER;
8613         MODE_PREEMPTIVE;
8614     } CONTRACTL_END;
8615
8616     CORINFO_MODULE_HANDLE result = NULL;
8617
8618     JIT_TO_EE_TRANSITION_LEAF();
8619
8620     MethodDesc* method = GetMethod(methodHnd);
8621
8622     if (method->IsDynamicMethod())
8623     {
8624         // this should never be called, thus the assert, I don't know if the (non existent) caller
8625         // expects the Module or the scope
8626         UNREACHABLE();
8627     }
8628     else
8629     {
8630         result = (CORINFO_MODULE_HANDLE) method->GetModule();
8631     }
8632     
8633     EE_TO_JIT_TRANSITION_LEAF();
8634
8635     return result;
8636 }
8637
8638 /*********************************************************************/
8639 CorInfoIntrinsics CEEInfo::getIntrinsicID(CORINFO_METHOD_HANDLE methodHnd,
8640                                           bool * pMustExpand)
8641 {
8642     CONTRACTL {
8643         SO_TOLERANT;
8644         THROWS;
8645         GC_TRIGGERS;
8646         MODE_PREEMPTIVE;
8647     } CONTRACTL_END;
8648
8649     CorInfoIntrinsics result = CORINFO_INTRINSIC_Illegal;
8650
8651     JIT_TO_EE_TRANSITION();
8652
8653     if (pMustExpand != NULL)
8654     {
8655         *pMustExpand = false;
8656     }
8657
8658     MethodDesc* method = GetMethod(methodHnd);
8659
8660     if (method->IsArray())
8661     {
8662         ArrayMethodDesc * arrMethod = (ArrayMethodDesc *)method;
8663         result = arrMethod->GetIntrinsicID();
8664     }
8665     else
8666     if (method->IsFCall())
8667     {
8668         result = ECall::GetIntrinsicID(method);
8669     }
8670     else
8671     {
8672         MethodTable * pMT = method->GetMethodTable();
8673         if (pMT->GetModule()->IsSystem() && pMT->IsByRefLike())
8674         {
8675             if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
8676             {
8677                 // ByReference<T> has just two methods: constructor and Value property
8678                 if (method->IsCtor())
8679                 {
8680                     result = CORINFO_INTRINSIC_ByReference_Ctor;
8681                 }
8682                 else
8683                 {
8684                     _ASSERTE(strcmp(method->GetName(), "get_Value") == 0);
8685                     result = CORINFO_INTRINSIC_ByReference_Value;
8686                 }
8687                 if (pMustExpand != nullptr)
8688                 {
8689                     *pMustExpand = true;
8690                 }
8691             }
8692             else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__SPAN)))
8693             {
8694                 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__SPAN__GET_ITEM)))
8695                 {
8696                     result = CORINFO_INTRINSIC_Span_GetItem;
8697                 }
8698             }
8699             else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__READONLY_SPAN)))
8700             {
8701                 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__READONLY_SPAN__GET_ITEM)))
8702                 {
8703                     result = CORINFO_INTRINSIC_ReadOnlySpan_GetItem;
8704                 }
8705             }
8706         }
8707     }
8708
8709     EE_TO_JIT_TRANSITION();
8710
8711     return result;
8712 }
8713
8714 /*********************************************************************/
8715 // TODO: This method should probably be renamed to something like "isSIMDType"
8716 bool CEEInfo::isInSIMDModule(CORINFO_CLASS_HANDLE classHnd)
8717 {
8718 CONTRACTL {
8719         SO_TOLERANT;
8720         NOTHROW;
8721         GC_NOTRIGGER;
8722         MODE_PREEMPTIVE;
8723     } CONTRACTL_END;
8724
8725     bool result = false;
8726     JIT_TO_EE_TRANSITION_LEAF();
8727
8728     TypeHandle VMClsHnd(classHnd);
8729     PTR_MethodTable methodTable = VMClsHnd.GetMethodTable();
8730     if (methodTable->GetAssembly()->IsSIMDVectorAssembly())
8731     {
8732         result = true;
8733     }
8734     else if (methodTable->IsIntrinsicType())
8735     {
8736         LPCUTF8 namespaceName;
8737         LPCUTF8 className = methodTable->GetFullyQualifiedNameInfo(&namespaceName);
8738
8739         if (strcmp(className, "Vector`1") == 0 || strcmp(className, "Vector") == 0)
8740         {
8741             assert(strcmp(namespaceName, "System.Numerics") == 0);
8742
8743             result = true;
8744         }
8745     }
8746     EE_TO_JIT_TRANSITION_LEAF();
8747
8748     return result;
8749 }
8750
8751 /*********************************************************************/
8752 void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd,
8753                                      unsigned * pOffsetOfIndirection,
8754                                      unsigned * pOffsetAfterIndirection,
8755                                      bool * isRelative)
8756 {
8757     CONTRACTL {
8758         SO_TOLERANT;
8759         NOTHROW;
8760         GC_NOTRIGGER;
8761         MODE_PREEMPTIVE;
8762     } CONTRACTL_END;
8763
8764     JIT_TO_EE_TRANSITION_LEAF();
8765
8766     MethodDesc* method = GetMethod(methodHnd);
8767
8768     //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8769     _ASSERTE(!method->HasMethodInstantiation());
8770
8771     _ASSERTE(MethodTable::GetVtableOffset() < 256);  // a rough sanity check
8772
8773     // better be in the vtable
8774     _ASSERTE(method->GetSlot() < method->GetMethodTable()->GetNumVirtuals());
8775
8776     *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * TARGET_POINTER_SIZE /* sizeof(MethodTable::VTableIndir_t) */;
8777     *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * TARGET_POINTER_SIZE /* sizeof(MethodTable::VTableIndir2_t) */;
8778     *isRelative = MethodTable::VTableIndir_t::isRelative ? 1 : 0;
8779     _ASSERTE(MethodTable::VTableIndir_t::isRelative == MethodTable::VTableIndir2_t::isRelative);
8780
8781     EE_TO_JIT_TRANSITION_LEAF();
8782 }
8783
8784 /*********************************************************************/
8785 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethodHelper(CORINFO_METHOD_HANDLE baseMethod,
8786                                                           CORINFO_CLASS_HANDLE derivedClass,
8787                                                           CORINFO_CONTEXT_HANDLE ownerType)
8788 {
8789     CONTRACTL {
8790         THROWS;
8791         GC_TRIGGERS;
8792         MODE_PREEMPTIVE;
8793     } CONTRACTL_END;
8794
8795     MethodDesc* pBaseMD = GetMethod(baseMethod);
8796     MethodTable* pBaseMT = pBaseMD->GetMethodTable();
8797
8798     // Method better be from a fully loaded class
8799     _ASSERTE(pBaseMD->IsRestored() && pBaseMT->IsFullyLoaded());
8800
8801     //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8802     _ASSERTE(!pBaseMD->HasMethodInstantiation());
8803
8804     // Method better be virtual
8805     _ASSERTE(pBaseMD->IsVirtual());
8806
8807     MethodDesc* pDevirtMD = nullptr;
8808
8809     TypeHandle DerivedClsHnd(derivedClass);
8810     MethodTable* pDerivedMT = DerivedClsHnd.GetMethodTable();
8811     _ASSERTE(pDerivedMT->IsRestored() && pDerivedMT->IsFullyLoaded());
8812
8813     // Can't devirtualize from __Canon.
8814     if (DerivedClsHnd == TypeHandle(g_pCanonMethodTableClass))
8815     {
8816         return nullptr;
8817     }
8818
8819     if (pBaseMT->IsInterface())
8820     {
8821
8822 #ifdef FEATURE_COMINTEROP
8823         // Don't try and devirtualize com interface calls.
8824         if (pDerivedMT->IsComObjectType())
8825         {
8826             return nullptr;
8827         }
8828 #endif // FEATURE_COMINTEROP
8829
8830         // Interface call devirtualization.
8831         //
8832         // We must ensure that pDerivedMT actually implements the
8833         // interface corresponding to pBaseMD.
8834         if (!pDerivedMT->CanCastToInterface(pBaseMT))
8835         {
8836             return nullptr;
8837         }
8838
8839         // For generic interface methods we must have an ownerType to
8840         // safely devirtualize.
8841         if (ownerType != nullptr)
8842         {
8843             TypeHandle OwnerClsHnd = GetTypeFromContext(ownerType);
8844             MethodTable* pOwnerMT = OwnerClsHnd.GetMethodTable();
8845
8846             // If the derived class is a shared class, make sure the
8847             // owner class is too.
8848             if (pDerivedMT->IsSharedByGenericInstantiations())
8849             {
8850                 pOwnerMT = pOwnerMT->GetCanonicalMethodTable();
8851             }
8852
8853             // In a try block because the interface method resolution might end up being
8854             // ambiguous (diamond inheritance case of default interface methods).
8855             EX_TRY
8856             {
8857                 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(TypeHandle(pOwnerMT), pBaseMD);
8858             }
8859             EX_CATCH
8860             {
8861             }
8862             EX_END_CATCH(RethrowTransientExceptions)
8863         }
8864         else if (!pBaseMD->HasClassOrMethodInstantiation())
8865         {
8866             // In a try block because the interface method resolution might end up being
8867             // ambiguous (diamond inheritance case of default interface methods).
8868             EX_TRY
8869             {
8870                 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(pBaseMD);
8871             }
8872             EX_CATCH
8873             {
8874             }
8875             EX_END_CATCH(RethrowTransientExceptions)
8876         }
8877         
8878         if (pDevirtMD == nullptr)
8879         {
8880             return nullptr;
8881         }
8882
8883         // If we devirtualized into a default interface method on a generic type, we should actually return an
8884         // instantiating stub but this is not happening.
8885         // Making this work is tracked by https://github.com/dotnet/coreclr/issues/15977
8886         if (pDevirtMD->GetMethodTable()->IsInterface() && pDevirtMD->HasClassInstantiation())
8887         {
8888             return nullptr;
8889         }
8890     }
8891     else
8892     {
8893         // Virtual call devirtualization.
8894         // 
8895         // The derived class should be a subclass of the the base class.
8896         MethodTable* pCheckMT = pDerivedMT;
8897         
8898         while (pCheckMT != nullptr)
8899         {
8900             if (pCheckMT->HasSameTypeDefAs(pBaseMT))
8901             {
8902                 break;
8903             }
8904             
8905             pCheckMT = pCheckMT->GetParentMethodTable();
8906         }
8907         
8908         if (pCheckMT == nullptr)
8909         {
8910             return nullptr;
8911         }
8912         
8913         // The base method should be in the base vtable
8914         WORD slot = pBaseMD->GetSlot();
8915         _ASSERTE(slot < pBaseMT->GetNumVirtuals());
8916         
8917         // Fetch the method that would be invoked if the class were
8918         // exactly derived class. It is up to the jit to determine whether
8919         // directly calling this method is correct.
8920         pDevirtMD = pDerivedMT->GetMethodDescForSlot(slot);
8921
8922         // If the derived method's slot does not match the vtable slot,
8923         // bail on devirtualization, as the method was installed into
8924         // the vtable slot via an explicit override and even if the
8925         // method is final, the slot may not be.
8926         //
8927         // Note the jit could still safely devirtualize if it had an exact
8928         // class, but such cases are likely rare.
8929         WORD dslot = pDevirtMD->GetSlot();
8930
8931         if (dslot != slot)
8932         {
8933             return nullptr;
8934         }
8935     }
8936
8937     _ASSERTE(pDevirtMD->IsRestored());
8938
8939 #ifdef FEATURE_READYTORUN_COMPILER
8940     // Check if devirtualization is dependent upon cross-version
8941     // bubble information and if so, disallow it.
8942     if (IsReadyToRunCompilation())
8943     {
8944         MethodDesc* callerMethod = m_pMethodBeingCompiled;
8945         Assembly* pCallerAssembly = callerMethod->GetModule()->GetAssembly();
8946         bool allowDevirt =
8947             IsInSameVersionBubble(pCallerAssembly , pDevirtMD->GetModule()->GetAssembly())
8948             && IsInSameVersionBubble(pCallerAssembly , pDerivedMT->GetAssembly());
8949
8950         if (!allowDevirt)
8951         {
8952             return nullptr;
8953         }
8954     }
8955 #endif
8956
8957     return (CORINFO_METHOD_HANDLE) pDevirtMD;
8958 }
8959
8960 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethod(CORINFO_METHOD_HANDLE methodHnd,
8961                                                     CORINFO_CLASS_HANDLE derivedClass,
8962                                                     CORINFO_CONTEXT_HANDLE ownerType)
8963 {
8964     CONTRACTL {
8965         SO_TOLERANT;
8966         THROWS;
8967         GC_TRIGGERS;
8968         MODE_PREEMPTIVE;
8969     } CONTRACTL_END;
8970
8971     CORINFO_METHOD_HANDLE result = nullptr;
8972
8973     JIT_TO_EE_TRANSITION();
8974
8975     result = resolveVirtualMethodHelper(methodHnd, derivedClass, ownerType);
8976
8977     EE_TO_JIT_TRANSITION();
8978
8979     return result;
8980 }
8981
8982 /*********************************************************************/
8983 CORINFO_METHOD_HANDLE CEEInfo::getUnboxedEntry(
8984     CORINFO_METHOD_HANDLE ftn,
8985     bool* requiresInstMethodTableArg)
8986 {
8987     CONTRACTL {
8988         SO_TOLERANT;
8989         THROWS;
8990         GC_TRIGGERS;
8991         MODE_PREEMPTIVE;
8992     } CONTRACTL_END;
8993
8994     CORINFO_METHOD_HANDLE result = NULL;
8995
8996     JIT_TO_EE_TRANSITION();
8997
8998     MethodDesc* pMD = GetMethod(ftn);
8999     bool requiresInstMTArg = false;
9000
9001     if (pMD->IsUnboxingStub())
9002     {
9003         MethodTable* pMT = pMD->GetMethodTable();
9004         MethodDesc* pUnboxedMD = pMT->GetUnboxedEntryPointMD(pMD);
9005
9006         result = (CORINFO_METHOD_HANDLE)pUnboxedMD;
9007         requiresInstMTArg = !!pUnboxedMD->RequiresInstMethodTableArg();
9008     }
9009
9010     if (requiresInstMethodTableArg != NULL)
9011     {
9012         *requiresInstMethodTableArg = requiresInstMTArg;
9013     }
9014
9015     EE_TO_JIT_TRANSITION();
9016
9017     return result;
9018 }
9019
9020 /*********************************************************************/
9021 void CEEInfo::expandRawHandleIntrinsic(
9022     CORINFO_RESOLVED_TOKEN *        pResolvedToken,
9023     CORINFO_GENERICHANDLE_RESULT *  pResult)
9024 {
9025     LIMITED_METHOD_CONTRACT;
9026     UNREACHABLE();      // only called with CoreRT.
9027 }
9028
9029 /*********************************************************************/
9030 CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE elemType)
9031 {
9032     CONTRACTL {
9033         SO_TOLERANT;
9034         THROWS;
9035         GC_TRIGGERS;
9036         MODE_PREEMPTIVE;
9037     } CONTRACTL_END;
9038
9039     CORINFO_CLASS_HANDLE result = NULL;
9040
9041     JIT_TO_EE_TRANSITION();
9042
9043     result = getDefaultEqualityComparerClassHelper(elemType);
9044
9045     EE_TO_JIT_TRANSITION();
9046
9047     return result;
9048 }
9049
9050 CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLASS_HANDLE elemType)
9051 {
9052     CONTRACTL {
9053         SO_TOLERANT;
9054         THROWS;
9055         GC_TRIGGERS;
9056         MODE_PREEMPTIVE;
9057     } CONTRACTL_END;
9058
9059     // Mirrors the logic in BCL's CompareHelpers.CreateDefaultEqualityComparer
9060     // And in compile.cpp's SpecializeEqualityComparer
9061     TypeHandle elemTypeHnd(elemType);
9062
9063     // Special case for byte
9064     if (elemTypeHnd.AsMethodTable()->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__ELEMENT_TYPE_U1)))
9065     {
9066         return CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__BYTE_EQUALITYCOMPARER));
9067     }
9068
9069     // Else we'll need to find the appropriate instantation
9070     Instantiation inst(&elemTypeHnd, 1);
9071
9072     // If T implements IEquatable<T>
9073     if (elemTypeHnd.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(inst)))
9074     {
9075         TypeHandle resultTh = ((TypeHandle)MscorlibBinder::GetClass(CLASS__GENERIC_EQUALITYCOMPARER)).Instantiate(inst);
9076         return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
9077     }
9078
9079     // Nullable<T>
9080     if (Nullable::IsNullableType(elemTypeHnd))
9081     {
9082         Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
9083         TypeHandle nullableComparer = TypeHandle(MscorlibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(nullableInst);
9084         if (nullableInst[0].CanCastTo(nullableComparer))
9085         {
9086             return CORINFO_CLASS_HANDLE(nullableComparer.GetMethodTable());
9087         }
9088     }
9089
9090     // Enum
9091     //
9092     // We need to special case the Enum comparers based on their underlying type,
9093     // to avoid boxing and call the correct versions of GetHashCode.
9094     if (elemTypeHnd.IsEnum())
9095     {
9096         MethodTable* targetClass = NULL;
9097         CorElementType normType = elemTypeHnd.GetVerifierCorElementType();
9098
9099         switch(normType)
9100         {
9101             case ELEMENT_TYPE_I1:
9102             case ELEMENT_TYPE_I2:
9103             case ELEMENT_TYPE_U1:
9104             case ELEMENT_TYPE_U2:
9105             case ELEMENT_TYPE_I4:
9106             case ELEMENT_TYPE_U4:
9107             {
9108                 targetClass = MscorlibBinder::GetClass(CLASS__ENUM_EQUALITYCOMPARER);
9109                 break;
9110             }
9111
9112             case ELEMENT_TYPE_I8:
9113             case ELEMENT_TYPE_U8:
9114             {
9115                 targetClass = MscorlibBinder::GetClass(CLASS__LONG_ENUM_EQUALITYCOMPARER);
9116                 break;
9117             }
9118
9119             default:
9120                 break;
9121         }
9122
9123         if (targetClass != NULL)
9124         {
9125             TypeHandle resultTh = ((TypeHandle)targetClass->GetCanonicalMethodTable()).Instantiate(inst);
9126             return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
9127         }
9128     }
9129
9130     // Default case
9131     TypeHandle resultTh = ((TypeHandle)MscorlibBinder::GetClass(CLASS__OBJECT_EQUALITYCOMPARER)).Instantiate(inst);
9132
9133     return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
9134 }
9135
9136 /*********************************************************************/
9137 void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE  ftnHnd,
9138                                     CORINFO_CONST_LOOKUP * pResult,
9139                                     CORINFO_ACCESS_FLAGS   accessFlags)
9140 {
9141     CONTRACTL {
9142         SO_TOLERANT;
9143         THROWS;
9144         GC_TRIGGERS;
9145         MODE_PREEMPTIVE;
9146     } CONTRACTL_END;
9147
9148     void* ret = NULL;
9149     InfoAccessType accessType = IAT_VALUE;
9150
9151     JIT_TO_EE_TRANSITION();
9152
9153     MethodDesc * ftn = GetMethod(ftnHnd);
9154 #if defined(FEATURE_GDBJIT)
9155     MethodDesc * orig_ftn = ftn;
9156 #endif
9157
9158     // Resolve methodImpl.
9159     ftn = ftn->GetMethodTable()->MapMethodDeclToMethodImpl(ftn);
9160
9161     ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags);
9162
9163     // TryGetMultiCallableAddrOfCode returns NULL if indirect access is desired
9164     if (ret == NULL)
9165     {
9166         // should never get here for EnC methods or if interception via remoting stub is required
9167         _ASSERTE(!ftn->IsEnCMethod());
9168
9169         ret = (void *)ftn->GetAddrOfSlot();
9170
9171         if (MethodTable::VTableIndir2_t::isRelative
9172             && ftn->IsVtableSlot())
9173         {
9174             accessType = IAT_RELPVALUE;
9175         }
9176         else
9177         {
9178             accessType = IAT_PVALUE;
9179         }
9180     }
9181
9182
9183 #if defined(FEATURE_GDBJIT)
9184     CalledMethod * pCM = new CalledMethod(orig_ftn, ret, m_pCalledMethods);
9185     m_pCalledMethods = pCM;
9186 #endif
9187
9188     EE_TO_JIT_TRANSITION();
9189
9190     _ASSERTE(ret != NULL);
9191
9192     pResult->accessType = accessType;
9193     pResult->addr = ret;
9194 }
9195
9196 /*********************************************************************/
9197 void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE   ftn,
9198                                          CORINFO_CONST_LOOKUP *  pResult)
9199 {
9200     CONTRACTL {
9201         SO_TOLERANT;
9202         THROWS;
9203         GC_TRIGGERS;
9204         MODE_PREEMPTIVE;
9205     } CONTRACTL_END;
9206
9207     JIT_TO_EE_TRANSITION();
9208
9209     MethodDesc * pMD = GetMethod(ftn);
9210
9211     pResult->accessType = IAT_VALUE;
9212
9213
9214 #ifndef CROSSGEN_COMPILE
9215     // If LDFTN target has [NativeCallable] attribute , then create a UMEntryThunk.
9216     if (pMD->HasNativeCallableAttribute())
9217     {
9218         pResult->addr = (void*)COMDelegate::ConvertToCallback(pMD);
9219     }
9220     else
9221 #endif //CROSSGEN_COMPILE
9222     {
9223         pResult->addr = (void *)pMD->GetMultiCallableAddrOfCode();
9224     }
9225     EE_TO_JIT_TRANSITION();
9226 }
9227
9228 /*********************************************************************/
9229 const char* CEEInfo::getFieldName (CORINFO_FIELD_HANDLE fieldHnd, const char** scopeName)
9230 {
9231     CONTRACTL {
9232         SO_TOLERANT;
9233         THROWS;
9234         GC_TRIGGERS;
9235         MODE_PREEMPTIVE;
9236     } CONTRACTL_END;
9237
9238     const char* result = NULL;
9239
9240     JIT_TO_EE_TRANSITION();
9241
9242     FieldDesc* field = (FieldDesc*) fieldHnd;
9243     if (scopeName != 0)
9244     {
9245         TypeHandle t = TypeHandle(field->GetApproxEnclosingMethodTable());
9246         *scopeName = "";
9247         if (!t.IsNull())
9248         {
9249 #ifdef _DEBUG
9250             t.GetName(ssClsNameBuff);
9251             *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
9252 #else // !_DEBUG
9253             // since this is for diagnostic purposes only,
9254             // give up on the namespace, as we don't have a buffer to concat it
9255             // also note this won't show array class names.
9256             LPCUTF8 nameSpace;
9257             *scopeName= t.GetMethodTable()->GetFullyQualifiedNameInfo(&nameSpace);
9258 #endif // !_DEBUG
9259         }
9260     }
9261
9262     result = field->GetName();
9263
9264     EE_TO_JIT_TRANSITION();
9265
9266     return result;
9267 }
9268
9269 /*********************************************************************/
9270 // Get the type that declares the field
9271 CORINFO_CLASS_HANDLE CEEInfo::getFieldClass (CORINFO_FIELD_HANDLE fieldHnd)
9272 {
9273     CONTRACTL {
9274         SO_TOLERANT;
9275         NOTHROW;
9276         GC_NOTRIGGER;
9277         MODE_PREEMPTIVE;
9278     } CONTRACTL_END;
9279
9280     CORINFO_CLASS_HANDLE result = NULL;
9281
9282     JIT_TO_EE_TRANSITION_LEAF();
9283
9284     FieldDesc* field = (FieldDesc*) fieldHnd;
9285     result = CORINFO_CLASS_HANDLE(field->GetApproxEnclosingMethodTable());
9286
9287     EE_TO_JIT_TRANSITION_LEAF();
9288
9289     return result;
9290 }
9291
9292 /*********************************************************************/
9293 // Returns the basic type of the field (not the the type that declares the field)
9294 //
9295 // pTypeHnd - Optional. If not null then on return, for reference and value types, 
9296 //            *pTypeHnd will contain the normalized type of the field.
9297 // owner - Optional. For resolving in a generic context
9298
9299 CorInfoType CEEInfo::getFieldType (CORINFO_FIELD_HANDLE fieldHnd, 
9300                                    CORINFO_CLASS_HANDLE* pTypeHnd, 
9301                                    CORINFO_CLASS_HANDLE owner)
9302 {
9303     CONTRACTL {
9304         SO_TOLERANT;
9305         THROWS;
9306         GC_TRIGGERS;
9307         MODE_PREEMPTIVE;
9308     } CONTRACTL_END;
9309
9310     CorInfoType result = CORINFO_TYPE_UNDEF;
9311
9312     JIT_TO_EE_TRANSITION();
9313
9314     result = getFieldTypeInternal(fieldHnd, pTypeHnd, owner);
9315
9316     EE_TO_JIT_TRANSITION();
9317
9318     return result;
9319 }
9320
9321 /*********************************************************************/
9322 CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd, 
9323                                            CORINFO_CLASS_HANDLE* pTypeHnd, 
9324                                            CORINFO_CLASS_HANDLE owner)
9325 {
9326     STANDARD_VM_CONTRACT;
9327
9328     if (pTypeHnd != nullptr)
9329     {
9330         *pTypeHnd = 0;
9331     }
9332
9333     TypeHandle clsHnd = TypeHandle();
9334     FieldDesc* field = (FieldDesc*) fieldHnd;
9335     CorElementType type   = field->GetFieldType();
9336
9337     // <REVISIT_TODO>TODO should not burn the time to do this for anything but Value Classes</REVISIT_TODO>
9338     _ASSERTE(type != ELEMENT_TYPE_BYREF);
9339
9340     if (type == ELEMENT_TYPE_I)
9341     {
9342         PTR_MethodTable enclosingMethodTable = field->GetApproxEnclosingMethodTable();
9343         if (enclosingMethodTable->IsByRefLike() && enclosingMethodTable->HasSameTypeDefAs(g_pByReferenceClass))
9344         {
9345             _ASSERTE(field->GetOffset() == 0);
9346             return CORINFO_TYPE_BYREF;
9347         }
9348     }
9349
9350     if (!CorTypeInfo::IsPrimitiveType(type))
9351     {
9352         PCCOR_SIGNATURE sig;
9353         DWORD sigCount;
9354         CorCallingConvention conv;
9355
9356         field->GetSig(&sig, &sigCount);
9357
9358         conv = (CorCallingConvention)CorSigUncompressCallingConv(sig);
9359         _ASSERTE(isCallConv(conv, IMAGE_CEE_CS_CALLCONV_FIELD));
9360
9361         SigPointer ptr(sig, sigCount);
9362
9363         // For verifying code involving generics, use the class instantiation
9364         // of the optional owner (to provide exact, not representative,
9365         // type information)
9366         SigTypeContext typeContext(field, (TypeHandle)owner);
9367
9368         clsHnd = ptr.GetTypeHandleThrowing(field->GetModule(), &typeContext);
9369         _ASSERTE(!clsHnd.IsNull());
9370
9371         // I believe it doesn't make any diff. if this is GetInternalCorElementType 
9372         // or GetSignatureCorElementType.
9373         type = clsHnd.GetSignatureCorElementType();
9374     }
9375
9376     return CEEInfo::asCorInfoType(type, clsHnd, pTypeHnd);
9377 }
9378
9379 /*********************************************************************/
9380 unsigned CEEInfo::getFieldOffset (CORINFO_FIELD_HANDLE fieldHnd)
9381 {
9382     CONTRACTL {
9383         SO_TOLERANT;
9384         THROWS;
9385         GC_TRIGGERS;
9386         MODE_PREEMPTIVE;
9387     } CONTRACTL_END;
9388
9389     unsigned result = (unsigned) -1;
9390
9391     JIT_TO_EE_TRANSITION();
9392
9393     FieldDesc* field = (FieldDesc*) fieldHnd;
9394
9395     // GetOffset() does not include the size of Object
9396     result = field->GetOffset();
9397
9398     // So if it is not a value class, add the Object into it
9399     if (field->IsStatic())
9400     {
9401         Module* pModule = field->GetModule();
9402         if (field->IsRVA() && pModule->IsRvaFieldTls(field->GetOffset()))
9403         {
9404             result = pModule->GetFieldTlsOffset(field->GetOffset());
9405         }
9406     }
9407     else if (!field->GetApproxEnclosingMethodTable()->IsValueType())
9408     {
9409         result += OBJECT_SIZE;
9410     }
9411
9412     EE_TO_JIT_TRANSITION();
9413
9414     return result;
9415 }
9416
9417 /*********************************************************************/
9418 bool CEEInfo::isWriteBarrierHelperRequired(CORINFO_FIELD_HANDLE field)
9419 {
9420     CONTRACTL {
9421         SO_TOLERANT;
9422         THROWS;
9423         GC_TRIGGERS;
9424         MODE_PREEMPTIVE;
9425     } CONTRACTL_END;
9426
9427     bool fHelperRequired = false;
9428
9429     JIT_TO_EE_TRANSITION();
9430
9431     FieldDesc * pField = (FieldDesc *)field;
9432
9433     // TODO: jit64 should be switched to the same plan as the i386 jits - use
9434     // getClassGClayout to figure out the need for writebarrier helper, and inline the copying.
9435     // Once this happens, USE_WRITE_BARRIER_HELPERS and CORINFO_FLG_WRITE_BARRIER_HELPER can be removed.
9436     CorElementType type = pField->GetFieldType();
9437
9438     if(CorTypeInfo::IsObjRef(type))
9439         fHelperRequired = true;
9440     else if (type == ELEMENT_TYPE_VALUETYPE)
9441     {
9442         TypeHandle th = pField->GetFieldTypeHandleThrowing();
9443         _ASSERTE(!th.IsNull());
9444         if(th.GetMethodTable()->ContainsPointers())
9445             fHelperRequired = true;
9446     }
9447
9448     EE_TO_JIT_TRANSITION();
9449
9450     return fHelperRequired;
9451 }
9452
9453 /*********************************************************************/
9454 DWORD CEEInfo::getFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE fieldHnd, void **ppIndirection)
9455 {
9456     CONTRACTL {
9457         SO_TOLERANT;
9458         THROWS;
9459         GC_TRIGGERS;
9460         MODE_PREEMPTIVE;
9461     } CONTRACTL_END;
9462
9463     DWORD result = 0;
9464
9465     if (ppIndirection != NULL)
9466         *ppIndirection = NULL;
9467
9468     JIT_TO_EE_TRANSITION();
9469
9470     FieldDesc* field = (FieldDesc*) fieldHnd;
9471     Module* module = field->GetModule();
9472
9473     _ASSERTE(field->IsRVA());       // Only RVA statics can be thread local
9474     _ASSERTE(module->IsRvaFieldTls(field->GetOffset()));
9475
9476     result = module->GetTlsIndex();
9477
9478     EE_TO_JIT_TRANSITION();
9479
9480     return result;
9481 }
9482
9483 void *CEEInfo::allocateArray(ULONG cBytes)
9484 {
9485     CONTRACTL {
9486         SO_TOLERANT;
9487         THROWS;
9488         GC_TRIGGERS;
9489         MODE_PREEMPTIVE;
9490     } CONTRACTL_END;
9491
9492     void * result = NULL;
9493
9494     JIT_TO_EE_TRANSITION();
9495
9496     result = new BYTE [cBytes];
9497
9498     EE_TO_JIT_TRANSITION();
9499
9500     return result;
9501 }
9502
9503 void CEEInfo::freeArray(void *array)
9504 {
9505     CONTRACTL {
9506         SO_TOLERANT;
9507         THROWS;
9508         GC_TRIGGERS;
9509         MODE_PREEMPTIVE;
9510     } CONTRACTL_END;
9511
9512     JIT_TO_EE_TRANSITION();
9513
9514     delete [] ((BYTE*) array);
9515
9516     EE_TO_JIT_TRANSITION();
9517 }
9518
9519 void CEEInfo::getBoundaries(CORINFO_METHOD_HANDLE ftn,
9520                                unsigned int *cILOffsets, DWORD **pILOffsets,
9521                                ICorDebugInfo::BoundaryTypes *implicitBoundaries)
9522 {
9523     CONTRACTL {
9524         SO_TOLERANT;
9525         THROWS;
9526         GC_TRIGGERS;
9527         MODE_PREEMPTIVE;
9528     } CONTRACTL_END;
9529
9530     JIT_TO_EE_TRANSITION();
9531
9532 #ifdef DEBUGGING_SUPPORTED
9533     if (g_pDebugInterface && !IsCompilationProcess())
9534     {
9535         g_pDebugInterface->getBoundaries(GetMethod(ftn), cILOffsets, pILOffsets,
9536                                      implicitBoundaries);
9537     }
9538     else
9539     {
9540         *cILOffsets = 0;
9541         *pILOffsets = NULL;
9542         *implicitBoundaries = ICorDebugInfo::DEFAULT_BOUNDARIES;
9543     }
9544 #endif // DEBUGGING_SUPPORTED
9545
9546     EE_TO_JIT_TRANSITION();
9547 }
9548
9549 void CEEInfo::getVars(CORINFO_METHOD_HANDLE ftn, ULONG32 *cVars, ICorDebugInfo::ILVarInfo **vars,
9550                          bool *extendOthers)
9551 {
9552     CONTRACTL {
9553         SO_TOLERANT;
9554         THROWS;
9555         GC_TRIGGERS;
9556         MODE_PREEMPTIVE;
9557     } CONTRACTL_END;
9558
9559     JIT_TO_EE_TRANSITION();
9560
9561 #ifdef DEBUGGING_SUPPORTED
9562     if (g_pDebugInterface && !IsCompilationProcess())
9563     {
9564         g_pDebugInterface->getVars(GetMethod(ftn), cVars, vars, extendOthers);
9565     }
9566     else
9567     {
9568         *cVars = 0;
9569         *vars = NULL;
9570
9571         // Just tell the JIT to extend everything.
9572         *extendOthers = true;
9573     }
9574 #endif // DEBUGGING_SUPPORTED
9575
9576     EE_TO_JIT_TRANSITION();
9577 }
9578
9579 /*********************************************************************/
9580 CORINFO_ARG_LIST_HANDLE CEEInfo::getArgNext(CORINFO_ARG_LIST_HANDLE args)
9581 {
9582     CONTRACTL {
9583         SO_TOLERANT;
9584         THROWS;
9585         GC_TRIGGERS;
9586         MODE_PREEMPTIVE;
9587     } CONTRACTL_END;
9588
9589     CORINFO_ARG_LIST_HANDLE result = NULL;
9590
9591     JIT_TO_EE_TRANSITION();
9592
9593     SigPointer ptr((unsigned __int8*) args);
9594     IfFailThrow(ptr.SkipExactlyOne());
9595
9596     result = (CORINFO_ARG_LIST_HANDLE) ptr.GetPtr();
9597
9598     EE_TO_JIT_TRANSITION();
9599     
9600     return result;
9601 }
9602
9603
9604 /*********************************************************************/
9605
9606 CorInfoTypeWithMod CEEInfo::getArgType (
9607         CORINFO_SIG_INFO*       sig,
9608         CORINFO_ARG_LIST_HANDLE args,
9609         CORINFO_CLASS_HANDLE*   vcTypeRet
9610         )
9611 {
9612     CONTRACTL {
9613         SO_TOLERANT;
9614         THROWS;
9615         GC_TRIGGERS;
9616         MODE_PREEMPTIVE;
9617     } CONTRACTL_END;
9618
9619     CorInfoTypeWithMod result = CorInfoTypeWithMod(CORINFO_TYPE_UNDEF);
9620
9621     JIT_TO_EE_TRANSITION();
9622
9623    _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args && (BYTE*) args < (BYTE*) sig->pSig + sig->cbSig);
9624    _ASSERTE((BYTE*) sig->args <= (BYTE*) args);
9625     INDEBUG(*vcTypeRet = CORINFO_CLASS_HANDLE((size_t)INVALID_POINTER_CC));
9626
9627     SigPointer ptr((unsigned __int8*) args);
9628     CorElementType eType;
9629     IfFailThrow(ptr.PeekElemType(&eType));
9630     while (eType == ELEMENT_TYPE_PINNED)
9631     {
9632         result = CORINFO_TYPE_MOD_PINNED;
9633         IfFailThrow(ptr.GetElemType(NULL));
9634         IfFailThrow(ptr.PeekElemType(&eType));
9635     }
9636
9637     // Now read off the "real" element type after taking any instantiations into consideration
9638     SigTypeContext typeContext;
9639     GetTypeContext(&sig->sigInst,&typeContext);
9640
9641     Module* pModule = GetModule(sig->scope);
9642
9643     CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9644
9645     TypeHandle typeHnd = TypeHandle();
9646     switch (type) {
9647       case ELEMENT_TYPE_VAR :
9648       case ELEMENT_TYPE_MVAR :
9649       case ELEMENT_TYPE_VALUETYPE :
9650       case ELEMENT_TYPE_TYPEDBYREF :
9651       case ELEMENT_TYPE_INTERNAL :
9652       {
9653             typeHnd = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9654             _ASSERTE(!typeHnd.IsNull());
9655
9656             CorElementType normType = typeHnd.GetInternalCorElementType();
9657
9658             // if we are looking up a value class, don't morph it to a refernece type
9659             // (This can only happen in illegal IL)
9660             if (!CorTypeInfo::IsObjRef(normType) || type != ELEMENT_TYPE_VALUETYPE)
9661             {
9662                 type = normType;
9663             }
9664         }
9665         break;
9666
9667     case ELEMENT_TYPE_PTR:
9668         // Load the type eagerly under debugger to make the eval work
9669         if (!isVerifyOnly() && CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
9670         {
9671             // NOTE: in some IJW cases, when the type pointed at is unmanaged,
9672             // the GetTypeHandle may fail, because there is no TypeDef for such type.
9673             // Usage of GetTypeHandleThrowing would lead to class load exception
9674             TypeHandle thPtr = ptr.GetTypeHandleNT(pModule, &typeContext);
9675             if(!thPtr.IsNull())
9676             {
9677                 m_pOverride->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(thPtr.AsPtr()));
9678             }
9679         }
9680         break;
9681
9682     case ELEMENT_TYPE_VOID:
9683         // void is not valid in local sigs
9684         if (sig->flags & CORINFO_SIGFLAG_IS_LOCAL_SIG)
9685             COMPlusThrowHR(COR_E_INVALIDPROGRAM);
9686         break;
9687
9688     case ELEMENT_TYPE_END:
9689            COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9690         break;
9691
9692     default:
9693         break;
9694     }
9695
9696     result = CorInfoTypeWithMod(result | CEEInfo::asCorInfoType(type, typeHnd, vcTypeRet));
9697     EE_TO_JIT_TRANSITION();
9698     
9699     return result;
9700 }
9701
9702 /*********************************************************************/
9703
9704 CORINFO_CLASS_HANDLE CEEInfo::getArgClass (
9705     CORINFO_SIG_INFO*       sig,
9706     CORINFO_ARG_LIST_HANDLE args
9707     )
9708 {
9709     CONTRACTL {
9710         SO_TOLERANT;
9711         THROWS;
9712         GC_TRIGGERS;
9713         MODE_PREEMPTIVE;
9714     } CONTRACTL_END;
9715
9716     CORINFO_CLASS_HANDLE result = NULL;
9717
9718     JIT_TO_EE_TRANSITION();
9719
9720     // make certain we dont have a completely wacked out sig pointer
9721     _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args);
9722     _ASSERTE((BYTE*) sig->args <= (BYTE*) args && (BYTE*) args < &((BYTE*) sig->args)[0x10000*5]);
9723
9724     Module* pModule = GetModule(sig->scope);
9725
9726     SigPointer ptr((unsigned __int8*) args);
9727
9728     CorElementType eType;
9729     IfFailThrow(ptr.PeekElemType(&eType));
9730
9731     while (eType == ELEMENT_TYPE_PINNED)
9732     {
9733         IfFailThrow(ptr.GetElemType(NULL));
9734         IfFailThrow(ptr.PeekElemType(&eType));
9735     }
9736     // Now read off the "real" element type after taking any instantiations into consideration
9737     SigTypeContext typeContext;
9738     GetTypeContext(&sig->sigInst, &typeContext);
9739     CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9740
9741     if (!CorTypeInfo::IsPrimitiveType(type)) {
9742         TypeHandle th = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9743         result = CORINFO_CLASS_HANDLE(th.AsPtr());
9744     }
9745
9746     EE_TO_JIT_TRANSITION();
9747     
9748     return result;
9749 }
9750
9751 /*********************************************************************/
9752
9753 CorInfoType CEEInfo::getHFAType(CORINFO_CLASS_HANDLE hClass)
9754 {
9755     CONTRACTL {
9756         SO_TOLERANT;
9757         THROWS;
9758         GC_TRIGGERS;
9759         MODE_PREEMPTIVE;
9760     } CONTRACTL_END;
9761
9762     CorInfoType result = CORINFO_TYPE_UNDEF;
9763
9764     JIT_TO_EE_TRANSITION();
9765
9766     TypeHandle VMClsHnd(hClass);
9767
9768     result = asCorInfoType(VMClsHnd.GetHFAType());
9769     
9770     EE_TO_JIT_TRANSITION();
9771
9772     return result;
9773 }
9774
9775 /*********************************************************************/
9776
9777     // return the unmanaged calling convention for a PInvoke
9778 CorInfoUnmanagedCallConv CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method)
9779 {
9780     CONTRACTL {
9781         SO_TOLERANT;
9782         THROWS;
9783         GC_TRIGGERS;
9784         MODE_PREEMPTIVE;
9785     } CONTRACTL_END;
9786
9787     CorInfoUnmanagedCallConv result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9788
9789     JIT_TO_EE_TRANSITION();
9790
9791     MethodDesc* pMD = NULL;
9792     pMD = GetMethod(method);
9793     _ASSERTE(pMD->IsNDirect());
9794
9795 #ifdef _TARGET_X86_
9796     EX_TRY
9797     {
9798         PInvokeStaticSigInfo sigInfo(pMD, PInvokeStaticSigInfo::NO_THROW_ON_ERROR);
9799
9800         switch (sigInfo.GetCallConv()) {
9801             case pmCallConvCdecl:
9802                 result = CORINFO_UNMANAGED_CALLCONV_C;
9803                 break;
9804             case pmCallConvStdcall:
9805                 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9806                 break;
9807             case pmCallConvThiscall:
9808                 result = CORINFO_UNMANAGED_CALLCONV_THISCALL;
9809                 break;
9810             default:
9811                 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9812         }
9813     }
9814     EX_CATCH
9815     {
9816         result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9817     }
9818     EX_END_CATCH(SwallowAllExceptions)
9819 #else // !_TARGET_X86_
9820     //
9821     // we have only one calling convention
9822     //
9823     result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9824 #endif // !_TARGET_X86_
9825
9826     EE_TO_JIT_TRANSITION();
9827     
9828     return result;
9829 }
9830
9831 /*********************************************************************/
9832 BOOL NDirectMethodDesc::ComputeMarshalingRequired()
9833 {
9834     WRAPPER_NO_CONTRACT;
9835
9836     return NDirect::MarshalingRequired(this);
9837 }
9838
9839 /*********************************************************************/
9840 BOOL CEEInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig)
9841 {
9842     CONTRACTL {
9843         SO_TOLERANT;
9844         THROWS;
9845         GC_TRIGGERS;
9846         MODE_PREEMPTIVE;
9847     } CONTRACTL_END;
9848
9849     BOOL result = FALSE;
9850
9851     JIT_TO_EE_TRANSITION();
9852
9853     if (method != 0)
9854     {
9855         MethodDesc* ftn = GetMethod(method);
9856         _ASSERTE(ftn->IsNDirect());
9857         NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9858
9859 #if defined(HAS_NDIRECT_IMPORT_PRECODE)
9860         if (pMD->IsVarArg())
9861         {
9862             // Varag P/Invoke must not be inlined because its NDirectMethodDesc
9863             // does not contain a meaningful stack size (it is call site specific).
9864             // See code:InlinedCallFrame.UpdateRegDisplay where this is needed.
9865             result = TRUE;
9866         }
9867         else if (pMD->MarshalingRequired())
9868         {
9869             // This is not a no-marshal signature.
9870             result = TRUE;
9871         }
9872         else
9873         {
9874             // This is a no-marshal non-vararg signature.
9875             result = FALSE;
9876         }
9877 #else
9878         // Marshalling is required to lazy initialize the indirection cell 
9879         // without NDirectImportPrecode.
9880         result = TRUE;
9881 #endif
9882     }
9883     else
9884     {
9885         // check the call site signature
9886         result = NDirect::MarshalingRequired(
9887                     GetMethod(method),
9888                     callSiteSig->pSig,
9889                     GetModule(callSiteSig->scope));
9890     }
9891
9892     EE_TO_JIT_TRANSITION();
9893
9894     return result;
9895 }
9896
9897 /*********************************************************************/
9898 // Generate a cookie based on the signature that would needs to be passed
9899 // to CORINFO_HELP_PINVOKE_CALLI
9900 LPVOID CEEInfo::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig,
9901                                             void **ppIndirection)
9902 {
9903     WRAPPER_NO_CONTRACT;
9904
9905     return getVarArgsHandle(szMetaSig, ppIndirection);
9906 }
9907
9908 bool CEEInfo::canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig)
9909 {
9910     LIMITED_METHOD_CONTRACT;
9911     return true;
9912 }
9913
9914
9915 // Check any constraints on method type arguments
9916 BOOL CEEInfo::satisfiesMethodConstraints(
9917     CORINFO_CLASS_HANDLE        parent,
9918     CORINFO_METHOD_HANDLE       method)
9919 {
9920     CONTRACTL {
9921         SO_TOLERANT;
9922         THROWS;
9923         GC_TRIGGERS;
9924         MODE_PREEMPTIVE;
9925     } CONTRACTL_END;
9926
9927     BOOL result = FALSE;
9928
9929     JIT_TO_EE_TRANSITION();
9930
9931     _ASSERTE(parent != NULL);
9932     _ASSERTE(method != NULL);
9933     result = GetMethod(method)->SatisfiesMethodConstraints(TypeHandle(parent));
9934
9935     EE_TO_JIT_TRANSITION();
9936
9937     return result;
9938 }
9939
9940
9941
9942 /*********************************************************************/
9943 // Given a delegate target class, a target method parent class,  a  target method,
9944 // a delegate class, check if the method signature is compatible with the Invoke method of the delegate
9945 // (under the typical instantiation of any free type variables in the memberref signatures).
9946 //
9947 // objCls should be NULL if the target object is NULL
9948 //@GENERICSVER: new (suitable for generics)
9949 BOOL CEEInfo::isCompatibleDelegate(
9950             CORINFO_CLASS_HANDLE        objCls,
9951             CORINFO_CLASS_HANDLE        methodParentCls,
9952             CORINFO_METHOD_HANDLE       method,
9953             CORINFO_CLASS_HANDLE        delegateCls,
9954             BOOL*                       pfIsOpenDelegate)
9955 {
9956     CONTRACTL {
9957         SO_TOLERANT;
9958         THROWS;
9959         GC_TRIGGERS;
9960         MODE_PREEMPTIVE;
9961     } CONTRACTL_END;
9962
9963     BOOL result = FALSE;
9964
9965     JIT_TO_EE_TRANSITION();
9966
9967     _ASSERTE(method != NULL);
9968     _ASSERTE(delegateCls != NULL);
9969
9970     TypeHandle delegateClsHnd = (TypeHandle) delegateCls;
9971
9972     _ASSERTE(delegateClsHnd.GetMethodTable()->IsDelegate());
9973
9974     TypeHandle methodParentHnd = (TypeHandle) (methodParentCls);
9975     MethodDesc* pMDFtn = GetMethod(method);
9976     TypeHandle objClsHnd(objCls);
9977
9978     EX_TRY
9979     {
9980       result = COMDelegate::ValidateCtor(objClsHnd, methodParentHnd, pMDFtn, delegateClsHnd, pfIsOpenDelegate);
9981     }
9982     EX_CATCH
9983     {
9984     }
9985     EX_END_CATCH(SwallowAllExceptions)
9986
9987     EE_TO_JIT_TRANSITION();
9988
9989     return result;
9990 }
9991
9992 /*********************************************************************/
9993     // return the unmanaged target *if method has already been prelinked.*
9994 void* CEEInfo::getPInvokeUnmanagedTarget(CORINFO_METHOD_HANDLE method,
9995                                                     void **ppIndirection)
9996 {
9997     CONTRACTL {
9998         SO_TOLERANT;
9999         THROWS;
10000         GC_TRIGGERS;
10001         MODE_PREEMPTIVE;
10002     } CONTRACTL_END;
10003
10004     // Not expected to work due to multicore and tiered JIT potentially needing
10005     // to call managed cctors
10006     _ASSERTE(FALSE);
10007
10008     if (ppIndirection != NULL)
10009     {
10010         *ppIndirection = NULL;
10011     }
10012
10013     return NULL;
10014 }
10015
10016 /*********************************************************************/
10017     // return address of fixup area for late-bound N/Direct calls.
10018 void* CEEInfo::getAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE method,
10019                                         void **ppIndirection)
10020 {
10021     CONTRACTL {
10022         SO_TOLERANT;
10023         NOTHROW;
10024         GC_NOTRIGGER;
10025         MODE_PREEMPTIVE;
10026     } CONTRACTL_END;
10027
10028     void * result = NULL;
10029
10030     if (ppIndirection != NULL)
10031         *ppIndirection = NULL;
10032
10033     JIT_TO_EE_TRANSITION_LEAF();
10034
10035     MethodDesc* ftn = GetMethod(method);
10036     _ASSERTE(ftn->IsNDirect());
10037     NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
10038
10039     result = (LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
10040
10041     EE_TO_JIT_TRANSITION_LEAF();
10042
10043     return result;
10044 }
10045
10046 /*********************************************************************/
10047     // return address of fixup area for late-bound N/Direct calls.
10048 void CEEInfo::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method,
10049                                         CORINFO_CONST_LOOKUP *pLookup)
10050 {
10051     WRAPPER_NO_CONTRACT;
10052
10053     void *pIndirection;
10054     pLookup->accessType = IAT_PVALUE;
10055     pLookup->addr = getAddressOfPInvokeFixup(method, &pIndirection);
10056     _ASSERTE(pIndirection == NULL);
10057 }
10058
10059 /*********************************************************************/
10060 CORINFO_JUST_MY_CODE_HANDLE CEEInfo::getJustMyCodeHandle(
10061                 CORINFO_METHOD_HANDLE       method,
10062                 CORINFO_JUST_MY_CODE_HANDLE**ppIndirection)
10063 {
10064     CONTRACTL {
10065         SO_TOLERANT;
10066         NOTHROW;
10067         GC_NOTRIGGER;
10068         MODE_PREEMPTIVE;
10069     } CONTRACTL_END;
10070
10071     CORINFO_JUST_MY_CODE_HANDLE result = NULL;
10072
10073     if (ppIndirection)
10074         *ppIndirection = NULL;
10075
10076     JIT_TO_EE_TRANSITION_LEAF();
10077
10078     // Get the flag from the debugger.
10079     MethodDesc* ftn = GetMethod(method);
10080     DWORD * pFlagAddr = NULL;
10081     
10082     if (g_pDebugInterface)
10083     {
10084         pFlagAddr = g_pDebugInterface->GetJMCFlagAddr(ftn->GetModule());
10085     }
10086
10087     result = (CORINFO_JUST_MY_CODE_HANDLE) pFlagAddr;
10088
10089     EE_TO_JIT_TRANSITION_LEAF();
10090
10091     return result;
10092 }
10093
10094 /*********************************************************************/
10095 void InlinedCallFrame::GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo *pInfo)
10096 {
10097     LIMITED_METHOD_CONTRACT;
10098
10099     pInfo->size                          = sizeof(GSCookie) + sizeof(InlinedCallFrame);
10100
10101     pInfo->offsetOfGSCookie              = 0;
10102     pInfo->offsetOfFrameVptr             = sizeof(GSCookie);
10103     pInfo->offsetOfFrameLink             = sizeof(GSCookie) + Frame::GetOffsetOfNextLink();
10104     pInfo->offsetOfCallSiteSP            = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallSiteSP);
10105     pInfo->offsetOfCalleeSavedFP         = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCalleeSavedFP);
10106     pInfo->offsetOfCallTarget            = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_Datum);
10107     pInfo->offsetOfReturnAddress         = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallerReturnAddress);
10108 }
10109
10110 /*********************************************************************/
10111 // Return details about EE internal data structures 
10112 void CEEInfo::getEEInfo(CORINFO_EE_INFO *pEEInfoOut)
10113 {
10114     CONTRACTL {
10115         SO_TOLERANT;
10116         THROWS;
10117         GC_TRIGGERS;
10118         MODE_PREEMPTIVE;
10119     } CONTRACTL_END;
10120
10121     INDEBUG(memset(pEEInfoOut, 0xCC, sizeof(*pEEInfoOut)));
10122
10123     JIT_TO_EE_TRANSITION();
10124
10125     if (!IsReadyToRunCompilation())
10126     {
10127         InlinedCallFrame::GetEEInfo(&pEEInfoOut->inlinedCallFrameInfo);
10128
10129         // Offsets into the Thread structure
10130         pEEInfoOut->offsetOfThreadFrame = Thread::GetOffsetOfCurrentFrame();
10131         pEEInfoOut->offsetOfGCState     = Thread::GetOffsetOfGCFlag();
10132     }
10133     else
10134     {
10135         // inlinedCallFrameInfo is not used for R2R compilation
10136         ZeroMemory(&pEEInfoOut->inlinedCallFrameInfo, sizeof(pEEInfoOut->inlinedCallFrameInfo));
10137
10138         pEEInfoOut->offsetOfThreadFrame = (DWORD)-1;
10139         pEEInfoOut->offsetOfGCState     = (DWORD)-1;
10140     }
10141
10142 #ifndef CROSSBITNESS_COMPILE
10143     // The assertions must hold in every non-crossbitness scenario
10144     _ASSERTE(OFFSETOF__DelegateObject__target       == DelegateObject::GetOffsetOfTarget());
10145     _ASSERTE(OFFSETOF__DelegateObject__methodPtr    == DelegateObject::GetOffsetOfMethodPtr());
10146     _ASSERTE(OFFSETOF__DelegateObject__methodPtrAux == DelegateObject::GetOffsetOfMethodPtrAux());
10147     _ASSERTE(OFFSETOF__PtrArray__m_Array_           == PtrArray::GetDataOffset());
10148 #endif
10149
10150     // Delegate offsets
10151     pEEInfoOut->offsetOfDelegateInstance    = OFFSETOF__DelegateObject__target;
10152     pEEInfoOut->offsetOfDelegateFirstTarget = OFFSETOF__DelegateObject__methodPtr;
10153
10154     // Secure delegate offsets
10155     pEEInfoOut->offsetOfSecureDelegateIndirectCell = OFFSETOF__DelegateObject__methodPtrAux;
10156
10157     // Remoting offsets
10158     pEEInfoOut->offsetOfTransparentProxyRP = (DWORD)-1;
10159     pEEInfoOut->offsetOfRealProxyServer    = (DWORD)-1;
10160
10161     pEEInfoOut->offsetOfObjArrayData       = OFFSETOF__PtrArray__m_Array_;
10162
10163     pEEInfoOut->sizeOfReversePInvokeFrame  = (DWORD)-1;
10164
10165     pEEInfoOut->osPageSize = GetOsPageSize();
10166     pEEInfoOut->maxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
10167     pEEInfoOut->targetAbi = CORINFO_CORECLR_ABI;
10168
10169     pEEInfoOut->osType = CORINFO_WINNT;
10170
10171     // hardcode OS version to 0.0.0. These fields can be removed from JITEE interface
10172     pEEInfoOut->osMajor = 0;
10173     pEEInfoOut->osMinor = 0;
10174     pEEInfoOut->osBuild = 0;
10175
10176     EE_TO_JIT_TRANSITION();
10177 }
10178
10179 LPCWSTR CEEInfo::getJitTimeLogFilename()
10180 {
10181     CONTRACTL {
10182         SO_TOLERANT;
10183         THROWS;
10184         GC_TRIGGERS;
10185         MODE_PREEMPTIVE;
10186     } CONTRACTL_END;
10187
10188     LPCWSTR result = NULL;
10189
10190     JIT_TO_EE_TRANSITION();
10191     result = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitTimeLogFile);
10192     EE_TO_JIT_TRANSITION();
10193
10194     return result;
10195 }
10196
10197
10198
10199     // Return details about EE internal data structures
10200 DWORD CEEInfo::getThreadTLSIndex(void **ppIndirection)
10201 {
10202     CONTRACTL {
10203         SO_TOLERANT;
10204         THROWS;
10205         GC_TRIGGERS;
10206         MODE_PREEMPTIVE;
10207     } CONTRACTL_END;
10208
10209     DWORD result = (DWORD)-1;
10210
10211     if (ppIndirection != NULL)
10212         *ppIndirection = NULL;
10213
10214     return result;
10215 }
10216
10217 const void * CEEInfo::getInlinedCallFrameVptr(void **ppIndirection)
10218 {
10219     CONTRACTL {
10220         SO_TOLERANT;
10221         NOTHROW;
10222         GC_NOTRIGGER;
10223         MODE_PREEMPTIVE;
10224     } CONTRACTL_END;
10225
10226     void * result = NULL;
10227
10228     if (ppIndirection != NULL)
10229         *ppIndirection = NULL;
10230
10231     JIT_TO_EE_TRANSITION_LEAF();
10232
10233 #ifndef CROSSGEN_COMPILE
10234     result = (void*)InlinedCallFrame::GetMethodFrameVPtr();
10235 #else
10236     result = (void*)0x43210;
10237 #endif
10238
10239     EE_TO_JIT_TRANSITION_LEAF();
10240
10241     return result;
10242 }
10243
10244 LONG * CEEInfo::getAddrOfCaptureThreadGlobal(void **ppIndirection)
10245 {
10246     CONTRACTL {
10247         SO_TOLERANT;
10248         NOTHROW;
10249         GC_NOTRIGGER;
10250         MODE_PREEMPTIVE;
10251     } CONTRACTL_END;
10252
10253     LONG * result = NULL;
10254
10255     if (ppIndirection != NULL)
10256         *ppIndirection = NULL;
10257
10258     JIT_TO_EE_TRANSITION_LEAF();
10259
10260     result = (LONG *)&g_TrapReturningThreads;
10261
10262     EE_TO_JIT_TRANSITION_LEAF();
10263
10264     return result;
10265 }
10266
10267
10268
10269 HRESULT CEEInfo::GetErrorHRESULT(struct _EXCEPTION_POINTERS *pExceptionPointers)
10270 {
10271     CONTRACTL {
10272         SO_TOLERANT;
10273         NOTHROW;
10274         GC_TRIGGERS;
10275         MODE_ANY;
10276     } CONTRACTL_END;
10277
10278     HRESULT hr = S_OK;
10279
10280     //This function is called from the JIT64 exception filter during PEVerify.  Because it is a filter, it
10281     //can be "called" from a NOTHROW region in the case of StackOverflow.  Security::MapToHR throws
10282     //internally, but it catches all exceptions.  Therefore, none of the children can cause an exception to
10283     //percolate out of this function (except for Stack Overflow).  Obviously I can't explain most of this to
10284     //the Contracts system, and I can't add this CONTRACT_VIOLATION to the filter in Jit64.
10285     CONTRACT_VIOLATION(ThrowsViolation);
10286
10287     JIT_TO_EE_TRANSITION();
10288
10289     GCX_COOP();
10290
10291     OBJECTREF throwable = GetThread()->LastThrownObject();
10292     hr = GetExceptionHResult(throwable);
10293
10294     EE_TO_JIT_TRANSITION();
10295
10296     return hr;
10297 }
10298
10299
10300 ULONG CEEInfo::GetErrorMessage(__inout_ecount(bufferLength) LPWSTR buffer, ULONG bufferLength)
10301 {
10302     CONTRACTL {
10303         SO_TOLERANT;
10304         THROWS;
10305         GC_TRIGGERS;
10306         MODE_PREEMPTIVE;
10307     } CONTRACTL_END;
10308
10309     ULONG result = 0;
10310
10311 #ifndef CROSSGEN_COMPILE
10312     JIT_TO_EE_TRANSITION();
10313
10314     GCX_COOP();
10315
10316     OBJECTREF throwable = GetThread()->LastThrownObject();
10317
10318     if (throwable != NULL)
10319     {
10320         EX_TRY
10321         {
10322             result = GetExceptionMessage(throwable, buffer, bufferLength);
10323         }
10324         EX_CATCH
10325         {
10326         }
10327         EX_END_CATCH(SwallowAllExceptions)
10328     }
10329
10330     EE_TO_JIT_TRANSITION();
10331 #endif
10332
10333     return result;
10334 }
10335
10336 // This method is called from CEEInfo::FilterException which
10337 // is run as part of the SEH filter clause for the JIT.
10338 // It is fatal to throw an exception while running a SEH filter clause
10339 // so our contract is NOTHROW, NOTRIGGER.
10340 //
10341 LONG EEFilterException(struct _EXCEPTION_POINTERS *pExceptionPointers, void *unused)
10342 {
10343     CONTRACTL {
10344         SO_TOLERANT;
10345         NOTHROW;
10346         GC_NOTRIGGER;
10347     } CONTRACTL_END;
10348
10349     int result = 0;
10350
10351     JIT_TO_EE_TRANSITION_LEAF();
10352
10353     VALIDATE_BACKOUT_STACK_CONSUMPTION;
10354
10355     unsigned code = pExceptionPointers->ExceptionRecord->ExceptionCode;
10356
10357 #ifdef _DEBUG
10358     if (code == EXCEPTION_ACCESS_VIOLATION)
10359     {
10360         static int hit = 0;
10361         if (hit++ == 0)
10362         {
10363             _ASSERTE(!"Access violation while Jitting!");
10364             // If you set the debugger to catch access violations and 'go'
10365             // you will get back to the point at which the access violation occurred
10366             result = EXCEPTION_CONTINUE_EXECUTION;
10367         }
10368         else
10369         {
10370             result = EXCEPTION_CONTINUE_SEARCH;
10371         }
10372     }
10373     else
10374 #endif // _DEBUG
10375     // No one should be catching breakpoint
10376     // Similarly the JIT doesn't know how to reset the guard page, so it shouldn't
10377     // be catching a hard stack overflow
10378     if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP || code == EXCEPTION_STACK_OVERFLOW)
10379     {
10380         result = EXCEPTION_CONTINUE_SEARCH;
10381     }
10382 #ifdef CROSSGEN_COMPILE
10383     else
10384     {
10385         result = EXCEPTION_EXECUTE_HANDLER;
10386     }
10387 #else
10388     else if (!IsComPlusException(pExceptionPointers->ExceptionRecord))
10389     {
10390         result = EXCEPTION_EXECUTE_HANDLER;
10391     }
10392     else
10393     {
10394         GCX_COOP();
10395
10396         // This is actually the LastThrown exception object.
10397         OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10398
10399         if (throwable != NULL)
10400         {
10401             struct 
10402             {
10403                 OBJECTREF oLastThrownObject;
10404             } _gc;
10405
10406             ZeroMemory(&_gc, sizeof(_gc));
10407             
10408             // Setup the throwables
10409             _gc.oLastThrownObject = throwable;
10410
10411             GCPROTECT_BEGIN(_gc);
10412
10413             // Don't catch ThreadAbort and other uncatchable exceptions
10414             if (IsUncatchable(&_gc.oLastThrownObject))
10415                 result = EXCEPTION_CONTINUE_SEARCH;
10416             else
10417                 result = EXCEPTION_EXECUTE_HANDLER;
10418             
10419             GCPROTECT_END();
10420         }
10421     }
10422 #endif
10423
10424     EE_TO_JIT_TRANSITION_LEAF();
10425
10426     return result;
10427 }
10428
10429 int CEEInfo::FilterException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10430 {
10431     WRAPPER_NO_CONTRACT;
10432     return EEFilterException(pExceptionPointers, nullptr);
10433 }
10434
10435 // This code is called if FilterException chose to handle the exception.
10436 void CEEInfo::HandleException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10437 {
10438     CONTRACTL {
10439         SO_TOLERANT;
10440         NOTHROW;
10441         GC_NOTRIGGER;
10442     } CONTRACTL_END;
10443
10444     JIT_TO_EE_TRANSITION_LEAF();
10445
10446 #ifndef CROSSGEN_COMPILE
10447     if (IsComPlusException(pExceptionPointers->ExceptionRecord))
10448     {
10449         GCX_COOP();
10450
10451         // This is actually the LastThrown exception object.
10452         OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10453
10454         if (throwable != NULL)
10455         {
10456             struct 
10457             {
10458                 OBJECTREF oLastThrownObject;
10459                 OBJECTREF oCurrentThrowable;
10460             } _gc;
10461
10462             ZeroMemory(&_gc, sizeof(_gc));
10463             
10464             PTR_Thread pCurThread = GetThread();
10465
10466             // Setup the throwables
10467             _gc.oLastThrownObject = throwable;
10468
10469             // This will be NULL if no managed exception is active. Otherwise,
10470             // it will reference the active throwable.
10471             _gc.oCurrentThrowable = pCurThread->GetThrowable(); 
10472
10473             GCPROTECT_BEGIN(_gc);
10474
10475             // JIT does not use or reference managed exceptions at all and simply swallows them,
10476             // or lets them fly through so that they will either get caught in managed code, the VM
10477             // or will go unhandled. 
10478             //
10479             // Blind swallowing of managed exceptions can break the semantic of "which exception handler"
10480             // gets to process the managed exception first. The expected handler is managed code exception 
10481             // handler (e.g. COMPlusFrameHandler on x86 and ProcessCLRException on 64bit) which will setup 
10482             // the exception tracker for the exception that will enable the expected sync between the 
10483             // LastThrownObject (LTO), setup in RaiseTheExceptionInternalOnly, and the exception tracker.
10484             // 
10485             // However, JIT can break this by swallowing the managed exception before managed code exception
10486             // handler gets a chance to setup an exception tracker for it. Since there is no cleanup
10487             // done for the swallowed exception as part of the unwind (because no exception tracker may have been setup), 
10488             // we need to reset the LTO, if it is out of sync from the active throwable.
10489             //
10490             // Hence, check if the LastThrownObject and active-exception throwable are in sync or not.
10491             // If not, bring them in sync.
10492             //
10493             // Example
10494             // -------
10495             // It is possible that an exception was already in progress and while processing it (e.g.
10496             // invoking finally block), we invoked JIT that had another managed exception @ JIT-EE transition boundary
10497             // that is swallowed by the JIT before managed code exception handler sees it. This breaks the sync between
10498             // LTO and the active exception in the exception tracker.
10499             if (_gc.oCurrentThrowable != _gc.oLastThrownObject)
10500             {
10501                 // Update the LTO. 
10502                 //
10503                 // Note: Incase of OOM, this will get set to OOM instance.
10504                 pCurThread->SafeSetLastThrownObject(_gc.oCurrentThrowable);
10505             }
10506  
10507             GCPROTECT_END();
10508         }
10509     }
10510 #endif
10511
10512     EE_TO_JIT_TRANSITION_LEAF();
10513 }
10514
10515 void ThrowExceptionForJit(HRESULT res);
10516
10517 void CEEInfo::ThrowExceptionForJitResult(
10518         HRESULT result)
10519 {
10520     CONTRACTL {
10521         SO_TOLERANT;
10522         THROWS;
10523         GC_TRIGGERS;
10524         MODE_PREEMPTIVE;
10525     } CONTRACTL_END;
10526
10527     JIT_TO_EE_TRANSITION();
10528
10529     if (!SUCCEEDED(result))
10530         ThrowExceptionForJit(result);
10531
10532     EE_TO_JIT_TRANSITION();
10533 }
10534
10535
10536 CORINFO_MODULE_HANDLE CEEInfo::embedModuleHandle(CORINFO_MODULE_HANDLE handle,
10537                                                  void **ppIndirection)
10538 {
10539     CONTRACTL {
10540         SO_TOLERANT;
10541         NOTHROW;
10542         GC_NOTRIGGER;
10543         MODE_PREEMPTIVE;
10544         PRECONDITION(!IsDynamicScope(handle));
10545     }
10546     CONTRACTL_END;
10547
10548     if (ppIndirection != NULL)
10549         *ppIndirection = NULL;
10550
10551     JIT_TO_EE_TRANSITION_LEAF();
10552
10553     EE_TO_JIT_TRANSITION_LEAF();
10554
10555     return handle;
10556 }
10557
10558 CORINFO_CLASS_HANDLE CEEInfo::embedClassHandle(CORINFO_CLASS_HANDLE handle,
10559                                                void **ppIndirection)
10560 {
10561     CONTRACTL {
10562         SO_TOLERANT;
10563         NOTHROW;
10564         GC_NOTRIGGER;
10565         MODE_PREEMPTIVE;
10566     }
10567     CONTRACTL_END;
10568
10569     if (ppIndirection != NULL)
10570         *ppIndirection = NULL;
10571
10572     JIT_TO_EE_TRANSITION_LEAF();
10573
10574     EE_TO_JIT_TRANSITION_LEAF();
10575
10576     return handle;
10577 }
10578
10579 CORINFO_FIELD_HANDLE CEEInfo::embedFieldHandle(CORINFO_FIELD_HANDLE handle,
10580                                                void **ppIndirection)
10581 {
10582     CONTRACTL {
10583         SO_TOLERANT;
10584         NOTHROW;
10585         GC_NOTRIGGER;
10586         MODE_PREEMPTIVE;
10587     }
10588     CONTRACTL_END;
10589
10590     if (ppIndirection != NULL)
10591         *ppIndirection = NULL;
10592
10593     JIT_TO_EE_TRANSITION_LEAF();
10594
10595     EE_TO_JIT_TRANSITION_LEAF();
10596
10597     return handle;
10598 }
10599
10600 CORINFO_METHOD_HANDLE CEEInfo::embedMethodHandle(CORINFO_METHOD_HANDLE handle,
10601                                                  void **ppIndirection)
10602 {
10603     CONTRACTL {
10604         SO_TOLERANT;
10605         NOTHROW;
10606         GC_NOTRIGGER;
10607         MODE_PREEMPTIVE;
10608     }
10609     CONTRACTL_END;
10610
10611     if (ppIndirection != NULL)
10612         *ppIndirection = NULL;
10613
10614     JIT_TO_EE_TRANSITION_LEAF();
10615
10616     EE_TO_JIT_TRANSITION_LEAF();
10617
10618     return handle;
10619 }
10620
10621 /*********************************************************************/
10622 void CEEInfo::setJitFlags(const CORJIT_FLAGS& jitFlags)
10623 {
10624     LIMITED_METHOD_CONTRACT;
10625
10626     m_jitFlags = jitFlags;
10627 }
10628
10629 /*********************************************************************/
10630 DWORD CEEInfo::getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes)
10631 {
10632     CONTRACTL {
10633         SO_TOLERANT;
10634         NOTHROW;
10635         GC_NOTRIGGER;
10636         MODE_PREEMPTIVE;
10637     } CONTRACTL_END;
10638
10639     JIT_TO_EE_TRANSITION_LEAF();
10640
10641     _ASSERTE(sizeInBytes >= sizeof(m_jitFlags));
10642     *jitFlags = m_jitFlags;
10643
10644     EE_TO_JIT_TRANSITION_LEAF();
10645
10646     return sizeof(m_jitFlags);
10647 }
10648
10649 /*********************************************************************/
10650 #if !defined(PLATFORM_UNIX)
10651
10652 struct RunWithErrorTrapFilterParam
10653 {
10654     ICorDynamicInfo* m_corInfo;
10655     void (*m_function)(void*);
10656     void* m_param;
10657     EXCEPTION_POINTERS m_exceptionPointers;
10658 };
10659
10660 static LONG RunWithErrorTrapFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
10661 {
10662     WRAPPER_NO_CONTRACT;
10663
10664     auto* param = reinterpret_cast<RunWithErrorTrapFilterParam*>(theParam);
10665     param->m_exceptionPointers = *exceptionPointers;
10666     return param->m_corInfo->FilterException(exceptionPointers);
10667 }
10668
10669 #endif // !defined(PLATFORM_UNIX)
10670
10671 bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param)
10672 {
10673     // No dynamic contract here because SEH is used
10674     STATIC_CONTRACT_THROWS;
10675     STATIC_CONTRACT_GC_TRIGGERS;
10676     STATIC_CONTRACT_SO_TOLERANT;
10677     STATIC_CONTRACT_MODE_PREEMPTIVE;
10678
10679     // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
10680     //       transitions into the EE proper should occur either via the call to
10681     //       `EEFilterException` (which is appropriately marked) or via JIT/EE
10682     //       interface calls made by `function`.
10683
10684     bool success = true;
10685
10686 #if !defined(PLATFORM_UNIX)
10687
10688     RunWithErrorTrapFilterParam trapParam;
10689     trapParam.m_corInfo = m_pOverride == nullptr ? this : m_pOverride;
10690     trapParam.m_function = function;
10691     trapParam.m_param = param;
10692
10693     PAL_TRY(RunWithErrorTrapFilterParam*, pTrapParam, &trapParam)
10694     {
10695         pTrapParam->m_function(pTrapParam->m_param);
10696     }
10697     PAL_EXCEPT_FILTER(RunWithErrorTrapFilter)
10698     {
10699         HandleException(&trapParam.m_exceptionPointers);
10700         success = false;
10701     }
10702     PAL_ENDTRY
10703
10704 #else // !defined(PLATFORM_UNIX)
10705
10706     // We shouldn't need PAL_TRY on *nix: any exceptions that we are able to catch
10707     // ought to originate from the runtime itself and should be catchable inside of
10708     // EX_TRY/EX_CATCH, including emulated SEH exceptions.
10709     EX_TRY
10710     {
10711         function(param);
10712     }
10713     EX_CATCH
10714     {
10715         success = false;
10716     }
10717     EX_END_CATCH(RethrowTerminalExceptions);
10718
10719 #endif
10720
10721     return success;
10722 }
10723
10724 /*********************************************************************/
10725 IEEMemoryManager* CEEInfo::getMemoryManager()
10726 {
10727     CONTRACTL {
10728         SO_TOLERANT;
10729         NOTHROW;
10730         GC_NOTRIGGER;
10731         MODE_PREEMPTIVE;
10732     } CONTRACTL_END;
10733
10734     IEEMemoryManager* result = NULL;
10735
10736     JIT_TO_EE_TRANSITION_LEAF();
10737
10738     result = GetEEMemoryManager();
10739
10740     EE_TO_JIT_TRANSITION_LEAF();
10741
10742     return result;
10743 }
10744
10745 /*********************************************************************/
10746 int CEEInfo::doAssert(const char* szFile, int iLine, const char* szExpr)
10747 {
10748     STATIC_CONTRACT_SO_TOLERANT;
10749     STATIC_CONTRACT_THROWS;
10750     STATIC_CONTRACT_GC_TRIGGERS;
10751     STATIC_CONTRACT_MODE_PREEMPTIVE;
10752     STATIC_CONTRACT_DEBUG_ONLY;
10753
10754     int result = 0;
10755
10756     JIT_TO_EE_TRANSITION();
10757
10758 #ifdef CROSSGEN_COMPILE
10759     ThrowHR(COR_E_INVALIDPROGRAM);
10760 #else
10761
10762 #ifdef _DEBUG
10763     BEGIN_DEBUG_ONLY_CODE;
10764     result = _DbgBreakCheck(szFile, iLine, szExpr);
10765     END_DEBUG_ONLY_CODE;
10766 #else // !_DEBUG
10767     result = 1;   // break into debugger
10768 #endif // !_DEBUG
10769
10770 #endif
10771
10772     EE_TO_JIT_TRANSITION();
10773
10774     return result;
10775 }
10776
10777 void CEEInfo::reportFatalError(CorJitResult result)
10778 {
10779     STATIC_CONTRACT_SO_TOLERANT;
10780     STATIC_CONTRACT_THROWS;
10781     STATIC_CONTRACT_GC_TRIGGERS;
10782     STATIC_CONTRACT_MODE_PREEMPTIVE;
10783
10784     JIT_TO_EE_TRANSITION_LEAF();
10785
10786     STRESS_LOG2(LF_JIT,LL_ERROR, "Jit reported error 0x%x while compiling 0x%p\n",
10787                 (int)result, (INT_PTR)getMethodBeingCompiled());
10788
10789     EE_TO_JIT_TRANSITION_LEAF();
10790 }
10791
10792 BOOL CEEInfo::logMsg(unsigned level, const char* fmt, va_list args)
10793 {
10794     STATIC_CONTRACT_SO_TOLERANT;
10795     STATIC_CONTRACT_THROWS;
10796     STATIC_CONTRACT_GC_TRIGGERS;
10797     STATIC_CONTRACT_MODE_PREEMPTIVE;
10798     STATIC_CONTRACT_DEBUG_ONLY;
10799
10800     BOOL result = FALSE;
10801
10802     JIT_TO_EE_TRANSITION_LEAF();
10803
10804 #ifdef LOGGING
10805     if (LoggingOn(LF_JIT, level))
10806     {
10807         LogSpewValist(LF_JIT, level, (char*) fmt, args);
10808         result = TRUE;
10809     }
10810 #endif // LOGGING
10811
10812     EE_TO_JIT_TRANSITION_LEAF();
10813
10814     return result;
10815 }
10816
10817 void CEEInfo::yieldExecution()
10818 {
10819     WRAPPER_NO_CONTRACT;
10820 }
10821
10822
10823 #ifndef CROSSGEN_COMPILE
10824
10825 /*********************************************************************/
10826
10827 void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc    ftnNum,         /* IN  */
10828                                void **            ppIndirection)  /* OUT */
10829 {
10830     CONTRACTL {
10831         SO_TOLERANT;
10832         NOTHROW;
10833         GC_NOTRIGGER;
10834         MODE_PREEMPTIVE;
10835     } CONTRACTL_END;
10836
10837     void* result = NULL;
10838
10839     if (ppIndirection != NULL)
10840         *ppIndirection = NULL;
10841
10842     JIT_TO_EE_TRANSITION_LEAF();
10843
10844     _ASSERTE(ftnNum < CORINFO_HELP_COUNT);
10845
10846     void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10847
10848     size_t dynamicFtnNum = ((size_t)pfnHelper - 1);
10849     if (dynamicFtnNum < DYNAMIC_CORINFO_HELP_COUNT)
10850     {
10851 #ifdef _PREFAST_
10852 #pragma warning(push)
10853 #pragma warning(disable:26001) // "Bounds checked above using the underflow trick"
10854 #endif /*_PREFAST_ */
10855
10856 #if defined(_TARGET_AMD64_)
10857         // To avoid using a jump stub we always call certain helpers using an indirect call.
10858         // Because when using a direct call and the target is father away than 2^31 bytes,
10859         // the direct call instead goes to a jump stub which jumps to the jit helper.
10860         // However in this process the jump stub will corrupt RAX.
10861         //
10862         // The set of helpers for which RAX must be preserved are the profiler probes
10863         // and the STOP_FOR_GC helper which maps to JIT_RareDisableHelper.
10864         // In the case of the STOP_FOR_GC helper RAX can be holding a function return value.
10865         //
10866         if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_STOP_FOR_GC    ||
10867             dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER ||
10868             dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE ||
10869             dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL)
10870         {
10871             _ASSERTE(ppIndirection != NULL);
10872             *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10873             return NULL;
10874         }
10875 #endif
10876
10877 #if defined(ENABLE_FAST_GCPOLL_HELPER)
10878         //always call this indirectly so that we can swap GC Poll helpers.
10879         if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_POLL_GC)
10880         {
10881             _ASSERTE(ppIndirection != NULL);
10882             *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10883             return NULL;
10884         }
10885 #endif
10886
10887         pfnHelper = hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10888
10889 #ifdef _PREFAST_
10890 #pragma warning(pop)
10891 #endif /*_PREFAST_*/
10892     }
10893
10894     _ASSERTE(pfnHelper);
10895
10896     result = (LPVOID)GetEEFuncEntryPoint(pfnHelper);
10897
10898     EE_TO_JIT_TRANSITION_LEAF();
10899
10900     return result;
10901 }
10902
10903 PCODE CEEJitInfo::getHelperFtnStatic(CorInfoHelpFunc ftnNum)
10904 {
10905     LIMITED_METHOD_CONTRACT;
10906
10907     void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10908
10909     // If pfnHelper is an index into the dynamic helper table, it should be less 
10910     // than DYNAMIC_CORINFO_HELP_COUNT.  In this case we need to find the actual pfnHelper 
10911     // using an extra indirection.  Note the special case
10912     // where pfnHelper==0 where pfnHelper-1 will underflow and we will avoid the indirection.
10913     if (((size_t)pfnHelper - 1) < DYNAMIC_CORINFO_HELP_COUNT)
10914     {
10915         pfnHelper = hlpDynamicFuncTable[((size_t)pfnHelper - 1)].pfnHelper;
10916     }
10917
10918     _ASSERTE(pfnHelper != NULL);
10919
10920     return GetEEFuncEntryPoint(pfnHelper);
10921 }
10922
10923 void CEEJitInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
10924 {
10925     CONTRACTL
10926     {
10927         STANDARD_VM_CHECK;
10928         PRECONDITION(CheckPointer(moduleFrom));
10929         PRECONDITION(!IsDynamicScope(moduleFrom));
10930         PRECONDITION(CheckPointer(moduleTo));
10931         PRECONDITION(!IsDynamicScope(moduleTo));
10932         PRECONDITION(moduleFrom != moduleTo);
10933     }
10934     CONTRACTL_END;
10935
10936     // This is only called internaly. JIT-EE transition is not needed.
10937     // JIT_TO_EE_TRANSITION();
10938
10939     Module *dependency = (Module *)moduleTo;
10940     _ASSERTE(!dependency->IsSystem());
10941
10942     if (m_pMethodBeingCompiled->IsLCGMethod())
10943     {
10944         // The context module of the m_pMethodBeingCompiled is irrelevant.  Rather than tracking
10945         // the dependency, we just do immediate activation.
10946         dependency->EnsureActive();
10947     }
10948     else
10949     {
10950 #ifdef FEATURE_LOADER_OPTIMIZATION
10951         Module *context = (Module *)moduleFrom;
10952
10953         // Record active dependency for loader.
10954         context->AddActiveDependency(dependency, FALSE);
10955 #else
10956         dependency->EnsureActive();
10957 #endif
10958     }
10959
10960     // EE_TO_JIT_TRANSITION();
10961 }
10962
10963
10964 // Wrapper around CEEInfo::GetProfilingHandle.  The first time this is called for a
10965 // method desc, it calls through to EEToProfInterfaceImpl::EEFunctionIDMappe and caches the
10966 // result in CEEJitInfo::GetProfilingHandleCache.  Thereafter, this wrapper regurgitates the cached values
10967 // rather than calling into CEEInfo::GetProfilingHandle each time.  This avoids
10968 // making duplicate calls into the profiler's FunctionIDMapper callback.
10969 void CEEJitInfo::GetProfilingHandle(BOOL                      *pbHookFunction,
10970                                     void                     **pProfilerHandle,
10971                                     BOOL                      *pbIndirectedHandles)
10972 {
10973     CONTRACTL {
10974         SO_TOLERANT;
10975         THROWS;
10976         GC_TRIGGERS;
10977         MODE_PREEMPTIVE;
10978     } CONTRACTL_END;
10979     
10980     _ASSERTE(pbHookFunction != NULL);
10981     _ASSERTE(pProfilerHandle != NULL);
10982     _ASSERTE(pbIndirectedHandles != NULL);
10983     
10984     if (!m_gphCache.m_bGphIsCacheValid)
10985     {
10986 #ifdef PROFILING_SUPPORTED
10987         JIT_TO_EE_TRANSITION();
10988
10989         // Cache not filled in, so make our first and only call to CEEInfo::GetProfilingHandle here        
10990
10991         // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
10992         // they shouldnever come here as they are called out in GetCompileFlag
10993         _ASSERTE(!m_pMethodBeingCompiled->IsNoMetadata());
10994
10995         // We pass in the typical method definition to the function mapper because in
10996         // Whidbey all the profiling API transactions are done in terms of typical
10997         // method definitions not instantiations.
10998         BOOL bHookFunction = TRUE;
10999         void * profilerHandle = m_pMethodBeingCompiled;
11000
11001         {
11002             BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
11003             profilerHandle = (void *)g_profControlBlock.pProfInterface->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction);
11004             END_PIN_PROFILER();
11005         }
11006
11007         m_gphCache.m_pvGphProfilerHandle = profilerHandle;
11008         m_gphCache.m_bGphHookFunction = (bHookFunction != FALSE);
11009         m_gphCache.m_bGphIsCacheValid = true;
11010
11011         EE_TO_JIT_TRANSITION();
11012 #endif //PROFILING_SUPPORTED
11013     }
11014         
11015     // Our cache of these values are bitfield bools, but the interface requires
11016     // BOOL.  So to avoid setting aside a staging area on the stack for these
11017     // values, we filled them in directly in the if (not cached yet) case.
11018     *pbHookFunction = (m_gphCache.m_bGphHookFunction != false);
11019
11020     // At this point, the remaining values must be in the cache by now, so use them  
11021     *pProfilerHandle = m_gphCache.m_pvGphProfilerHandle;
11022
11023     //
11024     // This is the JIT case, which is never indirected.
11025     //
11026     *pbIndirectedHandles = FALSE;
11027 }
11028
11029 /*********************************************************************/
11030 void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr)
11031 {
11032     CONTRACTL {
11033         NOTHROW;
11034         GC_TRIGGERS;
11035     } CONTRACTL_END;
11036
11037     CodeHeader* pCodeHeader = GetCodeHeader();
11038     if (pCodeHeader)
11039         jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len);
11040 }
11041
11042 /*********************************************************************/
11043 // Route jit information to the Jit Debug store.
11044 void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
11045                                ICorDebugInfo::OffsetMapping *pMap)
11046 {
11047     CONTRACTL {
11048         SO_TOLERANT;
11049         THROWS;
11050         GC_TRIGGERS;
11051         MODE_PREEMPTIVE;
11052     } CONTRACTL_END;
11053
11054     JIT_TO_EE_TRANSITION();
11055
11056     // We receive ownership of the array
11057     _ASSERTE(m_pOffsetMapping == NULL && m_iOffsetMapping == 0);
11058     m_iOffsetMapping = cMap;
11059     m_pOffsetMapping = pMap;
11060
11061     EE_TO_JIT_TRANSITION();
11062 }
11063
11064 void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
11065 {
11066     CONTRACTL {
11067         SO_TOLERANT;
11068         THROWS;
11069         GC_TRIGGERS;
11070         MODE_PREEMPTIVE;
11071     } CONTRACTL_END;
11072
11073     JIT_TO_EE_TRANSITION();
11074
11075     // We receive ownership of the array
11076     _ASSERTE(m_pNativeVarInfo == NULL && m_iNativeVarInfo == 0);
11077     m_iNativeVarInfo = cVars;
11078     m_pNativeVarInfo = vars;
11079
11080     EE_TO_JIT_TRANSITION();
11081 }
11082
11083 void CEEJitInfo::CompressDebugInfo()
11084 {
11085     CONTRACTL {
11086         SO_TOLERANT;
11087         THROWS;
11088         GC_TRIGGERS;
11089         MODE_PREEMPTIVE;
11090     } CONTRACTL_END;
11091
11092     // Don't track JIT info for DynamicMethods.
11093     if (m_pMethodBeingCompiled->IsDynamicMethod())
11094         return;
11095
11096     if (m_iOffsetMapping == 0 && m_iNativeVarInfo == 0)
11097         return;
11098
11099     JIT_TO_EE_TRANSITION();
11100
11101     EX_TRY
11102     {
11103         PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars(
11104             m_pOffsetMapping, m_iOffsetMapping,
11105             m_pNativeVarInfo, m_iNativeVarInfo,
11106             NULL, 
11107             m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap());
11108
11109         GetCodeHeader()->SetDebugInfo(pDebugInfo);
11110     }
11111     EX_CATCH
11112     {
11113         // Just ignore exceptions here. The debugger's structures will still be in a consistent state.
11114     }
11115     EX_END_CATCH(SwallowAllExceptions)
11116
11117     EE_TO_JIT_TRANSITION();
11118 }
11119
11120 void reservePersonalityRoutineSpace(ULONG &unwindSize)
11121 {
11122 #if defined(_TARGET_X86_)
11123     // Do nothing
11124 #elif defined(_TARGET_AMD64_)
11125     // Add space for personality routine, it must be 4-byte aligned.
11126     // Everything in the UNWIND_INFO up to the variable-sized UnwindCodes
11127     // array has already had its size included in unwindSize by the caller.
11128     unwindSize += sizeof(ULONG);
11129
11130     // Note that the count of unwind codes (2 bytes each) is stored as a UBYTE
11131     // So the largest size could be 510 bytes, plus the header and language
11132     // specific stuff.  This can't overflow.
11133
11134     _ASSERTE(FitsInU4(unwindSize + sizeof(ULONG)));
11135     unwindSize = (ULONG)(ALIGN_UP(unwindSize, sizeof(ULONG)));
11136 #elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
11137     // The JIT passes in a 4-byte aligned block of unwind data.
11138     _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
11139
11140     // Add space for personality routine, it must be 4-byte aligned.
11141     unwindSize += sizeof(ULONG);
11142 #else
11143     PORTABILITY_ASSERT("reservePersonalityRoutineSpace");
11144 #endif // !defined(_TARGET_AMD64_)
11145
11146 }
11147 // Reserve memory for the method/funclet's unwind information.
11148 // Note that this must be called before allocMem. It should be
11149 // called once for the main method, once for every funclet, and
11150 // once for every block of cold code for which allocUnwindInfo
11151 // will be called.
11152 //
11153 // This is necessary because jitted code must allocate all the
11154 // memory needed for the unwindInfo at the allocMem call.
11155 // For prejitted code we split up the unwinding information into
11156 // separate sections .rdata and .pdata.
11157 //
11158 void CEEJitInfo::reserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize)
11159 {
11160 #ifdef WIN64EXCEPTIONS
11161     CONTRACTL {
11162         SO_TOLERANT;
11163         NOTHROW;
11164         GC_NOTRIGGER;
11165         MODE_PREEMPTIVE;
11166     }
11167     CONTRACTL_END;
11168
11169     JIT_TO_EE_TRANSITION_LEAF();
11170
11171     CONSISTENCY_CHECK_MSG(!isColdCode, "Hot/Cold splitting is not supported in jitted code");
11172     _ASSERTE_MSG(m_theUnwindBlock == NULL,
11173         "reserveUnwindInfo() can only be called before allocMem(), but allocMem() has already been called. "
11174         "This may indicate the JIT has hit a NO_WAY assert after calling allocMem(), and is re-JITting. "
11175         "Set COMPlus_JitBreakOnBadCode=1 and rerun to get the real error.");
11176
11177     ULONG currentSize  = unwindSize;
11178
11179     reservePersonalityRoutineSpace(currentSize);
11180
11181     m_totalUnwindSize += currentSize;
11182
11183     m_totalUnwindInfos++;
11184
11185     EE_TO_JIT_TRANSITION_LEAF();
11186 #else // WIN64EXCEPTIONS
11187     LIMITED_METHOD_CONTRACT;
11188     // Dummy implementation to make cross-platform altjit work
11189 #endif // WIN64EXCEPTIONS
11190 }
11191
11192 // Allocate and initialize the .rdata and .pdata for this method or
11193 // funclet and get the block of memory needed for the machine specific
11194 // unwind information (the info for crawling the stack frame).
11195 // Note that allocMem must be called first.
11196 //
11197 // The pHotCode parameter points at the first byte of the code of the method
11198 // The startOffset and endOffset are the region (main or funclet) that
11199 // we are to allocate and create .rdata and .pdata for.
11200 // The pUnwindBlock is copied and contains the .pdata unwind area
11201 //
11202 // Parameters:
11203 //
11204 //    pHotCode        main method code buffer, always filled in
11205 //    pColdCode       always NULL for jitted code
11206 //    startOffset     start of code block, relative to pHotCode
11207 //    endOffset       end of code block, relative to pHotCode
11208 //    unwindSize      size of unwind info pointed to by pUnwindBlock
11209 //    pUnwindBlock    pointer to unwind info
11210 //    funcKind        type of funclet (main method code, handler, filter)
11211 //
11212 void CEEJitInfo::allocUnwindInfo (
11213         BYTE *              pHotCode,              /* IN */
11214         BYTE *              pColdCode,             /* IN */
11215         ULONG               startOffset,           /* IN */
11216         ULONG               endOffset,             /* IN */
11217         ULONG               unwindSize,            /* IN */
11218         BYTE *              pUnwindBlock,          /* IN */
11219         CorJitFuncKind      funcKind               /* IN */
11220         )
11221 {
11222 #ifdef WIN64EXCEPTIONS
11223     CONTRACTL {
11224         SO_TOLERANT;
11225         THROWS;
11226         GC_TRIGGERS;
11227         MODE_PREEMPTIVE;
11228         PRECONDITION(m_theUnwindBlock != NULL);
11229         PRECONDITION(m_usedUnwindSize < m_totalUnwindSize);
11230         PRECONDITION(m_usedUnwindInfos < m_totalUnwindInfos);
11231         PRECONDITION(endOffset <= m_codeSize);
11232     } CONTRACTL_END;
11233
11234     CONSISTENCY_CHECK_MSG(pColdCode == NULL, "Hot/Cold code splitting not supported for jitted code");
11235
11236     JIT_TO_EE_TRANSITION();
11237
11238     //
11239     // We add one callback-type dynamic function table per range section.
11240     // Therefore, the RUNTIME_FUNCTION info is always relative to the
11241     // image base contained in the dynamic function table, which happens
11242     // to be the LowAddress of the range section.  The JIT has no
11243     // knowledge of the range section, so it gives us offsets that are
11244     // relative to the beginning of the method (pHotCode) and we allocate
11245     // and initialize the RUNTIME_FUNCTION data and record its location
11246     // in this function.
11247     //
11248
11249     if (funcKind != CORJIT_FUNC_ROOT)
11250     {
11251         // The main method should be emitted before funclets
11252         _ASSERTE(m_usedUnwindInfos > 0);
11253     }
11254
11255     PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeader->GetUnwindInfo(m_usedUnwindInfos);
11256     m_usedUnwindInfos++;
11257
11258     // Make sure that the RUNTIME_FUNCTION is aligned on a DWORD sized boundary
11259     _ASSERTE(IS_ALIGNED(pRuntimeFunction, sizeof(DWORD)));
11260
11261     UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *) &(m_theUnwindBlock[m_usedUnwindSize]);
11262     m_usedUnwindSize += unwindSize;
11263
11264     reservePersonalityRoutineSpace(m_usedUnwindSize);
11265
11266     _ASSERTE(m_usedUnwindSize <= m_totalUnwindSize);
11267
11268     // Make sure that the UnwindInfo is aligned
11269     _ASSERTE(IS_ALIGNED(pUnwindInfo, sizeof(ULONG)));
11270
11271     /* Calculate Image Relative offset to add to the jit generated unwind offsets */     
11272
11273     TADDR baseAddress = m_moduleBase;
11274
11275     size_t currentCodeSizeT = (size_t)pHotCode - baseAddress;
11276
11277     /* Check if currentCodeSizeT offset fits in 32-bits */
11278     if (!FitsInU4(currentCodeSizeT))
11279     {
11280         _ASSERTE(!"Bad currentCodeSizeT");
11281         COMPlusThrowHR(E_FAIL);
11282     }
11283
11284     /* Check if EndAddress offset fits in 32-bit */
11285     if (!FitsInU4(currentCodeSizeT + endOffset))
11286     {
11287         _ASSERTE(!"Bad currentCodeSizeT");
11288         COMPlusThrowHR(E_FAIL);
11289     }
11290
11291     unsigned currentCodeOffset = (unsigned) currentCodeSizeT;
11292
11293     /* Calculate Unwind Info delta */
11294     size_t unwindInfoDeltaT = (size_t) pUnwindInfo - baseAddress;
11295
11296     /* Check if unwindDeltaT offset fits in 32-bits */
11297     if (!FitsInU4(unwindInfoDeltaT))
11298     {
11299         _ASSERTE(!"Bad unwindInfoDeltaT");
11300         COMPlusThrowHR(E_FAIL);
11301     }
11302
11303     unsigned unwindInfoDelta = (unsigned) unwindInfoDeltaT;
11304
11305     RUNTIME_FUNCTION__SetBeginAddress(pRuntimeFunction, currentCodeOffset + startOffset);
11306
11307 #ifdef _TARGET_AMD64_
11308     pRuntimeFunction->EndAddress        = currentCodeOffset + endOffset;
11309 #endif
11310
11311     RUNTIME_FUNCTION__SetUnwindInfoAddress(pRuntimeFunction, unwindInfoDelta);
11312
11313 #ifdef _DEBUG
11314     if (funcKind != CORJIT_FUNC_ROOT)
11315     {
11316         // Check the the new funclet doesn't overlap any existing funclet.
11317
11318         for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++)
11319         {
11320             PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeader->GetUnwindInfo(iUnwindInfo);
11321             _ASSERTE((   RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress)
11322                      || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction)));
11323         }
11324     }
11325 #endif // _DEBUG
11326
11327     /* Copy the UnwindBlock */
11328     memcpy(pUnwindInfo, pUnwindBlock, unwindSize);
11329
11330 #if defined(_TARGET_X86_)
11331
11332     // Do NOTHING
11333
11334 #elif defined(_TARGET_AMD64_)
11335
11336     pUnwindInfo->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
11337
11338     ULONG * pPersonalityRoutine = (ULONG*)ALIGN_UP(&(pUnwindInfo->UnwindCode[pUnwindInfo->CountOfUnwindCodes]), sizeof(ULONG));
11339     *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
11340
11341 #elif defined(_TARGET_ARM64_)
11342
11343     *(LONG *)pUnwindInfo |= (1 << 20); // X bit
11344
11345     ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
11346     *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
11347
11348 #elif defined(_TARGET_ARM_)
11349
11350     *(LONG *)pUnwindInfo |= (1 << 20); // X bit
11351
11352     ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
11353     *pPersonalityRoutine = (TADDR)ProcessCLRException - baseAddress;
11354
11355 #endif
11356
11357 #if defined(_TARGET_AMD64_)
11358     // Publish the new unwind information in a way that the ETW stack crawler can find
11359     if (m_usedUnwindInfos == m_totalUnwindInfos)
11360         UnwindInfoTable::PublishUnwindInfoForMethod(baseAddress, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos);
11361 #endif // defined(_TARGET_AMD64_)
11362
11363     EE_TO_JIT_TRANSITION();
11364 #else // WIN64EXCEPTIONS
11365     LIMITED_METHOD_CONTRACT;
11366     // Dummy implementation to make cross-platform altjit work
11367 #endif // WIN64EXCEPTIONS
11368 }
11369
11370 void CEEJitInfo::recordCallSite(ULONG                 instrOffset,
11371                                 CORINFO_SIG_INFO *    callSig,
11372                                 CORINFO_METHOD_HANDLE methodHandle)
11373 {
11374     // Currently, only testing tools use this method. The EE itself doesn't need record this information.
11375     // N.B. The memory that callSig points to is managed by the JIT and isn't guaranteed to be around after
11376     // this function returns, so future implementations should copy the sig info if they want it to persist.
11377     LIMITED_METHOD_CONTRACT;
11378 }
11379
11380 // This is a variant for AMD64 or other machines that
11381 // cannot always hold the destination address in a 32-bit location
11382 // A relocation is recorded if we are pre-jitting.
11383 // A jump thunk may be inserted if we are jitting
11384
11385 void CEEJitInfo::recordRelocation(void * location,
11386                                   void * target,
11387                                   WORD   fRelocType,
11388                                   WORD   slot,
11389                                   INT32  addlDelta)
11390 {
11391     CONTRACTL {
11392         SO_TOLERANT;
11393         THROWS;
11394         GC_TRIGGERS;
11395         MODE_PREEMPTIVE;
11396     } CONTRACTL_END;
11397
11398 #ifdef _WIN64
11399     JIT_TO_EE_TRANSITION();
11400
11401     INT64 delta;
11402
11403     switch (fRelocType)
11404     {
11405     case IMAGE_REL_BASED_DIR64:
11406         // Write 64-bits into location
11407         *((UINT64 *) ((BYTE *) location + slot)) = (UINT64) target;
11408         break;
11409
11410 #ifdef _TARGET_AMD64_
11411     case IMAGE_REL_BASED_REL32:
11412         {
11413             target = (BYTE *)target + addlDelta;
11414
11415             INT32 * fixupLocation = (INT32 *) ((BYTE *) location + slot);
11416             BYTE * baseAddr = (BYTE *)fixupLocation + sizeof(INT32);
11417
11418             delta  = (INT64)((BYTE *)target - baseAddr);
11419
11420             //
11421             // Do we need to insert a jump stub to make the source reach the target?
11422             //
11423             // Note that we cannot stress insertion of jump stub by inserting it unconditionally. JIT records the relocations 
11424             // for intra-module jumps and calls. It does not expect the register used by the jump stub to be trashed.
11425             //
11426             if (!FitsInI4(delta))
11427             {
11428                 if (m_fAllowRel32)
11429                 {
11430                     //
11431                     // When m_fAllowRel32 == TRUE, the JIT will use REL32s for both data addresses and direct code targets.
11432                     // Since we cannot tell what the relocation is for, we have to defensively retry.
11433                     //
11434                     m_fJumpStubOverflow = TRUE;
11435                     delta = 0;
11436                 }
11437                 else
11438                 {
11439                     //
11440                     // When m_fAllowRel32 == FALSE, the JIT will use a REL32s for direct code targets only.
11441                     // Use jump stub.
11442                     // 
11443                     delta = rel32UsingJumpStub(fixupLocation, (PCODE)target, m_pMethodBeingCompiled, NULL, false /* throwOnOutOfMemoryWithinRange */);
11444                     if (delta == 0)
11445                     {
11446                         // This forces the JIT to retry the method, which allows us to reserve more space for jump stubs and have a higher chance that
11447                         // we will find space for them.
11448                         m_fJumpStubOverflow = TRUE;
11449                     }
11450
11451                     // Keep track of conservative estimate of how much memory may be needed by jump stubs. We will use it to reserve extra memory 
11452                     // on retry to increase chances that the retry succeeds.
11453                     m_reserveForJumpStubs = max(0x400, m_reserveForJumpStubs + 0x10);
11454                 }
11455             }
11456
11457             LOG((LF_JIT, LL_INFO100000, "Encoded a PCREL32 at" FMT_ADDR "to" FMT_ADDR "+%d,  delta is 0x%04x\n",
11458                  DBG_ADDR(fixupLocation), DBG_ADDR(target), addlDelta, delta));
11459
11460             // Write the 32-bits pc-relative delta into location
11461             *fixupLocation = (INT32) delta;
11462         }
11463         break;
11464 #endif // _TARGET_AMD64_
11465
11466 #ifdef _TARGET_ARM64_
11467     case IMAGE_REL_ARM64_BRANCH26:   // 26 bit offset << 2 & sign ext, for B and BL
11468         {
11469             _ASSERTE(slot == 0);
11470             _ASSERTE(addlDelta == 0);
11471
11472             PCODE branchTarget  = (PCODE) target;
11473             _ASSERTE((branchTarget & 0x3) == 0);   // the low two bits must be zero
11474
11475             PCODE fixupLocation = (PCODE) location;
11476             _ASSERTE((fixupLocation & 0x3) == 0);  // the low two bits must be zero
11477
11478             delta = (INT64)(branchTarget - fixupLocation);
11479             _ASSERTE((delta & 0x3) == 0);          // the low two bits must be zero
11480
11481             UINT32 branchInstr = *((UINT32*) fixupLocation);
11482             branchInstr &= 0xFC000000;  // keep bits 31-26
11483             _ASSERTE((branchInstr & 0x7FFFFFFF) == 0x14000000);  // Must be B or BL
11484
11485             //
11486             // Do we need to insert a jump stub to make the source reach the target?
11487             //
11488             //
11489             if (!FitsInRel28(delta))
11490             {
11491                 // Use jump stub.
11492                 //
11493                 TADDR baseAddr = (TADDR)fixupLocation;
11494                 TADDR loAddr   = baseAddr - 0x08000000;   // -2^27
11495                 TADDR hiAddr   = baseAddr + 0x07FFFFFF;   // +2^27-1
11496
11497                 // Check for the wrap around cases
11498                 if (loAddr > baseAddr)
11499                     loAddr = UINT64_MIN; // overflow
11500                 if (hiAddr < baseAddr)
11501                     hiAddr = UINT64_MAX; // overflow
11502
11503                 PCODE jumpStubAddr = ExecutionManager::jumpStub(m_pMethodBeingCompiled,
11504                                                                 (PCODE)  target,
11505                                                                 (BYTE *) loAddr,
11506                                                                 (BYTE *) hiAddr,
11507                                                                 NULL,
11508                                                                 false);
11509
11510                 // Keep track of conservative estimate of how much memory may be needed by jump stubs. We will use it to reserve extra memory
11511                 // on retry to increase chances that the retry succeeds.
11512                 m_reserveForJumpStubs = max(0x400, m_reserveForJumpStubs + 2*BACK_TO_BACK_JUMP_ALLOCATE_SIZE);
11513
11514                 if (jumpStubAddr == 0)
11515                 {
11516                     // This forces the JIT to retry the method, which allows us to reserve more space for jump stubs and have a higher chance that
11517                     // we will find space for them.
11518                     m_fJumpStubOverflow = TRUE;
11519                     break;
11520                 }
11521
11522                 delta = (INT64)(jumpStubAddr - fixupLocation);
11523
11524                 if (!FitsInRel28(delta))
11525                 {
11526                     _ASSERTE(!"jump stub was not in expected range");
11527                     EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
11528                 }
11529
11530                 LOG((LF_JIT, LL_INFO100000, "Using JumpStub at" FMT_ADDR "that jumps to" FMT_ADDR "\n",
11531                      DBG_ADDR(jumpStubAddr), DBG_ADDR(target)));
11532             }
11533
11534             LOG((LF_JIT, LL_INFO100000, "Encoded a BRANCH26 at" FMT_ADDR "to" FMT_ADDR ",  delta is 0x%04x\n",
11535                  DBG_ADDR(fixupLocation), DBG_ADDR(target), delta));
11536
11537             _ASSERTE(FitsInRel28(delta));
11538
11539             PutArm64Rel28((UINT32*) fixupLocation, (INT32)delta);
11540         }
11541         break;
11542
11543     case IMAGE_REL_ARM64_PAGEBASE_REL21:
11544         {
11545             _ASSERTE(slot == 0);
11546             _ASSERTE(addlDelta == 0);
11547
11548             // Write the 21 bits pc-relative page address into location.
11549             INT64 targetPage = (INT64)target & 0xFFFFFFFFFFFFF000LL;
11550             INT64 locationPage = (INT64)location & 0xFFFFFFFFFFFFF000LL;
11551             INT64 relPage = (INT64)(targetPage - locationPage);
11552             INT32 imm21 = (INT32)(relPage >> 12) & 0x1FFFFF;
11553             PutArm64Rel21((UINT32 *)location, imm21);
11554         }
11555         break;
11556
11557     case IMAGE_REL_ARM64_PAGEOFFSET_12A:
11558         {
11559             _ASSERTE(slot == 0);
11560             _ASSERTE(addlDelta == 0);
11561
11562             // Write the 12 bits page offset into location.
11563             INT32 imm12 = (INT32)target & 0xFFFLL;
11564             PutArm64Rel12((UINT32 *)location, imm12);
11565         }
11566         break;
11567
11568 #endif // _TARGET_ARM64_
11569
11570     default:
11571         _ASSERTE(!"Unknown reloc type");
11572         break;
11573     }
11574
11575     EE_TO_JIT_TRANSITION();
11576 #else // _WIN64
11577     JIT_TO_EE_TRANSITION_LEAF();
11578
11579     // Nothing to do on 32-bit
11580
11581     EE_TO_JIT_TRANSITION_LEAF();
11582 #endif // _WIN64
11583 }
11584
11585 WORD CEEJitInfo::getRelocTypeHint(void * target)
11586 {
11587     CONTRACTL {
11588         SO_TOLERANT;
11589         THROWS;
11590         GC_TRIGGERS;
11591         MODE_PREEMPTIVE;
11592     } CONTRACTL_END;
11593
11594 #ifdef _TARGET_AMD64_
11595     if (m_fAllowRel32)
11596     {
11597         // The JIT calls this method for data addresses only. It always uses REL32s for direct code targets.
11598         if (IsPreferredExecutableRange(target))
11599             return IMAGE_REL_BASED_REL32;
11600     }
11601 #endif // _TARGET_AMD64_
11602
11603     // No hints
11604     return (WORD)-1;
11605 }
11606
11607 void CEEJitInfo::getModuleNativeEntryPointRange(void** pStart, void** pEnd)
11608 {
11609     CONTRACTL {
11610         SO_TOLERANT;
11611         NOTHROW;
11612         GC_NOTRIGGER;
11613         MODE_PREEMPTIVE;
11614     }
11615     CONTRACTL_END;
11616
11617     JIT_TO_EE_TRANSITION_LEAF();
11618
11619     *pStart = *pEnd = 0;
11620
11621     EE_TO_JIT_TRANSITION_LEAF();
11622 }
11623
11624 DWORD CEEJitInfo::getExpectedTargetArchitecture()
11625 {
11626     LIMITED_METHOD_CONTRACT;
11627
11628     return IMAGE_FILE_MACHINE_NATIVE;
11629 }
11630
11631 void CEEInfo::JitProcessShutdownWork()
11632 {
11633     LIMITED_METHOD_CONTRACT;
11634
11635     EEJitManager* jitMgr = ExecutionManager::GetEEJitManager();
11636
11637     // If we didn't load the JIT, there is no work to do.
11638     if (jitMgr->m_jit != NULL)
11639     {
11640         // Do the shutdown work.
11641         jitMgr->m_jit->ProcessShutdownWork(this);
11642     }
11643
11644 #ifdef ALLOW_SXS_JIT
11645     if (jitMgr->m_alternateJit != NULL)
11646     {
11647         jitMgr->m_alternateJit->ProcessShutdownWork(this);
11648     }
11649 #endif // ALLOW_SXS_JIT
11650 }
11651
11652 /*********************************************************************/
11653 InfoAccessType CEEJitInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
11654                                                   mdToken metaTok,
11655                                                   void **ppValue)
11656 {
11657     CONTRACTL {
11658         SO_TOLERANT;
11659         THROWS;
11660         GC_TRIGGERS;
11661         MODE_PREEMPTIVE;
11662     } CONTRACTL_END;
11663
11664     InfoAccessType result = IAT_PVALUE;
11665
11666     JIT_TO_EE_TRANSITION();
11667
11668     _ASSERTE(ppValue != NULL);
11669
11670     if (IsDynamicScope(scopeHnd))
11671     {
11672         *ppValue = (LPVOID)GetDynamicResolver(scopeHnd)->ConstructStringLiteral(metaTok);
11673     }
11674     else
11675     {
11676         *ppValue = (LPVOID)ConstructStringLiteral(scopeHnd, metaTok); // throws
11677     }
11678
11679     EE_TO_JIT_TRANSITION();
11680
11681     return result;
11682 }
11683
11684 /*********************************************************************/
11685 InfoAccessType CEEJitInfo::emptyStringLiteral(void ** ppValue)
11686 {
11687     CONTRACTL {
11688         SO_TOLERANT;
11689         THROWS;
11690         GC_TRIGGERS;
11691         MODE_PREEMPTIVE;
11692     } CONTRACTL_END;
11693
11694     InfoAccessType result = IAT_PVALUE;
11695
11696     if(NingenEnabled())
11697     {
11698         *ppValue = NULL;
11699         return result;
11700     }
11701
11702     JIT_TO_EE_TRANSITION();
11703     *ppValue = StringObject::GetEmptyStringRefPtr();
11704     EE_TO_JIT_TRANSITION();
11705
11706     return result;
11707 }
11708
11709 /*********************************************************************/
11710 void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
11711                                   void **ppIndirection)
11712 {
11713     CONTRACTL {
11714         SO_TOLERANT;
11715         THROWS;
11716         GC_TRIGGERS;
11717         MODE_PREEMPTIVE;
11718     } CONTRACTL_END;
11719
11720     void *result = NULL;
11721
11722     if (ppIndirection != NULL)
11723         *ppIndirection = NULL;
11724
11725     // Do not bother with initialization if we are only verifying the method.
11726     if (isVerifyOnly())
11727     {
11728         return (void *)0x10;
11729     }
11730
11731     JIT_TO_EE_TRANSITION();
11732
11733     FieldDesc* field = (FieldDesc*) fieldHnd;
11734
11735     MethodTable* pMT = field->GetEnclosingMethodTable();
11736
11737     _ASSERTE(!pMT->ContainsGenericVariables());
11738
11739     void *base = NULL;
11740
11741     if (!field->IsRVA())
11742     {
11743         // <REVISIT_TODO>@todo: assert that the current method being compiled is unshared</REVISIT_TODO>
11744         // We must not call here for statics of collectible types.
11745         _ASSERTE(!pMT->Collectible());
11746
11747         // Allocate space for the local class if necessary, but don't trigger
11748         // class construction.
11749         DomainLocalModule *pLocalModule = pMT->GetDomainLocalModule();
11750         pLocalModule->PopulateClass(pMT);
11751
11752         GCX_COOP();
11753
11754         base = (void *) field->GetBase();
11755     }
11756
11757     result = field->GetStaticAddressHandle(base);
11758
11759     EE_TO_JIT_TRANSITION();
11760
11761     return result;
11762 }
11763
11764 /*********************************************************************/
11765 CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
11766                                                             bool* pIsSpeculative)
11767 {
11768     CONTRACTL {
11769         SO_TOLERANT;
11770         THROWS;
11771         GC_TRIGGERS;
11772         MODE_PREEMPTIVE;
11773     } CONTRACTL_END;
11774
11775     CORINFO_CLASS_HANDLE result = NULL;
11776
11777     if (pIsSpeculative != NULL)
11778     {
11779         *pIsSpeculative = true;
11780     }
11781
11782     // Only examine the field's value if we are producing jitted code.
11783     if (isVerifyOnly() || IsCompilingForNGen() || IsReadyToRunCompilation())
11784     {
11785         return result;
11786     }
11787
11788     JIT_TO_EE_TRANSITION();
11789
11790     FieldDesc* field = (FieldDesc*) fieldHnd;
11791     bool isClassInitialized = false;
11792
11793     // We're only interested in ref class typed static fields
11794     // where the field handle specifies a unique location.
11795     if (field->IsStatic() && field->IsObjRef() && !field->IsThreadStatic())
11796     {
11797         MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
11798
11799         if (!pEnclosingMT->IsSharedByGenericInstantiations())
11800         {
11801             // Allocate space for the local class if necessary, but don't trigger
11802             // class construction.
11803             DomainLocalModule *pLocalModule = pEnclosingMT->GetDomainLocalModule();
11804             pLocalModule->PopulateClass(pEnclosingMT);
11805             
11806             GCX_COOP();
11807             
11808             OBJECTREF fieldObj = field->GetStaticOBJECTREF();
11809             VALIDATEOBJECTREF(fieldObj);
11810
11811             // Check for initialization before looking at the value
11812             isClassInitialized = !!pEnclosingMT->IsClassInited();
11813
11814             if (fieldObj != NULL)
11815             {
11816                 MethodTable *pObjMT = fieldObj->GetMethodTable();
11817                 
11818                 // TODO: Check if the jit is allowed to embed this handle in jitted code.
11819                 // Note for the initonly cases it probably won't embed.
11820                 result = (CORINFO_CLASS_HANDLE) pObjMT;
11821             }
11822         }
11823     }
11824
11825     // Did we find a class?
11826     if (result != NULL)
11827     {
11828         // Figure out what to report back.
11829         bool isResultImmutable = isClassInitialized && IsFdInitOnly(field->GetAttributes());
11830
11831         if (pIsSpeculative != NULL)
11832         {
11833             // Caller is ok with potentially mutable results.
11834             *pIsSpeculative = !isResultImmutable;
11835         }
11836         else
11837         {
11838             // Caller only wants to see immutable results.
11839             if (!isResultImmutable)
11840             {
11841                 result = NULL;
11842             }
11843         }
11844     }
11845
11846     EE_TO_JIT_TRANSITION();
11847
11848     return result;
11849 }
11850
11851 /*********************************************************************/
11852 static void *GetClassSync(MethodTable *pMT)
11853 {
11854     STANDARD_VM_CONTRACT;
11855
11856     GCX_COOP();
11857
11858     OBJECTREF ref = pMT->GetManagedClassObject();
11859     return (void*)ref->GetSyncBlock()->GetMonitor();
11860 }
11861
11862 /*********************************************************************/
11863 void* CEEJitInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
11864                                 void **ppIndirection)
11865 {
11866     CONTRACTL {
11867         SO_TOLERANT;
11868         THROWS;
11869         GC_TRIGGERS;
11870         MODE_PREEMPTIVE;
11871     } CONTRACTL_END;
11872
11873     void * result = NULL;
11874
11875     if (ppIndirection != NULL)
11876         *ppIndirection = NULL;
11877
11878     JIT_TO_EE_TRANSITION();
11879
11880     result = GetClassSync((GetMethod(ftnHnd))->GetMethodTable());
11881
11882     EE_TO_JIT_TRANSITION();
11883
11884     return result;
11885 }
11886
11887 /*********************************************************************/
11888 HRESULT CEEJitInfo::allocBBProfileBuffer (
11889     ULONG                         count,
11890     ICorJitInfo::ProfileBuffer ** profileBuffer
11891     )
11892 {
11893     CONTRACTL {
11894         SO_TOLERANT;
11895         THROWS;
11896         GC_TRIGGERS;
11897         MODE_PREEMPTIVE;
11898     } CONTRACTL_END;
11899
11900     HRESULT hr = E_FAIL;
11901
11902     JIT_TO_EE_TRANSITION();
11903
11904 #ifdef FEATURE_PREJIT
11905
11906     // We need to know the code size. Typically we can get the code size
11907     // from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so
11908     // for that case we need to use DynamicResolver to get the code size.
11909
11910     unsigned codeSize = 0; 
11911     if (m_pMethodBeingCompiled->IsDynamicMethod())
11912     {
11913         unsigned stackSize, ehSize;
11914         CorInfoOptions options;
11915         DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver();        
11916         pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize);
11917     }
11918     else
11919     {
11920         codeSize = m_ILHeader->GetCodeSize();    
11921     }
11922     
11923     *profileBuffer = m_pMethodBeingCompiled->GetLoaderModule()->AllocateProfileBuffer(m_pMethodBeingCompiled->GetMemberDef(), count, codeSize);
11924     hr = (*profileBuffer ? S_OK : E_OUTOFMEMORY);
11925 #else // FEATURE_PREJIT
11926     _ASSERTE(!"allocBBProfileBuffer not implemented on CEEJitInfo!");
11927     hr = E_NOTIMPL;
11928 #endif // !FEATURE_PREJIT
11929
11930     EE_TO_JIT_TRANSITION();
11931     
11932     return hr;
11933 }
11934
11935 // Consider implementing getBBProfileData on CEEJitInfo.  This will allow us
11936 // to use profile info in codegen for non zapped images.
11937 HRESULT CEEJitInfo::getBBProfileData (
11938     CORINFO_METHOD_HANDLE         ftnHnd,
11939     ULONG *                       size,
11940     ICorJitInfo::ProfileBuffer ** profileBuffer,
11941     ULONG *                       numRuns
11942     )
11943 {
11944     LIMITED_METHOD_CONTRACT;
11945     _ASSERTE(!"getBBProfileData not implemented on CEEJitInfo!");
11946     return E_NOTIMPL;
11947 }
11948
11949 void CEEJitInfo::allocMem (
11950     ULONG               hotCodeSize,    /* IN */
11951     ULONG               coldCodeSize,   /* IN */
11952     ULONG               roDataSize,     /* IN */
11953     ULONG               xcptnsCount,    /* IN */
11954     CorJitAllocMemFlag  flag,           /* IN */
11955     void **             hotCodeBlock,   /* OUT */
11956     void **             coldCodeBlock,  /* OUT */
11957     void **             roDataBlock     /* OUT */
11958             )
11959 {
11960     CONTRACTL {
11961         SO_TOLERANT;
11962         THROWS;
11963         GC_TRIGGERS;
11964         MODE_PREEMPTIVE;
11965     } CONTRACTL_END;
11966
11967     JIT_TO_EE_TRANSITION();
11968
11969     _ASSERTE(coldCodeSize == 0);
11970     if (coldCodeBlock)
11971     {
11972         *coldCodeBlock = NULL;
11973     }
11974
11975     ULONG codeSize      = hotCodeSize;
11976     void **codeBlock    = hotCodeBlock;
11977
11978     S_SIZE_T totalSize = S_SIZE_T(codeSize);
11979
11980     size_t roDataAlignment = sizeof(void*);
11981     if ((flag & CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN)!= 0)
11982     {
11983         roDataAlignment = 16;
11984     }
11985     else if (roDataSize >= 8)
11986     {
11987         roDataAlignment = 8;
11988     }
11989     if (roDataSize > 0)
11990     {
11991         size_t codeAlignment = ((flag & CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN)!= 0)
11992                                ? 16 : sizeof(void*);
11993         totalSize.AlignUp(codeAlignment);
11994         if (roDataAlignment > codeAlignment) {
11995             // Add padding to align read-only data.
11996             totalSize += (roDataAlignment - codeAlignment);
11997         }
11998         totalSize += roDataSize;
11999     }
12000
12001 #ifdef WIN64EXCEPTIONS
12002     totalSize.AlignUp(sizeof(DWORD));
12003     totalSize += m_totalUnwindSize;
12004 #endif
12005
12006     _ASSERTE(m_CodeHeader == 0 &&
12007             // The jit-compiler sometimes tries to compile a method a second time
12008             // if it failed the first time. In such a situation, m_CodeHeader may
12009             // have already been assigned. Its OK to ignore this assert in such a
12010             // situation - we will leak some memory, but that is acceptable
12011             // since this should happen very rarely.
12012             "Note that this may fire if the JITCompiler tries to recompile a method");
12013
12014     if( totalSize.IsOverflow() )
12015     {
12016         COMPlusThrowHR(CORJIT_OUTOFMEM);
12017     }
12018
12019     m_CodeHeader = m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), flag
12020 #ifdef WIN64EXCEPTIONS
12021                                            , m_totalUnwindInfos
12022                                            , &m_moduleBase
12023 #endif
12024                                            );
12025
12026     BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress();
12027
12028     *codeBlock = current;
12029     current += codeSize;
12030
12031     if (roDataSize > 0)
12032     {
12033         current = (BYTE *)ALIGN_UP(current, roDataAlignment);
12034         *roDataBlock = current;
12035         current += roDataSize;
12036     }
12037     else
12038     {
12039         *roDataBlock = NULL;
12040     }
12041
12042 #ifdef WIN64EXCEPTIONS
12043     current = (BYTE *)ALIGN_UP(current, sizeof(DWORD));
12044
12045     m_theUnwindBlock = current;
12046     current += m_totalUnwindSize;
12047 #endif
12048
12049     _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value());
12050
12051 #ifdef _DEBUG
12052     m_codeSize = codeSize;
12053 #endif  // _DEBUG
12054
12055     EE_TO_JIT_TRANSITION();
12056 }
12057
12058 /*********************************************************************/
12059 void * CEEJitInfo::allocGCInfo (size_t size)
12060 {
12061     CONTRACTL {
12062         SO_TOLERANT;
12063         THROWS;
12064         GC_TRIGGERS;
12065         MODE_PREEMPTIVE;
12066     } CONTRACTL_END;
12067
12068     void * block = NULL;
12069
12070     JIT_TO_EE_TRANSITION();
12071
12072     _ASSERTE(m_CodeHeader != 0);
12073     _ASSERTE(m_CodeHeader->GetGCInfo() == 0);
12074
12075 #ifdef _WIN64
12076     if (size & 0xFFFFFFFF80000000LL)
12077     {
12078         COMPlusThrowHR(CORJIT_OUTOFMEM);
12079     }
12080 #endif // _WIN64
12081
12082     block = m_jitManager->allocGCInfo(m_CodeHeader,(DWORD)size, &m_GCinfo_len);
12083     if (!block)
12084     {
12085         COMPlusThrowHR(CORJIT_OUTOFMEM);
12086     }
12087
12088     _ASSERTE(m_CodeHeader->GetGCInfo() != 0 && block == m_CodeHeader->GetGCInfo());
12089
12090     EE_TO_JIT_TRANSITION();
12091
12092     return block;
12093 }
12094
12095 /*********************************************************************/
12096 void CEEJitInfo::setEHcount (
12097         unsigned      cEH)
12098 {
12099     CONTRACTL {
12100         SO_TOLERANT;
12101         THROWS;
12102         GC_TRIGGERS;
12103         MODE_PREEMPTIVE;
12104     } CONTRACTL_END;
12105
12106     JIT_TO_EE_TRANSITION();
12107
12108     _ASSERTE(cEH != 0);
12109     _ASSERTE(m_CodeHeader != 0);
12110     _ASSERTE(m_CodeHeader->GetEHInfo() == 0);
12111
12112     EE_ILEXCEPTION* ret;
12113     ret = m_jitManager->allocEHInfo(m_CodeHeader,cEH, &m_EHinfo_len);
12114     _ASSERTE(ret);      // allocEHInfo throws if there's not enough memory
12115
12116     _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && m_CodeHeader->GetEHInfo()->EHCount() == cEH);
12117
12118     EE_TO_JIT_TRANSITION();
12119 }
12120
12121 /*********************************************************************/
12122 void CEEJitInfo::setEHinfo (
12123         unsigned      EHnumber,
12124         const CORINFO_EH_CLAUSE* clause)
12125 {
12126     CONTRACTL {
12127         SO_TOLERANT;
12128         THROWS;
12129         GC_TRIGGERS;
12130         MODE_PREEMPTIVE;
12131     } CONTRACTL_END;
12132
12133     JIT_TO_EE_TRANSITION();
12134
12135     // <REVISIT_TODO> Fix make the Code Manager EH clauses EH_INFO+</REVISIT_TODO>
12136     _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && EHnumber < m_CodeHeader->GetEHInfo()->EHCount());
12137
12138     EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeader->GetEHInfo()->EHClause(EHnumber);
12139
12140     pEHClause->TryStartPC     = clause->TryOffset;
12141     pEHClause->TryEndPC       = clause->TryLength;
12142     pEHClause->HandlerStartPC = clause->HandlerOffset;
12143     pEHClause->HandlerEndPC   = clause->HandlerLength;
12144     pEHClause->ClassToken     = clause->ClassToken;
12145     pEHClause->Flags          = (CorExceptionFlag)clause->Flags;
12146
12147     LOG((LF_EH, LL_INFO1000000, "Setting EH clause #%d for %s::%s\n", EHnumber, m_pMethodBeingCompiled->m_pszDebugClassName, m_pMethodBeingCompiled->m_pszDebugMethodName));
12148     LOG((LF_EH, LL_INFO1000000, "    Flags         : 0x%08lx  ->  0x%08lx\n",            clause->Flags,         pEHClause->Flags));
12149     LOG((LF_EH, LL_INFO1000000, "    TryOffset     : 0x%08lx  ->  0x%08lx (startpc)\n",  clause->TryOffset,     pEHClause->TryStartPC));
12150     LOG((LF_EH, LL_INFO1000000, "    TryLength     : 0x%08lx  ->  0x%08lx (endpc)\n",    clause->TryLength,     pEHClause->TryEndPC));
12151     LOG((LF_EH, LL_INFO1000000, "    HandlerOffset : 0x%08lx  ->  0x%08lx\n",            clause->HandlerOffset, pEHClause->HandlerStartPC));
12152     LOG((LF_EH, LL_INFO1000000, "    HandlerLength : 0x%08lx  ->  0x%08lx\n",            clause->HandlerLength, pEHClause->HandlerEndPC));
12153     LOG((LF_EH, LL_INFO1000000, "    ClassToken    : 0x%08lx  ->  0x%08lx\n",            clause->ClassToken,    pEHClause->ClassToken));
12154     LOG((LF_EH, LL_INFO1000000, "    FilterOffset  : 0x%08lx  ->  0x%08lx\n",            clause->FilterOffset,  pEHClause->FilterOffset));
12155
12156     if (m_pMethodBeingCompiled->IsDynamicMethod() &&
12157         ((pEHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) == 0) &&
12158         (clause->ClassToken != NULL))
12159     {
12160         MethodDesc * pMD; FieldDesc * pFD;
12161         m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver()->ResolveToken(clause->ClassToken, (TypeHandle *)&pEHClause->TypeHandle, &pMD, &pFD);
12162         SetHasCachedTypeHandle(pEHClause);
12163         LOG((LF_EH, LL_INFO1000000, "  CachedTypeHandle: 0x%08lx  ->  0x%08lx\n",        clause->ClassToken,    pEHClause->TypeHandle));
12164     }
12165
12166     EE_TO_JIT_TRANSITION();
12167 }
12168
12169 /*********************************************************************/
12170 // get individual exception handler
12171 void CEEJitInfo::getEHinfo(
12172                               CORINFO_METHOD_HANDLE  ftn,      /* IN  */
12173                               unsigned               EHnumber, /* IN  */
12174                               CORINFO_EH_CLAUSE*     clause)   /* OUT */
12175 {
12176     CONTRACTL {
12177         SO_TOLERANT;
12178         THROWS;
12179         GC_TRIGGERS;
12180         MODE_PREEMPTIVE;
12181     } CONTRACTL_END;
12182
12183     JIT_TO_EE_TRANSITION();
12184
12185     if (IsDynamicMethodHandle(ftn))
12186     {
12187         GetMethod(ftn)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
12188     }
12189     else
12190     {
12191         _ASSERTE(ftn == CORINFO_METHOD_HANDLE(m_pMethodBeingCompiled));  // For now only support if the method being jitted
12192         getEHinfoHelper(ftn, EHnumber, clause, m_ILHeader);
12193     }
12194
12195     EE_TO_JIT_TRANSITION();
12196 }
12197 #endif // CROSSGEN_COMPILE
12198
12199 #if defined(CROSSGEN_COMPILE)
12200 EXTERN_C ICorJitCompiler* __stdcall getJit();
12201 #endif // defined(CROSSGEN_COMPILE)
12202
12203 #ifdef FEATURE_INTERPRETER
12204 static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr,
12205                                                       CEEInfo *comp,
12206                                                       struct CORINFO_METHOD_INFO *info,
12207                                                       unsigned flags,
12208                                                       BYTE **nativeEntry,
12209                                                       ULONG *nativeSizeOfCode)
12210 {
12211     STATIC_CONTRACT_THROWS;
12212     STATIC_CONTRACT_GC_TRIGGERS;
12213     STATIC_CONTRACT_MODE_PREEMPTIVE;
12214     STATIC_CONTRACT_SO_INTOLERANT;
12215
12216     SString namespaceOrClassName, methodName, methodSignature;
12217     // Fire an ETW event to mark the beginning of JIT'ing
12218     ETW::MethodLog::MethodJitting(reinterpret_cast<MethodDesc*>(info->ftn), &namespaceOrClassName, &methodName, &methodSignature);
12219
12220     CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode);
12221
12222     // Logically, it would seem that the end-of-JITting ETW even should go here, but it must come after the native code has been
12223     // set for the given method desc, which happens in a caller.
12224
12225     return ret;
12226 }
12227 #endif // FEATURE_INTERPRETER
12228
12229 //
12230 // Helper function because can't have dtors in BEGIN_SO_TOLERANT_CODE.
12231 //
12232 CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr,
12233                                  CEEInfo *comp,
12234                                  struct CORINFO_METHOD_INFO *info,
12235                                  CORJIT_FLAGS jitFlags,
12236                                  BYTE **nativeEntry,
12237                                  ULONG *nativeSizeOfCode)
12238 {
12239     STATIC_CONTRACT_THROWS;
12240     STATIC_CONTRACT_GC_TRIGGERS;
12241     STATIC_CONTRACT_MODE_PREEMPTIVE;
12242     STATIC_CONTRACT_SO_INTOLERANT;
12243
12244     CorJitResult ret = CORJIT_SKIPPED;   // Note that CORJIT_SKIPPED is an error exit status code
12245
12246
12247     comp->setJitFlags(jitFlags);
12248
12249 #ifdef FEATURE_STACK_SAMPLING
12250     // SO_INTOLERANT due to init affecting global state.
12251     static ConfigDWORD s_stackSamplingEnabled;
12252     bool samplingEnabled = (s_stackSamplingEnabled.val(CLRConfig::UNSUPPORTED_StackSamplingEnabled) != 0);
12253 #endif
12254
12255     BEGIN_SO_TOLERANT_CODE(GetThread());
12256
12257
12258 #if defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
12259     if (FAILED(ret) && jitMgr->m_alternateJit
12260 #ifdef FEATURE_STACK_SAMPLING
12261         && (!samplingEnabled || (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)))
12262 #endif
12263        )
12264     {
12265         ret = jitMgr->m_alternateJit->compileMethod( comp,
12266                                                      info,
12267                                                      CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12268                                                      nativeEntry,
12269                                                      nativeSizeOfCode );
12270
12271 #ifdef FEATURE_STACK_SAMPLING
12272         if (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND))
12273         {
12274             // Don't bother with failures if we couldn't collect a trace.
12275             ret = CORJIT_OK;
12276         }
12277 #endif // FEATURE_STACK_SAMPLING
12278
12279         // If we failed to jit, then fall back to the primary Jit.
12280         if (FAILED(ret))
12281         {
12282             // Consider adding this call:
12283             //      ((CEEJitInfo*)comp)->BackoutJitData(jitMgr);
12284             ((CEEJitInfo*)comp)->ResetForJitRetry();
12285             ret = CORJIT_SKIPPED;
12286         }
12287     }
12288 #endif // defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
12289
12290 #ifdef FEATURE_INTERPRETER
12291     static ConfigDWORD s_InterpreterFallback;
12292
12293     bool isInterpreterStub   = false;
12294     bool interpreterFallback = (s_InterpreterFallback.val(CLRConfig::INTERNAL_InterpreterFallback) != 0);
12295
12296     if (interpreterFallback == false)
12297     {
12298         // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
12299         // (We assume that importation is completely architecture-independent, or at least nearly so.)
12300         if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
12301         {
12302             if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
12303             {
12304                 isInterpreterStub = true;
12305             }
12306         }
12307     }
12308     
12309     if (FAILED(ret) && jitMgr->m_jit)
12310     {
12311         ret = CompileMethodWithEtwWrapper(jitMgr, 
12312                                           comp,
12313                                           info,
12314                                           CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12315                                           nativeEntry,
12316                                           nativeSizeOfCode);
12317     }
12318
12319     if (interpreterFallback == true)
12320     {
12321         // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
12322         // (We assume that importation is completely architecture-independent, or at least nearly so.)
12323         if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
12324         {
12325             if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
12326             {
12327                 isInterpreterStub = true;
12328             }
12329         }
12330     }
12331 #else
12332     if (FAILED(ret))
12333     {
12334         ret = jitMgr->m_jit->compileMethod( comp,
12335                                             info,
12336                                             CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12337                                             nativeEntry,
12338                                             nativeSizeOfCode);
12339     }
12340 #endif // FEATURE_INTERPRETER
12341
12342 #if !defined(CROSSGEN_COMPILE)
12343     // Cleanup any internal data structures allocated 
12344     // such as IL code after a successfull JIT compile
12345     // If the JIT fails we keep the IL around and will
12346     // try reJIT the same IL.  VSW 525059
12347     //
12348     if (SUCCEEDED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !((CEEJitInfo*)comp)->JitAgain())
12349     {
12350         ((CEEJitInfo*)comp)->CompressDebugInfo();
12351
12352 #ifdef FEATURE_INTERPRETER
12353         // We do this cleanup in the prestub, where we know whether the method
12354         // has been interpreted.
12355 #else
12356         comp->MethodCompileComplete(info->ftn);
12357 #endif // FEATURE_INTERPRETER
12358     }
12359 #endif // !defined(CROSSGEN_COMPILE)
12360     
12361
12362 #if defined(FEATURE_GDBJIT)
12363     bool isJittedEntry = SUCCEEDED(ret) && *nativeEntry != NULL;
12364
12365 #ifdef FEATURE_INTERPRETER
12366     isJittedEntry &= !isInterpreterStub;
12367 #endif // FEATURE_INTERPRETER
12368
12369     if (isJittedEntry)
12370     {
12371         CodeHeader* pCH = ((CodeHeader*)((PCODE)*nativeEntry & ~1)) - 1;
12372         pCH->SetCalledMethods((PTR_VOID)comp->GetCalledMethods());
12373     }
12374 #endif
12375
12376     END_SO_TOLERANT_CODE;
12377
12378     return ret;
12379 }
12380
12381
12382 /*********************************************************************/
12383 CorJitResult invokeCompileMethod(EEJitManager *jitMgr,
12384                                  CEEInfo *comp,
12385                                  struct CORINFO_METHOD_INFO *info,
12386                                  CORJIT_FLAGS jitFlags,
12387                                  BYTE **nativeEntry,
12388                                  ULONG *nativeSizeOfCode)
12389 {
12390     CONTRACTL {
12391         THROWS;
12392         GC_TRIGGERS;
12393         MODE_COOPERATIVE;
12394     } CONTRACTL_END;
12395     //
12396     // The JIT runs in preemptive mode
12397     //
12398
12399     GCX_PREEMP();
12400
12401     CorJitResult ret = invokeCompileMethodHelper(jitMgr, comp, info, jitFlags, nativeEntry, nativeSizeOfCode);
12402
12403     //
12404     // Verify that we are still in preemptive mode when we return
12405     // from the JIT
12406     //
12407
12408     _ASSERTE(GetThread()->PreemptiveGCDisabled() == FALSE);
12409
12410     return ret;
12411 }
12412
12413 CorJitResult CallCompileMethodWithSEHWrapper(EEJitManager *jitMgr,
12414                                 CEEInfo *comp,
12415                                 struct CORINFO_METHOD_INFO *info,
12416                                 CORJIT_FLAGS flags,
12417                                 BYTE **nativeEntry,
12418                                 ULONG *nativeSizeOfCode,
12419                                 MethodDesc *ftn)
12420 {
12421     // no dynamic contract here because SEH is used, with a finally clause
12422     STATIC_CONTRACT_NOTHROW;
12423     STATIC_CONTRACT_GC_TRIGGERS;
12424
12425     LOG((LF_CORDB, LL_EVERYTHING, "CallCompileMethodWithSEHWrapper called...\n"));
12426
12427     struct Param
12428     {
12429         EEJitManager *jitMgr;
12430         CEEInfo *comp;
12431         struct CORINFO_METHOD_INFO *info;
12432         CORJIT_FLAGS flags;
12433         BYTE **nativeEntry;
12434         ULONG *nativeSizeOfCode;
12435         MethodDesc *ftn;
12436         CorJitResult res;
12437     }; Param param;
12438     param.jitMgr = jitMgr;
12439     param.comp = comp;
12440     param.info = info;
12441     param.flags = flags;
12442     param.nativeEntry = nativeEntry;
12443     param.nativeSizeOfCode = nativeSizeOfCode;
12444     param.ftn = ftn;
12445     param.res = CORJIT_INTERNALERROR;
12446
12447     PAL_TRY(Param *, pParam, &param)
12448     {
12449         //
12450         // Call out to the JIT-compiler
12451         //
12452
12453         pParam->res = invokeCompileMethod( pParam->jitMgr,
12454                                            pParam->comp,
12455                                            pParam->info,
12456                                            pParam->flags,
12457                                            pParam->nativeEntry,
12458                                            pParam->nativeSizeOfCode);
12459     }
12460     PAL_FINALLY
12461     {
12462 #if defined(DEBUGGING_SUPPORTED) && !defined(CROSSGEN_COMPILE)
12463         if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) &&
12464             !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MCJIT_BACKGROUND)
12465 #ifdef FEATURE_STACK_SAMPLING
12466             && !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)
12467 #endif // FEATURE_STACK_SAMPLING
12468            )
12469         {
12470             //
12471             // Notify the debugger that we have successfully jitted the function
12472             //
12473             if (g_pDebugInterface)
12474             {
12475                 if (param.res == CORJIT_OK && !((CEEJitInfo*)param.comp)->JitAgain())
12476                 {
12477                     g_pDebugInterface->JITComplete(ftn, (TADDR)*nativeEntry);
12478                 }
12479             }
12480         }
12481 #endif // DEBUGGING_SUPPORTED && !CROSSGEN_COMPILE
12482     }
12483     PAL_ENDTRY
12484
12485     return param.res;
12486 }
12487
12488 /*********************************************************************/
12489 // Figures out the compile flags that are used by both JIT and NGen
12490
12491 /* static */ CORJIT_FLAGS CEEInfo::GetBaseCompileFlags(MethodDesc * ftn)
12492 {
12493      CONTRACTL {
12494         THROWS;
12495         GC_TRIGGERS;
12496     } CONTRACTL_END;
12497
12498     //
12499     // Figure out the code quality flags
12500     //
12501
12502     CORJIT_FLAGS flags;
12503     if (g_pConfig->JitFramed())
12504         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12505     if (g_pConfig->JitAlignLoops())
12506         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_ALIGN_LOOPS);
12507     if (ftn->IsVersionableWithJumpStamp() || g_pConfig->AddRejitNops())
12508         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_REJIT_NOPS);
12509 #ifdef _TARGET_X86_
12510     if (g_pConfig->PInvokeRestoreEsp(ftn->GetModule()->IsPreV4Assembly()))
12511         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PINVOKE_RESTORE_ESP);
12512 #endif // _TARGET_X86_
12513
12514     //See if we should instruct the JIT to emit calls to JIT_PollGC for thread suspension.  If we have a
12515     //non-default value in the EE Config, then use that.  Otherwise select the platform specific default.
12516 #ifdef FEATURE_ENABLE_GCPOLL
12517     EEConfig::GCPollType pollType = g_pConfig->GetGCPollType();
12518     if (EEConfig::GCPOLL_TYPE_POLL == pollType)
12519         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_CALLS);
12520     else if (EEConfig::GCPOLL_TYPE_INLINE == pollType)
12521         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_INLINE);
12522 #endif //FEATURE_ENABLE_GCPOLL
12523
12524     // Set flags based on method's ImplFlags.
12525     if (!ftn->IsNoMetadata())
12526     {
12527          DWORD dwImplFlags = 0;
12528          IfFailThrow(ftn->GetMDImport()->GetMethodImplProps(ftn->GetMemberDef(), NULL, &dwImplFlags));
12529         
12530          if (IsMiNoOptimization(dwImplFlags))
12531          {
12532              flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12533          }
12534
12535          // Always emit frames for methods marked no-inline (see #define ETW_EBP_FRAMED in the JIT)
12536          if (IsMiNoInlining(dwImplFlags))
12537          {
12538              flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12539          }
12540     }
12541
12542     return flags;
12543 }
12544
12545 /*********************************************************************/
12546 // Figures out (some of) the flags to use to compile the method
12547 // Returns the new set to use
12548
12549 CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags)
12550 {
12551     STANDARD_VM_CONTRACT;
12552
12553     //Right now if we don't have a debug interface on CoreCLR, we can't generate debug info.  So, in those
12554     //cases don't attempt it.
12555     if (!g_pDebugInterface)
12556         return flags;
12557
12558 #ifdef DEBUGGING_SUPPORTED
12559
12560 #ifdef _DEBUG
12561     if (g_pConfig->GenDebuggableCode())
12562         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12563 #endif // _DEBUG
12564
12565 #ifdef EnC_SUPPORTED
12566     if (pModule->IsEditAndContinueEnabled())
12567     {
12568         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_EnC);
12569     }
12570 #endif // EnC_SUPPORTED
12571
12572     // Debug info is always tracked
12573     flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12574 #endif // DEBUGGING_SUPPORTED
12575
12576     if (CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
12577     {
12578         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12579     }
12580
12581     if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12582     {
12583         // If we are only verifying the method, dont need any debug info and this
12584         // prevents getVars()/getBoundaries() from being called unnecessarily.
12585         flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12586         flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12587     }
12588
12589     return flags;
12590 }
12591
12592 CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHOD_INFO * methodInfo)
12593 {
12594     STANDARD_VM_CONTRACT;
12595
12596     _ASSERTE(methodInfo->regionKind ==  CORINFO_REGION_JIT);
12597
12598     //
12599     // Get the compile flags that are shared between JIT and NGen
12600     //
12601     flags.Add(CEEInfo::GetBaseCompileFlags(ftn));
12602
12603     //
12604     // Get CPU specific flags
12605     //
12606     if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12607     {
12608         flags.Add(ExecutionManager::GetEEJitManager()->GetCPUCompileFlags());
12609     }
12610
12611     //
12612     // Find the debugger and profiler related flags
12613     //
12614
12615 #ifdef DEBUGGING_SUPPORTED
12616     flags.Add(GetDebuggerCompileFlags(ftn->GetModule(), flags));
12617 #endif
12618
12619 #ifdef PROFILING_SUPPORTED
12620     if (CORProfilerTrackEnterLeave() && !ftn->IsNoMetadata())
12621         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE);
12622
12623     if (CORProfilerTrackTransitions())
12624         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_NO_PINVOKE_INLINE);
12625 #endif // PROFILING_SUPPORTED
12626
12627     // Set optimization flags
12628     if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT))
12629     {
12630         unsigned optType = g_pConfig->GenOptimizeType();
12631         _ASSERTE(optType <= OPT_RANDOM);
12632
12633         if (optType == OPT_RANDOM)
12634             optType = methodInfo->ILCodeSize % OPT_RANDOM;
12635
12636         if (g_pConfig->JitMinOpts())
12637             flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12638
12639         if (optType == OPT_SIZE)
12640         {
12641             flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SIZE_OPT);
12642         }
12643         else if (optType == OPT_SPEED)
12644         {
12645             flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SPEED_OPT);
12646         }
12647     }
12648
12649     flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12650
12651     if (ftn->IsILStub())
12652     {
12653         // no debug info available for IL stubs
12654         flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12655     }
12656
12657     return flags;
12658 }
12659
12660 // ********************************************************************
12661
12662 // Throw the right type of exception for the given JIT result
12663
12664 void ThrowExceptionForJit(HRESULT res)
12665 {
12666     CONTRACTL
12667     {
12668         THROWS;
12669         GC_NOTRIGGER;
12670         SO_INTOLERANT;
12671         MODE_ANY;
12672     }
12673     CONTRACTL_END;
12674     switch (res)
12675     {
12676         case CORJIT_OUTOFMEM:
12677             COMPlusThrowOM();              
12678             break; 
12679             
12680         case CORJIT_INTERNALERROR:
12681             COMPlusThrow(kInvalidProgramException, (UINT) IDS_EE_JIT_COMPILER_ERROR);
12682             break;   
12683
12684         case CORJIT_BADCODE:
12685         default:                    
12686             COMPlusThrow(kInvalidProgramException);                                            
12687             break;
12688     }
12689  }
12690
12691 // ********************************************************************
12692 #ifdef _DEBUG
12693 LONG g_JitCount = 0;
12694 #endif
12695
12696 //#define PERF_TRACK_METHOD_JITTIMES
12697 #ifdef _TARGET_AMD64_
12698 BOOL g_fAllowRel32 = TRUE;
12699 #endif
12700
12701
12702 // ********************************************************************
12703 //                  README!!
12704 // ********************************************************************
12705
12706 // The reason that this is named UnsafeJitFunction is that this helper
12707 // method is not thread safe!  When multiple threads get in here for
12708 // the same pMD, ALL of them MUST return the SAME value.
12709 // To insure that this happens you must call MakeJitWorker.
12710 // It creates a DeadlockAware list of methods being jitted and prevents us
12711 // from trying to jit the same method more that once.
12712 //
12713 // Calls to this method that occur to check if inlining can occur on x86,
12714 // are OK since they discard the return value of this method.
12715
12716 PCODE UnsafeJitFunction(MethodDesc* ftn, COR_ILMETHOD_DECODER* ILHeader, CORJIT_FLAGS flags,
12717                         ULONG * pSizeOfCode)
12718 {
12719     STANDARD_VM_CONTRACT;
12720
12721     PCODE ret = NULL;
12722
12723     COOPERATIVE_TRANSITION_BEGIN();
12724
12725 #ifdef FEATURE_PREJIT
12726
12727     if (g_pConfig->RequireZaps() == EEConfig::REQUIRE_ZAPS_ALL &&
12728         ftn->GetModule()->GetDomainFile()->IsZapRequired() &&
12729         PartialNGenStressPercentage() == 0 && 
12730 #ifdef FEATURE_STACK_SAMPLING
12731         !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND) &&
12732 #endif
12733         !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12734     {
12735         StackSString ss(SString::Ascii, "ZapRequire: JIT compiler invoked for ");
12736         TypeString::AppendMethodInternal(ss, ftn);
12737
12738 #ifdef _DEBUG
12739         // Assert as some test may not check their error codes well. So throwing an
12740         // exception may not cause a test failure (as it should).
12741         StackScratchBuffer scratch;
12742         DbgAssertDialog(__FILE__, __LINE__, (char*)ss.GetUTF8(scratch));
12743 #endif // _DEBUG
12744
12745         COMPlusThrowNonLocalized(kFileNotFoundException, ss.GetUnicode());
12746     }
12747
12748 #endif // FEATURE_PREJIT
12749
12750 #ifndef CROSSGEN_COMPILE
12751     EEJitManager *jitMgr = ExecutionManager::GetEEJitManager();
12752     if (!jitMgr->LoadJIT())
12753     {
12754 #ifdef ALLOW_SXS_JIT
12755         if (!jitMgr->IsMainJitLoaded())
12756         {
12757             // Don't want to throw InvalidProgram from here.
12758             EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12759         }
12760         if (!jitMgr->IsAltJitLoaded())
12761         {
12762             // Don't want to throw InvalidProgram from here.
12763             EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load alternative JIT compiler"));
12764         }
12765 #else // ALLOW_SXS_JIT
12766         // Don't want to throw InvalidProgram from here.
12767         EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12768 #endif // ALLOW_SXS_JIT
12769     }
12770 #endif // CROSSGEN_COMPILE
12771
12772 #ifdef _DEBUG
12773     // This is here so we can see the name and class easily in the debugger
12774
12775     LPCUTF8 cls  = ftn->GetMethodTable()->GetDebugClassName();
12776     LPCUTF8 name = ftn->GetName();
12777
12778     if (ftn->IsNoMetadata())
12779     {
12780         if (ftn->IsILStub())
12781         {
12782             LOG((LF_JIT, LL_INFO10000, "{ Jitting IL Stub }\n"));
12783         }
12784         else
12785         {
12786             LOG((LF_JIT, LL_INFO10000, "{ Jitting dynamic method }\n"));
12787         }
12788     }
12789     else
12790     {
12791         SString methodString;
12792         if (LoggingOn(LF_JIT, LL_INFO10000))
12793             TypeString::AppendMethodDebug(methodString, ftn);
12794
12795         LOG((LF_JIT, LL_INFO10000, "{ Jitting method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12796     }
12797
12798 #if 0
12799     if (!SString::_stricmp(cls,"ENC") &&
12800        (!SString::_stricmp(name,"G")))
12801     {
12802        static count = 0;
12803        count++;
12804        if (count > 0)
12805             DebugBreak();
12806     }
12807 #endif // 0
12808 #endif // _DEBUG
12809
12810     CORINFO_METHOD_HANDLE ftnHnd = (CORINFO_METHOD_HANDLE)ftn;
12811     CORINFO_METHOD_INFO methodInfo;
12812
12813     getMethodInfoHelper(ftn, ftnHnd, ILHeader, &methodInfo);
12814
12815     // If it's generic then we can only enter through an instantiated md (unless we're just verifying it)
12816     _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || !ftn->IsGenericMethodDefinition());
12817
12818     // If it's an instance method then it must not be entered from a generic class
12819     _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || ftn->IsStatic() ||
12820              ftn->GetNumGenericClassArgs() == 0 || ftn->HasClassInstantiation());
12821
12822     // method attributes and signature are consistant
12823     _ASSERTE(!!ftn->IsStatic() == ((methodInfo.args.callConv & CORINFO_CALLCONV_HASTHIS) == 0));
12824
12825     flags = GetCompileFlags(ftn, flags, &methodInfo);
12826
12827 #ifdef _DEBUG
12828     if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION))
12829     {
12830         SString methodString;
12831         if (LoggingOn(LF_VERIFIER, LL_INFO100))
12832             TypeString::AppendMethodDebug(methodString, ftn);
12833
12834         LOG((LF_VERIFIER, LL_INFO100, "{ Will verify method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12835     }
12836 #endif //_DEBUG
12837
12838 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
12839     BOOL fForceJumpStubOverflow = FALSE;
12840
12841 #ifdef _DEBUG
12842     // Always exercise the overflow codepath with force relocs
12843     if (PEDecoder::GetForceRelocs())
12844         fForceJumpStubOverflow = TRUE;
12845 #endif
12846
12847 #if defined(_TARGET_AMD64_)
12848     BOOL fAllowRel32 = (g_fAllowRel32 | fForceJumpStubOverflow);
12849 #endif
12850
12851     size_t reserveForJumpStubs = 0;
12852
12853 #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
12854
12855     for (;;)
12856     {
12857 #ifndef CROSSGEN_COMPILE
12858         CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY), 
12859             !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING));
12860 #else
12861         // This path should be only ever used for verification in crossgen and so we should not need EEJitManager
12862         _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY));
12863         CEEInfo jitInfo(ftn, true);
12864         EEJitManager *jitMgr = NULL;
12865 #endif
12866
12867 #if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)) && !defined(CROSSGEN_COMPILE)
12868 #ifdef _TARGET_AMD64_
12869         if (fForceJumpStubOverflow)
12870             jitInfo.SetJumpStubOverflow(fAllowRel32);
12871         jitInfo.SetAllowRel32(fAllowRel32);
12872 #else
12873         if (fForceJumpStubOverflow)
12874             jitInfo.SetJumpStubOverflow(fForceJumpStubOverflow);
12875 #endif
12876         jitInfo.SetReserveForJumpStubs(reserveForJumpStubs);
12877 #endif
12878
12879         MethodDesc * pMethodForSecurity = jitInfo.GetMethodForSecurity(ftnHnd);
12880
12881         //Since the check could trigger a demand, we have to do this every time.
12882         //This is actually an overly complicated way to make sure that a method can access all its arguments
12883         //and its return type.
12884         AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
12885         TypeHandle ownerTypeForSecurity = TypeHandle(pMethodForSecurity->GetMethodTable());
12886         DynamicResolver *pAccessContext = NULL;
12887         BOOL doAccessCheck = TRUE;
12888         if (pMethodForSecurity->IsDynamicMethod())
12889         {
12890             doAccessCheck = ModifyCheckForDynamicMethod(pMethodForSecurity->AsDynamicMethodDesc()->GetResolver(),
12891                                                         &ownerTypeForSecurity,
12892                                                         &accessCheckType, &pAccessContext);
12893         }
12894         if (doAccessCheck)
12895         {
12896             AccessCheckOptions accessCheckOptions(accessCheckType,
12897                                                   pAccessContext,
12898                                                   TRUE /*Throw on error*/,
12899                                                   pMethodForSecurity);
12900
12901             StaticAccessCheckContext accessContext(pMethodForSecurity, ownerTypeForSecurity.GetMethodTable());
12902
12903             // We now do an access check from pMethodForSecurity to pMethodForSecurity, its sole purpose is to
12904             // verify that pMethodForSecurity/ownerTypeForSecurity has access to all its parameters.
12905
12906             // ownerTypeForSecurity.GetMethodTable() can be null if the pMethodForSecurity is a DynamicMethod
12907             // associated with a TypeDesc (Array, Ptr, Ref, or FnPtr). That doesn't make any sense, but we will
12908             // just do an access check from a NULL context which means only public types are accessible.
12909             if (!ClassLoader::CanAccess(&accessContext,
12910                                         ownerTypeForSecurity.GetMethodTable(),
12911                                         ownerTypeForSecurity.GetAssembly(),
12912                                         pMethodForSecurity->GetAttrs(),
12913                                         pMethodForSecurity,
12914                                         NULL,
12915                                         accessCheckOptions))
12916             {
12917                 EX_THROW(EEMethodException, (pMethodForSecurity));
12918             }
12919         }
12920
12921         CorJitResult res;
12922         PBYTE nativeEntry;
12923         ULONG sizeOfCode;
12924
12925         {
12926             GCX_COOP();
12927
12928             /* There is a double indirection to call compileMethod  - can we
12929                improve this with the new structure? */
12930
12931 #ifdef PERF_TRACK_METHOD_JITTIMES
12932             //Because we're not calling QPC enough.  I'm not going to track times if we're just importing.
12933             LARGE_INTEGER methodJitTimeStart = {0};
12934             if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12935                 QueryPerformanceCounter (&methodJitTimeStart);
12936
12937 #endif
12938 #if defined(ENABLE_PERF_COUNTERS)
12939             START_JIT_PERF();
12940 #endif
12941
12942 #if defined(ENABLE_PERF_COUNTERS)
12943             LARGE_INTEGER CycleStart;
12944             QueryPerformanceCounter (&CycleStart);
12945 #endif // defined(ENABLE_PERF_COUNTERS)
12946
12947             // Note on debuggerTrackInfo arg: if we're only importing (ie, verifying/
12948             // checking to make sure we could JIT, but not actually generating code (
12949             // eg, for inlining), then DON'T TELL THE DEBUGGER about this.
12950             res = CallCompileMethodWithSEHWrapper(jitMgr,
12951                                                   &jitInfo,
12952                                                   &methodInfo,
12953                                                   flags,
12954                                                   &nativeEntry,
12955                                                   &sizeOfCode,
12956                                                   (MethodDesc*)ftn);
12957             LOG((LF_CORDB, LL_EVERYTHING, "Got through CallCompile MethodWithSEHWrapper\n"));
12958
12959 #if FEATURE_PERFMAP
12960             // Save the code size so that it can be reported to the perfmap.
12961             if (pSizeOfCode != NULL)
12962             {
12963                 *pSizeOfCode = sizeOfCode;
12964             }
12965 #endif
12966
12967 #if defined(ENABLE_PERF_COUNTERS)
12968             LARGE_INTEGER CycleStop;
12969             QueryPerformanceCounter(&CycleStop);
12970             GetPerfCounters().m_Jit.timeInJitBase = GetPerfCounters().m_Jit.timeInJit;
12971             GetPerfCounters().m_Jit.timeInJit += static_cast<DWORD>(CycleStop.QuadPart - CycleStart.QuadPart);
12972             GetPerfCounters().m_Jit.cMethodsJitted++;
12973             GetPerfCounters().m_Jit.cbILJitted+=methodInfo.ILCodeSize;
12974
12975 #endif // defined(ENABLE_PERF_COUNTERS)
12976
12977 #if defined(ENABLE_PERF_COUNTERS)
12978             STOP_JIT_PERF();
12979 #endif
12980
12981 #ifdef PERF_TRACK_METHOD_JITTIMES
12982             //store the time in the string buffer.  Module name and token are unique enough.  Also, do not
12983             //capture importing time, just actual compilation time.
12984             if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12985             {
12986                 LARGE_INTEGER methodJitTimeStop;
12987                 QueryPerformanceCounter(&methodJitTimeStop);
12988                 SString codeBase;
12989                 ftn->GetModule()->GetDomainFile()->GetFile()->GetCodeBaseOrName(codeBase);
12990                 codeBase.AppendPrintf(W(",0x%x,%d,%d\n"),
12991                                  //(const WCHAR *)codeBase, //module name
12992                                  ftn->GetMemberDef(), //method token
12993                                  (unsigned)(methodJitTimeStop.QuadPart - methodJitTimeStart.QuadPart), //cycle count
12994                                  methodInfo.ILCodeSize //il size
12995                                 );
12996                 WszOutputDebugString((const WCHAR*)codeBase);
12997             }
12998 #endif // PERF_TRACK_METHOD_JITTIMES
12999
13000         }
13001
13002         LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s  %s }\n",cls,name, ftn->m_pszDebugMethodSignature));
13003
13004         if (!SUCCEEDED(res))
13005         {
13006             COUNTER_ONLY(GetPerfCounters().m_Jit.cJitFailures++);
13007
13008 #ifndef CROSSGEN_COMPILE
13009             jitInfo.BackoutJitData(jitMgr);
13010 #endif
13011
13012             ThrowExceptionForJit(res);
13013         }
13014
13015         if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
13016         {
13017             // We are done
13018             break;
13019         }
13020
13021         if (!nativeEntry)
13022             COMPlusThrow(kInvalidProgramException);
13023
13024 #if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)) && !defined(CROSSGEN_COMPILE)
13025         if (jitInfo.IsJumpStubOverflow())
13026         {
13027             // Backout and try again with fAllowRel32 == FALSE.
13028             jitInfo.BackoutJitData(jitMgr);
13029
13030 #ifdef _TARGET_AMD64_
13031             // Disallow rel32 relocs in future.
13032             g_fAllowRel32 = FALSE;
13033
13034             fAllowRel32 = FALSE;
13035 #endif // _TARGET_AMD64_
13036 #ifdef _TARGET_ARM64_
13037             fForceJumpStubOverflow = FALSE;
13038 #endif // _TARGET_ARM64_
13039
13040             reserveForJumpStubs = jitInfo.GetReserveForJumpStubs();
13041             continue;
13042         }
13043 #endif // (_TARGET_AMD64_ || _TARGET_ARM64_) && !CROSSGEN_COMPILE
13044
13045         LOG((LF_JIT, LL_INFO10000,
13046             "Jitted Entry at" FMT_ADDR "method %s::%s %s\n", DBG_ADDR(nativeEntry),
13047              ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
13048
13049 #if defined(FEATURE_CORESYSTEM)
13050
13051 #ifdef _DEBUG
13052         LPCUTF8 pszDebugClassName = ftn->m_pszDebugClassName;
13053         LPCUTF8 pszDebugMethodName = ftn->m_pszDebugMethodName;
13054         LPCUTF8 pszDebugMethodSignature = ftn->m_pszDebugMethodSignature;
13055 #else
13056         LPCUTF8 pszNamespace;
13057         LPCUTF8 pszDebugClassName = ftn->GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace);
13058         LPCUTF8 pszDebugMethodName = ftn->GetName();
13059         LPCUTF8 pszDebugMethodSignature = "";
13060 #endif
13061
13062         //DbgPrintf("Jitted Entry at" FMT_ADDR "method %s::%s %s size %08x\n", DBG_ADDR(nativeEntry),
13063         //          pszDebugClassName, pszDebugMethodName, pszDebugMethodSignature, sizeOfCode);
13064 #endif
13065
13066         ClrFlushInstructionCache(nativeEntry, sizeOfCode); 
13067         ret = (PCODE)nativeEntry;
13068
13069 #ifdef _TARGET_ARM_
13070         ret |= THUMB_CODE;
13071 #endif
13072
13073         // We are done
13074         break;
13075     }
13076
13077 #ifdef _DEBUG
13078     FastInterlockIncrement(&g_JitCount);
13079     static BOOL fHeartbeat = -1;
13080
13081     if (fHeartbeat == -1)
13082         fHeartbeat = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitHeartbeat);
13083
13084     if (fHeartbeat)
13085         printf(".");
13086 #endif // _DEBUG
13087
13088     COOPERATIVE_TRANSITION_END();
13089     return ret;
13090 }
13091
13092 extern "C" unsigned __stdcall PartialNGenStressPercentage()
13093 {
13094     LIMITED_METHOD_CONTRACT;
13095 #ifndef _DEBUG 
13096     return 0;
13097 #else // _DEBUG
13098     static ConfigDWORD partialNGenStress;
13099     DWORD partialNGenStressVal = partialNGenStress.val(CLRConfig::INTERNAL_partialNGenStress);
13100     _ASSERTE(partialNGenStressVal <= 100);
13101     return partialNGenStressVal;
13102 #endif // _DEBUG
13103 }
13104
13105 #ifdef FEATURE_PREJIT
13106 /*********************************************************************/
13107
13108 //
13109 // Table loading functions
13110 //
13111 void Module::LoadHelperTable()
13112 {
13113     STANDARD_VM_CONTRACT;
13114
13115 #ifndef CROSSGEN_COMPILE
13116     COUNT_T tableSize;
13117     BYTE * table = (BYTE *) GetNativeImage()->GetNativeHelperTable(&tableSize);
13118
13119     if (tableSize == 0)
13120         return;
13121
13122     EnsureWritableExecutablePages(table, tableSize);
13123
13124     BYTE * curEntry   = table;
13125     BYTE * tableEnd   = table + tableSize;
13126
13127 #ifdef FEATURE_PERFMAP
13128     PerfMap::LogStubs(__FUNCTION__, GetSimpleName(), (PCODE)table, tableSize);
13129 #endif
13130
13131 #ifdef LOGGING
13132     int iEntryNumber = 0;
13133 #endif // LOGGING
13134
13135     //
13136     // Fill in helpers
13137     //
13138
13139     while (curEntry < tableEnd)
13140     {
13141         DWORD dwHelper = *(DWORD *)curEntry;
13142
13143         int iHelper = (USHORT)dwHelper;
13144         _ASSERTE(iHelper < CORINFO_HELP_COUNT);
13145
13146         LOG((LF_JIT, LL_INFO1000000, "JIT helper %3d (%-40s: table @ %p, size 0x%x, entry %3d @ %p, pfnHelper %p)\n",
13147             iHelper, hlpFuncTable[iHelper].name, table, tableSize, iEntryNumber, curEntry, hlpFuncTable[iHelper].pfnHelper));
13148
13149 #if defined(ENABLE_FAST_GCPOLL_HELPER)
13150         // The fast GC poll helper works by calling indirect through a pointer that points to either
13151         // JIT_PollGC or JIT_PollGC_Nop, based on whether we need to poll or not. The JIT_PollGC_Nop
13152         // version is just a "ret". The pointer is stored in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
13153         // See EnableJitGCPoll() and DisableJitGCPoll().
13154         // In NGEN images, we generate a direct call to the helper table. Here, we replace that with
13155         // an indirect jump through the pointer in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
13156         if (iHelper == CORINFO_HELP_POLL_GC)
13157         {
13158             LOG((LF_JIT, LL_INFO1000000, "JIT helper CORINFO_HELP_POLL_GC (%d); emitting indirect jump to 0x%x\n",
13159                 CORINFO_HELP_POLL_GC, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper));
13160
13161             emitJumpInd(curEntry, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper);
13162             curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
13163         }
13164         else
13165 #endif // ENABLE_FAST_GCPOLL_HELPER
13166         {
13167             PCODE pfnHelper = CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)iHelper);
13168
13169             if (dwHelper & CORCOMPILE_HELPER_PTR)
13170             {
13171                 //
13172                 // Indirection cell
13173                 //
13174
13175                 *(TADDR *)curEntry = pfnHelper;
13176
13177                 curEntry = curEntry + sizeof(TADDR);
13178             }
13179             else
13180             {
13181                 //
13182                 // Jump thunk
13183                 //
13184
13185 #if defined(_TARGET_AMD64_)
13186                 *curEntry = X86_INSTR_JMP_REL32;
13187                 *(INT32 *)(curEntry + 1) = rel32UsingJumpStub((INT32 *)(curEntry + 1), pfnHelper, NULL, GetLoaderAllocator());   
13188 #else // all other platforms
13189                 emitJump(curEntry, (LPVOID)pfnHelper);
13190                 _ASSERTE(HELPER_TABLE_ENTRY_LEN >= JUMP_ALLOCATE_SIZE);
13191 #endif
13192
13193                 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
13194             }
13195         }
13196 #ifdef LOGGING
13197         // Note that some table entries are sizeof(TADDR) in length, and some are HELPER_TABLE_ENTRY_LEN in length
13198         ++iEntryNumber;
13199 #endif // LOGGING
13200     }
13201
13202     ClrFlushInstructionCache(table, tableSize);
13203 #endif // CROSSGEN_COMPILE
13204 }
13205
13206 #ifdef FEATURE_READYTORUN
13207 CorInfoHelpFunc MapReadyToRunHelper(ReadyToRunHelper helperNum)
13208 {
13209     LIMITED_METHOD_CONTRACT;
13210
13211     switch (helperNum)
13212     {
13213 #define HELPER(readyToRunHelper, corInfoHelpFunc, flags) \
13214     case readyToRunHelper:                                  return corInfoHelpFunc;
13215 #include "readytorunhelpers.h"
13216
13217     case READYTORUN_HELPER_GetString:                       return CORINFO_HELP_STRCNS;
13218
13219     default:                                                return CORINFO_HELP_UNDEF;
13220     }
13221 }
13222
13223 void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap)
13224 {
13225     STANDARD_VM_CONTRACT;
13226
13227     ZeroMemory(pGCRefMap, cbGCRefMap);
13228
13229     if (!pMT->ContainsPointers())
13230         return;
13231     
13232     CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
13233     CGCDescSeries* cur = map->GetHighestSeries();
13234     CGCDescSeries* last = map->GetLowestSeries();
13235     DWORD size = pMT->GetBaseSize();
13236     _ASSERTE(cur >= last);
13237
13238     do
13239     {
13240         // offset to embedded references in this series must be
13241         // adjusted by the VTable pointer, when in the unboxed state.
13242         size_t offset = cur->GetSeriesOffset() - TARGET_POINTER_SIZE;
13243         size_t offsetStop = offset + cur->GetSeriesSize() + size;
13244         while (offset < offsetStop)
13245         {
13246             size_t bit = offset / TARGET_POINTER_SIZE;
13247
13248             size_t index = bit / 8;
13249             _ASSERTE(index < cbGCRefMap);
13250             pGCRefMap[index] |= (1 << (bit & 7));
13251
13252             offset += TARGET_POINTER_SIZE;
13253         }
13254         cur--;
13255     } while (cur >= last);
13256 }
13257
13258 //
13259 // Type layout check verifies that there was no incompatible change in the value type layout. 
13260 // If there was one, we will fall back to JIT instead of using the pre-generated code from the ready to run image.
13261 // This should be rare situation. Changes in value type layout not common.
13262 //
13263 // The following properties of the value type layout are checked:
13264 // - Size
13265 // - HFA-ness (on platform that support HFAs)
13266 // - Alignment
13267 // - Position of GC references
13268 //
13269 BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob)
13270 {
13271     STANDARD_VM_CONTRACT;
13272
13273     SigPointer p(pBlob);
13274     IfFailThrow(p.SkipExactlyOne());
13275
13276     DWORD dwFlags;
13277     IfFailThrow(p.GetData(&dwFlags));
13278
13279     // Size is checked unconditionally
13280     DWORD dwExpectedSize;
13281     IfFailThrow(p.GetData(&dwExpectedSize));
13282
13283     DWORD dwActualSize = pMT->GetNumInstanceFieldBytes();
13284     if (dwExpectedSize != dwActualSize)
13285         return FALSE;
13286
13287 #ifdef FEATURE_HFA
13288     if (dwFlags & READYTORUN_LAYOUT_HFA)
13289     {
13290         DWORD dwExpectedHFAType;
13291         IfFailThrow(p.GetData(&dwExpectedHFAType));
13292
13293         DWORD dwActualHFAType = pMT->GetHFAType();
13294         if (dwExpectedHFAType != dwActualHFAType)
13295             return FALSE;
13296     }
13297     else
13298     {
13299         if (pMT->IsHFA())
13300             return FALSE;
13301     }
13302 #else
13303     _ASSERTE(!(dwFlags & READYTORUN_LAYOUT_HFA));
13304 #endif
13305
13306     if (dwFlags & READYTORUN_LAYOUT_Alignment)
13307     {
13308         DWORD dwExpectedAlignment = TARGET_POINTER_SIZE;
13309         if (!(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
13310         {
13311             IfFailThrow(p.GetData(&dwExpectedAlignment));
13312         }
13313
13314         DWORD dwActualAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
13315         if (dwExpectedAlignment != dwActualAlignment)
13316             return FALSE;
13317
13318     }
13319
13320     if (dwFlags & READYTORUN_LAYOUT_GCLayout)
13321     {
13322         if (dwFlags & READYTORUN_LAYOUT_GCLayout_Empty)
13323         {
13324             if (pMT->ContainsPointers())
13325                 return FALSE;
13326         }
13327         else
13328         {
13329             size_t cbGCRefMap = (dwActualSize / TARGET_POINTER_SIZE + 7) / 8;
13330             _ASSERTE(cbGCRefMap > 0);
13331
13332             BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
13333
13334             ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
13335
13336             if (memcmp(pGCRefMap, p.GetPtr(), cbGCRefMap) != 0)
13337                 return FALSE;
13338         }
13339     }
13340
13341     return TRUE;
13342 }
13343
13344 #endif // FEATURE_READYTORUN
13345
13346 BOOL LoadDynamicInfoEntry(Module *currentModule,
13347                           RVA fixupRva,
13348                           SIZE_T *entry)
13349 {
13350     STANDARD_VM_CONTRACT;
13351
13352     PCCOR_SIGNATURE pBlob = currentModule->GetNativeFixupBlobData(fixupRva);
13353
13354     BYTE kind = *pBlob++;
13355
13356     Module * pInfoModule = currentModule;
13357
13358     if (kind & ENCODE_MODULE_OVERRIDE)
13359     {
13360         pInfoModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13361         kind &= ~ENCODE_MODULE_OVERRIDE;
13362     }
13363
13364     MethodDesc * pMD = NULL;
13365
13366 #ifndef CROSSGEN_COMPILE
13367     PCCOR_SIGNATURE pSig;
13368     DWORD cSig;
13369 #endif // CROSSGEN_COMPILE
13370
13371     size_t result = 0;
13372     
13373     switch (kind)
13374     {
13375     case ENCODE_MODULE_HANDLE:
13376         result = (size_t)pInfoModule;
13377         break;
13378
13379     case ENCODE_TYPE_HANDLE:
13380     case ENCODE_TYPE_DICTIONARY:
13381         {
13382             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13383
13384             if (!th.IsTypeDesc())
13385             {
13386                 if (currentModule->IsReadyToRun())
13387                 {
13388                     // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13389                     th.AsMethodTable()->EnsureInstanceActive();
13390                 }
13391                 else
13392                 {
13393 #ifdef FEATURE_WINMD_RESILIENT
13394                     // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13395                     th.AsMethodTable()->EnsureInstanceActive();
13396 #endif
13397                 }
13398             }
13399
13400             result = (size_t)th.AsPtr();
13401         }
13402         break;
13403
13404     case ENCODE_METHOD_HANDLE:
13405     case ENCODE_METHOD_DICTIONARY:
13406         {
13407             MethodDesc * pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13408
13409             if (currentModule->IsReadyToRun())
13410             {
13411                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13412                 pMD->EnsureActive();
13413             }
13414
13415             result = (size_t)pMD;
13416         }
13417         break;
13418
13419     case ENCODE_FIELD_HANDLE:
13420         result = (size_t) ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13421         break;
13422
13423 #ifndef CROSSGEN_COMPILE
13424     case ENCODE_STRING_HANDLE:
13425         {
13426             // We need to update strings atomically (due to NoStringInterning attribute). Note
13427             // that modules with string interning dont really need this, as the hash tables have
13428             // their own locking, but dont add more complexity for what will be the non common
13429             // case.
13430
13431             // We will have to lock and update the entry. (this is really a double check, where
13432             // the first check is done in the caller of this function)
13433             DWORD rid = CorSigUncompressData(pBlob);
13434             if (rid == 0)
13435             {
13436                 // Empty string
13437                 result = (size_t)StringObject::GetEmptyStringRefPtr();
13438             }
13439             else
13440             {
13441                 CrstHolder ch(pInfoModule->GetFixupCrst());
13442
13443                 if (!CORCOMPILE_IS_POINTER_TAGGED(*entry) && (*entry != NULL))
13444                 {
13445                     // We lost the race, just return
13446                     return TRUE;
13447                 }
13448
13449                 // For generic instantiations compiled into the ngen image of some other
13450                 // client assembly, we need to ensure that we intern the string
13451                 // in the defining assembly.
13452                 bool mayNeedToSyncWithFixups = pInfoModule != currentModule;
13453
13454                 result = (size_t) pInfoModule->ResolveStringRef(TokenFromRid(rid, mdtString), currentModule->GetDomain(), mayNeedToSyncWithFixups);
13455             }
13456         }
13457         break;
13458
13459     case ENCODE_VARARGS_SIG:
13460         {
13461             mdSignature token = TokenFromRid(
13462                                     CorSigUncompressData(pBlob),
13463                                     mdtSignature);
13464
13465             IfFailThrow(pInfoModule->GetMDImport()->GetSigFromToken(token, &cSig, &pSig));
13466
13467             goto VarArgs;
13468         }
13469         break;
13470
13471     case ENCODE_VARARGS_METHODREF:
13472         {
13473             mdSignature token = TokenFromRid(
13474                                     CorSigUncompressData(pBlob),
13475                                     mdtMemberRef);
13476
13477             LPCSTR szName_Ignore;
13478             IfFailThrow(pInfoModule->GetMDImport()->GetNameAndSigOfMemberRef(token, &pSig, &cSig, &szName_Ignore));
13479
13480             goto VarArgs;
13481         }
13482         break;
13483
13484     case ENCODE_VARARGS_METHODDEF:
13485         {
13486             mdSignature token = TokenFromRid(
13487                                     CorSigUncompressData(pBlob),
13488                                     mdtMethodDef);
13489
13490             IfFailThrow(pInfoModule->GetMDImport()->GetSigOfMethodDef(token, &cSig, &pSig));
13491         }
13492         {
13493         VarArgs:
13494             result = (size_t) CORINFO_VARARGS_HANDLE(currentModule->GetVASigCookie(Signature(pSig, cSig)));
13495         }
13496         break;
13497
13498         // ENCODE_METHOD_NATIVECALLABLE_HANDLE is same as ENCODE_METHOD_ENTRY_DEF_TOKEN 
13499         // except for AddrOfCode
13500     case ENCODE_METHOD_NATIVE_ENTRY:
13501     case ENCODE_METHOD_ENTRY_DEF_TOKEN:
13502         {
13503             mdToken MethodDef = TokenFromRid(CorSigUncompressData(pBlob), mdtMethodDef);
13504             pMD = MemberLoader::GetMethodDescFromMethodDef(pInfoModule, MethodDef, FALSE);
13505
13506             pMD->PrepareForUseAsADependencyOfANativeImage();
13507
13508             if (currentModule->IsReadyToRun())
13509             {
13510                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13511                 pMD->EnsureActive();
13512             }
13513
13514             goto MethodEntry;
13515         }
13516
13517     case ENCODE_METHOD_ENTRY_REF_TOKEN:
13518         {
13519             SigTypeContext typeContext;
13520             mdToken MemberRef = TokenFromRid(CorSigUncompressData(pBlob), mdtMemberRef);
13521             FieldDesc * pFD = NULL;
13522             TypeHandle th;
13523
13524             MemberLoader::GetDescFromMemberRef(pInfoModule, MemberRef, &pMD, &pFD, &typeContext, FALSE /* strict metadata checks */, &th);
13525             _ASSERTE(pMD != NULL);
13526
13527             pMD->PrepareForUseAsADependencyOfANativeImage();
13528
13529             if (currentModule->IsReadyToRun())
13530             {
13531                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13532                 pMD->EnsureActive();
13533             }
13534             else
13535             {
13536 #ifdef FEATURE_WINMD_RESILIENT
13537                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13538                 pMD->EnsureActive();
13539 #endif
13540             }
13541
13542             goto MethodEntry;
13543         }
13544
13545     case ENCODE_METHOD_ENTRY:
13546         {
13547             pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13548
13549             if (currentModule->IsReadyToRun())
13550             {
13551                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13552                 pMD->EnsureActive();
13553             }
13554
13555         MethodEntry:
13556             if (kind == ENCODE_METHOD_NATIVE_ENTRY)
13557             {
13558                 result = COMDelegate::ConvertToCallback(pMD);
13559             }
13560             else
13561             {
13562                 result = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY);
13563             }
13564
13565         #ifndef _TARGET_ARM_
13566             if (CORCOMPILE_IS_PCODE_TAGGED(result))
13567             {
13568                 // There is a rare case where the function entrypoint may not be aligned. This could happen only for FCalls, 
13569                 // only on x86 and only if we failed to hardbind the fcall (e.g. ngen image for mscorlib.dll does not exist 
13570                 // and /nodependencies flag for ngen was used). The function entrypoints should be aligned in all other cases.
13571                 //
13572                 // We will wrap the unaligned method entrypoint by funcptr stub with aligned entrypoint.
13573                 _ASSERTE(pMD->IsFCall());
13574                 result = pMD->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pMD);
13575             }
13576         #endif
13577         }
13578         break;
13579
13580     case ENCODE_SYNC_LOCK:
13581         {
13582             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13583
13584             result = (size_t) GetClassSync(th.AsMethodTable());
13585         }
13586         break;
13587
13588     case ENCODE_INDIRECT_PINVOKE_TARGET:
13589         {
13590             MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13591
13592             _ASSERTE(pMethod->IsNDirect());
13593             NDirectMethodDesc *pMD = (NDirectMethodDesc*)pMethod;
13594             result = (size_t)(LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
13595         }
13596         break;
13597
13598 #if defined(PROFILING_SUPPORTED)
13599     case ENCODE_PROFILING_HANDLE:
13600         {
13601             MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13602
13603             // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
13604             // they shouldnever come here as they are called out in GetCompileFlag
13605             _ASSERTE(!pMethod->IsNoMetadata());
13606
13607             FunctionID funId = (FunctionID)pMethod;
13608
13609             BOOL bHookFunction = TRUE;
13610             CORINFO_PROFILING_HANDLE profilerHandle = (CORINFO_PROFILING_HANDLE)funId;
13611
13612             {
13613                 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
13614                 profilerHandle = (CORINFO_PROFILING_HANDLE) g_profControlBlock.pProfInterface->EEFunctionIDMapper(funId, &bHookFunction);
13615                 END_PIN_PROFILER();
13616             }
13617
13618             // Profiling handle is opaque token. It does not have to be aligned thus we can not store it in the same location as token.
13619             *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexClientData) = (SIZE_T)profilerHandle;
13620
13621             if (bHookFunction)
13622             {
13623                 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER].pfnHelper;
13624                 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE].pfnHelper;
13625                 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL].pfnHelper;
13626             }
13627             else
13628             {
13629                 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13630                 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13631                 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13632             }
13633         }
13634         break;
13635 #endif // PROFILING_SUPPORTED
13636
13637     case ENCODE_STATIC_FIELD_ADDRESS:
13638         {
13639             FieldDesc *pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13640
13641             pField->GetEnclosingMethodTable()->CheckRestore();
13642
13643             // We can take address of RVA field only since ngened code is domain neutral
13644             _ASSERTE(pField->IsRVA());
13645
13646             // Field address is not aligned thus we can not store it in the same location as token.
13647             *EnsureWritablePages(entry+1) = (size_t)pField->GetStaticAddressHandle(NULL);
13648         }
13649         break;
13650
13651     case ENCODE_VIRTUAL_ENTRY_SLOT:
13652         {
13653             DWORD slot = CorSigUncompressData(pBlob);
13654
13655             TypeHandle ownerType = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13656
13657             LOG((LF_ZAP, LL_INFO100000, "     Fixup stub dispatch\n"));
13658
13659             VirtualCallStubManager * pMgr = currentModule->GetLoaderAllocator()->GetVirtualCallStubManager();
13660
13661             // <REVISIT_TODO>
13662             // We should be generating a stub indirection here, but the zapper already uses one level
13663             // of indirection, i.e. we would have to return IAT_PPVALUE to the JIT, and on the whole the JITs
13664             // aren't quite set up to accept that. Furthermore the call sequences would be different - at
13665             // the moment an indirection cell uses "call [cell-addr]" on x86, and instead we would want the
13666             // euqivalent of "call [[call-addr]]".  This could perhaps be implemented as "call [eax]" </REVISIT_TODO>
13667             result = pMgr->GetCallStub(ownerType, slot);
13668         }
13669         break;
13670
13671     case ENCODE_CLASS_ID_FOR_STATICS:
13672         {
13673             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13674
13675             MethodTable * pMT = th.AsMethodTable();
13676             if (pMT->IsDynamicStatics())
13677             {
13678                 result = pMT->GetModuleDynamicEntryID();
13679             }
13680             else
13681             {
13682                 result = pMT->GetClassIndex();
13683             }
13684         }
13685         break;
13686
13687     case ENCODE_MODULE_ID_FOR_STATICS:
13688         {
13689             result = pInfoModule->GetModuleID();
13690         }
13691         break;
13692
13693     case ENCODE_MODULE_ID_FOR_GENERIC_STATICS:
13694         {
13695             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13696
13697             MethodTable * pMT = th.AsMethodTable();
13698
13699             result = pMT->GetModuleForStatics()->GetModuleID();
13700         }
13701         break;
13702
13703     case ENCODE_ACTIVE_DEPENDENCY:
13704         {
13705             Module* pModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13706
13707             STRESS_LOG3(LF_ZAP,LL_INFO10000,"Modules are: %08x,%08x,%08x",currentModule,pInfoModule,pModule);
13708             pInfoModule->AddActiveDependency(pModule, FALSE);
13709         }
13710         break;
13711
13712 #ifdef FEATURE_READYTORUN
13713     case ENCODE_READYTORUN_HELPER:
13714         {
13715             DWORD helperNum = CorSigUncompressData(pBlob);
13716
13717             CorInfoHelpFunc corInfoHelpFunc = MapReadyToRunHelper((ReadyToRunHelper)helperNum);
13718             if (corInfoHelpFunc != CORINFO_HELP_UNDEF)
13719             {
13720                 result = (size_t)CEEJitInfo::getHelperFtnStatic(corInfoHelpFunc);
13721             }
13722             else
13723             {
13724                 switch (helperNum)
13725                 {
13726                 case READYTORUN_HELPER_Module:
13727                     {
13728                         Module * pPrevious = InterlockedCompareExchangeT(EnsureWritablePages((Module **)entry), pInfoModule, NULL);
13729                         if (pPrevious != pInfoModule && pPrevious != NULL)
13730                             COMPlusThrowHR(COR_E_FILELOAD, IDS_NATIVE_IMAGE_CANNOT_BE_LOADED_MULTIPLE_TIMES, pInfoModule->GetPath());
13731                         return TRUE;
13732                     }
13733                     break;
13734
13735                 case READYTORUN_HELPER_GSCookie:
13736                     result = (size_t)GetProcessGSCookie();
13737                     break;
13738
13739                 case READYTORUN_HELPER_DelayLoad_MethodCall:
13740                     result = (size_t)GetEEFuncEntryPoint(DelayLoad_MethodCall);
13741                     break;
13742
13743                 case READYTORUN_HELPER_DelayLoad_Helper:
13744                     result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper);
13745                     break;
13746
13747                 case READYTORUN_HELPER_DelayLoad_Helper_Obj:
13748                     result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_Obj);
13749                     break;
13750
13751                 case READYTORUN_HELPER_DelayLoad_Helper_ObjObj:
13752                     result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_ObjObj);
13753                     break;
13754
13755                 default:
13756                     STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown READYTORUN_HELPER %d\n", helperNum);
13757                     _ASSERTE(!"Unknown READYTORUN_HELPER");
13758                     return FALSE;
13759                 }
13760             }
13761         }
13762         break;
13763
13764     case ENCODE_FIELD_OFFSET:
13765         {
13766             FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13767             _ASSERTE(!pFD->IsStatic());
13768             _ASSERTE(!pFD->IsFieldOfValueType());
13769
13770             DWORD dwOffset = (DWORD)sizeof(Object) + pFD->GetOffset();
13771
13772             if (dwOffset > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13773                 return FALSE;
13774             result = dwOffset;
13775         }
13776         break;
13777
13778     case ENCODE_FIELD_BASE_OFFSET:
13779         {
13780             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13781
13782             MethodTable * pMT = th.AsMethodTable();
13783             _ASSERTE(!pMT->IsValueType());
13784
13785             DWORD dwOffsetBase = ReadyToRunInfo::GetFieldBaseOffset(pMT);
13786             if (dwOffsetBase > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13787                 return FALSE;
13788             result = dwOffsetBase;
13789         }
13790         break;
13791
13792     case ENCODE_CHECK_TYPE_LAYOUT:
13793         {
13794             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13795             MethodTable * pMT = th.AsMethodTable();
13796             _ASSERTE(pMT->IsValueType());
13797
13798             if (!TypeLayoutCheck(pMT, pBlob))
13799                 return FALSE;
13800
13801             result = 1;
13802         }
13803         break;
13804
13805     case ENCODE_CHECK_FIELD_OFFSET:
13806         {
13807             DWORD dwExpectedOffset = CorSigUncompressData(pBlob);
13808
13809             FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13810             _ASSERTE(!pFD->IsStatic());
13811
13812             DWORD dwOffset = pFD->GetOffset();
13813             if (!pFD->IsFieldOfValueType())
13814                 dwOffset += sizeof(Object);
13815
13816             if (dwExpectedOffset != dwOffset)
13817                 return FALSE;
13818
13819             result = 1;
13820         }
13821         break;
13822 #endif // FEATURE_READYTORUN
13823
13824 #endif // CROSSGEN_COMPILE
13825
13826     default:
13827         STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown FIXUP_BLOB_KIND %d\n", kind);
13828         _ASSERTE(!"Unknown FIXUP_BLOB_KIND");
13829         return FALSE;
13830     }
13831
13832     MemoryBarrier();
13833     *EnsureWritablePages(entry) = result;
13834
13835     return TRUE;
13836 }
13837 #endif // FEATURE_PREJIT
13838
13839 void* CEEInfo::getTailCallCopyArgsThunk(CORINFO_SIG_INFO       *pSig,
13840                                         CorInfoHelperTailCallSpecialHandling flags)
13841 {
13842     CONTRACTL {
13843         SO_TOLERANT;
13844         THROWS;
13845         GC_TRIGGERS;
13846         MODE_PREEMPTIVE;
13847     } CONTRACTL_END;
13848
13849     void * ftn = NULL;
13850
13851 #if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)) && !defined(FEATURE_PAL)
13852
13853     JIT_TO_EE_TRANSITION();
13854
13855     Stub* pStub = CPUSTUBLINKER::CreateTailCallCopyArgsThunk(pSig, m_pMethodBeingCompiled, flags);
13856         
13857     ftn = (void*)pStub->GetEntryPoint();
13858
13859     EE_TO_JIT_TRANSITION();
13860
13861 #endif // (_TARGET_AMD64_ || _TARGET_ARM_) && !FEATURE_PAL
13862
13863     return ftn;
13864 }
13865
13866 bool CEEInfo::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert)
13867 {
13868     return false;
13869 }
13870
13871 void CEEInfo::allocMem (
13872         ULONG               hotCodeSize,    /* IN */
13873         ULONG               coldCodeSize,   /* IN */
13874         ULONG               roDataSize,     /* IN */
13875         ULONG               xcptnsCount,    /* IN */
13876         CorJitAllocMemFlag  flag,           /* IN */
13877         void **             hotCodeBlock,   /* OUT */
13878         void **             coldCodeBlock,  /* OUT */
13879         void **             roDataBlock     /* OUT */
13880         )
13881 {
13882     LIMITED_METHOD_CONTRACT;
13883     UNREACHABLE();      // only called on derived class.
13884 }
13885
13886 void CEEInfo::reserveUnwindInfo (
13887         BOOL                isFunclet,             /* IN */
13888         BOOL                isColdCode,            /* IN */
13889         ULONG               unwindSize             /* IN */
13890         )
13891 {
13892     LIMITED_METHOD_CONTRACT;
13893     UNREACHABLE();      // only called on derived class.
13894 }
13895
13896 void CEEInfo::allocUnwindInfo (
13897         BYTE *              pHotCode,              /* IN */
13898         BYTE *              pColdCode,             /* IN */
13899         ULONG               startOffset,           /* IN */
13900         ULONG               endOffset,             /* IN */
13901         ULONG               unwindSize,            /* IN */
13902         BYTE *              pUnwindBlock,          /* IN */
13903         CorJitFuncKind      funcKind               /* IN */
13904         )
13905 {
13906     LIMITED_METHOD_CONTRACT;
13907     UNREACHABLE();      // only called on derived class.
13908 }
13909
13910 void * CEEInfo::allocGCInfo (
13911         size_t                  size        /* IN */
13912         )
13913 {
13914     LIMITED_METHOD_CONTRACT;
13915     UNREACHABLE_RET();      // only called on derived class.
13916 }
13917
13918 void CEEInfo::setEHcount (
13919         unsigned             cEH    /* IN */
13920         )
13921 {
13922     LIMITED_METHOD_CONTRACT;
13923     UNREACHABLE();      // only called on derived class.
13924 }
13925
13926 void CEEInfo::setEHinfo (
13927         unsigned             EHnumber,   /* IN  */
13928         const CORINFO_EH_CLAUSE *clause      /* IN */
13929         )
13930 {
13931     LIMITED_METHOD_CONTRACT;
13932     UNREACHABLE();      // only called on derived class.
13933 }
13934
13935 InfoAccessType CEEInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
13936                                                mdToken metaTok,
13937                                                void **ppValue)
13938 {
13939     LIMITED_METHOD_CONTRACT;
13940     UNREACHABLE();      // only called on derived class.
13941 }
13942
13943 InfoAccessType CEEInfo::emptyStringLiteral(void ** ppValue)
13944 {
13945     LIMITED_METHOD_CONTRACT;
13946     _ASSERTE(isVerifyOnly());
13947     *ppValue = (void *)0x10;
13948     return IAT_PVALUE;
13949 }
13950
13951 void* CEEInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
13952                                   void **ppIndirection)
13953 {
13954     LIMITED_METHOD_CONTRACT;
13955     _ASSERTE(isVerifyOnly());
13956     if (ppIndirection != NULL)
13957         *ppIndirection = NULL;
13958     return (void *)0x10;
13959 }
13960
13961 CORINFO_CLASS_HANDLE CEEInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
13962                                                          bool* pIsSpeculative)
13963 {
13964     LIMITED_METHOD_CONTRACT;
13965     _ASSERTE(isVerifyOnly());
13966     if (pIsSpeculative != NULL)
13967         *pIsSpeculative = true;
13968     return NULL;
13969 }
13970
13971 void* CEEInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
13972                              void **ppIndirection)
13973 {
13974     LIMITED_METHOD_CONTRACT;
13975     UNREACHABLE();      // only called on derived class.
13976 }
13977
13978 HRESULT CEEInfo::allocBBProfileBuffer (
13979         ULONG                 count,           // The number of basic blocks that we have
13980         ProfileBuffer **      profileBuffer
13981         )
13982 {
13983     LIMITED_METHOD_CONTRACT;
13984     UNREACHABLE_RET();      // only called on derived class.
13985 }
13986
13987 HRESULT CEEInfo::getBBProfileData(
13988         CORINFO_METHOD_HANDLE ftnHnd,
13989         ULONG *               count,           // The number of basic blocks that we have
13990         ProfileBuffer **      profileBuffer,
13991         ULONG *               numRuns
13992         )
13993 {
13994     LIMITED_METHOD_CONTRACT;
13995     UNREACHABLE_RET();      // only called on derived class.
13996 }
13997
13998
13999 void CEEInfo::recordCallSite(
14000         ULONG                 instrOffset,  /* IN */
14001         CORINFO_SIG_INFO *    callSig,      /* IN */
14002         CORINFO_METHOD_HANDLE methodHandle  /* IN */
14003         )
14004 {
14005     LIMITED_METHOD_CONTRACT;
14006     UNREACHABLE();      // only called on derived class.
14007 }
14008
14009 void CEEInfo::recordRelocation(
14010         void *                 location,   /* IN  */
14011         void *                 target,     /* IN  */
14012         WORD                   fRelocType, /* IN  */
14013         WORD                   slotNum,  /* IN  */
14014         INT32                  addlDelta /* IN  */
14015         )
14016 {
14017     LIMITED_METHOD_CONTRACT;
14018     UNREACHABLE();      // only called on derived class.
14019 }
14020
14021 WORD CEEInfo::getRelocTypeHint(void * target)
14022 {
14023     LIMITED_METHOD_CONTRACT;
14024     UNREACHABLE_RET();      // only called on derived class.
14025 }
14026
14027 void CEEInfo::getModuleNativeEntryPointRange(
14028         void ** pStart, /* OUT */
14029         void ** pEnd    /* OUT */
14030         )
14031 {
14032     LIMITED_METHOD_CONTRACT;
14033     UNREACHABLE();      // only called on derived class.
14034 }
14035
14036 DWORD CEEInfo::getExpectedTargetArchitecture()
14037 {
14038     LIMITED_METHOD_CONTRACT;
14039
14040     return IMAGE_FILE_MACHINE_NATIVE;
14041 }
14042
14043 void CEEInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
14044                                ICorDebugInfo::OffsetMapping *pMap)
14045 {
14046     LIMITED_METHOD_CONTRACT;
14047     UNREACHABLE();      // only called on derived class.
14048 }
14049
14050 void CEEInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
14051 {
14052     LIMITED_METHOD_CONTRACT;
14053     UNREACHABLE();      // only called on derived class.
14054 }
14055
14056 void* CEEInfo::getHelperFtn(CorInfoHelpFunc    ftnNum,         /* IN  */
14057                             void **            ppIndirection)  /* OUT */
14058 {
14059     LIMITED_METHOD_CONTRACT;
14060     UNREACHABLE();      // only called on derived class.
14061 }
14062
14063 // Active dependency helpers
14064 void CEEInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
14065 {
14066     LIMITED_METHOD_CONTRACT;
14067     UNREACHABLE();      // only called on derived class.
14068 }
14069
14070 void CEEInfo::GetProfilingHandle(BOOL                      *pbHookFunction,
14071                                  void                     **pProfilerHandle,
14072                                  BOOL                      *pbIndirectedHandles)
14073 {
14074     LIMITED_METHOD_CONTRACT;
14075     UNREACHABLE();      // only called on derived class.
14076 }
14077
14078 #endif // !DACCESS_COMPILE
14079
14080 EECodeInfo::EECodeInfo()
14081 {
14082     WRAPPER_NO_CONTRACT;
14083
14084     m_codeAddress = NULL;
14085
14086     m_pJM = NULL;
14087     m_pMD = NULL;
14088     m_relOffset = 0;
14089
14090 #ifdef WIN64EXCEPTIONS
14091     m_pFunctionEntry = NULL;
14092 #endif
14093 }
14094
14095 void EECodeInfo::Init(PCODE codeAddress)
14096 {
14097     CONTRACTL {
14098         NOTHROW;
14099         GC_NOTRIGGER;
14100         SO_TOLERANT;
14101     } CONTRACTL_END;
14102
14103     Init(codeAddress, ExecutionManager::GetScanFlags());
14104 }
14105
14106 void EECodeInfo::Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag)
14107 {
14108     CONTRACTL {
14109         NOTHROW;
14110         GC_NOTRIGGER;
14111         SO_TOLERANT;
14112     } CONTRACTL_END;
14113
14114     m_codeAddress = codeAddress;
14115
14116     RangeSection * pRS = ExecutionManager::FindCodeRange(codeAddress, scanFlag);
14117     if (pRS == NULL)
14118         goto Invalid;
14119
14120     if (!pRS->pjit->JitCodeToMethodInfo(pRS, codeAddress, &m_pMD, this))
14121         goto Invalid;
14122
14123     m_pJM = pRS->pjit;
14124     return;
14125
14126 Invalid:
14127     m_pJM = NULL;
14128     m_pMD = NULL;
14129     m_relOffset = 0;
14130
14131 #ifdef WIN64EXCEPTIONS
14132     m_pFunctionEntry = NULL;
14133 #endif
14134 }
14135
14136 TADDR EECodeInfo::GetSavedMethodCode()
14137 {
14138     CONTRACTL {
14139         // All EECodeInfo methods must be NOTHROW/GC_NOTRIGGER since they can
14140         // be used during GC.
14141         NOTHROW;
14142         GC_NOTRIGGER;
14143         HOST_NOCALLS;
14144         SUPPORTS_DAC;
14145     } CONTRACTL_END;
14146 #ifndef _WIN64
14147 #if defined(HAVE_GCCOVER)
14148     _ASSERTE (!m_pMD->m_GcCover || GCStress<cfg_instr>::IsEnabled());
14149     if (GCStress<cfg_instr>::IsEnabled()
14150         && m_pMD->m_GcCover)
14151     {
14152         _ASSERTE(m_pMD->m_GcCover->savedCode);
14153
14154         // Make sure we return the TADDR of savedCode here.  The byte array is not marshaled automatically.
14155         // The caller is responsible for any necessary marshaling.
14156         return PTR_TO_MEMBER_TADDR(GCCoverageInfo, m_pMD->m_GcCover, savedCode);
14157     }
14158 #endif //defined(HAVE_GCCOVER)
14159 #endif
14160
14161     return GetStartAddress();
14162 }
14163
14164 TADDR EECodeInfo::GetStartAddress()
14165 {
14166     CONTRACTL {
14167         NOTHROW;
14168         GC_NOTRIGGER;
14169         HOST_NOCALLS;
14170         SUPPORTS_DAC;
14171     } CONTRACTL_END;
14172
14173     return m_pJM->JitTokenToStartAddress(m_methodToken);
14174 }
14175
14176 #if defined(WIN64EXCEPTIONS)
14177
14178 // ----------------------------------------------------------------------------
14179 // EECodeInfo::GetMainFunctionInfo
14180 //
14181 // Description: 
14182 //    Simple helper to transform a funclet's EECodeInfo into a parent function EECodeInfo.
14183 //
14184 // Return Value:
14185 //    An EECodeInfo for the start of the main function body (offset 0).
14186 //
14187
14188 EECodeInfo EECodeInfo::GetMainFunctionInfo()
14189 {
14190     LIMITED_METHOD_CONTRACT;
14191     SUPPORTS_DAC;
14192
14193     EECodeInfo result = *this;
14194     result.m_relOffset = 0;
14195     result.m_codeAddress = this->GetStartAddress();
14196     result.m_pFunctionEntry = NULL;
14197
14198     return result;
14199 }
14200
14201 PTR_RUNTIME_FUNCTION EECodeInfo::GetFunctionEntry()
14202 {
14203     LIMITED_METHOD_CONTRACT;
14204     SUPPORTS_DAC;
14205
14206     if (m_pFunctionEntry == NULL)
14207         m_pFunctionEntry = m_pJM->LazyGetFunctionEntry(this);
14208     return m_pFunctionEntry;
14209 }
14210
14211 #if defined(_TARGET_AMD64_)
14212
14213 BOOL EECodeInfo::HasFrameRegister()
14214 {
14215     LIMITED_METHOD_CONTRACT;
14216
14217     PTR_RUNTIME_FUNCTION pFuncEntry = GetFunctionEntry();
14218     _ASSERTE(pFuncEntry != NULL);
14219
14220     BOOL fHasFrameRegister = FALSE;
14221     PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(GetModuleBase() + pFuncEntry->UnwindData);
14222     if (pUnwindInfo->FrameRegister != 0)
14223     {
14224         fHasFrameRegister = TRUE;
14225         _ASSERTE(pUnwindInfo->FrameRegister == kRBP);
14226     }
14227
14228     return fHasFrameRegister;
14229 }
14230 #endif // defined(_TARGET_AMD64_)
14231
14232 #endif // defined(WIN64EXCEPTIONS)
14233
14234
14235 #if defined(_TARGET_AMD64_)
14236 // ----------------------------------------------------------------------------
14237 // EECodeInfo::GetUnwindInfoHelper
14238 //
14239 // Description: 
14240 //    Simple helper to return a pointer to the UNWIND_INFO given the offset to the unwind info.
14241 //    On DAC builds, this function will read the memory from the target process and create a host copy.
14242 //
14243 // Arguments:
14244 //    * unwindInfoOffset - This is the offset to the unwind info, relative to the beginning of the code heap
14245 //        for jitted code or to the module base for ngned code. this->GetModuleBase() will return the correct
14246 //        module base.
14247 //
14248 // Return Value:
14249 //    Return a pointer to the UNWIND_INFO.  On DAC builds, this function will create a host copy of the
14250 //    UNWIND_INFO and return a host pointer.  It will correctly read all of the memory for the variable-sized 
14251 //    unwind info.
14252 //
14253
14254 UNWIND_INFO * EECodeInfo::GetUnwindInfoHelper(ULONG unwindInfoOffset)
14255 {
14256 #if defined(DACCESS_COMPILE)
14257     return DacGetUnwindInfo(static_cast<TADDR>(this->GetModuleBase() + unwindInfoOffset));
14258 #else  // !DACCESS_COMPILE
14259     return reinterpret_cast<UNWIND_INFO *>(this->GetModuleBase() + unwindInfoOffset);
14260 #endif // !DACCESS_COMPILE
14261 }
14262
14263 // ----------------------------------------------------------------------------
14264 // EECodeInfo::GetFixedStackSize
14265 //
14266 // Description: 
14267 //    Return the fixed stack size of a specified managed method.  This function DOES NOT take current control
14268 //    PC into account.  So the fixed stack size returned by this function is not valid in the prolog or
14269 //    the epilog.
14270 //    
14271 // Return Value:
14272 //    Return the fixed stack size.
14273 //    
14274 // Notes:
14275 //    * For method with dynamic stack allocations, this function will return the fixed stack size on X64 (the
14276 //        stack size immediately after the prolog), and it will return 0 on IA64. This difference is due to
14277 //        the different unwind info encoding.
14278 //        
14279
14280 ULONG EECodeInfo::GetFixedStackSize()
14281 {
14282     WRAPPER_NO_CONTRACT;
14283     SUPPORTS_DAC;
14284
14285     ULONG uFixedStackSize = 0;
14286
14287     ULONG uDummy = 0;
14288     GetOffsetsFromUnwindInfo(&uFixedStackSize, &uDummy);
14289     
14290     return uFixedStackSize;
14291 }
14292
14293 #define kRBP    5
14294 // The information returned by this method is only valid if we are not in a prolog or an epilog.
14295 // Since this method is only used for the security stackwalk cache, this assumption is valid, since
14296 // we cannot make a call in a prolog or an epilog.
14297 //
14298 // The next assumption is that only rbp is used as a frame register in jitted code.  There is an 
14299 // assert below to guard this assumption.
14300 void EECodeInfo::GetOffsetsFromUnwindInfo(ULONG* pRSPOffset, ULONG* pRBPOffset)
14301 {
14302     LIMITED_METHOD_CONTRACT;
14303     SUPPORTS_DAC;
14304
14305     _ASSERTE((pRSPOffset != NULL) && (pRBPOffset != NULL));
14306
14307     // moduleBase is a target address.
14308     TADDR moduleBase = GetModuleBase();
14309
14310     DWORD unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(GetFunctionEntry());
14311
14312     if ((unwindInfo & RUNTIME_FUNCTION_INDIRECT) != 0)
14313     {
14314         unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(PTR_RUNTIME_FUNCTION(moduleBase + (unwindInfo & ~RUNTIME_FUNCTION_INDIRECT)));
14315     }
14316
14317     UNWIND_INFO * pInfo = GetUnwindInfoHelper(unwindInfo);
14318     if (pInfo->Flags & UNW_FLAG_CHAININFO)
14319     {
14320         _ASSERTE(!"GetRbpOffset() - chained unwind info used, violating assumptions of the security stackwalk cache");
14321         DebugBreak();
14322     }
14323
14324     // Either we are not using a frame pointer, or we are using rbp as the frame pointer.
14325     if ( (pInfo->FrameRegister != 0) && (pInfo->FrameRegister != kRBP) )
14326     {
14327         _ASSERTE(!"GetRbpOffset() - non-RBP frame pointer used, violating assumptions of the security stackwalk cache");
14328         DebugBreak();
14329     }
14330
14331     // Walk the unwind info.
14332     ULONG StackOffset     = 0;
14333     ULONG StackSize       = 0;
14334     for (int i = 0; i < pInfo->CountOfUnwindCodes; i++)
14335     {
14336         ULONG UnwindOp = pInfo->UnwindCode[i].UnwindOp;
14337         ULONG OpInfo   = pInfo->UnwindCode[i].OpInfo;
14338
14339         if (UnwindOp == UWOP_SAVE_NONVOL)
14340         {
14341             if (OpInfo == kRBP)
14342             {
14343                 StackOffset = pInfo->UnwindCode[i+1].FrameOffset * 8;
14344             }
14345         }
14346         else if (UnwindOp == UWOP_SAVE_NONVOL_FAR)
14347         {
14348             if (OpInfo == kRBP)
14349             {
14350                 StackOffset  =  pInfo->UnwindCode[i + 1].FrameOffset;
14351                 StackOffset += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14352             }
14353         }
14354         else if (UnwindOp == UWOP_ALLOC_SMALL)
14355         {
14356             StackSize += (OpInfo * 8) + 8;
14357         }
14358         else if (UnwindOp == UWOP_ALLOC_LARGE)
14359         {
14360             ULONG IncrementalStackSize = pInfo->UnwindCode[i + 1].FrameOffset;
14361             if (OpInfo == 0)
14362             {
14363                 IncrementalStackSize *= 8;
14364             }
14365             else
14366             {
14367                 IncrementalStackSize += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14368  
14369                 // This is a special opcode.  We need to increment the index by 1 in addition to the normal adjustments.
14370                 i += 1;        
14371             }
14372             StackSize += IncrementalStackSize;
14373         }
14374         else if (UnwindOp == UWOP_PUSH_NONVOL)
14375         {
14376             // Because of constraints on epilogs, this unwind opcode is always last in the unwind code array.
14377             // This means that StackSize has been initialized already when we first see this unwind opcode.  
14378             // Note that the intial value of StackSize does not include the stack space used for pushes.
14379             // Thus, here we only need to increment StackSize 8 bytes at a time until we see the unwind code for "push rbp".
14380             if (OpInfo == kRBP)
14381             {
14382                 StackOffset = StackSize;
14383             }
14384
14385             StackSize += 8;
14386         }
14387
14388         // Adjust the index into the unwind code array.
14389         i += UnwindOpExtraSlotTable[UnwindOp];
14390     }
14391
14392     *pRSPOffset = StackSize + 8;        // add 8 for the return address
14393     *pRBPOffset = StackOffset;
14394 }
14395 #undef kRBP
14396
14397
14398 #if defined(_DEBUG) && defined(HAVE_GCCOVER)
14399
14400 LPVOID                EECodeInfo::findNextFunclet (LPVOID pvFuncletStart, SIZE_T cbCode, LPVOID *ppvFuncletEnd)
14401 {
14402     CONTRACTL {
14403         NOTHROW;
14404         GC_NOTRIGGER;
14405     } CONTRACTL_END;
14406
14407     while (cbCode > 0)
14408     {
14409         PT_RUNTIME_FUNCTION   pFunctionEntry;
14410         ULONGLONG           uImageBase;
14411 #ifdef FEATURE_PAL
14412         EECodeInfo codeInfo;
14413         codeInfo.Init((PCODE)pvFuncletStart);
14414         pFunctionEntry = codeInfo.GetFunctionEntry();
14415         uImageBase = (ULONGLONG)codeInfo.GetModuleBase();
14416 #else // !FEATURE_PAL
14417         //
14418         // This is GCStress debug only - use the slow OS APIs to enumerate funclets
14419         //
14420
14421         pFunctionEntry = (PT_RUNTIME_FUNCTION) RtlLookupFunctionEntry((ULONGLONG)pvFuncletStart,
14422                               &uImageBase
14423                               AMD64_ARG(NULL)
14424                               );
14425 #endif
14426
14427         if (pFunctionEntry != NULL)
14428         {
14429 #ifdef FEATURE_PREJIT
14430             // workaround: Check for indirect entry that is generated for cold part of main method body.
14431             if ((TADDR)pvFuncletStart < (TADDR)uImageBase + pFunctionEntry->BeginAddress ||
14432                 (TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart)
14433             {
14434                 Module * pZapModule = ExecutionManager::FindZapModule((TADDR)pvFuncletStart);
14435                 NGenLayoutInfo * pLayoutInfo = pZapModule->GetNGenLayoutInfo();
14436
14437                 int ColdFunctionIndex = NativeUnwindInfoLookupTable::LookupUnwindInfoForMethod((DWORD)((TADDR)pvFuncletStart - uImageBase),
14438                                                                                pLayoutInfo->m_pRuntimeFunctions[2],
14439                                                                                0, pLayoutInfo->m_nRuntimeFunctions[2] - 1);
14440
14441                 pFunctionEntry = pLayoutInfo->m_pRuntimeFunctions[2] + ColdFunctionIndex;
14442             }
14443 #endif
14444
14445             _ASSERTE((TADDR)pvFuncletStart == (TADDR)uImageBase + pFunctionEntry->BeginAddress);
14446             _ASSERTE((TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart + cbCode);
14447             *ppvFuncletEnd = (LPVOID)(uImageBase + pFunctionEntry->EndAddress);
14448             return (LPVOID)(uImageBase + pFunctionEntry->BeginAddress);
14449         }
14450
14451         pvFuncletStart = (LPVOID)((TADDR)pvFuncletStart + 1);
14452         cbCode--;
14453     }
14454
14455     return NULL;
14456 }
14457 #endif // defined(_DEBUG) && !defined(HAVE_GCCOVER)
14458 #endif // defined(_TARGET_AMD64_)