New jit intrinsic support (#13815)
[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 "tls.h"
41 #include "ecall.h"
42 #include "generics.h"
43 #include "typestring.h"
44 #include "stackprobe.h"
45 #include "typedesc.h"
46 #include "genericdict.h"
47 #include "array.h"
48 #include "debuginfostore.h"
49 #include "safemath.h"
50 #include "runtimehandles.h"
51 #include "sigbuilder.h"
52 #include "openum.h"
53 #ifdef HAVE_GCCOVER
54 #include "gccover.h"
55 #endif // HAVE_GCCOVER
56
57 #include "mdaassistants.h"
58
59 #ifdef FEATURE_PREJIT
60 #include "compile.h"
61 #include "corcompile.h"
62 #endif // FEATURE_PREJIT
63
64
65 #ifdef FEATURE_INTERPRETER
66 #include "interpreter.h"
67 #endif // FEATURE_INTERPRETER
68
69 #ifdef FEATURE_PERFMAP
70 #include "perfmap.h"
71 #endif
72
73 // The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro
74 //
75
76 #define JIT_TO_EE_TRANSITION()          MAKE_CURRENT_THREAD_AVAILABLE_EX(m_pThread);                \
77                                         _ASSERTE(CURRENT_THREAD == GetThread());                    \
78                                         INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE;               \
79                                         COOPERATIVE_TRANSITION_BEGIN();                             \
80                                         START_NON_JIT_PERF();
81
82 #define EE_TO_JIT_TRANSITION()          STOP_NON_JIT_PERF();                                        \
83                                         COOPERATIVE_TRANSITION_END();                               \
84                                         UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE;
85
86 #define JIT_TO_EE_TRANSITION_LEAF()
87 #define EE_TO_JIT_TRANSITION_LEAF()
88
89
90 #if defined(CROSSGEN_COMPILE)
91 static const char *const hlpNameTable[CORINFO_HELP_COUNT] = {
92 #define JITHELPER(code, pfnHelper, sig) #code,
93 #include "jithelpers.h"
94 };
95 #endif
96
97 #ifdef DACCESS_COMPILE
98
99 // The real definitions are in jithelpers.cpp. However, those files are not included in the DAC build.
100 // Hence, we add them here.
101 GARY_IMPL(VMHELPDEF, hlpFuncTable, CORINFO_HELP_COUNT);
102 GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);
103
104 #else // DACCESS_COMPILE
105
106 /*********************************************************************/
107
108 #if defined(ENABLE_PERF_COUNTERS)
109 LARGE_INTEGER g_lastTimeInJitCompilation;
110 #endif
111
112 /*********************************************************************/
113
114 inline CORINFO_MODULE_HANDLE GetScopeHandle(MethodDesc* method) 
115 {
116     LIMITED_METHOD_CONTRACT;
117     if (method->IsDynamicMethod())
118     {
119         return MakeDynamicScope(method->AsDynamicMethodDesc()->GetResolver());
120     }
121     else
122     {
123         return GetScopeHandle(method->GetModule());
124     }
125 }
126
127 //This is common refactored code from within several of the access check functions.
128 BOOL ModifyCheckForDynamicMethod(DynamicResolver *pResolver,
129                                  TypeHandle *pOwnerTypeForSecurity,
130                                  AccessCheckOptions::AccessCheckType *pAccessCheckType,
131                                  DynamicResolver** ppAccessContext)
132 {
133     CONTRACTL {
134         STANDARD_VM_CHECK;
135         PRECONDITION(CheckPointer(pResolver));
136         PRECONDITION(CheckPointer(pOwnerTypeForSecurity));
137         PRECONDITION(CheckPointer(pAccessCheckType));
138         PRECONDITION(CheckPointer(ppAccessContext));
139         PRECONDITION(*pAccessCheckType == AccessCheckOptions::kNormalAccessibilityChecks);
140     } CONTRACTL_END;
141
142     BOOL doAccessCheck = TRUE;
143
144     //Do not blindly initialize fields, since they've already got important values.
145     DynamicResolver::SecurityControlFlags dwSecurityFlags = DynamicResolver::Default;
146         
147     TypeHandle dynamicOwner;
148     pResolver->GetJitContext(&dwSecurityFlags, &dynamicOwner);
149     if (!dynamicOwner.IsNull())
150         *pOwnerTypeForSecurity = dynamicOwner;
151
152     if (dwSecurityFlags & DynamicResolver::SkipVisibilityChecks)
153     {
154         doAccessCheck = FALSE;
155     }
156     else if (dwSecurityFlags & DynamicResolver::RestrictedSkipVisibilityChecks)
157     {
158         *pAccessCheckType = AccessCheckOptions::kRestrictedMemberAccessNoTransparency;
159     }
160     else
161     {
162         *pAccessCheckType = AccessCheckOptions::kNormalAccessNoTransparency;
163     }
164
165     return doAccessCheck;
166 }
167
168 /*****************************************************************************/
169
170 // Initialize from data we passed across to the JIT
171 inline static void GetTypeContext(const CORINFO_SIG_INST *info, SigTypeContext *pTypeContext)
172 {
173     LIMITED_METHOD_CONTRACT;
174     SigTypeContext::InitTypeContext(
175         Instantiation((TypeHandle *) info->classInst, info->classInstCount), 
176         Instantiation((TypeHandle *) info->methInst, info->methInstCount), 
177         pTypeContext);
178 }
179
180 static MethodDesc* GetMethodFromContext(CORINFO_CONTEXT_HANDLE context)
181 {
182     LIMITED_METHOD_CONTRACT;
183     if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
184     {
185         return NULL;
186     }
187     else
188     {
189         return GetMethod((CORINFO_METHOD_HANDLE)((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
190     }
191 }
192
193 static TypeHandle GetTypeFromContext(CORINFO_CONTEXT_HANDLE context)
194 {
195     LIMITED_METHOD_CONTRACT;
196     if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
197     {
198         return TypeHandle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
199     }
200     else
201     {
202         MethodTable * pMT = GetMethodFromContext(context)->GetMethodTable();
203         return TypeHandle(pMT);
204     }
205 }
206
207 // Initialize from a context parameter passed to the JIT and back.  This is a parameter
208 // that indicates which method is being jitted.
209
210 inline static void GetTypeContext(CORINFO_CONTEXT_HANDLE context, SigTypeContext *pTypeContext)
211 {
212     CONTRACTL
213     {
214         NOTHROW;
215         GC_NOTRIGGER;
216         SO_TOLERANT;
217         MODE_ANY;
218         PRECONDITION(context != NULL);
219     }
220     CONTRACTL_END;
221     if (GetMethodFromContext(context))
222     {
223         SigTypeContext::InitTypeContext(GetMethodFromContext(context), pTypeContext);
224     }
225     else
226     {
227         SigTypeContext::InitTypeContext(GetTypeFromContext(context), pTypeContext);
228     }
229 }
230
231 static BOOL ContextIsShared(CORINFO_CONTEXT_HANDLE context)
232 {
233     LIMITED_METHOD_CONTRACT;
234     MethodDesc *pContextMD = GetMethodFromContext(context);
235     if (pContextMD != NULL)
236     {
237         return pContextMD->IsSharedByGenericInstantiations();
238     }
239     else
240     {
241         // Type handle contexts are non-shared and are used for inlining of
242         // non-generic methods in generic classes
243         return FALSE;
244     }
245 }
246
247 // Returns true if context is providing any generic variables
248 static BOOL ContextIsInstantiated(CORINFO_CONTEXT_HANDLE context)
249 {
250     LIMITED_METHOD_CONTRACT;
251     if (GetMethodFromContext(context))
252     {
253         return GetMethodFromContext(context)->HasClassOrMethodInstantiation();
254     }
255     else
256     {
257         return GetTypeFromContext(context).HasInstantiation();
258     }
259 }
260
261 /*********************************************************************/
262 // This normalizes EE type information into the form expected by the JIT.
263 //
264 // If typeHnd contains exact type information, then *clsRet will contain
265 // the normalized CORINFO_CLASS_HANDLE information on return.
266
267 // Static
268 CorInfoType CEEInfo::asCorInfoType(CorElementType eeType,
269                                    TypeHandle typeHnd, /* optional in */
270                                    CORINFO_CLASS_HANDLE *clsRet/* optional out */ ) {
271     CONTRACT(CorInfoType) {
272         THROWS;
273         GC_TRIGGERS;
274         PRECONDITION((CorTypeInfo::IsGenericVariable(eeType)) == 
275                      (!typeHnd.IsNull() && typeHnd.IsGenericVariable()));
276         PRECONDITION(eeType != ELEMENT_TYPE_GENERICINST);
277     } CONTRACT_END;
278
279     TypeHandle typeHndUpdated = typeHnd;
280
281     if (!typeHnd.IsNull())
282     {
283         CorElementType normType = typeHnd.GetInternalCorElementType();
284         // If we have a type handle, then it has the better type
285         // in some cases
286         if (eeType == ELEMENT_TYPE_VALUETYPE && !CorTypeInfo::IsObjRef(normType))
287             eeType = normType;
288
289         // Zap the typeHnd when the type _really_ is a primitive
290         // as far as verification is concerned. Returning a null class
291         // handle means it is is a primitive.
292         //
293         // Enums are exactly like primitives, even from a verification standpoint,
294         // so we zap the type handle in this case.
295         //
296         // However RuntimeTypeHandle etc. are reported as E_T_INT (or something like that)
297         // but don't count as primitives as far as verification is concerned...
298         //
299         // To make things stranger, TypedReference returns true for "IsTruePrimitive".
300         // However the JIT likes us to report the type handle in that case.
301         if (!typeHnd.IsTypeDesc() && (
302                 (typeHnd.AsMethodTable()->IsTruePrimitive() && typeHnd != TypeHandle(g_TypedReferenceMT))
303                     || typeHnd.AsMethodTable()->IsEnum()) )
304         {
305             typeHndUpdated = TypeHandle();
306         }
307
308     }
309
310     static const BYTE map[] = {
311         CORINFO_TYPE_UNDEF,
312         CORINFO_TYPE_VOID,
313         CORINFO_TYPE_BOOL,
314         CORINFO_TYPE_CHAR,
315         CORINFO_TYPE_BYTE,
316         CORINFO_TYPE_UBYTE,
317         CORINFO_TYPE_SHORT,
318         CORINFO_TYPE_USHORT,
319         CORINFO_TYPE_INT,
320         CORINFO_TYPE_UINT,
321         CORINFO_TYPE_LONG,
322         CORINFO_TYPE_ULONG,
323         CORINFO_TYPE_FLOAT,
324         CORINFO_TYPE_DOUBLE,
325         CORINFO_TYPE_STRING,
326         CORINFO_TYPE_PTR,            // PTR
327         CORINFO_TYPE_BYREF,
328         CORINFO_TYPE_VALUECLASS,
329         CORINFO_TYPE_CLASS,
330         CORINFO_TYPE_VAR,            // VAR (type variable)
331         CORINFO_TYPE_CLASS,          // ARRAY
332         CORINFO_TYPE_CLASS,          // WITH
333         CORINFO_TYPE_REFANY,
334         CORINFO_TYPE_UNDEF,          // VALUEARRAY_UNSUPPORTED
335         CORINFO_TYPE_NATIVEINT,      // I
336         CORINFO_TYPE_NATIVEUINT,     // U
337         CORINFO_TYPE_UNDEF,          // R_UNSUPPORTED
338
339         // put the correct type when we know our implementation
340         CORINFO_TYPE_PTR,            // FNPTR
341         CORINFO_TYPE_CLASS,          // OBJECT
342         CORINFO_TYPE_CLASS,          // SZARRAY
343         CORINFO_TYPE_VAR,            // MVAR
344
345         CORINFO_TYPE_UNDEF,          // CMOD_REQD
346         CORINFO_TYPE_UNDEF,          // CMOD_OPT
347         CORINFO_TYPE_UNDEF,          // INTERNAL
348         };
349
350     _ASSERTE(sizeof(map) == ELEMENT_TYPE_MAX);
351     _ASSERTE(eeType < (CorElementType) sizeof(map));
352         // spot check of the map
353     _ASSERTE((CorInfoType) map[ELEMENT_TYPE_I4] == CORINFO_TYPE_INT);
354     _ASSERTE((CorInfoType) map[ELEMENT_TYPE_PTR] == CORINFO_TYPE_PTR);
355     _ASSERTE((CorInfoType) map[ELEMENT_TYPE_TYPEDBYREF] == CORINFO_TYPE_REFANY);
356
357     CorInfoType res = ((unsigned)eeType < ELEMENT_TYPE_MAX) ? ((CorInfoType) map[(unsigned)eeType]) : CORINFO_TYPE_UNDEF;
358
359     if (clsRet)
360         *clsRet = CORINFO_CLASS_HANDLE(typeHndUpdated.AsPtr());
361
362     RETURN res;
363 }
364
365
366 inline static CorInfoType toJitType(TypeHandle typeHnd, CORINFO_CLASS_HANDLE *clsRet = NULL)
367 {
368     WRAPPER_NO_CONTRACT;
369     return CEEInfo::asCorInfoType(typeHnd.GetInternalCorElementType(), typeHnd, clsRet);
370 }
371
372 #ifdef _DEBUG
373 void DebugSecurityCalloutStress(CORINFO_METHOD_HANDLE methodBeingCompiledHnd,
374                                 CorInfoIsAccessAllowedResult& currentAnswer,
375                                 CorInfoSecurityRuntimeChecks& currentRuntimeChecks)
376 {
377     WRAPPER_NO_CONTRACT;
378     if (currentAnswer != CORINFO_ACCESS_ALLOWED)
379     {
380         return;
381     }
382     static ConfigDWORD AlwaysInsertCallout;
383     switch (AlwaysInsertCallout.val(CLRConfig::INTERNAL_Security_AlwaysInsertCallout))
384     {
385     case 0: //No stress
386         return;
387     case 1: //Always
388         break;
389     default: //2 (or anything else), do so half the time
390         if (((size_t(methodBeingCompiledHnd) / sizeof(void*)) % 64) < 32)
391             return;
392     }
393     //Do the stress
394     currentAnswer = CORINFO_ACCESS_RUNTIME_CHECK;
395     currentRuntimeChecks = CORINFO_ACCESS_SECURITY_NONE;
396 }
397 #else
398 #define DebugSecurityCalloutStress(a, b, c) do {} while(0)
399 #endif //_DEBUG
400
401 void CheckForEquivalenceAndLoadTypeBeforeCodeIsRun(Module *pModule, mdToken token, Module *pDefModule, mdToken defToken, const SigParser *ptr, SigTypeContext *pTypeContext, void *pData)
402 {
403     CONTRACTL
404     {
405         THROWS;
406         GC_TRIGGERS;
407         SO_INTOLERANT;
408     }
409     CONTRACTL_END;
410
411     if (IsTypeDefEquivalent(defToken, pDefModule))
412     {
413         SigPointer sigPtr(*ptr);
414         TypeHandle th = sigPtr.GetTypeHandleThrowing(pModule, pTypeContext);
415         ((ICorDynamicInfo *)pData)->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(th.AsPtr()));
416     }
417 }
418
419 inline static void TypeEquivalenceFixupSpecificationHelper(ICorDynamicInfo * pCorInfo, MethodDesc *pMD)
420 {
421     STANDARD_VM_CONTRACT;
422
423     // A fixup is necessary to ensure that the parameters to the method are loaded before the method
424     // is called. In these cases we will not perform the appropriate loading when we load parameter
425     // types because with type equivalence, the parameter types at the call site do not necessarily
426     // match that those in the actual function. (They must be equivalent, but not necessarily the same.)
427     // In non-ngen scenarios this code here will force the types to be loaded directly by the call to
428     // HasTypeEquivalentStructParameters.
429     if (!pMD->IsVirtual())
430     {
431         if (pMD->HasTypeEquivalentStructParameters())
432         {
433             if (IsCompilationProcess())
434                 pMD->WalkValueTypeParameters(pMD->GetMethodTable(), CheckForEquivalenceAndLoadTypeBeforeCodeIsRun, pCorInfo);
435         }
436     }
437     else
438     {
439         if (pMD->GetMethodTable()->DependsOnEquivalentOrForwardedStructs())
440         {
441             if (pMD->HasTypeEquivalentStructParameters())
442                 pCorInfo->classMustBeLoadedBeforeCodeIsRun((CORINFO_CLASS_HANDLE)pMD->GetMethodTable());
443         }
444     }
445 }
446
447 //---------------------------------------------------------------------------------------
448 // 
449 //@GENERICS:
450 // The method handle is used to instantiate method and class type parameters
451 // It's also used to determine whether an extra dictionary parameter is required
452 //
453 // sig          - Input metadata signature
454 // scopeHnd     - The signature is to be interpreted in the context of this scope (module)
455 // token        - Metadata token used to refer to the signature (may be mdTokenNil for dynamic methods)
456 // sigRet       - Resulting output signature in a format that is understood by native compilers
457 // pContextMD   - The method with any instantiation information (may be NULL)
458 // localSig     - Is it a local variables declaration, or a method signature (with return type, etc).
459 // contextType  - The type with any instantiaton information
460 // 
461 //static
462 void 
463 CEEInfo::ConvToJitSig(
464     PCCOR_SIGNATURE       pSig, 
465     DWORD                 cbSig, 
466     CORINFO_MODULE_HANDLE scopeHnd, 
467     mdToken               token, 
468     CORINFO_SIG_INFO *    sigRet,
469     MethodDesc *          pContextMD,
470     bool                  localSig,
471     TypeHandle            contextType)
472 {
473     CONTRACTL {
474         THROWS;
475         GC_TRIGGERS;
476     } CONTRACTL_END;
477
478     SigTypeContext typeContext;
479
480     if (pContextMD)
481     {
482         SigTypeContext::InitTypeContext(pContextMD, contextType, &typeContext);
483     }
484     else
485     {
486         SigTypeContext::InitTypeContext(contextType, &typeContext);
487     }
488
489     _ASSERTE(CORINFO_CALLCONV_DEFAULT == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_DEFAULT);
490     _ASSERTE(CORINFO_CALLCONV_VARARG == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_VARARG);
491     _ASSERTE(CORINFO_CALLCONV_MASK == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_MASK);
492     _ASSERTE(CORINFO_CALLCONV_HASTHIS == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_HASTHIS);
493
494     TypeHandle typeHnd = TypeHandle();
495
496     sigRet->pSig = pSig;
497     sigRet->cbSig = cbSig;
498     sigRet->retTypeClass = 0;
499     sigRet->retTypeSigClass = 0;
500     sigRet->scope = scopeHnd;
501     sigRet->token = token;
502     sigRet->sigInst.classInst = (CORINFO_CLASS_HANDLE *) typeContext.m_classInst.GetRawArgs();
503     sigRet->sigInst.classInstCount = (unsigned) typeContext.m_classInst.GetNumArgs();
504     sigRet->sigInst.methInst = (CORINFO_CLASS_HANDLE *) typeContext.m_methodInst.GetRawArgs();
505     sigRet->sigInst.methInstCount = (unsigned) typeContext.m_methodInst.GetNumArgs();
506
507     SigPointer sig(pSig, cbSig);
508
509     if (!localSig)
510     {
511         // This is a method signature which includes calling convention, return type, 
512         // arguments, etc
513
514         _ASSERTE(!sig.IsNull());
515         Module * module = GetModule(scopeHnd);
516         sigRet->flags = 0;
517
518         ULONG data;
519         IfFailThrow(sig.GetCallingConvInfo(&data));
520         sigRet->callConv = (CorInfoCallConv) data;
521
522         if ((isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_VARARG)) ||
523             (isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_NATIVEVARARG)))
524         {
525             // This signature corresponds to a method that uses varargs, which are not supported.
526              COMPlusThrow(kInvalidProgramException, IDS_EE_VARARG_NOT_SUPPORTED);
527         }
528
529         // Skip number of type arguments
530         if (sigRet->callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
531           IfFailThrow(sig.GetData(NULL));
532
533         ULONG numArgs;
534         IfFailThrow(sig.GetData(&numArgs));
535         if (numArgs != (unsigned short) numArgs)
536             COMPlusThrowHR(COR_E_INVALIDPROGRAM);
537
538         sigRet->numArgs = (unsigned short) numArgs;
539
540         CorElementType type = sig.PeekElemTypeClosed(module, &typeContext);
541
542         if (!CorTypeInfo::IsPrimitiveType(type))
543         {
544             typeHnd = sig.GetTypeHandleThrowing(module, &typeContext);
545             _ASSERTE(!typeHnd.IsNull());
546
547             // I believe it doesn't make any diff. if this is
548             // GetInternalCorElementType or GetSignatureCorElementType
549             type = typeHnd.GetSignatureCorElementType();
550
551         }
552         sigRet->retType = CEEInfo::asCorInfoType(type, typeHnd, &sigRet->retTypeClass);
553         sigRet->retTypeSigClass = CORINFO_CLASS_HANDLE(typeHnd.AsPtr());
554
555         IfFailThrow(sig.SkipExactlyOne());  // must to a skip so we skip any class tokens associated with the return type
556         _ASSERTE(sigRet->retType < CORINFO_TYPE_COUNT);
557
558         sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
559     } 
560     else
561     {
562         // This is local variables declaration
563
564         sigRet->callConv = CORINFO_CALLCONV_DEFAULT;
565         sigRet->retType = CORINFO_TYPE_VOID;
566         sigRet->flags   = CORINFO_SIGFLAG_IS_LOCAL_SIG;
567         sigRet->numArgs = 0;
568         if (!sig.IsNull())
569         {
570             ULONG callConv;
571             IfFailThrow(sig.GetCallingConvInfo(&callConv));
572             if (callConv != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG)
573             {
574                 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_CALLCONV_NOT_LOCAL_SIG);
575             }
576
577             ULONG numArgs;
578             IfFailThrow(sig.GetData(&numArgs));
579             
580             if (numArgs != (unsigned short) numArgs)
581                 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
582
583             sigRet->numArgs = (unsigned short) numArgs;
584         }
585
586         sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
587     }
588
589     _ASSERTE(SigInfoFlagsAreValid(sigRet));
590 } // CEEInfo::ConvToJitSig
591
592 //---------------------------------------------------------------------------------------
593 // 
594 CORINFO_CLASS_HANDLE CEEInfo::getTokenTypeAsHandle (CORINFO_RESOLVED_TOKEN * pResolvedToken)
595 {
596     CONTRACTL {
597         SO_TOLERANT;
598         THROWS;
599         GC_TRIGGERS;
600         MODE_PREEMPTIVE;
601     } CONTRACTL_END;
602
603     CORINFO_CLASS_HANDLE tokenType = NULL;
604
605     JIT_TO_EE_TRANSITION();
606
607     _ASSERTE((pResolvedToken->hMethod == NULL) || (pResolvedToken->hField == NULL));
608
609     BinderClassID classID = CLASS__TYPE_HANDLE;
610
611     if (pResolvedToken->hMethod != NULL)
612     {
613         classID = CLASS__METHOD_HANDLE;
614     }
615     else
616     if (pResolvedToken->hField != NULL)
617     {
618         classID = CLASS__FIELD_HANDLE;
619     }
620
621     tokenType = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(classID));
622
623     EE_TO_JIT_TRANSITION();
624
625     return tokenType;
626 }
627
628 /*********************************************************************/
629 size_t CEEInfo::findNameOfToken (
630             CORINFO_MODULE_HANDLE       scopeHnd,
631             mdToken                     metaTOK,
632             __out_ecount (FQNameCapacity)  char * szFQName,
633             size_t FQNameCapacity)
634 {
635     CONTRACTL {
636         SO_TOLERANT;
637         THROWS;
638         GC_TRIGGERS;
639         MODE_PREEMPTIVE;
640     } CONTRACTL_END;
641
642     size_t NameLen = 0;
643
644     JIT_TO_EE_TRANSITION();
645
646     if (IsDynamicScope(scopeHnd))
647     {
648         strncpy_s (szFQName, FQNameCapacity, "DynamicToken", FQNameCapacity - 1);
649         NameLen = strlen (szFQName);
650     }
651     else
652     {
653         Module* module = (Module *)scopeHnd;
654         NameLen = findNameOfToken(module, metaTOK, szFQName, FQNameCapacity);
655     }
656         
657     EE_TO_JIT_TRANSITION();
658
659     return NameLen;
660 }
661
662 CorInfoCanSkipVerificationResult CEEInfo::canSkipMethodVerification(CORINFO_METHOD_HANDLE ftnHnd)
663 {
664     CONTRACTL {
665         SO_TOLERANT;
666         THROWS;
667         GC_TRIGGERS;
668         MODE_PREEMPTIVE;
669     } CONTRACTL_END;
670
671     return CORINFO_VERIFICATION_CAN_SKIP;
672 }
673
674 /*********************************************************************/
675 BOOL CEEInfo::shouldEnforceCallvirtRestriction(
676         CORINFO_MODULE_HANDLE scopeHnd)
677 {
678     LIMITED_METHOD_CONTRACT;
679     // see vsw 599197
680     // verification rule added in whidbey requiring virtual methods
681     // to be called via callvirt except if certain other rules are
682     // obeyed.
683
684     if (g_pConfig->LegacyVirtualMethodCallVerification())
685         return false;
686     else 
687         return true;
688        
689 }
690
691 #ifdef FEATURE_READYTORUN_COMPILER
692
693 // Returns true if assemblies are in the same version bubble
694 // Right now each assembly is in its own version bubble.
695 // If the need arises (i.e. performance issues) we will define sets of assemblies (e.g. all app assemblies)
696 // The main point is that all this logic is concentrated in one place.
697
698 // NOTICE: If you change this logic to allow multi-assembly version bubbles you
699 // need to consider the impact on diagnostic tools. Currently there is an inlining
700 // table which tracks inliner/inlinee relationships in R2R images but it is not
701 // yet capable of encoding cross-assembly inlines. The scenario where this
702 // may show are instrumenting profilers that want to instrument a given method A
703 // using the ReJit APIs. If method A happens to inlined within method B in another 
704 // assembly then the profiler needs to know that so it can rejit B too.
705 // The recommended approach is to upgrade the inlining table (vm\inlinetracking.h\.cpp)
706 // now that presumably R2R images have some way to refer to methods in other
707 // assemblies in their version bubble. Chat with the diagnostics team if you need more 
708 // details.
709 //
710 // There already is a case where cross-assembly inlining occurs in an
711 // unreported fashion for methods marked NonVersionable. There is a specific 
712 // exemption called out for this on ICorProfilerInfo6::EnumNgenModuleMethodsInliningThisMethod
713 // and the impact of the cut was vetted with partners. It would not be appropriate 
714 // to increase that unreported set without additional review.
715
716
717 bool IsInSameVersionBubble(Assembly * current, Assembly * target)
718 {
719     LIMITED_METHOD_CONTRACT;
720
721     // trivial case: current and target are identical
722     // DO NOT change this without reading the notice above
723     if (current == target)
724         return true;
725
726     return false;
727 }
728
729 // Returns true if the assemblies defining current and target are in the same version bubble
730 static bool IsInSameVersionBubble(MethodDesc* pCurMD, MethodDesc *pTargetMD)
731 {
732     LIMITED_METHOD_CONTRACT;
733     // DO NOT change this without reading the notice above
734     if (IsInSameVersionBubble(pCurMD->GetModule()->GetAssembly(),
735                               pTargetMD->GetModule()->GetAssembly()))
736     {
737         return true;
738     }
739     if (IsReadyToRunCompilation())
740     {
741         if (pTargetMD->GetModule()->GetMDImport()->GetCustomAttributeByName(pTargetMD->GetMemberDef(),
742                 NONVERSIONABLE_TYPE, NULL, NULL) == S_OK)
743         {
744             return true;
745         }
746     }
747     return false;
748
749 }
750
751 #endif // FEATURE_READYTORUN_COMPILER
752
753
754 /*********************************************************************/
755 CorInfoCanSkipVerificationResult CEEInfo::canSkipVerification(
756         CORINFO_MODULE_HANDLE moduleHnd)
757 {
758     CONTRACTL {
759         SO_TOLERANT;
760         THROWS;
761         GC_TRIGGERS;
762         MODE_PREEMPTIVE;
763     } CONTRACTL_END;
764
765     return CORINFO_VERIFICATION_CAN_SKIP;
766 }
767
768 /*********************************************************************/
769 // Checks if the given metadata token is valid
770 BOOL CEEInfo::isValidToken (
771         CORINFO_MODULE_HANDLE       module,
772         mdToken                     metaTOK)
773 {
774     CONTRACTL {
775         SO_TOLERANT;
776         NOTHROW;
777         GC_NOTRIGGER;
778         MODE_ANY;
779     } CONTRACTL_END;
780
781     BOOL result = FALSE;
782
783     JIT_TO_EE_TRANSITION_LEAF();
784
785     if (IsDynamicScope(module))
786     {
787         // No explicit token validation for dynamic code. Validation is
788         // side-effect of token resolution.
789         result = TRUE;
790     }
791     else
792     {
793         result = ((Module *)module)->GetMDImport()->IsValidToken(metaTOK);
794     }
795
796     EE_TO_JIT_TRANSITION_LEAF();
797
798     return result;
799 }
800
801 /*********************************************************************/
802 // Checks if the given metadata token is valid StringRef
803 BOOL CEEInfo::isValidStringRef (
804         CORINFO_MODULE_HANDLE       module,
805         mdToken                     metaTOK)
806 {
807     CONTRACTL {
808         SO_TOLERANT;
809         THROWS;
810         GC_TRIGGERS;
811         MODE_PREEMPTIVE;
812     } CONTRACTL_END;
813
814     BOOL result = FALSE;
815
816     JIT_TO_EE_TRANSITION();
817
818     if (IsDynamicScope(module))
819     {
820         result = GetDynamicResolver(module)->IsValidStringRef(metaTOK);
821     }
822     else
823     {
824         result = ((Module *)module)->CheckStringRef(metaTOK);
825         if (result)
826         {
827             DWORD dwCharCount;    
828             LPCWSTR pString;
829             result = (!FAILED(((Module *)module)->GetMDImport()->GetUserString(metaTOK, &dwCharCount, NULL, &pString)) &&
830                      pString != NULL);
831         }
832     }
833
834     EE_TO_JIT_TRANSITION();
835
836     return result;
837 }
838
839 /* static */
840 size_t CEEInfo::findNameOfToken (Module* module,
841                                                  mdToken metaTOK,
842                                                  __out_ecount (FQNameCapacity) char * szFQName,
843                                                  size_t FQNameCapacity)
844 {
845     CONTRACTL {
846         NOTHROW;
847         GC_TRIGGERS;
848     } CONTRACTL_END;
849
850 #ifdef _DEBUG
851     PCCOR_SIGNATURE sig = NULL;
852     DWORD           cSig;
853     LPCUTF8         pszNamespace = NULL;
854     LPCUTF8         pszClassName = NULL;
855     
856     mdToken tokType = TypeFromToken(metaTOK);
857     switch(tokType)
858     {
859         case mdtTypeRef:
860             {
861                 if (FAILED(module->GetMDImport()->GetNameOfTypeRef(metaTOK, &pszNamespace, &pszClassName)))
862                 {
863                     pszNamespace = pszClassName = "Invalid TypeRef record";
864                 }
865                 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
866                 break;
867             }
868         case mdtTypeDef:
869             {
870                 if (FAILED(module->GetMDImport()->GetNameOfTypeDef(metaTOK, &pszClassName, &pszNamespace)))
871                 {
872                     pszClassName = pszNamespace = "Invalid TypeDef record";
873                 }
874                 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
875                 break;
876             }
877         case mdtFieldDef:
878             {
879                 LPCSTR szFieldName;
880                 if (FAILED(module->GetMDImport()->GetNameOfFieldDef(metaTOK, &szFieldName)))
881                 {
882                     szFieldName = "Invalid FieldDef record";
883                 }
884                 strncpy_s(szFQName,  FQNameCapacity,  (char*)szFieldName, FQNameCapacity - 1);
885                 break;
886             }
887         case mdtMethodDef:
888             {
889                 LPCSTR szMethodName;
890                 if (FAILED(module->GetMDImport()->GetNameOfMethodDef(metaTOK, &szMethodName)))
891                 {
892                     szMethodName = "Invalid MethodDef record";
893                 }
894                 strncpy_s(szFQName, FQNameCapacity, (char*)szMethodName, FQNameCapacity - 1);
895                 break;
896             }
897         case mdtMemberRef:
898             {
899                 LPCSTR szName;
900                 if (FAILED(module->GetMDImport()->GetNameAndSigOfMemberRef((mdMemberRef)metaTOK, &sig, &cSig, &szName)))
901                 {
902                     szName = "Invalid MemberRef record";
903                 }
904                 strncpy_s(szFQName, FQNameCapacity, (char *)szName, FQNameCapacity - 1);
905                 break;
906             }
907         default:
908             sprintf_s(szFQName, FQNameCapacity, "!TK_%x", metaTOK);
909             break;
910     }
911
912 #else // !_DEBUG
913     strncpy_s (szFQName, FQNameCapacity, "<UNKNOWN>", FQNameCapacity - 1);
914 #endif // _DEBUG
915
916
917     return strlen (szFQName);
918 }
919
920 CorInfoHelpFunc CEEInfo::getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle)
921
922     CONTRACTL {
923         SO_TOLERANT;
924         NOTHROW;
925         GC_NOTRIGGER;
926         MODE_PREEMPTIVE;
927     } CONTRACTL_END;
928
929     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
930
931     JIT_TO_EE_TRANSITION_LEAF();
932
933     result = IsDynamicScope(handle) ? CORINFO_HELP_UNDEF : CORINFO_HELP_STRCNS;
934
935     EE_TO_JIT_TRANSITION_LEAF();
936
937     return result;
938 }
939
940
941 CHECK CheckContext(CORINFO_MODULE_HANDLE scopeHnd, CORINFO_CONTEXT_HANDLE context)
942 {
943     CHECK_MSG(scopeHnd != NULL, "Illegal null scope");
944     CHECK_MSG(((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK) != NULL, "Illegal null context");
945     if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
946     {
947         TypeHandle handle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
948         CHECK_MSG(handle.GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
949     }
950     else
951     {
952         MethodDesc* handle = (MethodDesc*) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK);
953         CHECK_MSG(handle->GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
954     }
955
956     CHECK_OK;
957 }
958
959
960 static DECLSPEC_NORETURN void ThrowBadTokenException(CORINFO_RESOLVED_TOKEN * pResolvedToken)
961 {
962     switch (pResolvedToken->tokenType & CORINFO_TOKENKIND_Mask)
963     {
964     case CORINFO_TOKENKIND_Class:
965         COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_CLASS_TOKEN);
966     case CORINFO_TOKENKIND_Method:
967         COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN);
968     case CORINFO_TOKENKIND_Field:
969         COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN);
970     default:
971         COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
972     }
973 }
974
975 /*********************************************************************/
976 void CEEInfo::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken)
977 {
978     CONTRACTL {
979         SO_TOLERANT;
980         THROWS;
981         GC_TRIGGERS;
982         MODE_PREEMPTIVE;
983     } CONTRACTL_END;
984
985     JIT_TO_EE_TRANSITION();
986
987     _ASSERTE(CheckContext(pResolvedToken->tokenScope, pResolvedToken->tokenContext));
988
989     pResolvedToken->pTypeSpec = NULL;
990     pResolvedToken->cbTypeSpec = NULL;
991     pResolvedToken->pMethodSpec = NULL;
992     pResolvedToken->cbMethodSpec = NULL;
993
994     TypeHandle th;
995     MethodDesc * pMD = NULL;
996     FieldDesc * pFD = NULL;
997
998     CorInfoTokenKind tokenType = pResolvedToken->tokenType;
999
1000     if (IsDynamicScope(pResolvedToken->tokenScope))
1001     {
1002         GetDynamicResolver(pResolvedToken->tokenScope)->ResolveToken(pResolvedToken->token, &th, &pMD, &pFD);
1003
1004         //
1005         // Check that we got the expected handles and fill in missing data if necessary
1006         //
1007
1008         CorTokenType tkType = (CorTokenType)TypeFromToken(pResolvedToken->token);
1009
1010         if (pMD != NULL)
1011         {
1012             if ((tkType != mdtMethodDef) && (tkType != mdtMemberRef))
1013                 ThrowBadTokenException(pResolvedToken);
1014             if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1015                 ThrowBadTokenException(pResolvedToken);
1016             if (th.IsNull())
1017                 th = pMD->GetMethodTable();
1018
1019             // "PermitUninstDefOrRef" check
1020             if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && pMD->ContainsGenericVariables())
1021             {
1022                 COMPlusThrow(kInvalidProgramException);
1023             }
1024
1025             // if this is a BoxedEntryPointStub get the UnboxedEntryPoint one
1026             if (pMD->IsUnboxingStub())
1027             {
1028                 pMD = pMD->GetMethodTable()->GetUnboxedEntryPointMD(pMD);
1029             }
1030
1031             // Activate target if required
1032             if (tokenType != CORINFO_TOKENKIND_Ldtoken)
1033             {
1034                 ScanTokenForDynamicScope(pResolvedToken, th, pMD);
1035             }
1036         }
1037         else
1038         if (pFD != NULL)
1039         {
1040             if ((tkType != mdtFieldDef) && (tkType != mdtMemberRef))
1041                 ThrowBadTokenException(pResolvedToken);
1042             if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1043                 ThrowBadTokenException(pResolvedToken);
1044             if (th.IsNull())
1045                 th = pFD->GetApproxEnclosingMethodTable();
1046
1047             if (pFD->IsStatic() && (tokenType != CORINFO_TOKENKIND_Ldtoken))
1048             {
1049                 ScanTokenForDynamicScope(pResolvedToken, th);
1050             }
1051         }
1052         else
1053         {
1054             if ((tkType != mdtTypeDef) && (tkType != mdtTypeRef))
1055                 ThrowBadTokenException(pResolvedToken);
1056             if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1057                 ThrowBadTokenException(pResolvedToken);
1058             if (th.IsNull())
1059                 ThrowBadTokenException(pResolvedToken);
1060
1061             if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained)
1062             {
1063                 ScanTokenForDynamicScope(pResolvedToken, th);
1064             }
1065         }
1066
1067         _ASSERTE((pMD == NULL) || (pFD == NULL));
1068         _ASSERTE(!th.IsNull());
1069
1070         // "PermitUninstDefOrRef" check
1071         if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && th.ContainsGenericVariables())
1072         {
1073             COMPlusThrow(kInvalidProgramException);
1074         }
1075
1076         // The JIT always wants to see normalized typedescs for arrays
1077         if (!th.IsTypeDesc() && th.AsMethodTable()->IsArray())
1078         {
1079             MethodTable * pMT = th.AsMethodTable();
1080         
1081             // Load the TypeDesc for the array type.
1082             DWORD rank = pMT->GetRank();
1083             TypeHandle elemType = pMT->GetApproxArrayElementTypeHandle();
1084             th = ClassLoader::LoadArrayTypeThrowing(elemType, pMT->GetInternalCorElementType(), rank);
1085         }
1086     }
1087     else
1088     {
1089         unsigned metaTOK = pResolvedToken->token;
1090         Module * pModule = (Module *)pResolvedToken->tokenScope;
1091
1092         switch (TypeFromToken(metaTOK))
1093         {
1094         case mdtModuleRef:
1095             if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1096                 ThrowBadTokenException(pResolvedToken);
1097         
1098             {
1099                 DomainFile *pTargetModule = pModule->LoadModule(GetAppDomain(), metaTOK, FALSE /* loadResources */);
1100                 if (pTargetModule == NULL)
1101                     COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1102                 th = TypeHandle(pTargetModule->GetModule()->GetGlobalMethodTable());
1103                 if (th.IsNull())
1104                     COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1105             }
1106             break;
1107
1108         case mdtTypeDef:
1109         case mdtTypeRef:
1110             if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1111                 ThrowBadTokenException(pResolvedToken);
1112
1113             th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, metaTOK, 
1114                                          ClassLoader::ThrowIfNotFound, 
1115                                          (tokenType == CORINFO_TOKENKIND_Ldtoken) ? 
1116                                             ClassLoader::PermitUninstDefOrRef : ClassLoader::FailIfUninstDefOrRef);
1117             break;
1118
1119         case mdtTypeSpec:
1120             {
1121                 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1122                     ThrowBadTokenException(pResolvedToken);
1123
1124                 IfFailThrow(pModule->GetMDImport()->GetTypeSpecFromToken(metaTOK, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec));
1125                 
1126                 SigTypeContext typeContext;
1127                 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1128
1129                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1130                 th = sigptr.GetTypeHandleThrowing(pModule, &typeContext);
1131             }
1132             break;
1133
1134         case mdtMethodDef:
1135             if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1136                 ThrowBadTokenException(pResolvedToken);
1137
1138             pMD = MemberLoader::GetMethodDescFromMethodDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1139
1140             th = pMD->GetMethodTable();
1141             break;
1142
1143         case mdtFieldDef:
1144             if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1145                 ThrowBadTokenException(pResolvedToken);
1146
1147             pFD = MemberLoader::GetFieldDescFromFieldDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1148
1149             th = pFD->GetEnclosingMethodTable();
1150             break;
1151
1152         case mdtMemberRef:
1153             {
1154                 SigTypeContext typeContext;
1155                 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1156
1157                 MemberLoader::GetDescFromMemberRef(pModule, metaTOK, &pMD, &pFD, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken),
1158                     &th, TRUE, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec);
1159
1160                 _ASSERTE((pMD != NULL) ^ (pFD != NULL));
1161                 _ASSERTE(!th.IsNull());
1162
1163                 if (pMD != NULL)
1164                 {
1165                     if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1166                         ThrowBadTokenException(pResolvedToken);
1167                 }
1168                 else
1169                 {
1170                     if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1171                         ThrowBadTokenException(pResolvedToken);
1172                 }
1173             }
1174             break;
1175
1176         case mdtMethodSpec:
1177             {
1178                 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1179                     ThrowBadTokenException(pResolvedToken);
1180
1181                 SigTypeContext typeContext;
1182                 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1183
1184                 // We need the method desc to carry exact instantiation, thus allowInstParam == FALSE.
1185                 pMD = MemberLoader::GetMethodDescFromMethodSpec(pModule, metaTOK, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken), FALSE /* allowInstParam */,
1186                     &th, TRUE, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec, &pResolvedToken->pMethodSpec, &pResolvedToken->cbMethodSpec);
1187             }
1188             break;
1189
1190         default:
1191             ThrowBadTokenException(pResolvedToken);
1192         }
1193
1194         //
1195         // Module dependency tracking
1196         //
1197         if (pMD != NULL)
1198         {
1199             ScanToken(pModule, pResolvedToken, th, pMD);
1200         }
1201         else
1202         if (pFD != NULL)
1203         {
1204             if (pFD->IsStatic())
1205                 ScanToken(pModule, pResolvedToken, th);
1206         }
1207         else
1208         {
1209             // It should not be required to trigger the modules cctors for ldtoken, it is done for backward compatibility only.
1210             if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained || tokenType == CORINFO_TOKENKIND_Ldtoken)
1211                 ScanToken(pModule, pResolvedToken, th);
1212         }
1213     }
1214
1215     //
1216     // tokenType specific verification and transformations
1217     //
1218     CorElementType et = th.GetInternalCorElementType();
1219     switch (tokenType)
1220     {            
1221         case CORINFO_TOKENKIND_Ldtoken:
1222             // Allow everything.
1223             break;
1224
1225         case CORINFO_TOKENKIND_Newarr:
1226             // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1227             if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1228                 COMPlusThrow(kInvalidProgramException);
1229
1230             th = ClassLoader::LoadArrayTypeThrowing(th);
1231             break;
1232             
1233         default:
1234             // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1235             if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1236                 COMPlusThrow(kInvalidProgramException);
1237             break;
1238     }
1239
1240     // The JIT interface should always return fully loaded types
1241     _ASSERTE(th.IsFullyLoaded());
1242
1243     pResolvedToken->hClass = CORINFO_CLASS_HANDLE(th.AsPtr());
1244     pResolvedToken->hMethod = CORINFO_METHOD_HANDLE(pMD);
1245     pResolvedToken->hField = CORINFO_FIELD_HANDLE(pFD);
1246
1247     EE_TO_JIT_TRANSITION();
1248 }
1249
1250 /*********************************************************************/
1251 struct TryResolveTokenFilterParam
1252 {
1253     CEEInfo* m_this;
1254     CORINFO_RESOLVED_TOKEN* m_resolvedToken;
1255     EXCEPTION_POINTERS m_exceptionPointers;
1256     bool m_success;
1257 };
1258
1259 bool isValidTokenForTryResolveToken(CEEInfo* info, CORINFO_RESOLVED_TOKEN* resolvedToken)
1260 {
1261     CONTRACTL {
1262         NOTHROW;
1263         GC_NOTRIGGER;
1264         SO_TOLERANT;
1265         MODE_ANY;
1266     } CONTRACTL_END;
1267
1268     if (!info->isValidToken(resolvedToken->tokenScope, resolvedToken->token))
1269     {
1270         return false;
1271     }
1272
1273     CorInfoTokenKind tokenType = resolvedToken->tokenType;
1274     switch (TypeFromToken(resolvedToken->token))
1275     {
1276     case mdtModuleRef:
1277     case mdtTypeDef:
1278     case mdtTypeRef:
1279     case mdtTypeSpec:
1280         if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1281             return false;
1282         break;
1283
1284     case mdtMethodDef:
1285     case mdtMethodSpec:
1286         if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1287             return false;
1288         break;
1289
1290     case mdtFieldDef:
1291         if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1292             return false;
1293         break;
1294
1295     case mdtMemberRef:
1296         if ((tokenType & (CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field)) == 0)
1297             return false;
1298         break;
1299
1300     default:
1301         return false;
1302     }
1303
1304     return true;
1305 }
1306
1307 LONG EEFilterException(struct _EXCEPTION_POINTERS* exceptionPointers, void* unused);
1308
1309 LONG TryResolveTokenFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
1310 {
1311     CONTRACTL {
1312         NOTHROW;
1313         GC_NOTRIGGER;
1314         SO_TOLERANT;
1315         MODE_ANY;
1316     } CONTRACTL_END;
1317
1318     // Backward compatibility: Convert bad image format exceptions thrown while resolving tokens
1319     // to simple true/false successes. This is done for backward compatibility only. Ideally,
1320     // we would always treat bad tokens in the IL  stream as fatal errors.
1321     if (exceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1322     {
1323         auto* param = reinterpret_cast<TryResolveTokenFilterParam*>(theParam);
1324         if (!isValidTokenForTryResolveToken(param->m_this, param->m_resolvedToken))
1325         {
1326             param->m_exceptionPointers = *exceptionPointers;
1327             return EEFilterException(exceptionPointers, nullptr);
1328         }
1329     }
1330
1331     return EXCEPTION_CONTINUE_SEARCH;
1332 }
1333
1334 bool CEEInfo::tryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
1335 {
1336     // No dynamic contract here because SEH is used
1337     STATIC_CONTRACT_SO_TOLERANT;
1338     STATIC_CONTRACT_THROWS;
1339     STATIC_CONTRACT_GC_TRIGGERS;
1340     STATIC_CONTRACT_MODE_PREEMPTIVE;
1341
1342     TryResolveTokenFilterParam param;
1343     param.m_this = this;
1344     param.m_resolvedToken = resolvedToken;
1345     param.m_success = true;
1346
1347     PAL_TRY(TryResolveTokenFilterParam*, pParam, &param)
1348     {
1349         pParam->m_this->resolveToken(pParam->m_resolvedToken);
1350     }
1351     PAL_EXCEPT_FILTER(TryResolveTokenFilter)
1352     {
1353         if (param.m_exceptionPointers.ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1354         {
1355             HandleException(&param.m_exceptionPointers);
1356         }
1357
1358         param.m_success = false;
1359     }
1360     PAL_ENDTRY
1361
1362     return param.m_success;
1363 }
1364
1365 /*********************************************************************/
1366 // We have a few frequently used constants in mscorlib that are defined as 
1367 // readonly static fields for historic reasons. Check for them here and 
1368 // allow them to be treated as actual constants by the JIT.
1369 static CORINFO_FIELD_ACCESSOR getFieldIntrinsic(FieldDesc * field)
1370 {
1371     STANDARD_VM_CONTRACT;
1372
1373     if (MscorlibBinder::GetField(FIELD__STRING__EMPTY) == field)
1374     {
1375         return CORINFO_FIELD_INTRINSIC_EMPTY_STRING;
1376     }
1377     else
1378     if ((MscorlibBinder::GetField(FIELD__INTPTR__ZERO) == field) ||
1379         (MscorlibBinder::GetField(FIELD__UINTPTR__ZERO) == field))
1380     {
1381         return CORINFO_FIELD_INTRINSIC_ZERO;
1382     }
1383     else
1384     if (MscorlibBinder::GetField(FIELD__BITCONVERTER__ISLITTLEENDIAN) == field)
1385     {
1386         return CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN;
1387     }
1388
1389     return (CORINFO_FIELD_ACCESSOR)-1;
1390 }
1391
1392 static CorInfoHelpFunc getGenericStaticsHelper(FieldDesc * pField)
1393 {
1394     STANDARD_VM_CONTRACT;
1395
1396     int helper = CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE;
1397
1398     if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1399         pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1400     {
1401         helper = CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1402     }
1403
1404     if (pField->IsThreadStatic())
1405     {
1406         const int delta = CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1407
1408         static_assert_no_msg(CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE 
1409             == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE + delta);
1410
1411         helper += (CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE);
1412     }
1413
1414     return (CorInfoHelpFunc)helper;
1415 }
1416
1417 CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable * pFieldMT)
1418 {
1419     STANDARD_VM_CONTRACT;
1420
1421     int helper = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
1422
1423     if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1424         pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1425     {
1426         helper = CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1427     }
1428
1429     if (pFieldMT->IsDynamicStatics())
1430     {
1431         const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1432
1433         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS 
1434             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1435
1436         helper += delta;
1437     }
1438     else
1439     if (!pFieldMT->HasClassConstructor() && !pFieldMT->HasBoxedRegularStatics())
1440     {
1441         const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1442
1443         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR 
1444             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1445
1446         helper += delta;
1447     }
1448
1449     if (pField->IsThreadStatic())
1450     {
1451         const int delta = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1452
1453         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE 
1454             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1455         static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR 
1456             == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR + delta);
1457         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR 
1458             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR + delta);
1459         static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS 
1460             == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS + delta);
1461         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS 
1462             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS + delta);
1463
1464         helper += delta;
1465     }
1466
1467     return (CorInfoHelpFunc)helper;
1468 }
1469
1470 static CorInfoHelpFunc getInstanceFieldHelper(FieldDesc * pField, CORINFO_ACCESS_FLAGS flags)
1471 {
1472     STANDARD_VM_CONTRACT;
1473
1474     int helper;
1475
1476     CorElementType type = pField->GetFieldType();
1477
1478     if (CorTypeInfo::IsObjRef(type))
1479         helper = CORINFO_HELP_GETFIELDOBJ;
1480     else
1481     switch (type)
1482     {
1483     case ELEMENT_TYPE_VALUETYPE:
1484         helper = CORINFO_HELP_GETFIELDSTRUCT;
1485         break;
1486     case ELEMENT_TYPE_I1:
1487     case ELEMENT_TYPE_BOOLEAN:
1488     case ELEMENT_TYPE_U1:
1489         helper = CORINFO_HELP_GETFIELD8;
1490         break;
1491     case ELEMENT_TYPE_I2:
1492     case ELEMENT_TYPE_CHAR:
1493     case ELEMENT_TYPE_U2:
1494         helper = CORINFO_HELP_GETFIELD16;
1495         break;
1496     case ELEMENT_TYPE_I4:
1497     case ELEMENT_TYPE_U4:
1498     IN_WIN32(default:)
1499         helper = CORINFO_HELP_GETFIELD32;
1500         break;
1501     case ELEMENT_TYPE_I8:
1502     case ELEMENT_TYPE_U8:
1503     IN_WIN64(default:)
1504         helper = CORINFO_HELP_GETFIELD64;
1505         break;
1506     case ELEMENT_TYPE_R4:
1507         helper = CORINFO_HELP_GETFIELDFLOAT;
1508         break;
1509     case ELEMENT_TYPE_R8:
1510         helper = CORINFO_HELP_GETFIELDDOUBLE;
1511         break;
1512     }
1513
1514     if (flags & CORINFO_ACCESS_SET)
1515     {
1516         const int delta = CORINFO_HELP_SETFIELDOBJ - CORINFO_HELP_GETFIELDOBJ;
1517
1518         static_assert_no_msg(CORINFO_HELP_SETFIELD8 == CORINFO_HELP_GETFIELD8 + delta);
1519         static_assert_no_msg(CORINFO_HELP_SETFIELD16 == CORINFO_HELP_GETFIELD16 + delta);
1520         static_assert_no_msg(CORINFO_HELP_SETFIELD32 == CORINFO_HELP_GETFIELD32 + delta);
1521         static_assert_no_msg(CORINFO_HELP_SETFIELD64 == CORINFO_HELP_GETFIELD64 + delta);
1522         static_assert_no_msg(CORINFO_HELP_SETFIELDSTRUCT == CORINFO_HELP_GETFIELDSTRUCT + delta);
1523         static_assert_no_msg(CORINFO_HELP_SETFIELDFLOAT == CORINFO_HELP_GETFIELDFLOAT + delta);
1524         static_assert_no_msg(CORINFO_HELP_SETFIELDDOUBLE == CORINFO_HELP_GETFIELDDOUBLE + delta);
1525
1526         helper += delta;
1527     }
1528
1529     return (CorInfoHelpFunc)helper;
1530 }
1531
1532 /*********************************************************************/
1533 void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken,
1534                             CORINFO_METHOD_HANDLE  callerHandle,
1535                             CORINFO_ACCESS_FLAGS   flags, 
1536                             CORINFO_FIELD_INFO    *pResult
1537                            )
1538 {
1539     CONTRACTL {
1540         SO_TOLERANT;
1541         THROWS;
1542         GC_TRIGGERS;
1543         MODE_PREEMPTIVE;
1544     } CONTRACTL_END;
1545
1546     JIT_TO_EE_TRANSITION();
1547
1548     _ASSERTE((flags & (CORINFO_ACCESS_GET | CORINFO_ACCESS_SET | CORINFO_ACCESS_ADDRESS | CORINFO_ACCESS_INIT_ARRAY)) != 0);
1549
1550     INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
1551
1552     FieldDesc * pField = (FieldDesc*)pResolvedToken->hField;
1553     MethodTable * pFieldMT = pField->GetApproxEnclosingMethodTable();
1554
1555     // Helper to use if the field access requires it
1556     CORINFO_FIELD_ACCESSOR fieldAccessor = (CORINFO_FIELD_ACCESSOR)-1;
1557     DWORD fieldFlags = 0;
1558
1559     pResult->offset = pField->GetOffset();
1560     if (pField->IsStatic())
1561     {
1562         fieldFlags |= CORINFO_FLG_FIELD_STATIC;
1563
1564         if (pField->IsRVA())
1565         {
1566             fieldFlags |= CORINFO_FLG_FIELD_UNMANAGED;
1567
1568             Module* module = pFieldMT->GetModule();
1569             if (module->IsRvaFieldTls(pResult->offset))
1570             {
1571                 fieldAccessor = CORINFO_FIELD_STATIC_TLS;
1572
1573                 // Provide helper to use if the JIT is not able to emit the TLS access
1574                 // as intrinsic
1575                 pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR_TLS;
1576
1577                 pResult->offset = module->GetFieldTlsOffset(pResult->offset);
1578             }
1579             else
1580             {
1581                 fieldAccessor = CORINFO_FIELD_STATIC_RVA_ADDRESS;
1582             }
1583
1584             // We are not going through a helper. The constructor has to be triggered explicitly.
1585             if (!pFieldMT->IsClassPreInited())
1586                 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1587         }
1588         else
1589         if (pField->IsContextStatic())
1590         {
1591             fieldAccessor = CORINFO_FIELD_STATIC_ADDR_HELPER;
1592
1593             pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR_CONTEXT;
1594         }
1595         else
1596         {
1597             // Regular or thread static
1598             CORINFO_FIELD_ACCESSOR intrinsicAccessor;
1599
1600             if (pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1601                 fieldFlags |= CORINFO_FLG_FIELD_STATIC_IN_HEAP;
1602
1603             if (pFieldMT->IsSharedByGenericInstantiations())
1604             {
1605                 fieldAccessor = CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER;
1606
1607                 pResult->helper = getGenericStaticsHelper(pField);
1608             }
1609             else
1610             if (pFieldMT->GetModule()->IsSystem() && (flags & CORINFO_ACCESS_GET) &&
1611                 (intrinsicAccessor = getFieldIntrinsic(pField)) != (CORINFO_FIELD_ACCESSOR)-1)
1612             {
1613                 // Intrinsics
1614                 fieldAccessor = intrinsicAccessor;
1615             }
1616             else
1617             if (// Domain neutral access.
1618                 m_pMethodBeingCompiled->IsDomainNeutral() || m_pMethodBeingCompiled->IsZapped() || IsCompilingForNGen() ||
1619                 // Static fields are not pinned in collectible types. We will always access 
1620                 // them using a helper since the address cannot be embeded into the code.
1621                 pFieldMT->Collectible() ||
1622                 // We always treat accessing thread statics as if we are in domain neutral code.
1623                 pField->IsThreadStatic()
1624                 )
1625             {
1626                 fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
1627
1628                 pResult->helper = getSharedStaticsHelper(pField, pFieldMT);
1629             }
1630             else
1631             {
1632                 fieldAccessor = CORINFO_FIELD_STATIC_ADDRESS;
1633
1634                 // We are not going through a helper. The constructor has to be triggered explicitly.
1635                 if (!pFieldMT->IsClassPreInited())
1636                     fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1637             }
1638         }
1639
1640         //
1641         // Currently, we only this optimization for regular statics, but it
1642         // looks like it may be permissible to do this optimization for
1643         // thread statics as well.
1644         //
1645         if ((flags & CORINFO_ACCESS_ADDRESS) &&
1646             !pField->IsThreadStatic() &&
1647             !pField->IsContextStatic() &&
1648             (fieldAccessor != CORINFO_FIELD_STATIC_TLS))
1649         {
1650             fieldFlags |= CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN;
1651         }
1652     }
1653     else
1654     {
1655         BOOL fInstanceHelper = FALSE;
1656
1657 #if CHECK_APP_DOMAIN_LEAKS
1658         if (g_pConfig->EnableFullDebug()
1659             && pField->IsDangerousAppDomainAgileField()
1660             && CorTypeInfo::IsObjRef(pField->GetFieldType()))
1661         {
1662             //
1663             // In a checked field with all checks turned on, we use a helper to enforce the app domain
1664             // agile invariant.
1665             //
1666             // <REVISIT_TODO>@todo: we'd like to check this for value type fields as well - we
1667             // just need to add some code to iterate through the fields for
1668             // references during the assignment.
1669             // </REVISIT_TODO>
1670             fInstanceHelper = TRUE;
1671         }
1672         else
1673 #endif // CHECK_APP_DOMAIN_LEAKS
1674
1675         if (fInstanceHelper)
1676         {
1677             if (flags & CORINFO_ACCESS_ADDRESS)
1678             {
1679                 fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1680
1681                 pResult->helper = CORINFO_HELP_GETFIELDADDR;
1682             }
1683             else
1684             {
1685                 fieldAccessor = CORINFO_FIELD_INSTANCE_HELPER;
1686
1687                 pResult->helper = getInstanceFieldHelper(pField, flags);
1688             }
1689         }
1690         else
1691         if (pField->IsEnCNew())
1692         {
1693             fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1694
1695             pResult->helper = CORINFO_HELP_GETFIELDADDR;
1696         }
1697         else
1698         {
1699             fieldAccessor = CORINFO_FIELD_INSTANCE;
1700         }
1701
1702         // FieldDesc::GetOffset() does not include the size of Object
1703         if (!pFieldMT->IsValueType())
1704         {
1705             pResult->offset += sizeof(Object);
1706         }
1707     }
1708
1709     // TODO: This is touching metadata. Can we avoid it?
1710     DWORD fieldAttribs = pField->GetAttributes();
1711
1712     if (IsFdFamily(fieldAttribs))
1713         fieldFlags |= CORINFO_FLG_FIELD_PROTECTED;
1714
1715     if (IsFdInitOnly(fieldAttribs))
1716         fieldFlags |= CORINFO_FLG_FIELD_FINAL;
1717
1718     pResult->fieldAccessor = fieldAccessor;
1719     pResult->fieldFlags = fieldFlags;
1720
1721     if (!(flags & CORINFO_ACCESS_INLINECHECK))
1722     {
1723         //get the field's type.  Grab the class for structs.
1724         pResult->fieldType = getFieldTypeInternal(pResolvedToken->hField, &pResult->structType, pResolvedToken->hClass);
1725
1726
1727         MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
1728
1729         //
1730         //Since we can't get the special verify-only instantiated FD like we can with MDs, go back to the parent
1731         //of the memberRef and load that one.  That should give us the open instantiation.
1732         //
1733         //If the field we found is owned by a generic type, you have to go back to the signature and reload.
1734         //Otherwise we filled in !0.
1735         TypeHandle fieldTypeForSecurity = TypeHandle(pResolvedToken->hClass);
1736         if (pResolvedToken->pTypeSpec != NULL)
1737         {
1738             SigTypeContext typeContext;
1739             SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
1740
1741             SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1742             fieldTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
1743
1744             // typeHnd can be a variable type
1745             if (fieldTypeForSecurity.GetMethodTable() == NULL)
1746             {
1747                 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
1748             }
1749         }
1750
1751         BOOL doAccessCheck = TRUE;
1752         AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
1753
1754         DynamicResolver * pAccessContext = NULL;
1755
1756         //More in code:CEEInfo::getCallInfo, but the short version is that the caller and callee Descs do
1757         //not completely describe the type.
1758         TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
1759         if (IsDynamicScope(pResolvedToken->tokenScope))
1760         {
1761             doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope), &callerTypeForSecurity,
1762                 &accessCheckType, &pAccessContext);
1763         }
1764
1765         //Now for some link time checks.
1766         //Um... where are the field link demands?
1767
1768         pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
1769
1770         if (doAccessCheck)
1771         {
1772             //Well, let's check some visibility at least.
1773             AccessCheckOptions accessCheckOptions(accessCheckType,
1774                 pAccessContext,
1775                 FALSE,
1776                 pField);
1777
1778             _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
1779             StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
1780
1781             BOOL canAccess = ClassLoader::CanAccess(
1782                 &accessContext,
1783                 fieldTypeForSecurity.GetMethodTable(),
1784                 fieldTypeForSecurity.GetAssembly(),
1785                 fieldAttribs,
1786                 NULL,
1787                 (flags & CORINFO_ACCESS_INIT_ARRAY) ? NULL : pField, // For InitializeArray, we don't need tocheck the type of the field.
1788                 accessCheckOptions);
1789
1790             if (!canAccess)
1791             {
1792                 //Set up the throw helper
1793                 pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL;
1794
1795                 pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_EXCEPTION;
1796                 pResult->accessCalloutHelper.numArgs = 2;
1797
1798                 pResult->accessCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
1799                 pResult->accessCalloutHelper.args[1].Set(CORINFO_FIELD_HANDLE(pField));
1800
1801                 if (IsCompilingForNGen())
1802                 {
1803                     //see code:CEEInfo::getCallInfo for more information.
1804                     if (pCallerForSecurity->ContainsGenericVariables())
1805                         COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
1806                 }
1807             }
1808             else
1809             {
1810                 CorInfoIsAccessAllowedResult isAccessAllowed = CORINFO_ACCESS_ALLOWED;
1811                 CorInfoSecurityRuntimeChecks runtimeChecks = CORINFO_ACCESS_SECURITY_NONE;
1812
1813                 DebugSecurityCalloutStress(getMethodBeingCompiled(), isAccessAllowed, runtimeChecks);
1814                 if (isAccessAllowed == CORINFO_ACCESS_RUNTIME_CHECK)
1815                 {
1816                     pResult->accessAllowed = isAccessAllowed;
1817                     //Explain the callback to the JIT.
1818                     pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_CHECK;
1819                     pResult->accessCalloutHelper.numArgs = 3;
1820
1821                     pResult->accessCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
1822
1823                     /* REVISIT_TODO Wed 4/8/2009
1824                      * This field handle is not useful on its own.  We also need to embed the enclosing class
1825                      * handle.
1826                      */
1827                     pResult->accessCalloutHelper.args[1].Set(CORINFO_FIELD_HANDLE(pField));
1828
1829                     pResult->accessCalloutHelper.args[2].Set(runtimeChecks);
1830
1831                     if (IsCompilingForNGen())
1832                     {
1833                         //see code:CEEInfo::getCallInfo for more information.
1834                         if (pCallerForSecurity->ContainsGenericVariables())
1835                             COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
1836                     }
1837                 }
1838             }
1839         }
1840     }
1841
1842     EE_TO_JIT_TRANSITION();
1843 }
1844
1845 //---------------------------------------------------------------------------------------
1846 // 
1847 bool CEEInfo::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd)
1848 {
1849     CONTRACTL {
1850         SO_TOLERANT;
1851         THROWS;
1852         GC_TRIGGERS;
1853         MODE_PREEMPTIVE;
1854     } CONTRACTL_END;
1855
1856     bool res = false;
1857     JIT_TO_EE_TRANSITION_LEAF();
1858     FieldDesc* field = (FieldDesc*)fldHnd;
1859     res = (field->IsStatic() != 0);
1860     EE_TO_JIT_TRANSITION_LEAF();
1861     return res;
1862 }
1863
1864 //---------------------------------------------------------------------------------------
1865 // 
1866 void 
1867 CEEInfo::findCallSiteSig(
1868     CORINFO_MODULE_HANDLE  scopeHnd, 
1869     unsigned               sigMethTok, 
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         DynamicResolver * pResolver = GetDynamicResolver(scopeHnd);
1888         SigPointer sig;
1889
1890         if (TypeFromToken(sigMethTok) == mdtMemberRef)
1891         {
1892             sig = pResolver->ResolveSignatureForVarArg(sigMethTok);
1893         }
1894         else
1895         {
1896             _ASSERTE(TypeFromToken(sigMethTok) == mdtMethodDef);
1897
1898             TypeHandle classHandle;
1899             MethodDesc * pMD = NULL;
1900             FieldDesc * pFD = NULL;
1901
1902             // in this case a method is asked for its sig. Resolve the method token and get the sig
1903             pResolver->ResolveToken(sigMethTok, &classHandle, &pMD, &pFD);
1904             if (pMD == NULL)
1905                 COMPlusThrow(kInvalidProgramException);
1906
1907             PCCOR_SIGNATURE pSig = NULL;
1908             DWORD           cbSig;
1909             pMD->GetSig(&pSig, &cbSig);
1910             sig = SigPointer(pSig, cbSig);
1911
1912             context = MAKE_METHODCONTEXT(pMD);
1913             scopeHnd = GetScopeHandle(pMD->GetModule());
1914         }
1915
1916         sig.GetSignature(&pSig, &cbSig);
1917         sigMethTok = mdTokenNil;
1918     }
1919     else
1920     {
1921         Module * module = (Module *)scopeHnd;
1922         LPCUTF8  szName;
1923
1924         if (TypeFromToken(sigMethTok) == mdtMemberRef)
1925         {
1926             IfFailThrow(module->GetMDImport()->GetNameAndSigOfMemberRef(sigMethTok, &pSig, &cbSig, &szName));
1927         }
1928         else if (TypeFromToken(sigMethTok) == mdtMethodDef)
1929         {
1930             IfFailThrow(module->GetMDImport()->GetSigOfMethodDef(sigMethTok, &cbSig, &pSig));
1931         }
1932     }
1933
1934     CEEInfo::ConvToJitSig(
1935         pSig, 
1936         cbSig, 
1937         scopeHnd, 
1938         sigMethTok, 
1939         sigRet, 
1940         GetMethodFromContext(context), 
1941         false,
1942         GetTypeFromContext(context));
1943     EE_TO_JIT_TRANSITION();
1944 } // CEEInfo::findCallSiteSig
1945
1946 //---------------------------------------------------------------------------------------
1947 // 
1948 void 
1949 CEEInfo::findSig(
1950     CORINFO_MODULE_HANDLE  scopeHnd, 
1951     unsigned               sigTok, 
1952     CORINFO_CONTEXT_HANDLE context, 
1953     CORINFO_SIG_INFO *     sigRet)
1954 {
1955     CONTRACTL {
1956         SO_TOLERANT;
1957         THROWS;
1958         GC_TRIGGERS;
1959         MODE_PREEMPTIVE;
1960     } CONTRACTL_END;
1961
1962     JIT_TO_EE_TRANSITION();
1963
1964     PCCOR_SIGNATURE       pSig = NULL;
1965     DWORD                 cbSig = 0;
1966
1967     if (IsDynamicScope(scopeHnd))
1968     {
1969         SigPointer sig = GetDynamicResolver(scopeHnd)->ResolveSignature(sigTok);
1970         sig.GetSignature(&pSig, &cbSig);
1971         sigTok = mdTokenNil;
1972     }
1973     else
1974     {
1975         Module * module = (Module *)scopeHnd;
1976         
1977         // We need to resolve this stand alone sig
1978         IfFailThrow(module->GetMDImport()->GetSigFromToken(
1979             (mdSignature)sigTok, 
1980             &cbSig, 
1981             &pSig));
1982     }
1983
1984     CEEInfo::ConvToJitSig(
1985         pSig, 
1986         cbSig, 
1987         scopeHnd, 
1988         sigTok, 
1989         sigRet, 
1990         GetMethodFromContext(context), 
1991         false,
1992         GetTypeFromContext(context));
1993     
1994     EE_TO_JIT_TRANSITION();
1995 } // CEEInfo::findSig
1996
1997 //---------------------------------------------------------------------------------------
1998 // 
1999 unsigned 
2000 CEEInfo::getClassSize(
2001     CORINFO_CLASS_HANDLE clsHnd)
2002 {
2003     CONTRACTL {
2004         SO_TOLERANT;
2005         NOTHROW;
2006         GC_NOTRIGGER;
2007         MODE_PREEMPTIVE;
2008     } CONTRACTL_END;
2009
2010     unsigned result = 0;
2011
2012     JIT_TO_EE_TRANSITION_LEAF();
2013
2014     TypeHandle VMClsHnd(clsHnd);
2015     result = VMClsHnd.GetSize();
2016
2017     EE_TO_JIT_TRANSITION_LEAF();
2018
2019     return result;
2020 }
2021
2022 unsigned CEEInfo::getClassAlignmentRequirement(CORINFO_CLASS_HANDLE type, BOOL fDoubleAlignHint)
2023 {
2024     CONTRACTL {
2025         SO_TOLERANT;
2026         NOTHROW;
2027         GC_NOTRIGGER;
2028         MODE_PREEMPTIVE;
2029     } CONTRACTL_END;
2030
2031     // Default alignment is sizeof(void*)
2032     unsigned result = sizeof(void*);
2033
2034     JIT_TO_EE_TRANSITION_LEAF();
2035
2036     TypeHandle clsHnd(type);
2037
2038 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
2039     if (fDoubleAlignHint)
2040     {
2041         MethodTable* pMT = clsHnd.GetMethodTable();
2042         if (pMT != NULL)
2043         {
2044             // Return the size of the double align hint. Ignore the actual alignment info account
2045             // so that structs with 64-bit integer fields do not trigger double aligned frames on x86.
2046             if (pMT->GetClass()->IsAlign8Candidate())
2047                 result = 8;
2048         }
2049     }
2050     else
2051 #endif
2052     {
2053         result = getClassAlignmentRequirementStatic(clsHnd);
2054     }
2055
2056     EE_TO_JIT_TRANSITION_LEAF();
2057
2058     return result;
2059 }
2060
2061 unsigned CEEInfo::getClassAlignmentRequirementStatic(TypeHandle clsHnd)
2062 {
2063     LIMITED_METHOD_CONTRACT;
2064
2065     // Default alignment is sizeof(void*)
2066     unsigned result = sizeof(void*);
2067
2068     MethodTable * pMT = clsHnd.GetMethodTable();
2069     if (pMT == NULL)
2070         return result;
2071
2072     if (pMT->HasLayout())
2073     {
2074         EEClassLayoutInfo* pInfo = pMT->GetLayoutInfo();
2075
2076         if (clsHnd.IsNativeValueType())
2077         {
2078             // if it's the unmanaged view of the managed type, we always use the unmanaged alignment requirement
2079             result = pInfo->m_LargestAlignmentRequirementOfAllMembers;
2080         }
2081         else
2082         if (pInfo->IsManagedSequential())
2083         {
2084             _ASSERTE(!pMT->ContainsPointers());
2085
2086             // if it's managed sequential, we use the managed alignment requirement
2087             result = pInfo->m_ManagedLargestAlignmentRequirementOfAllMembers;
2088         }
2089         else if (pInfo->IsBlittable())
2090         {
2091             _ASSERTE(!pMT->ContainsPointers());
2092
2093             // if it's blittable, we use the unmanaged alignment requirement
2094             result = pInfo->m_LargestAlignmentRequirementOfAllMembers;
2095         }
2096     }
2097
2098 #ifdef FEATURE_64BIT_ALIGNMENT
2099     if (result < 8 && pMT->RequiresAlign8())
2100     {
2101         // If the structure contains 64-bit primitive fields and the platform requires 8-byte alignment for
2102         // such fields then make sure we return at least 8-byte alignment. Note that it's technically possible
2103         // to create unmanaged APIs that take unaligned structures containing such fields and this
2104         // unconditional alignment bump would cause us to get the calling convention wrong on platforms such
2105         // as ARM. If we see such cases in the future we'd need to add another control (such as an alignment
2106         // property for the StructLayout attribute or a marshaling directive attribute for p/invoke arguments)
2107         // that allows more precise control. For now we'll go with the likely scenario.
2108         result = 8;
2109     }
2110 #endif // FEATURE_64BIT_ALIGNMENT
2111
2112     return result;
2113 }
2114
2115 CORINFO_FIELD_HANDLE
2116 CEEInfo::getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num)
2117 {
2118     CONTRACTL {
2119         SO_TOLERANT;
2120         NOTHROW;
2121         GC_NOTRIGGER;
2122         MODE_PREEMPTIVE;
2123     } CONTRACTL_END;
2124
2125     CORINFO_FIELD_HANDLE result = NULL;
2126
2127     JIT_TO_EE_TRANSITION_LEAF();
2128
2129     TypeHandle VMClsHnd(clsHnd);
2130
2131     MethodTable* pMT= VMClsHnd.AsMethodTable();
2132
2133     result = (CORINFO_FIELD_HANDLE) ((pMT->GetApproxFieldDescListRaw()) + num);
2134
2135     EE_TO_JIT_TRANSITION_LEAF();
2136
2137     return result;
2138 }
2139
2140 mdMethodDef
2141 CEEInfo::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod)
2142 {
2143     CONTRACTL {
2144         SO_TOLERANT;
2145         NOTHROW;
2146         GC_NOTRIGGER;
2147         MODE_PREEMPTIVE;
2148     } CONTRACTL_END;
2149
2150     mdMethodDef result = 0;
2151
2152     JIT_TO_EE_TRANSITION_LEAF();
2153
2154     MethodDesc* pMD = GetMethod(hMethod);
2155
2156     if (pMD->IsDynamicMethod())
2157     {
2158         // Dynamic methods do not have tokens
2159         result = mdMethodDefNil;
2160     }
2161     else
2162     {
2163         result = pMD->GetMemberDef();
2164     }
2165
2166     EE_TO_JIT_TRANSITION_LEAF();
2167
2168     return result;
2169 }
2170
2171 BOOL CEEInfo::checkMethodModifier(CORINFO_METHOD_HANDLE hMethod,
2172                                   LPCSTR modifier,
2173                                   BOOL fOptional)
2174 {
2175     CONTRACTL {
2176         SO_TOLERANT;
2177         THROWS;
2178         GC_TRIGGERS;
2179         MODE_PREEMPTIVE;
2180     } CONTRACTL_END;
2181
2182     BOOL result = FALSE;
2183
2184     JIT_TO_EE_TRANSITION();
2185
2186     MethodDesc* pMD = GetMethod(hMethod);
2187     Module* pModule = pMD->GetModule();
2188     MetaSig sig(pMD);
2189     CorElementType eeType = fOptional ? ELEMENT_TYPE_CMOD_OPT : ELEMENT_TYPE_CMOD_REQD;
2190
2191     // modopts/modreqs for the method are by convention stored on the return type
2192     result = sig.GetReturnProps().HasCustomModifier(pModule, modifier, eeType);
2193
2194     EE_TO_JIT_TRANSITION();
2195
2196     return result;
2197 }
2198
2199 /*********************************************************************/
2200 static unsigned ComputeGCLayout(MethodTable * pMT, BYTE* gcPtrs)
2201 {
2202     STANDARD_VM_CONTRACT;
2203
2204     unsigned result = 0;
2205
2206     _ASSERTE(pMT->IsValueType());
2207
2208     // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in which
2209     // case the check for g_TypedReferenceMT below would not be necessary
2210     if (pMT == g_TypedReferenceMT || pMT->HasSameTypeDefAs(g_pByReferenceClass))
2211     {
2212         if (gcPtrs[0] == TYPE_GC_NONE)
2213         {
2214             gcPtrs[0] = TYPE_GC_BYREF;
2215             result++;
2216         }
2217         else if (gcPtrs[0] != TYPE_GC_BYREF)
2218         {
2219             COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2220         }
2221         return result;
2222     }
2223
2224     ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
2225     for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
2226     {
2227         int fieldStartIndex = pFD->GetOffset() / sizeof(void*);
2228
2229         if (pFD->GetFieldType() != ELEMENT_TYPE_VALUETYPE)
2230         {
2231             if (pFD->IsObjRef())
2232             {
2233                 if (gcPtrs[fieldStartIndex] == TYPE_GC_NONE)
2234                 {
2235                     gcPtrs[fieldStartIndex] = TYPE_GC_REF;
2236                     result++;
2237                 }
2238                 else if (gcPtrs[fieldStartIndex] != TYPE_GC_REF)
2239                 {
2240                     COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2241                 }
2242             }
2243         }
2244         else
2245         {
2246             MethodTable * pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
2247             result += ComputeGCLayout(pFieldMT, gcPtrs + fieldStartIndex);
2248         }
2249     }
2250     return result;
2251 }
2252
2253 unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
2254 {
2255     CONTRACTL {
2256         SO_TOLERANT;
2257         THROWS;
2258         GC_TRIGGERS;
2259         MODE_PREEMPTIVE;
2260     } CONTRACTL_END;
2261
2262     unsigned result = 0;
2263
2264     JIT_TO_EE_TRANSITION();
2265
2266     TypeHandle VMClsHnd(clsHnd);
2267
2268     MethodTable* pMT = VMClsHnd.GetMethodTable();
2269
2270     if (pMT->IsByRefLike())
2271     {
2272         // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in
2273         // which case the check for g_TypedReferenceMT below would not be necessary
2274         if (pMT == g_TypedReferenceMT)
2275         {
2276             gcPtrs[0] = TYPE_GC_BYREF;
2277             gcPtrs[1] = TYPE_GC_NONE;
2278             result = 1;
2279         }
2280         else
2281         {
2282             memset(gcPtrs, TYPE_GC_NONE,
2283                 (VMClsHnd.GetSize() + sizeof(void*) - 1) / sizeof(void*));
2284             // Note: This case is more complicated than the TypedReference case
2285             // due to ByRefLike structs being included as fields in other value 
2286             // types (TypedReference can not be.)
2287             result = ComputeGCLayout(VMClsHnd.AsMethodTable(), gcPtrs);
2288         }
2289     }
2290     else if (VMClsHnd.IsNativeValueType())
2291     {
2292         // native value types have no GC pointers
2293         result = 0;
2294         memset(gcPtrs, TYPE_GC_NONE,
2295                (VMClsHnd.GetSize() + sizeof(void*) -1)/ sizeof(void*));
2296     }
2297     else
2298     {
2299         _ASSERTE(pMT->IsValueType());
2300         _ASSERTE(sizeof(BYTE) == 1);
2301
2302         // assume no GC pointers at first
2303         result = 0;
2304         memset(gcPtrs, TYPE_GC_NONE,
2305                (VMClsHnd.GetSize() + sizeof(void*) -1)/ sizeof(void*));
2306
2307         // walk the GC descriptors, turning on the correct bits
2308         if (pMT->ContainsPointers())
2309         {
2310             CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
2311             CGCDescSeries * pByValueSeries = map->GetLowestSeries();
2312
2313             for (SIZE_T i = 0; i < map->GetNumSeries(); i++)
2314             {
2315                 // Get offset into the value class of the first pointer field (includes a +Object)
2316                 size_t cbSeriesSize = pByValueSeries->GetSeriesSize() + pMT->GetBaseSize();
2317                 size_t cbOffset = pByValueSeries->GetSeriesOffset() - sizeof(Object);
2318
2319                 _ASSERTE (cbOffset % sizeof(void*) == 0);
2320                 _ASSERTE (cbSeriesSize % sizeof(void*) == 0);
2321
2322                 result += (unsigned) (cbSeriesSize / sizeof(void*));
2323                 memset(&gcPtrs[cbOffset/sizeof(void*)], TYPE_GC_REF, cbSeriesSize / sizeof(void*));
2324
2325                 pByValueSeries++;
2326             }
2327         }
2328     }
2329
2330     EE_TO_JIT_TRANSITION();
2331
2332     return result;
2333 }
2334
2335 // returns the enregister info for a struct based on type of fields, alignment, etc.
2336 bool CEEInfo::getSystemVAmd64PassStructInRegisterDescriptor(
2337                                                 /*IN*/  CORINFO_CLASS_HANDLE structHnd,
2338                                                 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
2339 {
2340     CONTRACTL {
2341         SO_TOLERANT;
2342         THROWS;
2343         GC_TRIGGERS;
2344         MODE_PREEMPTIVE;
2345     } CONTRACTL_END;
2346
2347 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
2348     JIT_TO_EE_TRANSITION();
2349
2350     _ASSERTE(structPassInRegDescPtr != nullptr);
2351     TypeHandle th(structHnd);
2352
2353     structPassInRegDescPtr->passedInRegisters = false;
2354     
2355     // Make sure this is a value type.
2356     if (th.IsValueType())
2357     {
2358         _ASSERTE((CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeStruct) ||
2359                  (CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeTypedReference));
2360
2361         // The useNativeLayout in this case tracks whether the classification
2362         // is for a native layout of the struct or not.
2363         // If the struct has special marshaling it has a native layout. 
2364         // In such cases the classifier needs to use the native layout.
2365         // For structs with no native layout, the managed layout should be used
2366         // even if classified for the purposes of marshaling/PInvoke passing.
2367         bool useNativeLayout = false;
2368         MethodTable* methodTablePtr = nullptr;
2369         if (!th.IsTypeDesc())
2370         {
2371             methodTablePtr = th.AsMethodTable();
2372         }
2373         else
2374         {
2375             _ASSERTE(th.IsNativeValueType());
2376
2377             useNativeLayout = true;
2378             methodTablePtr = th.AsNativeValueType();
2379         }
2380         _ASSERTE(methodTablePtr != nullptr);
2381
2382         // If we have full support for FEATURE_UNIX_AMD64_STRUCT_PASSING, and not just the interface,
2383         // then we've cached whether this is a reg passed struct in the MethodTable, computed during
2384         // MethodTable construction. Otherwise, we are just building in the interface, and we haven't
2385         // computed or cached anything, so we need to compute it now.
2386 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2387         bool canPassInRegisters = useNativeLayout ? methodTablePtr->GetLayoutInfo()->IsNativeStructPassedInRegisters()
2388                                                   : methodTablePtr->IsRegPassedStruct();
2389 #else // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2390         SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2391         bool canPassInRegisters = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2392 #endif // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2393
2394         if (canPassInRegisters)
2395         {
2396 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
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 // FEATURE_UNIX_AMD64_STRUCT_PASSING
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(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
2424     return false;
2425 #endif // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_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 algoritm (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 #if defined(_TARGET_ARM_)
3136         ThrowHR(E_NOTIMPL); /* TODO - NYI */
3137 #endif
3138         pResultLookup->lookupKind.runtimeLookupArgs = NULL;
3139
3140         switch (entryKind)
3141         {
3142         case DeclaringTypeHandleSlot:
3143             _ASSERTE(pTemplateMD != NULL);
3144             pResultLookup->lookupKind.runtimeLookupArgs = pTemplateMD->GetMethodTable();
3145             pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_DeclaringTypeHandle;
3146             break;
3147
3148         case TypeHandleSlot:
3149             pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_TypeHandle;
3150             break;
3151
3152         case MethodDescSlot:
3153         case MethodEntrySlot:
3154         case ConstrainedMethodEntrySlot:
3155         case DispatchStubAddrSlot:
3156         {
3157             if (pTemplateMD != (MethodDesc*)pResolvedToken->hMethod)
3158                 ThrowHR(E_NOTIMPL);
3159
3160             if (entryKind == MethodDescSlot)
3161                 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_MethodHandle;
3162             else if (entryKind == MethodEntrySlot || entryKind == ConstrainedMethodEntrySlot)
3163                 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_MethodEntry;
3164             else
3165                 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_VirtualEntry;
3166
3167             pResultLookup->lookupKind.runtimeLookupArgs = pConstrainedResolvedToken;
3168
3169             break;
3170         }
3171
3172         case FieldDescSlot:
3173             pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_FieldHandle;
3174             break;
3175
3176         default:
3177             _ASSERTE(!"Unknown dictionary entry kind!");
3178             IfFailThrow(E_FAIL);
3179         }
3180
3181         // For R2R compilations, we don't generate the dictionary lookup signatures (dictionary lookups are done in a 
3182         // different way that is more version resilient... plus we can't have pointers to existing MTs/MDs in the sigs)
3183         return;
3184     }
3185 #endif
3186     // If we've got a  method type parameter of any kind then we must look in the method desc arg
3187     if (pContextMD->RequiresInstMethodDescArg())
3188     {
3189         pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG : CORINFO_HELP_RUNTIMEHANDLE_METHOD;
3190
3191         if (fInstrument)
3192             goto NoSpecialCase;
3193
3194         // Special cases:
3195         // (1) Naked method type variable: look up directly in instantiation hanging off runtime md
3196         // (2) Reference to method-spec of current method (e.g. a recursive call) i.e. currentmeth<!0,...,!(n-1)>
3197         if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3198         {
3199             SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3200             CorElementType type;
3201             IfFailThrow(sigptr.GetElemType(&type));
3202             if (type == ELEMENT_TYPE_MVAR)
3203             {
3204                 pResult->indirections = 2;
3205                 pResult->testForNull = 0;
3206 #ifdef FEATURE_PREJIT
3207                 pResult->testForFixup = 1;
3208 #else
3209                 pResult->testForFixup = 0;
3210 #endif
3211                 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3212
3213                 if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
3214                 {
3215                     pResult->indirectFirstOffset = 1;
3216                 }
3217
3218                 ULONG data;
3219                 IfFailThrow(sigptr.GetData(&data));
3220                 pResult->offsets[1] = sizeof(TypeHandle) * data;
3221
3222                 return;
3223             }
3224         }
3225         else if (entryKind == MethodDescSlot)
3226         {
3227             // It's the context itself (i.e. a recursive call)
3228             if (!pTemplateMD->HasSameMethodDefAs(pContextMD))
3229                 goto NoSpecialCase;
3230
3231             // Now just check that the instantiation is (!!0, ..., !!(n-1))
3232             if (!IsMethodSpecForTypicalInstantation(SigPointer(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)))
3233                 goto NoSpecialCase;
3234
3235             // Type instantiation has to match too if there is one
3236             if (pContextMT->HasInstantiation())
3237             {
3238                 TypeHandle thTemplate(pResolvedToken->hClass);
3239
3240                 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3241                     goto NoSpecialCase;
3242
3243                 // This check filters out method instantiation on generic type definition, like G::M<!!0>()
3244                 // We may not ever get it here. Filter it out just to be sure...
3245                 if (pResolvedToken->pTypeSpec == NULL)
3246                     goto NoSpecialCase;
3247
3248                 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3249                     goto NoSpecialCase;
3250             }
3251
3252             // Just use the method descriptor that was passed in!
3253             pResult->indirections = 0;
3254             pResult->testForNull = 0;
3255             pResult->testForFixup = 0;
3256
3257             return;
3258         }
3259     }
3260     // Otherwise we must just have class type variables
3261     else
3262     {
3263         _ASSERTE(pContextMT->GetNumGenericArgs() > 0);
3264
3265         if (pContextMD->RequiresInstMethodTableArg())
3266         {
3267             // If we've got a vtable extra argument, go through that
3268             pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3269         }
3270         // If we've got an object, go through its vtable
3271         else
3272         {
3273             _ASSERTE(pContextMD->AcquiresInstMethodTableFromThis());
3274             pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3275         }
3276
3277         if (fInstrument)
3278             goto NoSpecialCase;
3279
3280         // Special cases:
3281         // (1) Naked class type variable: look up directly in instantiation hanging off vtable
3282         // (2) C<!0,...,!(n-1)> where C is the context's class and C is sealed: just return vtable ptr
3283         if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3284         {
3285             SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3286             CorElementType type;
3287             IfFailThrow(sigptr.GetElemType(&type));
3288             if (type == ELEMENT_TYPE_VAR)
3289             {
3290                 pResult->indirections = 3;
3291                 pResult->testForNull = 0;
3292 #ifdef FEATURE_PREJIT
3293                 pResult->testForFixup = 1;
3294 #else
3295                 pResult->testForFixup = 0;
3296 #endif
3297                 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3298                 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3299                 ULONG data;
3300                 IfFailThrow(sigptr.GetData(&data));
3301                 pResult->offsets[2] = sizeof(TypeHandle) * data;
3302
3303                 if (MethodTable::IsPerInstInfoRelative())
3304                 {
3305                     pResult->indirectFirstOffset = 1;
3306                     pResult->indirectSecondOffset = 1;
3307                 }
3308
3309                 return;
3310             }
3311             else if (type == ELEMENT_TYPE_GENERICINST &&
3312                 (pContextMT->IsSealed() || pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM))
3313             {
3314                 TypeHandle thTemplate(pResolvedToken->hClass);
3315
3316                 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3317                     goto NoSpecialCase;
3318
3319                 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3320                     goto NoSpecialCase;
3321
3322                 // Just use the vtable pointer itself!
3323                 pResult->indirections = 0;
3324                 pResult->testForNull = 0;
3325                 pResult->testForFixup = 0;
3326
3327                 return;
3328             }
3329         }
3330     }
3331
3332 NoSpecialCase:
3333
3334     SigBuilder sigBuilder;
3335
3336     sigBuilder.AppendData(entryKind);
3337
3338     if (pResultLookup->lookupKind.runtimeLookupKind != CORINFO_LOOKUP_METHODPARAM)
3339     {
3340         _ASSERTE(pContextMT->GetNumDicts() > 0);
3341         sigBuilder.AppendData(pContextMT->GetNumDicts() - 1);
3342     }
3343
3344     Module * pModule = (Module *)pResolvedToken->tokenScope;
3345
3346     switch (entryKind)
3347     {
3348     case DeclaringTypeHandleSlot:
3349         _ASSERTE(pTemplateMD != NULL);
3350         sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3351         sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3352         // fall through
3353
3354     case TypeHandleSlot:
3355         {
3356             if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
3357             {
3358                 if (!IsReadyToRunCompilation())
3359                 {
3360                     sigBuilder.AppendElementType((CorElementType)ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
3361                 }
3362
3363                 sigBuilder.AppendElementType(ELEMENT_TYPE_SZARRAY);
3364             }
3365
3366             // Note that we can come here with pResolvedToken->pTypeSpec == NULL for invalid IL that 
3367             // directly references __Canon
3368             if (pResolvedToken->pTypeSpec != NULL)
3369             {
3370                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3371                 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3372             }
3373             else
3374             {
3375                 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3376                 sigBuilder.AppendPointer(pResolvedToken->hClass);
3377             }
3378         }
3379         break;
3380
3381     case ConstrainedMethodEntrySlot:
3382         // Encode constrained type token
3383         if (pConstrainedResolvedToken->pTypeSpec != NULL)
3384         {
3385             SigPointer sigptr(pConstrainedResolvedToken->pTypeSpec, pConstrainedResolvedToken->cbTypeSpec);
3386             sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3387         }
3388         else
3389         {
3390             sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3391             sigBuilder.AppendPointer(pConstrainedResolvedToken->hClass);
3392         }
3393         // fall through
3394
3395     case MethodDescSlot:
3396     case MethodEntrySlot:
3397     case DispatchStubAddrSlot:
3398         {
3399             // Encode containing type
3400             if (pResolvedToken->pTypeSpec != NULL)
3401             {
3402                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3403                 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3404             }
3405             else
3406             {
3407                 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3408                 sigBuilder.AppendPointer(pResolvedToken->hClass);
3409             }
3410
3411             // Encode method
3412             _ASSERTE(pTemplateMD != NULL);
3413
3414             mdMethodDef methodToken               = pTemplateMD->GetMemberDef_NoLogging();
3415             DWORD       methodFlags               = 0;
3416
3417             // 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 
3418             // like instantiating stub for generic method definition that do not have method spec but that won't be caught by the later conditions either.
3419             BOOL fMethodNeedsInstantiation = (pResolvedToken->pMethodSpec != NULL) && pTemplateMD->HasMethodInstantiation() && !pTemplateMD->IsGenericMethodDefinition();
3420
3421             if (pTemplateMD->IsUnboxingStub())
3422                 methodFlags |= ENCODE_METHOD_SIG_UnboxingStub;
3423             // Always create instantiating stub for method entry points even if the template does not ask for it. It saves caller 
3424             // from creating throw-away instantiating stub.
3425             if (pTemplateMD->IsInstantiatingStub() || (entryKind == MethodEntrySlot))
3426                 methodFlags |= ENCODE_METHOD_SIG_InstantiatingStub;
3427             if (fMethodNeedsInstantiation)
3428                 methodFlags |= ENCODE_METHOD_SIG_MethodInstantiation;
3429             if (IsNilToken(methodToken))
3430             {
3431                 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3432             }
3433             else
3434             if (entryKind == DispatchStubAddrSlot && pTemplateMD->IsVtableMethod())
3435             {
3436                 // Encode the method for dispatch stub using slot to avoid touching the interface method MethodDesc at runtime
3437
3438                 // There should be no other flags set if we are encoding the method using slot for virtual stub dispatch
3439                 _ASSERTE(methodFlags == 0);
3440
3441                 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3442             }
3443             else
3444             if (!pTemplateMD->GetModule()->IsInCurrentVersionBubble())
3445             {
3446                 // Using a method defined in another version bubble. We can assume the slot number is stable only for real interface methods.
3447                 if (!pTemplateMD->GetMethodTable()->IsInterface() || pTemplateMD->IsStatic() || pTemplateMD->HasMethodInstantiation())
3448                 {
3449                     _ASSERTE(!"References to non-interface methods not yet supported in version resilient images");
3450                     IfFailThrow(E_FAIL);
3451                 }
3452                 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3453             }
3454
3455             sigBuilder.AppendData(methodFlags);
3456
3457             if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
3458             {
3459                 // Encode method token and its module context (as method's type)
3460                 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3461                 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3462                 
3463                 sigBuilder.AppendData(RidFromToken(methodToken));
3464             }
3465             else
3466             {
3467                 sigBuilder.AppendData(pTemplateMD->GetSlot());
3468             }
3469
3470             if (fMethodNeedsInstantiation)
3471             {
3472                 SigPointer sigptr(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
3473                 
3474                 BYTE etype;
3475                 IfFailThrow(sigptr.GetByte(&etype));
3476
3477                 // Load the generic method instantiation
3478                 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, pModule);
3479                 
3480                 DWORD nGenericMethodArgs;
3481                 IfFailThrow(sigptr.GetData(&nGenericMethodArgs));
3482                 sigBuilder.AppendData(nGenericMethodArgs);
3483                 
3484                 _ASSERTE(nGenericMethodArgs == pTemplateMD->GetNumGenericMethodArgs());
3485                 
3486                 for (DWORD i = 0; i < nGenericMethodArgs; i++)
3487                 {
3488                     sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3489                 }
3490             }
3491         }
3492         break;
3493         
3494     case FieldDescSlot:
3495         {
3496             if (pResolvedToken->pTypeSpec != NULL)
3497             {
3498                  // Encode containing type
3499                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3500                 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3501             }
3502             else
3503             {
3504                 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3505                 sigBuilder.AppendPointer(pResolvedToken->hClass);
3506             }
3507
3508             FieldDesc * pField = (FieldDesc *)pResolvedToken->hField;
3509             _ASSERTE(pField != NULL);
3510
3511             DWORD fieldIndex = pField->GetApproxEnclosingMethodTable()->GetIndexForFieldDesc(pField);
3512             sigBuilder.AppendData(fieldIndex);
3513         }
3514         break;
3515         
3516     default:
3517         _ASSERTE(false);
3518     }
3519
3520     DictionaryEntrySignatureSource signatureSource = (IsCompilationProcess() ? FromZapImage : FromJIT);
3521
3522     // It's a method dictionary lookup
3523     if (pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM)
3524     {
3525         _ASSERTE(pContextMD != NULL);
3526         _ASSERTE(pContextMD->HasMethodInstantiation());
3527
3528         if (DictionaryLayout::FindToken(pContextMD->GetLoaderAllocator(), pContextMD->GetNumGenericMethodArgs(), pContextMD->GetDictionaryLayout(), pResult, &sigBuilder, 1, signatureSource))
3529         {
3530             pResult->testForNull = 1;
3531             pResult->testForFixup = 0;
3532
3533             // Indirect through dictionary table pointer in InstantiatedMethodDesc
3534             pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3535
3536             if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
3537             {
3538                 pResult->indirectFirstOffset = 1;
3539             }
3540         }
3541     }
3542
3543     // It's a class dictionary lookup (CORINFO_LOOKUP_CLASSPARAM or CORINFO_LOOKUP_THISOBJ)
3544     else
3545     {
3546         if (DictionaryLayout::FindToken(pContextMT->GetLoaderAllocator(), pContextMT->GetNumGenericArgs(), pContextMT->GetClass()->GetDictionaryLayout(), pResult, &sigBuilder, 2, signatureSource))
3547         {
3548             pResult->testForNull = 1;
3549             pResult->testForFixup = 0;
3550
3551             // Indirect through dictionary table pointer in vtable
3552             pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3553
3554             // Next indirect through the dictionary appropriate to this instantiated type
3555             pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3556
3557             if (MethodTable::IsPerInstInfoRelative())
3558             {
3559                 pResult->indirectFirstOffset = 1;
3560                 pResult->indirectSecondOffset = 1;
3561             }
3562         }
3563     }
3564 }
3565
3566
3567
3568 /*********************************************************************/
3569 const char* CEEInfo::getClassName (CORINFO_CLASS_HANDLE clsHnd)
3570 {
3571     CONTRACTL {
3572         SO_TOLERANT;
3573         THROWS;
3574         GC_TRIGGERS;
3575         MODE_PREEMPTIVE;
3576     } CONTRACTL_END;
3577
3578     const char* result = NULL;
3579
3580     JIT_TO_EE_TRANSITION();
3581
3582     TypeHandle VMClsHnd(clsHnd);
3583     MethodTable* pMT = VMClsHnd.GetMethodTable();
3584     if (pMT == NULL)
3585     {
3586         result = "";
3587     }
3588     else
3589     {
3590 #ifdef _DEBUG
3591         result = pMT->GetDebugClassName();
3592 #else // !_DEBUG
3593         // since this is for diagnostic purposes only,
3594         // give up on the namespace, as we don't have a buffer to concat it
3595         // also note this won't show array class names.
3596         LPCUTF8 nameSpace;
3597         result = pMT->GetFullyQualifiedNameInfo(&nameSpace);
3598 #endif
3599     }
3600
3601     EE_TO_JIT_TRANSITION();
3602
3603     return result;
3604 }
3605
3606 /***********************************************************************/
3607 const char* CEEInfo::getHelperName (CorInfoHelpFunc ftnNum)
3608 {
3609     CONTRACTL {
3610         SO_TOLERANT;
3611         NOTHROW;
3612         GC_NOTRIGGER;
3613         MODE_PREEMPTIVE;
3614         PRECONDITION(ftnNum >= 0 && ftnNum < CORINFO_HELP_COUNT);
3615     } CONTRACTL_END;
3616
3617     const char* result = NULL;
3618
3619     JIT_TO_EE_TRANSITION_LEAF();
3620
3621 #ifdef CROSSGEN_COMPILE
3622     result = hlpNameTable[ftnNum];
3623 #else
3624 #ifdef _DEBUG
3625     result = hlpFuncTable[ftnNum].name;
3626 #else
3627     result = "AnyJITHelper";
3628 #endif
3629 #endif
3630
3631     EE_TO_JIT_TRANSITION_LEAF();
3632
3633     return result;
3634 }
3635
3636
3637 /*********************************************************************/
3638 int CEEInfo::appendClassName(__deref_inout_ecount(*pnBufLen) WCHAR** ppBuf,
3639                              int* pnBufLen,
3640                              CORINFO_CLASS_HANDLE    clsHnd,
3641                              BOOL fNamespace,
3642                              BOOL fFullInst,
3643                              BOOL fAssembly)
3644 {
3645     CONTRACTL {
3646         SO_TOLERANT;
3647         MODE_PREEMPTIVE;
3648         THROWS;
3649         GC_TRIGGERS;
3650     } CONTRACTL_END;
3651
3652     int nLen = 0;
3653
3654     JIT_TO_EE_TRANSITION();
3655
3656     TypeHandle th(clsHnd);
3657     StackSString ss;
3658     TypeString::AppendType(ss,th,
3659                            (fNamespace ? TypeString::FormatNamespace : 0) |
3660                            (fFullInst ? TypeString::FormatFullInst : 0) |
3661                            (fAssembly ? TypeString::FormatAssembly : 0));
3662     const WCHAR* szString = ss.GetUnicode();
3663     nLen = (int)wcslen(szString);
3664     if (*pnBufLen > 0)
3665     {
3666     wcscpy_s(*ppBuf, *pnBufLen, szString );
3667     (*ppBuf)[(*pnBufLen) - 1] = W('\0');
3668     (*ppBuf) += nLen;
3669     (*pnBufLen) -= nLen;
3670     }
3671
3672     EE_TO_JIT_TRANSITION();
3673
3674     return nLen;
3675 }
3676
3677 /*********************************************************************/
3678 CORINFO_MODULE_HANDLE CEEInfo::getClassModule(CORINFO_CLASS_HANDLE clsHnd)
3679 {
3680     CONTRACTL {
3681         SO_TOLERANT;
3682         NOTHROW;
3683         GC_NOTRIGGER;
3684         MODE_PREEMPTIVE;
3685     } CONTRACTL_END;
3686
3687     CORINFO_MODULE_HANDLE result = NULL;
3688
3689     JIT_TO_EE_TRANSITION_LEAF();
3690
3691     TypeHandle     VMClsHnd(clsHnd);
3692
3693     result = CORINFO_MODULE_HANDLE(VMClsHnd.GetModule());
3694
3695     EE_TO_JIT_TRANSITION_LEAF();
3696
3697     return result;
3698 }
3699
3700 /*********************************************************************/
3701 CORINFO_ASSEMBLY_HANDLE CEEInfo::getModuleAssembly(CORINFO_MODULE_HANDLE modHnd)
3702 {
3703     CONTRACTL {
3704         SO_TOLERANT;
3705         NOTHROW;
3706         GC_NOTRIGGER;
3707         MODE_PREEMPTIVE;
3708     } CONTRACTL_END;
3709
3710     CORINFO_ASSEMBLY_HANDLE result = NULL;
3711
3712     JIT_TO_EE_TRANSITION_LEAF();
3713
3714     result = CORINFO_ASSEMBLY_HANDLE(GetModule(modHnd)->GetAssembly());
3715
3716     EE_TO_JIT_TRANSITION_LEAF();
3717
3718     return result;
3719 }
3720
3721 /*********************************************************************/
3722 const char* CEEInfo::getAssemblyName(CORINFO_ASSEMBLY_HANDLE asmHnd)
3723 {
3724     CONTRACTL {
3725         SO_TOLERANT;
3726         THROWS;
3727         GC_TRIGGERS;
3728         MODE_PREEMPTIVE;
3729     } CONTRACTL_END;
3730
3731     const char*  result = NULL;
3732
3733     JIT_TO_EE_TRANSITION();
3734     result = ((Assembly*)asmHnd)->GetSimpleName();
3735     EE_TO_JIT_TRANSITION();
3736
3737     return result;
3738 }
3739
3740 /*********************************************************************/
3741 void* CEEInfo::LongLifetimeMalloc(size_t sz)
3742 {
3743     CONTRACTL {
3744         SO_TOLERANT;
3745         NOTHROW;
3746         GC_NOTRIGGER;
3747         MODE_PREEMPTIVE;
3748     } CONTRACTL_END;
3749
3750     void*  result = NULL;
3751
3752     JIT_TO_EE_TRANSITION_LEAF();
3753     result = new (nothrow) char[sz];
3754     EE_TO_JIT_TRANSITION_LEAF();
3755
3756     return result;
3757 }
3758
3759 /*********************************************************************/
3760 void CEEInfo::LongLifetimeFree(void* obj)
3761 {
3762     CONTRACTL {
3763         SO_TOLERANT;
3764         NOTHROW;
3765         GC_NOTRIGGER;
3766         MODE_PREEMPTIVE;
3767     } CONTRACTL_END;
3768
3769     JIT_TO_EE_TRANSITION_LEAF();
3770     (operator delete)(obj);
3771     EE_TO_JIT_TRANSITION_LEAF();
3772 }
3773
3774 /*********************************************************************/
3775 size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_MODULE_HANDLE *pModuleHandle, void **ppIndirection)
3776 {
3777     CONTRACTL {
3778         SO_TOLERANT;
3779         NOTHROW;
3780         GC_NOTRIGGER;
3781         MODE_PREEMPTIVE;
3782     } CONTRACTL_END;
3783
3784     size_t result = 0;
3785
3786     JIT_TO_EE_TRANSITION_LEAF();
3787
3788     TypeHandle     VMClsHnd(clsHnd);
3789     Module *pModule = VMClsHnd.AsMethodTable()->GetModuleForStatics();
3790
3791     if (ppIndirection != NULL)
3792         *ppIndirection = NULL;
3793
3794     // The zapper needs the module handle. The jit should not use it at all.
3795     if (pModuleHandle)
3796         *pModuleHandle = CORINFO_MODULE_HANDLE(pModule);
3797
3798     result = pModule->GetModuleID();
3799
3800     _ASSERTE(result);
3801
3802     EE_TO_JIT_TRANSITION_LEAF();
3803
3804     return result;
3805 }
3806
3807 /*********************************************************************/
3808 BOOL CEEInfo::isValueClass(CORINFO_CLASS_HANDLE clsHnd)
3809 {
3810     CONTRACTL {
3811         SO_TOLERANT;
3812         NOTHROW;
3813         GC_NOTRIGGER;
3814         MODE_PREEMPTIVE;
3815     } CONTRACTL_END;
3816
3817     BOOL ret = FALSE;
3818
3819     JIT_TO_EE_TRANSITION_LEAF();
3820
3821     _ASSERTE(clsHnd);
3822
3823     // Note that clsHnd.IsValueType() would not return what the JIT expects
3824     // for corner cases like ELEMENT_TYPE_FNPTR
3825     TypeHandle VMClsHnd(clsHnd);
3826     MethodTable * pMT = VMClsHnd.GetMethodTable();
3827     ret = (pMT != NULL) ? pMT->IsValueType() : 0;
3828
3829     EE_TO_JIT_TRANSITION_LEAF();
3830
3831     return ret;
3832 }
3833
3834 /*********************************************************************/
3835 // If this method returns true, JIT will do optimization to inline the check for
3836 //     GetClassFromHandle(handle) == obj.GetType()
3837 //
3838 // This will enable to use directly the typehandle instead of going through getClassByHandle
3839 BOOL CEEInfo::canInlineTypeCheckWithObjectVTable (CORINFO_CLASS_HANDLE clsHnd)
3840 {
3841     CONTRACTL {
3842         SO_TOLERANT;
3843         NOTHROW;
3844         GC_NOTRIGGER;
3845         MODE_PREEMPTIVE;
3846     } CONTRACTL_END;
3847
3848     BOOL ret = FALSE;
3849
3850     JIT_TO_EE_TRANSITION_LEAF();
3851
3852     _ASSERTE(clsHnd);
3853
3854     TypeHandle VMClsHnd(clsHnd);
3855
3856     if (VMClsHnd.IsTypeDesc())
3857     {
3858         // We can't do this optimization for arrays because of the object methodtable is template methodtable
3859         ret = FALSE;
3860     }
3861     else
3862     if (VMClsHnd.AsMethodTable()->IsMarshaledByRef())
3863     {
3864         // We can't do this optimization for marshalbyrefs because of the object methodtable can be transparent proxy
3865         ret = FALSE;
3866     }
3867     else
3868     if (VMClsHnd.AsMethodTable()->IsInterface())
3869     {
3870         // Object.GetType() should not ever return interface. However, WCF custom remoting proxy does it. Disable this
3871         // optimization for interfaces so that (autogenerated) code that compares Object.GetType() with interface type works 
3872         // as expected for WCF custom remoting proxy. Note that this optimization is still not going to work well for custom
3873         // remoting proxies that are even more broken than the WCF one, e.g. returning random non-marshalbyref types 
3874         // from Object.GetType().
3875         ret = FALSE;
3876     }
3877     else
3878     if (VMClsHnd == TypeHandle(g_pCanonMethodTableClass))   
3879     {
3880         // We can't do this optimization in shared generics code because of we do not know what the actual type is going to be.
3881         // (It can be array, marshalbyref, etc.)
3882         ret = FALSE;
3883     }
3884     else
3885     {
3886         // It is safe to perform this optimization
3887         ret = TRUE;
3888     }
3889
3890     EE_TO_JIT_TRANSITION_LEAF();
3891
3892     return(ret);
3893 }
3894
3895 /*********************************************************************/
3896 DWORD CEEInfo::getClassAttribs (CORINFO_CLASS_HANDLE clsHnd)
3897 {
3898     CONTRACTL {
3899         SO_TOLERANT;
3900         THROWS;
3901         GC_TRIGGERS;
3902         MODE_PREEMPTIVE;
3903     } CONTRACTL_END;
3904
3905     // <REVISIT_TODO>@todo FIX need to really fetch the class atributes.  at present
3906     // we don't need to because the JIT only cares in the case of COM classes</REVISIT_TODO>
3907     DWORD ret = 0;
3908
3909     JIT_TO_EE_TRANSITION();
3910
3911     ret = getClassAttribsInternal(clsHnd);
3912
3913     EE_TO_JIT_TRANSITION();
3914
3915     return ret;
3916 }
3917
3918
3919 /*********************************************************************/
3920 BOOL CEEInfo::isStructRequiringStackAllocRetBuf(CORINFO_CLASS_HANDLE clsHnd)
3921 {
3922     CONTRACTL {
3923         SO_TOLERANT;
3924         THROWS;
3925         GC_TRIGGERS;
3926         MODE_PREEMPTIVE;
3927     } CONTRACTL_END;
3928
3929     BOOL ret = 0;
3930
3931     JIT_TO_EE_TRANSITION_LEAF();
3932
3933     TypeHandle     VMClsHnd(clsHnd);
3934     MethodTable * pMT = VMClsHnd.GetMethodTable();
3935     ret = (pMT != NULL && pMT->IsStructRequiringStackAllocRetBuf());
3936
3937     EE_TO_JIT_TRANSITION_LEAF();
3938
3939     return ret;
3940 }
3941
3942 /*********************************************************************/
3943 DWORD CEEInfo::getClassAttribsInternal (CORINFO_CLASS_HANDLE clsHnd)
3944 {
3945     STANDARD_VM_CONTRACT;
3946
3947     DWORD ret = 0;
3948
3949     _ASSERTE(clsHnd);
3950
3951     TypeHandle     VMClsHnd(clsHnd);
3952
3953     // Byrefs should only occur in method and local signatures, which are accessed
3954     // using ICorClassInfo and ICorClassInfo.getChildType.
3955     // So getClassAttribs() should not be called for byrefs
3956
3957     if (VMClsHnd.IsByRef())
3958     {
3959         _ASSERTE(!"Did findClass() return a Byref?");
3960         COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3961     }
3962     else if (VMClsHnd.IsGenericVariable())
3963     {
3964         //@GENERICSVER: for now, type variables simply report "variable".
3965         ret |= CORINFO_FLG_GENERIC_TYPE_VARIABLE;
3966     }
3967     else
3968     {
3969         MethodTable *pMT = VMClsHnd.GetMethodTable();
3970
3971         if (!pMT)
3972         {
3973             _ASSERTE(!"Did findClass() return a Byref?");
3974             COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3975         }
3976
3977         EEClass * pClass = pMT->GetClass();
3978
3979         // The array flag is used to identify the faked-up methods on
3980         // array types, i.e. .ctor, Get, Set and Address
3981         if (pMT->IsArray())
3982             ret |= CORINFO_FLG_ARRAY;
3983
3984         if (pMT->IsInterface())
3985             ret |= CORINFO_FLG_INTERFACE;
3986
3987         if (pMT->HasComponentSize())
3988             ret |= CORINFO_FLG_VAROBJSIZE;
3989
3990         if (pMT->IsValueType())
3991         {
3992             ret |= CORINFO_FLG_VALUECLASS;
3993
3994             if (pMT->IsByRefLike())
3995                 ret |= CORINFO_FLG_CONTAINS_STACK_PTR;
3996
3997             if ((pClass->IsNotTightlyPacked() && (!pClass->IsManagedSequential() || pClass->HasExplicitSize())) ||
3998                 pMT == g_TypedReferenceMT ||
3999                 VMClsHnd.IsNativeValueType())
4000             {
4001                 ret |= CORINFO_FLG_CUSTOMLAYOUT;
4002             }
4003
4004             if (pClass->IsUnsafeValueClass())
4005                 ret |= CORINFO_FLG_UNSAFE_VALUECLASS;
4006         }
4007         if (pClass->HasExplicitFieldOffsetLayout() && pClass->HasOverLayedField())
4008             ret |= CORINFO_FLG_OVERLAPPING_FIELDS;
4009         if (VMClsHnd.IsCanonicalSubtype())
4010             ret |= CORINFO_FLG_SHAREDINST;
4011
4012         if (pMT->HasVariance())
4013             ret |= CORINFO_FLG_VARIANCE;
4014
4015         if (pMT->IsContextful())
4016             ret |= CORINFO_FLG_CONTEXTFUL;
4017
4018         if (pMT->IsMarshaledByRef())
4019             ret |= CORINFO_FLG_MARSHAL_BYREF;
4020
4021         if (pMT->ContainsPointers() || pMT == g_TypedReferenceMT)
4022             ret |= CORINFO_FLG_CONTAINS_GC_PTR;
4023
4024         if (pMT->IsDelegate())
4025             ret |= CORINFO_FLG_DELEGATE;
4026
4027         if (pClass->IsBeforeFieldInit())
4028         {
4029             if (IsReadyToRunCompilation() && !pMT->GetModule()->IsInCurrentVersionBubble())
4030             {
4031                 // For version resiliency do not allow hoisting static constructors out of loops
4032             }
4033             else
4034             {
4035                 ret |= CORINFO_FLG_BEFOREFIELDINIT;
4036             }
4037         }
4038
4039         if (pClass->IsAbstract())
4040             ret |= CORINFO_FLG_ABSTRACT;
4041
4042         if (pClass->IsSealed())
4043             ret |= CORINFO_FLG_FINAL;
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         if (!pMD->IsCtor() && !pTypeToInitMT->IsValueType())
4146         {
4147             // For instance methods of types with precise-initialization
4148             // semantics, we can assume that the .ctor triggerred the
4149             // type initialization.
4150             // This does not hold for NULL "this" object. However, the spec does
4151             // not require that case to work.
4152             result = CORINFO_INITCLASS_NOT_REQUIRED;
4153             goto exit;
4154         }
4155     }
4156
4157     if (pTypeToInitMT->IsSharedByGenericInstantiations())
4158     {
4159         // Shared generic code has to use helper. Moreover, tell JIT not to inline since
4160         // inlining of generic dictionary lookups is not supported.
4161         result = CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE;
4162         goto exit;
4163     }
4164
4165     //
4166     // Try to prove that the initialization is not necessary because of nesting
4167     //
4168
4169     if (pFD == NULL)
4170     {
4171         // Handled above
4172         _ASSERTE(fIgnoreBeforeFieldInit || !pTypeToInitMT->GetClass()->IsBeforeFieldInit());
4173
4174         // Note that jit has both methods the same if asking whether to emit cctor
4175         // for a given method's code (as opposed to inlining codegen).
4176         if (context != MAKE_METHODCONTEXT(methodBeingCompiled) && pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4177         {
4178             // If we're inling a call to a method in our own type, then we should already
4179             // have triggered the .cctor when caller was itself called.
4180             result = CORINFO_INITCLASS_NOT_REQUIRED;
4181             goto exit;
4182         }
4183     }
4184     else
4185     {
4186         // This optimization may cause static fields in reference types to be accessed without cctor being triggered
4187         // for NULL "this" object. It does not conform with what the spec says. However, we have been historically 
4188         // doing it for perf reasons.
4189         if (!pTypeToInitMT->IsValueType() && !pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4190         {
4191             if (pTypeToInitMT == GetTypeFromContext(context).AsMethodTable() || pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4192             {
4193                 // The class will be initialized by the time we access the field.
4194                 result = CORINFO_INITCLASS_NOT_REQUIRED;
4195                 goto exit;
4196             }
4197         }
4198
4199         // If we are currently compiling the class constructor for this static field access then we can skip the initClass 
4200         if (methodBeingCompiled->GetMethodTable() == pTypeToInitMT && methodBeingCompiled->IsStatic() && methodBeingCompiled->IsClassConstructor())
4201         {
4202             // The class will be initialized by the time we access the field.
4203             result = CORINFO_INITCLASS_NOT_REQUIRED;
4204             goto exit;
4205         }
4206     }
4207
4208     if (fMethodDomainNeutral)
4209     {
4210         // Well, because of code sharing we can't do anything at coge generation time.
4211         // We have to do it at runtime.
4212         result = CORINFO_INITCLASS_USE_HELPER;
4213         goto exit;
4214     }
4215
4216 #ifndef CROSSGEN_COMPILE
4217     //
4218     // Optimizations for domain specific code
4219     //
4220
4221     // Allocate space for the local class if necessary, but don't trigger
4222     // class construction.
4223     DomainLocalModule *pModule = pTypeToInitMT->GetDomainLocalModule();
4224     pModule->PopulateClass(pTypeToInitMT);
4225
4226     if (pTypeToInitMT->IsClassInited())
4227     {
4228         result = CORINFO_INITCLASS_INITIALIZED;
4229         goto exit;
4230     }
4231
4232 #ifdef FEATURE_MULTICOREJIT
4233     // Once multicore JIT is enabled in an AppDomain by calling SetProfileRoot, always use helper function to call class init, for consistency
4234     if (! GetAppDomain()->GetMulticoreJitManager().AllowCCtorsToRunDuringJITing())
4235     {
4236         result = CORINFO_INITCLASS_USE_HELPER;
4237
4238         goto exit;
4239     }
4240 #endif
4241
4242     // To preserve consistent behavior between ngen and not-ngenned states, do not eagerly
4243     // run class constructors for autongennable code.
4244     if (pTypeToInitMT->RunCCTorAsIfNGenImageExists())
4245     {
4246         result = CORINFO_INITCLASS_USE_HELPER;
4247         goto exit;
4248     }
4249
4250     if (!pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4251     {
4252         // Do not inline the access if we cannot initialize the class. Chances are that the class will get
4253         // initialized by the time the access is jitted.
4254         result = CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE;
4255         goto exit;
4256     }
4257
4258     if (speculative)
4259     {
4260         // Tell the JIT that we may be able to initialize the class when asked to.
4261         result = CORINFO_INITCLASS_SPECULATIVE;
4262         goto exit;
4263     }
4264
4265     //
4266     // We cannot run the class constructor without first activating the
4267     // module containing the class.  However, since the current module
4268     // we are compiling inside is not active, we don't want to do this.
4269     //
4270     // This should be an unusal case since normally the method's module should
4271     // be active during jitting.
4272     //
4273     // @TODO: We should check IsActivating() instead of IsActive() since we may
4274     // be running the Module::.cctor(). The assembly is not marked as active
4275     // until then.
4276     if (!methodBeingCompiled->GetLoaderModule()->GetDomainFile()->IsActive())
4277     {
4278         result = CORINFO_INITCLASS_USE_HELPER;
4279         goto exit;
4280     }
4281
4282     //
4283     // Run the .cctor
4284     //
4285
4286     EX_TRY
4287     {
4288         pTypeToInitMT->CheckRunClassInitThrowing();
4289     }
4290     EX_CATCH
4291     {
4292     } EX_END_CATCH(SwallowAllExceptions);
4293
4294     if (pTypeToInitMT->IsClassInited())
4295     {
4296         result = CORINFO_INITCLASS_INITIALIZED;
4297         goto exit;
4298     }
4299 #endif // CROSSGEN_COMPILE
4300
4301     // Do not inline the access if we were unable to initialize the class. Chances are that the class will get
4302     // initialized by the time the access is jitted.
4303     result = (CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE);
4304
4305     }
4306 exit: ;
4307     EE_TO_JIT_TRANSITION();
4308
4309     return (CorInfoInitClassResult)result;
4310 }
4311
4312
4313
4314 void CEEInfo::classMustBeLoadedBeforeCodeIsRun (CORINFO_CLASS_HANDLE typeToLoadHnd)
4315 {
4316     CONTRACTL {
4317         SO_TOLERANT;
4318         NOTHROW;
4319         GC_NOTRIGGER;
4320         MODE_PREEMPTIVE;
4321     } CONTRACTL_END;
4322
4323     JIT_TO_EE_TRANSITION_LEAF();
4324
4325     TypeHandle th = TypeHandle(typeToLoadHnd);
4326
4327     // Type handles returned to JIT at runtime are always fully loaded. Verify that it is the case.
4328     _ASSERTE(th.IsFullyLoaded());
4329
4330     EE_TO_JIT_TRANSITION_LEAF();
4331 }
4332
4333 /*********************************************************************/
4334 void CEEInfo::methodMustBeLoadedBeforeCodeIsRun (CORINFO_METHOD_HANDLE methHnd)
4335 {
4336     CONTRACTL {
4337         SO_TOLERANT;
4338         NOTHROW;
4339         GC_NOTRIGGER;
4340         MODE_PREEMPTIVE;
4341     } CONTRACTL_END;
4342
4343     JIT_TO_EE_TRANSITION_LEAF();
4344
4345     MethodDesc *pMD = (MethodDesc*) methHnd;
4346
4347     // MethodDescs returned to JIT at runtime are always fully loaded. Verify that it is the case.
4348     _ASSERTE(pMD->IsRestored() && pMD->GetMethodTable()->IsFullyLoaded());
4349
4350     EE_TO_JIT_TRANSITION_LEAF();
4351 }
4352
4353 /*********************************************************************/
4354 CORINFO_METHOD_HANDLE CEEInfo::mapMethodDeclToMethodImpl(CORINFO_METHOD_HANDLE methHnd)
4355 {
4356     CONTRACTL {
4357         SO_TOLERANT;
4358         THROWS;
4359         GC_TRIGGERS;
4360         MODE_PREEMPTIVE;
4361     } CONTRACTL_END;
4362
4363     CORINFO_METHOD_HANDLE result = NULL;
4364
4365     JIT_TO_EE_TRANSITION();
4366
4367     MethodDesc *pMD = GetMethod(methHnd);
4368     pMD = MethodTable::MapMethodDeclToMethodImpl(pMD);
4369     result = (CORINFO_METHOD_HANDLE) pMD;
4370
4371     EE_TO_JIT_TRANSITION();
4372
4373     return result;
4374 }
4375
4376 /*********************************************************************/
4377 CORINFO_CLASS_HANDLE CEEInfo::getBuiltinClass(CorInfoClassId classId)
4378 {
4379     CONTRACTL {
4380         SO_TOLERANT;
4381         THROWS;
4382         GC_TRIGGERS;
4383         MODE_PREEMPTIVE;
4384     } CONTRACTL_END;
4385
4386     CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE) 0;
4387
4388     JIT_TO_EE_TRANSITION();
4389
4390     switch (classId)
4391     {
4392     case CLASSID_SYSTEM_OBJECT:
4393         result = CORINFO_CLASS_HANDLE(g_pObjectClass);
4394         break;
4395     case CLASSID_TYPED_BYREF:
4396         result = CORINFO_CLASS_HANDLE(g_TypedReferenceMT);
4397         break;
4398     case CLASSID_TYPE_HANDLE:
4399         result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__TYPE_HANDLE));
4400         break;
4401     case CLASSID_FIELD_HANDLE:
4402         result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__FIELD_HANDLE));
4403         break;
4404     case CLASSID_METHOD_HANDLE:
4405         result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__METHOD_HANDLE));
4406         break;
4407     case CLASSID_ARGUMENT_HANDLE:
4408         result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__ARGUMENT_HANDLE));
4409         break;
4410     case CLASSID_STRING:
4411         result = CORINFO_CLASS_HANDLE(g_pStringClass);
4412         break;
4413     case CLASSID_RUNTIME_TYPE:
4414         result = CORINFO_CLASS_HANDLE(g_pRuntimeTypeClass);
4415         break;
4416     default:
4417         _ASSERTE(!"NYI: unknown classId");
4418         break;
4419     }
4420
4421     EE_TO_JIT_TRANSITION();
4422
4423     return result;
4424 }
4425
4426
4427
4428 /*********************************************************************/
4429 CorInfoType CEEInfo::getTypeForPrimitiveValueClass(
4430         CORINFO_CLASS_HANDLE clsHnd)
4431 {
4432     CONTRACTL {
4433         SO_TOLERANT;
4434         THROWS;
4435         GC_TRIGGERS;
4436         MODE_PREEMPTIVE;
4437     } CONTRACTL_END;
4438
4439     CorInfoType result = CORINFO_TYPE_UNDEF;
4440
4441     JIT_TO_EE_TRANSITION();
4442
4443     TypeHandle th(clsHnd);
4444     _ASSERTE (!th.IsGenericVariable());
4445
4446     MethodTable    *pMT = th.GetMethodTable();
4447     PREFIX_ASSUME(pMT != NULL);
4448
4449     // Is it a non primitive struct such as
4450     // RuntimeTypeHandle, RuntimeMethodHandle, RuntimeArgHandle?
4451     if (pMT->IsValueType() &&
4452         !pMT->IsTruePrimitive()  &&
4453         !pMT->IsEnum())
4454     {
4455         // default value CORINFO_TYPE_UNDEF is what we want
4456     }
4457     else
4458     {
4459         switch (th.GetInternalCorElementType())
4460         {
4461         case ELEMENT_TYPE_I1:
4462         case ELEMENT_TYPE_U1:
4463         case ELEMENT_TYPE_BOOLEAN:
4464             result = asCorInfoType(ELEMENT_TYPE_I1);
4465             break;
4466
4467         case ELEMENT_TYPE_I2:
4468         case ELEMENT_TYPE_U2:
4469         case ELEMENT_TYPE_CHAR:
4470             result = asCorInfoType(ELEMENT_TYPE_I2);
4471             break;
4472
4473         case ELEMENT_TYPE_I4:
4474         case ELEMENT_TYPE_U4:
4475             result = asCorInfoType(ELEMENT_TYPE_I4);
4476             break;
4477
4478         case ELEMENT_TYPE_I8:
4479         case ELEMENT_TYPE_U8:
4480             result = asCorInfoType(ELEMENT_TYPE_I8);
4481             break;
4482
4483         case ELEMENT_TYPE_I:
4484         case ELEMENT_TYPE_U:
4485             result = asCorInfoType(ELEMENT_TYPE_I);
4486             break;
4487
4488         case ELEMENT_TYPE_R4:
4489             result = asCorInfoType(ELEMENT_TYPE_R4);
4490             break;
4491
4492         case ELEMENT_TYPE_R8:
4493             result = asCorInfoType(ELEMENT_TYPE_R8);
4494             break;
4495
4496         case ELEMENT_TYPE_VOID:
4497             result = asCorInfoType(ELEMENT_TYPE_VOID);
4498             break;
4499
4500         case ELEMENT_TYPE_PTR:
4501         case ELEMENT_TYPE_FNPTR:
4502             result = asCorInfoType(ELEMENT_TYPE_PTR);
4503             break;
4504
4505         default:
4506             break;
4507         }
4508     }
4509
4510     EE_TO_JIT_TRANSITION();
4511
4512     return result;
4513 }
4514
4515
4516 void CEEInfo::getGSCookie(GSCookie * pCookieVal, GSCookie ** ppCookieVal)
4517 {
4518     CONTRACTL {
4519         SO_TOLERANT;
4520         THROWS;
4521         GC_TRIGGERS;
4522         MODE_PREEMPTIVE;
4523     } CONTRACTL_END;
4524
4525     JIT_TO_EE_TRANSITION();
4526
4527     if (pCookieVal)
4528     {
4529         *pCookieVal = GetProcessGSCookie();
4530         *ppCookieVal = NULL;
4531     }
4532     else
4533     {
4534         *ppCookieVal = GetProcessGSCookiePtr();
4535     }
4536
4537     EE_TO_JIT_TRANSITION();
4538 }
4539
4540
4541 /*********************************************************************/
4542 // TRUE if child is a subtype of parent
4543 // if parent is an interface, then does child implement / extend parent
4544 BOOL CEEInfo::canCast(
4545         CORINFO_CLASS_HANDLE        child,
4546         CORINFO_CLASS_HANDLE        parent)
4547 {
4548     CONTRACTL {
4549         SO_TOLERANT;
4550         THROWS;
4551         GC_TRIGGERS;
4552         MODE_PREEMPTIVE;
4553     } CONTRACTL_END;
4554
4555     BOOL result = FALSE;
4556
4557     JIT_TO_EE_TRANSITION();
4558
4559     result = ((TypeHandle)child).CanCastTo((TypeHandle)parent);
4560
4561     EE_TO_JIT_TRANSITION();
4562
4563     return result;
4564 }
4565
4566 /*********************************************************************/
4567 // TRUE if cls1 and cls2 are considered equivalent types.
4568 BOOL CEEInfo::areTypesEquivalent(
4569         CORINFO_CLASS_HANDLE        cls1,
4570         CORINFO_CLASS_HANDLE        cls2)
4571 {
4572     CONTRACTL {
4573         SO_TOLERANT;
4574         THROWS;
4575         GC_TRIGGERS;
4576         MODE_PREEMPTIVE;
4577     } CONTRACTL_END;
4578
4579     BOOL result = FALSE;
4580
4581     JIT_TO_EE_TRANSITION();
4582
4583     result = ((TypeHandle)cls1).IsEquivalentTo((TypeHandle)cls2);
4584
4585     EE_TO_JIT_TRANSITION();
4586
4587     return result;
4588 }
4589
4590 /*********************************************************************/
4591 // returns is the intersection of cls1 and cls2.
4592 CORINFO_CLASS_HANDLE CEEInfo::mergeClasses(
4593         CORINFO_CLASS_HANDLE        cls1,
4594         CORINFO_CLASS_HANDLE        cls2)
4595 {
4596     CONTRACTL {
4597         SO_TOLERANT;
4598         THROWS;
4599         GC_TRIGGERS;
4600         MODE_PREEMPTIVE;
4601     } CONTRACTL_END;
4602
4603     CORINFO_CLASS_HANDLE result = NULL;
4604
4605     JIT_TO_EE_TRANSITION();
4606
4607     TypeHandle merged = TypeHandle::MergeTypeHandlesToCommonParent(TypeHandle(cls1), TypeHandle(cls2));
4608 #ifdef _DEBUG
4609     {
4610         //Make sure the merge is reflexive in the cases we "support".
4611         TypeHandle hnd1 = TypeHandle(cls1);
4612         TypeHandle hnd2 = TypeHandle(cls2);
4613         TypeHandle reflexive = TypeHandle::MergeTypeHandlesToCommonParent(hnd2, hnd1);
4614
4615         //If both sides are classes than either they have a common non-interface parent (in which case it is
4616         //reflexive)
4617         //OR they share a common interface, and it can be order dependent (if they share multiple interfaces
4618         //in common)
4619         if (!hnd1.IsInterface() && !hnd2.IsInterface())
4620         {
4621             if (merged.IsInterface())
4622             {
4623                 _ASSERTE(reflexive.IsInterface());
4624             }
4625             else
4626             {
4627                 _ASSERTE(merged == reflexive);
4628             }
4629         }
4630         //Both results must either be interfaces or classes.  They cannot be mixed.
4631         _ASSERTE((!!merged.IsInterface()) == (!!reflexive.IsInterface()));
4632
4633         //If the result of the merge was a class, then the result of the reflexive merge was the same class.
4634         if (!merged.IsInterface())
4635         {
4636             _ASSERTE(merged == reflexive);
4637         }
4638
4639         //If both sides are arrays, then the result is either an array or g_pArrayClass.  The above is
4640         //actually true about the element type for references types, but I think that that is a little
4641         //excessive for sanity.
4642         if (hnd1.IsArray() && hnd2.IsArray())
4643         {
4644             _ASSERTE((merged.IsArray() && reflexive.IsArray())
4645                      || ((merged == g_pArrayClass) && (reflexive == g_pArrayClass)));
4646         }
4647
4648         //Can I assert anything about generic variables?
4649
4650         //The results must always be assignable
4651         _ASSERTE(hnd1.CanCastTo(merged) && hnd2.CanCastTo(merged) && hnd1.CanCastTo(reflexive)
4652                  && hnd2.CanCastTo(reflexive));
4653     }
4654 #endif
4655     result = CORINFO_CLASS_HANDLE(merged.AsPtr());
4656
4657     EE_TO_JIT_TRANSITION();
4658     return result;
4659 }
4660
4661 /*********************************************************************/
4662 // Given a class handle, returns the Parent type.
4663 // For COMObjectType, it returns Class Handle of System.Object.
4664 // Returns 0 if System.Object is passed in.
4665 CORINFO_CLASS_HANDLE CEEInfo::getParentType(
4666             CORINFO_CLASS_HANDLE    cls)
4667 {
4668     CONTRACTL {
4669         SO_TOLERANT;
4670         THROWS;
4671         GC_TRIGGERS;
4672         MODE_PREEMPTIVE;
4673     } CONTRACTL_END;
4674
4675     CORINFO_CLASS_HANDLE result = NULL;
4676
4677     JIT_TO_EE_TRANSITION();
4678
4679     TypeHandle th(cls);
4680
4681     _ASSERTE(!th.IsNull());
4682     _ASSERTE(!th.IsGenericVariable());
4683
4684     TypeHandle thParent = th.GetParent();
4685
4686 #ifdef FEATURE_COMINTEROP
4687     // If we encounter __ComObject in the hierarchy, we need to skip it
4688     // since this hierarchy is introduced by the EE, but won't be present
4689     // in the metadata.
4690     if (!thParent.IsNull() && IsComObjectClass(thParent))
4691     {
4692         result = (CORINFO_CLASS_HANDLE) g_pObjectClass;
4693     }
4694     else
4695 #endif // FEATURE_COMINTEROP
4696     {
4697         result = CORINFO_CLASS_HANDLE(thParent.AsPtr());
4698     }
4699
4700     EE_TO_JIT_TRANSITION();
4701
4702     return result;
4703 }
4704
4705
4706 /*********************************************************************/
4707 // Returns the CorInfoType of the "child type". If the child type is
4708 // not a primitive type, *clsRet will be set.
4709 // Given an Array of Type Foo, returns Foo.
4710 // Given BYREF Foo, returns Foo
4711 CorInfoType CEEInfo::getChildType (
4712         CORINFO_CLASS_HANDLE       clsHnd,
4713         CORINFO_CLASS_HANDLE       *clsRet
4714         )
4715 {
4716     CONTRACTL {
4717         SO_TOLERANT;
4718         THROWS;
4719         GC_TRIGGERS;
4720         MODE_PREEMPTIVE;
4721     } CONTRACTL_END;
4722
4723     CorInfoType ret = CORINFO_TYPE_UNDEF;
4724     *clsRet = 0;
4725     TypeHandle  retType = TypeHandle();
4726
4727     JIT_TO_EE_TRANSITION();
4728
4729     TypeHandle th(clsHnd);
4730
4731     _ASSERTE(!th.IsNull());
4732
4733     // BYREF, ARRAY types
4734     if (th.IsTypeDesc())
4735     {
4736         retType = th.AsTypeDesc()->GetTypeParam();
4737     }
4738     else
4739     {
4740         // <REVISIT_TODO> we really should not have this case.  arrays type handles
4741         // used in the JIT interface should never be ordinary method tables,
4742         // indeed array type handles should really never be ordinary MTs
4743         // at all.  Perhaps we should assert !th.IsTypeDesc() && th.AsMethodTable().IsArray()? </REVISIT_TODO>
4744         MethodTable* pMT= th.AsMethodTable();
4745         if (pMT->IsArray())
4746             retType = pMT->GetApproxArrayElementTypeHandle();
4747     }
4748
4749     if (!retType.IsNull()) {
4750         CorElementType type = retType.GetInternalCorElementType();
4751         ret = CEEInfo::asCorInfoType(type,retType, clsRet);
4752
4753         // <REVISIT_TODO>What if this one is a value array ?</REVISIT_TODO>
4754     }
4755
4756     EE_TO_JIT_TRANSITION();
4757
4758     return ret;
4759 }
4760
4761 /*********************************************************************/
4762 // Check any constraints on class type arguments
4763 BOOL CEEInfo::satisfiesClassConstraints(CORINFO_CLASS_HANDLE cls)
4764 {
4765     CONTRACTL {
4766         SO_TOLERANT;
4767         THROWS;
4768         GC_TRIGGERS;
4769         MODE_PREEMPTIVE;
4770     } CONTRACTL_END;
4771
4772     BOOL result = FALSE;
4773
4774     JIT_TO_EE_TRANSITION();
4775
4776     _ASSERTE(cls != NULL);
4777     result = TypeHandle(cls).SatisfiesClassConstraints();
4778
4779     EE_TO_JIT_TRANSITION();
4780
4781     return result;
4782 }
4783
4784 /*********************************************************************/
4785 // Check if this is a single dimensional array type
4786 BOOL CEEInfo::isSDArray(CORINFO_CLASS_HANDLE  cls)
4787 {
4788     CONTRACTL {
4789         SO_TOLERANT;
4790         THROWS;
4791         GC_TRIGGERS;
4792         MODE_PREEMPTIVE;
4793     } CONTRACTL_END;
4794
4795     BOOL result = FALSE;
4796
4797     JIT_TO_EE_TRANSITION();
4798
4799     TypeHandle th(cls);
4800
4801     _ASSERTE(!th.IsNull());
4802
4803     if (th.IsArrayType())
4804     {
4805         // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4806         _ASSERTE(th != TypeHandle(g_pArrayClass));
4807
4808         result = (th.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
4809     }
4810
4811     EE_TO_JIT_TRANSITION();
4812
4813     return result;
4814 }
4815
4816 /*********************************************************************/
4817 // Get the number of dimensions in an array
4818 unsigned CEEInfo::getArrayRank(CORINFO_CLASS_HANDLE  cls)
4819 {
4820     CONTRACTL {
4821         SO_TOLERANT;
4822         THROWS;
4823         GC_TRIGGERS;
4824         MODE_PREEMPTIVE;
4825     } CONTRACTL_END;
4826
4827     unsigned result = 0;
4828
4829     JIT_TO_EE_TRANSITION();
4830
4831     TypeHandle th(cls);
4832
4833     _ASSERTE(!th.IsNull());
4834
4835     if (th.IsArrayType())
4836     {
4837         // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4838         _ASSERTE(th != TypeHandle(g_pArrayClass));
4839
4840         result = th.GetPossiblySharedArrayMethodTable()->GetRank();
4841     }
4842
4843     EE_TO_JIT_TRANSITION();
4844
4845     return result;
4846 }
4847
4848 /*********************************************************************/
4849 // Get static field data for an array
4850 // Note that it's OK to return NULL from this method.  This will cause
4851 // the JIT to make a runtime call to InitializeArray instead of doing
4852 // the inline optimization (thus preserving the original behavior).
4853 void * CEEInfo::getArrayInitializationData(
4854             CORINFO_FIELD_HANDLE        field,
4855             DWORD                       size
4856             )
4857 {
4858     CONTRACTL {
4859         SO_TOLERANT;
4860         THROWS;
4861         GC_TRIGGERS;
4862         MODE_PREEMPTIVE;
4863     } CONTRACTL_END;
4864
4865     void * result = NULL;
4866
4867     JIT_TO_EE_TRANSITION();
4868
4869     FieldDesc* pField = (FieldDesc*) field;
4870
4871     if (!pField                    ||
4872         !pField->IsRVA()           ||
4873         (pField->LoadSize() < size)
4874 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
4875         // This will make sure that when IBC logging is on, the array initialization happens thru 
4876         // COMArrayInfo::InitializeArray. This gives a place to put the IBC probe that can help
4877         // separate hold and cold RVA blobs.
4878         || (IsCompilingForNGen() &&
4879             GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
4880 #endif // FEATURE_NATIVE_IMAGE_GENERATION
4881         )
4882     {
4883         result = NULL;
4884     }
4885     else
4886     {
4887         result = pField->GetStaticAddressHandle(NULL);
4888     }
4889
4890     EE_TO_JIT_TRANSITION();
4891
4892     return result;
4893 }
4894
4895 CorInfoIsAccessAllowedResult CEEInfo::canAccessClass(
4896             CORINFO_RESOLVED_TOKEN * pResolvedToken,
4897             CORINFO_METHOD_HANDLE   callerHandle,
4898             CORINFO_HELPER_DESC    *pAccessHelper
4899             )
4900 {
4901     CONTRACTL {
4902         SO_TOLERANT;
4903         THROWS;
4904         GC_TRIGGERS;
4905         MODE_PREEMPTIVE;
4906     } CONTRACTL_END;
4907
4908     CorInfoIsAccessAllowedResult isAccessAllowed = CORINFO_ACCESS_ALLOWED;
4909
4910     JIT_TO_EE_TRANSITION();
4911
4912     INDEBUG(memset(pAccessHelper, 0xCC, sizeof(*pAccessHelper)));
4913
4914     BOOL doAccessCheck = TRUE;
4915     AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
4916     DynamicResolver * pAccessContext = NULL;
4917
4918     //All access checks must be done on the open instantiation.
4919     MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
4920     TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
4921
4922     TypeHandle pCalleeForSecurity = TypeHandle(pResolvedToken->hClass);
4923     if (pResolvedToken->pTypeSpec != NULL)
4924     {
4925         SigTypeContext typeContext;
4926         SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
4927
4928         SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
4929         pCalleeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
4930     }
4931
4932     while (pCalleeForSecurity.HasTypeParam())
4933     {
4934         pCalleeForSecurity = pCalleeForSecurity.GetTypeParam();
4935     }
4936
4937     if (IsDynamicScope(pResolvedToken->tokenScope))
4938     {
4939         doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope),
4940                                                     &callerTypeForSecurity, &accessCheckType,
4941                                                     &pAccessContext);
4942     }
4943
4944     //Since this is a check against a TypeHandle, there are some things we can stick in a TypeHandle that
4945     //don't require access checks.
4946     if (pCalleeForSecurity.IsGenericVariable())
4947     {
4948         //I don't need to check for access against !!0.
4949         doAccessCheck = FALSE;
4950     }
4951
4952     //Now do the visibility checks
4953     if (doAccessCheck)
4954     {
4955         AccessCheckOptions accessCheckOptions(accessCheckType,
4956                                               pAccessContext,
4957                                               FALSE /*throw on error*/,
4958                                               pCalleeForSecurity.GetMethodTable());
4959
4960         _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
4961         StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
4962
4963         BOOL canAccessType = ClassLoader::CanAccessClass(&accessContext,
4964                                                          pCalleeForSecurity.GetMethodTable(),
4965                                                          pCalleeForSecurity.GetAssembly(),
4966                                                          accessCheckOptions);
4967
4968         isAccessAllowed = canAccessType ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
4969     }
4970
4971
4972     if (isAccessAllowed != CORINFO_ACCESS_ALLOWED)
4973     {
4974         //These all get the throw helper
4975         pAccessHelper->helperNum = CORINFO_HELP_CLASS_ACCESS_EXCEPTION;
4976         pAccessHelper->numArgs = 2;
4977
4978         pAccessHelper->args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
4979         pAccessHelper->args[1].Set(CORINFO_CLASS_HANDLE(pCalleeForSecurity.AsPtr()));
4980
4981         if (IsCompilingForNGen())
4982         {
4983             //see code:CEEInfo::getCallInfo for more information.
4984             if (pCallerForSecurity->ContainsGenericVariables() || pCalleeForSecurity.ContainsGenericVariables())
4985                 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic TypeHandle"));
4986         }
4987     }
4988
4989     if (isAccessAllowed == CORINFO_ACCESS_ALLOWED)
4990     {
4991         //Finally let's get me some transparency checks.
4992         CorInfoSecurityRuntimeChecks runtimeChecks = CORINFO_ACCESS_SECURITY_NONE; 
4993
4994
4995         DebugSecurityCalloutStress(getMethodBeingCompiled(), isAccessAllowed,
4996                                    runtimeChecks);
4997
4998         if (isAccessAllowed != CORINFO_ACCESS_ALLOWED)
4999         {
5000             _ASSERTE(isAccessAllowed == CORINFO_ACCESS_RUNTIME_CHECK);
5001             //Well, time for the runtime helper
5002             pAccessHelper->helperNum = CORINFO_HELP_CLASS_ACCESS_CHECK;
5003             pAccessHelper->numArgs = 3;
5004
5005             pAccessHelper->args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5006             pAccessHelper->args[1].Set(CORINFO_CLASS_HANDLE(pCalleeForSecurity.AsPtr()));
5007             pAccessHelper->args[2].Set(runtimeChecks);
5008
5009             if (IsCompilingForNGen())
5010             {
5011                 //see code:CEEInfo::getCallInfo for more information.
5012                 if (pCallerForSecurity->ContainsGenericVariables() || pCalleeForSecurity.ContainsGenericVariables())
5013                     COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic TypeHandle"));
5014             }
5015         }
5016     }
5017
5018     EE_TO_JIT_TRANSITION();
5019     return isAccessAllowed;
5020 }
5021
5022 /***********************************************************************/
5023 // return the address of a pointer to a callable stub that will do the
5024 // virtual or interface call
5025 void CEEInfo::getCallInfo(
5026             CORINFO_RESOLVED_TOKEN * pResolvedToken,
5027             CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
5028             CORINFO_METHOD_HANDLE   callerHandle,
5029             CORINFO_CALLINFO_FLAGS  flags,
5030             CORINFO_CALL_INFO      *pResult /*out */)
5031 {
5032     CONTRACTL {
5033         SO_TOLERANT;
5034         THROWS;
5035         GC_TRIGGERS;
5036         MODE_PREEMPTIVE;
5037     } CONTRACTL_END;
5038
5039     JIT_TO_EE_TRANSITION();
5040
5041     _ASSERTE(CheckPointer(pResult));
5042
5043     INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
5044
5045     MethodDesc* pMD = (MethodDesc *)pResolvedToken->hMethod;
5046     TypeHandle th(pResolvedToken->hClass);
5047
5048     _ASSERTE(pMD);
5049     _ASSERTE((size_t(pMD) & 0x1) == 0);
5050
5051     // Spec says that a callvirt lookup ignores static methods. Since static methods
5052     // can't have the exact same signature as instance methods, a lookup that found
5053     // a static method would have never found an instance method.
5054     if (pMD->IsStatic() && (flags & CORINFO_CALLINFO_CALLVIRT))
5055     {
5056         EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, W("?")));
5057     }
5058
5059
5060
5061     TypeHandle exactType = TypeHandle(pResolvedToken->hClass);
5062
5063     TypeHandle constrainedType;
5064     if ((flags & CORINFO_CALLINFO_CALLVIRT) && (pConstrainedResolvedToken != NULL))
5065     {
5066         constrainedType = TypeHandle(pConstrainedResolvedToken->hClass);
5067     }
5068
5069     BOOL fResolvedConstraint = FALSE;
5070     BOOL fForceUseRuntimeLookup = FALSE;
5071
5072     MethodDesc * pMDAfterConstraintResolution = pMD;
5073     if (constrainedType.IsNull())
5074     {
5075         pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5076     }
5077     // <NICE> Things go wrong when this code path is used when verifying generic code.
5078     // It would be nice if we didn't go down this sort of code path when verifying but
5079     // not generating code. </NICE>
5080     else if (constrainedType.ContainsGenericVariables() || exactType.ContainsGenericVariables())
5081     {
5082         // <NICE> It shouldn't really matter what we do here - but the x86 JIT is annoyingly sensitive
5083         // about what we do, since it pretend generic variables are reference types and generates
5084         // an internal JIT tree even when just verifying generic code. </NICE>
5085         if (constrainedType.IsGenericVariable())
5086         {
5087             pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &T --> T
5088         }
5089         else if (constrainedType.IsValueType())
5090         {
5091             pResult->thisTransform = CORINFO_BOX_THIS; // convert 'this' of type &VC<T> --> boxed(VC<T>)
5092         }
5093         else
5094         {
5095             pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &C<T> --> C<T>
5096         }
5097     }
5098     else
5099     {
5100         // We have a "constrained." call.  Try a partial resolve of the constraint call.  Note that this
5101         // will not necessarily resolve the call exactly, since we might be compiling
5102         // shared generic code - it may just resolve it to a candidate suitable for
5103         // JIT compilation, and require a runtime lookup for the actual code pointer
5104         // to call.
5105         if (constrainedType.IsEnum())
5106         {
5107             // Optimize constrained calls to enum's GetHashCode method. TryResolveConstraintMethodApprox would return
5108             // null since the virtual method resolves to System.Enum's implementation and that's a reference type.
5109             // We can't do this for any other method since ToString and Equals have different semantics for enums
5110             // and their underlying type.
5111             if (pMD->GetSlot() == MscorlibBinder::GetMethod(METHOD__OBJECT__GET_HASH_CODE)->GetSlot())
5112             {
5113                 // Pretend this was a "constrained. UnderlyingType" instruction prefix
5114                 constrainedType = TypeHandle(MscorlibBinder::GetElementType(constrainedType.GetVerifierCorElementType()));
5115
5116                 // Native image signature encoder will use this field. It needs to match that pretended type, a bogus signature
5117                 // would be produced otherwise.
5118                 pConstrainedResolvedToken->hClass = (CORINFO_CLASS_HANDLE)constrainedType.AsPtr();
5119
5120                 // Clear the token and typespec because of they do not match hClass anymore.
5121                 pConstrainedResolvedToken->token = mdTokenNil;
5122                 pConstrainedResolvedToken->pTypeSpec = NULL;
5123             }
5124         }
5125
5126         MethodDesc * directMethod = constrainedType.GetMethodTable()->TryResolveConstraintMethodApprox(
5127             exactType, 
5128             pMD, 
5129             &fForceUseRuntimeLookup);
5130         if (directMethod)
5131         {
5132             // Either
5133             //    1. no constraint resolution at compile time (!directMethod)
5134             // OR 2. no code sharing lookup in call
5135             // OR 3. we have have resolved to an instantiating stub
5136
5137             pMDAfterConstraintResolution = directMethod;
5138             _ASSERTE(!pMDAfterConstraintResolution->IsInterface());
5139             fResolvedConstraint = TRUE;
5140             pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5141
5142             exactType = constrainedType;
5143         }
5144         else  if (constrainedType.IsValueType())
5145         {
5146             pResult->thisTransform = CORINFO_BOX_THIS;
5147         }
5148         else
5149         {
5150             pResult->thisTransform = CORINFO_DEREF_THIS;
5151         }
5152     }
5153
5154     //
5155     // Initialize callee context used for inlining and instantiation arguments
5156     //
5157
5158     MethodDesc * pTargetMD = pMDAfterConstraintResolution;
5159
5160     if (pTargetMD->HasMethodInstantiation())
5161     {
5162         pResult->contextHandle = MAKE_METHODCONTEXT(pTargetMD);
5163         pResult->exactContextNeedsRuntimeLookup = pTargetMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(pTargetMD->GetMethodInstantiation());
5164     }
5165     else
5166     {
5167         if (!exactType.IsTypeDesc())
5168         {
5169             // Because of .NET's notion of base calls, exactType may point to a sub-class
5170             // of the actual class that defines pTargetMD.  If the JIT decides to inline, it is
5171             // important that they 'match', so we fix exactType here.
5172 #ifdef FEATURE_READYTORUN_COMPILER
5173             if (IsReadyToRunCompilation() &&
5174                 !isVerifyOnly() && 
5175                 !IsInSameVersionBubble((MethodDesc*)callerHandle, pTargetMD))
5176             {
5177                 // For version resilient code we can only inline within the same version bubble;
5178                 // we "repair" the precise types only for those callees.
5179                 // The above condition needs to stay in sync with CEEInfo::canInline
5180             }
5181             else
5182 #endif
5183             {
5184          
5185                 exactType = pTargetMD->GetExactDeclaringType(exactType.AsMethodTable());
5186                 _ASSERTE(!exactType.IsNull());
5187             }
5188         }
5189
5190         pResult->contextHandle = MAKE_CLASSCONTEXT(exactType.AsPtr());
5191         pResult->exactContextNeedsRuntimeLookup = exactType.IsSharedByGenericInstantiations();
5192     }
5193
5194     //
5195     // Determine whether to perform direct call
5196     //
5197
5198     bool directCall = false;
5199     bool resolvedCallVirt = false;
5200     bool callVirtCrossingVersionBubble = false;
5201
5202     // Delegate targets are always treated as direct calls here. (It would be nice to clean it up...).
5203     if (flags & CORINFO_CALLINFO_LDFTN)
5204     {
5205         if (m_pOverride != NULL)
5206             TypeEquivalenceFixupSpecificationHelper(m_pOverride, pTargetMD);
5207         directCall = true;
5208     }
5209     else
5210     // Static methods are always direct calls
5211     if (pTargetMD->IsStatic())
5212     {
5213         directCall = true;
5214     }
5215     else
5216     // Force all interface calls to be interpreted as if they are virtual.
5217     if (pTargetMD->GetMethodTable()->IsInterface())
5218     {
5219         directCall = false;
5220     }
5221     else
5222     if (!(flags & CORINFO_CALLINFO_CALLVIRT) || fResolvedConstraint)
5223     {
5224         directCall = true;
5225     }
5226     else
5227     {
5228         bool devirt;
5229
5230 #ifdef FEATURE_READYTORUN_COMPILER
5231
5232         // if we are generating version resilient code
5233         // AND
5234         //    caller/callee are in different version bubbles
5235         // we have to apply more restrictive rules
5236         // These rules are related to the "inlining rules" as far as the
5237         // boundaries of a version bubble are concerned.
5238
5239         if (IsReadyToRunCompilation() &&
5240             !isVerifyOnly() &&
5241             !IsInSameVersionBubble((MethodDesc*)callerHandle, pTargetMD)
5242            )
5243         {
5244             // For version resiliency we won't de-virtualize all final/sealed method calls.  Because during a 
5245             // servicing event it is legal to unseal a method or type.
5246             //
5247             // Note that it is safe to devirtualize in the following cases, since a servicing event cannot later modify it
5248             //  1) Callvirt on a virtual final method of a value type - since value types are sealed types as per ECMA spec
5249             //  2) Delegate.Invoke() - since a Delegate is a sealed class as per ECMA spec
5250             //  3) JIT intrinsics - since they have pre-defined behavior
5251             devirt = pTargetMD->GetMethodTable()->IsValueType() ||
5252                      (pTargetMD->GetMethodTable()->IsDelegate() && ((DelegateEEClass*)(pTargetMD->GetMethodTable()->GetClass()))->GetInvokeMethod() == pMD) ||
5253                      (pTargetMD->IsFCall() && ECall::GetIntrinsicID(pTargetMD) != CORINFO_INTRINSIC_Illegal);
5254
5255             callVirtCrossingVersionBubble = true;
5256         }
5257         else
5258 #endif
5259         {
5260             DWORD dwMethodAttrs = pTargetMD->GetAttrs();
5261             devirt = !IsMdVirtual(dwMethodAttrs) || IsMdFinal(dwMethodAttrs) || pTargetMD->GetMethodTable()->IsSealed();
5262         }
5263
5264         if (devirt)
5265         {
5266             // We can't allow generic remotable methods to be considered resolved, it leads to a non-instantiating method desc being
5267             // passed to the remoting stub. The easiest way to deal with these is to force them through the virtual code path.
5268             // It is actually good to do this deoptimization for all remotable methods since remoting interception via vtable dispatch 
5269             // is faster then remoting interception via thunk
5270             if (!pTargetMD->IsRemotingInterceptedViaVirtualDispatch() /* || !pTargetMD->HasMethodInstantiation() */)
5271             {
5272                 resolvedCallVirt = true;
5273                 directCall = true;
5274             }
5275         }
5276     }
5277
5278     if (directCall)
5279     {
5280         bool allowInstParam = (flags & CORINFO_CALLINFO_ALLOWINSTPARAM)
5281             // See code:IsRemotingInterceptedViaPrestub on why we need need to disallow inst param for remoting.
5282             && !( pTargetMD->MayBeRemotingIntercepted() && !pTargetMD->IsVtableMethod() );
5283
5284         // Create instantiating stub if necesary
5285         if (!allowInstParam && pTargetMD->RequiresInstArg())
5286         {
5287             pTargetMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pTargetMD, 
5288                 exactType.AsMethodTable(), 
5289                 FALSE /* forceBoxedEntryPoint */, 
5290                 pTargetMD->GetMethodInstantiation(),
5291                 FALSE /* allowInstParam */);
5292         }
5293
5294         // We don't allow a JIT to call the code directly if a runtime lookup is
5295         // needed. This is the case if
5296         //     1. the scan of the call token indicated that it involves code sharing
5297         // AND 2. the method is an instantiating stub
5298         //
5299         // In these cases the correct instantiating stub is only found via a runtime lookup.
5300         //
5301         // Note that most JITs don't call instantiating stubs directly if they can help it -
5302         // they call the underlying shared code and provide the type context parameter
5303         // explicitly. However
5304         //    (a) some JITs may call instantiating stubs (it makes the JIT simpler) and
5305         //    (b) if the method is a remote stub then the EE will force the
5306         //        call through an instantiating stub and
5307         //    (c) constraint calls that require runtime context lookup are never resolved 
5308         //        to underlying shared generic code
5309
5310         if (((pResult->exactContextNeedsRuntimeLookup && pTargetMD->IsInstantiatingStub() && (!allowInstParam || fResolvedConstraint)) || fForceUseRuntimeLookup)
5311                 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
5312                 && ContextIsShared(pResolvedToken->tokenContext))
5313         {
5314             _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5315             pResult->kind = CORINFO_CALL_CODE_POINTER;
5316
5317             // For reference types, the constrained type does not affect method resolution
5318             DictionaryEntryKind entryKind = (!constrainedType.IsNull() && constrainedType.IsValueType()) ? ConstrainedMethodEntrySlot : MethodEntrySlot;
5319
5320             ComputeRuntimeLookupForSharedGenericToken(entryKind,
5321                                                       pResolvedToken,
5322                                                       pConstrainedResolvedToken,
5323                                                       pMD,
5324                                                       &pResult->codePointerLookup);
5325         }
5326         else
5327         {
5328             if (allowInstParam && pTargetMD->IsInstantiatingStub())
5329             {
5330                 pTargetMD = pTargetMD->GetWrappedMethodDesc();
5331             }
5332
5333             pResult->kind = CORINFO_CALL;
5334
5335             if (IsReadyToRunCompilation())
5336             {
5337                 // Compensate for always treating delegates as direct calls above
5338                 if ((flags & CORINFO_CALLINFO_LDFTN) && (flags & CORINFO_CALLINFO_CALLVIRT) && !resolvedCallVirt)
5339                 {
5340                    pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5341                 }
5342             }
5343         }
5344         pResult->nullInstanceCheck = resolvedCallVirt;
5345     }
5346     // All virtual calls which take method instantiations must
5347     // currently be implemented by an indirect call via a runtime-lookup
5348     // function pointer
5349     else if (pTargetMD->HasMethodInstantiation())
5350     {
5351         pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;  // stub dispatch can't handle generic method calls yet
5352         pResult->nullInstanceCheck = TRUE;
5353     }
5354     // Non-interface dispatches go through the vtable
5355     else if (!pTargetMD->IsInterface() && !IsReadyToRunCompilation())
5356     {
5357         pResult->kind = CORINFO_VIRTUALCALL_VTABLE;
5358         pResult->nullInstanceCheck = TRUE;
5359     }
5360     else
5361     {
5362         if (IsReadyToRunCompilation())
5363         {
5364             // Insert explicit null checks for cross-version bubble non-interface calls. 
5365             // It is required to handle null checks properly for non-virtual <-> virtual change between versions
5366             pResult->nullInstanceCheck = !!(callVirtCrossingVersionBubble && !pTargetMD->IsInterface());
5367         }
5368         else
5369         {
5370             // No need to null check - the dispatch code will deal with null this.
5371             pResult->nullInstanceCheck = FALSE;
5372         }
5373 #ifdef STUB_DISPATCH_PORTABLE
5374         pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5375 #else // STUB_DISPATCH_PORTABLE
5376         pResult->kind = CORINFO_VIRTUALCALL_STUB;
5377
5378         // We can't make stub calls when we need exact information
5379         // for interface calls from shared code.
5380
5381         if (// If the token is not shared then we don't need a runtime lookup
5382             pResult->exactContextNeedsRuntimeLookup
5383             // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
5384             && ContextIsShared(pResolvedToken->tokenContext))
5385         {
5386             _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5387             
5388             ComputeRuntimeLookupForSharedGenericToken(DispatchStubAddrSlot,
5389                                                         pResolvedToken,
5390                                                         NULL,
5391                                                         pMD,
5392                                                         &pResult->stubLookup);
5393         }
5394         else
5395         {
5396             pResult->stubLookup.lookupKind.needsRuntimeLookup = false;
5397
5398             BYTE * indcell = NULL;
5399
5400             if (!(flags & CORINFO_CALLINFO_KINDONLY) && !isVerifyOnly())
5401             {
5402 #ifndef CROSSGEN_COMPILE
5403                 // We shouldn't be using GetLoaderAllocator here because for LCG, we need to get the 
5404                 // VirtualCallStubManager from where the stub will be used. 
5405                 // For normal methods there is no difference.
5406                 LoaderAllocator *pLoaderAllocator = m_pMethodBeingCompiled->GetLoaderAllocatorForCode();
5407                 VirtualCallStubManager *pMgr = pLoaderAllocator->GetVirtualCallStubManager();
5408
5409                 PCODE addr = pMgr->GetCallStub(exactType, pTargetMD);
5410                 _ASSERTE(pMgr->isStub(addr));
5411                 
5412                 // Now we want to indirect through a cell so that updates can take place atomically.
5413                 if (m_pMethodBeingCompiled->IsLCGMethod())
5414                 {
5415                     // LCG methods should use recycled indcells to prevent leaks.
5416                     indcell = pMgr->GenerateStubIndirection(addr, TRUE);
5417
5418                     // Add it to the per DM list so that we can recycle them when the resolver is finalized
5419                     LCGMethodResolver *pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetLCGMethodResolver();
5420                     pResolver->AddToUsedIndCellList(indcell);
5421                 }
5422                 else
5423                 {
5424                     // Normal methods should avoid recycled cells to preserve the locality of all indcells
5425                     // used by one method.
5426                     indcell = pMgr->GenerateStubIndirection(addr, FALSE);
5427                 }
5428 #else // CROSSGEN_COMPILE
5429                 // This path should be unreachable during crossgen
5430                 _ASSERTE(false);
5431 #endif // CROSSGEN_COMPILE
5432             }
5433
5434             // We use an indirect call
5435             pResult->stubLookup.constLookup.accessType = IAT_PVALUE;
5436             pResult->stubLookup.constLookup.addr = indcell;
5437         }
5438 #endif // STUB_DISPATCH_PORTABLE
5439     }
5440
5441     pResult->hMethod = CORINFO_METHOD_HANDLE(pTargetMD);
5442
5443     pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5444     if ((flags & CORINFO_CALLINFO_SECURITYCHECKS) &&
5445         !((MethodDesc *)callerHandle)->IsILStub()) // IL stubs can access everything, don't bother doing access checks
5446     {
5447         //Our type system doesn't always represent the target exactly with the MethodDesc.  In all cases,
5448         //carry around the parent MethodTable for both Caller and Callee.
5449         TypeHandle calleeTypeForSecurity = TypeHandle(pResolvedToken->hClass);
5450         MethodDesc * pCalleeForSecurity = pMD;
5451
5452         MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle); //Should this be the open MD?
5453
5454         if (pCallerForSecurity->HasClassOrMethodInstantiation())
5455         {
5456             _ASSERTE(!IsDynamicScope(pResolvedToken->tokenScope));
5457
5458             SigTypeContext typeContext;
5459             SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
5460             _ASSERTE(!typeContext.IsEmpty());
5461
5462             //If the caller is generic, load the open type and resolve the token again.  Use that for the access
5463             //checks.  If we don't do this then we can't tell the difference between:
5464             //
5465             //BadGeneric<T> containing a methodspec for InaccessibleType::member (illegal)
5466             //and
5467             //BadGeneric<T> containing a methodspec for !!0::member instantiated over InaccessibleType (legal)
5468
5469             if (pResolvedToken->pTypeSpec != NULL)
5470             {
5471                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
5472                 calleeTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5473
5474                 // typeHnd can be a variable type
5475                 if (calleeTypeForSecurity.GetMethodTable() == NULL)
5476                 {
5477                     COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
5478                 }
5479             }
5480
5481             if (pCalleeForSecurity->IsArray())
5482             {
5483                 // FindOrCreateAssociatedMethodDesc won't remap array method desc because of array base type 
5484                 // is not part of instantiation. We have to special case it.
5485                 pCalleeForSecurity = calleeTypeForSecurity.GetMethodTable()->GetParallelMethodDesc(pCalleeForSecurity);
5486             }
5487             else
5488             if (pResolvedToken->pMethodSpec != NULL)
5489             {
5490                 DWORD nGenericMethodArgs = 0;
5491                 CQuickBytes qbGenericMethodArgs;
5492                 TypeHandle *genericMethodArgs = NULL;
5493
5494                 SigPointer sp(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
5495
5496                 BYTE etype;
5497                 IfFailThrow(sp.GetByte(&etype));
5498
5499                 // Load the generic method instantiation
5500                 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, (Module *)pResolvedToken->tokenScope);
5501
5502                 IfFailThrow(sp.GetData(&nGenericMethodArgs));
5503
5504                 DWORD cbAllocSize = 0;
5505                 if (!ClrSafeInt<DWORD>::multiply(nGenericMethodArgs, sizeof(TypeHandle), cbAllocSize))
5506                 {
5507                     COMPlusThrowHR(COR_E_OVERFLOW);
5508                 }
5509
5510                 genericMethodArgs = reinterpret_cast<TypeHandle *>(qbGenericMethodArgs.AllocThrows(cbAllocSize));
5511
5512                 for (DWORD i = 0; i < nGenericMethodArgs; i++)
5513                 {
5514                     genericMethodArgs[i] = sp.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5515                     _ASSERTE (!genericMethodArgs[i].IsNull());
5516                     IfFailThrow(sp.SkipExactlyOne());
5517                 }
5518
5519                 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(genericMethodArgs, nGenericMethodArgs), FALSE);
5520             }
5521             else
5522             if (pResolvedToken->pTypeSpec != NULL)
5523             {
5524                 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(), TRUE);
5525             }
5526         }
5527
5528         TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5529
5530         //Passed various link-time checks.  Now do access checks.
5531
5532         BOOL doAccessCheck = TRUE;
5533         BOOL canAccessMethod = TRUE;
5534         AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
5535         DynamicResolver * pAccessContext = NULL;
5536
5537         callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5538         if (pCallerForSecurity->IsDynamicMethod())
5539         {
5540             doAccessCheck = ModifyCheckForDynamicMethod(pCallerForSecurity->AsDynamicMethodDesc()->GetResolver(),
5541                                                         &callerTypeForSecurity,
5542                                                         &accessCheckType, &pAccessContext);
5543         }
5544     
5545         pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5546
5547         if (doAccessCheck)
5548         {
5549             AccessCheckOptions accessCheckOptions(accessCheckType,
5550                                                   pAccessContext,
5551                                                   FALSE,
5552                                                   pCalleeForSecurity);
5553
5554             _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5555             StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5556
5557             canAccessMethod = ClassLoader::CanAccess(&accessContext,
5558                                                      calleeTypeForSecurity.GetMethodTable(),
5559                                                      calleeTypeForSecurity.GetAssembly(),
5560                                                      pCalleeForSecurity->GetAttrs(),
5561                                                      pCalleeForSecurity,
5562                                                      NULL,
5563                                                      accessCheckOptions
5564                                                     );
5565
5566             // If we were allowed access to the exact method, but it is on a type that has a type parameter
5567             // (for instance an array), we need to ensure that we also have access to the type parameter.
5568             if (canAccessMethod && calleeTypeForSecurity.HasTypeParam())
5569             {
5570                 TypeHandle typeParam = calleeTypeForSecurity.GetTypeParam();
5571                 while (typeParam.HasTypeParam())
5572                 {
5573                     typeParam = typeParam.GetTypeParam();
5574                 }
5575
5576                 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5577                 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5578
5579                 MethodTable* pTypeParamMT = typeParam.GetMethodTable();
5580
5581                 // No accees check is need for Var, MVar, or FnPtr.
5582                 if (pTypeParamMT != NULL)
5583                     canAccessMethod = ClassLoader::CanAccessClass(&accessContext,
5584                                                                   pTypeParamMT,
5585                                                                   typeParam.GetAssembly(),
5586                                                                   accessCheckOptions);
5587             }
5588
5589             pResult->accessAllowed = canAccessMethod ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
5590             if (!canAccessMethod)
5591             {
5592                 //Check failed, fill in the throw exception helper.
5593                 pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_METHOD_ACCESS_EXCEPTION;
5594                 pResult->callsiteCalloutHelper.numArgs = 2;
5595
5596                 pResult->callsiteCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5597                 pResult->callsiteCalloutHelper.args[1].Set(CORINFO_METHOD_HANDLE(pCalleeForSecurity));
5598
5599                 //We now embed open instantiations in a few places for security callouts (since you can only
5600                 //do the security check on the open instantiation).  We throw these methods out in
5601                 //TriageMethodForZap.  In addition, NGen has problems referencing them properly.  Just throw out the whole
5602                 //method and rejit at runtime.
5603                 if (IsCompilingForNGen())
5604                 {
5605                     if (pCallerForSecurity->ContainsGenericVariables()
5606                         || pCalleeForSecurity->ContainsGenericVariables())
5607                     {
5608                         COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
5609                     }
5610                 }
5611             }
5612         }
5613     }
5614
5615     //We're pretty much done at this point.  Let's grab the rest of the information that the jit is going to
5616     //need.
5617     pResult->classFlags = getClassAttribsInternal(pResolvedToken->hClass);
5618
5619     pResult->methodFlags = getMethodAttribsInternal(pResult->hMethod);
5620     getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL);
5621
5622     if (flags & CORINFO_CALLINFO_VERIFICATION)
5623     {
5624         if (pResult->hMethod != pResolvedToken->hMethod)
5625         {
5626             pResult->verMethodFlags = getMethodAttribsInternal(pResolvedToken->hMethod);
5627             getMethodSigInternal(pResolvedToken->hMethod, &pResult->verSig, pResolvedToken->hClass);
5628         }
5629         else
5630         {
5631             pResult->verMethodFlags = pResult->methodFlags;
5632             pResult->verSig = pResult->sig;
5633         }
5634     }
5635
5636     pResult->secureDelegateInvoke = FALSE;
5637
5638 #ifdef FEATURE_STUBS_AS_IL
5639     if (m_pMethodBeingCompiled->IsDynamicMethod())
5640     {
5641         auto pMD = m_pMethodBeingCompiled->AsDynamicMethodDesc();
5642         if (pMD->IsILStub() && pMD->IsSecureDelegateStub())
5643         {
5644             pResult->secureDelegateInvoke = TRUE;
5645         }
5646     }
5647 #endif
5648
5649     EE_TO_JIT_TRANSITION();
5650 }
5651
5652 BOOL CEEInfo::canAccessFamily(CORINFO_METHOD_HANDLE hCaller,
5653                               CORINFO_CLASS_HANDLE hInstanceType)
5654 {
5655     WRAPPER_NO_CONTRACT;
5656
5657     BOOL ret = FALSE;
5658
5659     //Since this is only for verification, I don't need to do the demand.
5660     JIT_TO_EE_TRANSITION();
5661
5662     TypeHandle targetType = TypeHandle(hInstanceType);
5663     TypeHandle accessingType = TypeHandle(GetMethod(hCaller)->GetMethodTable());
5664     AccessCheckOptions::AccessCheckType accessCheckOptions = AccessCheckOptions::kNormalAccessibilityChecks;
5665     DynamicResolver* pIgnored;
5666     BOOL doCheck = TRUE;
5667     if (GetMethod(hCaller)->IsDynamicMethod())
5668     {
5669         //If this is a DynamicMethod, perform the check from the type to which the DynamicMethod was
5670         //attached.
5671         //
5672         //If this is a dynamic method, don't do this check.  If they specified SkipVisibilityChecks
5673         //(ModifyCheckForDynamicMethod returned false), we should obviously skip the check for the C++
5674         //protected rule (since we skipped all the other visibility checks).  If they specified
5675         //RestrictedSkipVisibilityChecks, then they're a "free" DynamicMethod.  This check is meaningless
5676         //(i.e.  it would always fail).  We've already done a demand for access to the member.  Let that be
5677         //enough.
5678         doCheck = ModifyCheckForDynamicMethod(GetMethod(hCaller)->AsDynamicMethodDesc()->GetResolver(),
5679                                               &accessingType, &accessCheckOptions, &pIgnored);
5680         if (accessCheckOptions == AccessCheckOptions::kRestrictedMemberAccess 
5681             || accessCheckOptions == AccessCheckOptions::kRestrictedMemberAccessNoTransparency
5682             )
5683             doCheck = FALSE;
5684     }
5685
5686     if (doCheck)
5687     {
5688         ret = ClassLoader::CanAccessFamilyVerification(accessingType, targetType);
5689     }
5690     else
5691     {
5692         ret = TRUE;
5693     }
5694
5695     EE_TO_JIT_TRANSITION();
5696     return ret;
5697 }
5698 void CEEInfo::ThrowExceptionForHelper(const CORINFO_HELPER_DESC * throwHelper)
5699 {
5700     CONTRACTL {
5701         SO_TOLERANT;
5702         THROWS;
5703         GC_TRIGGERS;
5704         MODE_PREEMPTIVE;
5705     } CONTRACTL_END;
5706
5707     JIT_TO_EE_TRANSITION();
5708
5709     _ASSERTE(throwHelper->args[0].argType == CORINFO_HELPER_ARG_TYPE_Method);
5710     MethodDesc *pCallerMD = GetMethod(throwHelper->args[0].methodHandle);
5711
5712     StaticAccessCheckContext accessContext(pCallerMD);
5713
5714     switch (throwHelper->helperNum)
5715     {
5716     case CORINFO_HELP_METHOD_ACCESS_EXCEPTION:
5717         {
5718             _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Method);
5719             ThrowMethodAccessException(&accessContext, GetMethod(throwHelper->args[1].methodHandle));
5720         }
5721         break;
5722     case CORINFO_HELP_FIELD_ACCESS_EXCEPTION:
5723         {
5724             _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Field);
5725             ThrowFieldAccessException(&accessContext, reinterpret_cast<FieldDesc *>(throwHelper->args[1].fieldHandle));
5726         }
5727         break;
5728     case CORINFO_HELP_CLASS_ACCESS_EXCEPTION:
5729         {
5730             _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Class);
5731             TypeHandle typeHnd(throwHelper->args[1].classHandle);
5732             ThrowTypeAccessException(&accessContext, typeHnd.GetMethodTable());
5733         }
5734         break;
5735
5736     default:
5737         _ASSERTE(!"Unknown access exception type");
5738     }
5739     EE_TO_JIT_TRANSITION();
5740 }
5741
5742
5743 BOOL CEEInfo::isRIDClassDomainID(CORINFO_CLASS_HANDLE cls)
5744 {
5745     CONTRACTL {
5746         SO_TOLERANT;
5747         THROWS;
5748         GC_TRIGGERS;
5749         MODE_PREEMPTIVE;
5750     } CONTRACTL_END;
5751
5752     BOOL result = FALSE;
5753
5754     JIT_TO_EE_TRANSITION();
5755
5756     TypeHandle  VMClsHnd(cls);
5757
5758     result = !VMClsHnd.AsMethodTable()->IsDynamicStatics();
5759
5760     EE_TO_JIT_TRANSITION();
5761
5762     return result;
5763 }
5764
5765
5766 /***********************************************************************/
5767 unsigned CEEInfo::getClassDomainID (CORINFO_CLASS_HANDLE clsHnd,
5768                                     void **ppIndirection)
5769 {
5770     CONTRACTL {
5771         SO_TOLERANT;
5772         THROWS;
5773         GC_TRIGGERS;
5774         MODE_PREEMPTIVE;
5775     } CONTRACTL_END;
5776
5777     unsigned result = 0;
5778
5779     if (ppIndirection != NULL)
5780         *ppIndirection = NULL;
5781
5782     JIT_TO_EE_TRANSITION();
5783
5784     TypeHandle  VMClsHnd(clsHnd);
5785
5786     if (VMClsHnd.AsMethodTable()->IsDynamicStatics())
5787     {
5788         result = (unsigned)VMClsHnd.AsMethodTable()->GetModuleDynamicEntryID();
5789     }
5790     else
5791     {
5792         result = (unsigned)VMClsHnd.AsMethodTable()->GetClassIndex();
5793     }
5794
5795     EE_TO_JIT_TRANSITION();
5796
5797     return result;
5798 }
5799
5800 //---------------------------------------------------------------------------------------
5801 //
5802 // Used by the JIT to determine whether the profiler or IBC is tracking object
5803 // allocations
5804 //
5805 // Return Value:
5806 //    bool indicating whether the profiler or IBC is tracking object allocations
5807 //
5808 // Notes:
5809 //    Normally, a profiler would just directly call the inline helper to determine
5810 //    whether the profiler set the relevant event flag (e.g.,
5811 //    CORProfilerTrackAllocationsEnabled). However, this wrapper also asks whether we're
5812 //    running for IBC instrumentation or enabling the object allocated ETW event. If so,
5813 //    we treat that the same as if the profiler requested allocation information, so that
5814 //    the JIT will still use the profiling-friendly object allocation jit helper, so the
5815 //    allocations can be tracked.
5816 //
5817
5818 bool __stdcall TrackAllocationsEnabled()
5819 {
5820     CONTRACTL 
5821     {
5822         NOTHROW;
5823         GC_NOTRIGGER;
5824         MODE_ANY;      
5825     } 
5826     CONTRACTL_END;
5827
5828     return (
5829         (g_IBCLogger.InstrEnabled() != FALSE)
5830 #ifdef PROFILING_SUPPORTED
5831         || CORProfilerTrackAllocationsEnabled()
5832 #endif // PROFILING_SUPPORTED
5833 #ifdef FEATURE_EVENT_TRACE
5834         || ETW::TypeSystemLog::IsHeapAllocEventEnabled()
5835 #endif // FEATURE_EVENT_TRACE
5836         );
5837 }
5838
5839 /***********************************************************************/
5840 CorInfoHelpFunc CEEInfo::getNewHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_METHOD_HANDLE callerHandle)
5841 {
5842     CONTRACTL {
5843         SO_TOLERANT;
5844         THROWS;
5845         GC_TRIGGERS;
5846         MODE_PREEMPTIVE;
5847     } CONTRACTL_END;
5848
5849     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5850
5851     JIT_TO_EE_TRANSITION();
5852
5853     TypeHandle  VMClsHnd(pResolvedToken->hClass);
5854
5855     if(VMClsHnd.IsTypeDesc())
5856     {
5857         COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateFunctionPointer"));
5858     }
5859
5860     if(VMClsHnd.IsAbstract())
5861     {
5862         COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateAbstractClass"));
5863     }
5864
5865     MethodTable* pMT = VMClsHnd.AsMethodTable();
5866     result = getNewHelperStatic(pMT);
5867
5868     _ASSERTE(result != CORINFO_HELP_UNDEF);
5869         
5870     EE_TO_JIT_TRANSITION();
5871
5872     return result;
5873 }
5874
5875 /***********************************************************************/
5876 CorInfoHelpFunc CEEInfo::getNewHelperStatic(MethodTable * pMT)
5877 {
5878     STANDARD_VM_CONTRACT;
5879
5880
5881     // Slow helper is the default
5882     CorInfoHelpFunc helper = CORINFO_HELP_NEWFAST;
5883
5884
5885     if (pMT->IsComObjectType())
5886     {
5887         // Use slow helper
5888         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5889     }
5890     else
5891     if ((pMT->GetBaseSize() >= LARGE_OBJECT_SIZE) || 
5892         pMT->HasFinalizer())
5893     {
5894         // Use slow helper
5895         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5896     }
5897     else
5898     // don't call the super-optimized one since that does not check
5899     // for GCStress
5900     if (GCStress<cfg_alloc>::IsEnabled())
5901     {
5902         // Use slow helper
5903         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5904     }
5905     else
5906 #ifdef _LOGALLOC
5907 #ifdef LOGGING
5908     // Super fast version doesn't do logging
5909     if (LoggingOn(LF_GCALLOC, LL_INFO10))
5910     {
5911         // Use slow helper
5912         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5913     }
5914     else
5915 #endif // LOGGING
5916 #endif // _LOGALLOC
5917     // Don't use the SFAST allocator when tracking object allocations,
5918     // so we don't have to instrument it.
5919     if (TrackAllocationsEnabled())
5920     {
5921         // Use slow helper
5922         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5923     }
5924     else
5925 #ifdef FEATURE_64BIT_ALIGNMENT
5926     // @ARMTODO: Force all 8-byte alignment requiring allocations down one slow path. As performance
5927     // measurements dictate we can spread these out to faster, more specialized helpers later.
5928     if (pMT->RequiresAlign8())
5929     {
5930         // Use slow helper
5931         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5932     }
5933     else
5934 #endif
5935     {
5936         // Use the fast helper when all conditions are met
5937         helper = CORINFO_HELP_NEWSFAST;
5938     }
5939
5940 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
5941     // If we are use the the fast allocator we also may need the 
5942     // specialized varion for align8
5943     if (pMT->GetClass()->IsAlign8Candidate() &&
5944         (helper == CORINFO_HELP_NEWSFAST))
5945     {
5946         helper = CORINFO_HELP_NEWSFAST_ALIGN8;
5947     }
5948 #endif // FEATURE_DOUBLE_ALIGNMENT_HINT
5949
5950     return helper;
5951 }
5952
5953 /***********************************************************************/
5954 // <REVIEW> this only works for shared generic code because all the
5955 // helpers are actually the same. If they were different then things might
5956 // break because the same helper would end up getting used for different but
5957 // representation-compatible arrays (e.g. one with a default constructor
5958 // and one without) </REVIEW>
5959 CorInfoHelpFunc CEEInfo::getNewArrHelper (CORINFO_CLASS_HANDLE arrayClsHnd)
5960 {
5961     CONTRACTL {
5962         SO_TOLERANT;
5963         THROWS;
5964         GC_TRIGGERS;
5965         MODE_PREEMPTIVE;
5966     } CONTRACTL_END;
5967
5968     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5969
5970     JIT_TO_EE_TRANSITION();
5971
5972     TypeHandle arrayType(arrayClsHnd);
5973
5974     result = getNewArrHelperStatic(arrayType);
5975
5976     _ASSERTE(result != CORINFO_HELP_UNDEF);
5977
5978     EE_TO_JIT_TRANSITION();
5979
5980     return result;
5981 }
5982
5983 /***********************************************************************/
5984 CorInfoHelpFunc CEEInfo::getNewArrHelperStatic(TypeHandle clsHnd)
5985 {
5986     STANDARD_VM_CONTRACT;
5987
5988     ArrayTypeDesc* arrayTypeDesc = clsHnd.AsArray();
5989     _ASSERTE(arrayTypeDesc->GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
5990
5991     if (GCStress<cfg_alloc>::IsEnabled())
5992     {
5993         return CORINFO_HELP_NEWARR_1_DIRECT;
5994     }
5995
5996     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5997
5998     TypeHandle thElemType = arrayTypeDesc->GetTypeParam();
5999     CorElementType elemType = thElemType.GetInternalCorElementType();
6000
6001     // This is if we're asked for newarr !0 when verifying generic code
6002     // Of course ideally you wouldn't even be generating code when
6003     // simply doing verification (we run the JIT importer in import-only
6004     // mode), but importing does more than one would like so we try to be
6005     // tolerant when asked for non-sensical helpers.
6006     if (CorTypeInfo::IsGenericVariable(elemType))
6007     {
6008         result = CORINFO_HELP_NEWARR_1_OBJ;
6009     }
6010     else if (CorTypeInfo::IsObjRef(elemType))
6011     {
6012         // It is an array of object refs
6013         result = CORINFO_HELP_NEWARR_1_OBJ;
6014     }
6015     else
6016     {
6017         // These cases always must use the slow helper
6018         if (
6019 #ifdef FEATURE_64BIT_ALIGNMENT
6020             thElemType.RequiresAlign8() ||
6021 #endif
6022             (elemType == ELEMENT_TYPE_VOID) ||
6023             LoggingOn(LF_GCALLOC, LL_INFO10) ||
6024             TrackAllocationsEnabled())
6025         {
6026             // Use the slow helper
6027             result = CORINFO_HELP_NEWARR_1_DIRECT;
6028         }
6029 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
6030         else if (elemType == ELEMENT_TYPE_R8)
6031         {
6032             // Use the Align8 fast helper
6033             result = CORINFO_HELP_NEWARR_1_ALIGN8;
6034         }
6035 #endif
6036         else
6037         {
6038             // Yea, we can do it the fast way!
6039             result = CORINFO_HELP_NEWARR_1_VC;
6040         }
6041     }
6042
6043     return result;
6044 }
6045
6046 /***********************************************************************/
6047 CorInfoHelpFunc CEEInfo::getCastingHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fThrowing)
6048 {
6049     CONTRACTL {
6050         SO_TOLERANT;
6051         THROWS;
6052         GC_TRIGGERS;
6053         MODE_PREEMPTIVE;
6054     } CONTRACTL_END;
6055
6056     if (isVerifyOnly())
6057         return fThrowing ? CORINFO_HELP_CHKCASTANY : CORINFO_HELP_ISINSTANCEOFANY;
6058
6059     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6060
6061     JIT_TO_EE_TRANSITION();
6062
6063     bool fClassMustBeRestored;
6064     result = getCastingHelperStatic(TypeHandle(pResolvedToken->hClass), fThrowing, &fClassMustBeRestored);
6065     if (fClassMustBeRestored && m_pOverride != NULL)
6066         m_pOverride->classMustBeLoadedBeforeCodeIsRun(pResolvedToken->hClass);
6067
6068     EE_TO_JIT_TRANSITION();
6069
6070     return result;
6071 }
6072
6073 /***********************************************************************/
6074 CorInfoHelpFunc CEEInfo::getCastingHelperStatic(TypeHandle clsHnd, bool fThrowing, bool * pfClassMustBeRestored)
6075 {
6076     STANDARD_VM_CONTRACT;
6077
6078     // Slow helper is the default
6079     int helper = CORINFO_HELP_ISINSTANCEOFANY;
6080
6081     *pfClassMustBeRestored = false;
6082
6083     if (clsHnd == TypeHandle(g_pCanonMethodTableClass))
6084     {
6085         // In shared code just use the catch-all helper for type variables, as the same
6086         // code may be used for interface/array/class instantiations
6087         //
6088         // We may be able to take advantage of constraints to select a specialized helper.
6089         // This optimizations does not seem to be warranted at the moment.
6090         _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6091     }
6092     else
6093     if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasVariance())
6094     {
6095         // Casting to variant type requires the type to be fully loaded
6096         *pfClassMustBeRestored = true;
6097
6098         _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6099     }
6100     else
6101     if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasTypeEquivalence())
6102     {
6103         // If the type can be equivalent with something, use the slow helper
6104         // Note: if the type of the instance is the one marked as equivalent, it will be
6105         // caught by the fast helpers in the same way as they catch transparent proxies.
6106         _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6107     }
6108     else
6109     if (clsHnd.IsInterface())
6110     {
6111         // If it is a non-variant interface, use the fast interface helper
6112         helper = CORINFO_HELP_ISINSTANCEOFINTERFACE;
6113     }
6114     else
6115     if (clsHnd.IsArray())
6116     {           
6117         if (clsHnd.AsArray()->GetInternalCorElementType() != ELEMENT_TYPE_SZARRAY)
6118         {
6119             // Casting to multidimensional array type requires restored pointer to EEClass to fetch rank
6120             *pfClassMustBeRestored = true;
6121         }
6122
6123         // If it is an array, use the fast array helper
6124         helper = CORINFO_HELP_ISINSTANCEOFARRAY;
6125     }
6126     else
6127     if (!clsHnd.IsTypeDesc() && !Nullable::IsNullableType(clsHnd))
6128     {
6129         // If it is a non-variant class, use the fast class helper
6130         helper = CORINFO_HELP_ISINSTANCEOFCLASS;
6131     }
6132     else
6133     {
6134         // Otherwise, use the slow helper
6135         _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6136     }
6137
6138 #ifdef FEATURE_PREJIT
6139     BOOL t1, t2, forceInstr;
6140     SystemDomain::GetCompilationOverrides(&t1, &t2, &forceInstr);
6141     if (forceInstr)
6142     {
6143         // If we're compiling for instrumentation, use the slowest but instrumented cast helper
6144         helper = CORINFO_HELP_ISINSTANCEOFANY;
6145     }
6146 #endif
6147
6148     if (fThrowing)
6149     {
6150         const int delta = CORINFO_HELP_CHKCASTANY - CORINFO_HELP_ISINSTANCEOFANY;
6151
6152         static_assert_no_msg(CORINFO_HELP_CHKCASTINTERFACE 
6153             == CORINFO_HELP_ISINSTANCEOFINTERFACE + delta);
6154         static_assert_no_msg(CORINFO_HELP_CHKCASTARRAY 
6155             == CORINFO_HELP_ISINSTANCEOFARRAY + delta);
6156         static_assert_no_msg(CORINFO_HELP_CHKCASTCLASS 
6157             == CORINFO_HELP_ISINSTANCEOFCLASS + delta);
6158
6159         helper += delta;
6160     }
6161
6162     return (CorInfoHelpFunc)helper;
6163 }
6164
6165 /***********************************************************************/
6166 CorInfoHelpFunc CEEInfo::getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd)
6167 {
6168     CONTRACTL {
6169         SO_TOLERANT;
6170         NOTHROW;
6171         GC_NOTRIGGER;
6172         MODE_PREEMPTIVE;
6173     } CONTRACTL_END;
6174
6175     CorInfoHelpFunc result = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
6176
6177     JIT_TO_EE_TRANSITION_LEAF();
6178
6179     TypeHandle cls(clsHnd);
6180     MethodTable* pMT = cls.AsMethodTable();
6181
6182     if (pMT->IsDynamicStatics())
6183     {
6184         _ASSERTE(!cls.ContainsGenericVariables());
6185         _ASSERTE(pMT->GetModuleDynamicEntryID() != (unsigned) -1);
6186
6187         result = CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
6188     }
6189
6190     EE_TO_JIT_TRANSITION_LEAF();
6191
6192     return result;
6193 }
6194
6195 /***********************************************************************/
6196 CorInfoHelpFunc CEEInfo::getUnBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6197 {
6198     LIMITED_METHOD_CONTRACT;
6199
6200     if (m_pOverride != NULL)
6201         m_pOverride->classMustBeLoadedBeforeCodeIsRun(clsHnd);
6202
6203     TypeHandle VMClsHnd(clsHnd);
6204     if (Nullable::IsNullableType(VMClsHnd))
6205         return CORINFO_HELP_UNBOX_NULLABLE;
6206     
6207     return CORINFO_HELP_UNBOX;
6208 }
6209
6210 /***********************************************************************/
6211 bool CEEInfo::getReadyToRunHelper(
6212         CORINFO_RESOLVED_TOKEN *        pResolvedToken,
6213         CORINFO_LOOKUP_KIND *           pGenericLookupKind,
6214         CorInfoHelpFunc                 id,
6215         CORINFO_CONST_LOOKUP *          pLookup
6216         )
6217 {
6218     LIMITED_METHOD_CONTRACT;
6219     UNREACHABLE();      // only called during NGen
6220 }
6221
6222 /***********************************************************************/
6223 void CEEInfo::getReadyToRunDelegateCtorHelper(
6224         CORINFO_RESOLVED_TOKEN * pTargetMethod,
6225         CORINFO_CLASS_HANDLE     delegateType,
6226         CORINFO_LOOKUP *   pLookup
6227         )
6228 {
6229     LIMITED_METHOD_CONTRACT;
6230     UNREACHABLE();      // only called during NGen
6231 }
6232
6233 /***********************************************************************/
6234 // see code:Nullable#NullableVerification
6235
6236 CORINFO_CLASS_HANDLE  CEEInfo::getTypeForBox(CORINFO_CLASS_HANDLE  cls)
6237 {
6238     LIMITED_METHOD_CONTRACT;
6239
6240     TypeHandle VMClsHnd(cls);
6241     if (Nullable::IsNullableType(VMClsHnd)) {
6242         VMClsHnd = VMClsHnd.AsMethodTable()->GetInstantiation()[0];
6243     }    
6244     return static_cast<CORINFO_CLASS_HANDLE>(VMClsHnd.AsPtr());
6245 }
6246
6247 /***********************************************************************/
6248 // see code:Nullable#NullableVerification
6249 CorInfoHelpFunc CEEInfo::getBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6250 {
6251     CONTRACTL {
6252         SO_TOLERANT;
6253         THROWS;
6254         GC_TRIGGERS;
6255         MODE_PREEMPTIVE;
6256     } CONTRACTL_END;
6257
6258     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6259
6260     JIT_TO_EE_TRANSITION();
6261
6262     TypeHandle VMClsHnd(clsHnd);
6263     if (Nullable::IsNullableType(VMClsHnd))
6264     {
6265         result = CORINFO_HELP_BOX_NULLABLE;
6266     }
6267     else 
6268     {
6269         // Dev10 718281 - This has been functionally broken fora very long time (at least 2.0).
6270         // The recent addition of the check for stack pointers has caused it to now AV instead
6271         // of gracefully failing with an InvalidOperationException. Since nobody has noticed
6272         // it being broken, we are choosing not to invest to fix it, and instead explicitly
6273         // breaking it and failing early and consistently.
6274         if(VMClsHnd.IsTypeDesc())
6275         {
6276             COMPlusThrow(kInvalidOperationException,W("InvalidOperation_TypeCannotBeBoxed"));
6277         }
6278
6279         // we shouldn't allow boxing of types that contains stack pointers
6280         // csc and vbc already disallow it.
6281         if (VMClsHnd.AsMethodTable()->IsByRefLike())
6282             COMPlusThrow(kInvalidProgramException);
6283
6284         result = CORINFO_HELP_BOX;
6285     }
6286     
6287     EE_TO_JIT_TRANSITION();
6288
6289     return result;
6290 }
6291
6292 /***********************************************************************/
6293 CorInfoHelpFunc CEEInfo::getSecurityPrologHelper(CORINFO_METHOD_HANDLE ftn)
6294 {
6295     CONTRACTL {
6296         SO_TOLERANT;
6297         THROWS;
6298         GC_TRIGGERS;
6299         MODE_PREEMPTIVE;
6300     } CONTRACTL_END;
6301
6302     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6303
6304     JIT_TO_EE_TRANSITION();
6305
6306 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6307     // This will make sure that when IBC logging is on, we call the slow helper with IBC probe
6308     if (IsCompilingForNGen() &&
6309         GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
6310     {
6311         result = CORINFO_HELP_SECURITY_PROLOG_FRAMED;
6312     }
6313 #endif // FEATURE_NATIVE_IMAGE_GENERATION
6314
6315     if (result == CORINFO_HELP_UNDEF)
6316     {
6317         result = CORINFO_HELP_SECURITY_PROLOG;
6318     }
6319
6320     EE_TO_JIT_TRANSITION();
6321
6322     return result;
6323 }
6324
6325 /***********************************************************************/
6326 // registers a vararg sig & returns a class-specific cookie for it.
6327
6328 CORINFO_VARARGS_HANDLE CEEInfo::getVarArgsHandle(CORINFO_SIG_INFO *sig,
6329                                                  void **ppIndirection)
6330 {
6331     CONTRACTL {
6332         SO_TOLERANT;
6333         THROWS;
6334         GC_TRIGGERS;
6335         MODE_PREEMPTIVE;
6336     } CONTRACTL_END;
6337
6338     CORINFO_VARARGS_HANDLE result = NULL;
6339
6340     if (ppIndirection != NULL)
6341         *ppIndirection = NULL;
6342
6343     JIT_TO_EE_TRANSITION();
6344
6345     Module* module = GetModule(sig->scope);
6346
6347     result = CORINFO_VARARGS_HANDLE(module->GetVASigCookie(Signature(sig->pSig, sig->cbSig)));
6348
6349     EE_TO_JIT_TRANSITION();
6350
6351     return result;
6352 }
6353
6354 bool CEEInfo::canGetVarArgsHandle(CORINFO_SIG_INFO *sig)
6355 {
6356     LIMITED_METHOD_CONTRACT;
6357     return true;
6358 }
6359
6360 /***********************************************************************/
6361 unsigned CEEInfo::getMethodHash (CORINFO_METHOD_HANDLE ftnHnd)
6362 {
6363     CONTRACTL {
6364         SO_TOLERANT;
6365         THROWS;
6366         GC_TRIGGERS;
6367         MODE_PREEMPTIVE;
6368     } CONTRACTL_END;
6369
6370     unsigned result = 0;
6371
6372     JIT_TO_EE_TRANSITION();
6373
6374     MethodDesc* ftn = GetMethod(ftnHnd);
6375
6376     result = (unsigned) ftn->GetStableHash();
6377
6378     EE_TO_JIT_TRANSITION();
6379
6380     return result;
6381 }
6382
6383 /***********************************************************************/
6384 const char* CEEInfo::getMethodName (CORINFO_METHOD_HANDLE ftnHnd, const char** scopeName)
6385 {
6386     CONTRACTL {
6387         SO_TOLERANT;
6388         THROWS;
6389         GC_TRIGGERS;
6390         MODE_PREEMPTIVE;
6391     } CONTRACTL_END;
6392
6393     const char* result = NULL;
6394
6395     JIT_TO_EE_TRANSITION();
6396
6397     MethodDesc *ftn;
6398
6399     ftn = GetMethod(ftnHnd);
6400
6401     if (scopeName != 0)
6402     {
6403         if (ftn->IsLCGMethod())
6404         {
6405             *scopeName = "DynamicClass";
6406         }
6407         else if (ftn->IsILStub())
6408         {
6409             *scopeName = ILStubResolver::GetStubClassName(ftn);
6410         }
6411         else
6412         {
6413             MethodTable * pMT = ftn->GetMethodTable();
6414 #if defined(_DEBUG) 
6415 #ifdef FEATURE_SYMDIFF
6416             if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SymDiffDump))
6417             {
6418                 if (pMT->IsArray())
6419                 {
6420                     ssClsNameBuff.Clear();
6421                     ssClsNameBuff.SetUTF8(pMT->GetDebugClassName());
6422                 }
6423                 else
6424                     pMT->_GetFullyQualifiedNameForClassNestedAware(ssClsNameBuff);
6425             }
6426             else
6427             {
6428 #endif
6429                 // Calling _GetFullyQualifiedNameForClass in chk build is very expensive
6430                 // since it construct the class name everytime we call this method. In chk
6431                 // builds we already have a cheaper way to get the class name -
6432                 // GetDebugClassName - which doesn't calculate the class name everytime.
6433                 // This results in huge saving in Ngen time for checked builds. 
6434                 ssClsNameBuff.Clear();
6435                 ssClsNameBuff.SetUTF8(pMT->GetDebugClassName());
6436
6437 #ifdef FEATURE_SYMDIFF
6438             }
6439 #endif            
6440             // Append generic instantiation at the end
6441             Instantiation inst = pMT->GetInstantiation();
6442             if (!inst.IsEmpty())
6443                 TypeString::AppendInst(ssClsNameBuff, inst);
6444                 
6445             *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
6446 #else // !_DEBUG
6447             // since this is for diagnostic purposes only,
6448             // give up on the namespace, as we don't have a buffer to concat it
6449             // also note this won't show array class names.
6450             LPCUTF8 nameSpace;
6451             *scopeName= pMT->GetFullyQualifiedNameInfo(&nameSpace);
6452 #endif // !_DEBUG
6453         }
6454     }
6455
6456     result = ftn->GetName();
6457
6458     EE_TO_JIT_TRANSITION();
6459     
6460     return result;
6461 }
6462
6463 const char* CEEInfo::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftnHnd, const char** className, const char** namespaceName)
6464 {
6465     CONTRACTL {
6466         SO_TOLERANT;
6467         THROWS;
6468         GC_TRIGGERS;
6469         MODE_PREEMPTIVE;
6470     } CONTRACTL_END;
6471
6472     const char* result = NULL;
6473     const char* classResult = NULL;
6474     const char* namespaceResult = NULL;
6475
6476     JIT_TO_EE_TRANSITION();
6477
6478     MethodDesc *ftn = GetMethod(ftnHnd);
6479     mdMethodDef token = ftn->GetMemberDef();
6480
6481     if (!IsNilToken(token))
6482     {
6483         if (!FAILED(ftn->GetMDImport()->GetNameOfMethodDef(token, &result)))
6484         {
6485             MethodTable* pMT = ftn->GetMethodTable();
6486             classResult = pMT->GetFullyQualifiedNameInfo(&namespaceResult);
6487         }
6488     }
6489
6490     if (className != NULL)
6491     {
6492         *className = classResult;
6493     }
6494
6495     if (namespaceName != NULL)
6496     {
6497         *namespaceName = namespaceResult;
6498     }
6499
6500     EE_TO_JIT_TRANSITION();
6501     
6502     return result;
6503 }
6504
6505 /*********************************************************************/
6506 DWORD CEEInfo::getMethodAttribs (CORINFO_METHOD_HANDLE ftn)
6507 {
6508     CONTRACTL {
6509         SO_TOLERANT;
6510         THROWS;
6511         GC_TRIGGERS;
6512         MODE_PREEMPTIVE;
6513     } CONTRACTL_END;
6514
6515     DWORD result = 0;
6516
6517     JIT_TO_EE_TRANSITION();
6518
6519     result = getMethodAttribsInternal(ftn);
6520
6521     EE_TO_JIT_TRANSITION();
6522
6523     return result;
6524 }
6525
6526 /*********************************************************************/
6527 DWORD CEEInfo::getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftn)
6528 {
6529     STANDARD_VM_CONTRACT;
6530
6531 /*
6532     returns method attribute flags (defined in corhdr.h)
6533
6534     NOTE: This doesn't return certain method flags
6535     (mdAssem, mdFamANDAssem, mdFamORAssem, mdPrivateScope)
6536 */
6537
6538     MethodDesc* pMD = GetMethod(ftn);
6539
6540     if (pMD->IsLCGMethod()) 
6541     {
6542         return CORINFO_FLG_STATIC | CORINFO_FLG_DONT_INLINE | CORINFO_FLG_NOSECURITYWRAP;
6543     }
6544
6545     DWORD result = CORINFO_FLG_NOSECURITYWRAP;
6546
6547     // <REVISIT_TODO>@todo: can we git rid of CORINFO_FLG_ stuff and just include cor.h?</REVISIT_TODO>
6548
6549     DWORD attribs = pMD->GetAttrs();
6550
6551     if (IsMdFamily(attribs))
6552         result |= CORINFO_FLG_PROTECTED;
6553     if (IsMdStatic(attribs))
6554         result |= CORINFO_FLG_STATIC;
6555     if (pMD->IsSynchronized())
6556         result |= CORINFO_FLG_SYNCH;
6557     if (pMD->IsFCallOrIntrinsic())
6558         result |= CORINFO_FLG_NOGCCHECK | CORINFO_FLG_INTRINSIC;
6559     if (pMD->IsJitIntrinsic())
6560         result |= CORINFO_FLG_JIT_INTRINSIC;
6561     if (IsMdVirtual(attribs))
6562         result |= CORINFO_FLG_VIRTUAL;
6563     if (IsMdAbstract(attribs))
6564         result |= CORINFO_FLG_ABSTRACT;
6565     if (IsMdRTSpecialName(attribs))
6566     {
6567         LPCUTF8 pName = pMD->GetName();
6568         if (IsMdInstanceInitializer(attribs, pName) ||
6569             IsMdClassConstructor(attribs, pName))
6570             result |= CORINFO_FLG_CONSTRUCTOR;
6571     }
6572
6573     //
6574     // See if we need to embed a .cctor call at the head of the
6575     // method body.
6576     //
6577
6578     MethodTable* pMT = pMD->GetMethodTable();
6579
6580     // method or class might have the final bit
6581     if (IsMdFinal(attribs) || pMT->IsSealed())
6582     {
6583         result |= CORINFO_FLG_FINAL;
6584     }
6585
6586     if (pMD->IsEnCAddedMethod())
6587     {
6588         result |= CORINFO_FLG_EnC;
6589     }
6590
6591     if (pMD->IsSharedByGenericInstantiations())
6592     {
6593         result |= CORINFO_FLG_SHAREDINST;
6594     }
6595
6596     if (pMD->IsNDirect())
6597     {
6598         result |= CORINFO_FLG_PINVOKE;
6599     }
6600
6601     if (IsMdRequireSecObject(attribs))
6602     {
6603         // Assume all methods marked as DynamicSecurity are
6604         // marked that way because they use StackCrawlMark to identify
6605         // the caller.
6606         // See comments in canInline or canTailCall
6607         result |= CORINFO_FLG_DONT_INLINE_CALLER;
6608     }
6609
6610     // Check for an inlining directive.
6611     if (pMD->IsNotInline())
6612     {
6613         /* Function marked as not inlineable */
6614         result |= CORINFO_FLG_DONT_INLINE;
6615     }
6616     // AggressiveInlining only makes sense for IL methods.
6617     else if (pMD->IsIL() && IsMiAggressiveInlining(pMD->GetImplAttrs()))
6618     {
6619         result |= CORINFO_FLG_FORCEINLINE;
6620     }
6621
6622     if (pMT->IsDelegate() && ((DelegateEEClass*)(pMT->GetClass()))->GetInvokeMethod() == pMD)
6623     {
6624         // This is now used to emit efficient invoke code for any delegate invoke,
6625         // including multicast.
6626         result |= CORINFO_FLG_DELEGATE_INVOKE;
6627     }
6628
6629     return result;
6630 }
6631
6632 /*********************************************************************/
6633 void CEEInfo::setMethodAttribs (
6634         CORINFO_METHOD_HANDLE ftnHnd,
6635         CorInfoMethodRuntimeFlags attribs)
6636 {
6637     CONTRACTL {
6638         SO_TOLERANT;
6639         THROWS;
6640         GC_TRIGGERS;
6641         MODE_PREEMPTIVE;
6642     } CONTRACTL_END;
6643
6644     JIT_TO_EE_TRANSITION();
6645
6646     MethodDesc* ftn = GetMethod(ftnHnd);
6647
6648     if (attribs & CORINFO_FLG_BAD_INLINEE)
6649     {
6650         BOOL fCacheInliningHint = TRUE;
6651
6652 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6653         if (IsCompilationProcess())
6654         {
6655             // Since we are running managed code during NGen the inlining hint may be 
6656             // changing underneeth us as the code is JITed. We need to prevent the inlining
6657             // hints from changing once we start to use them to place IL in the image.
6658             if (!g_pCEECompileInfo->IsCachingOfInliningHintsEnabled())
6659             {
6660                 fCacheInliningHint = FALSE;
6661             }
6662             else
6663             {
6664                 // Don't cache inlining hints inside mscorlib during NGen of other assemblies,
6665                 // since mscorlib is loaded domain neutral and will survive worker process recycling,
6666                 // causing determinism problems.
6667                 Module * pModule = ftn->GetModule();
6668                 if (pModule->IsSystem() && pModule->HasNativeImage())
6669                 {
6670                     fCacheInliningHint = FALSE;
6671                 }
6672             }
6673         }
6674 #endif
6675
6676         if (fCacheInliningHint)
6677         {
6678             ftn->SetNotInline(true);
6679         }
6680     }
6681
6682     EE_TO_JIT_TRANSITION();
6683 }
6684
6685 /*********************************************************************/
6686
6687 void getMethodInfoILMethodHeaderHelper(
6688     COR_ILMETHOD_DECODER* header,
6689     CORINFO_METHOD_INFO* methInfo
6690     )
6691 {
6692     LIMITED_METHOD_CONTRACT;
6693     
6694     methInfo->ILCode          = const_cast<BYTE*>(header->Code);
6695     methInfo->ILCodeSize      = header->GetCodeSize();
6696     methInfo->maxStack        = static_cast<unsigned short>(header->GetMaxStack());
6697     methInfo->EHcount         = static_cast<unsigned short>(header->EHCount());
6698
6699     methInfo->options         =
6700         (CorInfoOptions)((header->GetFlags() & CorILMethod_InitLocals) ? CORINFO_OPT_INIT_LOCALS : 0) ;
6701 }
6702
6703 mdToken FindGenericMethodArgTypeSpec(IMDInternalImport* pInternalImport)
6704 {
6705     STANDARD_VM_CONTRACT;
6706
6707     HENUMInternalHolder hEnumTypeSpecs(pInternalImport);
6708     mdToken token;
6709
6710     static const BYTE signature[] = { ELEMENT_TYPE_MVAR, 0 };
6711
6712     hEnumTypeSpecs.EnumAllInit(mdtTypeSpec);
6713     while (hEnumTypeSpecs.EnumNext(&token))
6714     {
6715         PCCOR_SIGNATURE pSig;
6716         ULONG cbSig;
6717         IfFailThrow(pInternalImport->GetTypeSpecFromToken(token, &pSig, &cbSig));
6718         if (cbSig == sizeof(signature) && memcmp(pSig, signature, cbSig) == 0)
6719             return token;
6720     }
6721
6722     COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6723 }
6724
6725 /*********************************************************************
6726
6727 IL is the most efficient and portable way to implement certain low level methods 
6728 in mscorlib.dll. Unfortunately, there is no good way to link IL into mscorlib.dll today.
6729 Until we find a good way to link IL into mscorlib.dll, we will provide the IL implementation here.
6730
6731 - All IL intrinsincs are members of System.Runtime.CompilerServices.JitHelpers class
6732 - All IL intrinsincs should be kept very simple. Implement the minimal reusable version of 
6733 unsafe construct and depend on inlining to do the rest.
6734 - The C# implementation of the IL intrinsic should be good enough for functionalily. Everything should work 
6735 correctly (but slower) if the IL intrinsics are removed.
6736
6737 *********************************************************************/
6738
6739 bool getILIntrinsicImplementation(MethodDesc * ftn,
6740                                   CORINFO_METHOD_INFO * methInfo)
6741 {
6742     STANDARD_VM_CONTRACT;
6743
6744     // Precondition: ftn is a method in mscorlib 
6745     _ASSERTE(ftn->GetModule()->IsSystem());
6746
6747     mdMethodDef tk = ftn->GetMemberDef();
6748
6749     // Compare tokens to cover all generic instantiations
6750     // The body of the first method is simply ret Arg0. The second one first casts the arg to I4.
6751
6752     if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_CAST)->GetMemberDef())
6753     {
6754         // Return the argument that was passed in.
6755         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
6756         methInfo->ILCode = const_cast<BYTE*>(ilcode);
6757         methInfo->ILCodeSize = sizeof(ilcode);
6758         methInfo->maxStack = 1;
6759         methInfo->EHcount = 0;
6760         methInfo->options = (CorInfoOptions)0;
6761         return true;
6762     }
6763     else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_CAST_TO_STACKPTR)->GetMemberDef())
6764     {
6765         // Return the argument that was passed in converted to IntPtr
6766         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I, CEE_RET };
6767         methInfo->ILCode = const_cast<BYTE*>(ilcode);
6768         methInfo->ILCodeSize = sizeof(ilcode);
6769         methInfo->maxStack = 1;
6770         methInfo->EHcount = 0;
6771         methInfo->options = (CorInfoOptions)0;
6772         return true;
6773     }
6774     else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST)->GetMemberDef()) 
6775     {
6776         // Normally we would follow the above pattern and unconditionally replace the IL,
6777         // relying on generic type constraints to guarantee that it will only ever be instantiated
6778         // on the type/size of argument we expect.
6779         //
6780         // However C#/CLR does not support restricting a generic type to be an Enum, so the best
6781         // we can do is constrain it to be a value type.  This is fine for run time, since we only
6782         // ever create instantiations on 4 byte or less Enums. But during NGen we may compile instantiations
6783         // on other value types (to be specific, every value type instatiation of EqualityComparer
6784         // because of its TypeDependencyAttribute; here again we would like to restrict this to
6785         // 4 byte or less Enums but cannot).
6786         //
6787         // This IL is invalid for those instantiations, and replacing it would lead to all sorts of
6788         // errors at NGen time.  So we only replace it for instantiations where it would be valid, 
6789         // leaving the others, which we should never execute, with the C# implementation of throwing.
6790
6791         _ASSERTE(ftn->HasMethodInstantiation());
6792         Instantiation inst = ftn->GetMethodInstantiation();
6793
6794         _ASSERTE(inst.GetNumArgs() == 1);
6795         CorElementType et = inst[0].GetVerifierCorElementType();
6796         if (et == ELEMENT_TYPE_I4 ||
6797             et == ELEMENT_TYPE_U4 ||
6798             et == ELEMENT_TYPE_I2 ||
6799             et == ELEMENT_TYPE_U2 ||
6800             et == ELEMENT_TYPE_I1 ||
6801             et == ELEMENT_TYPE_U1)
6802         {
6803             // Cast to I4 and return the argument that was passed in.
6804             static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I4, CEE_RET };
6805             methInfo->ILCode = const_cast<BYTE*>(ilcode);
6806             methInfo->ILCodeSize = sizeof(ilcode);
6807             methInfo->maxStack = 1;
6808             methInfo->EHcount = 0;
6809             methInfo->options = (CorInfoOptions)0;
6810             return true;
6811         }
6812     }
6813     else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG)->GetMemberDef()) 
6814     {
6815         // The the comment above on why this is is not an unconditional replacement.  This case handles
6816         // Enums backed by 8 byte values.
6817
6818         _ASSERTE(ftn->HasMethodInstantiation());
6819         Instantiation inst = ftn->GetMethodInstantiation();
6820
6821         _ASSERTE(inst.GetNumArgs() == 1);
6822         CorElementType et = inst[0].GetVerifierCorElementType();
6823         if (et == ELEMENT_TYPE_I8 ||
6824             et == ELEMENT_TYPE_U8)
6825         {
6826             // Cast to I8 and return the argument that was passed in.
6827             static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I8, CEE_RET };
6828             methInfo->ILCode = const_cast<BYTE*>(ilcode);
6829             methInfo->ILCodeSize = sizeof(ilcode);
6830             methInfo->maxStack = 1;
6831             methInfo->EHcount = 0;
6832             methInfo->options = (CorInfoOptions)0;
6833             return true;
6834         }
6835     }
6836     else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__GET_RAW_SZ_ARRAY_DATA)->GetMemberDef())
6837     {
6838         mdToken tokArrayPinningHelper = MscorlibBinder::GetField(FIELD__ARRAY_PINNING_HELPER__M_ARRAY_DATA)->GetMemberDef();
6839
6840         static BYTE ilcode[] = { CEE_LDARG_0,
6841                                  CEE_LDFLDA,0,0,0,0,
6842                                  CEE_RET };
6843
6844         ilcode[2] = (BYTE)(tokArrayPinningHelper);
6845         ilcode[3] = (BYTE)(tokArrayPinningHelper >> 8);
6846         ilcode[4] = (BYTE)(tokArrayPinningHelper >> 16);
6847         ilcode[5] = (BYTE)(tokArrayPinningHelper >> 24);
6848
6849         methInfo->ILCode = const_cast<BYTE*>(ilcode);
6850         methInfo->ILCodeSize = sizeof(ilcode);
6851         methInfo->maxStack = 1;
6852         methInfo->EHcount = 0;
6853         methInfo->options = (CorInfoOptions)0;
6854         return true;
6855     }
6856
6857     return false;
6858 }
6859
6860 bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
6861                                            CORINFO_METHOD_INFO * methInfo)
6862 {
6863     STANDARD_VM_CONTRACT;
6864
6865     // Precondition: ftn is a method in mscorlib 
6866     _ASSERTE(ftn->GetModule()->IsSystem());
6867
6868     mdMethodDef tk = ftn->GetMemberDef();
6869
6870     if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_POINTER)->GetMemberDef())
6871     {
6872         // Return the argument that was passed in.
6873         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_U, CEE_RET };
6874         methInfo->ILCode = const_cast<BYTE*>(ilcode);
6875         methInfo->ILCodeSize = sizeof(ilcode);
6876         methInfo->maxStack = 1;
6877         methInfo->EHcount = 0;
6878         methInfo->options = (CorInfoOptions)0;
6879         return true;
6880     }
6881     if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__SIZEOF)->GetMemberDef())
6882     {
6883         _ASSERTE(ftn->HasMethodInstantiation());
6884         Instantiation inst = ftn->GetMethodInstantiation();
6885
6886         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
6887         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6888
6889         static BYTE ilcode[] = { CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0, CEE_RET };
6890
6891         ilcode[2] = (BYTE)(tokGenericArg);
6892         ilcode[3] = (BYTE)(tokGenericArg >> 8);
6893         ilcode[4] = (BYTE)(tokGenericArg >> 16);
6894         ilcode[5] = (BYTE)(tokGenericArg >> 24);
6895
6896         methInfo->ILCode = const_cast<BYTE*>(ilcode);
6897         methInfo->ILCodeSize = sizeof(ilcode);
6898         methInfo->maxStack = 1;
6899         methInfo->EHcount = 0;
6900         methInfo->options = (CorInfoOptions)0;
6901         return true;
6902     }
6903     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef() ||
6904              tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__OBJECT_AS)->GetMemberDef())
6905     {
6906         // Return the argument that was passed in.
6907         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
6908         methInfo->ILCode = const_cast<BYTE*>(ilcode);
6909         methInfo->ILCodeSize = sizeof(ilcode);
6910         methInfo->maxStack = 1;
6911         methInfo->EHcount = 0;
6912         methInfo->options = (CorInfoOptions)0;
6913         return true;
6914     }
6915     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD)->GetMemberDef() ||
6916              tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_ADD)->GetMemberDef())
6917     {
6918         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6919
6920         static BYTE ilcode[] = { CEE_LDARG_1,
6921             CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0,
6922             CEE_CONV_I,
6923             CEE_MUL,
6924             CEE_LDARG_0,
6925             CEE_ADD,
6926             CEE_RET };
6927
6928         ilcode[3] = (BYTE)(tokGenericArg);
6929         ilcode[4] = (BYTE)(tokGenericArg >> 8);
6930         ilcode[5] = (BYTE)(tokGenericArg >> 16);
6931         ilcode[6] = (BYTE)(tokGenericArg >> 24);
6932
6933         methInfo->ILCode = const_cast<BYTE*>(ilcode);
6934         methInfo->ILCodeSize = sizeof(ilcode);
6935         methInfo->maxStack = 2;
6936         methInfo->EHcount = 0;
6937         methInfo->options = (CorInfoOptions)0;
6938         return true;
6939     }
6940     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD_BYTE_OFFSET)->GetMemberDef())
6941     {
6942         static BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_ADD, CEE_RET };
6943
6944         methInfo->ILCode = const_cast<BYTE*>(ilcode);
6945         methInfo->ILCodeSize = sizeof(ilcode);
6946         methInfo->maxStack = 2;
6947         methInfo->EHcount = 0;
6948         methInfo->options = (CorInfoOptions)0;
6949         return true;
6950     }
6951     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ARE_SAME)->GetMemberDef())
6952     {
6953         // Compare the two arguments
6954         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CEQ & 0xFF), CEE_RET };
6955         methInfo->ILCode = const_cast<BYTE*>(ilcode);
6956         methInfo->ILCodeSize = sizeof(ilcode);
6957         methInfo->maxStack = 2;
6958         methInfo->EHcount = 0;
6959         methInfo->options = (CorInfoOptions)0;
6960         return true;
6961     }
6962     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_INIT_BLOCK_UNALIGNED)->GetMemberDef())
6963     {
6964         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 };
6965         methInfo->ILCode = const_cast<BYTE*>(ilcode);
6966         methInfo->ILCodeSize = sizeof(ilcode);
6967         methInfo->maxStack = 3;
6968         methInfo->EHcount = 0;
6969         methInfo->options = (CorInfoOptions)0;
6970         return true;
6971     }
6972     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_READ_UNALIGNED)->GetMemberDef() ||
6973              tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_READ_UNALIGNED)->GetMemberDef())
6974     {
6975         _ASSERTE(ftn->HasMethodInstantiation());
6976         Instantiation inst = ftn->GetMethodInstantiation();
6977         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
6978         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6979
6980         static const BYTE ilcode[]
6981         { 
6982             CEE_LDARG_0,
6983             CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
6984             CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6985             CEE_RET
6986         };
6987
6988         methInfo->ILCode = const_cast<BYTE*>(ilcode);
6989         methInfo->ILCodeSize = sizeof(ilcode);
6990         methInfo->maxStack = 2;
6991         methInfo->EHcount = 0;
6992         methInfo->options = (CorInfoOptions)0;
6993         return true;
6994     }
6995     else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_WRITE_UNALIGNED)->GetMemberDef() ||
6996              tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_WRITE_UNALIGNED)->GetMemberDef())
6997     {
6998         _ASSERTE(ftn->HasMethodInstantiation());
6999         Instantiation inst = ftn->GetMethodInstantiation();
7000         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7001         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7002
7003         static const BYTE ilcode[]
7004         {
7005             CEE_LDARG_0,
7006             CEE_LDARG_1,
7007             CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
7008             CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7009             CEE_RET
7010         };
7011
7012         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7013         methInfo->ILCodeSize = sizeof(ilcode);
7014         methInfo->maxStack = 2;
7015         methInfo->EHcount = 0;
7016         methInfo->options = (CorInfoOptions)0;
7017         return true;
7018     }
7019
7020     return false;
7021 }
7022
7023 bool getILIntrinsicImplementationForVolatile(MethodDesc * ftn,
7024                                              CORINFO_METHOD_INFO * methInfo)
7025 {
7026     STANDARD_VM_CONTRACT;
7027
7028     //
7029     // This replaces the implementations of Volatile.* in mscorlib with more efficient ones.
7030     // We do this because we cannot otherwise express these in C#.  What we *want* to do is
7031     // to treat the byref args to these methods as "volatile."  In pseudo-C#, this would look
7032     // like:
7033     //
7034     //   int Read(ref volatile int location)
7035     //   {
7036     //       return location;
7037     //   }
7038     //
7039     // However, C# does not yet provide a way to declare a byref as "volatile."  So instead,
7040     // we substitute raw IL bodies for these methods that use the correct volatile instructions.
7041     //
7042
7043     // Precondition: ftn is a method in mscorlib in the System.Threading.Volatile class
7044     _ASSERTE(ftn->GetModule()->IsSystem());
7045     _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__VOLATILE));
7046     _ASSERTE(strcmp(ftn->GetMethodTable()->GetClass()->GetDebugClassName(), "System.Threading.Volatile") == 0);
7047
7048     const size_t VolatileMethodBodySize = 6;
7049
7050     struct VolatileMethodImpl
7051     {
7052         BinderMethodID methodId;
7053         BYTE body[VolatileMethodBodySize];
7054     };
7055
7056 #define VOLATILE_IMPL(type, loadinst, storeinst) \
7057     { \
7058         METHOD__VOLATILE__READ_##type, \
7059         { \
7060             CEE_LDARG_0, \
7061             CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7062             loadinst, \
7063             CEE_NOP, /*pad to VolatileMethodBodySize bytes*/ \
7064             CEE_RET \
7065         } \
7066     }, \
7067     { \
7068         METHOD__VOLATILE__WRITE_##type, \
7069         { \
7070             CEE_LDARG_0, \
7071             CEE_LDARG_1, \
7072             CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7073             storeinst, \
7074             CEE_RET \
7075         } \
7076     },
7077
7078     static const VolatileMethodImpl volatileImpls[] =
7079     {
7080         VOLATILE_IMPL(T,       CEE_LDIND_REF, CEE_STIND_REF)
7081         VOLATILE_IMPL(Bool,    CEE_LDIND_I1,  CEE_STIND_I1)
7082         VOLATILE_IMPL(Int,     CEE_LDIND_I4,  CEE_STIND_I4)
7083         VOLATILE_IMPL(IntPtr,  CEE_LDIND_I,   CEE_STIND_I)
7084         VOLATILE_IMPL(UInt,    CEE_LDIND_U4,  CEE_STIND_I4)
7085         VOLATILE_IMPL(UIntPtr, CEE_LDIND_I,   CEE_STIND_I)
7086         VOLATILE_IMPL(SByt,    CEE_LDIND_I1,  CEE_STIND_I1)
7087         VOLATILE_IMPL(Byte,    CEE_LDIND_U1,  CEE_STIND_I1)
7088         VOLATILE_IMPL(Shrt,    CEE_LDIND_I2,  CEE_STIND_I2)
7089         VOLATILE_IMPL(UShrt,   CEE_LDIND_U2,  CEE_STIND_I2)
7090         VOLATILE_IMPL(Flt,     CEE_LDIND_R4,  CEE_STIND_R4)
7091
7092         //
7093         // Ordinary volatile loads and stores only guarantee atomicity for pointer-sized (or smaller) data.
7094         // So, on 32-bit platforms we must use Interlocked operations instead for the 64-bit types.
7095         // The implementation in mscorlib already does this, so we will only substitute a new
7096         // IL body if we're running on a 64-bit platform.
7097         //
7098         IN_WIN64(VOLATILE_IMPL(Long,  CEE_LDIND_I8, CEE_STIND_I8))
7099         IN_WIN64(VOLATILE_IMPL(ULong, CEE_LDIND_I8, CEE_STIND_I8))
7100         IN_WIN64(VOLATILE_IMPL(Dbl,   CEE_LDIND_R8, CEE_STIND_R8))
7101     };
7102
7103     mdMethodDef md = ftn->GetMemberDef();
7104     for (unsigned i = 0; i < NumItems(volatileImpls); i++)
7105     {
7106         if (md == MscorlibBinder::GetMethod(volatileImpls[i].methodId)->GetMemberDef())
7107         {
7108             methInfo->ILCode = const_cast<BYTE*>(volatileImpls[i].body);
7109             methInfo->ILCodeSize = VolatileMethodBodySize;
7110             methInfo->maxStack = 2;
7111             methInfo->EHcount = 0;
7112             methInfo->options = (CorInfoOptions)0;
7113             return true;
7114         }
7115     }
7116
7117     return false;
7118 }
7119
7120 bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn,
7121                                                 CORINFO_METHOD_INFO * methInfo)
7122 {
7123     STANDARD_VM_CONTRACT;
7124
7125     // Precondition: ftn is a method in mscorlib in the System.Threading.Interlocked class
7126     _ASSERTE(ftn->GetModule()->IsSystem());
7127     _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__INTERLOCKED));
7128
7129     // We are only interested if ftn's token and CompareExchange<T> token match
7130     if (ftn->GetMemberDef() != MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_T)->GetMemberDef())
7131         return false;       
7132
7133     // Get MethodDesc for System.Threading.Interlocked.CompareExchangeFast()
7134     MethodDesc* cmpxchgFast = MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_OBJECT);
7135
7136     // The MethodDesc lookup must not fail, and it should have the name "CompareExchangeFast"
7137     _ASSERTE(cmpxchgFast != NULL);
7138     _ASSERTE(strcmp(cmpxchgFast->GetName(), "CompareExchange") == 0);
7139
7140     // Setup up the body of the method
7141     static BYTE il[] = {
7142                           CEE_LDARG_0,
7143                           CEE_LDARG_1,
7144                           CEE_LDARG_2,
7145                           CEE_CALL,0,0,0,0, 
7146                           CEE_RET
7147                         };
7148
7149     // Get the token for System.Threading.Interlocked.CompareExchangeFast(), and patch [target]
7150     mdMethodDef cmpxchgFastToken = cmpxchgFast->GetMemberDef();
7151     il[4] = (BYTE)((int)cmpxchgFastToken >> 0);
7152     il[5] = (BYTE)((int)cmpxchgFastToken >> 8);
7153     il[6] = (BYTE)((int)cmpxchgFastToken >> 16);
7154     il[7] = (BYTE)((int)cmpxchgFastToken >> 24);
7155
7156     // Initialize methInfo
7157     methInfo->ILCode = const_cast<BYTE*>(il);
7158     methInfo->ILCodeSize = sizeof(il);
7159     methInfo->maxStack = 3;
7160     methInfo->EHcount = 0;
7161     methInfo->options = (CorInfoOptions)0;
7162
7163     return true;
7164 }
7165
7166 bool getILIntrinsicImplementationForRuntimeHelpers(MethodDesc * ftn,
7167     CORINFO_METHOD_INFO * methInfo)
7168 {
7169     STANDARD_VM_CONTRACT;
7170
7171     // Precondition: ftn is a method in mscorlib 
7172     _ASSERTE(ftn->GetModule()->IsSystem());
7173
7174     mdMethodDef tk = ftn->GetMemberDef();
7175
7176     if (tk == MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_REFERENCE_OR_CONTAINS_REFERENCES)->GetMemberDef())
7177     {
7178         _ASSERTE(ftn->HasMethodInstantiation());
7179         Instantiation inst = ftn->GetMethodInstantiation();
7180
7181         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7182         TypeHandle typeHandle = inst[0];
7183         MethodTable * methodTable = typeHandle.GetMethodTable();
7184
7185         static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
7186         static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };
7187
7188         if (!methodTable->IsValueType() || methodTable->ContainsPointers())
7189         {
7190             methInfo->ILCode = const_cast<BYTE*>(returnTrue);
7191         }
7192         else
7193         {
7194             methInfo->ILCode = const_cast<BYTE*>(returnFalse);
7195         }
7196
7197         methInfo->ILCodeSize = sizeof(returnTrue);
7198         methInfo->maxStack = 1;
7199         methInfo->EHcount = 0;
7200         methInfo->options = (CorInfoOptions)0;
7201         return true;
7202     }
7203
7204     return false;
7205 }
7206
7207 //---------------------------------------------------------------------------------------
7208 // 
7209 //static
7210 void 
7211 getMethodInfoHelper(
7212     MethodDesc *           ftn, 
7213     CORINFO_METHOD_HANDLE  ftnHnd, 
7214     COR_ILMETHOD_DECODER * header, 
7215     CORINFO_METHOD_INFO *  methInfo)
7216 {
7217     STANDARD_VM_CONTRACT;
7218
7219     _ASSERTE(ftn == GetMethod(ftnHnd));
7220
7221     methInfo->ftn             = ftnHnd;
7222     methInfo->scope           = GetScopeHandle(ftn);
7223     methInfo->regionKind      = CORINFO_REGION_JIT;
7224     //
7225     // For Jitted code the regionKind is JIT;
7226     // For Ngen-ed code the zapper will set this to HOT or COLD, if we  
7227     // are using IBC data to partition methods into Hot/Cold regions
7228
7229     /* Grab information from the IL header */
7230
7231     PCCOR_SIGNATURE pLocalSig = NULL;
7232     DWORD           cbLocalSig = 0;
7233
7234     if (NULL != header)
7235     {
7236         bool fILIntrinsic = false;
7237
7238         MethodTable * pMT  = ftn->GetMethodTable();
7239
7240         if (pMT->GetModule()->IsSystem())
7241         {
7242             if (MscorlibBinder::IsClass(pMT, CLASS__JIT_HELPERS))
7243             {
7244                 fILIntrinsic = getILIntrinsicImplementation(ftn, methInfo);
7245             }
7246             else if (MscorlibBinder::IsClass(pMT, CLASS__UNSAFE))
7247             {
7248                 fILIntrinsic = getILIntrinsicImplementationForUnsafe(ftn, methInfo);
7249             }
7250             else if (MscorlibBinder::IsClass(pMT, CLASS__INTERLOCKED))
7251             {
7252                 fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo);
7253             }
7254             else if (MscorlibBinder::IsClass(pMT, CLASS__VOLATILE))
7255             {
7256                 fILIntrinsic = getILIntrinsicImplementationForVolatile(ftn, methInfo);
7257             }
7258             else if (MscorlibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS))
7259             {
7260                 fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo);
7261             }
7262         }
7263
7264         if (!fILIntrinsic)
7265         {
7266             getMethodInfoILMethodHeaderHelper(header, methInfo);
7267
7268             // Workaround for https://github.com/dotnet/coreclr/issues/1279
7269             // Set init locals bit to zero for system module unless profiler may have overrided it. Remove once we have
7270             // better solution for this issue.
7271             if (pMT->GetModule()->IsSystem() && !(CORProfilerDisableAllNGenImages() || CORProfilerUseProfileImages()))
7272                 methInfo->options = (CorInfoOptions)0;
7273
7274             pLocalSig = header->LocalVarSig;
7275             cbLocalSig = header->cbLocalVarSig;
7276         }
7277     }
7278     else
7279     {
7280         _ASSERTE(ftn->IsDynamicMethod());
7281
7282         DynamicResolver * pResolver = ftn->AsDynamicMethodDesc()->GetResolver();        
7283         unsigned int EHCount;
7284         methInfo->ILCode = pResolver->GetCodeInfo(&methInfo->ILCodeSize,
7285                                                   &methInfo->maxStack,
7286                                                   &methInfo->options,
7287                                                   &EHCount);
7288         methInfo->EHcount = (unsigned short)EHCount;
7289         SigPointer localSig = pResolver->GetLocalSig();
7290         localSig.GetSignature(&pLocalSig, &cbLocalSig);
7291     }
7292
7293     methInfo->options = (CorInfoOptions)(((UINT32)methInfo->options) | 
7294                             ((ftn->AcquiresInstMethodTableFromThis() ? CORINFO_GENERICS_CTXT_FROM_THIS : 0) |
7295                              (ftn->RequiresInstMethodTableArg() ? CORINFO_GENERICS_CTXT_FROM_METHODTABLE : 0) |
7296                              (ftn->RequiresInstMethodDescArg() ? CORINFO_GENERICS_CTXT_FROM_METHODDESC : 0)));
7297
7298     // EEJitManager::ResolveEHClause and CrawlFrame::GetExactGenericInstantiations
7299     // need to be able to get to CORINFO_GENERICS_CTXT_MASK if there are any
7300     // catch clauses like "try {} catch(MyException<T> e) {}".
7301     // Such constructs are rare, and having to extend the lifetime of variable
7302     // for such cases is reasonable
7303
7304     if (methInfo->options & CORINFO_GENERICS_CTXT_MASK)
7305     {
7306 #if defined(PROFILING_SUPPORTED)
7307         BOOL fProfilerRequiresGenericsContextForEnterLeave = FALSE;
7308         {
7309             BEGIN_PIN_PROFILER(CORProfilerPresent());
7310             if (g_profControlBlock.pProfInterface->RequiresGenericsContextForEnterLeave())
7311             {
7312                 fProfilerRequiresGenericsContextForEnterLeave = TRUE;
7313             }
7314             END_PIN_PROFILER();
7315         }
7316         if (fProfilerRequiresGenericsContextForEnterLeave)
7317         {
7318             methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7319         }
7320         else
7321 #endif // defined(PROFILING_SUPPORTED)
7322         {
7323             // Check all the exception clauses
7324
7325             if (ftn->IsDynamicMethod())
7326             {
7327                 // @TODO: how do we detect the need to mark this flag?
7328             }
7329             else
7330             {
7331                 COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
7332
7333                 for (unsigned i = 0; i < methInfo->EHcount; i++)
7334                 {
7335                     const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo =
7336                             (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)header->EH->EHClause(i, &ehClause);
7337
7338                     // Is it a typed catch clause?
7339                     if (ehInfo->GetFlags() != COR_ILEXCEPTION_CLAUSE_NONE)
7340                         continue;
7341
7342                     // Check if we catch "C<T>" ?
7343
7344                     DWORD catchTypeToken = ehInfo->GetClassToken();
7345                     if (TypeFromToken(catchTypeToken) != mdtTypeSpec)
7346                         continue;
7347
7348                     PCCOR_SIGNATURE pSig;
7349                     ULONG cSig;
7350                     IfFailThrow(ftn->GetMDImport()->GetTypeSpecFromToken(catchTypeToken, &pSig, &cSig));
7351                     
7352                     SigPointer psig(pSig, cSig);
7353
7354                     SigTypeContext sigTypeContext(ftn);
7355                     if (psig.IsPolyType(&sigTypeContext) & hasSharableVarsMask)
7356                     {
7357                         methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7358                         break;
7359                     }
7360                 }
7361             }
7362         }
7363     }
7364
7365     PCCOR_SIGNATURE pSig = NULL;
7366     DWORD           cbSig = 0;
7367     ftn->GetSig(&pSig, &cbSig);
7368     
7369     /* Fetch the method signature */
7370     // Type parameters in the signature should be instantiated according to the
7371     // class/method/array instantiation of ftnHnd
7372     CEEInfo::ConvToJitSig(
7373         pSig, 
7374         cbSig, 
7375         GetScopeHandle(ftn), 
7376         mdTokenNil, 
7377         &methInfo->args, 
7378         ftn, 
7379         false);
7380
7381     // Shared generic or static per-inst methods and shared methods on generic structs
7382     // take an extra argument representing their instantiation
7383     if (ftn->RequiresInstArg())
7384         methInfo->args.callConv = (CorInfoCallConv)(methInfo->args.callConv | CORINFO_CALLCONV_PARAMTYPE);
7385
7386     _ASSERTE((IsMdStatic(ftn->GetAttrs()) == 0) == ((methInfo->args.callConv & CORINFO_CALLCONV_HASTHIS) != 0));
7387
7388     /* And its local variables */
7389     // Type parameters in the signature should be instantiated according to the
7390     // class/method/array instantiation of ftnHnd
7391     CEEInfo::ConvToJitSig(
7392         pLocalSig, 
7393         cbLocalSig, 
7394         GetScopeHandle(ftn), 
7395         mdTokenNil, 
7396         &methInfo->locals, 
7397         ftn, 
7398         true);
7399 } // getMethodInfoHelper
7400
7401 //---------------------------------------------------------------------------------------
7402 // 
7403 bool 
7404 CEEInfo::getMethodInfo(
7405     CORINFO_METHOD_HANDLE ftnHnd, 
7406     CORINFO_METHOD_INFO * methInfo)
7407 {
7408     CONTRACTL {
7409         SO_TOLERANT;
7410         THROWS;
7411         GC_TRIGGERS;
7412         MODE_PREEMPTIVE;
7413     } CONTRACTL_END;
7414
7415     bool result = false;
7416
7417     JIT_TO_EE_TRANSITION();
7418
7419     MethodDesc * ftn = GetMethod(ftnHnd);
7420
7421     if (!ftn->IsDynamicMethod() && (!ftn->IsIL() || !ftn->GetRVA() || ftn->IsWrapperStub()))
7422     {
7423     /* Return false if not IL or has no code */
7424         result = false;
7425     }
7426     else
7427     {
7428         /* Get the IL header */
7429
7430         if (ftn->IsDynamicMethod())
7431         {
7432             getMethodInfoHelper(ftn, ftnHnd, NULL, methInfo);
7433         }
7434         else
7435         {
7436             COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
7437
7438             getMethodInfoHelper(ftn, ftnHnd, &header, methInfo);
7439         }
7440
7441         LOG((LF_JIT, LL_INFO100000, "Getting method info (possible inline) %s::%s%s\n",
7442             ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
7443
7444         result = true;
7445     }
7446
7447     EE_TO_JIT_TRANSITION();
7448
7449     return result;
7450 }
7451
7452 #ifdef _DEBUG
7453
7454 /************************************************************************
7455     Return true when ftn contains a local of type CLASS__STACKCRAWMARK
7456 */
7457
7458 bool containsStackCrawlMarkLocal(MethodDesc* ftn)
7459 {
7460     STANDARD_VM_CONTRACT;
7461     
7462     COR_ILMETHOD* ilHeader = ftn->GetILHeader();
7463     _ASSERTE(ilHeader);
7464
7465     COR_ILMETHOD_DECODER header(ilHeader, ftn->GetMDImport(), NULL);
7466
7467     if (header.LocalVarSig == NULL)
7468         return NULL;
7469
7470     SigPointer ptr(header.LocalVarSig, header.cbLocalVarSig);
7471
7472     IfFailThrow(ptr.GetData(NULL)); // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
7473
7474     ULONG numLocals;
7475     IfFailThrow(ptr.GetData(&numLocals));
7476
7477     for(ULONG i = 0; i < numLocals; i++)
7478     {
7479         CorElementType eType;
7480         IfFailThrow(ptr.PeekElemType(&eType));
7481         if (eType != ELEMENT_TYPE_VALUETYPE)
7482         {
7483             IfFailThrow(ptr.SkipExactlyOne());
7484             continue;
7485         }
7486
7487         IfFailThrow(ptr.GetElemType(NULL));
7488
7489         mdToken token;
7490         IfFailThrow(ptr.GetToken(&token));
7491
7492         // We are inside mscorlib - simple token match is sufficient
7493         if (token == MscorlibBinder::GetClass(CLASS__STACKCRAWMARK)->GetCl())
7494             return TRUE;
7495     }
7496
7497     return FALSE;
7498 }
7499
7500 #endif
7501
7502 /*************************************************************
7503  * Check if the caller and calle are in the same assembly
7504  * i.e. do not inline across assemblies
7505  *************************************************************/
7506
7507 CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller,
7508                                   CORINFO_METHOD_HANDLE hCallee,
7509                                   DWORD*                pRestrictions)
7510 {
7511     CONTRACTL {
7512         SO_TOLERANT;
7513         THROWS;
7514         GC_TRIGGERS;
7515         MODE_PREEMPTIVE;
7516     } CONTRACTL_END;
7517
7518     CorInfoInline result = INLINE_PASS;  // By default we pass.  
7519                                          // Do not set pass in the rest of the method.
7520     DWORD         dwRestrictions = 0;    // By default, no restrictions
7521     const char *  szFailReason = NULL;   // for reportInlineDecision
7522
7523     JIT_TO_EE_TRANSITION();
7524
7525     // This does not work in the multi-threaded case
7526 #if 0
7527     // Caller should check this condition first
7528     _ASSERTE(!(CORINFO_FLG_DONT_INLINE & getMethodAttribsInternal(hCallee)));
7529 #endif
7530
7531     MethodDesc* pCaller = GetMethod(hCaller);
7532     MethodDesc* pCallee = GetMethod(hCallee);
7533
7534     if (pCallee->IsNoMetadata())
7535     {
7536         result = INLINE_FAIL;
7537         szFailReason = "Inlinee is NoMetadata";
7538         goto exit;
7539     }
7540
7541 #ifdef DEBUGGING_SUPPORTED
7542
7543     // If the callee wants debuggable code, don't allow it to be inlined
7544
7545     {
7546         // Combining the next two lines, and eliminating jitDebuggerFlags, leads to bad codegen in x86 Release builds using Visual C++ 19.00.24215.1.
7547         CORJIT_FLAGS jitDebuggerFlags = GetDebuggerCompileFlags(pCallee->GetModule(), CORJIT_FLAGS());
7548         if (jitDebuggerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE))
7549         {
7550             result = INLINE_NEVER;
7551             szFailReason = "Inlinee is debuggable";
7552             goto exit;
7553         }
7554     }
7555 #endif
7556
7557     // The orginal caller is the current method
7558     MethodDesc *  pOrigCaller;
7559     pOrigCaller = m_pMethodBeingCompiled;
7560     Module *      pOrigCallerModule;
7561     pOrigCallerModule = pOrigCaller->GetLoaderModule();
7562
7563     if (pCallee->IsNotInline()) 
7564     {
7565         result = INLINE_NEVER;
7566         szFailReason = "Inlinee is marked as no inline";
7567         goto exit;
7568     }
7569
7570     // Also check to see if the method requires a security object.  This means they call demand and
7571     // shouldn't be inlined.
7572     if (IsMdRequireSecObject(pCallee->GetAttrs())) 
7573     {
7574         result = INLINE_NEVER;
7575         szFailReason = "Inlinee requires a security object (or contains StackCrawlMark)";
7576         goto exit;
7577     }
7578
7579     // If the method is MethodImpl'd by another method within the same type, then we have
7580     // an issue that the importer will import the wrong body. In this case, we'll just
7581     // disallow inlining because getFunctionEntryPoint will do the right thing.
7582     {
7583         MethodDesc  *pMDDecl = pCallee;
7584         MethodTable *pMT     = pMDDecl->GetMethodTable();
7585         MethodDesc  *pMDImpl = pMT->MapMethodDeclToMethodImpl(pMDDecl);
7586
7587         if (pMDDecl != pMDImpl)
7588         {
7589             result = INLINE_NEVER;
7590             szFailReason = "Inlinee is MethodImpl'd by another method within the same type";
7591             goto exit;
7592         }
7593     }
7594
7595     //
7596     // Perform the Cross-Assembly inlining checks
7597     // 
7598     {
7599         Module *    pCalleeModule   = pCallee->GetModule();
7600
7601 #ifdef FEATURE_PREJIT
7602         Assembly *  pCalleeAssembly = pCalleeModule->GetAssembly();
7603
7604 #ifdef _DEBUG
7605         //
7606         // Make sure that all methods with StackCrawlMark are marked as IsMdRequireSecObject
7607         //
7608         if (pCalleeAssembly->IsSystem())
7609         {
7610             _ASSERTE(!containsStackCrawlMarkLocal(pCallee));
7611         }
7612 #endif
7613
7614         // To allow for servicing of Ngen images we want to disable most 
7615         // Cross-Assembly inlining except for the cases that we explicitly allow.
7616         // 
7617         if (IsCompilingForNGen())
7618         {
7619             // This is an canInline call at Ngen time 
7620             //
7621             //
7622             Assembly *  pOrigCallerAssembly = pOrigCallerModule->GetAssembly();
7623
7624             if (pCalleeAssembly == pOrigCallerAssembly)
7625             {
7626                 // Within the same assembly
7627                 // we can freely inline with no restrictions
7628             }
7629             else
7630             {
7631 #ifdef FEATURE_READYTORUN_COMPILER
7632                 // No inlinining for version resilient code except if in the same version bubble
7633                 // If this condition changes, please make the corresponding change
7634                 // in getCallInfo, too.
7635                 if (IsReadyToRunCompilation() &&
7636                     !isVerifyOnly() &&
7637                     !IsInSameVersionBubble(pCaller, pCallee)
7638                    )
7639                 {
7640                     result = INLINE_NEVER;
7641                     szFailReason = "Cross-module inlining in version resilient code";
7642                     goto exit;
7643                 }
7644 #endif
7645             }
7646         }
7647 #endif  // FEATURE_PREJIT
7648
7649         // TODO: We can probably be smarter here if the caller is jitted, as we will
7650         // know for sure if the inlinee has really no string interning active (currently
7651         // it's only on in the ngen case (besides requiring the attribute)), but this is getting
7652         // too subtle. Will only do if somebody screams about it, as bugs here are going to
7653         // be tough to find
7654         if ((pOrigCallerModule != pCalleeModule) &&  pCalleeModule->IsNoStringInterning())
7655         {
7656             dwRestrictions |= INLINE_NO_CALLEE_LDSTR;
7657         }
7658
7659         // The remoting interception can be skipped only if the call is on same this pointer
7660         if (pCallee->MayBeRemotingIntercepted())
7661         {
7662             dwRestrictions |= INLINE_SAME_THIS;
7663         }
7664     }
7665
7666 #ifdef PROFILING_SUPPORTED
7667     if (CORProfilerPresent())
7668     {
7669         // #rejit
7670         // 
7671         // Currently the rejit path is the only path which sets this.
7672         // If we get more reasons to set this then we may need to change
7673         // the failure reason message or disambiguate them.
7674         if (!m_allowInlining)
7675         {
7676             result = INLINE_FAIL;
7677             szFailReason = "ReJIT request disabled inlining from caller";
7678             goto exit;
7679         }
7680
7681         // If the profiler has set a mask preventing inlining, always return
7682         // false to the jit.
7683         if (CORProfilerDisableInlining())
7684         {
7685             result = INLINE_FAIL;
7686             szFailReason = "Profiler disabled inlining globally";
7687             goto exit;
7688         }
7689
7690         // If the profiler wishes to be notified of JIT events and the result from
7691         // the above tests will cause a function to be inlined, we need to tell the
7692         // profiler that this inlining is going to take place, and give them a
7693         // chance to prevent it.
7694         {
7695             BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo());
7696             if (pCaller->IsILStub() || pCallee->IsILStub())
7697             {
7698                 // do nothing
7699             }
7700             else
7701             {
7702                 BOOL fShouldInline;
7703
7704                 HRESULT hr = g_profControlBlock.pProfInterface->JITInlining(
7705                     (FunctionID)pCaller,
7706                     (FunctionID)pCallee,
7707                     &fShouldInline);
7708
7709                 if (SUCCEEDED(hr) && !fShouldInline)
7710                 {
7711                     result = INLINE_FAIL;
7712                     szFailReason = "Profiler disabled inlining locally";
7713                     goto exit;
7714                 }
7715             }
7716             END_PIN_PROFILER();
7717         }
7718     }
7719 #endif // PROFILING_SUPPORTED
7720
7721 exit: ;
7722
7723     EE_TO_JIT_TRANSITION();
7724
7725     if (result == INLINE_PASS && dwRestrictions)
7726     {
7727         if (pRestrictions)
7728         {
7729             *pRestrictions = dwRestrictions;
7730         }
7731         else
7732         {
7733             // If the jitter didn't want to know about restrictions, it shouldn't be inlining
7734             result = INLINE_FAIL;
7735             szFailReason = "Inlinee has restrictions the JIT doesn't want";
7736         }
7737     }
7738     else
7739     {
7740         if (pRestrictions)
7741         {
7742             // Denied inlining, makes no sense to pass out restrictions,
7743             *pRestrictions = 0;
7744         }
7745     }
7746
7747     if (dontInline(result))
7748     {
7749         // If you hit this assert, it means you added a new way to prevent inlining
7750         // without documenting it for ETW!
7751         _ASSERTE(szFailReason != NULL);
7752         reportInliningDecision(hCaller, hCallee, result, szFailReason);
7753     }
7754
7755     return result;
7756 }
7757
7758 void CEEInfo::reportInliningDecision (CORINFO_METHOD_HANDLE inlinerHnd,
7759                                       CORINFO_METHOD_HANDLE inlineeHnd,
7760                                       CorInfoInline inlineResult,
7761                                       const char * reason)
7762 {
7763     STATIC_CONTRACT_THROWS;
7764     STATIC_CONTRACT_GC_TRIGGERS;
7765     STATIC_CONTRACT_SO_TOLERANT;
7766
7767     JIT_TO_EE_TRANSITION();
7768
7769 #ifdef _DEBUG
7770     if (LoggingOn(LF_JIT, LL_INFO100000))
7771     {
7772         SString currentMethodName;
7773         currentMethodName.AppendUTF8(m_pMethodBeingCompiled->GetModule_NoLogging()->GetFile()->GetSimpleName());
7774         currentMethodName.Append(L'/');
7775         TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled, TypeString::FormatBasic);
7776
7777         SString inlineeMethodName;
7778         if (GetMethod(inlineeHnd))
7779         {
7780             inlineeMethodName.AppendUTF8(GetMethod(inlineeHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
7781             inlineeMethodName.Append(L'/');
7782             TypeString::AppendMethodInternal(inlineeMethodName, GetMethod(inlineeHnd), TypeString::FormatBasic);
7783         }
7784         else
7785         {
7786             inlineeMethodName.AppendASCII( "<null>" );
7787         }
7788
7789         SString inlinerMethodName;
7790         if (GetMethod(inlinerHnd))
7791         {
7792             inlinerMethodName.AppendUTF8(GetMethod(inlinerHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
7793             inlinerMethodName.Append(L'/');
7794             TypeString::AppendMethodInternal(inlinerMethodName, GetMethod(inlinerHnd), TypeString::FormatBasic);
7795         }
7796         else
7797         {
7798             inlinerMethodName.AppendASCII("<null>");
7799         }
7800
7801         if (dontInline(inlineResult))
7802         {
7803             LOG((LF_JIT, LL_INFO100000,
7804                  "While compiling '%S', inline of '%S' into '%S' failed because: '%s'.\n",
7805                  currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
7806                  inlinerMethodName.GetUnicode(), reason));
7807         }
7808         else
7809         {
7810             LOG((LF_JIT, LL_INFO100000, "While compiling '%S', inline of '%S' into '%S' succeeded.\n",
7811                  currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
7812                  inlinerMethodName.GetUnicode()));
7813
7814         }
7815     }
7816 #endif //_DEBUG
7817
7818     //I'm gonna duplicate this code because the format is slightly different.  And LoggingOn is debug only.
7819     if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
7820                                      TRACE_LEVEL_VERBOSE,
7821                                      CLR_JITTRACING_KEYWORD))
7822     {
7823         SString methodBeingCompiledNames[3];
7824         SString inlinerNames[3];
7825         SString inlineeNames[3];
7826         MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
7827 #define GMI(pMD, strArray) \
7828         do { \
7829             if (pMD) { \
7830                 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
7831             } else {  \
7832                 (strArray)[0].Set(W("<null>")); \
7833                 (strArray)[1].Set(W("<null>")); \
7834                 (strArray)[2].Set(W("<null>")); \
7835             } } while (0)
7836
7837         GMI(methodBeingCompiled, methodBeingCompiledNames);
7838         GMI(GetMethod(inlinerHnd), inlinerNames);
7839         GMI(GetMethod(inlineeHnd), inlineeNames);
7840 #undef GMI
7841         if (dontInline(inlineResult))
7842         {
7843             const char * str = (reason ? reason : "");
7844
7845             FireEtwMethodJitInliningFailed(methodBeingCompiledNames[0].GetUnicode(),
7846                                            methodBeingCompiledNames[1].GetUnicode(),
7847                                            methodBeingCompiledNames[2].GetUnicode(),
7848                                            inlinerNames[0].GetUnicode(),
7849                                            inlinerNames[1].GetUnicode(),
7850                                            inlinerNames[2].GetUnicode(),
7851                                            inlineeNames[0].GetUnicode(),
7852                                            inlineeNames[1].GetUnicode(),
7853                                            inlineeNames[2].GetUnicode(),
7854                                            inlineResult == INLINE_NEVER,
7855                                            str,
7856                                            GetClrInstanceId());
7857         }
7858         else
7859         {
7860             FireEtwMethodJitInliningSucceeded(methodBeingCompiledNames[0].GetUnicode(),
7861                                               methodBeingCompiledNames[1].GetUnicode(),
7862                                               methodBeingCompiledNames[2].GetUnicode(),
7863                                               inlinerNames[0].GetUnicode(),
7864                                               inlinerNames[1].GetUnicode(),
7865                                               inlinerNames[2].GetUnicode(),
7866                                               inlineeNames[0].GetUnicode(),
7867                                               inlineeNames[1].GetUnicode(),
7868                                               inlineeNames[2].GetUnicode(),
7869                                               GetClrInstanceId());
7870         }
7871
7872     }
7873
7874     EE_TO_JIT_TRANSITION();
7875 }
7876
7877
7878 /*************************************************************
7879 This loads the (formal) declared constraints on the class and method type parameters, 
7880 and detects (but does not itself reject) circularities among the class type parameters 
7881 and (separately) method type parameters. 
7882
7883 It must be called whenever we verify a typical method, ie any method (generic or
7884 nongeneric) in a typical class. It must be called for non-generic methods too, 
7885 because their bodies may still mention class type parameters which will need to
7886 have their formal constraints loaded in order to perform type compatibility tests.
7887
7888 We have to rule out cycles like "C<U,T> where T:U, U:T" only to avoid looping 
7889 in the verifier (ie the T.CanCast(A) would loop calling U.CanCast(A) then 
7890 T.CanCastTo(A) etc.). Since the JIT only tries to walk the hierarchy from a type
7891 a parameter when verifying, it should be safe to JIT unverified, but trusted, 
7892 instantiations even in the presence of cycle constraints.
7893 @TODO: It should be possible (and easy) to detect cycles much earlier on by
7894 directly inspecting the metadata. All you have to do is check that, for each
7895 of the n type parameters to a class or method there is no path of length n 
7896 obtained by following naked type parameter constraints of the same kind. 
7897 This can be detected by looking directly at metadata, without actually loading
7898 the typehandles for the naked type parameters.
7899  *************************************************************/
7900
7901 void CEEInfo::initConstraintsForVerification(CORINFO_METHOD_HANDLE hMethod,
7902                                              BOOL *pfHasCircularClassConstraints,
7903                                              BOOL *pfHasCircularMethodConstraints)
7904 {
7905     CONTRACTL {
7906         SO_TOLERANT;
7907         THROWS;
7908         GC_TRIGGERS;
7909         MODE_PREEMPTIVE;
7910         PRECONDITION(CheckPointer(pfHasCircularClassConstraints));
7911         PRECONDITION(CheckPointer(pfHasCircularMethodConstraints));
7912     } CONTRACTL_END;
7913
7914     *pfHasCircularClassConstraints  = FALSE;
7915     *pfHasCircularMethodConstraints = FALSE;
7916
7917     JIT_TO_EE_TRANSITION();
7918
7919     MethodDesc* pMethod = GetMethod(hMethod);
7920     if (pMethod->IsTypicalMethodDefinition())
7921     {
7922         // Force a load of the constraints on the type parameters, detecting cyclic bounds
7923         pMethod->LoadConstraintsForTypicalMethodDefinition(pfHasCircularClassConstraints,pfHasCircularMethodConstraints);
7924     }
7925
7926     EE_TO_JIT_TRANSITION();
7927 }
7928
7929 /*************************************************************
7930  * Check if a method to be compiled is an instantiation
7931  * of generic code that has already been verified.
7932  * Three possible return values (see corinfo.h)
7933  *************************************************************/
7934
7935 CorInfoInstantiationVerification  
7936     CEEInfo::isInstantiationOfVerifiedGeneric(CORINFO_METHOD_HANDLE hMethod)
7937 {
7938     CONTRACTL {
7939         SO_TOLERANT;
7940         THROWS;
7941         GC_TRIGGERS;
7942         MODE_PREEMPTIVE;
7943     } CONTRACTL_END;
7944
7945     CorInfoInstantiationVerification result = INSTVER_NOT_INSTANTIATION;
7946
7947     JIT_TO_EE_TRANSITION();
7948
7949     MethodDesc * pMethod = GetMethod(hMethod);
7950
7951     if (!(pMethod->HasClassOrMethodInstantiation()))
7952     {
7953         result = INSTVER_NOT_INSTANTIATION;
7954         goto exit;
7955     }
7956
7957     if (pMethod->IsTypicalMethodDefinition())
7958     {
7959         result = INSTVER_NOT_INSTANTIATION;
7960         goto exit;
7961     }
7962
7963     result = INSTVER_GENERIC_PASSED_VERIFICATION;
7964
7965  exit: ;
7966
7967     EE_TO_JIT_TRANSITION();
7968
7969     return result;
7970 }
7971
7972 /*************************************************************
7973  * Similar to above, but perform check for tail call
7974  * eligibility. The callee can be passed as NULL if not known
7975  * (calli and callvirt).
7976  *************************************************************/
7977
7978 bool CEEInfo::canTailCall (CORINFO_METHOD_HANDLE hCaller,
7979                            CORINFO_METHOD_HANDLE hDeclaredCallee,
7980                            CORINFO_METHOD_HANDLE hExactCallee,
7981                            bool fIsTailPrefix)
7982 {
7983     CONTRACTL {
7984         SO_TOLERANT;
7985         THROWS;
7986         GC_TRIGGERS;
7987         MODE_PREEMPTIVE;
7988     } CONTRACTL_END;
7989
7990     bool result = false;
7991     const char * szFailReason = NULL;
7992
7993     JIT_TO_EE_TRANSITION();
7994
7995     // See comments in canInline above.
7996
7997     MethodDesc* pCaller = GetMethod(hCaller);
7998     MethodDesc* pDeclaredCallee = GetMethod(hDeclaredCallee);
7999     MethodDesc* pExactCallee = GetMethod(hExactCallee);
8000
8001     _ASSERTE(pCaller->GetModule());
8002     _ASSERTE(pCaller->GetModule()->GetClassLoader());
8003
8004     _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule());
8005     _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule()->GetClassLoader());
8006
8007     // If the caller is the static constructor (.cctor) of a class which has a ComImport base class
8008     // somewhere up the class hierarchy, then we cannot make the call into a tailcall.  See
8009     // RegisterObjectCreationCallback() in ExtensibleClassFactory.cpp for more information.
8010     if (pCaller->IsClassConstructor() &&
8011         pCaller->GetMethodTable()->IsComObjectType())
8012     {
8013         result = false;
8014         szFailReason = "Caller is  ComImport .cctor";
8015         goto exit;
8016     }
8017
8018     if (!fIsTailPrefix)        
8019     {
8020         mdMethodDef callerToken = pCaller->GetMemberDef();
8021
8022         // We don't want to tailcall the entrypoint for an application; JIT64 will sometimes
8023         // do this for simple entrypoints and it results in a rather confusing debugging 
8024         // experience.
8025         if (callerToken == pCaller->GetModule()->GetEntryPointToken())
8026         {
8027             result = false;
8028             szFailReason = "Caller is the entry point";
8029             goto exit;
8030         }
8031
8032         if (!pCaller->IsNoMetadata())
8033         {
8034             // Do not tailcall from methods that are marked as noinline (people often use no-inline
8035             // to mean "I want to always see this method in stacktrace")
8036             DWORD dwImplFlags = 0;
8037             IfFailThrow(pCaller->GetMDImport()->GetMethodImplProps(callerToken, NULL, &dwImplFlags));
8038             
8039             if (IsMiNoInlining(dwImplFlags))
8040             {
8041                 result = false;
8042                 szFailReason = "Caller is marked as no inline";
8043                 goto exit;
8044             }
8045         }
8046
8047         // Methods with StackCrawlMark depend on finding their caller on the stack.
8048         // If we tail call one of these guys, they get confused.  For lack of
8049         // a better way of identifying them, we use DynamicSecurity attribute to identify
8050         // them. We have an assert in canInline that ensures all StackCrawlMark
8051         // methods are appropriately marked.
8052         //
8053         if ((pExactCallee != NULL) && IsMdRequireSecObject(pExactCallee->GetAttrs()))
8054         {
8055             result = false;
8056             szFailReason = "Callee might have a StackCrawlMark.LookForMyCaller";
8057             goto exit;
8058         }
8059     }
8060
8061
8062     result = true;
8063
8064 exit: ;
8065
8066     EE_TO_JIT_TRANSITION();
8067
8068     if (!result)
8069     {
8070         // If you hit this assert, it means you added a new way to prevent tail calls
8071         // without documenting it for ETW!
8072         _ASSERTE(szFailReason != NULL);
8073         reportTailCallDecision(hCaller, hExactCallee, fIsTailPrefix, TAILCALL_FAIL, szFailReason);
8074     }
8075
8076     return result;
8077 }
8078
8079 void CEEInfo::reportTailCallDecision (CORINFO_METHOD_HANDLE callerHnd,
8080                                      CORINFO_METHOD_HANDLE calleeHnd,
8081                                      bool fIsTailPrefix,
8082                                      CorInfoTailCall tailCallResult,
8083                                      const char * reason)
8084 {
8085     STATIC_CONTRACT_THROWS;
8086     STATIC_CONTRACT_GC_TRIGGERS;
8087     STATIC_CONTRACT_SO_TOLERANT;
8088
8089     JIT_TO_EE_TRANSITION();
8090
8091     //put code here.  Make sure to report the method being compiled in addition to inliner and inlinee.
8092 #ifdef _DEBUG
8093     if (LoggingOn(LF_JIT, LL_INFO100000))
8094     {
8095         SString currentMethodName;
8096         TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled,
8097                                          TypeString::FormatBasic);
8098
8099         SString calleeMethodName;
8100         if (GetMethod(calleeHnd))
8101         {
8102             TypeString::AppendMethodInternal(calleeMethodName, GetMethod(calleeHnd),
8103                                              TypeString::FormatBasic);
8104         }
8105         else
8106         {
8107             calleeMethodName.AppendASCII( "<null>" );
8108         }
8109
8110         SString callerMethodName;
8111         if (GetMethod(callerHnd))
8112         {
8113             TypeString::AppendMethodInternal(callerMethodName, GetMethod(callerHnd),
8114                                              TypeString::FormatBasic);
8115         }
8116         else
8117         {
8118             callerMethodName.AppendASCII( "<null>" );
8119         }
8120         if (tailCallResult == TAILCALL_FAIL)
8121         {
8122             LOG((LF_JIT, LL_INFO100000,
8123                  "While compiling '%S', %Splicit tail call from '%S' to '%S' failed because: '%s'.\n",
8124                  currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8125                  callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), reason));
8126         }
8127         else
8128         {
8129             static const char * const tailCallType[] = {
8130                 "optimized tail call", "recursive loop", "helper assisted tailcall"
8131             };
8132             _ASSERTE(tailCallResult >= 0 && (size_t)tailCallResult < sizeof(tailCallType) / sizeof(tailCallType[0]));
8133             LOG((LF_JIT, LL_INFO100000,
8134                  "While compiling '%S', %Splicit tail call from '%S' to '%S' generated as a %s.\n",
8135                  currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8136                  callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), tailCallType[tailCallResult]));
8137
8138         }
8139     }
8140 #endif //_DEBUG
8141
8142     // I'm gonna duplicate this code because the format is slightly different.  And LoggingOn is debug only.
8143     if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, 
8144                                      TRACE_LEVEL_VERBOSE,
8145                                      CLR_JITTRACING_KEYWORD))
8146     {
8147         SString methodBeingCompiledNames[3];
8148         SString callerNames[3];
8149         SString calleeNames[3];
8150         MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8151 #define GMI(pMD, strArray) \
8152         do { \
8153             if (pMD) { \
8154                 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8155             } else {  \
8156                 (strArray)[0].Set(W("<null>")); \
8157                 (strArray)[1].Set(W("<null>")); \
8158                 (strArray)[2].Set(W("<null>")); \
8159             } } while (0)
8160
8161         GMI(methodBeingCompiled, methodBeingCompiledNames);
8162         GMI(GetMethod(callerHnd), callerNames);
8163         GMI(GetMethod(calleeHnd), calleeNames);
8164 #undef GMI
8165         if (tailCallResult == TAILCALL_FAIL)
8166         {
8167             const char * str = (reason ? reason : "");
8168
8169             FireEtwMethodJitTailCallFailed(methodBeingCompiledNames[0].GetUnicode(),
8170                                            methodBeingCompiledNames[1].GetUnicode(),
8171                                            methodBeingCompiledNames[2].GetUnicode(),
8172                                            callerNames[0].GetUnicode(),
8173                                            callerNames[1].GetUnicode(),
8174                                            callerNames[2].GetUnicode(),
8175                                            calleeNames[0].GetUnicode(),
8176                                            calleeNames[1].GetUnicode(),
8177                                            calleeNames[2].GetUnicode(),
8178                                            fIsTailPrefix,
8179                                            str,
8180                                            GetClrInstanceId());
8181         }
8182         else
8183         {
8184             FireEtwMethodJitTailCallSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8185                                               methodBeingCompiledNames[1].GetUnicode(),
8186                                               methodBeingCompiledNames[2].GetUnicode(),
8187                                               callerNames[0].GetUnicode(),
8188                                               callerNames[1].GetUnicode(),
8189                                               callerNames[2].GetUnicode(),
8190                                               calleeNames[0].GetUnicode(),
8191                                               calleeNames[1].GetUnicode(),
8192                                               calleeNames[2].GetUnicode(),
8193                                               fIsTailPrefix,
8194                                               tailCallResult,
8195                                               GetClrInstanceId());
8196         }
8197
8198     }
8199
8200
8201     EE_TO_JIT_TRANSITION();
8202 }
8203
8204 void CEEInfo::getEHinfoHelper(
8205     CORINFO_METHOD_HANDLE   ftnHnd,
8206     unsigned                EHnumber,
8207     CORINFO_EH_CLAUSE*      clause,
8208     COR_ILMETHOD_DECODER*   pILHeader)
8209 {
8210     STANDARD_VM_CONTRACT;
8211
8212     _ASSERTE(CheckPointer(pILHeader->EH));
8213     _ASSERTE(EHnumber < pILHeader->EH->EHCount());
8214
8215     COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
8216     const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo;
8217     ehInfo = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)pILHeader->EH->EHClause(EHnumber, &ehClause);
8218
8219     clause->Flags = (CORINFO_EH_CLAUSE_FLAGS)ehInfo->GetFlags();
8220     clause->TryOffset = ehInfo->GetTryOffset();
8221     clause->TryLength = ehInfo->GetTryLength();
8222     clause->HandlerOffset = ehInfo->GetHandlerOffset();
8223     clause->HandlerLength = ehInfo->GetHandlerLength();
8224     if ((clause->Flags & CORINFO_EH_CLAUSE_FILTER) == 0)
8225         clause->ClassToken = ehInfo->GetClassToken();
8226     else
8227         clause->FilterOffset = ehInfo->GetFilterOffset();
8228 }
8229
8230 /*********************************************************************/
8231 // get individual exception handler
8232 void CEEInfo::getEHinfo(
8233             CORINFO_METHOD_HANDLE ftnHnd,
8234             unsigned      EHnumber,
8235             CORINFO_EH_CLAUSE* clause)
8236 {
8237     CONTRACTL {
8238         SO_TOLERANT;
8239         THROWS;
8240         GC_TRIGGERS;
8241         MODE_PREEMPTIVE;
8242     } CONTRACTL_END;
8243
8244     JIT_TO_EE_TRANSITION();
8245
8246     MethodDesc * ftn          = GetMethod(ftnHnd);
8247
8248     if (IsDynamicMethodHandle(ftnHnd))
8249     {
8250         GetMethod(ftnHnd)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
8251     }
8252     else
8253     {
8254         COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
8255         getEHinfoHelper(ftnHnd, EHnumber, clause, &header);
8256     }
8257
8258     EE_TO_JIT_TRANSITION();
8259 }
8260
8261 //---------------------------------------------------------------------------------------
8262 // 
8263 void 
8264 CEEInfo::getMethodSig(
8265     CORINFO_METHOD_HANDLE ftnHnd, 
8266     CORINFO_SIG_INFO *    sigRet, 
8267     CORINFO_CLASS_HANDLE  owner)
8268 {
8269     CONTRACTL {
8270         SO_TOLERANT;
8271         THROWS;
8272         GC_TRIGGERS;
8273         MODE_PREEMPTIVE;
8274     } CONTRACTL_END;
8275
8276     JIT_TO_EE_TRANSITION();
8277
8278     getMethodSigInternal(ftnHnd, sigRet, owner);
8279
8280     EE_TO_JIT_TRANSITION();
8281 }
8282
8283 //---------------------------------------------------------------------------------------
8284 // 
8285 void 
8286 CEEInfo::getMethodSigInternal(
8287     CORINFO_METHOD_HANDLE ftnHnd, 
8288     CORINFO_SIG_INFO *    sigRet, 
8289     CORINFO_CLASS_HANDLE  owner)
8290 {
8291     STANDARD_VM_CONTRACT;
8292
8293     MethodDesc * ftn = GetMethod(ftnHnd);
8294     
8295     PCCOR_SIGNATURE pSig = NULL;
8296     DWORD           cbSig = 0;
8297     ftn->GetSig(&pSig, &cbSig);
8298
8299     // Type parameters in the signature are instantiated
8300     // according to the class/method/array instantiation of ftnHnd and owner
8301     CEEInfo::ConvToJitSig(
8302         pSig, 
8303         cbSig, 
8304         GetScopeHandle(ftn), 
8305         mdTokenNil, 
8306         sigRet, 
8307         ftn, 
8308         false, 
8309         (TypeHandle)owner);
8310
8311     //@GENERICS:
8312     // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation
8313     if (ftn->RequiresInstArg())
8314     {
8315         sigRet->callConv = (CorInfoCallConv) (sigRet->callConv | CORINFO_CALLCONV_PARAMTYPE);
8316     }
8317
8318     // We want the calling convention bit to be consistant with the method attribute bit
8319     _ASSERTE( (IsMdStatic(ftn->GetAttrs()) == 0) == ((sigRet->callConv & CORINFO_CALLCONV_HASTHIS) != 0) );
8320 }
8321
8322 //---------------------------------------------------------------------------------------
8323 // 
8324 //@GENERICSVER: for a method desc in a typical instantiation of a generic class,
8325 // this will return the typical instantiation of the generic class,
8326 // but only provided type variables are never shared.
8327 // The JIT verifier relies on this behaviour to extract the typical class from an instantiated method's typical method handle.
8328 // 
8329 CORINFO_CLASS_HANDLE 
8330 CEEInfo::getMethodClass(
8331     CORINFO_METHOD_HANDLE methodHnd)
8332 {
8333     CONTRACTL {
8334         SO_TOLERANT;
8335         THROWS;
8336         GC_TRIGGERS;
8337         MODE_PREEMPTIVE;
8338     } CONTRACTL_END;
8339
8340     CORINFO_CLASS_HANDLE result = NULL;
8341
8342     JIT_TO_EE_TRANSITION();
8343
8344     MethodDesc* method = GetMethod(methodHnd);
8345
8346     if (method->IsDynamicMethod())
8347     {
8348         DynamicResolver::SecurityControlFlags securityControlFlags = DynamicResolver::Default;
8349         TypeHandle typeOwner;
8350
8351         DynamicResolver* pResolver = method->AsDynamicMethodDesc()->GetResolver();
8352         pResolver->GetJitContext(&securityControlFlags, &typeOwner);
8353             
8354         if (!typeOwner.IsNull() && (method == pResolver->GetDynamicMethod())) 
8355         {
8356             result = CORINFO_CLASS_HANDLE(typeOwner.AsPtr());
8357         }
8358     }
8359
8360     if (result == NULL)
8361     {
8362         TypeHandle th = TypeHandle(method->GetMethodTable());
8363
8364         result = CORINFO_CLASS_HANDLE(th.AsPtr());
8365     }
8366
8367     EE_TO_JIT_TRANSITION();
8368
8369     return result;
8370 }
8371
8372 /***********************************************************************/
8373 CORINFO_MODULE_HANDLE CEEInfo::getMethodModule (CORINFO_METHOD_HANDLE methodHnd)
8374 {
8375     CONTRACTL {
8376         SO_TOLERANT;
8377         NOTHROW;
8378         GC_NOTRIGGER;
8379         MODE_PREEMPTIVE;
8380     } CONTRACTL_END;
8381
8382     CORINFO_MODULE_HANDLE result = NULL;
8383
8384     JIT_TO_EE_TRANSITION_LEAF();
8385
8386     MethodDesc* method = GetMethod(methodHnd);
8387
8388     if (method->IsDynamicMethod())
8389     {
8390         // this should never be called, thus the assert, I don't know if the (non existent) caller
8391         // expects the Module or the scope
8392         UNREACHABLE();
8393     }
8394     else
8395     {
8396         result = (CORINFO_MODULE_HANDLE) method->GetModule();
8397     }
8398     
8399     EE_TO_JIT_TRANSITION_LEAF();
8400
8401     return result;
8402 }
8403
8404 /*********************************************************************/
8405 CorInfoIntrinsics CEEInfo::getIntrinsicID(CORINFO_METHOD_HANDLE methodHnd,
8406                                           bool * pMustExpand)
8407 {
8408     CONTRACTL {
8409         SO_TOLERANT;
8410         THROWS;
8411         GC_TRIGGERS;
8412         MODE_PREEMPTIVE;
8413     } CONTRACTL_END;
8414
8415     CorInfoIntrinsics result = CORINFO_INTRINSIC_Illegal;
8416
8417     JIT_TO_EE_TRANSITION();
8418
8419     if (pMustExpand != NULL)
8420     {
8421         *pMustExpand = false;
8422     }
8423
8424     MethodDesc* method = GetMethod(methodHnd);
8425
8426     if (method->IsArray())
8427     {
8428         ArrayMethodDesc * arrMethod = (ArrayMethodDesc *)method;
8429         result = arrMethod->GetIntrinsicID();
8430     }
8431     else
8432     if (method->IsFCall())
8433     {
8434         result = ECall::GetIntrinsicID(method);
8435     }
8436     else
8437     {
8438         MethodTable * pMT = method->GetMethodTable();
8439         if (pMT->GetModule()->IsSystem() && pMT->IsByRefLike())
8440         {
8441             if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
8442             {
8443                 // ByReference<T> has just two methods: constructor and Value property
8444                 if (method->IsCtor())
8445                 {
8446                     result = CORINFO_INTRINSIC_ByReference_Ctor;
8447                 }
8448                 else
8449                 {
8450                     _ASSERTE(strcmp(method->GetName(), "get_Value") == 0);
8451                     result = CORINFO_INTRINSIC_ByReference_Value;
8452                 }
8453                 if (pMustExpand != nullptr)
8454                 {
8455                     *pMustExpand = true;
8456                 }
8457             }
8458             else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__SPAN)))
8459             {
8460                 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__SPAN__GET_ITEM)))
8461                 {
8462                     result = CORINFO_INTRINSIC_Span_GetItem;
8463                 }
8464             }
8465             else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__READONLY_SPAN)))
8466             {
8467                 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__READONLY_SPAN__GET_ITEM)))
8468                 {
8469                     result = CORINFO_INTRINSIC_ReadOnlySpan_GetItem;
8470                 }
8471             }
8472         }
8473     }
8474
8475     EE_TO_JIT_TRANSITION();
8476
8477     return result;
8478 }
8479
8480 /*********************************************************************/
8481 bool CEEInfo::isInSIMDModule(CORINFO_CLASS_HANDLE classHnd)
8482 {
8483 CONTRACTL {
8484         SO_TOLERANT;
8485         NOTHROW;
8486         GC_NOTRIGGER;
8487         MODE_PREEMPTIVE;
8488     } CONTRACTL_END;
8489
8490     bool result = false;
8491     JIT_TO_EE_TRANSITION_LEAF();
8492
8493     TypeHandle VMClsHnd(classHnd);
8494     if (VMClsHnd.GetMethodTable()->GetAssembly()->IsSIMDVectorAssembly())
8495     {
8496         result = true;
8497     }
8498     EE_TO_JIT_TRANSITION_LEAF();
8499
8500     return result;
8501 }
8502
8503 /*********************************************************************/
8504 void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd,
8505                                      unsigned * pOffsetOfIndirection,
8506                                      unsigned * pOffsetAfterIndirection,
8507                                      bool * isRelative)
8508 {
8509     CONTRACTL {
8510         SO_TOLERANT;
8511         NOTHROW;
8512         GC_NOTRIGGER;
8513         MODE_PREEMPTIVE;
8514     } CONTRACTL_END;
8515
8516     JIT_TO_EE_TRANSITION_LEAF();
8517
8518     MethodDesc* method = GetMethod(methodHnd);
8519
8520     //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8521     _ASSERTE(!method->HasMethodInstantiation());
8522
8523     _ASSERTE(MethodTable::GetVtableOffset() < 256);  // a rough sanity check
8524
8525     // better be in the vtable
8526     _ASSERTE(method->GetSlot() < method->GetMethodTable()->GetNumVirtuals());
8527
8528     *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * sizeof(MethodTable::VTableIndir_t);
8529     *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * sizeof(PCODE);
8530     *isRelative = MethodTable::VTableIndir_t::isRelative ? 1 : 0;
8531
8532     EE_TO_JIT_TRANSITION_LEAF();
8533 }
8534
8535 /*********************************************************************/
8536 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethodHelper(CORINFO_METHOD_HANDLE baseMethod,
8537                                                           CORINFO_CLASS_HANDLE derivedClass,
8538                                                           CORINFO_CONTEXT_HANDLE ownerType)
8539 {
8540     CONTRACTL {
8541         THROWS;
8542         GC_TRIGGERS;
8543         MODE_PREEMPTIVE;
8544     } CONTRACTL_END;
8545
8546     MethodDesc* pBaseMD = GetMethod(baseMethod);
8547     MethodTable* pBaseMT = pBaseMD->GetMethodTable();
8548
8549     // Method better be from a fully loaded class
8550     _ASSERTE(pBaseMD->IsRestored() && pBaseMT->IsFullyLoaded());
8551
8552     //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8553     _ASSERTE(!pBaseMD->HasMethodInstantiation());
8554
8555     // Method better be virtual
8556     _ASSERTE(pBaseMD->IsVirtual());
8557
8558     MethodDesc* pDevirtMD = nullptr;
8559
8560     TypeHandle DerivedClsHnd(derivedClass);
8561     MethodTable* pDerivedMT = DerivedClsHnd.GetMethodTable();
8562     _ASSERTE(pDerivedMT->IsRestored() && pDerivedMT->IsFullyLoaded());
8563
8564     // Can't devirtualize from __Canon.
8565     if (DerivedClsHnd == TypeHandle(g_pCanonMethodTableClass))
8566     {
8567         return nullptr;
8568     }
8569
8570     if (pBaseMT->IsInterface())
8571     {
8572
8573 #ifdef FEATURE_COMINTEROP
8574         // Don't try and devirtualize com interface calls.
8575         if (pDerivedMT->IsComObjectType())
8576         {
8577             return nullptr;
8578         }
8579 #endif // FEATURE_COMINTEROP
8580
8581         // Interface call devirtualization.
8582         //
8583         // We must ensure that pDerivedMT actually implements the
8584         // interface corresponding to pBaseMD.
8585         if (!pDerivedMT->CanCastToInterface(pBaseMT))
8586         {
8587             return nullptr;
8588         }
8589
8590         // For generic interface methods we must have an ownerType to
8591         // safely devirtualize.
8592         if (ownerType != nullptr)
8593         {
8594             TypeHandle OwnerClsHnd = GetTypeFromContext(ownerType);
8595             MethodTable* pOwnerMT = OwnerClsHnd.GetMethodTable();
8596
8597             // If the derived class is a shared class, make sure the
8598             // owner class is too.
8599             if (pDerivedMT->IsSharedByGenericInstantiations())
8600             {
8601                 pOwnerMT = pOwnerMT->GetCanonicalMethodTable();
8602             }
8603
8604             pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(TypeHandle(pOwnerMT), pBaseMD);
8605         }
8606         else if (!pBaseMD->HasClassOrMethodInstantiation())
8607         {
8608             pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(pBaseMD);
8609         }
8610         else
8611         {
8612             return nullptr;
8613         }
8614     }
8615     else
8616     {
8617         // Virtual call devirtualization.
8618         // 
8619         // The derived class should be a subclass of the the base class.
8620         MethodTable* pCheckMT = pDerivedMT;
8621         
8622         while (pCheckMT != nullptr)
8623         {
8624             if (pCheckMT->HasSameTypeDefAs(pBaseMT))
8625             {
8626                 break;
8627             }
8628             
8629             pCheckMT = pCheckMT->GetParentMethodTable();
8630         }
8631         
8632         if (pCheckMT == nullptr)
8633         {
8634             return nullptr;
8635         }
8636         
8637         // The base method should be in the base vtable
8638         WORD slot = pBaseMD->GetSlot();
8639         _ASSERTE(slot < pBaseMT->GetNumVirtuals());
8640         
8641         // Fetch the method that would be invoked if the class were
8642         // exactly derived class. It is up to the jit to determine whether
8643         // directly calling this method is correct.
8644         pDevirtMD = pDerivedMT->GetMethodDescForSlot(slot);
8645     }
8646
8647     _ASSERTE(pDevirtMD->IsRestored());
8648
8649 #ifdef FEATURE_READYTORUN_COMPILER
8650     // Check if devirtualization is dependent upon cross-version
8651     // bubble information and if so, disallow it.
8652     if (IsReadyToRunCompilation())
8653     {
8654         MethodDesc* callerMethod = m_pMethodBeingCompiled;
8655         Assembly* pCallerAssembly = callerMethod->GetModule()->GetAssembly();
8656         bool allowDevirt =
8657             IsInSameVersionBubble(pCallerAssembly , pDevirtMD->GetModule()->GetAssembly())
8658             && IsInSameVersionBubble(pCallerAssembly , pDerivedMT->GetAssembly());
8659
8660         if (!allowDevirt)
8661         {
8662             return nullptr;
8663         }
8664     }
8665 #endif
8666
8667     return (CORINFO_METHOD_HANDLE) pDevirtMD;
8668 }
8669
8670 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethod(CORINFO_METHOD_HANDLE methodHnd,
8671                                                     CORINFO_CLASS_HANDLE derivedClass,
8672                                                     CORINFO_CONTEXT_HANDLE ownerType)
8673 {
8674     CONTRACTL {
8675         SO_TOLERANT;
8676         THROWS;
8677         GC_TRIGGERS;
8678         MODE_PREEMPTIVE;
8679     } CONTRACTL_END;
8680
8681     CORINFO_METHOD_HANDLE result = nullptr;
8682
8683     JIT_TO_EE_TRANSITION();
8684
8685     result = resolveVirtualMethodHelper(methodHnd, derivedClass, ownerType);
8686
8687     EE_TO_JIT_TRANSITION();
8688
8689     return result;
8690 }
8691
8692 void CEEInfo::expandRawHandleIntrinsic(
8693     CORINFO_RESOLVED_TOKEN *        pResolvedToken,
8694     CORINFO_GENERICHANDLE_RESULT *  pResult)
8695 {
8696     LIMITED_METHOD_CONTRACT;
8697     UNREACHABLE();      // only called with CoreRT.
8698 }
8699
8700 /*********************************************************************/
8701 void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE  ftnHnd,
8702                                     CORINFO_CONST_LOOKUP * pResult,
8703                                     CORINFO_ACCESS_FLAGS   accessFlags)
8704 {
8705     CONTRACTL {
8706         SO_TOLERANT;
8707         THROWS;
8708         GC_TRIGGERS;
8709         MODE_PREEMPTIVE;
8710     } CONTRACTL_END;
8711
8712     void* ret = NULL;
8713     InfoAccessType accessType = IAT_VALUE;
8714
8715     JIT_TO_EE_TRANSITION();
8716
8717     MethodDesc * ftn = GetMethod(ftnHnd);
8718 #if defined(FEATURE_GDBJIT)
8719     MethodDesc * orig_ftn = ftn;
8720 #endif
8721
8722     // Resolve methodImpl.
8723     ftn = ftn->GetMethodTable()->MapMethodDeclToMethodImpl(ftn);
8724
8725     ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags);
8726
8727     // TryGetMultiCallableAddrOfCode returns NULL if indirect access is desired
8728     if (ret == NULL)
8729     {
8730         // should never get here for EnC methods or if interception via remoting stub is required
8731         _ASSERTE(!ftn->IsEnCMethod());
8732
8733         _ASSERTE((accessFlags & CORINFO_ACCESS_THIS) || !ftn->IsRemotingInterceptedViaVirtualDispatch());
8734
8735         ret = ftn->GetAddrOfSlot();
8736         accessType = IAT_PVALUE;
8737     }
8738
8739
8740 #if defined(FEATURE_GDBJIT)
8741     CalledMethod * pCM = new CalledMethod(orig_ftn, ret, m_pCalledMethods);
8742     m_pCalledMethods = pCM;
8743 #endif
8744
8745     EE_TO_JIT_TRANSITION();
8746
8747     _ASSERTE(ret != NULL);
8748
8749     pResult->accessType = accessType;
8750     pResult->addr = ret;
8751 }
8752
8753 /*********************************************************************/
8754 void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE   ftn,
8755                                          CORINFO_CONST_LOOKUP *  pResult)
8756 {
8757     CONTRACTL {
8758         SO_TOLERANT;
8759         THROWS;
8760         GC_TRIGGERS;
8761         MODE_PREEMPTIVE;
8762     } CONTRACTL_END;
8763
8764     JIT_TO_EE_TRANSITION();
8765
8766     MethodDesc * pMD = GetMethod(ftn);
8767
8768     pResult->accessType = IAT_VALUE;
8769
8770
8771 #ifndef CROSSGEN_COMPILE
8772     // If LDFTN target has [NativeCallable] attribute , then create a UMEntryThunk.
8773     if (pMD->HasNativeCallableAttribute())
8774     {
8775         pResult->addr = (void*)COMDelegate::ConvertToCallback(pMD);
8776     }
8777     else
8778 #endif //CROSSGEN_COMPILE
8779     {
8780         pResult->addr = (void *)pMD->GetMultiCallableAddrOfCode();
8781     }
8782     EE_TO_JIT_TRANSITION();
8783 }
8784
8785 /*********************************************************************/
8786 const char* CEEInfo::getFieldName (CORINFO_FIELD_HANDLE fieldHnd, const char** scopeName)
8787 {
8788     CONTRACTL {
8789         SO_TOLERANT;
8790         THROWS;
8791         GC_TRIGGERS;
8792         MODE_PREEMPTIVE;
8793     } CONTRACTL_END;
8794
8795     const char* result = NULL;
8796
8797     JIT_TO_EE_TRANSITION();
8798
8799     FieldDesc* field = (FieldDesc*) fieldHnd;
8800     if (scopeName != 0)
8801     {
8802         TypeHandle t = TypeHandle(field->GetApproxEnclosingMethodTable());
8803         *scopeName = "";
8804         if (!t.IsNull())
8805         {
8806 #ifdef _DEBUG
8807             t.GetName(ssClsNameBuff);
8808             *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
8809 #else // !_DEBUG
8810             // since this is for diagnostic purposes only,
8811             // give up on the namespace, as we don't have a buffer to concat it
8812             // also note this won't show array class names.
8813             LPCUTF8 nameSpace;
8814             *scopeName= t.GetMethodTable()->GetFullyQualifiedNameInfo(&nameSpace);
8815 #endif // !_DEBUG
8816         }
8817     }
8818
8819     result = field->GetName();
8820
8821     EE_TO_JIT_TRANSITION();
8822
8823     return result;
8824 }
8825
8826 /*********************************************************************/
8827 // Get the type that declares the field
8828 CORINFO_CLASS_HANDLE CEEInfo::getFieldClass (CORINFO_FIELD_HANDLE fieldHnd)
8829 {
8830     CONTRACTL {
8831         SO_TOLERANT;
8832         NOTHROW;
8833         GC_NOTRIGGER;
8834         MODE_PREEMPTIVE;
8835     } CONTRACTL_END;
8836
8837     CORINFO_CLASS_HANDLE result = NULL;
8838
8839     JIT_TO_EE_TRANSITION_LEAF();
8840
8841     FieldDesc* field = (FieldDesc*) fieldHnd;
8842     result = CORINFO_CLASS_HANDLE(field->GetApproxEnclosingMethodTable());
8843
8844     EE_TO_JIT_TRANSITION_LEAF();
8845
8846     return result;
8847 }
8848
8849 /*********************************************************************/
8850 // Returns the basic type of the field (not the the type that declares the field)
8851 //
8852 // pTypeHnd - On return, for reference and value types, *pTypeHnd will contain 
8853 //            the normalized type of the field.
8854 // owner - Optional. For resolving in a generic context
8855
8856 CorInfoType CEEInfo::getFieldType (CORINFO_FIELD_HANDLE fieldHnd, 
8857                                    CORINFO_CLASS_HANDLE* pTypeHnd, 
8858                                    CORINFO_CLASS_HANDLE owner)
8859 {
8860     CONTRACTL {
8861         SO_TOLERANT;
8862         THROWS;
8863         GC_TRIGGERS;
8864         MODE_PREEMPTIVE;
8865     } CONTRACTL_END;
8866
8867     CorInfoType result = CORINFO_TYPE_UNDEF;
8868
8869     JIT_TO_EE_TRANSITION();
8870
8871     result = getFieldTypeInternal(fieldHnd, pTypeHnd, owner);
8872
8873     EE_TO_JIT_TRANSITION();
8874
8875     return result;
8876 }
8877
8878 /*********************************************************************/
8879 CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd, 
8880                                            CORINFO_CLASS_HANDLE* pTypeHnd, 
8881                                            CORINFO_CLASS_HANDLE owner)
8882 {
8883     STANDARD_VM_CONTRACT;
8884
8885     *pTypeHnd = 0;
8886
8887     TypeHandle clsHnd = TypeHandle();
8888     FieldDesc* field = (FieldDesc*) fieldHnd;
8889     CorElementType type   = field->GetFieldType();
8890
8891     // <REVISIT_TODO>TODO should not burn the time to do this for anything but Value Classes</REVISIT_TODO>
8892     _ASSERTE(type != ELEMENT_TYPE_BYREF);
8893
8894     if (type == ELEMENT_TYPE_I)
8895     {
8896         PTR_MethodTable enclosingMethodTable = field->GetApproxEnclosingMethodTable();
8897         if (enclosingMethodTable->IsByRefLike() && enclosingMethodTable->HasSameTypeDefAs(g_pByReferenceClass))
8898         {
8899             _ASSERTE(field->GetOffset() == 0);
8900             return CORINFO_TYPE_BYREF;
8901         }
8902     }
8903
8904     if (!CorTypeInfo::IsPrimitiveType(type))
8905     {
8906         PCCOR_SIGNATURE sig;
8907         DWORD sigCount;
8908         CorCallingConvention conv;
8909
8910         field->GetSig(&sig, &sigCount);
8911
8912         conv = (CorCallingConvention)CorSigUncompressCallingConv(sig);
8913         _ASSERTE(isCallConv(conv, IMAGE_CEE_CS_CALLCONV_FIELD));
8914
8915         SigPointer ptr(sig, sigCount);
8916
8917         // For verifying code involving generics, use the class instantiation
8918         // of the optional owner (to provide exact, not representative,
8919         // type information)
8920         SigTypeContext typeContext(field, (TypeHandle)owner);
8921
8922         clsHnd = ptr.GetTypeHandleThrowing(field->GetModule(), &typeContext);
8923         _ASSERTE(!clsHnd.IsNull());
8924
8925         // I believe it doesn't make any diff. if this is GetInternalCorElementType 
8926         // or GetSignatureCorElementType.
8927         type = clsHnd.GetSignatureCorElementType();
8928     }
8929
8930     return CEEInfo::asCorInfoType(type, clsHnd, pTypeHnd);
8931 }
8932
8933 /*********************************************************************/
8934 unsigned CEEInfo::getFieldOffset (CORINFO_FIELD_HANDLE fieldHnd)
8935 {
8936     CONTRACTL {
8937         SO_TOLERANT;
8938         THROWS;
8939         GC_TRIGGERS;
8940         MODE_PREEMPTIVE;
8941     } CONTRACTL_END;
8942
8943     unsigned result = (unsigned) -1;
8944
8945     JIT_TO_EE_TRANSITION();
8946
8947     FieldDesc* field = (FieldDesc*) fieldHnd;
8948
8949     // GetOffset() does not include the size of Object
8950     result = field->GetOffset();
8951
8952     // So if it is not a value class, add the Object into it
8953     if (field->IsStatic())
8954     {
8955         Module* pModule = field->GetModule();
8956         if (field->IsRVA() && pModule->IsRvaFieldTls(field->GetOffset()))
8957         {
8958             result = pModule->GetFieldTlsOffset(field->GetOffset());
8959         }
8960     }
8961     else if (!field->GetApproxEnclosingMethodTable()->IsValueType())
8962     {
8963         result += sizeof(Object);
8964     }
8965
8966     EE_TO_JIT_TRANSITION();
8967
8968     return result;
8969 }
8970
8971 /*********************************************************************/
8972 bool CEEInfo::isWriteBarrierHelperRequired(CORINFO_FIELD_HANDLE field)
8973 {
8974     CONTRACTL {
8975         SO_TOLERANT;
8976         THROWS;
8977         GC_TRIGGERS;
8978         MODE_PREEMPTIVE;
8979     } CONTRACTL_END;
8980
8981     bool fHelperRequired = false;
8982
8983     JIT_TO_EE_TRANSITION();
8984
8985     FieldDesc * pField = (FieldDesc *)field;
8986
8987     // TODO: jit64 should be switched to the same plan as the i386 jits - use
8988     // getClassGClayout to figure out the need for writebarrier helper, and inline the copying.
8989     // Once this happens, USE_WRITE_BARRIER_HELPERS and CORINFO_FLG_WRITE_BARRIER_HELPER can be removed.
8990     CorElementType type = pField->GetFieldType();
8991
8992     if(CorTypeInfo::IsObjRef(type))
8993         fHelperRequired = true;
8994     else if (type == ELEMENT_TYPE_VALUETYPE)
8995     {
8996         TypeHandle th = pField->GetFieldTypeHandleThrowing();
8997         _ASSERTE(!th.IsNull());
8998         if(th.GetMethodTable()->ContainsPointers())
8999             fHelperRequired = true;
9000     }
9001
9002     EE_TO_JIT_TRANSITION();
9003
9004     return fHelperRequired;
9005 }
9006
9007 /*********************************************************************/
9008 DWORD CEEInfo::getFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE fieldHnd, void **ppIndirection)
9009 {
9010     CONTRACTL {
9011         SO_TOLERANT;
9012         THROWS;
9013         GC_TRIGGERS;
9014         MODE_PREEMPTIVE;
9015     } CONTRACTL_END;
9016
9017     DWORD result = 0;
9018
9019     if (ppIndirection != NULL)
9020         *ppIndirection = NULL;
9021
9022     JIT_TO_EE_TRANSITION();
9023
9024     FieldDesc* field = (FieldDesc*) fieldHnd;
9025     Module* module = field->GetModule();
9026
9027     _ASSERTE(field->IsRVA());       // Only RVA statics can be thread local
9028     _ASSERTE(module->IsRvaFieldTls(field->GetOffset()));
9029
9030     result = module->GetTlsIndex();
9031
9032     EE_TO_JIT_TRANSITION();
9033
9034     return result;
9035 }
9036
9037 void *CEEInfo::allocateArray(ULONG cBytes)
9038 {
9039     CONTRACTL {
9040         SO_TOLERANT;
9041         THROWS;
9042         GC_TRIGGERS;
9043         MODE_PREEMPTIVE;
9044     } CONTRACTL_END;
9045
9046     void * result = NULL;
9047
9048     JIT_TO_EE_TRANSITION();
9049
9050     result = new BYTE [cBytes];
9051
9052     EE_TO_JIT_TRANSITION();
9053
9054     return result;
9055 }
9056
9057 void CEEInfo::freeArray(void *array)
9058 {
9059     CONTRACTL {
9060         SO_TOLERANT;
9061         THROWS;
9062         GC_TRIGGERS;
9063         MODE_PREEMPTIVE;
9064     } CONTRACTL_END;
9065
9066     JIT_TO_EE_TRANSITION();
9067
9068     delete [] ((BYTE*) array);
9069
9070     EE_TO_JIT_TRANSITION();
9071 }
9072
9073 void CEEInfo::getBoundaries(CORINFO_METHOD_HANDLE ftn,
9074                                unsigned int *cILOffsets, DWORD **pILOffsets,
9075                                ICorDebugInfo::BoundaryTypes *implicitBoundaries)
9076 {
9077     CONTRACTL {
9078         SO_TOLERANT;
9079         THROWS;
9080         GC_TRIGGERS;
9081         MODE_PREEMPTIVE;
9082     } CONTRACTL_END;
9083
9084     JIT_TO_EE_TRANSITION();
9085
9086 #ifdef DEBUGGING_SUPPORTED
9087     if (g_pDebugInterface && !IsCompilationProcess())
9088     {
9089         g_pDebugInterface->getBoundaries(GetMethod(ftn), cILOffsets, pILOffsets,
9090                                      implicitBoundaries);
9091     }
9092     else
9093     {
9094         *cILOffsets = 0;
9095         *pILOffsets = NULL;
9096         *implicitBoundaries = ICorDebugInfo::DEFAULT_BOUNDARIES;
9097     }
9098 #endif // DEBUGGING_SUPPORTED
9099
9100     EE_TO_JIT_TRANSITION();
9101 }
9102
9103 void CEEInfo::getVars(CORINFO_METHOD_HANDLE ftn, ULONG32 *cVars, ICorDebugInfo::ILVarInfo **vars,
9104                          bool *extendOthers)
9105 {
9106     CONTRACTL {
9107         SO_TOLERANT;
9108         THROWS;
9109         GC_TRIGGERS;
9110         MODE_PREEMPTIVE;
9111     } CONTRACTL_END;
9112
9113     JIT_TO_EE_TRANSITION();
9114
9115 #ifdef DEBUGGING_SUPPORTED
9116     if (g_pDebugInterface && !IsCompilationProcess())
9117     {
9118         g_pDebugInterface->getVars(GetMethod(ftn), cVars, vars, extendOthers);
9119     }
9120     else
9121     {
9122         *cVars = 0;
9123         *vars = NULL;
9124
9125         // Just tell the JIT to extend everything.
9126         *extendOthers = true;
9127     }
9128 #endif // DEBUGGING_SUPPORTED
9129
9130     EE_TO_JIT_TRANSITION();
9131 }
9132
9133 /*********************************************************************/
9134 CORINFO_ARG_LIST_HANDLE CEEInfo::getArgNext(CORINFO_ARG_LIST_HANDLE args)
9135 {
9136     CONTRACTL {
9137         SO_TOLERANT;
9138         THROWS;
9139         GC_TRIGGERS;
9140         MODE_PREEMPTIVE;
9141     } CONTRACTL_END;
9142
9143     CORINFO_ARG_LIST_HANDLE result = NULL;
9144
9145     JIT_TO_EE_TRANSITION();
9146
9147     SigPointer ptr((unsigned __int8*) args);
9148     IfFailThrow(ptr.SkipExactlyOne());
9149
9150     result = (CORINFO_ARG_LIST_HANDLE) ptr.GetPtr();
9151
9152     EE_TO_JIT_TRANSITION();
9153     
9154     return result;
9155 }
9156
9157
9158 /*********************************************************************/
9159
9160 CorInfoTypeWithMod CEEInfo::getArgType (
9161         CORINFO_SIG_INFO*       sig,
9162         CORINFO_ARG_LIST_HANDLE args,
9163         CORINFO_CLASS_HANDLE*   vcTypeRet
9164         )
9165 {
9166     CONTRACTL {
9167         SO_TOLERANT;
9168         THROWS;
9169         GC_TRIGGERS;
9170         MODE_PREEMPTIVE;
9171     } CONTRACTL_END;
9172
9173     CorInfoTypeWithMod result = CorInfoTypeWithMod(CORINFO_TYPE_UNDEF);
9174
9175     JIT_TO_EE_TRANSITION();
9176
9177    _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args && (BYTE*) args < (BYTE*) sig->pSig + sig->cbSig);
9178    _ASSERTE((BYTE*) sig->args <= (BYTE*) args);
9179     INDEBUG(*vcTypeRet = CORINFO_CLASS_HANDLE((size_t)INVALID_POINTER_CC));
9180
9181     SigPointer ptr((unsigned __int8*) args);
9182     CorElementType eType;
9183     IfFailThrow(ptr.PeekElemType(&eType));
9184     while (eType == ELEMENT_TYPE_PINNED)
9185     {
9186         result = CORINFO_TYPE_MOD_PINNED;
9187         IfFailThrow(ptr.GetElemType(NULL));
9188         IfFailThrow(ptr.PeekElemType(&eType));
9189     }
9190
9191     // Now read off the "real" element type after taking any instantiations into consideration
9192     SigTypeContext typeContext;
9193     GetTypeContext(&sig->sigInst,&typeContext);
9194
9195     Module* pModule = GetModule(sig->scope);
9196
9197     CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9198
9199     TypeHandle typeHnd = TypeHandle();
9200     switch (type) {
9201       case ELEMENT_TYPE_VAR :
9202       case ELEMENT_TYPE_MVAR :
9203       case ELEMENT_TYPE_VALUETYPE :
9204       case ELEMENT_TYPE_TYPEDBYREF :
9205       case ELEMENT_TYPE_INTERNAL :
9206       {
9207             typeHnd = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9208             _ASSERTE(!typeHnd.IsNull());
9209
9210             CorElementType normType = typeHnd.GetInternalCorElementType();
9211
9212             // if we are looking up a value class, don't morph it to a refernece type
9213             // (This can only happen in illegal IL)
9214             if (!CorTypeInfo::IsObjRef(normType) || type != ELEMENT_TYPE_VALUETYPE)
9215             {
9216                 type = normType;
9217             }
9218         }
9219         break;
9220
9221     case ELEMENT_TYPE_PTR:
9222         // Load the type eagerly under debugger to make the eval work
9223         if (!isVerifyOnly() && CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
9224         {
9225             // NOTE: in some IJW cases, when the type pointed at is unmanaged,
9226             // the GetTypeHandle may fail, because there is no TypeDef for such type.
9227             // Usage of GetTypeHandleThrowing would lead to class load exception
9228             TypeHandle thPtr = ptr.GetTypeHandleNT(pModule, &typeContext);
9229             if(!thPtr.IsNull())
9230             {
9231                 m_pOverride->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(thPtr.AsPtr()));
9232             }
9233         }
9234         break;
9235
9236     case ELEMENT_TYPE_VOID:
9237         // void is not valid in local sigs
9238         if (sig->flags & CORINFO_SIGFLAG_IS_LOCAL_SIG)
9239             COMPlusThrowHR(COR_E_INVALIDPROGRAM);
9240         break;
9241
9242     case ELEMENT_TYPE_END:
9243            COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9244         break;
9245
9246     default:
9247         break;
9248     }
9249
9250     result = CorInfoTypeWithMod(result | CEEInfo::asCorInfoType(type, typeHnd, vcTypeRet));
9251     EE_TO_JIT_TRANSITION();
9252     
9253     return result;
9254 }
9255
9256 /*********************************************************************/
9257
9258 CORINFO_CLASS_HANDLE CEEInfo::getArgClass (
9259     CORINFO_SIG_INFO*       sig,
9260     CORINFO_ARG_LIST_HANDLE args
9261     )
9262 {
9263     CONTRACTL {
9264         SO_TOLERANT;
9265         THROWS;
9266         GC_TRIGGERS;
9267         MODE_PREEMPTIVE;
9268     } CONTRACTL_END;
9269
9270     CORINFO_CLASS_HANDLE result = NULL;
9271
9272     JIT_TO_EE_TRANSITION();
9273
9274     // make certain we dont have a completely wacked out sig pointer
9275     _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args);
9276     _ASSERTE((BYTE*) sig->args <= (BYTE*) args && (BYTE*) args < &((BYTE*) sig->args)[0x10000*5]);
9277
9278     Module* pModule = GetModule(sig->scope);
9279
9280     SigPointer ptr((unsigned __int8*) args);
9281
9282     CorElementType eType;
9283     IfFailThrow(ptr.PeekElemType(&eType));
9284
9285     while (eType == ELEMENT_TYPE_PINNED)
9286     {
9287         IfFailThrow(ptr.GetElemType(NULL));
9288         IfFailThrow(ptr.PeekElemType(&eType));
9289     }
9290     // Now read off the "real" element type after taking any instantiations into consideration
9291     SigTypeContext typeContext;
9292     GetTypeContext(&sig->sigInst, &typeContext);
9293     CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9294
9295     if (!CorTypeInfo::IsPrimitiveType(type)) {
9296         TypeHandle th = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9297         result = CORINFO_CLASS_HANDLE(th.AsPtr());
9298     }
9299
9300     EE_TO_JIT_TRANSITION();
9301     
9302     return result;
9303 }
9304
9305 /*********************************************************************/
9306
9307 CorInfoType CEEInfo::getHFAType(CORINFO_CLASS_HANDLE hClass)
9308 {
9309     CONTRACTL {
9310         SO_TOLERANT;
9311         THROWS;
9312         GC_TRIGGERS;
9313         MODE_PREEMPTIVE;
9314     } CONTRACTL_END;
9315
9316     CorInfoType result = CORINFO_TYPE_UNDEF;
9317
9318     JIT_TO_EE_TRANSITION();
9319
9320     TypeHandle VMClsHnd(hClass);
9321
9322     result = asCorInfoType(VMClsHnd.GetHFAType());
9323     
9324     EE_TO_JIT_TRANSITION();
9325
9326     return result;
9327 }
9328
9329 /*********************************************************************/
9330
9331     // return the unmanaged calling convention for a PInvoke
9332 CorInfoUnmanagedCallConv CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method)
9333 {
9334     CONTRACTL {
9335         SO_TOLERANT;
9336         THROWS;
9337         GC_TRIGGERS;
9338         MODE_PREEMPTIVE;
9339     } CONTRACTL_END;
9340
9341     CorInfoUnmanagedCallConv result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9342
9343     JIT_TO_EE_TRANSITION();
9344
9345     MethodDesc* pMD = NULL;
9346     pMD = GetMethod(method);
9347     _ASSERTE(pMD->IsNDirect());
9348
9349 #ifdef _TARGET_X86_
9350     EX_TRY
9351     {
9352         PInvokeStaticSigInfo sigInfo(pMD, PInvokeStaticSigInfo::NO_THROW_ON_ERROR);
9353
9354         switch (sigInfo.GetCallConv()) {
9355             case pmCallConvCdecl:
9356                 result = CORINFO_UNMANAGED_CALLCONV_C;
9357                 break;
9358             case pmCallConvStdcall:
9359                 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9360                 break;
9361             case pmCallConvThiscall:
9362                 result = CORINFO_UNMANAGED_CALLCONV_THISCALL;
9363                 break;
9364             default:
9365                 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9366         }
9367     }
9368     EX_CATCH
9369     {
9370         result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9371     }
9372     EX_END_CATCH(SwallowAllExceptions)
9373 #else // !_TARGET_X86_
9374     //
9375     // we have only one calling convention
9376     //
9377     result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9378 #endif // !_TARGET_X86_
9379
9380     EE_TO_JIT_TRANSITION();
9381     
9382     return result;
9383 }
9384
9385 /*********************************************************************/
9386 BOOL NDirectMethodDesc::ComputeMarshalingRequired()
9387 {
9388     WRAPPER_NO_CONTRACT;
9389
9390     return NDirect::MarshalingRequired(this);
9391 }
9392
9393 /*********************************************************************/
9394 BOOL CEEInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig)
9395 {
9396     CONTRACTL {
9397         SO_TOLERANT;
9398         THROWS;
9399         GC_TRIGGERS;
9400         MODE_PREEMPTIVE;
9401     } CONTRACTL_END;
9402
9403     BOOL result = FALSE;
9404
9405     JIT_TO_EE_TRANSITION();
9406
9407     if (method != 0)
9408     {
9409         MethodDesc* ftn = GetMethod(method);
9410         _ASSERTE(ftn->IsNDirect());
9411         NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9412
9413 #if defined(HAS_NDIRECT_IMPORT_PRECODE)
9414         if (pMD->IsVarArg())
9415         {
9416             // Varag P/Invoke must not be inlined because its NDirectMethodDesc
9417             // does not contain a meaningful stack size (it is call site specific).
9418             // See code:InlinedCallFrame.UpdateRegDisplay where this is needed.
9419             result = TRUE;
9420         }
9421         else if (pMD->MarshalingRequired())
9422         {
9423             // This is not a no-marshal signature.
9424             result = TRUE;
9425         }
9426         else
9427         {
9428             // This is a no-marshal non-vararg signature.
9429             result = FALSE;
9430         }
9431 #else
9432         // Marshalling is required to lazy initialize the indirection cell 
9433         // without NDirectImportPrecode.
9434         result = TRUE;
9435 #endif
9436     }
9437     else
9438     {
9439         // check the call site signature
9440         result = NDirect::MarshalingRequired(
9441                     GetMethod(method),
9442                     callSiteSig->pSig,
9443                     GetModule(callSiteSig->scope));
9444     }
9445
9446     EE_TO_JIT_TRANSITION();
9447
9448     return result;
9449 }
9450
9451 /*********************************************************************/
9452 // Generate a cookie based on the signature that would needs to be passed
9453 // to CORINFO_HELP_PINVOKE_CALLI
9454 LPVOID CEEInfo::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig,
9455                                             void **ppIndirection)
9456 {
9457     WRAPPER_NO_CONTRACT;
9458
9459     return getVarArgsHandle(szMetaSig, ppIndirection);
9460 }
9461
9462 bool CEEInfo::canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig)
9463 {
9464     LIMITED_METHOD_CONTRACT;
9465     return true;
9466 }
9467
9468
9469 // Check any constraints on method type arguments
9470 BOOL CEEInfo::satisfiesMethodConstraints(
9471     CORINFO_CLASS_HANDLE        parent,
9472     CORINFO_METHOD_HANDLE       method)
9473 {
9474     CONTRACTL {
9475         SO_TOLERANT;
9476         THROWS;
9477         GC_TRIGGERS;
9478         MODE_PREEMPTIVE;
9479     } CONTRACTL_END;
9480
9481     BOOL result = FALSE;
9482
9483     JIT_TO_EE_TRANSITION();
9484
9485     _ASSERTE(parent != NULL);
9486     _ASSERTE(method != NULL);
9487     result = GetMethod(method)->SatisfiesMethodConstraints(TypeHandle(parent));
9488
9489     EE_TO_JIT_TRANSITION();
9490
9491     return result;
9492 }
9493
9494
9495
9496 /*********************************************************************/
9497 // Given a delegate target class, a target method parent class,  a  target method,
9498 // a delegate class, check if the method signature is compatible with the Invoke method of the delegate
9499 // (under the typical instantiation of any free type variables in the memberref signatures).
9500 //
9501 // objCls should be NULL if the target object is NULL
9502 //@GENERICSVER: new (suitable for generics)
9503 BOOL CEEInfo::isCompatibleDelegate(
9504             CORINFO_CLASS_HANDLE        objCls,
9505             CORINFO_CLASS_HANDLE        methodParentCls,
9506             CORINFO_METHOD_HANDLE       method,
9507             CORINFO_CLASS_HANDLE        delegateCls,
9508             BOOL*                       pfIsOpenDelegate)
9509 {
9510     CONTRACTL {
9511         SO_TOLERANT;
9512         THROWS;
9513         GC_TRIGGERS;
9514         MODE_PREEMPTIVE;
9515     } CONTRACTL_END;
9516
9517     BOOL result = FALSE;
9518
9519     JIT_TO_EE_TRANSITION();
9520
9521     _ASSERTE(method != NULL);
9522     _ASSERTE(delegateCls != NULL);
9523
9524     TypeHandle delegateClsHnd = (TypeHandle) delegateCls;
9525
9526     _ASSERTE(delegateClsHnd.GetMethodTable()->IsDelegate());
9527
9528     TypeHandle methodParentHnd = (TypeHandle) (methodParentCls);
9529     MethodDesc* pMDFtn = GetMethod(method);
9530     TypeHandle objClsHnd(objCls);
9531
9532     EX_TRY
9533     {
9534       result = COMDelegate::ValidateCtor(objClsHnd, methodParentHnd, pMDFtn, delegateClsHnd, pfIsOpenDelegate);
9535     }
9536     EX_CATCH
9537     {
9538     }
9539     EX_END_CATCH(SwallowAllExceptions)
9540
9541     EE_TO_JIT_TRANSITION();
9542
9543     return result;
9544 }
9545
9546 /*********************************************************************/
9547     // return the unmanaged target *if method has already been prelinked.*
9548 void* CEEInfo::getPInvokeUnmanagedTarget(CORINFO_METHOD_HANDLE method,
9549                                                     void **ppIndirection)
9550 {
9551     CONTRACTL {
9552         SO_TOLERANT;
9553         THROWS;
9554         GC_TRIGGERS;
9555         MODE_PREEMPTIVE;
9556     } CONTRACTL_END;
9557
9558     void* result = NULL;
9559
9560     if (ppIndirection != NULL)
9561         *ppIndirection = NULL;
9562
9563 #ifndef CROSSGEN_COMPILE
9564     JIT_TO_EE_TRANSITION();
9565
9566     MethodDesc* ftn = GetMethod(method);
9567     _ASSERTE(ftn->IsNDirect());
9568     NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9569
9570     if (pMD->NDirectTargetIsImportThunk())
9571     {
9572     }
9573     else
9574     {
9575         result = pMD->GetNDirectTarget();
9576     }
9577
9578     EE_TO_JIT_TRANSITION();
9579 #endif // CROSSGEN_COMPILE
9580
9581     return result;
9582 }
9583
9584 /*********************************************************************/
9585     // return address of fixup area for late-bound N/Direct calls.
9586 void* CEEInfo::getAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE method,
9587                                         void **ppIndirection)
9588 {
9589     CONTRACTL {
9590         SO_TOLERANT;
9591         NOTHROW;
9592         GC_NOTRIGGER;
9593         MODE_PREEMPTIVE;
9594     } CONTRACTL_END;
9595
9596     void * result = NULL;
9597
9598     if (ppIndirection != NULL)
9599         *ppIndirection = NULL;
9600
9601     JIT_TO_EE_TRANSITION_LEAF();
9602
9603     MethodDesc* ftn = GetMethod(method);
9604     _ASSERTE(ftn->IsNDirect());
9605     NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9606
9607     result = (LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
9608
9609     EE_TO_JIT_TRANSITION_LEAF();
9610
9611     return result;
9612 }
9613
9614 /*********************************************************************/
9615     // return address of fixup area for late-bound N/Direct calls.
9616 void CEEInfo::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method,
9617                                         CORINFO_CONST_LOOKUP *pLookup)
9618 {
9619     WRAPPER_NO_CONTRACT;
9620
9621     void *pIndirection;
9622     pLookup->accessType = IAT_PVALUE;
9623     pLookup->addr = getAddressOfPInvokeFixup(method, &pIndirection);
9624     _ASSERTE(pIndirection == NULL);
9625 }
9626
9627 /*********************************************************************/
9628 CORINFO_JUST_MY_CODE_HANDLE CEEInfo::getJustMyCodeHandle(
9629                 CORINFO_METHOD_HANDLE       method,
9630                 CORINFO_JUST_MY_CODE_HANDLE**ppIndirection)
9631 {
9632     CONTRACTL {
9633         SO_TOLERANT;
9634         NOTHROW;
9635         GC_NOTRIGGER;
9636         MODE_PREEMPTIVE;
9637     } CONTRACTL_END;
9638
9639     CORINFO_JUST_MY_CODE_HANDLE result = NULL;
9640
9641     if (ppIndirection)
9642         *ppIndirection = NULL;
9643
9644     JIT_TO_EE_TRANSITION_LEAF();
9645
9646     // Get the flag from the debugger.
9647     MethodDesc* ftn = GetMethod(method);
9648     DWORD * pFlagAddr = NULL;
9649     
9650     if (g_pDebugInterface)
9651     {
9652         pFlagAddr = g_pDebugInterface->GetJMCFlagAddr(ftn->GetModule());
9653     }
9654
9655     result = (CORINFO_JUST_MY_CODE_HANDLE) pFlagAddr;
9656
9657     EE_TO_JIT_TRANSITION_LEAF();
9658
9659     return result;
9660 }
9661
9662 /*********************************************************************/
9663 void InlinedCallFrame::GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo *pInfo)
9664 {
9665     LIMITED_METHOD_CONTRACT;
9666
9667     pInfo->size                          = sizeof(GSCookie) + sizeof(InlinedCallFrame);
9668
9669     pInfo->offsetOfGSCookie              = 0;
9670     pInfo->offsetOfFrameVptr             = sizeof(GSCookie);
9671     pInfo->offsetOfFrameLink             = sizeof(GSCookie) + Frame::GetOffsetOfNextLink();
9672     pInfo->offsetOfCallSiteSP            = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallSiteSP);
9673     pInfo->offsetOfCalleeSavedFP         = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCalleeSavedFP);
9674     pInfo->offsetOfCallTarget            = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_Datum);
9675     pInfo->offsetOfReturnAddress         = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallerReturnAddress);
9676 }
9677
9678 /*********************************************************************/
9679 // Return details about EE internal data structures 
9680 void CEEInfo::getEEInfo(CORINFO_EE_INFO *pEEInfoOut)
9681 {
9682     CONTRACTL {
9683         SO_TOLERANT;
9684         THROWS;
9685         GC_TRIGGERS;
9686         MODE_PREEMPTIVE;
9687     } CONTRACTL_END;
9688
9689     INDEBUG(memset(pEEInfoOut, 0xCC, sizeof(*pEEInfoOut)));
9690
9691     JIT_TO_EE_TRANSITION();
9692
9693     InlinedCallFrame::GetEEInfo(&pEEInfoOut->inlinedCallFrameInfo);
9694
9695     // Offsets into the Thread structure
9696     pEEInfoOut->offsetOfThreadFrame = Thread::GetOffsetOfCurrentFrame();
9697     pEEInfoOut->offsetOfGCState     = Thread::GetOffsetOfGCFlag();
9698
9699     // Delegate offsets
9700     pEEInfoOut->offsetOfDelegateInstance    = DelegateObject::GetOffsetOfTarget();
9701     pEEInfoOut->offsetOfDelegateFirstTarget = DelegateObject::GetOffsetOfMethodPtr();
9702
9703     // Secure delegate offsets
9704     pEEInfoOut->offsetOfSecureDelegateIndirectCell = DelegateObject::GetOffsetOfMethodPtrAux();
9705
9706     // Remoting offsets
9707     pEEInfoOut->offsetOfTransparentProxyRP = TransparentProxyObject::GetOffsetOfRP();
9708     pEEInfoOut->offsetOfRealProxyServer    = RealProxyObject::GetOffsetOfServerObject();
9709
9710     pEEInfoOut->offsetOfObjArrayData       = (DWORD)PtrArray::GetDataOffset();
9711
9712     pEEInfoOut->sizeOfReversePInvokeFrame  = (DWORD)-1;
9713
9714     pEEInfoOut->osPageSize = GetOsPageSize();
9715     pEEInfoOut->maxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
9716     pEEInfoOut->targetAbi = CORINFO_CORECLR_ABI;
9717
9718     pEEInfoOut->osType = CORINFO_WINNT;
9719
9720     // hardcode OS version to 0.0.0. These fields can be removed from JITEE interface
9721     pEEInfoOut->osMajor = 0;
9722     pEEInfoOut->osMinor = 0;
9723     pEEInfoOut->osBuild = 0;
9724
9725     EE_TO_JIT_TRANSITION();
9726 }
9727
9728 LPCWSTR CEEInfo::getJitTimeLogFilename()
9729 {
9730     CONTRACTL {
9731         SO_TOLERANT;
9732         THROWS;
9733         GC_TRIGGERS;
9734         MODE_PREEMPTIVE;
9735     } CONTRACTL_END;
9736
9737     LPCWSTR result = NULL;
9738
9739     JIT_TO_EE_TRANSITION();
9740     result = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitTimeLogFile);
9741     EE_TO_JIT_TRANSITION();
9742
9743     return result;
9744 }
9745
9746
9747
9748     // Return details about EE internal data structures
9749 DWORD CEEInfo::getThreadTLSIndex(void **ppIndirection)
9750 {
9751     CONTRACTL {
9752         SO_TOLERANT;
9753         THROWS;
9754         GC_TRIGGERS;
9755         MODE_PREEMPTIVE;
9756     } CONTRACTL_END;
9757
9758     DWORD result = (DWORD)-1;
9759
9760     if (ppIndirection != NULL)
9761         *ppIndirection = NULL;
9762
9763     JIT_TO_EE_TRANSITION();
9764
9765 #if !defined(CROSSGEN_COMPILE) && !defined(FEATURE_IMPLICIT_TLS)
9766     result = GetThreadTLSIndex();
9767
9768     // The JIT can use the optimized TLS access only if the runtime is using it as well.
9769     //  (This is necessaryto make managed code work well under appverifier.)
9770     if (GetTLSAccessMode(result) == TLSACCESS_GENERIC)
9771         result = (DWORD)-1;
9772 #endif
9773
9774     EE_TO_JIT_TRANSITION();
9775
9776     return result;
9777 }
9778
9779 const void * CEEInfo::getInlinedCallFrameVptr(void **ppIndirection)
9780 {
9781     CONTRACTL {
9782         SO_TOLERANT;
9783         NOTHROW;
9784         GC_NOTRIGGER;
9785         MODE_PREEMPTIVE;
9786     } CONTRACTL_END;
9787
9788     void * result = NULL;
9789
9790     if (ppIndirection != NULL)
9791         *ppIndirection = NULL;
9792
9793     JIT_TO_EE_TRANSITION_LEAF();
9794
9795 #ifndef CROSSGEN_COMPILE
9796     result = (void*)InlinedCallFrame::GetMethodFrameVPtr();
9797 #else
9798     result = (void*)0x43210;
9799 #endif
9800
9801     EE_TO_JIT_TRANSITION_LEAF();
9802
9803     return result;
9804 }
9805
9806 LONG * CEEInfo::getAddrOfCaptureThreadGlobal(void **ppIndirection)
9807 {
9808     CONTRACTL {
9809         SO_TOLERANT;
9810         NOTHROW;
9811         GC_NOTRIGGER;
9812         MODE_PREEMPTIVE;
9813     } CONTRACTL_END;
9814
9815     LONG * result = NULL;
9816
9817     if (ppIndirection != NULL)
9818         *ppIndirection = NULL;
9819
9820     JIT_TO_EE_TRANSITION_LEAF();
9821
9822     result = (LONG *)&g_TrapReturningThreads;
9823
9824     EE_TO_JIT_TRANSITION_LEAF();
9825
9826     return result;
9827 }
9828
9829
9830
9831 HRESULT CEEInfo::GetErrorHRESULT(struct _EXCEPTION_POINTERS *pExceptionPointers)
9832 {
9833     CONTRACTL {
9834         SO_TOLERANT;
9835         NOTHROW;
9836         GC_TRIGGERS;
9837         MODE_ANY;
9838     } CONTRACTL_END;
9839
9840     HRESULT hr = S_OK;
9841
9842     //This function is called from the JIT64 exception filter during PEVerify.  Because it is a filter, it
9843     //can be "called" from a NOTHROW region in the case of StackOverflow.  Security::MapToHR throws
9844     //internally, but it catches all exceptions.  Therefore, none of the children can cause an exception to
9845     //percolate out of this function (except for Stack Overflow).  Obviously I can't explain most of this to
9846     //the Contracts system, and I can't add this CONTRACT_VIOLATION to the filter in Jit64.
9847     CONTRACT_VIOLATION(ThrowsViolation);
9848
9849     JIT_TO_EE_TRANSITION();
9850
9851     GCX_COOP();
9852
9853     OBJECTREF throwable = GetThread()->LastThrownObject();
9854     hr = GetExceptionHResult(throwable);
9855
9856     EE_TO_JIT_TRANSITION();
9857
9858     return hr;
9859 }
9860
9861
9862 ULONG CEEInfo::GetErrorMessage(__inout_ecount(bufferLength) LPWSTR buffer, ULONG bufferLength)
9863 {
9864     CONTRACTL {
9865         SO_TOLERANT;
9866         THROWS;
9867         GC_TRIGGERS;
9868         MODE_PREEMPTIVE;
9869     } CONTRACTL_END;
9870
9871     ULONG result = 0;
9872
9873 #ifndef CROSSGEN_COMPILE
9874     JIT_TO_EE_TRANSITION();
9875
9876     GCX_COOP();
9877
9878     OBJECTREF throwable = GetThread()->LastThrownObject();
9879
9880     if (throwable != NULL)
9881     {
9882         EX_TRY
9883         {
9884             result = GetExceptionMessage(throwable, buffer, bufferLength);
9885         }
9886         EX_CATCH
9887         {
9888         }
9889         EX_END_CATCH(SwallowAllExceptions)
9890     }
9891
9892     EE_TO_JIT_TRANSITION();
9893 #endif
9894
9895     return result;
9896 }
9897
9898 // This method is called from CEEInfo::FilterException which
9899 // is run as part of the SEH filter clause for the JIT.
9900 // It is fatal to throw an exception while running a SEH filter clause
9901 // so our contract is NOTHROW, NOTRIGGER.
9902 //
9903 LONG EEFilterException(struct _EXCEPTION_POINTERS *pExceptionPointers, void *unused)
9904 {
9905     CONTRACTL {
9906         SO_TOLERANT;
9907         NOTHROW;
9908         GC_NOTRIGGER;
9909     } CONTRACTL_END;
9910
9911     int result = 0;
9912
9913     JIT_TO_EE_TRANSITION_LEAF();
9914
9915     VALIDATE_BACKOUT_STACK_CONSUMPTION;
9916
9917     unsigned code = pExceptionPointers->ExceptionRecord->ExceptionCode;
9918
9919 #ifdef _DEBUG
9920     if (code == EXCEPTION_ACCESS_VIOLATION)
9921     {
9922         static int hit = 0;
9923         if (hit++ == 0)
9924         {
9925             _ASSERTE(!"Access violation while Jitting!");
9926             // If you set the debugger to catch access violations and 'go'
9927             // you will get back to the point at which the access violation occurred
9928             result = EXCEPTION_CONTINUE_EXECUTION;
9929         }
9930         else
9931         {
9932             result = EXCEPTION_CONTINUE_SEARCH;
9933         }
9934     }
9935     else
9936 #endif // _DEBUG
9937     // No one should be catching breakpoint
9938     // Similarly the JIT doesn't know how to reset the guard page, so it shouldn't
9939     // be catching a hard stack overflow
9940     if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP || code == EXCEPTION_STACK_OVERFLOW)
9941     {
9942         result = EXCEPTION_CONTINUE_SEARCH;
9943     }
9944 #ifdef CROSSGEN_COMPILE
9945     else
9946     {
9947         result = EXCEPTION_EXECUTE_HANDLER;
9948     }
9949 #else
9950     else if (!IsComPlusException(pExceptionPointers->ExceptionRecord))
9951     {
9952         result = EXCEPTION_EXECUTE_HANDLER;
9953     }
9954     else
9955     {
9956         GCX_COOP();
9957
9958         // This is actually the LastThrown exception object.
9959         OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
9960
9961         if (throwable != NULL)
9962         {
9963             struct 
9964             {
9965                 OBJECTREF oLastThrownObject;
9966             } _gc;
9967
9968             ZeroMemory(&_gc, sizeof(_gc));
9969             
9970             // Setup the throwables
9971             _gc.oLastThrownObject = throwable;
9972
9973             GCPROTECT_BEGIN(_gc);
9974
9975             // Don't catch ThreadAbort and other uncatchable exceptions
9976             if (IsUncatchable(&_gc.oLastThrownObject))
9977                 result = EXCEPTION_CONTINUE_SEARCH;
9978             else
9979                 result = EXCEPTION_EXECUTE_HANDLER;
9980             
9981             GCPROTECT_END();
9982         }
9983     }
9984 #endif
9985
9986     EE_TO_JIT_TRANSITION_LEAF();
9987
9988     return result;
9989 }
9990
9991 int CEEInfo::FilterException(struct _EXCEPTION_POINTERS *pExceptionPointers)
9992 {
9993     WRAPPER_NO_CONTRACT;
9994     return EEFilterException(pExceptionPointers, nullptr);
9995 }
9996
9997 // This code is called if FilterException chose to handle the exception.
9998 void CEEInfo::HandleException(struct _EXCEPTION_POINTERS *pExceptionPointers)
9999 {
10000     CONTRACTL {
10001         SO_TOLERANT;
10002         NOTHROW;
10003         GC_NOTRIGGER;
10004     } CONTRACTL_END;
10005
10006     JIT_TO_EE_TRANSITION_LEAF();
10007
10008 #ifndef CROSSGEN_COMPILE
10009     if (IsComPlusException(pExceptionPointers->ExceptionRecord))
10010     {
10011         GCX_COOP();
10012
10013         // This is actually the LastThrown exception object.
10014         OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10015
10016         if (throwable != NULL)
10017         {
10018             struct 
10019             {
10020                 OBJECTREF oLastThrownObject;
10021                 OBJECTREF oCurrentThrowable;
10022             } _gc;
10023
10024             ZeroMemory(&_gc, sizeof(_gc));
10025             
10026             PTR_Thread pCurThread = GetThread();
10027
10028             // Setup the throwables
10029             _gc.oLastThrownObject = throwable;
10030
10031             // This will be NULL if no managed exception is active. Otherwise,
10032             // it will reference the active throwable.
10033             _gc.oCurrentThrowable = pCurThread->GetThrowable(); 
10034
10035             GCPROTECT_BEGIN(_gc);
10036
10037             // JIT does not use or reference managed exceptions at all and simply swallows them,
10038             // or lets them fly through so that they will either get caught in managed code, the VM
10039             // or will go unhandled. 
10040             //
10041             // Blind swallowing of managed exceptions can break the semantic of "which exception handler"
10042             // gets to process the managed exception first. The expected handler is managed code exception 
10043             // handler (e.g. COMPlusFrameHandler on x86 and ProcessCLRException on 64bit) which will setup 
10044             // the exception tracker for the exception that will enable the expected sync between the 
10045             // LastThrownObject (LTO), setup in RaiseTheExceptionInternalOnly, and the exception tracker.
10046             // 
10047             // However, JIT can break this by swallowing the managed exception before managed code exception
10048             // handler gets a chance to setup an exception tracker for it. Since there is no cleanup
10049             // done for the swallowed exception as part of the unwind (because no exception tracker may have been setup), 
10050             // we need to reset the LTO, if it is out of sync from the active throwable.
10051             //
10052             // Hence, check if the LastThrownObject and active-exception throwable are in sync or not.
10053             // If not, bring them in sync.
10054             //
10055             // Example
10056             // -------
10057             // It is possible that an exception was already in progress and while processing it (e.g.
10058             // invoking finally block), we invoked JIT that had another managed exception @ JIT-EE transition boundary
10059             // that is swallowed by the JIT before managed code exception handler sees it. This breaks the sync between
10060             // LTO and the active exception in the exception tracker.
10061             if (_gc.oCurrentThrowable != _gc.oLastThrownObject)
10062             {
10063                 // Update the LTO. 
10064                 //
10065                 // Note: Incase of OOM, this will get set to OOM instance.
10066                 pCurThread->SafeSetLastThrownObject(_gc.oCurrentThrowable);
10067             }
10068  
10069             GCPROTECT_END();
10070         }
10071     }
10072 #endif
10073
10074     EE_TO_JIT_TRANSITION_LEAF();
10075 }
10076
10077 void ThrowExceptionForJit(HRESULT res);
10078
10079 void CEEInfo::ThrowExceptionForJitResult(
10080         HRESULT result)
10081 {
10082     CONTRACTL {
10083         SO_TOLERANT;
10084         THROWS;
10085         GC_TRIGGERS;
10086         MODE_PREEMPTIVE;
10087     } CONTRACTL_END;
10088
10089     JIT_TO_EE_TRANSITION();
10090
10091     if (!SUCCEEDED(result))
10092         ThrowExceptionForJit(result);
10093
10094     EE_TO_JIT_TRANSITION();
10095 }
10096
10097
10098 CORINFO_MODULE_HANDLE CEEInfo::embedModuleHandle(CORINFO_MODULE_HANDLE handle,
10099                                                  void **ppIndirection)
10100 {
10101     CONTRACTL {
10102         SO_TOLERANT;
10103         NOTHROW;
10104         GC_NOTRIGGER;
10105         MODE_PREEMPTIVE;
10106         PRECONDITION(!IsDynamicScope(handle));
10107     }
10108     CONTRACTL_END;
10109
10110     if (ppIndirection != NULL)
10111         *ppIndirection = NULL;
10112
10113     JIT_TO_EE_TRANSITION_LEAF();
10114
10115     EE_TO_JIT_TRANSITION_LEAF();
10116
10117     return handle;
10118 }
10119
10120 CORINFO_CLASS_HANDLE CEEInfo::embedClassHandle(CORINFO_CLASS_HANDLE handle,
10121                                                void **ppIndirection)
10122 {
10123     CONTRACTL {
10124         SO_TOLERANT;
10125         NOTHROW;
10126         GC_NOTRIGGER;
10127         MODE_PREEMPTIVE;
10128     }
10129     CONTRACTL_END;
10130
10131     if (ppIndirection != NULL)
10132         *ppIndirection = NULL;
10133
10134     JIT_TO_EE_TRANSITION_LEAF();
10135
10136     EE_TO_JIT_TRANSITION_LEAF();
10137
10138     return handle;
10139 }
10140
10141 CORINFO_FIELD_HANDLE CEEInfo::embedFieldHandle(CORINFO_FIELD_HANDLE handle,
10142                                                void **ppIndirection)
10143 {
10144     CONTRACTL {
10145         SO_TOLERANT;
10146         NOTHROW;
10147         GC_NOTRIGGER;
10148         MODE_PREEMPTIVE;
10149     }
10150     CONTRACTL_END;
10151
10152     if (ppIndirection != NULL)
10153         *ppIndirection = NULL;
10154
10155     JIT_TO_EE_TRANSITION_LEAF();
10156
10157     EE_TO_JIT_TRANSITION_LEAF();
10158
10159     return handle;
10160 }
10161
10162 CORINFO_METHOD_HANDLE CEEInfo::embedMethodHandle(CORINFO_METHOD_HANDLE handle,
10163                                                  void **ppIndirection)
10164 {
10165     CONTRACTL {
10166         SO_TOLERANT;
10167         NOTHROW;
10168         GC_NOTRIGGER;
10169         MODE_PREEMPTIVE;
10170     }
10171     CONTRACTL_END;
10172
10173     if (ppIndirection != NULL)
10174         *ppIndirection = NULL;
10175
10176     JIT_TO_EE_TRANSITION_LEAF();
10177
10178     EE_TO_JIT_TRANSITION_LEAF();
10179
10180     return handle;
10181 }
10182
10183 /*********************************************************************/
10184 void CEEInfo::setJitFlags(const CORJIT_FLAGS& jitFlags)
10185 {
10186     LIMITED_METHOD_CONTRACT;
10187
10188     m_jitFlags = jitFlags;
10189 }
10190
10191 /*********************************************************************/
10192 DWORD CEEInfo::getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes)
10193 {
10194     CONTRACTL {
10195         SO_TOLERANT;
10196         NOTHROW;
10197         GC_NOTRIGGER;
10198         MODE_PREEMPTIVE;
10199     } CONTRACTL_END;
10200
10201     JIT_TO_EE_TRANSITION_LEAF();
10202
10203     _ASSERTE(sizeInBytes >= sizeof(m_jitFlags));
10204     *jitFlags = m_jitFlags;
10205
10206     EE_TO_JIT_TRANSITION_LEAF();
10207
10208     return sizeof(m_jitFlags);
10209 }
10210
10211 /*********************************************************************/
10212 #if !defined(PLATFORM_UNIX)
10213
10214 struct RunWithErrorTrapFilterParam
10215 {
10216     ICorDynamicInfo* m_corInfo;
10217     void (*m_function)(void*);
10218     void* m_param;
10219     EXCEPTION_POINTERS m_exceptionPointers;
10220 };
10221
10222 static LONG RunWithErrorTrapFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
10223 {
10224     WRAPPER_NO_CONTRACT;
10225
10226     auto* param = reinterpret_cast<RunWithErrorTrapFilterParam*>(theParam);
10227     param->m_exceptionPointers = *exceptionPointers;
10228     return param->m_corInfo->FilterException(exceptionPointers);
10229 }
10230
10231 #endif // !defined(PLATFORM_UNIX)
10232
10233 bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param)
10234 {
10235     // No dynamic contract here because SEH is used
10236     STATIC_CONTRACT_THROWS;
10237     STATIC_CONTRACT_GC_TRIGGERS;
10238     STATIC_CONTRACT_SO_TOLERANT;
10239     STATIC_CONTRACT_MODE_PREEMPTIVE;
10240
10241     // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
10242     //       transitions into the EE proper should occur either via the call to
10243     //       `EEFilterException` (which is appropraitely marked) or via JIT/EE
10244     //       interface calls made by `function`.
10245
10246     bool success = true;
10247
10248 #if !defined(PLATFORM_UNIX)
10249
10250     RunWithErrorTrapFilterParam trapParam;
10251     trapParam.m_corInfo = m_pOverride == nullptr ? this : m_pOverride;
10252     trapParam.m_function = function;
10253     trapParam.m_param = param;
10254
10255     PAL_TRY(RunWithErrorTrapFilterParam*, pTrapParam, &trapParam)
10256     {
10257         pTrapParam->m_function(pTrapParam->m_param);
10258     }
10259     PAL_EXCEPT_FILTER(RunWithErrorTrapFilter)
10260     {
10261         HandleException(&trapParam.m_exceptionPointers);
10262         success = false;
10263     }
10264     PAL_ENDTRY
10265
10266 #else // !defined(PLATFORM_UNIX)
10267
10268     // We shouldn't need PAL_TRY on *nix: any exceptions that we are able to catch
10269     // ought to originate from the runtime itself and should be catchable inside of
10270     // EX_TRY/EX_CATCH, including emulated SEH exceptions.
10271     EX_TRY
10272     {
10273         function(param);
10274     }
10275     EX_CATCH
10276     {
10277         success = false;
10278     }
10279     EX_END_CATCH(RethrowTerminalExceptions);
10280
10281 #endif
10282
10283     return success;
10284 }
10285
10286 /*********************************************************************/
10287 IEEMemoryManager* CEEInfo::getMemoryManager()
10288 {
10289     CONTRACTL {
10290         SO_TOLERANT;
10291         NOTHROW;
10292         GC_NOTRIGGER;
10293         MODE_PREEMPTIVE;
10294     } CONTRACTL_END;
10295
10296     IEEMemoryManager* result = NULL;
10297
10298     JIT_TO_EE_TRANSITION_LEAF();
10299
10300     result = GetEEMemoryManager();
10301
10302     EE_TO_JIT_TRANSITION_LEAF();
10303
10304     return result;
10305 }
10306
10307 /*********************************************************************/
10308 int CEEInfo::doAssert(const char* szFile, int iLine, const char* szExpr)
10309 {
10310     STATIC_CONTRACT_SO_TOLERANT;
10311     STATIC_CONTRACT_THROWS;
10312     STATIC_CONTRACT_GC_TRIGGERS;
10313     STATIC_CONTRACT_MODE_PREEMPTIVE;
10314     STATIC_CONTRACT_DEBUG_ONLY;
10315
10316     int result = 0;
10317
10318     JIT_TO_EE_TRANSITION();
10319
10320 #ifdef CROSSGEN_COMPILE
10321     ThrowHR(COR_E_INVALIDPROGRAM);
10322 #else
10323
10324 #ifdef _DEBUG
10325     BEGIN_DEBUG_ONLY_CODE;
10326     result = _DbgBreakCheck(szFile, iLine, szExpr);
10327     END_DEBUG_ONLY_CODE;
10328 #else // !_DEBUG
10329     result = 1;   // break into debugger
10330 #endif // !_DEBUG
10331
10332 #endif
10333
10334     EE_TO_JIT_TRANSITION();
10335
10336     return result;
10337 }
10338
10339 void CEEInfo::reportFatalError(CorJitResult result)
10340 {
10341     STATIC_CONTRACT_SO_TOLERANT;
10342     STATIC_CONTRACT_THROWS;
10343     STATIC_CONTRACT_GC_TRIGGERS;
10344     STATIC_CONTRACT_MODE_PREEMPTIVE;
10345
10346     JIT_TO_EE_TRANSITION_LEAF();
10347
10348     STRESS_LOG2(LF_JIT,LL_ERROR, "Jit reported error 0x%x while compiling 0x%p\n",
10349                 (int)result, (INT_PTR)getMethodBeingCompiled());
10350
10351     EE_TO_JIT_TRANSITION_LEAF();
10352 }
10353
10354 BOOL CEEInfo::logMsg(unsigned level, const char* fmt, va_list args)
10355 {
10356     STATIC_CONTRACT_SO_TOLERANT;
10357     STATIC_CONTRACT_THROWS;
10358     STATIC_CONTRACT_GC_TRIGGERS;
10359     STATIC_CONTRACT_MODE_PREEMPTIVE;
10360     STATIC_CONTRACT_DEBUG_ONLY;
10361
10362     BOOL result = FALSE;
10363
10364     JIT_TO_EE_TRANSITION_LEAF();
10365
10366 #ifdef LOGGING
10367     if (LoggingOn(LF_JIT, level))
10368     {
10369         LogSpewValist(LF_JIT, level, (char*) fmt, args);
10370         result = TRUE;
10371     }
10372 #endif // LOGGING
10373
10374     EE_TO_JIT_TRANSITION_LEAF();
10375
10376     return result;
10377 }
10378
10379 void CEEInfo::yieldExecution()
10380 {
10381     WRAPPER_NO_CONTRACT;
10382 }
10383
10384
10385 #ifndef CROSSGEN_COMPILE
10386
10387 /*********************************************************************/
10388
10389 void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc    ftnNum,         /* IN  */
10390                                void **            ppIndirection)  /* OUT */
10391 {
10392     CONTRACTL {
10393         SO_TOLERANT;
10394         NOTHROW;
10395         GC_NOTRIGGER;
10396         MODE_PREEMPTIVE;
10397     } CONTRACTL_END;
10398
10399     void* result = NULL;
10400
10401     if (ppIndirection != NULL)
10402         *ppIndirection = NULL;
10403
10404     JIT_TO_EE_TRANSITION_LEAF();
10405
10406     _ASSERTE(ftnNum < CORINFO_HELP_COUNT);
10407
10408     void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10409
10410     size_t dynamicFtnNum = ((size_t)pfnHelper - 1);
10411     if (dynamicFtnNum < DYNAMIC_CORINFO_HELP_COUNT)
10412     {
10413 #ifdef _PREFAST_
10414 #pragma warning(push)
10415 #pragma warning(disable:26001) // "Bounds checked above using the underflow trick"
10416 #endif /*_PREFAST_ */
10417
10418 #if defined(_TARGET_AMD64_)
10419         // To avoid using a jump stub we always call certain helpers using an indirect call.
10420         // Because when using a direct call and the target is father away than 2^31 bytes,
10421         // the direct call instead goes to a jump stub which jumps to the jit helper.
10422         // However in this process the jump stub will corrupt RAX.
10423         //
10424         // The set of helpers for which RAX must be preserved are the profiler probes
10425         // and the STOP_FOR_GC helper which maps to JIT_RareDisableHelper.
10426         // In the case of the STOP_FOR_GC helper RAX can be holding a function return value.
10427         //
10428         if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_STOP_FOR_GC    ||
10429             dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER ||
10430             dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE ||
10431             dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL)
10432         {
10433             _ASSERTE(ppIndirection != NULL);
10434             *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10435             return NULL;
10436         }
10437 #endif
10438
10439 #if defined(ENABLE_FAST_GCPOLL_HELPER)
10440         //always call this indirectly so that we can swap GC Poll helpers.
10441         if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_POLL_GC)
10442         {
10443             _ASSERTE(ppIndirection != NULL);
10444             *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10445             return NULL;
10446         }
10447 #endif
10448
10449         pfnHelper = hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10450
10451 #ifdef _PREFAST_
10452 #pragma warning(pop)
10453 #endif /*_PREFAST_*/
10454     }
10455
10456     _ASSERTE(pfnHelper);
10457
10458     result = (LPVOID)GetEEFuncEntryPoint(pfnHelper);
10459
10460     EE_TO_JIT_TRANSITION_LEAF();
10461
10462     return result;
10463 }
10464
10465 PCODE CEEJitInfo::getHelperFtnStatic(CorInfoHelpFunc ftnNum)
10466 {
10467     LIMITED_METHOD_CONTRACT;
10468
10469     void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10470
10471     // If pfnHelper is an index into the dynamic helper table, it should be less 
10472     // than DYNAMIC_CORINFO_HELP_COUNT.  In this case we need to find the actual pfnHelper 
10473     // using an extra indirection.  Note the special case
10474     // where pfnHelper==0 where pfnHelper-1 will underflow and we will avoid the indirection.
10475     if (((size_t)pfnHelper - 1) < DYNAMIC_CORINFO_HELP_COUNT)
10476     {
10477         pfnHelper = hlpDynamicFuncTable[((size_t)pfnHelper - 1)].pfnHelper;
10478     }
10479
10480     _ASSERTE(pfnHelper != NULL);
10481
10482     return GetEEFuncEntryPoint(pfnHelper);
10483 }
10484
10485 void CEEJitInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
10486 {
10487     CONTRACTL
10488     {
10489         STANDARD_VM_CHECK;
10490         PRECONDITION(CheckPointer(moduleFrom));
10491         PRECONDITION(!IsDynamicScope(moduleFrom));
10492         PRECONDITION(CheckPointer(moduleTo));
10493         PRECONDITION(!IsDynamicScope(moduleTo));
10494         PRECONDITION(moduleFrom != moduleTo);
10495     }
10496     CONTRACTL_END;
10497
10498     // This is only called internaly. JIT-EE transition is not needed.
10499     // JIT_TO_EE_TRANSITION();
10500
10501     Module *dependency = (Module *)moduleTo;
10502     _ASSERTE(!dependency->IsSystem());
10503
10504     if (m_pMethodBeingCompiled->IsLCGMethod())
10505     {
10506         // The context module of the m_pMethodBeingCompiled is irrelevant.  Rather than tracking
10507         // the dependency, we just do immediate activation.
10508         dependency->EnsureActive();
10509     }
10510     else
10511     {
10512 #ifdef FEATURE_LOADER_OPTIMIZATION
10513         Module *context = (Module *)moduleFrom;
10514
10515         // Record active dependency for loader.
10516         context->AddActiveDependency(dependency, FALSE);
10517 #else
10518         dependency->EnsureActive();
10519 #endif
10520     }
10521
10522     // EE_TO_JIT_TRANSITION();
10523 }
10524
10525
10526 // Wrapper around CEEInfo::GetProfilingHandle.  The first time this is called for a
10527 // method desc, it calls through to EEToProfInterfaceImpl::EEFunctionIDMappe and caches the
10528 // result in CEEJitInfo::GetProfilingHandleCache.  Thereafter, this wrapper regurgitates the cached values
10529 // rather than calling into CEEInfo::GetProfilingHandle each time.  This avoids
10530 // making duplicate calls into the profiler's FunctionIDMapper callback.
10531 void CEEJitInfo::GetProfilingHandle(BOOL                      *pbHookFunction,
10532                                     void                     **pProfilerHandle,
10533                                     BOOL                      *pbIndirectedHandles)
10534 {
10535     CONTRACTL {
10536         SO_TOLERANT;
10537         THROWS;
10538         GC_TRIGGERS;
10539         MODE_PREEMPTIVE;
10540     } CONTRACTL_END;
10541     
10542     _ASSERTE(pbHookFunction != NULL);
10543     _ASSERTE(pProfilerHandle != NULL);
10544     _ASSERTE(pbIndirectedHandles != NULL);
10545     
10546     if (!m_gphCache.m_bGphIsCacheValid)
10547     {
10548 #ifdef PROFILING_SUPPORTED
10549         JIT_TO_EE_TRANSITION();
10550
10551         // Cache not filled in, so make our first and only call to CEEInfo::GetProfilingHandle here        
10552
10553         // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
10554         // they shouldnever come here as they are called out in GetCompileFlag
10555         _ASSERTE(!m_pMethodBeingCompiled->IsNoMetadata());
10556
10557         // We pass in the typical method definition to the function mapper because in
10558         // Whidbey all the profiling API transactions are done in terms of typical
10559         // method definitions not instantiations.
10560         BOOL bHookFunction = TRUE;
10561         void * profilerHandle = m_pMethodBeingCompiled;
10562
10563         {
10564             BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
10565             profilerHandle = (void *)g_profControlBlock.pProfInterface->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction);
10566             END_PIN_PROFILER();
10567         }
10568
10569         m_gphCache.m_pvGphProfilerHandle = profilerHandle;
10570         m_gphCache.m_bGphHookFunction = (bHookFunction != FALSE);
10571         m_gphCache.m_bGphIsCacheValid = true;
10572
10573         EE_TO_JIT_TRANSITION();
10574 #endif //PROFILING_SUPPORTED
10575     }
10576         
10577     // Our cache of these values are bitfield bools, but the interface requires
10578     // BOOL.  So to avoid setting aside a staging area on the stack for these
10579     // values, we filled them in directly in the if (not cached yet) case.
10580     *pbHookFunction = (m_gphCache.m_bGphHookFunction != false);
10581
10582     // At this point, the remaining values must be in the cache by now, so use them  
10583     *pProfilerHandle = m_gphCache.m_pvGphProfilerHandle;
10584
10585     //
10586     // This is the JIT case, which is never indirected.
10587     //
10588     *pbIndirectedHandles = FALSE;
10589 }
10590
10591 /*********************************************************************/
10592 void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr)
10593 {
10594     CONTRACTL {
10595         NOTHROW;
10596         GC_TRIGGERS;
10597     } CONTRACTL_END;
10598
10599     CodeHeader* pCodeHeader = GetCodeHeader();
10600     if (pCodeHeader)
10601         jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len);
10602 }
10603
10604 /*********************************************************************/
10605 // Route jit information to the Jit Debug store.
10606 void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
10607                                ICorDebugInfo::OffsetMapping *pMap)
10608 {
10609     CONTRACTL {
10610         SO_TOLERANT;
10611         THROWS;
10612         GC_TRIGGERS;
10613         MODE_PREEMPTIVE;
10614     } CONTRACTL_END;
10615
10616     JIT_TO_EE_TRANSITION();
10617
10618     // We receive ownership of the array
10619     _ASSERTE(m_pOffsetMapping == NULL && m_iOffsetMapping == 0);
10620     m_iOffsetMapping = cMap;
10621     m_pOffsetMapping = pMap;
10622
10623     EE_TO_JIT_TRANSITION();
10624 }
10625
10626 void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
10627 {
10628     CONTRACTL {
10629         SO_TOLERANT;
10630         THROWS;
10631         GC_TRIGGERS;
10632         MODE_PREEMPTIVE;
10633     } CONTRACTL_END;
10634
10635     JIT_TO_EE_TRANSITION();
10636
10637     // We receive ownership of the array
10638     _ASSERTE(m_pNativeVarInfo == NULL && m_iNativeVarInfo == 0);
10639     m_iNativeVarInfo = cVars;
10640     m_pNativeVarInfo = vars;
10641
10642     EE_TO_JIT_TRANSITION();
10643 }
10644
10645 void CEEJitInfo::CompressDebugInfo()
10646 {
10647     CONTRACTL {
10648         SO_TOLERANT;
10649         THROWS;
10650         GC_TRIGGERS;
10651         MODE_PREEMPTIVE;
10652     } CONTRACTL_END;
10653
10654     // Don't track JIT info for DynamicMethods.
10655     if (m_pMethodBeingCompiled->IsDynamicMethod())
10656         return;
10657
10658     if (m_iOffsetMapping == 0 && m_iNativeVarInfo == 0)
10659         return;
10660
10661     JIT_TO_EE_TRANSITION();
10662
10663     EX_TRY
10664     {
10665         PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars(
10666             m_pOffsetMapping, m_iOffsetMapping,
10667             m_pNativeVarInfo, m_iNativeVarInfo,
10668             NULL, 
10669             m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap());
10670
10671         GetCodeHeader()->SetDebugInfo(pDebugInfo);
10672     }
10673     EX_CATCH
10674     {
10675         // Just ignore exceptions here. The debugger's structures will still be in a consistent state.
10676     }
10677     EX_END_CATCH(SwallowAllExceptions)
10678
10679     EE_TO_JIT_TRANSITION();
10680 }
10681
10682 void reservePersonalityRoutineSpace(ULONG &unwindSize)
10683 {
10684 #if defined(_TARGET_X86_)
10685     // Do nothing
10686 #elif defined(_TARGET_AMD64_)
10687     // Add space for personality routine, it must be 4-byte aligned.
10688     // Everything in the UNWIND_INFO up to the variable-sized UnwindCodes
10689     // array has already had its size included in unwindSize by the caller.
10690     unwindSize += sizeof(ULONG);
10691
10692     // Note that the count of unwind codes (2 bytes each) is stored as a UBYTE
10693     // So the largest size could be 510 bytes, plus the header and language
10694     // specific stuff.  This can't overflow.
10695
10696     _ASSERTE(FitsInU4(unwindSize + sizeof(ULONG)));
10697     unwindSize = (ULONG)(ALIGN_UP(unwindSize, sizeof(ULONG)));
10698 #elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
10699     // The JIT passes in a 4-byte aligned block of unwind data.
10700     _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
10701
10702     // Add space for personality routine, it must be 4-byte aligned.
10703     unwindSize += sizeof(ULONG);
10704 #else
10705     PORTABILITY_ASSERT("reservePersonalityRoutineSpace");
10706 #endif // !defined(_TARGET_AMD64_)
10707
10708 }
10709 // Reserve memory for the method/funclet's unwind information.
10710 // Note that this must be called before allocMem. It should be
10711 // called once for the main method, once for every funclet, and
10712 // once for every block of cold code for which allocUnwindInfo
10713 // will be called.
10714 //
10715 // This is necessary because jitted code must allocate all the
10716 // memory needed for the unwindInfo at the allocMem call.
10717 // For prejitted code we split up the unwinding information into
10718 // separate sections .rdata and .pdata.
10719 //
10720 void CEEJitInfo::reserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize)
10721 {
10722 #ifdef WIN64EXCEPTIONS
10723     CONTRACTL {
10724         SO_TOLERANT;
10725         NOTHROW;
10726         GC_NOTRIGGER;
10727         MODE_PREEMPTIVE;
10728     }
10729     CONTRACTL_END;
10730
10731     JIT_TO_EE_TRANSITION_LEAF();
10732
10733     CONSISTENCY_CHECK_MSG(!isColdCode, "Hot/Cold splitting is not supported in jitted code");
10734     _ASSERTE_MSG(m_theUnwindBlock == NULL,
10735         "reserveUnwindInfo() can only be called before allocMem(), but allocMem() has already been called. "
10736         "This may indicate the JIT has hit a NO_WAY assert after calling allocMem(), and is re-JITting. "
10737         "Set COMPlus_JitBreakOnBadCode=1 and rerun to get the real error.");
10738
10739     ULONG currentSize  = unwindSize;
10740
10741     reservePersonalityRoutineSpace(currentSize);
10742
10743     m_totalUnwindSize += currentSize;
10744
10745     m_totalUnwindInfos++;
10746
10747     EE_TO_JIT_TRANSITION_LEAF();
10748 #else // WIN64EXCEPTIONS
10749     LIMITED_METHOD_CONTRACT;
10750     // Dummy implementation to make cross-platform altjit work
10751 #endif // WIN64EXCEPTIONS
10752 }
10753
10754 // Allocate and initialize the .rdata and .pdata for this method or
10755 // funclet and get the block of memory needed for the machine specific
10756 // unwind information (the info for crawling the stack frame).
10757 // Note that allocMem must be called first.
10758 //
10759 // The pHotCode parameter points at the first byte of the code of the method
10760 // The startOffset and endOffset are the region (main or funclet) that
10761 // we are to allocate and create .rdata and .pdata for.
10762 // The pUnwindBlock is copied and contains the .pdata unwind area
10763 //
10764 // Parameters:
10765 //
10766 //    pHotCode        main method code buffer, always filled in
10767 //    pColdCode       always NULL for jitted code
10768 //    startOffset     start of code block, relative to pHotCode
10769 //    endOffset       end of code block, relative to pHotCode
10770 //    unwindSize      size of unwind info pointed to by pUnwindBlock
10771 //    pUnwindBlock    pointer to unwind info
10772 //    funcKind        type of funclet (main method code, handler, filter)
10773 //
10774 void CEEJitInfo::allocUnwindInfo (
10775         BYTE *              pHotCode,              /* IN */
10776         BYTE *              pColdCode,             /* IN */
10777         ULONG               startOffset,           /* IN */
10778         ULONG               endOffset,             /* IN */
10779         ULONG               unwindSize,            /* IN */
10780         BYTE *              pUnwindBlock,          /* IN */
10781         CorJitFuncKind      funcKind               /* IN */
10782         )
10783 {
10784 #ifdef WIN64EXCEPTIONS
10785     CONTRACTL {
10786         SO_TOLERANT;
10787         THROWS;
10788         GC_TRIGGERS;
10789         MODE_PREEMPTIVE;
10790         PRECONDITION(m_theUnwindBlock != NULL);
10791         PRECONDITION(m_usedUnwindSize < m_totalUnwindSize);
10792         PRECONDITION(m_usedUnwindInfos < m_totalUnwindInfos);
10793         PRECONDITION(endOffset <= m_codeSize);
10794     } CONTRACTL_END;
10795
10796     CONSISTENCY_CHECK_MSG(pColdCode == NULL, "Hot/Cold code splitting not supported for jitted code");
10797
10798     JIT_TO_EE_TRANSITION();
10799
10800     //
10801     // We add one callback-type dynamic function table per range section.
10802     // Therefore, the RUNTIME_FUNCTION info is always relative to the
10803     // image base contained in the dynamic function table, which happens
10804     // to be the LowAddress of the range section.  The JIT has no
10805     // knowledge of the range section, so it gives us offsets that are
10806     // relative to the beginning of the method (pHotCode) and we allocate
10807     // and initialize the RUNTIME_FUNCTION data and record its location
10808     // in this function.
10809     //
10810
10811     if (funcKind != CORJIT_FUNC_ROOT)
10812     {
10813         // The main method should be emitted before funclets
10814         _ASSERTE(m_usedUnwindInfos > 0);
10815     }
10816
10817     PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeader->GetUnwindInfo(m_usedUnwindInfos);
10818     m_usedUnwindInfos++;
10819
10820     // Make sure that the RUNTIME_FUNCTION is aligned on a DWORD sized boundary
10821     _ASSERTE(IS_ALIGNED(pRuntimeFunction, sizeof(DWORD)));
10822
10823     UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *) &(m_theUnwindBlock[m_usedUnwindSize]);
10824     m_usedUnwindSize += unwindSize;
10825
10826     reservePersonalityRoutineSpace(m_usedUnwindSize);
10827
10828     _ASSERTE(m_usedUnwindSize <= m_totalUnwindSize);
10829
10830     // Make sure that the UnwindInfo is aligned
10831     _ASSERTE(IS_ALIGNED(pUnwindInfo, sizeof(ULONG)));
10832
10833     /* Calculate Image Relative offset to add to the jit generated unwind offsets */     
10834
10835     TADDR baseAddress = m_moduleBase;
10836
10837     size_t currentCodeSizeT = (size_t)pHotCode - baseAddress;
10838
10839     /* Check if currentCodeSizeT offset fits in 32-bits */
10840     if (!FitsInU4(currentCodeSizeT))
10841     {
10842         _ASSERTE(!"Bad currentCodeSizeT");
10843         COMPlusThrowHR(E_FAIL);
10844     }
10845
10846     /* Check if EndAddress offset fits in 32-bit */
10847     if (!FitsInU4(currentCodeSizeT + endOffset))
10848     {
10849         _ASSERTE(!"Bad currentCodeSizeT");
10850         COMPlusThrowHR(E_FAIL);
10851     }
10852
10853     unsigned currentCodeOffset = (unsigned) currentCodeSizeT;
10854
10855     /* Calculate Unwind Info delta */
10856     size_t unwindInfoDeltaT = (size_t) pUnwindInfo - baseAddress;
10857
10858     /* Check if unwindDeltaT offset fits in 32-bits */
10859     if (!FitsInU4(unwindInfoDeltaT))
10860     {
10861         _ASSERTE(!"Bad unwindInfoDeltaT");
10862         COMPlusThrowHR(E_FAIL);
10863     }
10864
10865     unsigned unwindInfoDelta = (unsigned) unwindInfoDeltaT;
10866
10867     RUNTIME_FUNCTION__SetBeginAddress(pRuntimeFunction, currentCodeOffset + startOffset);
10868
10869 #ifdef _TARGET_AMD64_
10870     pRuntimeFunction->EndAddress        = currentCodeOffset + endOffset;
10871 #endif
10872
10873     RUNTIME_FUNCTION__SetUnwindInfoAddress(pRuntimeFunction, unwindInfoDelta);
10874
10875 #ifdef _DEBUG
10876     if (funcKind != CORJIT_FUNC_ROOT)
10877     {
10878         // Check the the new funclet doesn't overlap any existing funclet.
10879
10880         for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++)
10881         {
10882             PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeader->GetUnwindInfo(iUnwindInfo);
10883             _ASSERTE((   RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress)
10884                      || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction)));
10885         }
10886     }
10887 #endif // _DEBUG
10888
10889     /* Copy the UnwindBlock */
10890     memcpy(pUnwindInfo, pUnwindBlock, unwindSize);
10891
10892 #if defined(_TARGET_X86_)
10893
10894     // Do NOTHING
10895
10896 #elif defined(_TARGET_AMD64_)
10897
10898     pUnwindInfo->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
10899
10900     ULONG * pPersonalityRoutine = (ULONG*)ALIGN_UP(&(pUnwindInfo->UnwindCode[pUnwindInfo->CountOfUnwindCodes]), sizeof(ULONG));
10901     *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
10902
10903 #elif defined(_TARGET_ARM64_)
10904
10905     *(LONG *)pUnwindInfo |= (1 << 20); // X bit
10906
10907     ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
10908     *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
10909
10910 #elif defined(_TARGET_ARM_)
10911
10912     *(LONG *)pUnwindInfo |= (1 << 20); // X bit
10913
10914     ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
10915     *pPersonalityRoutine = (TADDR)ProcessCLRException - baseAddress;
10916
10917 #endif
10918
10919 #if defined(_TARGET_AMD64_)
10920     // Publish the new unwind information in a way that the ETW stack crawler can find
10921     if (m_usedUnwindInfos == m_totalUnwindInfos)
10922         UnwindInfoTable::PublishUnwindInfoForMethod(baseAddress, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos);
10923 #endif // defined(_TARGET_AMD64_)
10924
10925     EE_TO_JIT_TRANSITION();
10926 #else // WIN64EXCEPTIONS
10927     LIMITED_METHOD_CONTRACT;
10928     // Dummy implementation to make cross-platform altjit work
10929 #endif // WIN64EXCEPTIONS
10930 }
10931
10932 void CEEJitInfo::recordCallSite(ULONG                 instrOffset,
10933                                 CORINFO_SIG_INFO *    callSig,
10934                                 CORINFO_METHOD_HANDLE methodHandle)
10935 {
10936     // Currently, only testing tools use this method. The EE itself doesn't need record this information.
10937     // N.B. The memory that callSig points to is managed by the JIT and isn't guaranteed to be around after
10938     // this function returns, so future implementations should copy the sig info if they want it to persist.
10939     LIMITED_METHOD_CONTRACT;
10940 }
10941
10942 // This is a variant for AMD64 or other machines that
10943 // cannot always hold the destination address in a 32-bit location
10944 // A relocation is recorded if we are pre-jitting.
10945 // A jump thunk may be inserted if we are jitting
10946
10947 void CEEJitInfo::recordRelocation(void * location,
10948                                   void * target,
10949                                   WORD   fRelocType,
10950                                   WORD   slot,
10951                                   INT32  addlDelta)
10952 {
10953     CONTRACTL {
10954         SO_TOLERANT;
10955         THROWS;
10956         GC_TRIGGERS;
10957         MODE_PREEMPTIVE;
10958     } CONTRACTL_END;
10959
10960 #ifdef _WIN64
10961     JIT_TO_EE_TRANSITION();
10962
10963     INT64 delta;
10964
10965     switch (fRelocType)
10966     {
10967     case IMAGE_REL_BASED_DIR64:
10968         // Write 64-bits into location
10969         *((UINT64 *) ((BYTE *) location + slot)) = (UINT64) target;
10970         break;
10971
10972 #ifdef _TARGET_AMD64_
10973     case IMAGE_REL_BASED_REL32:
10974         {
10975             target = (BYTE *)target + addlDelta;
10976
10977             INT32 * fixupLocation = (INT32 *) ((BYTE *) location + slot);
10978             BYTE * baseAddr = (BYTE *)fixupLocation + sizeof(INT32);
10979
10980             delta  = (INT64)((BYTE *)target - baseAddr);
10981
10982             //
10983             // Do we need to insert a jump stub to make the source reach the target?
10984             //
10985             // Note that we cannot stress insertion of jump stub by inserting it unconditionally. JIT records the relocations 
10986             // for intra-module jumps and calls. It does not expect the register used by the jump stub to be trashed.
10987             //
10988             if (!FitsInI4(delta))
10989             {
10990                 if (m_fAllowRel32)
10991                 {
10992                     //
10993                     // When m_fAllowRel32 == TRUE, the JIT will use REL32s for both data addresses and direct code targets.
10994                     // Since we cannot tell what the relocation is for, we have to defensively retry.
10995                     //
10996                     m_fRel32Overflow = TRUE;
10997                     delta = 0;
10998                 }
10999                 else
11000                 {
11001                     //
11002                     // When m_fAllowRel32 == FALSE, the JIT will use a REL32s for direct code targets only.
11003                     // Use jump stub.
11004                     // 
11005                     delta = rel32UsingJumpStub(fixupLocation, (PCODE)target, m_pMethodBeingCompiled);
11006                 }
11007             }
11008
11009             LOG((LF_JIT, LL_INFO100000, "Encoded a PCREL32 at" FMT_ADDR "to" FMT_ADDR "+%d,  delta is 0x%04x\n",
11010                  DBG_ADDR(fixupLocation), DBG_ADDR(target), addlDelta, delta));
11011
11012             // Write the 32-bits pc-relative delta into location
11013             *fixupLocation = (INT32) delta;
11014         }
11015         break;
11016 #endif // _TARGET_AMD64_
11017
11018 #ifdef _TARGET_ARM64_
11019     case IMAGE_REL_ARM64_BRANCH26:   // 26 bit offset << 2 & sign ext, for B and BL
11020         {
11021             _ASSERTE(slot == 0);
11022             _ASSERTE(addlDelta == 0);
11023
11024             PCODE branchTarget  = (PCODE) target;
11025             _ASSERTE((branchTarget & 0x3) == 0);   // the low two bits must be zero
11026
11027             PCODE fixupLocation = (PCODE) location;
11028             _ASSERTE((fixupLocation & 0x3) == 0);  // the low two bits must be zero
11029
11030             delta = (INT64)(branchTarget - fixupLocation);
11031             _ASSERTE((delta & 0x3) == 0);          // the low two bits must be zero
11032
11033             UINT32 branchInstr = *((UINT32*) fixupLocation);
11034             branchInstr &= 0xFC000000;  // keep bits 31-26
11035             _ASSERTE((branchInstr & 0x7FFFFFFF) == 0x14000000);  // Must be B or BL
11036
11037             //
11038             // Do we need to insert a jump stub to make the source reach the target?
11039             //
11040             //
11041             if (!FitsInRel28(delta))
11042             {
11043                 // Use jump stub.
11044                 // 
11045                 TADDR baseAddr = (TADDR)fixupLocation;
11046                 TADDR loAddr   = baseAddr - 0x08000000;   // -2^27
11047                 TADDR hiAddr   = baseAddr + 0x07FFFFFF;   // +2^27-1
11048
11049                 // Check for the wrap around cases  
11050                 if (loAddr > baseAddr)
11051                     loAddr = UINT64_MIN; // overflow
11052                 if (hiAddr < baseAddr)
11053                     hiAddr = UINT64_MAX; // overflow
11054
11055                 PCODE jumpStubAddr = ExecutionManager::jumpStub(m_pMethodBeingCompiled,
11056                                                                 (PCODE)  target,
11057                                                                 (BYTE *) loAddr,
11058                                                                 (BYTE *) hiAddr);
11059
11060                 delta = (INT64)(jumpStubAddr - fixupLocation);
11061
11062                 if (!FitsInRel28(delta))
11063                 {
11064                     _ASSERTE(!"jump stub was not in expected range");
11065                     EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
11066                 }
11067
11068                 LOG((LF_JIT, LL_INFO100000, "Using JumpStub at" FMT_ADDR "that jumps to" FMT_ADDR "\n",
11069                      DBG_ADDR(jumpStubAddr), DBG_ADDR(target)));
11070             }
11071
11072             LOG((LF_JIT, LL_INFO100000, "Encoded a BRANCH26 at" FMT_ADDR "to" FMT_ADDR ",  delta is 0x%04x\n",
11073                  DBG_ADDR(fixupLocation), DBG_ADDR(target), delta));
11074
11075             _ASSERTE(FitsInRel28(delta));
11076
11077             PutArm64Rel28((UINT32*) fixupLocation, (INT32)delta);
11078         }
11079         break;
11080
11081     case IMAGE_REL_ARM64_PAGEBASE_REL21:
11082         {
11083             _ASSERTE(slot == 0);
11084             _ASSERTE(addlDelta == 0);
11085
11086             // Write the 21 bits pc-relative page address into location.
11087             INT64 targetPage = (INT64)target & 0xFFFFFFFFFFFFF000LL;
11088             INT64 lcoationPage = (INT64)location & 0xFFFFFFFFFFFFF000LL;
11089             INT64 relPage = (INT64)(targetPage - lcoationPage);
11090             INT32 imm21 = (INT32)(relPage >> 12) & 0x1FFFFF;
11091             PutArm64Rel21((UINT32 *)location, imm21);
11092         }
11093         break;
11094
11095     case IMAGE_REL_ARM64_PAGEOFFSET_12A:
11096         {
11097             _ASSERTE(slot == 0);
11098             _ASSERTE(addlDelta == 0);
11099
11100             // Write the 12 bits page offset into location.
11101             INT32 imm12 = (INT32)target & 0xFFFLL;
11102             PutArm64Rel12((UINT32 *)location, imm12);
11103         }
11104         break;
11105
11106 #endif // _TARGET_ARM64_
11107
11108     default:
11109         _ASSERTE(!"Unknown reloc type");
11110         break;
11111     }
11112
11113     EE_TO_JIT_TRANSITION();
11114 #else // _WIN64
11115     JIT_TO_EE_TRANSITION_LEAF();
11116
11117     // Nothing to do on 32-bit
11118
11119     EE_TO_JIT_TRANSITION_LEAF();
11120 #endif // _WIN64
11121 }
11122
11123 WORD CEEJitInfo::getRelocTypeHint(void * target)
11124 {
11125     CONTRACTL {
11126         SO_TOLERANT;
11127         THROWS;
11128         GC_TRIGGERS;
11129         MODE_PREEMPTIVE;
11130     } CONTRACTL_END;
11131
11132 #ifdef _TARGET_AMD64_
11133     if (m_fAllowRel32)
11134     {
11135         // The JIT calls this method for data addresses only. It always uses REL32s for direct code targets.
11136         if (IsPreferredExecutableRange(target))
11137             return IMAGE_REL_BASED_REL32;
11138     }
11139 #endif // _TARGET_AMD64_
11140
11141     // No hints
11142     return (WORD)-1;
11143 }
11144
11145 void CEEJitInfo::getModuleNativeEntryPointRange(void** pStart, void** pEnd)
11146 {
11147     CONTRACTL {
11148         SO_TOLERANT;
11149         NOTHROW;
11150         GC_NOTRIGGER;
11151         MODE_PREEMPTIVE;
11152     }
11153     CONTRACTL_END;
11154
11155     JIT_TO_EE_TRANSITION_LEAF();
11156
11157     *pStart = *pEnd = 0;
11158
11159     EE_TO_JIT_TRANSITION_LEAF();
11160 }
11161
11162 DWORD CEEJitInfo::getExpectedTargetArchitecture()
11163 {
11164     LIMITED_METHOD_CONTRACT;
11165
11166     return IMAGE_FILE_MACHINE_NATIVE;
11167 }
11168
11169 void CEEInfo::JitProcessShutdownWork()
11170 {
11171     LIMITED_METHOD_CONTRACT;
11172
11173     EEJitManager* jitMgr = ExecutionManager::GetEEJitManager();
11174
11175     // If we didn't load the JIT, there is no work to do.
11176     if (jitMgr->m_jit != NULL)
11177     {
11178         // Do the shutdown work.
11179         jitMgr->m_jit->ProcessShutdownWork(this);
11180     }
11181
11182 #ifdef ALLOW_SXS_JIT
11183     if (jitMgr->m_alternateJit != NULL)
11184     {
11185         jitMgr->m_alternateJit->ProcessShutdownWork(this);
11186     }
11187 #endif // ALLOW_SXS_JIT
11188 }
11189
11190 /*********************************************************************/
11191 InfoAccessType CEEJitInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
11192                                                   mdToken metaTok,
11193                                                   void **ppValue)
11194 {
11195     CONTRACTL {
11196         SO_TOLERANT;
11197         THROWS;
11198         GC_TRIGGERS;
11199         MODE_PREEMPTIVE;
11200     } CONTRACTL_END;
11201
11202     InfoAccessType result = IAT_PVALUE;
11203
11204     JIT_TO_EE_TRANSITION();
11205
11206     _ASSERTE(ppValue != NULL);
11207
11208     if (IsDynamicScope(scopeHnd))
11209     {
11210         *ppValue = (LPVOID)GetDynamicResolver(scopeHnd)->ConstructStringLiteral(metaTok);
11211     }
11212     else
11213     {
11214         *ppValue = (LPVOID)ConstructStringLiteral(scopeHnd, metaTok); // throws
11215     }
11216
11217     EE_TO_JIT_TRANSITION();
11218
11219     return result;
11220 }
11221
11222 /*********************************************************************/
11223 InfoAccessType CEEJitInfo::emptyStringLiteral(void ** ppValue)
11224 {
11225     CONTRACTL {
11226         SO_TOLERANT;
11227         THROWS;
11228         GC_TRIGGERS;
11229         MODE_PREEMPTIVE;
11230     } CONTRACTL_END;
11231
11232     InfoAccessType result = IAT_PVALUE;
11233
11234     if(NingenEnabled())
11235     {
11236         *ppValue = NULL;
11237         return result;
11238     }
11239
11240     JIT_TO_EE_TRANSITION();
11241     *ppValue = StringObject::GetEmptyStringRefPtr();
11242     EE_TO_JIT_TRANSITION();
11243
11244     return result;
11245 }
11246
11247 /*********************************************************************/
11248 void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
11249                                   void **ppIndirection)
11250 {
11251     CONTRACTL {
11252         SO_TOLERANT;
11253         THROWS;
11254         GC_TRIGGERS;
11255         MODE_PREEMPTIVE;
11256     } CONTRACTL_END;
11257
11258     void *result = NULL;
11259
11260     if (ppIndirection != NULL)
11261         *ppIndirection = NULL;
11262
11263     // Do not bother with initialization if we are only verifying the method.
11264     if (isVerifyOnly())
11265     {
11266         return (void *)0x10;
11267     }
11268
11269     JIT_TO_EE_TRANSITION();
11270
11271     FieldDesc* field = (FieldDesc*) fieldHnd;
11272
11273     MethodTable* pMT = field->GetEnclosingMethodTable();
11274
11275     _ASSERTE(!pMT->ContainsGenericVariables());
11276
11277     // We must not call here for statics of collectible types.
11278     _ASSERTE(!pMT->Collectible());
11279
11280     void *base = NULL;
11281
11282     if (!field->IsRVA())
11283     {
11284         // <REVISIT_TODO>@todo: assert that the current method being compiled is unshared</REVISIT_TODO>
11285
11286         // Allocate space for the local class if necessary, but don't trigger
11287         // class construction.
11288         DomainLocalModule *pLocalModule = pMT->GetDomainLocalModule();
11289         pLocalModule->PopulateClass(pMT);
11290
11291         GCX_COOP();
11292
11293         base = (void *) field->GetBase();
11294     }
11295
11296     result = field->GetStaticAddressHandle(base);
11297
11298     EE_TO_JIT_TRANSITION();
11299
11300     return result;
11301 }
11302
11303 static void *GetClassSync(MethodTable *pMT)
11304 {
11305     STANDARD_VM_CONTRACT;
11306
11307     GCX_COOP();
11308
11309     OBJECTREF ref = pMT->GetManagedClassObject();
11310     return (void*)ref->GetSyncBlock()->GetMonitor();
11311 }
11312
11313 /*********************************************************************/
11314 void* CEEJitInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
11315                                 void **ppIndirection)
11316 {
11317     CONTRACTL {
11318         SO_TOLERANT;
11319         THROWS;
11320         GC_TRIGGERS;
11321         MODE_PREEMPTIVE;
11322     } CONTRACTL_END;
11323
11324     void * result = NULL;
11325
11326     if (ppIndirection != NULL)
11327         *ppIndirection = NULL;
11328
11329     JIT_TO_EE_TRANSITION();
11330
11331     result = GetClassSync((GetMethod(ftnHnd))->GetMethodTable());
11332
11333     EE_TO_JIT_TRANSITION();
11334
11335     return result;
11336 }
11337
11338 /*********************************************************************/
11339 HRESULT CEEJitInfo::allocBBProfileBuffer (
11340     ULONG                         count,
11341     ICorJitInfo::ProfileBuffer ** profileBuffer
11342     )
11343 {
11344     CONTRACTL {
11345         SO_TOLERANT;
11346         THROWS;
11347         GC_TRIGGERS;
11348         MODE_PREEMPTIVE;
11349     } CONTRACTL_END;
11350
11351     HRESULT hr = E_FAIL;
11352
11353     JIT_TO_EE_TRANSITION();
11354
11355 #ifdef FEATURE_PREJIT
11356
11357     // We need to know the code size. Typically we can get the code size
11358     // from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so
11359     // for that case we need to use DynamicResolver to get the code size.
11360
11361     unsigned codeSize = 0; 
11362     if (m_pMethodBeingCompiled->IsDynamicMethod())
11363     {
11364         unsigned stackSize, ehSize;
11365         CorInfoOptions options;
11366         DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver();        
11367         pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize);
11368     }
11369     else
11370     {
11371         codeSize = m_ILHeader->GetCodeSize();    
11372     }
11373     
11374     *profileBuffer = m_pMethodBeingCompiled->GetLoaderModule()->AllocateProfileBuffer(m_pMethodBeingCompiled->GetMemberDef(), count, codeSize);
11375     hr = (*profileBuffer ? S_OK : E_OUTOFMEMORY);
11376 #else // FEATURE_PREJIT
11377     _ASSERTE(!"allocBBProfileBuffer not implemented on CEEJitInfo!");
11378     hr = E_NOTIMPL;
11379 #endif // !FEATURE_PREJIT
11380
11381     EE_TO_JIT_TRANSITION();
11382     
11383     return hr;
11384 }
11385
11386 // Consider implementing getBBProfileData on CEEJitInfo.  This will allow us
11387 // to use profile info in codegen for non zapped images.
11388 HRESULT CEEJitInfo::getBBProfileData (
11389     CORINFO_METHOD_HANDLE         ftnHnd,
11390     ULONG *                       size,
11391     ICorJitInfo::ProfileBuffer ** profileBuffer,
11392     ULONG *                       numRuns
11393     )
11394 {
11395     LIMITED_METHOD_CONTRACT;
11396     _ASSERTE(!"getBBProfileData not implemented on CEEJitInfo!");
11397     return E_NOTIMPL;
11398 }
11399
11400 void CEEJitInfo::allocMem (
11401     ULONG               hotCodeSize,    /* IN */
11402     ULONG               coldCodeSize,   /* IN */
11403     ULONG               roDataSize,     /* IN */
11404     ULONG               xcptnsCount,    /* IN */
11405     CorJitAllocMemFlag  flag,           /* IN */
11406     void **             hotCodeBlock,   /* OUT */
11407     void **             coldCodeBlock,  /* OUT */
11408     void **             roDataBlock     /* OUT */
11409             )
11410 {
11411     CONTRACTL {
11412         SO_TOLERANT;
11413         THROWS;
11414         GC_TRIGGERS;
11415         MODE_PREEMPTIVE;
11416     } CONTRACTL_END;
11417
11418     JIT_TO_EE_TRANSITION();
11419
11420     _ASSERTE(coldCodeSize == 0);
11421     if (coldCodeBlock)
11422     {
11423         *coldCodeBlock = NULL;
11424     }
11425
11426     ULONG codeSize      = hotCodeSize;
11427     void **codeBlock    = hotCodeBlock;
11428
11429     S_SIZE_T totalSize = S_SIZE_T(codeSize);
11430
11431     size_t roDataAlignment = sizeof(void*);
11432     if ((flag & CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN)!= 0)
11433     {
11434         roDataAlignment = 16;
11435     }
11436     else if (roDataSize >= 8)
11437     {
11438         roDataAlignment = 8;
11439     }
11440     if (roDataSize > 0)
11441     {
11442         size_t codeAlignment = ((flag & CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN)!= 0)
11443                                ? 16 : sizeof(void*);
11444         totalSize.AlignUp(codeAlignment);
11445         if (roDataAlignment > codeAlignment) {
11446             // Add padding to align read-only data.
11447             totalSize += (roDataAlignment - codeAlignment);
11448         }
11449         totalSize += roDataSize;
11450     }
11451
11452 #ifdef WIN64EXCEPTIONS
11453     totalSize.AlignUp(sizeof(DWORD));
11454     totalSize += m_totalUnwindSize;
11455 #endif
11456
11457     _ASSERTE(m_CodeHeader == 0 &&
11458             // The jit-compiler sometimes tries to compile a method a second time
11459             // if it failed the first time. In such a situation, m_CodeHeader may
11460             // have already been assigned. Its OK to ignore this assert in such a
11461             // situation - we will leak some memory, but that is acceptable
11462             // since this should happen very rarely.
11463             "Note that this may fire if the JITCompiler tries to recompile a method");
11464
11465     if( totalSize.IsOverflow() )
11466     {
11467         COMPlusThrowHR(CORJIT_OUTOFMEM);
11468     }
11469
11470     m_CodeHeader = m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), flag
11471 #ifdef WIN64EXCEPTIONS
11472                                            , m_totalUnwindInfos
11473                                            , &m_moduleBase
11474 #endif
11475                                            );
11476
11477     BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress();
11478
11479     *codeBlock = current;
11480     current += codeSize;
11481
11482     if (roDataSize > 0)
11483     {
11484         current = (BYTE *)ALIGN_UP(current, roDataAlignment);
11485         *roDataBlock = current;
11486         current += roDataSize;
11487     }
11488     else
11489     {
11490         *roDataBlock = NULL;
11491     }
11492
11493 #ifdef WIN64EXCEPTIONS
11494     current = (BYTE *)ALIGN_UP(current, sizeof(DWORD));
11495
11496     m_theUnwindBlock = current;
11497     current += m_totalUnwindSize;
11498 #endif
11499
11500     _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value());
11501
11502 #ifdef _DEBUG
11503     m_codeSize = codeSize;
11504 #endif  // _DEBUG
11505
11506     EE_TO_JIT_TRANSITION();
11507 }
11508
11509 /*********************************************************************/
11510 void * CEEJitInfo::allocGCInfo (size_t size)
11511 {
11512     CONTRACTL {
11513         SO_TOLERANT;
11514         THROWS;
11515         GC_TRIGGERS;
11516         MODE_PREEMPTIVE;
11517     } CONTRACTL_END;
11518
11519     void * block = NULL;
11520
11521     JIT_TO_EE_TRANSITION();
11522
11523     _ASSERTE(m_CodeHeader != 0);
11524     _ASSERTE(m_CodeHeader->GetGCInfo() == 0);
11525
11526 #ifdef _WIN64
11527     if (size & 0xFFFFFFFF80000000LL)
11528     {
11529         COMPlusThrowHR(CORJIT_OUTOFMEM);
11530     }
11531 #endif // _WIN64
11532
11533     block = m_jitManager->allocGCInfo(m_CodeHeader,(DWORD)size, &m_GCinfo_len);
11534     if (!block)
11535     {
11536         COMPlusThrowHR(CORJIT_OUTOFMEM);
11537     }
11538
11539     _ASSERTE(m_CodeHeader->GetGCInfo() != 0 && block == m_CodeHeader->GetGCInfo());
11540
11541     EE_TO_JIT_TRANSITION();
11542
11543     return block;
11544 }
11545
11546 /*********************************************************************/
11547 void CEEJitInfo::setEHcount (
11548         unsigned      cEH)
11549 {
11550     CONTRACTL {
11551         SO_TOLERANT;
11552         THROWS;
11553         GC_TRIGGERS;
11554         MODE_PREEMPTIVE;
11555     } CONTRACTL_END;
11556
11557     JIT_TO_EE_TRANSITION();
11558
11559     _ASSERTE(cEH != 0);
11560     _ASSERTE(m_CodeHeader != 0);
11561     _ASSERTE(m_CodeHeader->GetEHInfo() == 0);
11562
11563     EE_ILEXCEPTION* ret;
11564     ret = m_jitManager->allocEHInfo(m_CodeHeader,cEH, &m_EHinfo_len);
11565     _ASSERTE(ret);      // allocEHInfo throws if there's not enough memory
11566
11567     _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && m_CodeHeader->GetEHInfo()->EHCount() == cEH);
11568
11569     EE_TO_JIT_TRANSITION();
11570 }
11571
11572 /*********************************************************************/
11573 void CEEJitInfo::setEHinfo (
11574         unsigned      EHnumber,
11575         const CORINFO_EH_CLAUSE* clause)
11576 {
11577     CONTRACTL {
11578         SO_TOLERANT;
11579         THROWS;
11580         GC_TRIGGERS;
11581         MODE_PREEMPTIVE;
11582     } CONTRACTL_END;
11583
11584     JIT_TO_EE_TRANSITION();
11585
11586     // <REVISIT_TODO> Fix make the Code Manager EH clauses EH_INFO+</REVISIT_TODO>
11587     _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && EHnumber < m_CodeHeader->GetEHInfo()->EHCount());
11588
11589     EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeader->GetEHInfo()->EHClause(EHnumber);
11590
11591     pEHClause->TryStartPC     = clause->TryOffset;
11592     pEHClause->TryEndPC       = clause->TryLength;
11593     pEHClause->HandlerStartPC = clause->HandlerOffset;
11594     pEHClause->HandlerEndPC   = clause->HandlerLength;
11595     pEHClause->ClassToken     = clause->ClassToken;
11596     pEHClause->Flags          = (CorExceptionFlag)clause->Flags;
11597
11598     LOG((LF_EH, LL_INFO1000000, "Setting EH clause #%d for %s::%s\n", EHnumber, m_pMethodBeingCompiled->m_pszDebugClassName, m_pMethodBeingCompiled->m_pszDebugMethodName));
11599     LOG((LF_EH, LL_INFO1000000, "    Flags         : 0x%08lx  ->  0x%08lx\n",            clause->Flags,         pEHClause->Flags));
11600     LOG((LF_EH, LL_INFO1000000, "    TryOffset     : 0x%08lx  ->  0x%08lx (startpc)\n",  clause->TryOffset,     pEHClause->TryStartPC));
11601     LOG((LF_EH, LL_INFO1000000, "    TryLength     : 0x%08lx  ->  0x%08lx (endpc)\n",    clause->TryLength,     pEHClause->TryEndPC));
11602     LOG((LF_EH, LL_INFO1000000, "    HandlerOffset : 0x%08lx  ->  0x%08lx\n",            clause->HandlerOffset, pEHClause->HandlerStartPC));
11603     LOG((LF_EH, LL_INFO1000000, "    HandlerLength : 0x%08lx  ->  0x%08lx\n",            clause->HandlerLength, pEHClause->HandlerEndPC));
11604     LOG((LF_EH, LL_INFO1000000, "    ClassToken    : 0x%08lx  ->  0x%08lx\n",            clause->ClassToken,    pEHClause->ClassToken));
11605     LOG((LF_EH, LL_INFO1000000, "    FilterOffset  : 0x%08lx  ->  0x%08lx\n",            clause->FilterOffset,  pEHClause->FilterOffset));
11606
11607     if (m_pMethodBeingCompiled->IsDynamicMethod() &&
11608         ((pEHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) == 0) &&
11609         (clause->ClassToken != NULL))
11610     {
11611         MethodDesc * pMD; FieldDesc * pFD;
11612         m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver()->ResolveToken(clause->ClassToken, (TypeHandle *)&pEHClause->TypeHandle, &pMD, &pFD);
11613         SetHasCachedTypeHandle(pEHClause);
11614         LOG((LF_EH, LL_INFO1000000, "  CachedTypeHandle: 0x%08lx  ->  0x%08lx\n",        clause->ClassToken,    pEHClause->TypeHandle));
11615     }
11616
11617     EE_TO_JIT_TRANSITION();
11618 }
11619
11620 /*********************************************************************/
11621 // get individual exception handler
11622 void CEEJitInfo::getEHinfo(
11623                               CORINFO_METHOD_HANDLE  ftn,      /* IN  */
11624                               unsigned               EHnumber, /* IN  */
11625                               CORINFO_EH_CLAUSE*     clause)   /* OUT */
11626 {
11627     CONTRACTL {
11628         SO_TOLERANT;
11629         THROWS;
11630         GC_TRIGGERS;
11631         MODE_PREEMPTIVE;
11632     } CONTRACTL_END;
11633
11634     JIT_TO_EE_TRANSITION();
11635
11636     if (IsDynamicMethodHandle(ftn))
11637     {
11638         GetMethod(ftn)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
11639     }
11640     else
11641     {
11642         _ASSERTE(ftn == CORINFO_METHOD_HANDLE(m_pMethodBeingCompiled));  // For now only support if the method being jitted
11643         getEHinfoHelper(ftn, EHnumber, clause, m_ILHeader);
11644     }
11645
11646     EE_TO_JIT_TRANSITION();
11647 }
11648 #endif // CROSSGEN_COMPILE
11649
11650 #if defined(CROSSGEN_COMPILE)
11651 EXTERN_C ICorJitCompiler* __stdcall getJit();
11652 #endif // defined(CROSSGEN_COMPILE)
11653
11654 #ifdef FEATURE_INTERPRETER
11655 static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr,
11656                                                       CEEInfo *comp,
11657                                                       struct CORINFO_METHOD_INFO *info,
11658                                                       unsigned flags,
11659                                                       BYTE **nativeEntry,
11660                                                       ULONG *nativeSizeOfCode)
11661 {
11662     STATIC_CONTRACT_THROWS;
11663     STATIC_CONTRACT_GC_TRIGGERS;
11664     STATIC_CONTRACT_MODE_PREEMPTIVE;
11665     STATIC_CONTRACT_SO_INTOLERANT;
11666
11667     SString namespaceOrClassName, methodName, methodSignature;
11668     // Fire an ETW event to mark the beginning of JIT'ing
11669     ETW::MethodLog::MethodJitting(reinterpret_cast<MethodDesc*>(info->ftn), &namespaceOrClassName, &methodName, &methodSignature);
11670
11671     CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode);
11672
11673     // Logically, it would seem that the end-of-JITting ETW even should go here, but it must come after the native code has been
11674     // set for the given method desc, which happens in a caller.
11675
11676     return ret;
11677 }
11678 #endif // FEATURE_INTERPRETER
11679
11680 //
11681 // Helper function because can't have dtors in BEGIN_SO_TOLERANT_CODE.
11682 //
11683 CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr,
11684                                  CEEInfo *comp,
11685                                  struct CORINFO_METHOD_INFO *info,
11686                                  CORJIT_FLAGS jitFlags,
11687                                  BYTE **nativeEntry,
11688                                  ULONG *nativeSizeOfCode)
11689 {
11690     STATIC_CONTRACT_THROWS;
11691     STATIC_CONTRACT_GC_TRIGGERS;
11692     STATIC_CONTRACT_MODE_PREEMPTIVE;
11693     STATIC_CONTRACT_SO_INTOLERANT;
11694
11695     CorJitResult ret = CORJIT_SKIPPED;   // Note that CORJIT_SKIPPED is an error exit status code
11696
11697
11698     comp->setJitFlags(jitFlags);
11699
11700 #ifdef FEATURE_STACK_SAMPLING
11701     // SO_INTOLERANT due to init affecting global state.
11702     static ConfigDWORD s_stackSamplingEnabled;
11703     bool samplingEnabled = (s_stackSamplingEnabled.val(CLRConfig::UNSUPPORTED_StackSamplingEnabled) != 0);
11704 #endif
11705
11706     BEGIN_SO_TOLERANT_CODE(GetThread());
11707
11708
11709 #if defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
11710     if (FAILED(ret) && jitMgr->m_alternateJit
11711 #ifdef FEATURE_STACK_SAMPLING
11712         && (!samplingEnabled || (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)))
11713 #endif
11714        )
11715     {
11716         ret = jitMgr->m_alternateJit->compileMethod( comp,
11717                                                      info,
11718                                                      CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11719                                                      nativeEntry,
11720                                                      nativeSizeOfCode );
11721
11722 #ifdef FEATURE_STACK_SAMPLING
11723         if (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND))
11724         {
11725             // Don't bother with failures if we couldn't collect a trace.
11726             ret = CORJIT_OK;
11727         }
11728 #endif // FEATURE_STACK_SAMPLING
11729
11730         // If we failed to jit, then fall back to the primary Jit.
11731         if (FAILED(ret))
11732         {
11733             // Consider adding this call:
11734             //      ((CEEJitInfo*)comp)->BackoutJitData(jitMgr);
11735             ((CEEJitInfo*)comp)->ResetForJitRetry();
11736             ret = CORJIT_SKIPPED;
11737         }
11738     }
11739 #endif // defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
11740
11741 #ifdef FEATURE_INTERPRETER
11742     static ConfigDWORD s_InterpreterFallback;
11743
11744     bool isInterpreterStub   = false;
11745     bool interpreterFallback = (s_InterpreterFallback.val(CLRConfig::INTERNAL_InterpreterFallback) != 0);
11746
11747     if (interpreterFallback == false)
11748     {
11749         // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
11750         // (We assume that importation is completely architecture-independent, or at least nearly so.)
11751         if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
11752         {
11753             if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
11754             {
11755                 isInterpreterStub = true;
11756             }
11757         }
11758     }
11759     
11760     if (FAILED(ret) && jitMgr->m_jit)
11761     {
11762         ret = CompileMethodWithEtwWrapper(jitMgr, 
11763                                           comp,
11764                                           info,
11765                                           CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11766                                           nativeEntry,
11767                                           nativeSizeOfCode);
11768     }
11769
11770     if (interpreterFallback == true)
11771     {
11772         // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
11773         // (We assume that importation is completely architecture-independent, or at least nearly so.)
11774         if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
11775         {
11776             if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
11777             {
11778                 isInterpreterStub = true;
11779             }
11780         }
11781     }
11782 #else
11783     if (FAILED(ret))
11784     {
11785         ret = jitMgr->m_jit->compileMethod( comp,
11786                                             info,
11787                                             CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11788                                             nativeEntry,
11789                                             nativeSizeOfCode);
11790     }
11791 #endif // FEATURE_INTERPRETER
11792
11793 #if !defined(CROSSGEN_COMPILE)
11794     // Cleanup any internal data structures allocated 
11795     // such as IL code after a successfull JIT compile
11796     // If the JIT fails we keep the IL around and will
11797     // try reJIT the same IL.  VSW 525059
11798     //
11799     if (SUCCEEDED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !((CEEJitInfo*)comp)->JitAgain())
11800     {
11801         ((CEEJitInfo*)comp)->CompressDebugInfo();
11802
11803 #ifdef FEATURE_INTERPRETER
11804         // We do this cleanup in the prestub, where we know whether the method
11805         // has been interpreted.
11806 #else
11807         comp->MethodCompileComplete(info->ftn);
11808 #endif // FEATURE_INTERPRETER
11809     }
11810 #endif // !defined(CROSSGEN_COMPILE)
11811     
11812
11813 #if defined(FEATURE_GDBJIT)
11814     bool isJittedEntry = SUCCEEDED(ret) && *nativeEntry != NULL;
11815
11816 #ifdef FEATURE_INTERPRETER
11817     isJittedEntry &= !isInterpreterStub;
11818 #endif // FEATURE_INTERPRETER
11819
11820     if (isJittedEntry)
11821     {
11822         CodeHeader* pCH = ((CodeHeader*)((PCODE)*nativeEntry & ~1)) - 1;
11823         pCH->SetCalledMethods((PTR_VOID)comp->GetCalledMethods());
11824     }
11825 #endif
11826
11827     END_SO_TOLERANT_CODE;
11828
11829     return ret;
11830 }
11831
11832
11833 /*********************************************************************/
11834 CorJitResult invokeCompileMethod(EEJitManager *jitMgr,
11835                                  CEEInfo *comp,
11836                                  struct CORINFO_METHOD_INFO *info,
11837                                  CORJIT_FLAGS jitFlags,
11838                                  BYTE **nativeEntry,
11839                                  ULONG *nativeSizeOfCode)
11840 {
11841     CONTRACTL {
11842         THROWS;
11843         GC_TRIGGERS;
11844         MODE_COOPERATIVE;
11845     } CONTRACTL_END;
11846     //
11847     // The JIT runs in preemptive mode
11848     //
11849
11850     GCX_PREEMP();
11851
11852     CorJitResult ret = invokeCompileMethodHelper(jitMgr, comp, info, jitFlags, nativeEntry, nativeSizeOfCode);
11853
11854     //
11855     // Verify that we are still in preemptive mode when we return
11856     // from the JIT
11857     //
11858
11859     _ASSERTE(GetThread()->PreemptiveGCDisabled() == FALSE);
11860
11861     return ret;
11862 }
11863
11864 CorJitResult CallCompileMethodWithSEHWrapper(EEJitManager *jitMgr,
11865                                 CEEInfo *comp,
11866                                 struct CORINFO_METHOD_INFO *info,
11867                                 CORJIT_FLAGS flags,
11868                                 BYTE **nativeEntry,
11869                                 ULONG *nativeSizeOfCode,
11870                                 MethodDesc *ftn)
11871 {
11872     // no dynamic contract here because SEH is used, with a finally clause
11873     STATIC_CONTRACT_NOTHROW;
11874     STATIC_CONTRACT_GC_TRIGGERS;
11875
11876     LOG((LF_CORDB, LL_EVERYTHING, "CallCompileMethodWithSEHWrapper called...\n"));
11877
11878     struct Param
11879     {
11880         EEJitManager *jitMgr;
11881         CEEInfo *comp;
11882         struct CORINFO_METHOD_INFO *info;
11883         CORJIT_FLAGS flags;
11884         BYTE **nativeEntry;
11885         ULONG *nativeSizeOfCode;
11886         MethodDesc *ftn;
11887         CorJitResult res;
11888     }; Param param;
11889     param.jitMgr = jitMgr;
11890     param.comp = comp;
11891     param.info = info;
11892     param.flags = flags;
11893     param.nativeEntry = nativeEntry;
11894     param.nativeSizeOfCode = nativeSizeOfCode;
11895     param.ftn = ftn;
11896     param.res = CORJIT_INTERNALERROR;
11897
11898     PAL_TRY(Param *, pParam, &param)
11899     {
11900         //
11901         // Call out to the JIT-compiler
11902         //
11903
11904         pParam->res = invokeCompileMethod( pParam->jitMgr,
11905                                            pParam->comp,
11906                                            pParam->info,
11907                                            pParam->flags,
11908                                            pParam->nativeEntry,
11909                                            pParam->nativeSizeOfCode);
11910     }
11911     PAL_FINALLY
11912     {
11913 #if defined(DEBUGGING_SUPPORTED) && !defined(CROSSGEN_COMPILE)
11914         if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) &&
11915             !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MCJIT_BACKGROUND)
11916 #ifdef FEATURE_STACK_SAMPLING
11917             && !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)
11918 #endif // FEATURE_STACK_SAMPLING
11919            )
11920         {
11921             //
11922             // Notify the debugger that we have successfully jitted the function
11923             //
11924             if (ftn->HasNativeCode())
11925             {
11926                 //
11927                 // Nothing to do here (don't need to notify the debugger
11928                 // because the function has already been successfully jitted)
11929                 //
11930                 // This is the case where we aborted the jit because of a deadlock cycle
11931                 // in initClass.  
11932                 //
11933             }
11934             else
11935             {
11936                 if (g_pDebugInterface)
11937                 {
11938                     if (param.res == CORJIT_OK && !((CEEJitInfo*)param.comp)->JitAgain())
11939                     {
11940                         g_pDebugInterface->JITComplete(ftn, (TADDR) *nativeEntry);
11941                     }
11942                 }
11943             }
11944         }
11945 #endif // DEBUGGING_SUPPORTED && !CROSSGEN_COMPILE
11946     }
11947     PAL_ENDTRY
11948
11949     return param.res;
11950 }
11951
11952 /*********************************************************************/
11953 // Figures out the compile flags that are used by both JIT and NGen
11954
11955 /* static */ CORJIT_FLAGS CEEInfo::GetBaseCompileFlags(MethodDesc * ftn)
11956 {
11957      CONTRACTL {
11958         THROWS;
11959         GC_TRIGGERS;
11960     } CONTRACTL_END;
11961
11962     //
11963     // Figure out the code quality flags
11964     //
11965
11966     CORJIT_FLAGS flags;
11967     if (g_pConfig->JitFramed())
11968         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
11969     if (g_pConfig->JitAlignLoops())
11970         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_ALIGN_LOOPS);
11971     if (ReJitManager::IsReJITEnabled() || g_pConfig->AddRejitNops())
11972         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_REJIT_NOPS);
11973 #ifdef _TARGET_X86_
11974     if (g_pConfig->PInvokeRestoreEsp(ftn->GetModule()->IsPreV4Assembly()))
11975         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PINVOKE_RESTORE_ESP);
11976 #endif // _TARGET_X86_
11977
11978     //See if we should instruct the JIT to emit calls to JIT_PollGC for thread suspension.  If we have a
11979     //non-default value in the EE Config, then use that.  Otherwise select the platform specific default.
11980 #ifdef FEATURE_ENABLE_GCPOLL
11981     EEConfig::GCPollType pollType = g_pConfig->GetGCPollType();
11982     if (EEConfig::GCPOLL_TYPE_POLL == pollType)
11983         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_CALLS);
11984     else if (EEConfig::GCPOLL_TYPE_INLINE == pollType)
11985         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_INLINE);
11986 #endif //FEATURE_ENABLE_GCPOLL
11987
11988     // Set flags based on method's ImplFlags.
11989     if (!ftn->IsNoMetadata())
11990     {
11991          DWORD dwImplFlags = 0;
11992          IfFailThrow(ftn->GetMDImport()->GetMethodImplProps(ftn->GetMemberDef(), NULL, &dwImplFlags));
11993         
11994          if (IsMiNoOptimization(dwImplFlags))
11995          {
11996              flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
11997          }
11998
11999          // Always emit frames for methods marked no-inline (see #define ETW_EBP_FRAMED in the JIT)
12000          if (IsMiNoInlining(dwImplFlags))
12001          {
12002              flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12003          }
12004     }
12005
12006     return flags;
12007 }
12008
12009 /*********************************************************************/
12010 // Figures out (some of) the flags to use to compile the method
12011 // Returns the new set to use
12012
12013 CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags)
12014 {
12015     STANDARD_VM_CONTRACT;
12016
12017     //Right now if we don't have a debug interface on CoreCLR, we can't generate debug info.  So, in those
12018     //cases don't attempt it.
12019     if (!g_pDebugInterface)
12020         return flags;
12021
12022 #ifdef DEBUGGING_SUPPORTED
12023
12024 #ifdef _DEBUG
12025     if (g_pConfig->GenDebuggableCode())
12026         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12027 #endif // _DEBUG
12028
12029 #ifdef EnC_SUPPORTED
12030     if (pModule->IsEditAndContinueEnabled())
12031     {
12032         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_EnC);
12033     }
12034 #endif // EnC_SUPPORTED
12035
12036     // Debug info is always tracked
12037     flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12038 #endif // DEBUGGING_SUPPORTED
12039
12040     if (CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
12041     {
12042         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12043     }
12044
12045     if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12046     {
12047         // If we are only verifying the method, dont need any debug info and this
12048         // prevents getVars()/getBoundaries() from being called unnecessarily.
12049         flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12050         flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12051     }
12052
12053     return flags;
12054 }
12055
12056 CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHOD_INFO * methodInfo)
12057 {
12058     STANDARD_VM_CONTRACT;
12059
12060     _ASSERTE(methodInfo->regionKind ==  CORINFO_REGION_JIT);
12061
12062     //
12063     // Get the compile flags that are shared between JIT and NGen
12064     //
12065     flags.Add(CEEInfo::GetBaseCompileFlags(ftn));
12066
12067     //
12068     // Get CPU specific flags
12069     //
12070     if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12071     {
12072         flags.Add(ExecutionManager::GetEEJitManager()->GetCPUCompileFlags());
12073     }
12074
12075     //
12076     // Find the debugger and profiler related flags
12077     //
12078
12079 #ifdef DEBUGGING_SUPPORTED
12080     flags.Add(GetDebuggerCompileFlags(ftn->GetModule(), flags));
12081 #endif
12082
12083 #ifdef PROFILING_SUPPORTED
12084     if (CORProfilerTrackEnterLeave() && !ftn->IsNoMetadata())
12085         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE);
12086
12087     if (CORProfilerTrackTransitions())
12088         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_NO_PINVOKE_INLINE);
12089 #endif // PROFILING_SUPPORTED
12090
12091     // Set optimization flags
12092     if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT))
12093     {
12094         unsigned optType = g_pConfig->GenOptimizeType();
12095         _ASSERTE(optType <= OPT_RANDOM);
12096
12097         if (optType == OPT_RANDOM)
12098             optType = methodInfo->ILCodeSize % OPT_RANDOM;
12099
12100         if (g_pConfig->JitMinOpts())
12101             flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12102
12103         if (optType == OPT_SIZE)
12104         {
12105             flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SIZE_OPT);
12106         }
12107         else if (optType == OPT_SPEED)
12108         {
12109             flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SPEED_OPT);
12110         }
12111     }
12112
12113     flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12114
12115     if (ftn->IsILStub())
12116     {
12117         // no debug info available for IL stubs
12118         flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12119     }
12120
12121     return flags;
12122 }
12123
12124 // ********************************************************************
12125
12126 // Throw the right type of exception for the given JIT result
12127
12128 void ThrowExceptionForJit(HRESULT res)
12129 {
12130     CONTRACTL
12131     {
12132         THROWS;
12133         GC_NOTRIGGER;
12134         SO_INTOLERANT;
12135         MODE_ANY;
12136     }
12137     CONTRACTL_END;
12138     switch (res)
12139     {
12140         case CORJIT_OUTOFMEM:
12141             COMPlusThrowOM();              
12142             break; 
12143             
12144 #ifdef _TARGET_X86_
12145         // Currently, only x86 JIT returns adequate error codes. The x86 JIT is also the
12146         // JIT that has more limitations and given that to get this message for 64 bit
12147         // is going to require some code churn (either changing their EH handlers or
12148         // fixing the 3 or 4 code sites they have that return CORJIT_INTERNALERROR independently
12149         // of the error, the least risk fix is making this x86 only.
12150         case CORJIT_INTERNALERROR:
12151             COMPlusThrow(kInvalidProgramException, (UINT) IDS_EE_JIT_COMPILER_ERROR);
12152             break;   
12153 #endif
12154
12155         case CORJIT_BADCODE:
12156         default:                    
12157             COMPlusThrow(kInvalidProgramException);                                            
12158             break;
12159     }
12160  }
12161
12162 // ********************************************************************
12163 #ifdef _DEBUG
12164 LONG g_JitCount = 0;
12165 #endif
12166
12167 //#define PERF_TRACK_METHOD_JITTIMES
12168 #ifdef _TARGET_AMD64_
12169 BOOL g_fAllowRel32 = TRUE;
12170 #endif
12171
12172
12173 // ********************************************************************
12174 //                  README!!
12175 // ********************************************************************
12176
12177 // The reason that this is named UnsafeJitFunction is that this helper
12178 // method is not thread safe!  When multiple threads get in here for
12179 // the same pMD, ALL of them MUST return the SAME value.
12180 // To insure that this happens you must call MakeJitWorker.
12181 // It creates a DeadlockAware list of methods being jitted and prevents us
12182 // from trying to jit the same method more that once.
12183 //
12184 // Calls to this method that occur to check if inlining can occur on x86,
12185 // are OK since they discard the return value of this method.
12186
12187 PCODE UnsafeJitFunction(MethodDesc* ftn, COR_ILMETHOD_DECODER* ILHeader, CORJIT_FLAGS flags,
12188                         ULONG * pSizeOfCode)
12189 {
12190     STANDARD_VM_CONTRACT;
12191
12192     PCODE ret = NULL;
12193
12194     COOPERATIVE_TRANSITION_BEGIN();
12195
12196 #ifdef FEATURE_PREJIT
12197
12198     if (g_pConfig->RequireZaps() == EEConfig::REQUIRE_ZAPS_ALL &&
12199         ftn->GetModule()->GetDomainFile()->IsZapRequired() &&
12200         PartialNGenStressPercentage() == 0 && 
12201 #ifdef FEATURE_STACK_SAMPLING
12202         !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND) &&
12203 #endif
12204         !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12205     {
12206         StackSString ss(SString::Ascii, "ZapRequire: JIT compiler invoked for ");
12207         TypeString::AppendMethodInternal(ss, ftn);
12208
12209 #ifdef _DEBUG
12210         // Assert as some test may not check their error codes well. So throwing an
12211         // exception may not cause a test failure (as it should).
12212         StackScratchBuffer scratch;
12213         DbgAssertDialog(__FILE__, __LINE__, (char*)ss.GetUTF8(scratch));
12214 #endif // _DEBUG
12215
12216         COMPlusThrowNonLocalized(kFileNotFoundException, ss.GetUnicode());
12217     }
12218
12219 #endif // FEATURE_PREJIT
12220
12221 #ifndef CROSSGEN_COMPILE
12222     EEJitManager *jitMgr = ExecutionManager::GetEEJitManager();
12223     if (!jitMgr->LoadJIT())
12224     {
12225 #ifdef ALLOW_SXS_JIT
12226         if (!jitMgr->IsMainJitLoaded())
12227         {
12228             // Don't want to throw InvalidProgram from here.
12229             EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12230         }
12231         if (!jitMgr->IsAltJitLoaded())
12232         {
12233             // Don't want to throw InvalidProgram from here.
12234             EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load alternative JIT compiler"));
12235         }
12236 #else // ALLOW_SXS_JIT
12237         // Don't want to throw InvalidProgram from here.
12238         EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12239 #endif // ALLOW_SXS_JIT
12240     }
12241 #endif // CROSSGEN_COMPILE
12242
12243 #ifdef _DEBUG
12244     // This is here so we can see the name and class easily in the debugger
12245
12246     LPCUTF8 cls  = ftn->GetMethodTable()->GetDebugClassName();
12247     LPCUTF8 name = ftn->GetName();
12248
12249     if (ftn->IsNoMetadata())
12250     {
12251         if (ftn->IsILStub())
12252         {
12253             LOG((LF_JIT, LL_INFO10000, "{ Jitting IL Stub }\n"));
12254         }
12255         else
12256         {
12257             LOG((LF_JIT, LL_INFO10000, "{ Jitting dynamic method }\n"));
12258         }
12259     }
12260     else
12261     {
12262         SString methodString;
12263         if (LoggingOn(LF_JIT, LL_INFO10000))
12264             TypeString::AppendMethodDebug(methodString, ftn);
12265
12266         LOG((LF_JIT, LL_INFO10000, "{ Jitting method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12267     }
12268
12269 #if 0
12270     if (!SString::_stricmp(cls,"ENC") &&
12271        (!SString::_stricmp(name,"G")))
12272     {
12273        static count = 0;
12274        count++;
12275        if (count > 0)
12276             DebugBreak();
12277     }
12278 #endif // 0
12279 #endif // _DEBUG
12280
12281     CORINFO_METHOD_HANDLE ftnHnd = (CORINFO_METHOD_HANDLE)ftn;
12282     CORINFO_METHOD_INFO methodInfo;
12283
12284     getMethodInfoHelper(ftn, ftnHnd, ILHeader, &methodInfo);
12285
12286     // If it's generic then we can only enter through an instantiated md (unless we're just verifying it)
12287     _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || !ftn->IsGenericMethodDefinition());
12288
12289     // If it's an instance method then it must not be entered from a generic class
12290     _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || ftn->IsStatic() ||
12291              ftn->GetNumGenericClassArgs() == 0 || ftn->HasClassInstantiation());
12292
12293     // method attributes and signature are consistant
12294     _ASSERTE(!!ftn->IsStatic() == ((methodInfo.args.callConv & CORINFO_CALLCONV_HASTHIS) == 0));
12295
12296     flags = GetCompileFlags(ftn, flags, &methodInfo);
12297
12298 #ifdef _DEBUG
12299     if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION))
12300     {
12301         SString methodString;
12302         if (LoggingOn(LF_VERIFIER, LL_INFO100))
12303             TypeString::AppendMethodDebug(methodString, ftn);
12304
12305         LOG((LF_VERIFIER, LL_INFO100, "{ Will verify method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12306     }
12307 #endif //_DEBUG
12308
12309 #ifdef _TARGET_AMD64_
12310     BOOL fForceRel32Overflow = FALSE;
12311
12312 #ifdef _DEBUG
12313     // Always exercise the overflow codepath with force relocs
12314     if (PEDecoder::GetForceRelocs())
12315         fForceRel32Overflow = TRUE;
12316 #endif
12317
12318     BOOL fAllowRel32 = g_fAllowRel32 | fForceRel32Overflow;
12319
12320     // For determinism, never try to use the REL32 in compilation process
12321     if (IsCompilationProcess())
12322     {
12323         fForceRel32Overflow = FALSE;
12324         fAllowRel32 = FALSE;
12325     }
12326 #endif // _TARGET_AMD64_
12327
12328     for (;;)
12329     {
12330 #ifndef CROSSGEN_COMPILE
12331         CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY), 
12332             !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING));
12333 #else
12334         // This path should be only ever used for verification in crossgen and so we should not need EEJitManager
12335         _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY));
12336         CEEInfo jitInfo(ftn, true);
12337         EEJitManager *jitMgr = NULL;
12338 #endif
12339
12340 #if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE)
12341         if (fForceRel32Overflow)
12342             jitInfo.SetRel32Overflow(fAllowRel32);
12343         jitInfo.SetAllowRel32(fAllowRel32);
12344 #endif
12345
12346         MethodDesc * pMethodForSecurity = jitInfo.GetMethodForSecurity(ftnHnd);
12347
12348         //Since the check could trigger a demand, we have to do this every time.
12349         //This is actually an overly complicated way to make sure that a method can access all its arguments
12350         //and its return type.
12351         AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
12352         TypeHandle ownerTypeForSecurity = TypeHandle(pMethodForSecurity->GetMethodTable());
12353         DynamicResolver *pAccessContext = NULL;
12354         BOOL doAccessCheck = TRUE;
12355         if (pMethodForSecurity->IsDynamicMethod())
12356         {
12357             doAccessCheck = ModifyCheckForDynamicMethod(pMethodForSecurity->AsDynamicMethodDesc()->GetResolver(),
12358                                                         &ownerTypeForSecurity,
12359                                                         &accessCheckType, &pAccessContext);
12360         }
12361         if (doAccessCheck)
12362         {
12363             AccessCheckOptions accessCheckOptions(accessCheckType,
12364                                                   pAccessContext,
12365                                                   TRUE /*Throw on error*/,
12366                                                   pMethodForSecurity);
12367
12368             StaticAccessCheckContext accessContext(pMethodForSecurity, ownerTypeForSecurity.GetMethodTable());
12369
12370             // We now do an access check from pMethodForSecurity to pMethodForSecurity, its sole purpose is to
12371             // verify that pMethodForSecurity/ownerTypeForSecurity has access to all its parameters.
12372
12373             // ownerTypeForSecurity.GetMethodTable() can be null if the pMethodForSecurity is a DynamicMethod
12374             // associated with a TypeDesc (Array, Ptr, Ref, or FnPtr). That doesn't make any sense, but we will
12375             // just do an access check from a NULL context which means only public types are accessible.
12376             if (!ClassLoader::CanAccess(&accessContext,
12377                                         ownerTypeForSecurity.GetMethodTable(),
12378                                         ownerTypeForSecurity.GetAssembly(),
12379                                         pMethodForSecurity->GetAttrs(),
12380                                         pMethodForSecurity,
12381                                         NULL,
12382                                         accessCheckOptions))
12383             {
12384                 EX_THROW(EEMethodException, (pMethodForSecurity));
12385             }
12386         }
12387
12388         CorJitResult res;
12389         PBYTE nativeEntry;
12390         ULONG sizeOfCode;
12391
12392         {
12393             GCX_COOP();
12394
12395             /* There is a double indirection to call compileMethod  - can we
12396                improve this with the new structure? */
12397
12398 #ifdef PERF_TRACK_METHOD_JITTIMES
12399             //Because we're not calling QPC enough.  I'm not going to track times if we're just importing.
12400             LARGE_INTEGER methodJitTimeStart = {0};
12401             if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12402                 QueryPerformanceCounter (&methodJitTimeStart);
12403
12404 #endif
12405 #if defined(ENABLE_PERF_COUNTERS)
12406             START_JIT_PERF();
12407 #endif
12408
12409 #if defined(ENABLE_PERF_COUNTERS)
12410             LARGE_INTEGER CycleStart;
12411             QueryPerformanceCounter (&CycleStart);
12412 #endif // defined(ENABLE_PERF_COUNTERS)
12413
12414             // Note on debuggerTrackInfo arg: if we're only importing (ie, verifying/
12415             // checking to make sure we could JIT, but not actually generating code (
12416             // eg, for inlining), then DON'T TELL THE DEBUGGER about this.
12417             res = CallCompileMethodWithSEHWrapper(jitMgr,
12418                                                   &jitInfo,
12419                                                   &methodInfo,
12420                                                   flags,
12421                                                   &nativeEntry,
12422                                                   &sizeOfCode,
12423                                                   (MethodDesc*)ftn);
12424             LOG((LF_CORDB, LL_EVERYTHING, "Got through CallCompile MethodWithSEHWrapper\n"));
12425
12426 #if FEATURE_PERFMAP
12427             // Save the code size so that it can be reported to the perfmap.
12428             if (pSizeOfCode != NULL)
12429             {
12430                 *pSizeOfCode = sizeOfCode;
12431             }
12432 #endif
12433
12434 #if defined(ENABLE_PERF_COUNTERS)
12435             LARGE_INTEGER CycleStop;
12436             QueryPerformanceCounter(&CycleStop);
12437             GetPerfCounters().m_Jit.timeInJitBase = GetPerfCounters().m_Jit.timeInJit;
12438             GetPerfCounters().m_Jit.timeInJit += static_cast<DWORD>(CycleStop.QuadPart - CycleStart.QuadPart);
12439             GetPerfCounters().m_Jit.cMethodsJitted++;
12440             GetPerfCounters().m_Jit.cbILJitted+=methodInfo.ILCodeSize;
12441
12442 #endif // defined(ENABLE_PERF_COUNTERS)
12443
12444 #if defined(ENABLE_PERF_COUNTERS)
12445             STOP_JIT_PERF();
12446 #endif
12447
12448 #ifdef PERF_TRACK_METHOD_JITTIMES
12449             //store the time in the string buffer.  Module name and token are unique enough.  Also, do not
12450             //capture importing time, just actual compilation time.
12451             if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12452             {
12453                 LARGE_INTEGER methodJitTimeStop;
12454                 QueryPerformanceCounter(&methodJitTimeStop);
12455                 SString codeBase;
12456                 ftn->GetModule()->GetDomainFile()->GetFile()->GetCodeBaseOrName(codeBase);
12457                 codeBase.AppendPrintf(W(",0x%x,%d,%d\n"),
12458                                  //(const WCHAR *)codeBase, //module name
12459                                  ftn->GetMemberDef(), //method token
12460                                  (unsigned)(methodJitTimeStop.QuadPart - methodJitTimeStart.QuadPart), //cycle count
12461                                  methodInfo.ILCodeSize //il size
12462                                 );
12463                 WszOutputDebugString((const WCHAR*)codeBase);
12464             }
12465 #endif // PERF_TRACK_METHOD_JITTIMES
12466
12467         }
12468
12469         LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s  %s }\n",cls,name, ftn->m_pszDebugMethodSignature));
12470
12471         if (!SUCCEEDED(res))
12472         {
12473             COUNTER_ONLY(GetPerfCounters().m_Jit.cJitFailures++);
12474
12475 #ifndef CROSSGEN_COMPILE
12476             jitInfo.BackoutJitData(jitMgr);
12477 #endif
12478
12479             ThrowExceptionForJit(res);
12480         }
12481
12482         if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12483         {
12484             // We are done
12485             break;
12486         }
12487
12488         if (!nativeEntry)
12489             COMPlusThrow(kInvalidProgramException);
12490
12491 #if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE)
12492         if (jitInfo.IsRel32Overflow())
12493         {
12494             // Backout and try again with fAllowRel32 == FALSE.
12495             jitInfo.BackoutJitData(jitMgr);
12496
12497             // Disallow rel32 relocs in future.
12498             g_fAllowRel32 = FALSE;
12499
12500             _ASSERTE(fAllowRel32 != FALSE);
12501             fAllowRel32 = FALSE;
12502             continue;
12503         }
12504 #endif // _TARGET_AMD64_ && !CROSSGEN_COMPILE
12505
12506         LOG((LF_JIT, LL_INFO10000,
12507             "Jitted Entry at" FMT_ADDR "method %s::%s %s\n", DBG_ADDR(nativeEntry),
12508              ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
12509
12510 #if defined(FEATURE_CORESYSTEM)
12511
12512 #ifdef _DEBUG
12513         LPCUTF8 pszDebugClassName = ftn->m_pszDebugClassName;
12514         LPCUTF8 pszDebugMethodName = ftn->m_pszDebugMethodName;
12515         LPCUTF8 pszDebugMethodSignature = ftn->m_pszDebugMethodSignature;
12516 #else
12517         LPCUTF8 pszNamespace;
12518         LPCUTF8 pszDebugClassName = ftn->GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace);
12519         LPCUTF8 pszDebugMethodName = ftn->GetName();
12520         LPCUTF8 pszDebugMethodSignature = "";
12521 #endif
12522
12523         //DbgPrintf("Jitted Entry at" FMT_ADDR "method %s::%s %s size %08x\n", DBG_ADDR(nativeEntry),
12524         //          pszDebugClassName, pszDebugMethodName, pszDebugMethodSignature, sizeOfCode);
12525 #endif
12526
12527         ClrFlushInstructionCache(nativeEntry, sizeOfCode); 
12528         ret = (PCODE)nativeEntry;
12529
12530 #ifdef _TARGET_ARM_
12531         ret |= THUMB_CODE;
12532 #endif
12533
12534         // We are done
12535         break;
12536     }
12537
12538 #ifdef _DEBUG
12539     FastInterlockIncrement(&g_JitCount);
12540     static BOOL fHeartbeat = -1;
12541
12542     if (fHeartbeat == -1)
12543         fHeartbeat = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitHeartbeat);
12544
12545     if (fHeartbeat)
12546         printf(".");
12547 #endif // _DEBUG
12548
12549     COOPERATIVE_TRANSITION_END();
12550     return ret;
12551 }
12552
12553 extern "C" unsigned __stdcall PartialNGenStressPercentage()
12554 {
12555     LIMITED_METHOD_CONTRACT;
12556 #ifndef _DEBUG 
12557     return 0;
12558 #else // _DEBUG
12559     static ConfigDWORD partialNGenStress;
12560     DWORD partialNGenStressVal = partialNGenStress.val(CLRConfig::INTERNAL_partialNGenStress);
12561     _ASSERTE(partialNGenStressVal <= 100);
12562     return partialNGenStressVal;
12563 #endif // _DEBUG
12564 }
12565
12566 #ifdef FEATURE_PREJIT
12567 /*********************************************************************/
12568
12569 //
12570 // Table loading functions
12571 //
12572 void Module::LoadHelperTable()
12573 {
12574     STANDARD_VM_CONTRACT;
12575
12576 #ifndef CROSSGEN_COMPILE
12577     COUNT_T tableSize;
12578     BYTE * table = (BYTE *) GetNativeImage()->GetNativeHelperTable(&tableSize);
12579
12580     if (tableSize == 0)
12581         return;
12582
12583     EnsureWritableExecutablePages(table, tableSize);
12584
12585     BYTE * curEntry   = table;
12586     BYTE * tableEnd   = table + tableSize;
12587
12588 #ifdef FEATURE_PERFMAP
12589     PerfMap::LogStubs(__FUNCTION__, GetSimpleName(), (PCODE)table, tableSize);
12590 #endif
12591
12592 #ifdef LOGGING
12593     int iEntryNumber = 0;
12594 #endif // LOGGING
12595
12596     //
12597     // Fill in helpers
12598     //
12599
12600     while (curEntry < tableEnd)
12601     {
12602         DWORD dwHelper = *(DWORD *)curEntry;
12603
12604         int iHelper = (USHORT)dwHelper;
12605         _ASSERTE(iHelper < CORINFO_HELP_COUNT);
12606
12607         LOG((LF_JIT, LL_INFO1000000, "JIT helper %3d (%-40s: table @ %p, size 0x%x, entry %3d @ %p, pfnHelper %p)\n",
12608             iHelper, hlpFuncTable[iHelper].name, table, tableSize, iEntryNumber, curEntry, hlpFuncTable[iHelper].pfnHelper));
12609
12610 #if defined(ENABLE_FAST_GCPOLL_HELPER)
12611         // The fast GC poll helper works by calling indirect through a pointer that points to either
12612         // JIT_PollGC or JIT_PollGC_Nop, based on whether we need to poll or not. The JIT_PollGC_Nop
12613         // version is just a "ret". The pointer is stored in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
12614         // See EnableJitGCPoll() and DisableJitGCPoll().
12615         // In NGEN images, we generate a direct call to the helper table. Here, we replace that with
12616         // an indirect jump through the pointer in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
12617         if (iHelper == CORINFO_HELP_POLL_GC)
12618         {
12619             LOG((LF_JIT, LL_INFO1000000, "JIT helper CORINFO_HELP_POLL_GC (%d); emitting indirect jump to 0x%x\n",
12620                 CORINFO_HELP_POLL_GC, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper));
12621
12622             emitJumpInd(curEntry, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper);
12623             curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
12624         }
12625         else
12626 #endif // ENABLE_FAST_GCPOLL_HELPER
12627         {
12628             PCODE pfnHelper = CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)iHelper);
12629
12630             if (dwHelper & CORCOMPILE_HELPER_PTR)
12631             {
12632                 //
12633                 // Indirection cell
12634                 //
12635
12636                 *(TADDR *)curEntry = pfnHelper;
12637
12638                 curEntry = curEntry + sizeof(TADDR);
12639             }
12640             else
12641             {
12642                 //
12643                 // Jump thunk
12644                 //
12645
12646 #if defined(_TARGET_AMD64_)
12647                 *curEntry = X86_INSTR_JMP_REL32;
12648                 *(INT32 *)(curEntry + 1) = rel32UsingJumpStub((INT32 *)(curEntry + 1), pfnHelper, NULL, GetLoaderAllocator());   
12649 #else // all other platforms
12650                 emitJump(curEntry, (LPVOID)pfnHelper);
12651                 _ASSERTE(HELPER_TABLE_ENTRY_LEN >= JUMP_ALLOCATE_SIZE);
12652 #endif
12653
12654                 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
12655             }
12656         }
12657 #ifdef LOGGING
12658         // Note that some table entries are sizeof(TADDR) in length, and some are HELPER_TABLE_ENTRY_LEN in length
12659         ++iEntryNumber;
12660 #endif // LOGGING
12661     }
12662
12663     ClrFlushInstructionCache(table, tableSize);
12664 #endif // CROSSGEN_COMPILE
12665 }
12666
12667 #ifdef FEATURE_READYTORUN
12668 CorInfoHelpFunc MapReadyToRunHelper(ReadyToRunHelper helperNum)
12669 {
12670     LIMITED_METHOD_CONTRACT;
12671
12672     switch (helperNum)
12673     {
12674 #define HELPER(readyToRunHelper, corInfoHelpFunc, flags) \
12675     case readyToRunHelper:                                  return corInfoHelpFunc;
12676 #include "readytorunhelpers.h"
12677
12678     case READYTORUN_HELPER_GetString:                       return CORINFO_HELP_STRCNS;
12679
12680     default:                                                return CORINFO_HELP_UNDEF;
12681     }
12682 }
12683
12684 void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap)
12685 {
12686     STANDARD_VM_CONTRACT;
12687
12688     ZeroMemory(pGCRefMap, cbGCRefMap);
12689
12690     if (!pMT->ContainsPointers())
12691         return;
12692     
12693     CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
12694     CGCDescSeries* cur = map->GetHighestSeries();
12695     CGCDescSeries* last = map->GetLowestSeries();
12696     DWORD size = pMT->GetBaseSize();
12697     _ASSERTE(cur >= last);
12698
12699     do
12700     {
12701         // offset to embedded references in this series must be
12702         // adjusted by the VTable pointer, when in the unboxed state.
12703         size_t offset = cur->GetSeriesOffset() - sizeof(void*);
12704         size_t offsetStop = offset + cur->GetSeriesSize() + size;
12705         while (offset < offsetStop)
12706         {
12707             size_t bit = offset / sizeof(void *);
12708
12709             size_t index = bit / 8;
12710             _ASSERTE(index < cbGCRefMap);
12711             pGCRefMap[index] |= (1 << (bit & 7));
12712
12713             offset += sizeof(void *);
12714         }
12715         cur--;
12716     } while (cur >= last);
12717 }
12718
12719 //
12720 // Type layout check verifies that there was no incompatible change in the value type layout. 
12721 // If there was one, we will fall back to JIT instead of using the pre-generated code from the ready to run image.
12722 // This should be rare situation. Changes in value type layout not common.
12723 //
12724 // The following properties of the value type layout are checked:
12725 // - Size
12726 // - HFA-ness (on platform that support HFAs)
12727 // - Alignment
12728 // - Position of GC references
12729 //
12730 BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob)
12731 {
12732     STANDARD_VM_CONTRACT;
12733
12734     SigPointer p(pBlob);
12735     IfFailThrow(p.SkipExactlyOne());
12736
12737     DWORD dwFlags;
12738     IfFailThrow(p.GetData(&dwFlags));
12739
12740     // Size is checked unconditionally
12741     DWORD dwExpectedSize;
12742     IfFailThrow(p.GetData(&dwExpectedSize));
12743
12744     DWORD dwActualSize = pMT->GetNumInstanceFieldBytes();
12745     if (dwExpectedSize != dwActualSize)
12746         return FALSE;
12747
12748 #ifdef FEATURE_HFA
12749     if (dwFlags & READYTORUN_LAYOUT_HFA)
12750     {
12751         DWORD dwExpectedHFAType;
12752         IfFailThrow(p.GetData(&dwExpectedHFAType));
12753
12754         DWORD dwActualHFAType = pMT->GetHFAType();
12755         if (dwExpectedHFAType != dwActualHFAType)
12756             return FALSE;
12757     }
12758     else
12759     {
12760         if (pMT->IsHFA())
12761             return FALSE;
12762     }
12763 #else
12764     _ASSERTE(!(dwFlags & READYTORUN_LAYOUT_HFA));
12765 #endif
12766
12767     if (dwFlags & READYTORUN_LAYOUT_Alignment)
12768     {
12769         DWORD dwExpectedAlignment = sizeof(void *);
12770         if (!(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
12771         {
12772             IfFailThrow(p.GetData(&dwExpectedAlignment));
12773         }
12774
12775         DWORD dwActualAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
12776         if (dwExpectedAlignment != dwActualAlignment)
12777             return FALSE;
12778
12779     }
12780
12781     if (dwFlags & READYTORUN_LAYOUT_GCLayout)
12782     {
12783         if (dwFlags & READYTORUN_LAYOUT_GCLayout_Empty)
12784         {
12785             if (pMT->ContainsPointers())
12786                 return FALSE;
12787         }
12788         else
12789         {
12790             size_t cbGCRefMap = (dwActualSize / sizeof(TADDR) + 7) / 8;
12791             _ASSERTE(cbGCRefMap > 0);
12792
12793             BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
12794
12795             ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
12796
12797             if (memcmp(pGCRefMap, p.GetPtr(), cbGCRefMap) != 0)
12798                 return FALSE;
12799         }
12800     }
12801
12802     return TRUE;
12803 }
12804
12805 #endif // FEATURE_READYTORUN
12806
12807 BOOL LoadDynamicInfoEntry(Module *currentModule,
12808                           RVA fixupRva,
12809                           SIZE_T *entry)
12810 {
12811     STANDARD_VM_CONTRACT;
12812
12813     PCCOR_SIGNATURE pBlob = currentModule->GetNativeFixupBlobData(fixupRva);
12814
12815     BYTE kind = *pBlob++;
12816
12817     Module * pInfoModule = currentModule;
12818
12819     if (kind & ENCODE_MODULE_OVERRIDE)
12820     {
12821         pInfoModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
12822         kind &= ~ENCODE_MODULE_OVERRIDE;
12823     }
12824
12825     MethodDesc * pMD = NULL;
12826
12827     PCCOR_SIGNATURE pSig;
12828     DWORD cSig;
12829
12830     mdSignature token;
12831
12832     size_t result = 0;
12833     
12834     switch (kind)
12835     {
12836     case ENCODE_MODULE_HANDLE:
12837         result = (size_t)pInfoModule;
12838         break;
12839
12840     case ENCODE_TYPE_HANDLE:
12841     case ENCODE_TYPE_DICTIONARY:
12842         {
12843             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
12844
12845             if (!th.IsTypeDesc())
12846             {
12847                 if (currentModule->IsReadyToRun())
12848                 {
12849                     // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12850                     th.AsMethodTable()->EnsureInstanceActive();
12851                 }
12852                 else
12853                 {
12854 #ifdef FEATURE_WINMD_RESILIENT
12855                     // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12856                     th.AsMethodTable()->EnsureInstanceActive();
12857 #endif
12858                 }
12859             }
12860
12861             result = (size_t)th.AsPtr();
12862         }
12863         break;
12864
12865     case ENCODE_METHOD_HANDLE:
12866     case ENCODE_METHOD_DICTIONARY:
12867         {
12868             MethodDesc * pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
12869
12870             if (currentModule->IsReadyToRun())
12871             {
12872                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12873                 pMD->EnsureActive();
12874             }
12875
12876             result = (size_t)pMD;
12877         }
12878         break;
12879
12880     case ENCODE_FIELD_HANDLE:
12881         result = (size_t) ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
12882         break;
12883
12884 #ifndef CROSSGEN_COMPILE
12885     case ENCODE_STRING_HANDLE:
12886         {
12887             // We need to update strings atomically (due to NoStringInterning attribute). Note
12888             // that modules with string interning dont really need this, as the hash tables have
12889             // their own locking, but dont add more complexity for what will be the non common
12890             // case.
12891
12892             // We will have to lock and update the entry. (this is really a double check, where
12893             // the first check is done in the caller of this function)
12894             DWORD rid = CorSigUncompressData(pBlob);
12895             if (rid == 0)
12896             {
12897                 // Empty string
12898                 result = (size_t)StringObject::GetEmptyStringRefPtr();
12899             }
12900             else
12901             {
12902                 CrstHolder ch(pInfoModule->GetFixupCrst());
12903
12904                 if (!CORCOMPILE_IS_POINTER_TAGGED(*entry) && (*entry != NULL))
12905                 {
12906                     // We lost the race, just return
12907                     return TRUE;
12908                 }
12909
12910                 // For generic instantiations compiled into the ngen image of some other
12911                 // client assembly, we need to ensure that we intern the string
12912                 // in the defining assembly.
12913                 bool mayNeedToSyncWithFixups = pInfoModule != currentModule;
12914
12915                 result = (size_t) pInfoModule->ResolveStringRef(TokenFromRid(rid, mdtString), currentModule->GetDomain(), mayNeedToSyncWithFixups);
12916             }
12917         }
12918         break;
12919
12920     case ENCODE_VARARGS_SIG:
12921         {
12922             mdSignature token = TokenFromRid(
12923                                     CorSigUncompressData(pBlob),
12924                                     mdtSignature);
12925
12926             IfFailThrow(pInfoModule->GetMDImport()->GetSigFromToken(token, &cSig, &pSig));
12927
12928             goto VarArgs;
12929         }
12930         break;
12931
12932     case ENCODE_VARARGS_METHODREF:
12933         {
12934             mdSignature token = TokenFromRid(
12935                                     CorSigUncompressData(pBlob),
12936                                     mdtMemberRef);
12937
12938             LPCSTR szName_Ignore;
12939             IfFailThrow(pInfoModule->GetMDImport()->GetNameAndSigOfMemberRef(token, &pSig, &cSig, &szName_Ignore));
12940
12941             goto VarArgs;
12942         }
12943         break;
12944
12945     case ENCODE_VARARGS_METHODDEF:
12946         {
12947             token = TokenFromRid(
12948                         CorSigUncompressData(pBlob),
12949                         mdtMethodDef);
12950
12951             IfFailThrow(pInfoModule->GetMDImport()->GetSigOfMethodDef(token, &cSig, &pSig));
12952
12953         VarArgs:
12954             result = (size_t) CORINFO_VARARGS_HANDLE(currentModule->GetVASigCookie(Signature(pSig, cSig)));
12955         }
12956         break;
12957
12958         // ENCODE_METHOD_NATIVECALLABLE_HANDLE is same as ENCODE_METHOD_ENTRY_DEF_TOKEN 
12959         // except for AddrOfCode
12960     case ENCODE_METHOD_NATIVE_ENTRY:
12961     case ENCODE_METHOD_ENTRY_DEF_TOKEN:
12962         {
12963             mdToken MethodDef = TokenFromRid(CorSigUncompressData(pBlob), mdtMethodDef);
12964             pMD = MemberLoader::GetMethodDescFromMethodDef(pInfoModule, MethodDef, FALSE);
12965
12966             pMD->PrepareForUseAsADependencyOfANativeImage();
12967
12968             if (currentModule->IsReadyToRun())
12969             {
12970                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12971                 pMD->EnsureActive();
12972             }
12973
12974             goto MethodEntry;
12975         }
12976
12977     case ENCODE_METHOD_ENTRY_REF_TOKEN:
12978         {
12979             SigTypeContext typeContext;
12980             mdToken MemberRef = TokenFromRid(CorSigUncompressData(pBlob), mdtMemberRef);
12981             FieldDesc * pFD = NULL;
12982             TypeHandle th;
12983
12984             MemberLoader::GetDescFromMemberRef(pInfoModule, MemberRef, &pMD, &pFD, &typeContext, FALSE /* strict metadata checks */, &th);
12985             _ASSERTE(pMD != NULL);
12986
12987             pMD->PrepareForUseAsADependencyOfANativeImage();
12988
12989             if (currentModule->IsReadyToRun())
12990             {
12991                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12992                 pMD->EnsureActive();
12993             }
12994             else
12995             {
12996 #ifdef FEATURE_WINMD_RESILIENT
12997                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12998                 pMD->EnsureActive();
12999 #endif
13000             }
13001
13002             goto MethodEntry;
13003         }
13004
13005     case ENCODE_METHOD_ENTRY:
13006         {
13007             pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13008
13009             if (currentModule->IsReadyToRun())
13010             {
13011                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13012                 pMD->EnsureActive();
13013             }
13014
13015         MethodEntry:
13016             if (kind == ENCODE_METHOD_NATIVE_ENTRY)
13017             {
13018                 result = COMDelegate::ConvertToCallback(pMD);
13019             }
13020             else
13021             {
13022                 result = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY);
13023             }
13024
13025         #ifndef _TARGET_ARM_
13026             if (CORCOMPILE_IS_PCODE_TAGGED(result))
13027             {
13028                 // There is a rare case where the function entrypoint may not be aligned. This could happen only for FCalls, 
13029                 // only on x86 and only if we failed to hardbind the fcall (e.g. ngen image for mscorlib.dll does not exist 
13030                 // and /nodependencies flag for ngen was used). The function entrypoints should be aligned in all other cases.
13031                 //
13032                 // We will wrap the unaligned method entrypoint by funcptr stub with aligned entrypoint.
13033                 _ASSERTE(pMD->IsFCall());
13034                 result = pMD->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pMD);
13035             }
13036         #endif
13037         }
13038         break;
13039
13040     case ENCODE_SYNC_LOCK:
13041         {
13042             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13043
13044             result = (size_t) GetClassSync(th.AsMethodTable());
13045         }
13046         break;
13047
13048     case ENCODE_INDIRECT_PINVOKE_TARGET:
13049         {
13050             MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13051
13052             _ASSERTE(pMethod->IsNDirect());
13053             NDirectMethodDesc *pMD = (NDirectMethodDesc*)pMethod;
13054             result = (size_t)(LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
13055         }
13056         break;
13057
13058 #if defined(PROFILING_SUPPORTED)
13059     case ENCODE_PROFILING_HANDLE:
13060         {
13061             MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13062
13063             // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
13064             // they shouldnever come here as they are called out in GetCompileFlag
13065             _ASSERTE(!pMethod->IsNoMetadata());
13066
13067             FunctionID funId = (FunctionID)pMethod;
13068
13069             BOOL bHookFunction = TRUE;
13070             CORINFO_PROFILING_HANDLE profilerHandle = (CORINFO_PROFILING_HANDLE)funId;
13071
13072             {
13073                 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
13074                 profilerHandle = (CORINFO_PROFILING_HANDLE) g_profControlBlock.pProfInterface->EEFunctionIDMapper(funId, &bHookFunction);
13075                 END_PIN_PROFILER();
13076             }
13077
13078             // Profiling handle is opaque token. It does not have to be aligned thus we can not store it in the same location as token.
13079             *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexClientData) = (SIZE_T)profilerHandle;
13080
13081             if (bHookFunction)
13082             {
13083                 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER].pfnHelper;
13084                 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE].pfnHelper;
13085                 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL].pfnHelper;
13086             }
13087             else
13088             {
13089                 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13090                 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13091                 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13092             }
13093         }
13094         break;
13095 #endif // PROFILING_SUPPORTED
13096
13097     case ENCODE_STATIC_FIELD_ADDRESS:
13098         {
13099             FieldDesc *pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13100
13101             pField->GetEnclosingMethodTable()->CheckRestore();
13102
13103             // We can take address of RVA field only since ngened code is domain neutral
13104             _ASSERTE(pField->IsRVA());
13105
13106             // Field address is not aligned thus we can not store it in the same location as token.
13107             *EnsureWritablePages(entry+1) = (size_t)pField->GetStaticAddressHandle(NULL);
13108         }
13109         break;
13110
13111     case ENCODE_VIRTUAL_ENTRY_SLOT:
13112         {
13113             DWORD slot = CorSigUncompressData(pBlob);
13114
13115             TypeHandle ownerType = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13116
13117             LOG((LF_ZAP, LL_INFO100000, "     Fixup stub dispatch\n"));
13118
13119             VirtualCallStubManager * pMgr = currentModule->GetLoaderAllocator()->GetVirtualCallStubManager();
13120
13121             // <REVISIT_TODO>
13122             // We should be generating a stub indirection here, but the zapper already uses one level
13123             // of indirection, i.e. we would have to return IAT_PPVALUE to the JIT, and on the whole the JITs
13124             // aren't quite set up to accept that. Furthermore the call sequences would be different - at
13125             // the moment an indirection cell uses "call [cell-addr]" on x86, and instead we would want the
13126             // euqivalent of "call [[call-addr]]".  This could perhaps be implemented as "call [eax]" </REVISIT_TODO>
13127             result = pMgr->GetCallStub(ownerType, slot);
13128         }
13129         break;
13130
13131     case ENCODE_CLASS_ID_FOR_STATICS:
13132         {
13133             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13134
13135             MethodTable * pMT = th.AsMethodTable();
13136             if (pMT->IsDynamicStatics())
13137             {
13138                 result = pMT->GetModuleDynamicEntryID();
13139             }
13140             else
13141             {
13142                 result = pMT->GetClassIndex();
13143             }
13144         }
13145         break;
13146
13147     case ENCODE_MODULE_ID_FOR_STATICS:
13148         {
13149             result = pInfoModule->GetModuleID();
13150         }
13151         break;
13152
13153     case ENCODE_MODULE_ID_FOR_GENERIC_STATICS:
13154         {
13155             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13156
13157             MethodTable * pMT = th.AsMethodTable();
13158
13159             result = pMT->GetModuleForStatics()->GetModuleID();
13160         }
13161         break;
13162
13163     case ENCODE_ACTIVE_DEPENDENCY:
13164         {
13165             Module* pModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13166
13167             STRESS_LOG3(LF_ZAP,LL_INFO10000,"Modules are: %08x,%08x,%08x",currentModule,pInfoModule,pModule);
13168             pInfoModule->AddActiveDependency(pModule, FALSE);
13169         }
13170         break;
13171
13172 #ifdef FEATURE_READYTORUN
13173     case ENCODE_READYTORUN_HELPER:
13174         {
13175             DWORD helperNum = CorSigUncompressData(pBlob);
13176
13177             CorInfoHelpFunc corInfoHelpFunc = MapReadyToRunHelper((ReadyToRunHelper)helperNum);
13178             if (corInfoHelpFunc != CORINFO_HELP_UNDEF)
13179             {
13180                 result = (size_t)CEEJitInfo::getHelperFtnStatic(corInfoHelpFunc);
13181             }
13182             else
13183             {
13184                 switch (helperNum)
13185                 {
13186                 case READYTORUN_HELPER_Module:
13187                     {
13188                         Module * pPrevious = InterlockedCompareExchangeT(EnsureWritablePages((Module **)entry), pInfoModule, NULL);
13189                         if (pPrevious != pInfoModule && pPrevious != NULL)
13190                             COMPlusThrowHR(COR_E_FILELOAD, IDS_NATIVE_IMAGE_CANNOT_BE_LOADED_MULTIPLE_TIMES, pInfoModule->GetPath());
13191                         return TRUE;
13192                     }
13193                     break;
13194
13195                 case READYTORUN_HELPER_GSCookie:
13196                     result = (size_t)GetProcessGSCookie();
13197                     break;
13198
13199                 case READYTORUN_HELPER_DelayLoad_MethodCall:
13200                     result = (size_t)GetEEFuncEntryPoint(DelayLoad_MethodCall);
13201                     break;
13202
13203                 case READYTORUN_HELPER_DelayLoad_Helper:
13204                     result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper);
13205                     break;
13206
13207                 case READYTORUN_HELPER_DelayLoad_Helper_Obj:
13208                     result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_Obj);
13209                     break;
13210
13211                 case READYTORUN_HELPER_DelayLoad_Helper_ObjObj:
13212                     result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_ObjObj);
13213                     break;
13214
13215                 default:
13216                     STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown READYTORUN_HELPER %d\n", helperNum);
13217                     _ASSERTE(!"Unknown READYTORUN_HELPER");
13218                     return FALSE;
13219                 }
13220             }
13221         }
13222         break;
13223
13224     case ENCODE_FIELD_OFFSET:
13225         {
13226             FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13227             _ASSERTE(!pFD->IsStatic());
13228             _ASSERTE(!pFD->IsFieldOfValueType());
13229
13230             DWORD dwOffset = (DWORD)sizeof(Object) + pFD->GetOffset();
13231
13232             if (dwOffset > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13233                 return FALSE;
13234             result = dwOffset;
13235         }
13236         break;
13237
13238     case ENCODE_FIELD_BASE_OFFSET:
13239         {
13240             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13241
13242             MethodTable * pMT = th.AsMethodTable();
13243             _ASSERTE(!pMT->IsValueType());
13244
13245             DWORD dwOffsetBase = ReadyToRunInfo::GetFieldBaseOffset(pMT);
13246             if (dwOffsetBase > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13247                 return FALSE;
13248             result = dwOffsetBase;
13249         }
13250         break;
13251
13252     case ENCODE_CHECK_TYPE_LAYOUT:
13253         {
13254             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13255             MethodTable * pMT = th.AsMethodTable();
13256             _ASSERTE(pMT->IsValueType());
13257
13258             if (!TypeLayoutCheck(pMT, pBlob))
13259                 return FALSE;
13260
13261             result = 1;
13262         }
13263         break;
13264
13265     case ENCODE_CHECK_FIELD_OFFSET:
13266         {
13267             DWORD dwExpectedOffset = CorSigUncompressData(pBlob);
13268
13269             FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13270             _ASSERTE(!pFD->IsStatic());
13271
13272             DWORD dwOffset = pFD->GetOffset();
13273             if (!pFD->IsFieldOfValueType())
13274                 dwOffset += sizeof(Object);
13275
13276             if (dwExpectedOffset != dwOffset)
13277                 return FALSE;
13278
13279             result = 1;
13280         }
13281         break;
13282 #endif // FEATURE_READYTORUN
13283
13284 #endif // CROSSGEN_COMPILE
13285
13286     default:
13287         STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown FIXUP_BLOB_KIND %d\n", kind);
13288         _ASSERTE(!"Unknown FIXUP_BLOB_KIND");
13289         return FALSE;
13290     }
13291
13292     MemoryBarrier();
13293     *EnsureWritablePages(entry) = result;
13294
13295     return TRUE;
13296 }
13297 #endif // FEATURE_PREJIT
13298
13299 void* CEEInfo::getTailCallCopyArgsThunk(CORINFO_SIG_INFO       *pSig,
13300                                         CorInfoHelperTailCallSpecialHandling flags)
13301 {
13302     CONTRACTL {
13303         SO_TOLERANT;
13304         THROWS;
13305         GC_TRIGGERS;
13306         MODE_PREEMPTIVE;
13307     } CONTRACTL_END;
13308
13309     void * ftn = NULL;
13310
13311 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)
13312
13313     JIT_TO_EE_TRANSITION();
13314
13315     Stub* pStub = CPUSTUBLINKER::CreateTailCallCopyArgsThunk(pSig, flags);
13316         
13317     ftn = (void*)pStub->GetEntryPoint();
13318
13319     EE_TO_JIT_TRANSITION();
13320
13321 #endif // _TARGET_AMD64_ || _TARGET_ARM_
13322
13323     return ftn;
13324 }
13325
13326 void CEEInfo::allocMem (
13327         ULONG               hotCodeSize,    /* IN */
13328         ULONG               coldCodeSize,   /* IN */
13329         ULONG               roDataSize,     /* IN */
13330         ULONG               xcptnsCount,    /* IN */
13331         CorJitAllocMemFlag  flag,           /* IN */
13332         void **             hotCodeBlock,   /* OUT */
13333         void **             coldCodeBlock,  /* OUT */
13334         void **             roDataBlock     /* OUT */
13335         )
13336 {
13337     LIMITED_METHOD_CONTRACT;
13338     UNREACHABLE();      // only called on derived class.
13339 }
13340
13341 void CEEInfo::reserveUnwindInfo (
13342         BOOL                isFunclet,             /* IN */
13343         BOOL                isColdCode,            /* IN */
13344         ULONG               unwindSize             /* IN */
13345         )
13346 {
13347     LIMITED_METHOD_CONTRACT;
13348     UNREACHABLE();      // only called on derived class.
13349 }
13350
13351 void CEEInfo::allocUnwindInfo (
13352         BYTE *              pHotCode,              /* IN */
13353         BYTE *              pColdCode,             /* IN */
13354         ULONG               startOffset,           /* IN */
13355         ULONG               endOffset,             /* IN */
13356         ULONG               unwindSize,            /* IN */
13357         BYTE *              pUnwindBlock,          /* IN */
13358         CorJitFuncKind      funcKind               /* IN */
13359         )
13360 {
13361     LIMITED_METHOD_CONTRACT;
13362     UNREACHABLE();      // only called on derived class.
13363 }
13364
13365 void * CEEInfo::allocGCInfo (
13366         size_t                  size        /* IN */
13367         )
13368 {
13369     LIMITED_METHOD_CONTRACT;
13370     UNREACHABLE_RET();      // only called on derived class.
13371 }
13372
13373 void CEEInfo::setEHcount (
13374         unsigned             cEH    /* IN */
13375         )
13376 {
13377     LIMITED_METHOD_CONTRACT;
13378     UNREACHABLE();      // only called on derived class.
13379 }
13380
13381 void CEEInfo::setEHinfo (
13382         unsigned             EHnumber,   /* IN  */
13383         const CORINFO_EH_CLAUSE *clause      /* IN */
13384         )
13385 {
13386     LIMITED_METHOD_CONTRACT;
13387     UNREACHABLE();      // only called on derived class.
13388 }
13389
13390 InfoAccessType CEEInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
13391                                                mdToken metaTok,
13392                                                void **ppValue)
13393 {
13394     LIMITED_METHOD_CONTRACT;
13395     UNREACHABLE();      // only called on derived class.
13396 }
13397
13398 InfoAccessType CEEInfo::emptyStringLiteral(void ** ppValue)
13399 {
13400     LIMITED_METHOD_CONTRACT;
13401     _ASSERTE(isVerifyOnly());
13402     *ppValue = (void *)0x10;
13403     return IAT_PVALUE;
13404 }
13405
13406 void* CEEInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
13407                                   void **ppIndirection)
13408 {
13409     LIMITED_METHOD_CONTRACT;
13410     _ASSERTE(isVerifyOnly());
13411     if (ppIndirection != NULL)
13412         *ppIndirection = NULL;
13413     return (void *)0x10;
13414 }
13415
13416 void* CEEInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
13417                              void **ppIndirection)
13418 {
13419     LIMITED_METHOD_CONTRACT;
13420     UNREACHABLE();      // only called on derived class.
13421 }
13422
13423 HRESULT CEEInfo::allocBBProfileBuffer (
13424         ULONG                 count,           // The number of basic blocks that we have
13425         ProfileBuffer **      profileBuffer
13426         )
13427 {
13428     LIMITED_METHOD_CONTRACT;
13429     UNREACHABLE_RET();      // only called on derived class.
13430 }
13431
13432 HRESULT CEEInfo::getBBProfileData(
13433         CORINFO_METHOD_HANDLE ftnHnd,
13434         ULONG *               count,           // The number of basic blocks that we have
13435         ProfileBuffer **      profileBuffer,
13436         ULONG *               numRuns
13437         )
13438 {
13439     LIMITED_METHOD_CONTRACT;
13440     UNREACHABLE_RET();      // only called on derived class.
13441 }
13442
13443
13444 void CEEInfo::recordCallSite(
13445         ULONG                 instrOffset,  /* IN */
13446         CORINFO_SIG_INFO *    callSig,      /* IN */
13447         CORINFO_METHOD_HANDLE methodHandle  /* IN */
13448         )
13449 {
13450     LIMITED_METHOD_CONTRACT;
13451     UNREACHABLE();      // only called on derived class.
13452 }
13453
13454 void CEEInfo::recordRelocation(
13455         void *                 location,   /* IN  */
13456         void *                 target,     /* IN  */
13457         WORD                   fRelocType, /* IN  */
13458         WORD                   slotNum,  /* IN  */
13459         INT32                  addlDelta /* IN  */
13460         )
13461 {
13462     LIMITED_METHOD_CONTRACT;
13463     UNREACHABLE();      // only called on derived class.
13464 }
13465
13466 WORD CEEInfo::getRelocTypeHint(void * target)
13467 {
13468     LIMITED_METHOD_CONTRACT;
13469     UNREACHABLE_RET();      // only called on derived class.
13470 }
13471
13472 void CEEInfo::getModuleNativeEntryPointRange(
13473         void ** pStart, /* OUT */
13474         void ** pEnd    /* OUT */
13475         )
13476 {
13477     LIMITED_METHOD_CONTRACT;
13478     UNREACHABLE();      // only called on derived class.
13479 }
13480
13481 DWORD CEEInfo::getExpectedTargetArchitecture()
13482 {
13483     LIMITED_METHOD_CONTRACT;
13484
13485     return IMAGE_FILE_MACHINE_NATIVE;
13486 }
13487
13488 void CEEInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
13489                                ICorDebugInfo::OffsetMapping *pMap)
13490 {
13491     LIMITED_METHOD_CONTRACT;
13492     UNREACHABLE();      // only called on derived class.
13493 }
13494
13495 void CEEInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
13496 {
13497     LIMITED_METHOD_CONTRACT;
13498     UNREACHABLE();      // only called on derived class.
13499 }
13500
13501 void* CEEInfo::getHelperFtn(CorInfoHelpFunc    ftnNum,         /* IN  */
13502                             void **            ppIndirection)  /* OUT */
13503 {
13504     LIMITED_METHOD_CONTRACT;
13505     UNREACHABLE();      // only called on derived class.
13506 }
13507
13508 // Active dependency helpers
13509 void CEEInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
13510 {
13511     LIMITED_METHOD_CONTRACT;
13512     UNREACHABLE();      // only called on derived class.
13513 }
13514
13515 void CEEInfo::GetProfilingHandle(BOOL                      *pbHookFunction,
13516                                  void                     **pProfilerHandle,
13517                                  BOOL                      *pbIndirectedHandles)
13518 {
13519     LIMITED_METHOD_CONTRACT;
13520     UNREACHABLE();      // only called on derived class.
13521 }
13522
13523 #endif // !DACCESS_COMPILE
13524
13525 EECodeInfo::EECodeInfo()
13526 {
13527     WRAPPER_NO_CONTRACT;
13528
13529     m_codeAddress = NULL;
13530
13531     m_pJM = NULL;
13532     m_pMD = NULL;
13533     m_relOffset = 0;
13534
13535 #ifdef WIN64EXCEPTIONS
13536     m_pFunctionEntry = NULL;
13537 #endif
13538 }
13539
13540 void EECodeInfo::Init(PCODE codeAddress)
13541 {
13542     CONTRACTL {
13543         NOTHROW;
13544         GC_NOTRIGGER;
13545         SO_TOLERANT;
13546     } CONTRACTL_END;
13547
13548     Init(codeAddress, ExecutionManager::GetScanFlags());
13549 }
13550
13551 void EECodeInfo::Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag)
13552 {
13553     CONTRACTL {
13554         NOTHROW;
13555         GC_NOTRIGGER;
13556         SO_TOLERANT;
13557     } CONTRACTL_END;
13558
13559     m_codeAddress = codeAddress;
13560
13561     RangeSection * pRS = ExecutionManager::FindCodeRange(codeAddress, scanFlag);
13562     if (pRS == NULL)
13563         goto Invalid;
13564
13565     if (!pRS->pjit->JitCodeToMethodInfo(pRS, codeAddress, &m_pMD, this))
13566         goto Invalid;
13567
13568     m_pJM = pRS->pjit;
13569     return;
13570
13571 Invalid:
13572     m_pJM = NULL;
13573     m_pMD = NULL;
13574     m_relOffset = 0;
13575
13576 #ifdef WIN64EXCEPTIONS
13577     m_pFunctionEntry = NULL;
13578 #endif
13579 }
13580
13581 TADDR EECodeInfo::GetSavedMethodCode()
13582 {
13583     CONTRACTL {
13584         // All EECodeInfo methods must be NOTHROW/GC_NOTRIGGER since they can
13585         // be used during GC.
13586         NOTHROW;
13587         GC_NOTRIGGER;
13588         HOST_NOCALLS;
13589         SUPPORTS_DAC;
13590     } CONTRACTL_END;
13591 #ifndef _WIN64
13592 #if defined(HAVE_GCCOVER)
13593     _ASSERTE (!m_pMD->m_GcCover || GCStress<cfg_instr>::IsEnabled());
13594     if (GCStress<cfg_instr>::IsEnabled()
13595         && m_pMD->m_GcCover)
13596     {
13597         _ASSERTE(m_pMD->m_GcCover->savedCode);
13598
13599         // Make sure we return the TADDR of savedCode here.  The byte array is not marshaled automatically.
13600         // The caller is responsible for any necessary marshaling.
13601         return PTR_TO_MEMBER_TADDR(GCCoverageInfo, m_pMD->m_GcCover, savedCode);
13602     }
13603 #endif //defined(HAVE_GCCOVER)
13604 #endif
13605
13606     return GetStartAddress();
13607 }
13608
13609 TADDR EECodeInfo::GetStartAddress()
13610 {
13611     CONTRACTL {
13612         NOTHROW;
13613         GC_NOTRIGGER;
13614         HOST_NOCALLS;
13615         SUPPORTS_DAC;
13616     } CONTRACTL_END;
13617
13618     return m_pJM->JitTokenToStartAddress(m_methodToken);
13619 }
13620
13621 #if defined(WIN64EXCEPTIONS)
13622
13623 // ----------------------------------------------------------------------------
13624 // EECodeInfo::GetMainFunctionInfo
13625 //
13626 // Description: 
13627 //    Simple helper to transform a funclet's EECodeInfo into a parent function EECodeInfo.
13628 //
13629 // Return Value:
13630 //    An EECodeInfo for the start of the main function body (offset 0).
13631 //
13632
13633 EECodeInfo EECodeInfo::GetMainFunctionInfo()
13634 {
13635     LIMITED_METHOD_CONTRACT;
13636     SUPPORTS_DAC;
13637
13638     EECodeInfo result = *this;
13639     result.m_relOffset = 0;
13640     result.m_codeAddress = this->GetStartAddress();
13641     result.m_pFunctionEntry = NULL;
13642
13643     return result;
13644 }
13645
13646 PTR_RUNTIME_FUNCTION EECodeInfo::GetFunctionEntry()
13647 {
13648     LIMITED_METHOD_CONTRACT;
13649     SUPPORTS_DAC;
13650
13651     if (m_pFunctionEntry == NULL)
13652         m_pFunctionEntry = m_pJM->LazyGetFunctionEntry(this);
13653     return m_pFunctionEntry;
13654 }
13655
13656 #if defined(_TARGET_AMD64_)
13657
13658 BOOL EECodeInfo::HasFrameRegister()
13659 {
13660     LIMITED_METHOD_CONTRACT;
13661
13662     PTR_RUNTIME_FUNCTION pFuncEntry = GetFunctionEntry();
13663     _ASSERTE(pFuncEntry != NULL);
13664
13665     BOOL fHasFrameRegister = FALSE;
13666     PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(GetModuleBase() + pFuncEntry->UnwindData);
13667     if (pUnwindInfo->FrameRegister != 0)
13668     {
13669         fHasFrameRegister = TRUE;
13670         _ASSERTE(pUnwindInfo->FrameRegister == kRBP);
13671     }
13672
13673     return fHasFrameRegister;
13674 }
13675 #endif // defined(_TARGET_AMD64_)
13676
13677 #endif // defined(WIN64EXCEPTIONS)
13678
13679
13680 #if defined(_TARGET_AMD64_)
13681 // ----------------------------------------------------------------------------
13682 // EECodeInfo::GetUnwindInfoHelper
13683 //
13684 // Description: 
13685 //    Simple helper to return a pointer to the UNWIND_INFO given the offset to the unwind info.
13686 //    On DAC builds, this function will read the memory from the target process and create a host copy.
13687 //
13688 // Arguments:
13689 //    * unwindInfoOffset - This is the offset to the unwind info, relative to the beginning of the code heap
13690 //        for jitted code or to the module base for ngned code. this->GetModuleBase() will return the correct
13691 //        module base.
13692 //
13693 // Return Value:
13694 //    Return a pointer to the UNWIND_INFO.  On DAC builds, this function will create a host copy of the
13695 //    UNWIND_INFO and return a host pointer.  It will correctly read all of the memory for the variable-sized 
13696 //    unwind info.
13697 //
13698
13699 UNWIND_INFO * EECodeInfo::GetUnwindInfoHelper(ULONG unwindInfoOffset)
13700 {
13701 #if defined(DACCESS_COMPILE)
13702     return DacGetUnwindInfo(static_cast<TADDR>(this->GetModuleBase() + unwindInfoOffset));
13703 #else  // !DACCESS_COMPILE
13704     return reinterpret_cast<UNWIND_INFO *>(this->GetModuleBase() + unwindInfoOffset);
13705 #endif // !DACCESS_COMPILE
13706 }
13707
13708 // ----------------------------------------------------------------------------
13709 // EECodeInfo::GetFixedStackSize
13710 //
13711 // Description: 
13712 //    Return the fixed stack size of a specified managed method.  This function DOES NOT take current control
13713 //    PC into account.  So the fixed stack size returned by this function is not valid in the prolog or
13714 //    the epilog.
13715 //    
13716 // Return Value:
13717 //    Return the fixed stack size.
13718 //    
13719 // Notes:
13720 //    * For method with dynamic stack allocations, this function will return the fixed stack size on X64 (the
13721 //        stack size immediately after the prolog), and it will return 0 on IA64. This difference is due to
13722 //        the different unwind info encoding.
13723 //        
13724
13725 ULONG EECodeInfo::GetFixedStackSize()
13726 {
13727     WRAPPER_NO_CONTRACT;
13728     SUPPORTS_DAC;
13729
13730     ULONG uFixedStackSize = 0;
13731
13732     ULONG uDummy = 0;
13733     GetOffsetsFromUnwindInfo(&uFixedStackSize, &uDummy);
13734     
13735     return uFixedStackSize;
13736 }
13737
13738 #define kRBP    5
13739 // The information returned by this method is only valid if we are not in a prolog or an epilog.
13740 // Since this method is only used for the security stackwalk cache, this assumption is valid, since
13741 // we cannot make a call in a prolog or an epilog.
13742 //
13743 // The next assumption is that only rbp is used as a frame register in jitted code.  There is an 
13744 // assert below to guard this assumption.
13745 void EECodeInfo::GetOffsetsFromUnwindInfo(ULONG* pRSPOffset, ULONG* pRBPOffset)
13746 {
13747     LIMITED_METHOD_CONTRACT;
13748     SUPPORTS_DAC;
13749
13750     _ASSERTE((pRSPOffset != NULL) && (pRBPOffset != NULL));
13751
13752     // moduleBase is a target address.
13753     TADDR moduleBase = GetModuleBase();
13754
13755     DWORD unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(GetFunctionEntry());
13756
13757     if ((unwindInfo & RUNTIME_FUNCTION_INDIRECT) != 0)
13758     {
13759         unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(PTR_RUNTIME_FUNCTION(moduleBase + (unwindInfo & ~RUNTIME_FUNCTION_INDIRECT)));
13760     }
13761
13762     UNWIND_INFO * pInfo = GetUnwindInfoHelper(unwindInfo);
13763     if (pInfo->Flags & UNW_FLAG_CHAININFO)
13764     {
13765         _ASSERTE(!"GetRbpOffset() - chained unwind info used, violating assumptions of the security stackwalk cache");
13766         DebugBreak();
13767     }
13768
13769     // Either we are not using a frame pointer, or we are using rbp as the frame pointer.
13770     if ( (pInfo->FrameRegister != 0) && (pInfo->FrameRegister != kRBP) )
13771     {
13772         _ASSERTE(!"GetRbpOffset() - non-RBP frame pointer used, violating assumptions of the security stackwalk cache");
13773         DebugBreak();
13774     }
13775
13776     // Walk the unwind info.
13777     ULONG StackOffset     = 0;
13778     ULONG StackSize       = 0;
13779     for (int i = 0; i < pInfo->CountOfUnwindCodes; i++)
13780     {
13781         ULONG UnwindOp = pInfo->UnwindCode[i].UnwindOp;
13782         ULONG OpInfo   = pInfo->UnwindCode[i].OpInfo;
13783
13784         if (UnwindOp == UWOP_SAVE_NONVOL)
13785         {
13786             if (OpInfo == kRBP)
13787             {
13788                 StackOffset = pInfo->UnwindCode[i+1].FrameOffset * 8;
13789             }
13790         }
13791         else if (UnwindOp == UWOP_SAVE_NONVOL_FAR)
13792         {
13793             if (OpInfo == kRBP)
13794             {
13795                 StackOffset  =  pInfo->UnwindCode[i + 1].FrameOffset;
13796                 StackOffset += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
13797             }
13798         }
13799         else if (UnwindOp == UWOP_ALLOC_SMALL)
13800         {
13801             StackSize += (OpInfo * 8) + 8;
13802         }
13803         else if (UnwindOp == UWOP_ALLOC_LARGE)
13804         {
13805             ULONG IncrementalStackSize = pInfo->UnwindCode[i + 1].FrameOffset;
13806             if (OpInfo == 0)
13807             {
13808                 IncrementalStackSize *= 8;
13809             }
13810             else
13811             {
13812                 IncrementalStackSize += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
13813  
13814                 // This is a special opcode.  We need to increment the index by 1 in addition to the normal adjustments.
13815                 i += 1;        
13816             }
13817             StackSize += IncrementalStackSize;
13818         }
13819         else if (UnwindOp == UWOP_PUSH_NONVOL)
13820         {
13821             // Because of constraints on epilogs, this unwind opcode is always last in the unwind code array.
13822             // This means that StackSize has been initialized already when we first see this unwind opcode.  
13823             // Note that the intial value of StackSize does not include the stack space used for pushes.
13824             // Thus, here we only need to increment StackSize 8 bytes at a time until we see the unwind code for "push rbp".
13825             if (OpInfo == kRBP)
13826             {
13827                 StackOffset = StackSize;
13828             }
13829
13830             StackSize += 8;
13831         }
13832
13833         // Adjust the index into the unwind code array.
13834         i += UnwindOpExtraSlotTable[UnwindOp];
13835     }
13836
13837     *pRSPOffset = StackSize + 8;        // add 8 for the return address
13838     *pRBPOffset = StackOffset;
13839 }
13840 #undef kRBP
13841
13842
13843 #if defined(_DEBUG) && defined(HAVE_GCCOVER)
13844
13845 LPVOID                EECodeInfo::findNextFunclet (LPVOID pvFuncletStart, SIZE_T cbCode, LPVOID *ppvFuncletEnd)
13846 {
13847     CONTRACTL {
13848         NOTHROW;
13849         GC_NOTRIGGER;
13850     } CONTRACTL_END;
13851
13852     while (cbCode > 0)
13853     {
13854         PT_RUNTIME_FUNCTION   pFunctionEntry;
13855         ULONGLONG           uImageBase;
13856 #ifdef FEATURE_PAL
13857         EECodeInfo codeInfo;
13858         codeInfo.Init((PCODE)pvFuncletStart);
13859         pFunctionEntry = codeInfo.GetFunctionEntry();
13860         uImageBase = (ULONGLONG)codeInfo.GetModuleBase();
13861 #else // !FEATURE_PAL
13862         //
13863         // This is GCStress debug only - use the slow OS APIs to enumerate funclets
13864         //
13865
13866         pFunctionEntry = (PT_RUNTIME_FUNCTION) RtlLookupFunctionEntry((ULONGLONG)pvFuncletStart,
13867                               &uImageBase
13868                               AMD64_ARG(NULL)
13869                               );
13870 #endif
13871
13872         if (pFunctionEntry != NULL)
13873         {
13874 #ifdef FEATURE_PREJIT
13875             // workaround: Check for indirect entry that is generated for cold part of main method body.
13876             if ((TADDR)pvFuncletStart < (TADDR)uImageBase + pFunctionEntry->BeginAddress ||
13877                 (TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart)
13878             {
13879                 Module * pZapModule = ExecutionManager::FindZapModule((TADDR)pvFuncletStart);
13880                 NGenLayoutInfo * pLayoutInfo = pZapModule->GetNGenLayoutInfo();
13881
13882                 int ColdFunctionIndex = NativeUnwindInfoLookupTable::LookupUnwindInfoForMethod((DWORD)((TADDR)pvFuncletStart - uImageBase),
13883                                                                                pLayoutInfo->m_pRuntimeFunctions[2],
13884                                                                                0, pLayoutInfo->m_nRuntimeFunctions[2] - 1);
13885
13886                 pFunctionEntry = pLayoutInfo->m_pRuntimeFunctions[2] + ColdFunctionIndex;
13887             }
13888 #endif
13889
13890             _ASSERTE((TADDR)pvFuncletStart == (TADDR)uImageBase + pFunctionEntry->BeginAddress);
13891             _ASSERTE((TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart + cbCode);
13892             *ppvFuncletEnd = (LPVOID)(uImageBase + pFunctionEntry->EndAddress);
13893             return (LPVOID)(uImageBase + pFunctionEntry->BeginAddress);
13894         }
13895
13896         pvFuncletStart = (LPVOID)((TADDR)pvFuncletStart + 1);
13897         cbCode--;
13898     }
13899
13900     return NULL;
13901 }
13902 #endif // defined(_DEBUG) && !defined(HAVE_GCCOVER)
13903 #endif // defined(_TARGET_AMD64_)