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