Sync may31 release/8.0-tizen (#510)
[platform/upstream/dotnet/runtime.git] / src / coreclr / 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 // ===========================================================================
4 // File: JITinterface.CPP
5 //
6
7 // ===========================================================================
8
9 #include "common.h"
10 #include "jitinterface.h"
11 #include "codeman.h"
12 #include "method.hpp"
13 #include "class.h"
14 #include "object.h"
15 #include "field.h"
16 #include "stublink.h"
17 #include "virtualcallstub.h"
18 #include "corjit.h"
19 #include "eeconfig.h"
20 #include "excep.h"
21 #include "log.h"
22 #include "excep.h"
23 #include "float.h"      // for isnan
24 #include "dbginterface.h"
25 #include "dllimport.h"
26 #include "callconvbuilder.hpp"
27 #include "gcheaputilities.h"
28 #include "comdelegate.h"
29 #include "corprof.h"
30 #include "eeprofinterfaces.h"
31 #ifdef PROFILING_SUPPORTED
32 #include "proftoeeinterfaceimpl.h"
33 #include "eetoprofinterfaceimpl.h"
34 #include "eetoprofinterfaceimpl.inl"
35 #include "profilepriv.h"
36 #include "rejit.h"
37 #endif // PROFILING_SUPPORTED
38 #include "ecall.h"
39 #include "generics.h"
40 #include "typestring.h"
41 #include "typedesc.h"
42 #include "genericdict.h"
43 #include "array.h"
44 #include "debuginfostore.h"
45 #include "safemath.h"
46 #include "runtimehandles.h"
47 #include "sigbuilder.h"
48 #include "openum.h"
49 #include "fieldmarshaler.h"
50 #ifdef HAVE_GCCOVER
51 #include "gccover.h"
52 #endif // HAVE_GCCOVER
53
54 #ifdef FEATURE_INTERPRETER
55 #include "interpreter.h"
56 #endif // FEATURE_INTERPRETER
57
58 #ifdef FEATURE_PERFMAP
59 #include "perfmap.h"
60 #endif
61
62 #ifdef FEATURE_PGO
63 #include "pgo.h"
64 #endif
65
66 #include "tailcallhelp.h"
67
68 #ifdef TARGET_WINDOWS
69 EXTERN_C uint32_t _tls_index;
70 #endif
71
72 struct ThreadStaticBlockInfo
73 {
74     uint32_t NonGCMaxThreadStaticBlocks;
75     void** NonGCThreadStaticBlocks;
76
77     uint32_t GCMaxThreadStaticBlocks;
78     void** GCThreadStaticBlocks;
79 };
80 #ifdef _MSC_VER
81 __declspec(selectany) __declspec(thread)  ThreadStaticBlockInfo t_ThreadStatics;
82 __declspec(selectany) __declspec(thread)  uint32_t t_NonGCThreadStaticBlocksSize;
83 __declspec(selectany) __declspec(thread)  uint32_t t_GCThreadStaticBlocksSize;
84 #else
85 extern "C" void* __tls_get_addr(void* ti);
86 __thread ThreadStaticBlockInfo t_ThreadStatics;
87 __thread uint32_t t_NonGCThreadStaticBlocksSize;
88 __thread uint32_t t_GCThreadStaticBlocksSize;
89 #endif // _MSC_VER
90
91 // The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro
92 //
93
94 #define JIT_TO_EE_TRANSITION()          MAKE_CURRENT_THREAD_AVAILABLE_EX(m_pThread);                \
95                                         INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE;               \
96                                         COOPERATIVE_TRANSITION_BEGIN();                             \
97
98 #define EE_TO_JIT_TRANSITION()          COOPERATIVE_TRANSITION_END();                               \
99                                         UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE;
100
101 #define JIT_TO_EE_TRANSITION_LEAF()
102 #define EE_TO_JIT_TRANSITION_LEAF()
103
104 #ifdef DACCESS_COMPILE
105
106 // The real definitions are in jithelpers.cpp. However, those files are not included in the DAC build.
107 // Hence, we add them here.
108 GARY_IMPL(VMHELPDEF, hlpFuncTable, CORINFO_HELP_COUNT);
109 GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);
110
111 #else // DACCESS_COMPILE
112
113 Volatile<int64_t> g_cbILJitted = 0;
114 Volatile<int64_t> g_cMethodsJitted = 0;
115 Volatile<int64_t> g_c100nsTicksInJit = 0;
116 thread_local int64_t t_cbILJittedForThread = 0;
117 thread_local int64_t t_cMethodsJittedForThread = 0;
118 thread_local int64_t t_c100nsTicksInJitForThread = 0;
119
120 // This prevents tearing of 64 bit values on 32 bit systems
121 static inline
122 int64_t AtomicLoad64WithoutTearing(int64_t volatile *valueRef)
123 {
124     WRAPPER_NO_CONTRACT;
125 #if TARGET_64BIT
126     return VolatileLoad(valueRef);
127 #else
128     return InterlockedCompareExchangeT((LONG64 volatile *)valueRef, (LONG64)0, (LONG64)0);
129 #endif // TARGET_64BIT
130 }
131
132 FCIMPL1(INT64, GetCompiledILBytes, CLR_BOOL currentThread)
133 {
134     FCALL_CONTRACT;
135
136     return currentThread ? t_cbILJittedForThread : AtomicLoad64WithoutTearing(&g_cbILJitted);
137 }
138 FCIMPLEND
139
140 FCIMPL1(INT64, GetCompiledMethodCount, CLR_BOOL currentThread)
141 {
142     FCALL_CONTRACT;
143
144     return currentThread ? t_cMethodsJittedForThread : AtomicLoad64WithoutTearing(&g_cMethodsJitted);
145 }
146 FCIMPLEND
147
148 FCIMPL1(INT64, GetCompilationTimeInTicks, CLR_BOOL currentThread)
149 {
150     FCALL_CONTRACT;
151
152     return currentThread ? t_c100nsTicksInJitForThread : AtomicLoad64WithoutTearing(&g_c100nsTicksInJit);
153 }
154 FCIMPLEND
155
156 /*********************************************************************/
157
158 inline CORINFO_MODULE_HANDLE GetScopeHandle(MethodDesc* method)
159 {
160     LIMITED_METHOD_CONTRACT;
161     if (method->IsDynamicMethod())
162     {
163         return MakeDynamicScope(method->AsDynamicMethodDesc()->GetResolver());
164     }
165     else
166     {
167         return GetScopeHandle(method->GetModule());
168     }
169 }
170
171 //This is common refactored code from within several of the access check functions.
172 static BOOL ModifyCheckForDynamicMethod(DynamicResolver *pResolver,
173                                  TypeHandle *pOwnerTypeForSecurity,
174                                  AccessCheckOptions::AccessCheckType *pAccessCheckType,
175                                  DynamicResolver** ppAccessContext)
176 {
177     CONTRACTL {
178         STANDARD_VM_CHECK;
179         PRECONDITION(CheckPointer(pResolver));
180         PRECONDITION(CheckPointer(pOwnerTypeForSecurity));
181         PRECONDITION(CheckPointer(pAccessCheckType));
182         PRECONDITION(CheckPointer(ppAccessContext));
183         PRECONDITION(*pAccessCheckType == AccessCheckOptions::kNormalAccessibilityChecks);
184     } CONTRACTL_END;
185
186     BOOL doAccessCheck = TRUE;
187
188     //Do not blindly initialize fields, since they've already got important values.
189     DynamicResolver::SecurityControlFlags dwSecurityFlags = DynamicResolver::Default;
190
191     TypeHandle dynamicOwner;
192     pResolver->GetJitContext(&dwSecurityFlags, &dynamicOwner);
193     if (!dynamicOwner.IsNull())
194         *pOwnerTypeForSecurity = dynamicOwner;
195
196     if (dwSecurityFlags & DynamicResolver::SkipVisibilityChecks)
197     {
198         doAccessCheck = FALSE;
199     }
200     else if (dwSecurityFlags & DynamicResolver::RestrictedSkipVisibilityChecks)
201     {
202         *pAccessCheckType = AccessCheckOptions::kRestrictedMemberAccessNoTransparency;
203     }
204     else
205     {
206         *pAccessCheckType = AccessCheckOptions::kNormalAccessNoTransparency;
207     }
208
209     return doAccessCheck;
210 }
211
212 TransientMethodDetails::TransientMethodDetails(MethodDesc* pMD, _In_opt_ COR_ILMETHOD_DECODER* header, CORINFO_MODULE_HANDLE scope)
213     : Method{ pMD }
214     , Header{ header }
215     , Scope{ scope }
216 {
217     LIMITED_METHOD_CONTRACT;
218     _ASSERTE(Method != NULL);
219     _ASSERTE(Scope == NULL || IsDynamicScope(Scope));
220 }
221
222 TransientMethodDetails::TransientMethodDetails(TransientMethodDetails&& other)
223 {
224     LIMITED_METHOD_CONTRACT;
225     *this = std::move(other);
226 }
227
228 TransientMethodDetails::~TransientMethodDetails()
229 {
230     CONTRACTL
231     {
232         NOTHROW;
233         GC_NOTRIGGER;
234         MODE_ANY;
235     }
236     CONTRACTL_END;
237
238     // If the supplied scope is dynamic, release resources.
239     if (IsDynamicScope(Scope))
240     {
241         DynamicResolver* resolver = GetDynamicResolver(Scope);
242         resolver->FreeCompileTimeState();
243         delete resolver;
244     }
245 }
246
247 TransientMethodDetails& TransientMethodDetails::operator=(TransientMethodDetails&& other)
248 {
249     LIMITED_METHOD_CONTRACT;
250     if (this != &other)
251     {
252         Method = other.Method;
253         Header = other.Header;
254         Scope = other.Scope;
255         other.Method = NULL;
256         other.Header = NULL;
257         other.Scope = NULL;
258     }
259     return *this;
260 }
261
262 /*****************************************************************************/
263
264 // Initialize from data we passed across to the JIT
265 void CEEInfo::GetTypeContext(const CORINFO_SIG_INST *info, SigTypeContext *pTypeContext)
266 {
267     LIMITED_METHOD_CONTRACT;
268     SigTypeContext::InitTypeContext(
269         Instantiation((TypeHandle *) info->classInst, info->classInstCount),
270         Instantiation((TypeHandle *) info->methInst, info->methInstCount),
271         pTypeContext);
272 }
273
274 MethodDesc* CEEInfo::GetMethodFromContext(CORINFO_CONTEXT_HANDLE context)
275 {
276     LIMITED_METHOD_CONTRACT;
277
278     if (context == METHOD_BEING_COMPILED_CONTEXT())
279         return m_pMethodBeingCompiled;
280
281     if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
282     {
283         return NULL;
284     }
285     else
286     {
287         return GetMethod((CORINFO_METHOD_HANDLE)((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
288     }
289 }
290
291 TypeHandle CEEInfo::GetTypeFromContext(CORINFO_CONTEXT_HANDLE context)
292 {
293     LIMITED_METHOD_CONTRACT;
294
295     if (context == METHOD_BEING_COMPILED_CONTEXT())
296         return m_pMethodBeingCompiled->GetMethodTable();
297
298     if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
299     {
300         return TypeHandle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
301     }
302     else
303     {
304         return GetMethod((CORINFO_METHOD_HANDLE)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK))->GetMethodTable();
305     }
306 }
307
308 // Initialize from a context parameter passed to the JIT and back.  This is a parameter
309 // that indicates which method is being jitted.
310
311 void CEEInfo::GetTypeContext(CORINFO_CONTEXT_HANDLE context, SigTypeContext *pTypeContext)
312 {
313     CONTRACTL
314     {
315         NOTHROW;
316         GC_NOTRIGGER;
317         MODE_ANY;
318         PRECONDITION(context != NULL);
319     }
320     CONTRACTL_END;
321     MethodDesc* pMD = GetMethodFromContext(context);
322     if (pMD != NULL)
323     {
324         SigTypeContext::InitTypeContext(pMD, pTypeContext);
325     }
326     else
327     {
328         SigTypeContext::InitTypeContext(GetTypeFromContext(context), pTypeContext);
329     }
330 }
331
332 /*********************************************************************/
333 // This normalizes EE type information into the form expected by the JIT.
334 //
335 // If typeHnd contains exact type information, then *clsRet will contain
336 // the normalized CORINFO_CLASS_HANDLE information on return.
337
338 // Static
339 CorInfoType CEEInfo::asCorInfoType(CorElementType eeType,
340                                    TypeHandle typeHnd, /* optional in */
341                                    CORINFO_CLASS_HANDLE *clsRet/* optional out */ ) {
342     CONTRACT(CorInfoType) {
343         THROWS;
344         GC_TRIGGERS;
345         PRECONDITION((CorTypeInfo::IsGenericVariable(eeType)) ==
346                      (!typeHnd.IsNull() && typeHnd.IsGenericVariable()));
347         PRECONDITION(eeType != ELEMENT_TYPE_GENERICINST);
348     } CONTRACT_END;
349
350     TypeHandle typeHndUpdated = typeHnd;
351
352     if (!typeHnd.IsNull())
353     {
354         CorElementType normType = typeHnd.GetInternalCorElementType();
355         // If we have a type handle, then it has the better type
356         // in some cases
357         if (eeType == ELEMENT_TYPE_VALUETYPE && !CorTypeInfo::IsObjRef(normType))
358             eeType = normType;
359
360         // Zap the typeHnd when the type _really_ is a primitive
361         // as far as verification is concerned. Returning a null class
362         // handle means it is a primitive.
363         //
364         // Enums are exactly like primitives, even from a verification standpoint,
365         // so we zap the type handle in this case.
366         //
367         // However RuntimeTypeHandle etc. are reported as E_T_INT (or something like that)
368         // but don't count as primitives as far as verification is concerned...
369         //
370         // To make things stranger, TypedReference returns true for "IsTruePrimitive".
371         // However the JIT likes us to report the type handle in that case.
372         if (!typeHnd.IsTypeDesc() && (
373                 (typeHnd.AsMethodTable()->IsTruePrimitive() && typeHnd != TypeHandle(g_TypedReferenceMT))
374                     || typeHnd.AsMethodTable()->IsEnum()) )
375         {
376             typeHndUpdated = TypeHandle();
377         }
378
379     }
380
381     static const BYTE map[] = {
382         CORINFO_TYPE_UNDEF,
383         CORINFO_TYPE_VOID,
384         CORINFO_TYPE_BOOL,
385         CORINFO_TYPE_CHAR,
386         CORINFO_TYPE_BYTE,
387         CORINFO_TYPE_UBYTE,
388         CORINFO_TYPE_SHORT,
389         CORINFO_TYPE_USHORT,
390         CORINFO_TYPE_INT,
391         CORINFO_TYPE_UINT,
392         CORINFO_TYPE_LONG,
393         CORINFO_TYPE_ULONG,
394         CORINFO_TYPE_FLOAT,
395         CORINFO_TYPE_DOUBLE,
396         CORINFO_TYPE_STRING,
397         CORINFO_TYPE_PTR,            // PTR
398         CORINFO_TYPE_BYREF,
399         CORINFO_TYPE_VALUECLASS,
400         CORINFO_TYPE_CLASS,
401         CORINFO_TYPE_VAR,            // VAR (type variable)
402         CORINFO_TYPE_CLASS,          // ARRAY
403         CORINFO_TYPE_CLASS,          // WITH
404         CORINFO_TYPE_REFANY,
405         CORINFO_TYPE_UNDEF,          // VALUEARRAY_UNSUPPORTED
406         CORINFO_TYPE_NATIVEINT,      // I
407         CORINFO_TYPE_NATIVEUINT,     // U
408         CORINFO_TYPE_UNDEF,          // R_UNSUPPORTED
409
410         // put the correct type when we know our implementation
411         CORINFO_TYPE_PTR,            // FNPTR
412         CORINFO_TYPE_CLASS,          // OBJECT
413         CORINFO_TYPE_CLASS,          // SZARRAY
414         CORINFO_TYPE_VAR,            // MVAR
415
416         CORINFO_TYPE_UNDEF,          // CMOD_REQD
417         CORINFO_TYPE_UNDEF,          // CMOD_OPT
418         CORINFO_TYPE_UNDEF,          // INTERNAL
419         };
420
421     _ASSERTE(sizeof(map) == ELEMENT_TYPE_MAX);
422     _ASSERTE(eeType < (CorElementType) sizeof(map));
423         // spot check of the map
424     _ASSERTE((CorInfoType) map[ELEMENT_TYPE_I4] == CORINFO_TYPE_INT);
425     _ASSERTE((CorInfoType) map[ELEMENT_TYPE_PTR] == CORINFO_TYPE_PTR);
426     _ASSERTE((CorInfoType) map[ELEMENT_TYPE_TYPEDBYREF] == CORINFO_TYPE_REFANY);
427
428     CorInfoType res = ((unsigned)eeType < ELEMENT_TYPE_MAX) ? ((CorInfoType) map[(unsigned)eeType]) : CORINFO_TYPE_UNDEF;
429
430     if (clsRet)
431         *clsRet = CORINFO_CLASS_HANDLE(typeHndUpdated.AsPtr());
432
433     RETURN res;
434 }
435
436
437 inline static CorInfoType toJitType(TypeHandle typeHnd, CORINFO_CLASS_HANDLE *clsRet = NULL)
438 {
439     WRAPPER_NO_CONTRACT;
440     return CEEInfo::asCorInfoType(typeHnd.GetInternalCorElementType(), typeHnd, clsRet);
441 }
442
443 enum ConvToJitSigFlags : int
444 {
445     CONV_TO_JITSIG_FLAGS_NONE       = 0x0,
446     CONV_TO_JITSIG_FLAGS_LOCALSIG   = 0x1,
447 };
448
449 //---------------------------------------------------------------------------------------
450 //
451 //@GENERICS:
452 // The method handle is used to instantiate method and class type parameters
453 // It's also used to determine whether an extra dictionary parameter is required
454 //
455 // sig          - Input metadata signature
456 // scopeHnd     - The signature is to be interpreted in the context of this scope (module)
457 // token        - Metadata token used to refer to the signature (may be mdTokenNil for dynamic methods)
458 // sigRet       - Resulting output signature in a format that is understood by native compilers
459 // pContextMD   - The method with any instantiation information (may be NULL)
460 // localSig     - Is it a local variables declaration, or a method signature (with return type, etc).
461 // contextType  - The type with any instantiaton information
462 //
463 static void ConvToJitSig(
464     PCCOR_SIGNATURE       pSig,
465     DWORD                 cbSig,
466     CORINFO_MODULE_HANDLE scopeHnd,
467     mdToken               token,
468     SigTypeContext*       typeContext,
469     ConvToJitSigFlags     flags,
470     CORINFO_SIG_INFO *    sigRet)
471 {
472     CONTRACTL {
473         THROWS;
474         GC_TRIGGERS;
475     } CONTRACTL_END;
476
477     uint32_t sigRetFlags = 0;
478
479     static_assert_no_msg(CORINFO_CALLCONV_DEFAULT == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_DEFAULT);
480     static_assert_no_msg(CORINFO_CALLCONV_VARARG == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_VARARG);
481     static_assert_no_msg(CORINFO_CALLCONV_MASK == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_MASK);
482     static_assert_no_msg(CORINFO_CALLCONV_HASTHIS == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_HASTHIS);
483
484     TypeHandle typeHnd = TypeHandle();
485
486     sigRet->pSig = pSig;
487     sigRet->cbSig = cbSig;
488     sigRet->methodSignature = 0;
489     sigRet->retTypeClass = 0;
490     sigRet->retTypeSigClass = 0;
491     sigRet->scope = scopeHnd;
492     sigRet->token = token;
493     sigRet->sigInst.classInst = (CORINFO_CLASS_HANDLE *) typeContext->m_classInst.GetRawArgs();
494     sigRet->sigInst.classInstCount = (unsigned) typeContext->m_classInst.GetNumArgs();
495     sigRet->sigInst.methInst = (CORINFO_CLASS_HANDLE *) typeContext->m_methodInst.GetRawArgs();
496     sigRet->sigInst.methInstCount = (unsigned) typeContext->m_methodInst.GetNumArgs();
497
498     SigPointer sig(pSig, cbSig);
499
500     if ((flags & CONV_TO_JITSIG_FLAGS_LOCALSIG) == 0)
501     {
502         // This is a method signature which includes calling convention, return type,
503         // arguments, etc
504
505         _ASSERTE(!sig.IsNull());
506         Module * module = GetModule(scopeHnd);
507
508         uint32_t data;
509         IfFailThrow(sig.GetCallingConvInfo(&data));
510         sigRet->callConv = (CorInfoCallConv) data;
511
512 #if defined(TARGET_UNIX) || defined(TARGET_ARM)
513         if ((isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_VARARG)) ||
514             (isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_NATIVEVARARG)))
515         {
516             // This signature corresponds to a method that uses varargs, which are not supported.
517              COMPlusThrow(kInvalidProgramException, IDS_EE_VARARG_NOT_SUPPORTED);
518         }
519 #endif // defined(TARGET_UNIX) || defined(TARGET_ARM)
520
521         // Skip number of type arguments
522         if (sigRet->callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
523           IfFailThrow(sig.GetData(NULL));
524
525         uint32_t numArgs;
526         IfFailThrow(sig.GetData(&numArgs));
527         if (numArgs != (unsigned short) numArgs)
528             COMPlusThrowHR(COR_E_INVALIDPROGRAM);
529
530         sigRet->numArgs = (unsigned short) numArgs;
531
532         CorElementType type = sig.PeekElemTypeClosed(module, typeContext);
533
534         if (!CorTypeInfo::IsPrimitiveType(type))
535         {
536             typeHnd = sig.GetTypeHandleThrowing(module, typeContext);
537             _ASSERTE(!typeHnd.IsNull());
538
539             // I believe it doesn't make any diff. if this is
540             // GetInternalCorElementType or GetSignatureCorElementType
541             type = typeHnd.GetSignatureCorElementType();
542
543         }
544         sigRet->retType = CEEInfo::asCorInfoType(type, typeHnd, &sigRet->retTypeClass);
545         sigRet->retTypeSigClass = CORINFO_CLASS_HANDLE(typeHnd.AsPtr());
546
547         IfFailThrow(sig.SkipExactlyOne());  // must to a skip so we skip any class tokens associated with the return type
548         _ASSERTE(sigRet->retType < CORINFO_TYPE_COUNT);
549
550         sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
551     }
552     else
553     {
554         // This is local variables declaration
555         sigRetFlags |= CORINFO_SIGFLAG_IS_LOCAL_SIG;
556
557         sigRet->callConv = CORINFO_CALLCONV_DEFAULT;
558         sigRet->retType = CORINFO_TYPE_VOID;
559         sigRet->numArgs = 0;
560         if (!sig.IsNull())
561         {
562             uint32_t callConv;
563             IfFailThrow(sig.GetCallingConvInfo(&callConv));
564             if (callConv != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG)
565             {
566                 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_CALLCONV_NOT_LOCAL_SIG);
567             }
568
569             uint32_t numArgs;
570             IfFailThrow(sig.GetData(&numArgs));
571
572             if (numArgs != (unsigned short) numArgs)
573                 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
574
575             sigRet->numArgs = (unsigned short) numArgs;
576         }
577
578         sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
579     }
580
581     // Set computed flags
582     sigRet->flags = sigRetFlags;
583
584     _ASSERTE(SigInfoFlagsAreValid(sigRet));
585 } // ConvToJitSig
586
587 //---------------------------------------------------------------------------------------
588 //
589 CORINFO_CLASS_HANDLE CEEInfo::getTokenTypeAsHandle (CORINFO_RESOLVED_TOKEN * pResolvedToken)
590 {
591     CONTRACTL {
592         THROWS;
593         GC_TRIGGERS;
594         MODE_PREEMPTIVE;
595     } CONTRACTL_END;
596
597     CORINFO_CLASS_HANDLE tokenType = NULL;
598
599     JIT_TO_EE_TRANSITION();
600
601     _ASSERTE((pResolvedToken->hMethod == NULL) || (pResolvedToken->hField == NULL));
602
603     BinderClassID classID = CLASS__TYPE_HANDLE;
604
605     if (pResolvedToken->hMethod != NULL)
606     {
607         classID = CLASS__METHOD_HANDLE;
608     }
609     else
610     if (pResolvedToken->hField != NULL)
611     {
612         classID = CLASS__FIELD_HANDLE;
613     }
614
615     tokenType = CORINFO_CLASS_HANDLE(CoreLibBinder::GetClass(classID));
616
617     EE_TO_JIT_TRANSITION();
618
619     return tokenType;
620 }
621
622
623 int CEEInfo::getStringLiteral (
624         CORINFO_MODULE_HANDLE       moduleHnd,
625         mdToken                     metaTOK,
626         char16_t*                   buffer,
627         int                         bufferSize,
628         int                         startIndex)
629 {
630     CONTRACTL{
631         THROWS;
632         GC_TRIGGERS;
633         MODE_PREEMPTIVE;
634     } CONTRACTL_END;
635
636     Module* module = GetModule(moduleHnd);
637
638     _ASSERTE(bufferSize >= 0);
639     _ASSERTE(startIndex >= 0);
640
641     int result = -1;
642
643     JIT_TO_EE_TRANSITION();
644
645     if (IsDynamicScope(moduleHnd))
646     {
647         GCX_COOP();
648         STRINGREF strRef = GetDynamicResolver(moduleHnd)->GetStringLiteral(metaTOK);
649         if (strRef != NULL)
650         {
651             StringObject* strObj = STRINGREFToObject(strRef);
652             int length = (int)strObj->GetStringLength();
653             result = (length >= startIndex) ? (length - startIndex) : 0;
654             if (buffer != NULL && result != 0)
655             {
656                 memcpyNoGCRefs(buffer, strObj->GetBuffer() + startIndex, min(bufferSize, result) * sizeof(char16_t));
657             }
658         }
659     }
660     else
661     {
662         ULONG dwCharCount;
663         LPCWSTR pString;
664         if (!FAILED((module)->GetMDImport()->GetUserString(metaTOK, &dwCharCount, NULL, &pString)))
665         {
666             _ASSERTE(dwCharCount >= 0 && dwCharCount <= INT_MAX);
667             int length = (int)dwCharCount;
668             result = (length >= startIndex) ? (length - startIndex) : 0;
669             if (buffer != NULL && result != 0)
670             {
671                 memcpyNoGCRefs(buffer, pString + startIndex, min(bufferSize, result) * sizeof(char16_t));
672             }
673         }
674     }
675
676     EE_TO_JIT_TRANSITION();
677
678     return result;
679 }
680
681 size_t CEEInfo::printObjectDescription (
682         CORINFO_OBJECT_HANDLE  handle,
683         char*                  buffer,
684         size_t                 bufferSize,
685         size_t*                pRequiredBufferSize)
686 {
687     CONTRACTL{
688         THROWS;
689         GC_TRIGGERS;
690         MODE_PREEMPTIVE;
691     } CONTRACTL_END;
692
693     size_t bytesWritten = 0;
694
695     _ASSERT(handle != nullptr);
696
697     JIT_TO_EE_TRANSITION();
698
699     GCX_COOP();
700     OBJECTREF obj = getObjectFromJitHandle(handle);
701     StackSString stackStr;
702
703     // Currently only supported for String and RuntimeType
704     if (obj->GetMethodTable()->IsString())
705     {
706         ((STRINGREF)obj)->GetSString(stackStr);
707     }
708     else if (obj->GetMethodTable() == g_pRuntimeTypeClass)
709     {
710         ((REFLECTCLASSBASEREF)obj)->GetType().GetName(stackStr);
711     }
712     else
713     {
714         obj->GetMethodTable()->_GetFullyQualifiedNameForClass(stackStr);
715     }
716
717     const UTF8* utf8data = stackStr.GetUTF8();
718     if (bufferSize > 0)
719     {
720         bytesWritten = min(bufferSize - 1, stackStr.GetCount());
721         memcpy((BYTE*)buffer, (BYTE*)utf8data, bytesWritten);
722
723         // Always null-terminate
724         buffer[bytesWritten] = 0;
725     }
726
727     if (pRequiredBufferSize != nullptr)
728     {
729         *pRequiredBufferSize = stackStr.GetCount() + 1;
730     }
731
732     EE_TO_JIT_TRANSITION();
733
734     return bytesWritten;
735 }
736
737 /* static */
738 size_t CEEInfo::findNameOfToken (Module* module,
739                                                  mdToken metaTOK,
740                                                  _Out_writes_ (FQNameCapacity) char * szFQName,
741                                                  size_t FQNameCapacity)
742 {
743     CONTRACTL {
744         NOTHROW;
745         GC_TRIGGERS;
746     } CONTRACTL_END;
747
748 #ifdef _DEBUG
749     PCCOR_SIGNATURE sig = NULL;
750     DWORD           cSig;
751     LPCUTF8         pszNamespace = NULL;
752     LPCUTF8         pszClassName = NULL;
753
754     mdToken tokType = TypeFromToken(metaTOK);
755     switch(tokType)
756     {
757         case mdtTypeRef:
758             {
759                 if (FAILED(module->GetMDImport()->GetNameOfTypeRef(metaTOK, &pszNamespace, &pszClassName)))
760                 {
761                     pszNamespace = pszClassName = "Invalid TypeRef record";
762                 }
763                 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
764                 break;
765             }
766         case mdtTypeDef:
767             {
768                 if (FAILED(module->GetMDImport()->GetNameOfTypeDef(metaTOK, &pszClassName, &pszNamespace)))
769                 {
770                     pszClassName = pszNamespace = "Invalid TypeDef record";
771                 }
772                 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
773                 break;
774             }
775         case mdtFieldDef:
776             {
777                 LPCSTR szFieldName;
778                 if (FAILED(module->GetMDImport()->GetNameOfFieldDef(metaTOK, &szFieldName)))
779                 {
780                     szFieldName = "Invalid FieldDef record";
781                 }
782                 strncpy_s(szFQName,  FQNameCapacity,  (char*)szFieldName, FQNameCapacity - 1);
783                 break;
784             }
785         case mdtMethodDef:
786             {
787                 LPCSTR szMethodName;
788                 if (FAILED(module->GetMDImport()->GetNameOfMethodDef(metaTOK, &szMethodName)))
789                 {
790                     szMethodName = "Invalid MethodDef record";
791                 }
792                 strncpy_s(szFQName, FQNameCapacity, (char*)szMethodName, FQNameCapacity - 1);
793                 break;
794             }
795         case mdtMemberRef:
796             {
797                 LPCSTR szName;
798                 if (FAILED(module->GetMDImport()->GetNameAndSigOfMemberRef((mdMemberRef)metaTOK, &sig, &cSig, &szName)))
799                 {
800                     szName = "Invalid MemberRef record";
801                 }
802                 strncpy_s(szFQName, FQNameCapacity, (char *)szName, FQNameCapacity - 1);
803                 break;
804             }
805         default:
806             sprintf_s(szFQName, FQNameCapacity, "!TK_%x", metaTOK);
807             break;
808     }
809
810 #else // !_DEBUG
811     strncpy_s (szFQName, FQNameCapacity, "<UNKNOWN>", FQNameCapacity - 1);
812 #endif // _DEBUG
813
814
815     return strlen (szFQName);
816 }
817
818 CorInfoHelpFunc CEEInfo::getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle)
819 {
820     CONTRACTL {
821         NOTHROW;
822         GC_NOTRIGGER;
823         MODE_PREEMPTIVE;
824     } CONTRACTL_END;
825
826     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
827
828     JIT_TO_EE_TRANSITION_LEAF();
829
830     result = IsDynamicScope(handle) ? CORINFO_HELP_UNDEF : CORINFO_HELP_STRCNS;
831
832     EE_TO_JIT_TRANSITION_LEAF();
833
834     return result;
835 }
836
837
838 CHECK CheckContext(CORINFO_MODULE_HANDLE scopeHnd, CORINFO_CONTEXT_HANDLE context)
839 {
840     if (context != METHOD_BEING_COMPILED_CONTEXT())
841     {
842         CHECK_MSG(scopeHnd != NULL, "Illegal null scope");
843         CHECK_MSG(((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK) != NULL, "Illegal null context");
844         if (((size_t)context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
845         {
846             TypeHandle handle((CORINFO_CLASS_HANDLE)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK));
847             CHECK_MSG(handle.GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
848         }
849         else
850         {
851             MethodDesc* handle = (MethodDesc*)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK);
852             CHECK_MSG(handle->GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
853         }
854     }
855
856     CHECK_OK;
857 }
858
859
860 static DECLSPEC_NORETURN void ThrowBadTokenException(CORINFO_RESOLVED_TOKEN * pResolvedToken)
861 {
862     switch (pResolvedToken->tokenType & CORINFO_TOKENKIND_Mask)
863     {
864     case CORINFO_TOKENKIND_Class:
865         COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_CLASS_TOKEN);
866     case CORINFO_TOKENKIND_Method:
867         COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN);
868     case CORINFO_TOKENKIND_Field:
869         COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN);
870     default:
871         COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
872     }
873 }
874
875 /*********************************************************************/
876 void CEEInfo::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken)
877 {
878     CONTRACTL {
879         THROWS;
880         GC_TRIGGERS;
881         MODE_PREEMPTIVE;
882     } CONTRACTL_END;
883
884     JIT_TO_EE_TRANSITION();
885
886     _ASSERTE(CheckContext(pResolvedToken->tokenScope, pResolvedToken->tokenContext));
887
888     pResolvedToken->pTypeSpec = NULL;
889     pResolvedToken->cbTypeSpec = NULL;
890     pResolvedToken->pMethodSpec = NULL;
891     pResolvedToken->cbMethodSpec = NULL;
892
893     TypeHandle th;
894     MethodDesc * pMD = NULL;
895     FieldDesc * pFD = NULL;
896
897     CorInfoTokenKind tokenType = pResolvedToken->tokenType;
898
899     if (IsDynamicScope(pResolvedToken->tokenScope))
900     {
901         GetDynamicResolver(pResolvedToken->tokenScope)->ResolveToken(pResolvedToken->token, &th, &pMD, &pFD);
902
903         //
904         // Check that we got the expected handles and fill in missing data if necessary
905         //
906
907         CorTokenType tkType = (CorTokenType)TypeFromToken(pResolvedToken->token);
908
909         if (pMD != NULL)
910         {
911             if ((tkType != mdtMethodDef) && (tkType != mdtMemberRef))
912                 ThrowBadTokenException(pResolvedToken);
913             if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
914                 ThrowBadTokenException(pResolvedToken);
915             if (th.IsNull())
916                 th = pMD->GetMethodTable();
917
918             // "PermitUninstDefOrRef" check
919             if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && pMD->ContainsGenericVariables())
920             {
921                 COMPlusThrow(kInvalidProgramException);
922             }
923
924             // if this is a BoxedEntryPointStub get the UnboxedEntryPoint one
925             if (pMD->IsUnboxingStub())
926             {
927                 pMD = pMD->GetMethodTable()->GetUnboxedEntryPointMD(pMD);
928             }
929
930             // Activate target if required
931             if (tokenType != CORINFO_TOKENKIND_Ldtoken)
932             {
933                 EnsureActive(th, pMD);
934             }
935         }
936         else if (pFD != NULL)
937         {
938             if ((tkType != mdtFieldDef) && (tkType != mdtMemberRef))
939                 ThrowBadTokenException(pResolvedToken);
940             if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
941                 ThrowBadTokenException(pResolvedToken);
942             if (th.IsNull())
943                 th = pFD->GetApproxEnclosingMethodTable();
944
945             if (pFD->IsStatic() && (tokenType != CORINFO_TOKENKIND_Ldtoken))
946             {
947                 EnsureActive(th);
948             }
949         }
950         else
951         {
952             if ((tkType != mdtTypeDef) && (tkType != mdtTypeRef))
953                 ThrowBadTokenException(pResolvedToken);
954             if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
955                 ThrowBadTokenException(pResolvedToken);
956             if (th.IsNull())
957                 ThrowBadTokenException(pResolvedToken);
958
959             if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained)
960             {
961                 EnsureActive(th);
962             }
963         }
964
965         _ASSERTE((pMD == NULL) || (pFD == NULL));
966         _ASSERTE(!th.IsNull());
967
968         // "PermitUninstDefOrRef" check
969         if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && th.ContainsGenericVariables())
970         {
971             COMPlusThrow(kInvalidProgramException);
972         }
973     }
974     else
975     {
976         mdToken metaTOK = pResolvedToken->token;
977         Module * pModule = (Module *)pResolvedToken->tokenScope;
978
979         switch (TypeFromToken(metaTOK))
980         {
981         case mdtModuleRef:
982             if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
983                 ThrowBadTokenException(pResolvedToken);
984
985             {
986                 DomainAssembly *pTargetModule = pModule->LoadModule(metaTOK);
987                 if (pTargetModule == NULL)
988                     COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
989                 th = TypeHandle(pTargetModule->GetModule()->GetGlobalMethodTable());
990                 if (th.IsNull())
991                     COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
992             }
993             break;
994
995         case mdtTypeDef:
996         case mdtTypeRef:
997             if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
998                 ThrowBadTokenException(pResolvedToken);
999
1000             th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, metaTOK,
1001                                          ClassLoader::ThrowIfNotFound,
1002                                          (tokenType == CORINFO_TOKENKIND_Ldtoken) ?
1003                                             ClassLoader::PermitUninstDefOrRef : ClassLoader::FailIfUninstDefOrRef);
1004             break;
1005
1006         case mdtTypeSpec:
1007             {
1008                 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1009                     ThrowBadTokenException(pResolvedToken);
1010
1011                 IfFailThrow(pModule->GetMDImport()->GetTypeSpecFromToken(metaTOK, &pResolvedToken->pTypeSpec, (ULONG*)&pResolvedToken->cbTypeSpec));
1012
1013                 SigTypeContext typeContext;
1014                 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1015
1016                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1017                 th = sigptr.GetTypeHandleThrowing(pModule, &typeContext);
1018             }
1019             break;
1020
1021         case mdtMethodDef:
1022             if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1023                 ThrowBadTokenException(pResolvedToken);
1024
1025             pMD = MemberLoader::GetMethodDescFromMethodDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1026
1027             th = pMD->GetMethodTable();
1028             break;
1029
1030         case mdtFieldDef:
1031             if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1032                 ThrowBadTokenException(pResolvedToken);
1033
1034             pFD = MemberLoader::GetFieldDescFromFieldDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1035
1036             th = pFD->GetEnclosingMethodTable();
1037             break;
1038
1039         case mdtMemberRef:
1040             {
1041                 SigTypeContext typeContext;
1042                 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1043
1044                 MemberLoader::GetDescFromMemberRef(pModule, metaTOK, &pMD, &pFD, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken),
1045                     &th, TRUE, &pResolvedToken->pTypeSpec, (ULONG*)&pResolvedToken->cbTypeSpec);
1046
1047                 _ASSERTE((pMD != NULL) ^ (pFD != NULL));
1048                 _ASSERTE(!th.IsNull());
1049
1050                 if (pMD != NULL)
1051                 {
1052                     if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1053                         ThrowBadTokenException(pResolvedToken);
1054                 }
1055                 else
1056                 {
1057                     if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1058                         ThrowBadTokenException(pResolvedToken);
1059                 }
1060             }
1061             break;
1062
1063         case mdtMethodSpec:
1064             {
1065                 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1066                     ThrowBadTokenException(pResolvedToken);
1067
1068                 SigTypeContext typeContext;
1069                 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1070
1071                 // We need the method desc to carry exact instantiation, thus allowInstParam == FALSE.
1072                 pMD = MemberLoader::GetMethodDescFromMethodSpec(pModule, metaTOK, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken), FALSE /* allowInstParam */,
1073                     &th, TRUE, &pResolvedToken->pTypeSpec, (ULONG*)&pResolvedToken->cbTypeSpec, &pResolvedToken->pMethodSpec, (ULONG*)&pResolvedToken->cbMethodSpec);
1074             }
1075             break;
1076
1077         default:
1078             ThrowBadTokenException(pResolvedToken);
1079         }
1080
1081         //
1082         // Module activation tracking
1083         //
1084         if (!pModule->IsSystem())
1085         {
1086             if (pMD != NULL)
1087             {
1088                 EnsureActive(th, pMD);
1089             }
1090             else
1091             if (pFD != NULL)
1092             {
1093                 if (pFD->IsStatic())
1094                     EnsureActive(th);
1095             }
1096             else
1097             {
1098                 // It should not be required to trigger the modules cctors for ldtoken, it is done for backward compatibility only.
1099                 if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained || tokenType == CORINFO_TOKENKIND_Ldtoken)
1100                     EnsureActive(th);
1101             }
1102         }
1103     }
1104
1105     //
1106     // tokenType specific verification and transformations
1107     //
1108     CorElementType et = th.GetInternalCorElementType();
1109     switch (tokenType)
1110     {
1111         case CORINFO_TOKENKIND_Ldtoken:
1112             // Allow everything.
1113             break;
1114
1115         case CORINFO_TOKENKIND_Newarr:
1116             // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1117             if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1118                 COMPlusThrow(kInvalidProgramException);
1119
1120             th = ClassLoader::LoadArrayTypeThrowing(th);
1121             break;
1122
1123         default:
1124             // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1125             if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1126                 COMPlusThrow(kInvalidProgramException);
1127             break;
1128     }
1129
1130     // The JIT interface should always return fully loaded types
1131     _ASSERTE(th.IsFullyLoaded());
1132
1133     pResolvedToken->hClass = CORINFO_CLASS_HANDLE(th.AsPtr());
1134     pResolvedToken->hMethod = CORINFO_METHOD_HANDLE(pMD);
1135     pResolvedToken->hField = CORINFO_FIELD_HANDLE(pFD);
1136
1137     EE_TO_JIT_TRANSITION();
1138 }
1139
1140
1141 /*********************************************************************/
1142 // We have a few frequently used constants in CoreLib that are defined as
1143 // readonly static fields for historic reasons. Check for them here and
1144 // allow them to be treated as actual constants by the JIT.
1145 static CORINFO_FIELD_ACCESSOR getFieldIntrinsic(FieldDesc * field)
1146 {
1147     STANDARD_VM_CONTRACT;
1148
1149     if (CoreLibBinder::GetField(FIELD__STRING__EMPTY) == field)
1150     {
1151         return CORINFO_FIELD_INTRINSIC_EMPTY_STRING;
1152     }
1153     else
1154     if ((CoreLibBinder::GetField(FIELD__INTPTR__ZERO) == field) ||
1155         (CoreLibBinder::GetField(FIELD__UINTPTR__ZERO) == field))
1156     {
1157         return CORINFO_FIELD_INTRINSIC_ZERO;
1158     }
1159     else
1160     if (CoreLibBinder::GetField(FIELD__BITCONVERTER__ISLITTLEENDIAN) == field)
1161     {
1162         return CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN;
1163     }
1164
1165     return (CORINFO_FIELD_ACCESSOR)-1;
1166 }
1167
1168 static CorInfoHelpFunc getGenericStaticsHelper(FieldDesc * pField)
1169 {
1170     STANDARD_VM_CONTRACT;
1171
1172     int helper = CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE;
1173
1174     if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1175         pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1176     {
1177         helper = CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1178     }
1179
1180     if (pField->IsThreadStatic())
1181     {
1182         const int delta = CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1183
1184         static_assert_no_msg(CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE
1185             == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE + delta);
1186
1187         helper += (CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE);
1188     }
1189
1190     return (CorInfoHelpFunc)helper;
1191 }
1192
1193 CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable * pFieldMT)
1194 {
1195     STANDARD_VM_CONTRACT;
1196
1197     int helper = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
1198
1199     if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1200         pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1201     {
1202         helper = CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1203     }
1204
1205     if (pFieldMT->IsDynamicStatics())
1206     {
1207         const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1208
1209         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS
1210             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1211
1212         helper += delta;
1213     }
1214     else
1215     if ((!pFieldMT->HasClassConstructor() && !pFieldMT->HasBoxedRegularStatics()) || pFieldMT->IsClassInited())
1216     {
1217         const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1218
1219         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR
1220             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1221
1222         helper += delta;
1223     }
1224
1225     if (pField->IsThreadStatic())
1226     {
1227         const int delta = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1228
1229         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE
1230             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1231         static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR
1232             == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR + delta);
1233         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR
1234             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR + delta);
1235         static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS
1236             == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS + delta);
1237         static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS
1238             == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS + delta);
1239
1240         helper += delta;
1241     }
1242
1243     return (CorInfoHelpFunc)helper;
1244 }
1245
1246 static CorInfoHelpFunc getInstanceFieldHelper(FieldDesc * pField, CORINFO_ACCESS_FLAGS flags)
1247 {
1248     STANDARD_VM_CONTRACT;
1249
1250     int helper;
1251
1252     CorElementType type = pField->GetFieldType();
1253
1254     if (CorTypeInfo::IsObjRef(type))
1255         helper = CORINFO_HELP_GETFIELDOBJ;
1256     else
1257     switch (type)
1258     {
1259     case ELEMENT_TYPE_VALUETYPE:
1260         helper = CORINFO_HELP_GETFIELDSTRUCT;
1261         break;
1262     case ELEMENT_TYPE_I1:
1263     case ELEMENT_TYPE_BOOLEAN:
1264     case ELEMENT_TYPE_U1:
1265         helper = CORINFO_HELP_GETFIELD8;
1266         break;
1267     case ELEMENT_TYPE_I2:
1268     case ELEMENT_TYPE_CHAR:
1269     case ELEMENT_TYPE_U2:
1270         helper = CORINFO_HELP_GETFIELD16;
1271         break;
1272     case ELEMENT_TYPE_I4:
1273     case ELEMENT_TYPE_U4:
1274     IN_TARGET_32BIT(default:)
1275         helper = CORINFO_HELP_GETFIELD32;
1276         break;
1277     case ELEMENT_TYPE_I8:
1278     case ELEMENT_TYPE_U8:
1279     IN_TARGET_64BIT(default:)
1280         helper = CORINFO_HELP_GETFIELD64;
1281         break;
1282     case ELEMENT_TYPE_R4:
1283         helper = CORINFO_HELP_GETFIELDFLOAT;
1284         break;
1285     case ELEMENT_TYPE_R8:
1286         helper = CORINFO_HELP_GETFIELDDOUBLE;
1287         break;
1288     }
1289
1290     if (flags & CORINFO_ACCESS_SET)
1291     {
1292         const int delta = CORINFO_HELP_SETFIELDOBJ - CORINFO_HELP_GETFIELDOBJ;
1293
1294         static_assert_no_msg(CORINFO_HELP_SETFIELD8 == CORINFO_HELP_GETFIELD8 + delta);
1295         static_assert_no_msg(CORINFO_HELP_SETFIELD16 == CORINFO_HELP_GETFIELD16 + delta);
1296         static_assert_no_msg(CORINFO_HELP_SETFIELD32 == CORINFO_HELP_GETFIELD32 + delta);
1297         static_assert_no_msg(CORINFO_HELP_SETFIELD64 == CORINFO_HELP_GETFIELD64 + delta);
1298         static_assert_no_msg(CORINFO_HELP_SETFIELDSTRUCT == CORINFO_HELP_GETFIELDSTRUCT + delta);
1299         static_assert_no_msg(CORINFO_HELP_SETFIELDFLOAT == CORINFO_HELP_GETFIELDFLOAT + delta);
1300         static_assert_no_msg(CORINFO_HELP_SETFIELDDOUBLE == CORINFO_HELP_GETFIELDDOUBLE + delta);
1301
1302         helper += delta;
1303     }
1304
1305     return (CorInfoHelpFunc)helper;
1306 }
1307
1308
1309
1310 /*********************************************************************/
1311 uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE  field, bool isGCType)
1312 {
1313     CONTRACTL {
1314         THROWS;
1315         GC_TRIGGERS;
1316         MODE_PREEMPTIVE;
1317     } CONTRACTL_END;
1318
1319     UINT32 typeIndex = 0;
1320
1321     JIT_TO_EE_TRANSITION();
1322
1323     FieldDesc* fieldDesc = (FieldDesc*)field;
1324     _ASSERTE(fieldDesc->IsThreadStatic());
1325
1326     if (isGCType)
1327     {
1328         typeIndex = AppDomain::GetCurrentDomain()->GetGCThreadStaticTypeIndex(fieldDesc->GetEnclosingMethodTable());
1329     }
1330     else
1331     {
1332         typeIndex = AppDomain::GetCurrentDomain()->GetNonGCThreadStaticTypeIndex(fieldDesc->GetEnclosingMethodTable());
1333     }
1334
1335     assert(typeIndex != TypeIDProvider::INVALID_TYPE_ID);
1336
1337     EE_TO_JIT_TRANSITION();
1338     return typeIndex;
1339 }
1340
1341 #if defined(TARGET_WINDOWS)
1342 /*********************************************************************/
1343 static uint32_t ThreadLocalOffset(void* p)
1344 {
1345     PTEB Teb = NtCurrentTeb();
1346     uint8_t** pTls = (uint8_t**)Teb->ThreadLocalStoragePointer;
1347     uint8_t* pOurTls = pTls[_tls_index];
1348     return (uint32_t)((uint8_t*)p - pOurTls);
1349 }
1350 #elif defined(TARGET_OSX)
1351 extern "C" void* GetThreadVarsAddress();
1352
1353 static void* GetThreadVarsSectionAddressFromDesc(uint8_t* p)
1354 {
1355     _ASSERT(p[0] == 0x48 && p[1] == 0x8d && p[2] == 0x3d);
1356
1357     // At this point, `p` contains the instruction pointer and is pointing to the above opcodes.
1358     // These opcodes are patched by the dynamic linker.
1359     // Move beyond the opcodes that we have already checked above.
1360     p += 3;
1361
1362     // The descriptor address is located at *p at this point.
1363     // (p + 4) below skips the descriptor address bytes embedded in the instruction and
1364     // add it to the `instruction pointer` to find out the address.
1365     return *(uint32_t*)p + (p + 4);
1366 }
1367
1368 static void* GetThreadVarsSectionAddress()
1369 {
1370 #ifdef TARGET_AMD64
1371     // On x64, the address is related to rip, so, disassemble the function,
1372     // read the offset, and then relative to the IP, find the final address of
1373     // __thread_vars section.
1374     uint8_t* p = reinterpret_cast<uint8_t*>(&GetThreadVarsAddress);
1375     return GetThreadVarsSectionAddressFromDesc(p);
1376 #else
1377     return GetThreadVarsAddress();
1378 #endif // TARGET_AMD64
1379 }
1380
1381 #else
1382
1383 // Linux
1384
1385 #ifdef TARGET_AMD64
1386
1387 extern "C" void* GetTlsIndexObjectDescOffset();
1388
1389 static void* GetThreadStaticDescriptor(uint8_t* p)
1390 {
1391     if (!(p[0] == 0x66 && p[1] == 0x48 && p[2] == 0x8d && p[3] == 0x3d))
1392     {
1393         // The optimization is disabled if coreclr is not compiled in .so format.
1394         _ASSERTE(false && "Unexpected code sequence");
1395         return nullptr;
1396     }
1397
1398     // At this point, `p` contains the instruction pointer and is pointing to the above opcodes.
1399     // These opcodes are patched by the dynamic linker.
1400     // Move beyond the opcodes that we have already checked above.
1401     p += 4;
1402
1403     // The descriptor address is located at *p at this point. Read that and add
1404     // it to the instruction pointer to locate the address of `ti` that will be used
1405     // to pass to __tls_get_addr during execution.
1406     // (p + 4) below skips the descriptor address bytes embedded in the instruction and
1407     // add it to the `instruction pointer` to find out the address.
1408     return *(uint32_t*)p + (p + 4);
1409 }
1410
1411 static void* GetTlsIndexObjectAddress()
1412 {
1413     uint8_t* p = reinterpret_cast<uint8_t*>(&GetTlsIndexObjectDescOffset);
1414     return GetThreadStaticDescriptor(p);
1415 }
1416
1417 #elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
1418
1419 extern "C" size_t GetThreadStaticsVariableOffset();
1420
1421 #endif // TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64
1422 #endif // TARGET_WINDOWS
1423
1424
1425 void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType)
1426 {
1427     CONTRACTL {
1428         NOTHROW;
1429         GC_NOTRIGGER;
1430         MODE_PREEMPTIVE;
1431     } CONTRACTL_END;
1432
1433     JIT_TO_EE_TRANSITION_LEAF();
1434
1435     size_t threadStaticBaseOffset = 0;
1436
1437 #if defined(TARGET_WINDOWS)
1438     pInfo->tlsIndex.addr = (void*)static_cast<uintptr_t>(_tls_index);
1439     pInfo->tlsIndex.accessType = IAT_VALUE;
1440
1441     pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer);
1442     threadStaticBaseOffset = ThreadLocalOffset(&t_ThreadStatics);
1443
1444 #elif defined(TARGET_OSX)
1445
1446     pInfo->threadVarsSection = GetThreadVarsSectionAddress();
1447
1448 #elif defined(TARGET_AMD64)
1449
1450     // For Linux/x64, get the address of tls_get_addr system method and the base address
1451     // of struct that we will pass to it.
1452     pInfo->tlsGetAddrFtnPtr = reinterpret_cast<void*>(&__tls_get_addr);
1453     pInfo->tlsIndexObject = GetTlsIndexObjectAddress();
1454
1455 #elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
1456
1457     // For Linux arm64/loongarch64/riscv64, just get the offset of thread static variable, and during execution,
1458     // this offset, arm64 taken from trpid_elp0 system register gives back the thread variable address.
1459     // this offset, loongarch64 taken from $tp register gives back the thread variable address.
1460     threadStaticBaseOffset = GetThreadStaticsVariableOffset();
1461
1462 #else
1463     _ASSERTE_MSG(false, "Unsupported scenario of optimizing TLS access on Linux Arm32/x86");
1464 #endif // TARGET_WINDOWS
1465
1466     if (isGCType)
1467     {
1468         pInfo->offsetOfMaxThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, GCMaxThreadStaticBlocks));
1469         pInfo->offsetOfThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, GCThreadStaticBlocks));
1470     }
1471     else
1472     {
1473         pInfo->offsetOfMaxThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, NonGCMaxThreadStaticBlocks));
1474         pInfo->offsetOfThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, NonGCThreadStaticBlocks));
1475     }
1476     pInfo->offsetOfGCDataPointer = static_cast<uint32_t>(PtrArray::GetDataOffset());
1477
1478     EE_TO_JIT_TRANSITION_LEAF();
1479 }
1480
1481 /*********************************************************************/
1482 void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken,
1483                             CORINFO_METHOD_HANDLE  callerHandle,
1484                             CORINFO_ACCESS_FLAGS   flags,
1485                             CORINFO_FIELD_INFO    *pResult
1486                            )
1487 {
1488     CONTRACTL {
1489         THROWS;
1490         GC_TRIGGERS;
1491         MODE_PREEMPTIVE;
1492     } CONTRACTL_END;
1493
1494     JIT_TO_EE_TRANSITION();
1495
1496     _ASSERTE((flags & (CORINFO_ACCESS_GET | CORINFO_ACCESS_SET | CORINFO_ACCESS_ADDRESS | CORINFO_ACCESS_INIT_ARRAY)) != 0);
1497
1498     INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
1499
1500     FieldDesc * pField = (FieldDesc*)pResolvedToken->hField;
1501     MethodTable * pFieldMT = pField->GetApproxEnclosingMethodTable();
1502
1503     // Helper to use if the field access requires it
1504     CORINFO_FIELD_ACCESSOR fieldAccessor = (CORINFO_FIELD_ACCESSOR)-1;
1505     DWORD fieldFlags = 0;
1506
1507     pResult->offset = pField->GetOffset();
1508     pResult->fieldLookup.addr = nullptr;
1509
1510     if (pField->IsStatic())
1511     {
1512         fieldFlags |= CORINFO_FLG_FIELD_STATIC;
1513
1514         if (pField->IsRVA())
1515         {
1516             fieldFlags |= CORINFO_FLG_FIELD_UNMANAGED;
1517
1518             Module* module = pFieldMT->GetModule();
1519             if (module->IsRvaFieldTls(pResult->offset))
1520             {
1521                 fieldAccessor = CORINFO_FIELD_STATIC_TLS;
1522
1523                 // Provide helper to use if the JIT is not able to emit the TLS access
1524                 // as intrinsic
1525                 pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR_TLS;
1526
1527                 pResult->offset = module->GetFieldTlsOffset(pResult->offset);
1528             }
1529             else
1530             {
1531                 fieldAccessor = CORINFO_FIELD_STATIC_RVA_ADDRESS;
1532                 pResult->fieldLookup.addr = pField->GetStaticAddressHandle(NULL);
1533                 pResult->fieldLookup.accessType = IAT_VALUE;
1534             }
1535
1536             // We are not going through a helper. The constructor has to be triggered explicitly.
1537             if (!pFieldMT->IsClassInited())
1538                 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1539         }
1540         else
1541         {
1542             // Regular or thread static
1543             CORINFO_FIELD_ACCESSOR intrinsicAccessor;
1544
1545             if (pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1546                 fieldFlags |= CORINFO_FLG_FIELD_STATIC_IN_HEAP;
1547
1548             if (pFieldMT->IsSharedByGenericInstantiations())
1549             {
1550                 if (pField->IsEnCNew())
1551                 {
1552                     fieldAccessor = CORINFO_FIELD_STATIC_ADDR_HELPER;
1553
1554                     pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR;
1555                 }
1556                 else
1557                 {
1558                     fieldAccessor = CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER;
1559
1560                     pResult->helper = getGenericStaticsHelper(pField);
1561                 }
1562             }
1563             else
1564             if (pFieldMT->GetModule()->IsSystem() && (flags & CORINFO_ACCESS_GET) &&
1565                 (intrinsicAccessor = getFieldIntrinsic(pField)) != (CORINFO_FIELD_ACCESSOR)-1)
1566             {
1567                 // Intrinsics
1568                 fieldAccessor = intrinsicAccessor;
1569             }
1570             else
1571             if (pFieldMT->Collectible())
1572             {
1573                 // Static fields are not pinned in collectible types. We will always access
1574                 // them using a helper since the address cannot be embedded into the code.
1575                 fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
1576
1577                 pResult->helper = getSharedStaticsHelper(pField, pFieldMT);
1578             }
1579             else if (pField->IsThreadStatic())
1580             {
1581                  // We always treat accessing thread statics as if we are in domain neutral code.
1582                 fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
1583
1584                 pResult->helper = getSharedStaticsHelper(pField, pFieldMT);
1585 #if defined(TARGET_ARM)
1586                 // Optimization is disabled for linux/windows arm
1587 #elif !defined(TARGET_WINDOWS) && defined(TARGET_X86)
1588                 // Optimization is disabled for linux/x86
1589 #elif defined(TARGET_LINUX_MUSL) && defined(TARGET_ARM64)
1590                 // Optimization is disabled for linux musl arm64
1591 #else
1592                 bool optimizeThreadStaticAccess = true;
1593 #if !defined(TARGET_OSX) && defined(TARGET_UNIX) && defined(TARGET_AMD64)
1594                 // For linux/x64, check if compiled coreclr as .so file and not single file.
1595                 // For single file, the `tls_index` might not be accurate.
1596                 // Do not perform this optimization in such case.
1597                 optimizeThreadStaticAccess = GetTlsIndexObjectAddress() != nullptr;
1598 #endif // !TARGET_OSX && TARGET_UNIX && TARGET_AMD64
1599
1600                 if (optimizeThreadStaticAccess)
1601                 {
1602                     // For windows x64/x86/arm64, linux x64/arm64/loongarch64/riscv64:
1603                     // We convert the TLS access to the optimized helper where we will store
1604                     // the static blocks in TLS directly and access them via inline code.
1605                     if ((pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR) ||
1606                         (pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE))
1607                     {
1608                         fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED;
1609                         pResult->helper = CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED;
1610                     }
1611                     else if ((pResult->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR) ||
1612                                 (pResult->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE))
1613                     {
1614                         fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED;
1615                         pResult->helper = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED;
1616                     }
1617                 }
1618 #endif // TARGET_ARM
1619             }
1620             else
1621             {
1622                 fieldAccessor = CORINFO_FIELD_STATIC_ADDRESS;
1623
1624                 // Allocate space for the local class if necessary, but don't trigger
1625                 // class construction.
1626                 DomainLocalModule* pLocalModule = pFieldMT->GetDomainLocalModule();
1627                 pLocalModule->PopulateClass(pFieldMT);
1628
1629                 // We are not going through a helper. The constructor has to be triggered explicitly.
1630                 if (!pFieldMT->IsClassInited())
1631                     fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1632
1633                 GCX_COOP();
1634
1635                 _ASSERT(!pFieldMT->Collectible());
1636                 // Field address is expected to be pinned so we don't need to protect it from GC here
1637                 pResult->fieldLookup.addr = pField->GetStaticAddressHandle((void*)pField->GetBase());
1638                 pResult->fieldLookup.accessType = IAT_VALUE;
1639                 if (fieldFlags & CORINFO_FLG_FIELD_STATIC_IN_HEAP)
1640                 {
1641                     Object* frozenObj = VolatileLoad((Object**)pResult->fieldLookup.addr);
1642
1643                     if (frozenObj == nullptr)
1644                     {
1645                         // Boxed static is not yet set, allocate it
1646                         pFieldMT->AllocateRegularStaticBox(pField, (Object**)pResult->fieldLookup.addr);
1647                         frozenObj = VolatileLoad((Object**)pResult->fieldLookup.addr);
1648                     }
1649
1650                     _ASSERT(frozenObj != nullptr);
1651
1652                     // ContainsPointers here is unnecessary but it's cheaper than IsInFrozenSegment
1653                     // for structs containing gc handles
1654                     if (!frozenObj->GetMethodTable()->ContainsPointers() &&
1655                         GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(frozenObj))
1656                     {
1657                         pResult->fieldLookup.addr = frozenObj->GetData();
1658                         fieldFlags &= ~CORINFO_FLG_FIELD_STATIC_IN_HEAP;
1659                     }
1660                 }
1661             }
1662         }
1663     }
1664     else
1665     {
1666         if (pField->IsEnCNew())
1667         {
1668             fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1669
1670             pResult->helper = CORINFO_HELP_GETFIELDADDR;
1671         }
1672         else
1673         {
1674             fieldAccessor = CORINFO_FIELD_INSTANCE;
1675         }
1676
1677         // FieldDesc::GetOffset() does not include the size of Object
1678         if (!pFieldMT->IsValueType())
1679         {
1680             pResult->offset += OBJECT_SIZE;
1681         }
1682     }
1683
1684     // TODO: This is touching metadata. Can we avoid it?
1685     DWORD fieldAttribs = pField->GetAttributes();
1686
1687     if (IsFdFamily(fieldAttribs))
1688         fieldFlags |= CORINFO_FLG_FIELD_PROTECTED;
1689
1690     if (IsFdInitOnly(fieldAttribs))
1691         fieldFlags |= CORINFO_FLG_FIELD_FINAL;
1692
1693     pResult->fieldAccessor = fieldAccessor;
1694     pResult->fieldFlags = fieldFlags;
1695
1696     if (!(flags & CORINFO_ACCESS_INLINECHECK))
1697     {
1698         //get the field's type.  Grab the class for structs.
1699         pResult->fieldType = getFieldTypeInternal(pResolvedToken->hField, &pResult->structType, pResolvedToken->hClass);
1700
1701
1702         MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
1703
1704         //
1705         //Since we can't get the special verify-only instantiated FD like we can with MDs, go back to the parent
1706         //of the memberRef and load that one.  That should give us the open instantiation.
1707         //
1708         //If the field we found is owned by a generic type, you have to go back to the signature and reload.
1709         //Otherwise we filled in !0.
1710         TypeHandle fieldTypeForSecurity = TypeHandle(pResolvedToken->hClass);
1711         if (pResolvedToken->pTypeSpec != NULL)
1712         {
1713             SigTypeContext typeContext;
1714             SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
1715
1716             SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1717             fieldTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
1718
1719             // typeHnd can be a variable type
1720             if (fieldTypeForSecurity.GetMethodTable() == NULL)
1721             {
1722                 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
1723             }
1724         }
1725
1726         BOOL doAccessCheck = TRUE;
1727         AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
1728
1729         DynamicResolver * pAccessContext = NULL;
1730
1731         //More in code:CEEInfo::getCallInfo, but the short version is that the caller and callee Descs do
1732         //not completely describe the type.
1733         TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
1734         if (IsDynamicScope(pResolvedToken->tokenScope))
1735         {
1736             doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope), &callerTypeForSecurity,
1737                 &accessCheckType, &pAccessContext);
1738         }
1739
1740         //Now for some link time checks.
1741         //Um... where are the field link demands?
1742
1743         pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
1744
1745         if (doAccessCheck)
1746         {
1747             //Well, let's check some visibility at least.
1748             AccessCheckOptions accessCheckOptions(accessCheckType,
1749                 pAccessContext,
1750                 FALSE,
1751                 pField);
1752
1753             _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
1754             AccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
1755
1756             BOOL canAccess = ClassLoader::CanAccess(
1757                 &accessContext,
1758                 fieldTypeForSecurity.GetMethodTable(),
1759                 fieldTypeForSecurity.GetAssembly(),
1760                 fieldAttribs,
1761                 NULL,
1762                 (flags & CORINFO_ACCESS_INIT_ARRAY) ? NULL : pField, // For InitializeArray, we don't need tocheck the type of the field.
1763                 accessCheckOptions);
1764
1765             if (!canAccess)
1766             {
1767                 //Set up the throw helper
1768                 pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL;
1769
1770                 pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_EXCEPTION;
1771                 pResult->accessCalloutHelper.numArgs = 2;
1772
1773                 pResult->accessCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
1774                 pResult->accessCalloutHelper.args[1].Set(CORINFO_FIELD_HANDLE(pField));
1775             }
1776         }
1777     }
1778
1779     EE_TO_JIT_TRANSITION();
1780 }
1781
1782 //---------------------------------------------------------------------------------------
1783 //
1784 bool CEEInfo::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd)
1785 {
1786     CONTRACTL {
1787         THROWS;
1788         GC_TRIGGERS;
1789         MODE_PREEMPTIVE;
1790     } CONTRACTL_END;
1791
1792     bool res = false;
1793     JIT_TO_EE_TRANSITION_LEAF();
1794     FieldDesc* field = (FieldDesc*)fldHnd;
1795     res = (field->IsStatic() != 0);
1796     EE_TO_JIT_TRANSITION_LEAF();
1797     return res;
1798 }
1799
1800 int CEEInfo::getArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd)
1801 {
1802     CONTRACTL {
1803         THROWS;
1804         GC_TRIGGERS;
1805         MODE_PREEMPTIVE;
1806     } CONTRACTL_END;
1807
1808     int arrLen = -1;
1809     JIT_TO_EE_TRANSITION();
1810
1811     _ASSERT(objHnd != NULL);
1812
1813     GCX_COOP();
1814
1815     OBJECTREF obj = getObjectFromJitHandle(objHnd);
1816
1817     if (obj->GetMethodTable()->IsArray())
1818     {
1819         arrLen = ((ARRAYBASEREF)obj)->GetNumComponents();
1820     }
1821     else if (obj->GetMethodTable()->IsString())
1822     {
1823         arrLen = ((STRINGREF)obj)->GetStringLength();
1824     }
1825
1826     EE_TO_JIT_TRANSITION();
1827     return arrLen;
1828 }
1829
1830 //---------------------------------------------------------------------------------------
1831 //
1832 void
1833 CEEInfo::findCallSiteSig(
1834     CORINFO_MODULE_HANDLE  scopeHnd,
1835     unsigned               sigMethTok,
1836     CORINFO_CONTEXT_HANDLE context,
1837     CORINFO_SIG_INFO *     sigRet)
1838 {
1839     CONTRACTL {
1840         THROWS;
1841         GC_TRIGGERS;
1842         MODE_PREEMPTIVE;
1843     } CONTRACTL_END;
1844
1845     JIT_TO_EE_TRANSITION();
1846
1847     PCCOR_SIGNATURE       pSig = NULL;
1848     uint32_t              cbSig = 0;
1849
1850     if (IsDynamicScope(scopeHnd))
1851     {
1852         DynamicResolver * pResolver = GetDynamicResolver(scopeHnd);
1853         SigPointer sig;
1854
1855         if (TypeFromToken(sigMethTok) == mdtMemberRef)
1856         {
1857             sig = pResolver->ResolveSignatureForVarArg(sigMethTok);
1858         }
1859         else
1860         {
1861             _ASSERTE(TypeFromToken(sigMethTok) == mdtMethodDef);
1862
1863             TypeHandle classHandle;
1864             MethodDesc * pMD = NULL;
1865             FieldDesc * pFD = NULL;
1866
1867             // in this case a method is asked for its sig. Resolve the method token and get the sig
1868             pResolver->ResolveToken(sigMethTok, &classHandle, &pMD, &pFD);
1869             if (pMD == NULL)
1870                 COMPlusThrow(kInvalidProgramException);
1871
1872             PCCOR_SIGNATURE pSig = NULL;
1873             DWORD           cbSig;
1874             pMD->GetSig(&pSig, &cbSig);
1875             sig = SigPointer(pSig, cbSig);
1876
1877             context = MAKE_METHODCONTEXT(pMD);
1878             scopeHnd = GetScopeHandle(pMD->GetModule());
1879         }
1880
1881         sig.GetSignature(&pSig, &cbSig);
1882         sigMethTok = mdTokenNil;
1883     }
1884     else
1885     {
1886         Module * module = (Module *)scopeHnd;
1887         LPCUTF8  szName;
1888
1889         if (TypeFromToken(sigMethTok) == mdtMemberRef)
1890         {
1891             IfFailThrow(module->GetMDImport()->GetNameAndSigOfMemberRef(sigMethTok, &pSig, (ULONG*)&cbSig, &szName));
1892         }
1893         else if (TypeFromToken(sigMethTok) == mdtMethodDef)
1894         {
1895             IfFailThrow(module->GetMDImport()->GetSigOfMethodDef(sigMethTok, (ULONG*)&cbSig, &pSig));
1896         }
1897     }
1898
1899     SigTypeContext typeContext;
1900     GetTypeContext(context, &typeContext);
1901
1902     ConvToJitSig(
1903         pSig,
1904         cbSig,
1905         scopeHnd,
1906         sigMethTok,
1907         &typeContext,
1908         CONV_TO_JITSIG_FLAGS_NONE,
1909         sigRet);
1910     EE_TO_JIT_TRANSITION();
1911 } // CEEInfo::findCallSiteSig
1912
1913 //---------------------------------------------------------------------------------------
1914 //
1915 void
1916 CEEInfo::findSig(
1917     CORINFO_MODULE_HANDLE  scopeHnd,
1918     unsigned               sigTok,
1919     CORINFO_CONTEXT_HANDLE context,
1920     CORINFO_SIG_INFO *     sigRet)
1921 {
1922     CONTRACTL {
1923         THROWS;
1924         GC_TRIGGERS;
1925         MODE_PREEMPTIVE;
1926     } CONTRACTL_END;
1927
1928     JIT_TO_EE_TRANSITION();
1929
1930     PCCOR_SIGNATURE       pSig = NULL;
1931     uint32_t              cbSig = 0;
1932
1933     if (IsDynamicScope(scopeHnd))
1934     {
1935         SigPointer sig = GetDynamicResolver(scopeHnd)->ResolveSignature(sigTok);
1936         sig.GetSignature(&pSig, &cbSig);
1937         sigTok = mdTokenNil;
1938     }
1939     else
1940     {
1941         Module * module = (Module *)scopeHnd;
1942
1943         // We need to resolve this stand alone sig
1944         IfFailThrow(module->GetMDImport()->GetSigFromToken(
1945             (mdSignature)sigTok,
1946             (ULONG*)(&cbSig),
1947             &pSig));
1948     }
1949
1950     SigTypeContext typeContext;
1951     GetTypeContext(context, &typeContext);
1952
1953     ConvToJitSig(
1954         pSig,
1955         cbSig,
1956         scopeHnd,
1957         sigTok,
1958         &typeContext,
1959         CONV_TO_JITSIG_FLAGS_NONE,
1960         sigRet);
1961
1962     EE_TO_JIT_TRANSITION();
1963 } // CEEInfo::findSig
1964
1965 //---------------------------------------------------------------------------------------
1966 //
1967 unsigned
1968 CEEInfo::getClassSize(
1969     CORINFO_CLASS_HANDLE clsHnd)
1970 {
1971     CONTRACTL {
1972         THROWS;
1973         GC_TRIGGERS;
1974         MODE_PREEMPTIVE;
1975     } CONTRACTL_END;
1976
1977     unsigned result = 0;
1978
1979     JIT_TO_EE_TRANSITION_LEAF();
1980
1981     TypeHandle VMClsHnd(clsHnd);
1982     result = VMClsHnd.GetSize();
1983
1984     EE_TO_JIT_TRANSITION_LEAF();
1985
1986     return result;
1987 }
1988
1989 //---------------------------------------------------------------------------------------
1990 //
1991 // Get the size of a reference type as allocated on the heap. This includes the size of the fields
1992 // (and any padding between the fields) and the size of a method table pointer but doesn't include
1993 // object header size or any padding for minimum size.
1994 unsigned
1995 CEEInfo::getHeapClassSize(
1996     CORINFO_CLASS_HANDLE clsHnd)
1997 {
1998     CONTRACTL{
1999         NOTHROW;
2000         GC_NOTRIGGER;
2001         MODE_PREEMPTIVE;
2002     } CONTRACTL_END;
2003
2004     unsigned result = 0;
2005
2006     JIT_TO_EE_TRANSITION_LEAF();
2007
2008     TypeHandle VMClsHnd(clsHnd);
2009     MethodTable* pMT = VMClsHnd.GetMethodTable();
2010     _ASSERTE(pMT);
2011     _ASSERTE(!pMT->IsValueType());
2012     _ASSERTE(!pMT->HasComponentSize());
2013
2014     // Add OBJECT_SIZE to account for method table pointer.
2015     result = pMT->GetNumInstanceFieldBytes() + OBJECT_SIZE;
2016
2017     EE_TO_JIT_TRANSITION_LEAF();
2018     return result;
2019 }
2020
2021 //---------------------------------------------------------------------------------------
2022 //
2023 // Return TRUE if an object of this type can be allocated on the stack.
2024 bool CEEInfo::canAllocateOnStack(CORINFO_CLASS_HANDLE clsHnd)
2025 {
2026     CONTRACTL{
2027         NOTHROW;
2028         GC_NOTRIGGER;
2029         MODE_PREEMPTIVE;
2030     } CONTRACTL_END;
2031
2032     bool result = false;
2033
2034     JIT_TO_EE_TRANSITION_LEAF();
2035
2036     TypeHandle VMClsHnd(clsHnd);
2037     MethodTable* pMT = VMClsHnd.GetMethodTable();
2038     _ASSERTE(pMT);
2039     _ASSERTE(!pMT->IsValueType());
2040
2041     result = !pMT->HasFinalizer();
2042
2043     EE_TO_JIT_TRANSITION_LEAF();
2044     return result;
2045 }
2046
2047 unsigned CEEInfo::getClassAlignmentRequirement(CORINFO_CLASS_HANDLE type, bool fDoubleAlignHint)
2048 {
2049     CONTRACTL {
2050         NOTHROW;
2051         GC_NOTRIGGER;
2052         MODE_PREEMPTIVE;
2053     } CONTRACTL_END;
2054
2055     // Default alignment is sizeof(void*)
2056     unsigned result = TARGET_POINTER_SIZE;
2057
2058     JIT_TO_EE_TRANSITION_LEAF();
2059
2060     TypeHandle clsHnd(type);
2061
2062 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
2063     if (fDoubleAlignHint)
2064     {
2065         MethodTable* pMT = clsHnd.GetMethodTable();
2066         if (pMT != NULL)
2067         {
2068             // Return the size of the double align hint. Ignore the actual alignment info account
2069             // so that structs with 64-bit integer fields do not trigger double aligned frames on x86.
2070             if (pMT->GetClass()->IsAlign8Candidate())
2071                 result = 8;
2072         }
2073     }
2074     else
2075 #endif
2076     {
2077         result = getClassAlignmentRequirementStatic(clsHnd);
2078     }
2079
2080     EE_TO_JIT_TRANSITION_LEAF();
2081
2082     return result;
2083 }
2084
2085 unsigned CEEInfo::getClassAlignmentRequirementStatic(TypeHandle clsHnd)
2086 {
2087     LIMITED_METHOD_CONTRACT;
2088
2089     // Default alignment is sizeof(void*)
2090     unsigned result = TARGET_POINTER_SIZE;
2091
2092     MethodTable * pMT = clsHnd.GetMethodTable();
2093     if (pMT == NULL)
2094         return result;
2095
2096     if (pMT->HasLayout())
2097     {
2098         EEClassLayoutInfo* pInfo = pMT->GetLayoutInfo();
2099
2100         if (clsHnd.IsNativeValueType())
2101         {
2102             // if it's the unmanaged view of the managed type, we always use the unmanaged alignment requirement
2103             result = pMT->GetNativeLayoutInfo()->GetLargestAlignmentRequirement();
2104         }
2105         else if (pInfo->IsManagedSequential() || pInfo->IsBlittable())
2106         {
2107             _ASSERTE(!pMT->ContainsPointers());
2108
2109             // if it's managed sequential, we use the managed alignment requirement
2110             result = pInfo->m_ManagedLargestAlignmentRequirementOfAllMembers;
2111         }
2112     }
2113
2114 #ifdef FEATURE_64BIT_ALIGNMENT
2115     if (result < 8 && pMT->RequiresAlign8())
2116     {
2117         // If the structure contains 64-bit primitive fields and the platform requires 8-byte alignment for
2118         // such fields then make sure we return at least 8-byte alignment. Note that it's technically possible
2119         // to create unmanaged APIs that take unaligned structures containing such fields and this
2120         // unconditional alignment bump would cause us to get the calling convention wrong on platforms such
2121         // as ARM. If we see such cases in the future we'd need to add another control (such as an alignment
2122         // property for the StructLayout attribute or a marshaling directive attribute for p/invoke arguments)
2123         // that allows more precise control. For now we'll go with the likely scenario.
2124         result = 8;
2125     }
2126 #endif // FEATURE_64BIT_ALIGNMENT
2127
2128     return result;
2129 }
2130
2131 CORINFO_FIELD_HANDLE
2132 CEEInfo::getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num)
2133 {
2134     CONTRACTL {
2135         NOTHROW;
2136         GC_NOTRIGGER;
2137         MODE_PREEMPTIVE;
2138     } CONTRACTL_END;
2139
2140     CORINFO_FIELD_HANDLE result = NULL;
2141
2142     JIT_TO_EE_TRANSITION_LEAF();
2143
2144     TypeHandle VMClsHnd(clsHnd);
2145
2146     MethodTable* pMT= VMClsHnd.AsMethodTable();
2147
2148     result = (CORINFO_FIELD_HANDLE) ((pMT->GetApproxFieldDescListRaw()) + num);
2149
2150     EE_TO_JIT_TRANSITION_LEAF();
2151
2152     return result;
2153 }
2154
2155 static GetTypeLayoutResult GetTypeLayoutHelper(
2156     MethodTable* pMT,
2157     unsigned parentIndex,
2158     unsigned baseOffs,
2159     FieldDesc* pFD,
2160     CORINFO_TYPE_LAYOUT_NODE* treeNodes,
2161     size_t maxTreeNodes,
2162     size_t* numTreeNodes)
2163 {
2164     STANDARD_VM_CONTRACT;
2165
2166     if (*numTreeNodes >= maxTreeNodes)
2167     {
2168         return GetTypeLayoutResult::Partial;
2169     }
2170
2171     unsigned structNodeIndex = (unsigned)(*numTreeNodes)++;
2172     CORINFO_TYPE_LAYOUT_NODE& parNode = treeNodes[structNodeIndex];
2173     parNode.simdTypeHnd = NULL;
2174     parNode.diagFieldHnd = CORINFO_FIELD_HANDLE(pFD);
2175     parNode.parent = parentIndex;
2176     parNode.offset = baseOffs;
2177     parNode.size = pMT->GetNumInstanceFieldBytes();
2178     parNode.numFields = 0;
2179     parNode.type = CorInfoType::CORINFO_TYPE_VALUECLASS;
2180
2181     EEClass* pClass = pMT->GetClass();
2182     parNode.hasSignificantPadding = pClass->HasExplicitFieldOffsetLayout() || pClass->HasExplicitSize();
2183
2184     // The intrinsic SIMD/HW SIMD types have a lot of fields that the JIT does
2185     // not care about since they are considered primitives by the JIT.
2186     if (pMT->IsIntrinsicType())
2187     {
2188         const char* nsName;
2189         pMT->GetFullyQualifiedNameInfo(&nsName);
2190
2191         if ((strcmp(nsName, "System.Runtime.Intrinsics") == 0) ||
2192             (strcmp(nsName, "System.Numerics") == 0))
2193         {
2194             parNode.simdTypeHnd = CORINFO_CLASS_HANDLE(pMT);
2195             if (parentIndex != UINT32_MAX)
2196             {
2197                 return GetTypeLayoutResult::Success;
2198             }
2199         }
2200     }
2201
2202     ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
2203     for (FieldDesc* pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
2204     {
2205         CorElementType fieldType = pFD->GetFieldType();
2206         parNode.numFields++;
2207
2208         if (fieldType == ELEMENT_TYPE_VALUETYPE)
2209         {
2210             MethodTable* pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
2211             GetTypeLayoutResult result = GetTypeLayoutHelper(pFieldMT, structNodeIndex, baseOffs + pFD->GetOffset(), pFD, treeNodes, maxTreeNodes, numTreeNodes);
2212             if (result != GetTypeLayoutResult::Success)
2213             {
2214                 return result;
2215             }
2216         }
2217         else
2218         {
2219             if (*numTreeNodes >= maxTreeNodes)
2220             {
2221                 return GetTypeLayoutResult::Partial;
2222             }
2223
2224             CorInfoType corInfoType = CEEInfo::asCorInfoType(fieldType);
2225             _ASSERTE(corInfoType != CORINFO_TYPE_UNDEF);
2226
2227             CORINFO_TYPE_LAYOUT_NODE& treeNode = treeNodes[(*numTreeNodes)++];
2228             treeNode.simdTypeHnd = NULL;
2229             treeNode.diagFieldHnd = CORINFO_FIELD_HANDLE(pFD);
2230             treeNode.parent = structNodeIndex;
2231             treeNode.offset = baseOffs + pFD->GetOffset();
2232             treeNode.size = GetSizeForCorElementType(fieldType);
2233             treeNode.numFields = 0;
2234             treeNode.type = corInfoType;
2235             treeNode.hasSignificantPadding = false;
2236         }
2237
2238         if (pMT->GetClass()->IsInlineArray())
2239         {
2240             size_t treeNodeEnd = *numTreeNodes;
2241             uint32_t elemSize = pFD->GetSize();
2242             uint32_t arrSize = pMT->GetNumInstanceFieldBytes();
2243
2244             // Number of fields added for each element, including all
2245             // subfields. For example, for ValueTuple<int, int>[4]:
2246             // [ 0]: InlineArray
2247             // [ 1]:   ValueTuple<int, int>  parent = 0          -
2248             // [ 2]:     int                 parent = 1          |
2249             // [ 3]:     int                 parent = 1          |
2250             // [ 4]:   ValueTuple<int, int>  parent = 0          - stride = 3
2251             // [ 5]:     int                 parent = 4
2252             // [ 6]:     int                 parent = 4
2253             // [ 7]:   ValueTuple<int, int>  parent = 0
2254             // [ 8]:     int                 parent = 7
2255             // [ 9]:     int                 parent = 7
2256             // [10]:   ValueTuple<int, int>  parent = 0
2257             // [11]:     int                 parent = 10
2258             // [12]:     int                 parent = 10
2259
2260             unsigned elemFieldsStride = (unsigned)*numTreeNodes - (structNodeIndex + 1);
2261
2262             // Now duplicate the fields of the previous entry for each
2263             // additional element. For each entry we have to update the offset
2264             // and the parent index.
2265             for (uint32_t elemOffset = elemSize; elemOffset < arrSize; elemOffset += elemSize)
2266             {
2267                 size_t prevElemStart = *numTreeNodes - elemFieldsStride;
2268                 for (size_t i = 0; i < elemFieldsStride; i++)
2269                 {
2270                     if (*numTreeNodes >= maxTreeNodes)
2271                     {
2272                         return GetTypeLayoutResult::Partial;
2273                     }
2274
2275                     CORINFO_TYPE_LAYOUT_NODE& treeNode = treeNodes[(*numTreeNodes)++];
2276                     treeNode = treeNodes[prevElemStart + i];
2277                     treeNode.offset += elemSize;
2278                     // The first field points back to the inline array and has
2279                     // no bias; the rest of them do.
2280                     treeNode.parent += (i == 0) ? 0 : elemFieldsStride;
2281                 }
2282
2283                 parNode.numFields++;
2284             }
2285         }
2286     }
2287
2288     return GetTypeLayoutResult::Success;
2289 }
2290
2291 GetTypeLayoutResult CEEInfo::getTypeLayout(
2292     CORINFO_CLASS_HANDLE clsHnd,
2293     CORINFO_TYPE_LAYOUT_NODE* treeNodes,
2294     size_t* numTreeNodes)
2295 {
2296     STANDARD_VM_CONTRACT;
2297
2298     GetTypeLayoutResult result = GetTypeLayoutResult::Failure;
2299
2300     JIT_TO_EE_TRANSITION_LEAF();
2301
2302     TypeHandle typeHnd(clsHnd);
2303
2304     if (typeHnd.IsNativeValueType())
2305     {
2306         if (*numTreeNodes > 0)
2307         {
2308             *numTreeNodes = 1;
2309             treeNodes[0].simdTypeHnd = NULL;
2310             treeNodes[0].diagFieldHnd = NULL;
2311             treeNodes[0].parent = UINT32_MAX;
2312             treeNodes[0].offset = 0;
2313             treeNodes[0].size = typeHnd.GetSize();
2314             treeNodes[0].numFields = 0;
2315             treeNodes[0].type = CORINFO_TYPE_VALUECLASS;
2316             treeNodes[0].hasSignificantPadding = true;
2317             result = GetTypeLayoutResult::Success;
2318         }
2319         else
2320         {
2321             result = GetTypeLayoutResult::Partial;
2322         }
2323     }
2324     else if (typeHnd.IsValueType())
2325     {
2326         MethodTable* pMT = typeHnd.AsMethodTable();
2327
2328         size_t maxTreeNodes = *numTreeNodes;
2329         *numTreeNodes = 0;
2330         result = GetTypeLayoutHelper(pMT, UINT32_MAX, 0, NULL, treeNodes, maxTreeNodes, numTreeNodes);
2331     }
2332
2333     EE_TO_JIT_TRANSITION_LEAF();
2334
2335     return result;
2336 }
2337
2338 mdMethodDef
2339 CEEInfo::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod)
2340 {
2341     CONTRACTL {
2342         NOTHROW;
2343         GC_NOTRIGGER;
2344         MODE_PREEMPTIVE;
2345     } CONTRACTL_END;
2346
2347     mdMethodDef result = 0;
2348
2349     JIT_TO_EE_TRANSITION_LEAF();
2350
2351     MethodDesc* pMD = GetMethod(hMethod);
2352
2353     if (pMD->IsDynamicMethod())
2354     {
2355         // Dynamic methods do not have tokens
2356         result = mdMethodDefNil;
2357     }
2358     else
2359     {
2360         result = pMD->GetMemberDef();
2361     }
2362
2363     EE_TO_JIT_TRANSITION_LEAF();
2364
2365     return result;
2366 }
2367
2368 bool CEEInfo::checkMethodModifier(CORINFO_METHOD_HANDLE hMethod,
2369                                   LPCSTR modifier,
2370                                   bool fOptional)
2371 {
2372     CONTRACTL {
2373         THROWS;
2374         GC_TRIGGERS;
2375         MODE_PREEMPTIVE;
2376     } CONTRACTL_END;
2377
2378     bool result = false;
2379
2380     JIT_TO_EE_TRANSITION();
2381
2382     MethodDesc* pMD = GetMethod(hMethod);
2383     Module* pModule = pMD->GetModule();
2384     MetaSig sig(pMD);
2385     CorElementType eeType = fOptional ? ELEMENT_TYPE_CMOD_OPT : ELEMENT_TYPE_CMOD_REQD;
2386
2387     // modopts/modreqs for the method are by convention stored on the return type
2388     result = sig.GetReturnProps().HasCustomModifier(pModule, modifier, eeType);
2389
2390     EE_TO_JIT_TRANSITION();
2391
2392     return result;
2393 }
2394
2395 static unsigned MarkGCField(BYTE* gcPtrs, CorInfoGCType type)
2396 {
2397     STANDARD_VM_CONTRACT;
2398
2399     // Ensure that if we have multiple fields with the same offset,
2400     // that we don't double count the data in the gc layout.
2401     if (*gcPtrs == TYPE_GC_NONE)
2402     {
2403         *gcPtrs = (BYTE)type;
2404         return 1;
2405     }
2406     else if (*gcPtrs != type)
2407     {
2408         COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2409     }
2410
2411     return 0;
2412 }
2413
2414 static unsigned ComputeGCLayout(MethodTable* pMT, BYTE* gcPtrs)
2415 {
2416     STANDARD_VM_CONTRACT;
2417
2418     _ASSERTE(pMT->IsValueType());
2419
2420     unsigned result = 0;
2421     bool isInlineArray = pMT->GetClass()->IsInlineArray();
2422     ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
2423     for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
2424     {
2425         int fieldStartIndex = pFD->GetOffset() / TARGET_POINTER_SIZE;
2426
2427         if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
2428         {
2429             MethodTable* pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
2430             result += ComputeGCLayout(pFieldMT, gcPtrs + fieldStartIndex);
2431         }
2432         else if (pFD->IsObjRef())
2433         {
2434             result += MarkGCField(gcPtrs + fieldStartIndex, TYPE_GC_REF);
2435         }
2436         else if (pFD->IsByRef())
2437         {
2438             result += MarkGCField(gcPtrs + fieldStartIndex, TYPE_GC_BYREF);
2439         }
2440
2441         if (isInlineArray)
2442         {
2443             if (result > 0)
2444             {
2445                 _ASSERTE(pFD->GetOffset() == 0);
2446                 DWORD totalLayoutSize = pMT->GetNumInstanceFieldBytes() / TARGET_POINTER_SIZE;
2447                 DWORD elementLayoutSize = pFD->GetSize() / TARGET_POINTER_SIZE;
2448                 DWORD gcPointersInElement = result;
2449                 for (DWORD offset = elementLayoutSize; offset < totalLayoutSize; offset += elementLayoutSize)
2450                 {
2451                     memcpy(gcPtrs + offset, gcPtrs, elementLayoutSize);
2452                     result += gcPointersInElement;
2453                 }
2454             }
2455
2456             // inline array has only one element field
2457             break;
2458         }
2459     }
2460     return result;
2461 }
2462
2463 unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
2464 {
2465     CONTRACTL {
2466         THROWS;
2467         GC_TRIGGERS;
2468         MODE_PREEMPTIVE;
2469     } CONTRACTL_END;
2470
2471     unsigned result = 0;
2472
2473     JIT_TO_EE_TRANSITION();
2474
2475     TypeHandle VMClsHnd(clsHnd);
2476     result = getClassGClayoutStatic(VMClsHnd, gcPtrs);
2477
2478     EE_TO_JIT_TRANSITION();
2479
2480     return result;
2481 }
2482
2483
2484 unsigned CEEInfo::getClassGClayoutStatic(TypeHandle VMClsHnd, BYTE* gcPtrs)
2485 {
2486     STANDARD_VM_CONTRACT;
2487
2488     unsigned result = 0;
2489     MethodTable* pMT = VMClsHnd.GetMethodTable();
2490
2491     if (VMClsHnd.IsNativeValueType())
2492     {
2493         // native value types have no GC pointers
2494         result = 0;
2495         memset(gcPtrs, TYPE_GC_NONE,
2496                (VMClsHnd.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2497     }
2498     else if (pMT->IsByRefLike())
2499     {
2500         memset(gcPtrs, TYPE_GC_NONE,
2501             (VMClsHnd.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2502         // ByRefLike structs can contain byref fields or other ByRefLike structs
2503         result = ComputeGCLayout(VMClsHnd.AsMethodTable(), gcPtrs);
2504     }
2505     else
2506     {
2507         _ASSERTE(sizeof(BYTE) == 1);
2508
2509         BOOL isValueClass = pMT->IsValueType();
2510         unsigned int size = isValueClass ? VMClsHnd.GetSize() : pMT->GetNumInstanceFieldBytes() + OBJECT_SIZE;
2511
2512         // assume no GC pointers at first
2513         result = 0;
2514         memset(gcPtrs, TYPE_GC_NONE,
2515                (size + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2516
2517         // walk the GC descriptors, turning on the correct bits
2518         if (pMT->ContainsPointers())
2519         {
2520             CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
2521             CGCDescSeries * pByValueSeries = map->GetLowestSeries();
2522
2523             for (SIZE_T i = 0; i < map->GetNumSeries(); i++)
2524             {
2525                 // Get offset into the value class of the first pointer field (includes a +Object)
2526                 size_t cbSeriesSize = pByValueSeries->GetSeriesSize() + pMT->GetBaseSize();
2527                 size_t cbSeriesOffset = pByValueSeries->GetSeriesOffset();
2528                 size_t cbOffset = isValueClass ? cbSeriesOffset - OBJECT_SIZE : cbSeriesOffset;
2529
2530                 _ASSERTE (cbOffset % TARGET_POINTER_SIZE == 0);
2531                 _ASSERTE (cbSeriesSize % TARGET_POINTER_SIZE == 0);
2532
2533                 result += (unsigned) (cbSeriesSize / TARGET_POINTER_SIZE);
2534                 memset(&gcPtrs[cbOffset / TARGET_POINTER_SIZE], TYPE_GC_REF, cbSeriesSize / TARGET_POINTER_SIZE);
2535
2536                 pByValueSeries++;
2537             }
2538         }
2539     }
2540
2541     return result;
2542 }
2543
2544 // returns the enregister info for a struct based on type of fields, alignment, etc.
2545 bool CEEInfo::getSystemVAmd64PassStructInRegisterDescriptor(
2546                                                 /*IN*/  CORINFO_CLASS_HANDLE structHnd,
2547                                                 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
2548 {
2549     CONTRACTL {
2550         THROWS;
2551         GC_TRIGGERS;
2552         MODE_PREEMPTIVE;
2553     } CONTRACTL_END;
2554
2555 #if defined(UNIX_AMD64_ABI_ITF)
2556     JIT_TO_EE_TRANSITION();
2557
2558     _ASSERTE(structPassInRegDescPtr != nullptr);
2559     TypeHandle th(structHnd);
2560
2561     structPassInRegDescPtr->passedInRegisters = false;
2562
2563     // Make sure this is a value type.
2564     if (th.IsValueType())
2565     {
2566         _ASSERTE(CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeStruct);
2567
2568         // The useNativeLayout in this case tracks whether the classification
2569         // is for a native layout of the struct or not.
2570         // If the struct has special marshaling it has a native layout.
2571         // In such cases the classifier needs to use the native layout.
2572         // For structs with no native layout, the managed layout should be used
2573         // even if classified for the purposes of marshaling/PInvoke passing.
2574         bool useNativeLayout = false;
2575         MethodTable* methodTablePtr = nullptr;
2576         if (!th.IsTypeDesc())
2577         {
2578             methodTablePtr = th.AsMethodTable();
2579         }
2580         else
2581         {
2582             _ASSERTE(th.IsNativeValueType());
2583
2584             useNativeLayout = true;
2585             methodTablePtr = th.AsNativeValueType();
2586         }
2587         _ASSERTE(methodTablePtr != nullptr);
2588
2589         // If we have full support for UNIX_AMD64_ABI, and not just the interface,
2590         // then we've cached whether this is a reg passed struct in the MethodTable, computed during
2591         // MethodTable construction. Otherwise, we are just building in the interface, and we haven't
2592         // computed or cached anything, so we need to compute it now.
2593 #if defined(UNIX_AMD64_ABI)
2594         bool canPassInRegisters = useNativeLayout ? methodTablePtr->GetNativeLayoutInfo()->IsNativeStructPassedInRegisters()
2595                                                   : methodTablePtr->IsRegPassedStruct();
2596 #else // !defined(UNIX_AMD64_ABI)
2597         bool canPassInRegisters = false;
2598         SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2599         if (th.GetSize() <= CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)
2600         {
2601             canPassInRegisters = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2602         }
2603 #endif // !defined(UNIX_AMD64_ABI)
2604
2605         if (canPassInRegisters)
2606         {
2607 #if defined(UNIX_AMD64_ABI)
2608             SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2609             bool result = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2610
2611             // The answer must be true at this point.
2612             _ASSERTE(result);
2613 #endif // UNIX_AMD64_ABI
2614
2615             structPassInRegDescPtr->passedInRegisters = true;
2616
2617             structPassInRegDescPtr->eightByteCount = (uint8_t)helper.eightByteCount;
2618             _ASSERTE(structPassInRegDescPtr->eightByteCount <= CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS);
2619
2620             for (unsigned int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++)
2621             {
2622                 structPassInRegDescPtr->eightByteClassifications[i] = helper.eightByteClassifications[i];
2623                 structPassInRegDescPtr->eightByteSizes[i] = (uint8_t)helper.eightByteSizes[i];
2624                 structPassInRegDescPtr->eightByteOffsets[i] = (uint8_t)helper.eightByteOffsets[i];
2625             }
2626         }
2627
2628         _ASSERTE(structPassInRegDescPtr->passedInRegisters == canPassInRegisters);
2629     }
2630
2631     EE_TO_JIT_TRANSITION();
2632
2633     return true;
2634 #else // !defined(UNIX_AMD64_ABI_ITF)
2635     return false;
2636 #endif // !defined(UNIX_AMD64_ABI_ITF)
2637 }
2638
2639 /*********************************************************************/
2640 unsigned CEEInfo::getClassNumInstanceFields (CORINFO_CLASS_HANDLE clsHnd)
2641 {
2642     CONTRACTL {
2643         NOTHROW;
2644         GC_NOTRIGGER;
2645         MODE_PREEMPTIVE;
2646     } CONTRACTL_END;
2647
2648     unsigned result = 0;
2649
2650     JIT_TO_EE_TRANSITION_LEAF();
2651
2652     TypeHandle th(clsHnd);
2653
2654     if (!th.IsTypeDesc())
2655     {
2656         result = th.AsMethodTable()->GetNumInstanceFields();
2657     }
2658     else
2659     {
2660         // native value types are opaque aggregates with explicit size
2661         result = 0;
2662     }
2663
2664     EE_TO_JIT_TRANSITION_LEAF();
2665
2666     return result;
2667 }
2668
2669
2670 CorInfoType CEEInfo::asCorInfoType (CORINFO_CLASS_HANDLE clsHnd)
2671 {
2672     CONTRACTL {
2673         THROWS;
2674         GC_TRIGGERS;
2675         MODE_PREEMPTIVE;
2676     } CONTRACTL_END;
2677
2678     CorInfoType result = CORINFO_TYPE_UNDEF;
2679
2680     JIT_TO_EE_TRANSITION();
2681
2682     TypeHandle VMClsHnd(clsHnd);
2683     result = toJitType(VMClsHnd);
2684
2685     EE_TO_JIT_TRANSITION();
2686
2687     return result;
2688 }
2689
2690
2691 void CEEInfo::getLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* pLookupKind)
2692 {
2693     CONTRACTL {
2694         THROWS;
2695         GC_TRIGGERS;
2696         MODE_PREEMPTIVE;
2697     } CONTRACTL_END;
2698
2699     /* Initialize fields of result for debug build warning */
2700     pLookupKind->needsRuntimeLookup = false;
2701     pLookupKind->runtimeLookupKind  = CORINFO_LOOKUP_THISOBJ;
2702
2703     JIT_TO_EE_TRANSITION();
2704
2705     MethodDesc *pContextMD = GetMethod(context);
2706
2707     // If the method table is not shared, then return CONST
2708     if (!pContextMD->GetMethodTable()->IsSharedByGenericInstantiations())
2709     {
2710         pLookupKind->needsRuntimeLookup = false;
2711     }
2712     else
2713     {
2714         pLookupKind->needsRuntimeLookup = true;
2715
2716         // If we've got a vtable extra argument, go through that
2717         if (pContextMD->RequiresInstMethodTableArg())
2718         {
2719             pLookupKind->runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
2720         }
2721         // If we've got an object, go through its vtable
2722         else if (pContextMD->AcquiresInstMethodTableFromThis())
2723         {
2724             pLookupKind->runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
2725         }
2726         // Otherwise go through the method-desc argument
2727         else
2728         {
2729             _ASSERTE(pContextMD->RequiresInstMethodDescArg());
2730             pLookupKind->runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
2731         }
2732     }
2733
2734     EE_TO_JIT_TRANSITION();
2735 }
2736
2737 CORINFO_METHOD_HANDLE CEEInfo::GetDelegateCtor(
2738                                         CORINFO_METHOD_HANDLE methHnd,
2739                                         CORINFO_CLASS_HANDLE clsHnd,
2740                                         CORINFO_METHOD_HANDLE targetMethodHnd,
2741                                         DelegateCtorArgs *pCtorData)
2742 {
2743     CONTRACTL {
2744         THROWS;
2745         GC_TRIGGERS;
2746         MODE_PREEMPTIVE;
2747     } CONTRACTL_END;
2748
2749     CORINFO_METHOD_HANDLE result = NULL;
2750
2751     JIT_TO_EE_TRANSITION();
2752
2753     MethodDesc *pCurrentCtor = (MethodDesc*)methHnd;
2754     if (!pCurrentCtor->IsFCall())
2755     {
2756         result =  methHnd;
2757     }
2758     else
2759     {
2760         MethodDesc *pTargetMethod = (MethodDesc*)targetMethodHnd;
2761         TypeHandle delegateType = (TypeHandle)clsHnd;
2762
2763         MethodDesc *pDelegateCtor = COMDelegate::GetDelegateCtor(delegateType, pTargetMethod, pCtorData);
2764         if (!pDelegateCtor)
2765             pDelegateCtor = pCurrentCtor;
2766         result = (CORINFO_METHOD_HANDLE)pDelegateCtor;
2767     }
2768
2769     EE_TO_JIT_TRANSITION();
2770
2771     return result;
2772 }
2773
2774 void CEEInfo::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd)
2775 {
2776     CONTRACTL {
2777         THROWS;
2778         GC_TRIGGERS;
2779         MODE_PREEMPTIVE;
2780     } CONTRACTL_END;
2781
2782     JIT_TO_EE_TRANSITION();
2783
2784     MethodDesc* pMD = GetMethod(methHnd);
2785
2786     if (pMD->IsDynamicMethod())
2787     {
2788         pMD->AsDynamicMethodDesc()->GetResolver()->FreeCompileTimeState();
2789     }
2790
2791     EE_TO_JIT_TRANSITION();
2792 }
2793
2794 // Given a module scope (scopeHnd), a method handle (context) and an metadata token,
2795 // attempt to load the handle (type, field or method) associated with the token.
2796 // If this is not possible at compile-time (because the method code is shared and the token contains type parameters)
2797 // then indicate how the handle should be looked up at run-time.
2798 //
2799 // See corinfo.h for more details
2800 //
2801 void CEEInfo::embedGenericHandle(
2802             CORINFO_RESOLVED_TOKEN * pResolvedToken,
2803             bool                     fEmbedParent,
2804             CORINFO_GENERICHANDLE_RESULT *pResult)
2805 {
2806     CONTRACTL {
2807         THROWS;
2808         GC_TRIGGERS;
2809         MODE_PREEMPTIVE;
2810     } CONTRACTL_END;
2811
2812     INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
2813
2814     JIT_TO_EE_TRANSITION();
2815
2816     BOOL fRuntimeLookup;
2817     MethodDesc * pTemplateMD = NULL;
2818
2819     if (!fEmbedParent && pResolvedToken->hMethod != NULL)
2820     {
2821         MethodDesc * pMD = (MethodDesc *)pResolvedToken->hMethod;
2822         TypeHandle th(pResolvedToken->hClass);
2823
2824         pResult->handleType = CORINFO_HANDLETYPE_METHOD;
2825
2826         Instantiation methodInst = pMD->GetMethodInstantiation();
2827
2828         pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, th.GetMethodTable(), FALSE, methodInst, FALSE);
2829
2830         // Normalize the method handle for reflection
2831         if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Ldtoken)
2832             pMD = MethodDesc::FindOrCreateAssociatedMethodDescForReflection(pMD, th, methodInst);
2833
2834         pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pMD;
2835         pTemplateMD = pMD;
2836
2837         // Runtime lookup is only required for stubs. Regular entrypoints are always the same shared MethodDescs.
2838         fRuntimeLookup = pMD->IsWrapperStub() &&
2839             (th.IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(methodInst));
2840     }
2841     else
2842     if (!fEmbedParent && pResolvedToken->hField != NULL)
2843     {
2844         FieldDesc * pFD = (FieldDesc *)pResolvedToken->hField;
2845         TypeHandle th(pResolvedToken->hClass);
2846
2847         pResult->handleType = CORINFO_HANDLETYPE_FIELD;
2848
2849         pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pFD;
2850
2851         fRuntimeLookup = th.IsSharedByGenericInstantiations() && pFD->IsStatic();
2852     }
2853     else
2854     {
2855         TypeHandle th(pResolvedToken->hClass);
2856
2857         pResult->handleType = CORINFO_HANDLETYPE_CLASS;
2858         pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsPtr();
2859
2860         if (fEmbedParent && pResolvedToken->hMethod != NULL)
2861         {
2862             MethodDesc * pDeclaringMD = (MethodDesc *)pResolvedToken->hMethod;
2863
2864             if (!pDeclaringMD->GetMethodTable()->HasSameTypeDefAs(th.GetMethodTable()))
2865             {
2866                 //
2867                 // The method type may point to a sub-class of the actual class that declares the method.
2868                 // It is important to embed the declaring type in this case.
2869                 //
2870
2871                 pTemplateMD = pDeclaringMD;
2872
2873                 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pDeclaringMD->GetMethodTable();
2874             }
2875         }
2876
2877         // IsSharedByGenericInstantiations would not work here. The runtime lookup is required
2878         // even for standalone generic variables that show up as __Canon here.
2879         fRuntimeLookup = th.IsCanonicalSubtype();
2880     }
2881
2882     _ASSERTE(pResult->compileTimeHandle);
2883
2884     if (fRuntimeLookup)
2885     {
2886         DictionaryEntryKind entryKind = EmptySlot;
2887         switch (pResult->handleType)
2888         {
2889         case CORINFO_HANDLETYPE_CLASS:
2890             entryKind = (pTemplateMD != NULL) ? DeclaringTypeHandleSlot : TypeHandleSlot;
2891             break;
2892         case CORINFO_HANDLETYPE_METHOD:
2893             entryKind = MethodDescSlot;
2894             break;
2895         case CORINFO_HANDLETYPE_FIELD:
2896             entryKind = FieldDescSlot;
2897             break;
2898         default:
2899             _ASSERTE(false);
2900         }
2901
2902         ComputeRuntimeLookupForSharedGenericToken(entryKind,
2903                                                   pResolvedToken,
2904                                                   NULL,
2905                                                   pTemplateMD,
2906                                                   &pResult->lookup);
2907     }
2908     else
2909     {
2910         // If the target is not shared then we've already got our result and
2911         // can simply do a static look up
2912         pResult->lookup.lookupKind.needsRuntimeLookup = false;
2913
2914         pResult->lookup.constLookup.handle = pResult->compileTimeHandle;
2915         pResult->lookup.constLookup.accessType = IAT_VALUE;
2916     }
2917
2918     EE_TO_JIT_TRANSITION();
2919 }
2920
2921 //
2922 // EnsureActive is used to track triggers for creation of per-AppDomain state instead, including allocations required for statics and
2923 // triggering of module cctors.
2924 //
2925 // The basic rule is: There should be no possibility of a module that is "active" to have a direct call into a  module that
2926 // is not "active". And we don't want to intercept every call during runtime, so during compile time we track static calls and
2927 // everything that can result in new virtual calls.
2928 //
2929 // The current algorithm (scan the parent type chain and instantiation variables) is more than enough to maintain this invariant.
2930 // One could come up with a more efficient algorithm that still maintains the invariant, but it may introduce backward compatibility
2931 // issues.
2932 //
2933 void CEEInfo::EnsureActive(TypeHandle th, MethodDesc * pMD)
2934 {
2935     STANDARD_VM_CONTRACT;
2936
2937     if (pMD != NULL && pMD->HasMethodInstantiation())
2938         pMD->EnsureActive();
2939     if (!th.IsTypeDesc())
2940         th.AsMethodTable()->EnsureInstanceActive();
2941 }
2942
2943 CORINFO_OBJECT_HANDLE CEEInfo::getJitHandleForObject(OBJECTREF objref, bool knownFrozen)
2944 {
2945     CONTRACTL
2946     {
2947         THROWS;
2948         GC_TRIGGERS;
2949         MODE_COOPERATIVE;
2950     }
2951     CONTRACTL_END;
2952
2953     Object* obj = OBJECTREFToObject(objref);
2954     if (knownFrozen || GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
2955     {
2956         return (CORINFO_OBJECT_HANDLE)obj;
2957     }
2958
2959     if (m_pJitHandles == nullptr)
2960     {
2961         m_pJitHandles = new SArray<OBJECTHANDLE>();
2962     }
2963
2964     OBJECTHANDLEHolder handle = AppDomain::GetCurrentDomain()->CreateHandle(objref);
2965     m_pJitHandles->Append(handle);
2966     handle.SuppressRelease();
2967
2968     // We know that handle is aligned so we use the lowest bit as a marker
2969     // "this is a handle, not a frozen object".
2970     return (CORINFO_OBJECT_HANDLE)((size_t)handle.GetValue() | 1);
2971 }
2972
2973 OBJECTREF CEEInfo::getObjectFromJitHandle(CORINFO_OBJECT_HANDLE handle)
2974 {
2975     CONTRACTL
2976     {
2977         NOTHROW;
2978         GC_NOTRIGGER;
2979         MODE_COOPERATIVE;
2980     }
2981     CONTRACTL_END;
2982
2983     size_t intHandle = (size_t)handle;
2984     if (intHandle & 1)
2985     {
2986         return ObjectToOBJECTREF(*(Object**)(intHandle - 1));
2987     }
2988
2989     // Frozen object
2990     return ObjectToOBJECTREF((Object*)intHandle);
2991 }
2992
2993 MethodDesc * CEEInfo::GetMethodForSecurity(CORINFO_METHOD_HANDLE callerHandle)
2994 {
2995     STANDARD_VM_CONTRACT;
2996
2997     // Cache the cast lookup
2998     if (callerHandle == m_hMethodForSecurity_Key)
2999     {
3000         return m_pMethodForSecurity_Value;
3001     }
3002
3003     MethodDesc * pCallerMethod = (MethodDesc *)callerHandle;
3004
3005     //If the caller is generic, load the open type and then load the field again,  This allows us to
3006     //differentiate between BadGeneric<T> containing a memberRef for a field of type InaccessibleClass and
3007     //GoodGeneric<T> containing a memberRef for a field of type T instantiated over InaccessibleClass.
3008     MethodDesc * pMethodForSecurity = pCallerMethod->IsILStub() ?
3009         pCallerMethod : pCallerMethod->LoadTypicalMethodDefinition();
3010
3011     m_hMethodForSecurity_Key = callerHandle;
3012     m_pMethodForSecurity_Value = pMethodForSecurity;
3013
3014     return pMethodForSecurity;
3015 }
3016
3017 // Check that the instantiation is <!/!!0, ..., !/!!(n-1)>
3018 static bool IsSignatureForTypicalInstantiation(SigPointer sigptr, CorElementType varType, ULONG ntypars)
3019 {
3020     STANDARD_VM_CONTRACT;
3021
3022     for (uint32_t i = 0; i < ntypars; i++)
3023     {
3024         CorElementType type;
3025         IfFailThrow(sigptr.GetElemType(&type));
3026         if (type != varType)
3027             return false;
3028
3029         uint32_t data;
3030         IfFailThrow(sigptr.GetData(&data));
3031
3032         if (data != i)
3033              return false;
3034     }
3035
3036     return true;
3037 }
3038
3039 // Check that methodSpec instantiation is <!!0, ..., !!(n-1)>
3040 static bool IsMethodSpecForTypicalInstantiation(SigPointer sigptr)
3041 {
3042     STANDARD_VM_CONTRACT;
3043
3044     BYTE etype;
3045     IfFailThrow(sigptr.GetByte(&etype));
3046     _ASSERTE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST);
3047
3048     uint32_t ntypars;
3049     IfFailThrow(sigptr.GetData(&ntypars));
3050
3051     return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_MVAR, ntypars);
3052 }
3053
3054 // Check that typeSpec instantiation is <!0, ..., !(n-1)>
3055 static bool IsTypeSpecForTypicalInstantiation(SigPointer sigptr)
3056 {
3057     STANDARD_VM_CONTRACT;
3058
3059     CorElementType type;
3060     IfFailThrow(sigptr.GetElemType(&type));
3061     if (type != ELEMENT_TYPE_GENERICINST)
3062         return false;
3063
3064     IfFailThrow(sigptr.SkipExactlyOne());
3065
3066     uint32_t ntypars;
3067     IfFailThrow(sigptr.GetData(&ntypars));
3068
3069     return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_VAR, ntypars);
3070 }
3071
3072 void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entryKind,
3073                                                         CORINFO_RESOLVED_TOKEN * pResolvedToken,
3074                                                         CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
3075                                                         MethodDesc * pTemplateMD /* for method-based slots */,
3076                                                         CORINFO_LOOKUP *pResultLookup)
3077 {
3078     CONTRACTL{
3079         STANDARD_VM_CHECK;
3080         PRECONDITION(CheckPointer(pResultLookup));
3081     } CONTRACTL_END;
3082
3083     pResultLookup->lookupKind.needsRuntimeLookup = true;
3084     pResultLookup->lookupKind.runtimeLookupFlags = 0;
3085
3086     CORINFO_RUNTIME_LOOKUP *pResult = &pResultLookup->runtimeLookup;
3087     pResult->signature = NULL;
3088
3089     pResult->indirectFirstOffset = 0;
3090     pResult->indirectSecondOffset = 0;
3091
3092     // Dictionary size checks skipped by default, unless we decide otherwise
3093     pResult->sizeOffset = CORINFO_NO_SIZE_CHECK;
3094
3095     // Unless we decide otherwise, just do the lookup via a helper function
3096     pResult->indirections = CORINFO_USEHELPER;
3097
3098     // Runtime lookups in inlined contexts are not supported by the runtime for now
3099     if (pResolvedToken->tokenContext != METHOD_BEING_COMPILED_CONTEXT())
3100     {
3101         pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_NOT_SUPPORTED;
3102         return;
3103     }
3104
3105     MethodDesc* pContextMD = GetMethodFromContext(pResolvedToken->tokenContext);
3106     MethodTable* pContextMT = pContextMD->GetMethodTable();
3107     bool isStaticVirtual = (pConstrainedResolvedToken != nullptr && pContextMD != nullptr && pContextMD->IsStatic());
3108
3109     // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup.
3110     if (!pContextMD->IsSharedByGenericInstantiations())
3111         COMPlusThrow(kInvalidProgramException);
3112
3113     BOOL fInstrument = FALSE;
3114
3115     if (pContextMD->RequiresInstMethodDescArg())
3116     {
3117         pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
3118     }
3119     else
3120     {
3121         if (pContextMD->RequiresInstMethodTableArg())
3122             pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
3123         else
3124             pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
3125     }
3126
3127     // If we've got a  method type parameter of any kind then we must look in the method desc arg
3128     if (pContextMD->RequiresInstMethodDescArg())
3129     {
3130         pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG : CORINFO_HELP_RUNTIMEHANDLE_METHOD;
3131
3132         if (fInstrument)
3133             goto NoSpecialCase;
3134
3135         // Special cases:
3136         // (1) Naked method type variable: look up directly in instantiation hanging off runtime md
3137         // (2) Reference to method-spec of current method (e.g. a recursive call) i.e. currentmeth<!0,...,!(n-1)>
3138         if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3139         {
3140             SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3141             CorElementType type;
3142             IfFailThrow(sigptr.GetElemType(&type));
3143             if (type == ELEMENT_TYPE_MVAR)
3144             {
3145                 pResult->indirections = 2;
3146                 pResult->testForNull = 0;
3147                 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3148
3149                 uint32_t data;
3150                 IfFailThrow(sigptr.GetData(&data));
3151                 pResult->offsets[1] = sizeof(TypeHandle) * data;
3152
3153                 return;
3154             }
3155         }
3156         else if (entryKind == MethodDescSlot)
3157         {
3158             // It's the context itself (i.e. a recursive call)
3159             if (!pTemplateMD->HasSameMethodDefAs(pContextMD))
3160                 goto NoSpecialCase;
3161
3162             // Now just check that the instantiation is (!!0, ..., !!(n-1))
3163             if (!IsMethodSpecForTypicalInstantiation(SigPointer(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)))
3164                 goto NoSpecialCase;
3165
3166             // Type instantiation has to match too if there is one
3167             if (pContextMT->HasInstantiation())
3168             {
3169                 TypeHandle thTemplate(pResolvedToken->hClass);
3170
3171                 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3172                     goto NoSpecialCase;
3173
3174                 // This check filters out method instantiation on generic type definition, like G::M<!!0>()
3175                 // We may not ever get it here. Filter it out just to be sure...
3176                 if (pResolvedToken->pTypeSpec == NULL)
3177                     goto NoSpecialCase;
3178
3179                 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3180                     goto NoSpecialCase;
3181             }
3182
3183             // Just use the method descriptor that was passed in!
3184             pResult->indirections = 0;
3185             pResult->testForNull = 0;
3186
3187             return;
3188         }
3189     }
3190     // Otherwise we must just have class type variables
3191     else
3192     {
3193         _ASSERTE(pContextMT->GetNumGenericArgs() > 0);
3194
3195         if (pContextMD->RequiresInstMethodTableArg())
3196         {
3197             // If we've got a vtable extra argument, go through that
3198             pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3199         }
3200         // If we've got an object, go through its vtable
3201         else
3202         {
3203             _ASSERTE(pContextMD->AcquiresInstMethodTableFromThis());
3204             pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3205         }
3206
3207         if (fInstrument)
3208             goto NoSpecialCase;
3209
3210         // Special cases:
3211         // (1) Naked class type variable: look up directly in instantiation hanging off vtable
3212         // (2) C<!0,...,!(n-1)> where C is the context's class and C is sealed: just return vtable ptr
3213         if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3214         {
3215             SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3216             CorElementType type;
3217             IfFailThrow(sigptr.GetElemType(&type));
3218             if (type == ELEMENT_TYPE_VAR)
3219             {
3220                 pResult->indirections = 3;
3221                 pResult->testForNull = 0;
3222                 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3223                 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3224                 uint32_t data;
3225                 IfFailThrow(sigptr.GetData(&data));
3226                 pResult->offsets[2] = sizeof(TypeHandle) * data;
3227
3228                 return;
3229             }
3230             else if (type == ELEMENT_TYPE_GENERICINST &&
3231                 (pContextMT->IsSealed() || pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM))
3232             {
3233                 TypeHandle thTemplate(pResolvedToken->hClass);
3234
3235                 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3236                     goto NoSpecialCase;
3237
3238                 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3239                     goto NoSpecialCase;
3240
3241                 // Just use the vtable pointer itself!
3242                 pResult->indirections = 0;
3243                 pResult->testForNull = 0;
3244
3245                 return;
3246             }
3247         }
3248     }
3249
3250 NoSpecialCase:
3251
3252     SigBuilder sigBuilder;
3253
3254     sigBuilder.AppendData(entryKind);
3255
3256     if (pResultLookup->lookupKind.runtimeLookupKind != CORINFO_LOOKUP_METHODPARAM)
3257     {
3258         _ASSERTE(pContextMT->GetNumDicts() > 0);
3259         sigBuilder.AppendData(pContextMT->GetNumDicts() - 1);
3260     }
3261
3262     Module * pModule = (Module *)pResolvedToken->tokenScope;
3263
3264     switch (entryKind)
3265     {
3266     case DeclaringTypeHandleSlot:
3267         _ASSERTE(pTemplateMD != NULL);
3268         sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3269         sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3270         FALLTHROUGH;
3271
3272     case TypeHandleSlot:
3273         {
3274             if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
3275             {
3276                 sigBuilder.AppendElementType(ELEMENT_TYPE_SZARRAY);
3277             }
3278
3279             // Note that we can come here with pResolvedToken->pTypeSpec == NULL for invalid IL that
3280             // directly references __Canon
3281             if (pResolvedToken->pTypeSpec != NULL)
3282             {
3283                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3284                 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3285             }
3286             else
3287             {
3288                 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3289                 sigBuilder.AppendPointer(pResolvedToken->hClass);
3290             }
3291         }
3292         break;
3293
3294     case ConstrainedMethodEntrySlot:
3295         // Encode constrained type token
3296         if (pConstrainedResolvedToken->pTypeSpec != NULL)
3297         {
3298             SigPointer sigptr(pConstrainedResolvedToken->pTypeSpec, pConstrainedResolvedToken->cbTypeSpec);
3299             sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3300         }
3301         else
3302         {
3303             sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3304             sigBuilder.AppendPointer(pConstrainedResolvedToken->hClass);
3305         }
3306         FALLTHROUGH;
3307
3308     case MethodDescSlot:
3309     case MethodEntrySlot:
3310     case DispatchStubAddrSlot:
3311         {
3312             // Encode containing type
3313             if (pResolvedToken->pTypeSpec != NULL)
3314             {
3315                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3316                 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3317             }
3318             else
3319             {
3320                 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3321                 sigBuilder.AppendPointer(pResolvedToken->hClass);
3322             }
3323
3324             // Encode method
3325             _ASSERTE(pTemplateMD != NULL);
3326
3327             mdMethodDef methodToken               = pTemplateMD->GetMemberDef();
3328             DWORD       methodFlags               = 0;
3329
3330             // 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
3331             // like instantiating stub for generic method definition that do not have method spec but that won't be caught by the later conditions either.
3332             BOOL fMethodNeedsInstantiation = (pResolvedToken->pMethodSpec != NULL) && pTemplateMD->HasMethodInstantiation() && !pTemplateMD->IsGenericMethodDefinition();
3333
3334             if (pTemplateMD->IsUnboxingStub())
3335                 methodFlags |= ENCODE_METHOD_SIG_UnboxingStub;
3336             // Always create instantiating stub for method entry points even if the template does not ask for it. It saves caller
3337             // from creating throw-away instantiating stub.
3338             if (pTemplateMD->IsInstantiatingStub() || (entryKind == MethodEntrySlot))
3339                 methodFlags |= ENCODE_METHOD_SIG_InstantiatingStub;
3340             if (fMethodNeedsInstantiation)
3341                 methodFlags |= ENCODE_METHOD_SIG_MethodInstantiation;
3342             if (IsNilToken(methodToken))
3343             {
3344                 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3345             }
3346             else
3347             if (entryKind == DispatchStubAddrSlot && pTemplateMD->IsVtableMethod())
3348             {
3349                 // Encode the method for dispatch stub using slot to avoid touching the interface method MethodDesc at runtime
3350
3351                 // There should be no other flags set if we are encoding the method using slot for virtual stub dispatch
3352                 _ASSERTE(methodFlags == 0);
3353
3354                 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3355             }
3356
3357             sigBuilder.AppendData(methodFlags);
3358
3359             if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
3360             {
3361                 // Encode method token and its module context (as method's type)
3362                 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3363                 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3364
3365                 sigBuilder.AppendData(RidFromToken(methodToken));
3366             }
3367             else
3368             {
3369                 sigBuilder.AppendData(pTemplateMD->GetSlot());
3370             }
3371
3372             if (fMethodNeedsInstantiation)
3373             {
3374                 SigPointer sigptr(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
3375
3376                 BYTE etype;
3377                 IfFailThrow(sigptr.GetByte(&etype));
3378
3379                 // Load the generic method instantiation
3380                 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, pModule);
3381
3382                 uint32_t nGenericMethodArgs;
3383                 IfFailThrow(sigptr.GetData(&nGenericMethodArgs));
3384                 sigBuilder.AppendData(nGenericMethodArgs);
3385
3386                 _ASSERTE(nGenericMethodArgs == pTemplateMD->GetNumGenericMethodArgs());
3387
3388                 for (DWORD i = 0; i < nGenericMethodArgs; i++)
3389                 {
3390                     sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3391                 }
3392             }
3393         }
3394         break;
3395
3396     case FieldDescSlot:
3397         {
3398             if (pResolvedToken->pTypeSpec != NULL)
3399             {
3400                  // Encode containing type
3401                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3402                 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3403             }
3404             else
3405             {
3406                 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3407                 sigBuilder.AppendPointer(pResolvedToken->hClass);
3408             }
3409
3410             FieldDesc * pField = (FieldDesc *)pResolvedToken->hField;
3411             _ASSERTE(pField != NULL);
3412
3413             DWORD fieldIndex = pField->GetApproxEnclosingMethodTable()->GetIndexForFieldDesc(pField);
3414             sigBuilder.AppendData(fieldIndex);
3415         }
3416         break;
3417
3418     default:
3419         _ASSERTE(false);
3420     }
3421
3422     DictionaryEntrySignatureSource signatureSource = FromJIT;
3423
3424     WORD slot;
3425
3426     // It's a method dictionary lookup
3427     if (pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM)
3428     {
3429         _ASSERTE(pContextMD != NULL);
3430         _ASSERTE(pContextMD->HasMethodInstantiation());
3431
3432         if (DictionaryLayout::FindToken(pContextMD, pContextMD->GetLoaderAllocator(), 1, &sigBuilder, NULL, signatureSource, pResult, &slot))
3433         {
3434             pResult->testForNull = 1;
3435             int minDictSize = pContextMD->GetNumGenericMethodArgs() + 1 + pContextMD->GetDictionaryLayout()->GetNumInitialSlots();
3436             if (slot >= minDictSize)
3437             {
3438                 // Dictionaries are guaranteed to have at least the number of slots allocated initially, so skip size check for smaller indexes
3439                 pResult->sizeOffset = (WORD)pContextMD->GetNumGenericMethodArgs() * sizeof(DictionaryEntry);
3440             }
3441
3442             // Indirect through dictionary table pointer in InstantiatedMethodDesc
3443             pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3444         }
3445     }
3446
3447     // It's a class dictionary lookup (CORINFO_LOOKUP_CLASSPARAM or CORINFO_LOOKUP_THISOBJ)
3448     else
3449     {
3450         if (DictionaryLayout::FindToken(pContextMT, pContextMT->GetLoaderAllocator(), 2, &sigBuilder, NULL, signatureSource, pResult, &slot))
3451         {
3452             pResult->testForNull = 1;
3453             int minDictSize = pContextMT->GetNumGenericArgs() + 1 + pContextMT->GetClass()->GetDictionaryLayout()->GetNumInitialSlots();
3454             if (slot >= minDictSize)
3455             {
3456                 // Dictionaries are guaranteed to have at least the number of slots allocated initially, so skip size check for smaller indexes
3457                 pResult->sizeOffset = (WORD)pContextMT->GetNumGenericArgs() * sizeof(DictionaryEntry);
3458             }
3459
3460             // Indirect through dictionary table pointer in vtable
3461             pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3462
3463             // Next indirect through the dictionary appropriate to this instantiated type
3464             pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3465         }
3466     }
3467 }
3468
3469 void CEEInfo::AddTransientMethodDetails(TransientMethodDetails details)
3470 {
3471     STANDARD_VM_CONTRACT;
3472     _ASSERTE(details.Method != NULL);
3473
3474     if (m_transientDetails == NULL)
3475         m_transientDetails = new SArray<TransientMethodDetails, FALSE>();
3476     m_transientDetails->Append(std::move(details));
3477 }
3478
3479 TransientMethodDetails CEEInfo::RemoveTransientMethodDetails(MethodDesc* pMD)
3480 {
3481     STANDARD_VM_CONTRACT;
3482     _ASSERTE(pMD != NULL);
3483
3484     TransientMethodDetails local{};
3485     TransientMethodDetails* details;
3486     if (FindTransientMethodDetails(pMD, &details))
3487     {
3488         // Details found, move contents to return
3489         // and default initialize the found instance.
3490         local = std::move(*details);
3491         *details = {};
3492     }
3493     return local;
3494 }
3495
3496 bool CEEInfo::FindTransientMethodDetails(MethodDesc* pMD, TransientMethodDetails** details)
3497 {
3498     STANDARD_VM_CONTRACT;
3499     _ASSERTE(pMD != NULL);
3500     _ASSERTE(details != NULL);
3501
3502     if (m_transientDetails != NULL)
3503     {
3504         TransientMethodDetails* curr = m_transientDetails->GetElements();
3505         TransientMethodDetails* end = curr + m_transientDetails->GetCount();
3506         for (;curr != end; ++curr)
3507         {
3508             if (curr->Method == pMD)
3509             {
3510                 *details = curr;
3511                 return true;
3512             }
3513         }
3514     }
3515     return false;
3516 }
3517
3518 /*********************************************************************/
3519 size_t CEEInfo::printClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize)
3520 {
3521     CONTRACTL {
3522         MODE_PREEMPTIVE;
3523         THROWS;
3524         GC_TRIGGERS;
3525     } CONTRACTL_END;
3526
3527     size_t bytesWritten = 0;
3528
3529     JIT_TO_EE_TRANSITION();
3530
3531     size_t requiredBufferSize = 0;
3532
3533     TypeHandle th(cls);
3534     IMDInternalImport* pImport = th.GetMethodTable()->GetMDImport();
3535
3536     auto append = [buffer, bufferSize, &bytesWritten, &requiredBufferSize](const char* str)
3537     {
3538         size_t strLen = strlen(str);
3539
3540         if ((buffer != nullptr) && (bytesWritten + 1 < bufferSize))
3541         {
3542             if (bytesWritten + strLen >= bufferSize)
3543             {
3544                 memcpy(buffer + bytesWritten, str, bufferSize - bytesWritten - 1);
3545                 bytesWritten = bufferSize - 1;
3546             }
3547             else
3548             {
3549                 memcpy(buffer + bytesWritten, str, strLen);
3550                 bytesWritten += strLen;
3551             }
3552         }
3553
3554         requiredBufferSize += strLen;
3555     };
3556
3557     // Subset of TypeString that does just what we need while staying in UTF8
3558     // and avoiding expensive copies. This function is called a lot in checked
3559     // builds.
3560     // One difference is that we do not handle escaping type names here (see
3561     // IsTypeNameReservedChar). The situation is rare and somewhat complicated
3562     // to handle since it requires iterating UTF8 encoded codepoints. Given
3563     // that this function is only needed for diagnostics the complication seems
3564     // unnecessary.
3565     mdTypeDef td = th.GetCl();
3566     if (IsNilToken(td))
3567     {
3568         append("(dynamicClass)");
3569     }
3570     else
3571     {
3572         DWORD attr;
3573         IfFailThrow(pImport->GetTypeDefProps(td, &attr, NULL));
3574
3575         StackSArray<mdTypeDef> nestedHierarchy;
3576         nestedHierarchy.Append(td);
3577
3578         if (IsTdNested(attr))
3579         {
3580             while (SUCCEEDED(pImport->GetNestedClassProps(td, &td)))
3581                 nestedHierarchy.Append(td);
3582         }
3583
3584         for (SCOUNT_T i = nestedHierarchy.GetCount() - 1; i >= 0; i--)
3585         {
3586             LPCUTF8 name;
3587             LPCUTF8 nameSpace;
3588             IfFailThrow(pImport->GetNameOfTypeDef(nestedHierarchy[i], &name, &nameSpace));
3589
3590             if ((nameSpace != NULL) && (*nameSpace != '\0'))
3591             {
3592                 append(nameSpace);
3593                 append(".");
3594             }
3595
3596             append(name);
3597
3598             if (i != 0)
3599             {
3600                 append("+");
3601             }
3602         }
3603     }
3604
3605     if (bufferSize > 0)
3606     {
3607         _ASSERTE(bytesWritten < bufferSize);
3608         buffer[bytesWritten] = '\0';
3609     }
3610
3611     if (pRequiredBufferSize != nullptr)
3612     {
3613         *pRequiredBufferSize = requiredBufferSize + 1;
3614     }
3615
3616     EE_TO_JIT_TRANSITION();
3617
3618     return bytesWritten;
3619 }
3620
3621 /*********************************************************************/
3622 CORINFO_MODULE_HANDLE CEEInfo::getClassModule(CORINFO_CLASS_HANDLE clsHnd)
3623 {
3624     CONTRACTL {
3625         NOTHROW;
3626         GC_NOTRIGGER;
3627         MODE_PREEMPTIVE;
3628     } CONTRACTL_END;
3629
3630     CORINFO_MODULE_HANDLE result = NULL;
3631
3632     JIT_TO_EE_TRANSITION_LEAF();
3633
3634     TypeHandle     VMClsHnd(clsHnd);
3635
3636     result = CORINFO_MODULE_HANDLE(VMClsHnd.GetModule());
3637
3638     EE_TO_JIT_TRANSITION_LEAF();
3639
3640     return result;
3641 }
3642
3643 /*********************************************************************/
3644 CORINFO_ASSEMBLY_HANDLE CEEInfo::getModuleAssembly(CORINFO_MODULE_HANDLE modHnd)
3645 {
3646     CONTRACTL {
3647         NOTHROW;
3648         GC_NOTRIGGER;
3649         MODE_PREEMPTIVE;
3650     } CONTRACTL_END;
3651
3652     CORINFO_ASSEMBLY_HANDLE result = NULL;
3653
3654     JIT_TO_EE_TRANSITION_LEAF();
3655
3656     result = CORINFO_ASSEMBLY_HANDLE(GetModule(modHnd)->GetAssembly());
3657
3658     EE_TO_JIT_TRANSITION_LEAF();
3659
3660     return result;
3661 }
3662
3663 /*********************************************************************/
3664 const char* CEEInfo::getAssemblyName(CORINFO_ASSEMBLY_HANDLE asmHnd)
3665 {
3666     CONTRACTL {
3667         THROWS;
3668         GC_TRIGGERS;
3669         MODE_PREEMPTIVE;
3670     } CONTRACTL_END;
3671
3672     const char*  result = NULL;
3673
3674     JIT_TO_EE_TRANSITION();
3675     result = ((Assembly*)asmHnd)->GetSimpleName();
3676     EE_TO_JIT_TRANSITION();
3677
3678     return result;
3679 }
3680
3681 /*********************************************************************/
3682 void* CEEInfo::LongLifetimeMalloc(size_t sz)
3683 {
3684     CONTRACTL {
3685         NOTHROW;
3686         GC_NOTRIGGER;
3687         MODE_PREEMPTIVE;
3688     } CONTRACTL_END;
3689
3690     void*  result = NULL;
3691
3692     JIT_TO_EE_TRANSITION_LEAF();
3693     result = new (nothrow) char[sz];
3694     EE_TO_JIT_TRANSITION_LEAF();
3695
3696     return result;
3697 }
3698
3699 /*********************************************************************/
3700 void CEEInfo::LongLifetimeFree(void* obj)
3701 {
3702     CONTRACTL {
3703         NOTHROW;
3704         GC_NOTRIGGER;
3705         MODE_PREEMPTIVE;
3706     } CONTRACTL_END;
3707
3708     JIT_TO_EE_TRANSITION_LEAF();
3709     (operator delete)(obj);
3710     EE_TO_JIT_TRANSITION_LEAF();
3711 }
3712
3713 /*********************************************************************/
3714 size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_MODULE_HANDLE *pModuleHandle, void **ppIndirection)
3715 {
3716     CONTRACTL {
3717         NOTHROW;
3718         GC_NOTRIGGER;
3719         MODE_PREEMPTIVE;
3720     } CONTRACTL_END;
3721
3722     size_t result = 0;
3723
3724     JIT_TO_EE_TRANSITION_LEAF();
3725
3726     TypeHandle     VMClsHnd(clsHnd);
3727     Module *pModule = VMClsHnd.AsMethodTable()->GetModuleForStatics();
3728
3729     if (ppIndirection != NULL)
3730         *ppIndirection = NULL;
3731
3732     // The zapper needs the module handle. The jit should not use it at all.
3733     if (pModuleHandle)
3734         *pModuleHandle = CORINFO_MODULE_HANDLE(pModule);
3735
3736     result = pModule->GetModuleID();
3737
3738     _ASSERTE(result);
3739
3740     EE_TO_JIT_TRANSITION_LEAF();
3741
3742     return result;
3743 }
3744
3745 /*********************************************************************/
3746 bool CEEInfo::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset)
3747 {
3748     CONTRACTL {
3749         NOTHROW;
3750         GC_NOTRIGGER;
3751         MODE_PREEMPTIVE;
3752     } CONTRACTL_END;
3753
3754     _ASSERTE(addr);
3755
3756     JIT_TO_EE_TRANSITION_LEAF();
3757
3758     TypeHandle clsTypeHandle(cls);
3759     PTR_MethodTable pMT = clsTypeHandle.AsMethodTable();
3760
3761     // Impl is based on IsPrecomputedClassInitialized()
3762     UINT32 clsIndex = 0;
3763     if (pMT->IsDynamicStatics())
3764     {
3765         clsIndex = (UINT32)pMT->GetModuleDynamicEntryID();
3766     }
3767     else
3768     {
3769         clsIndex = (UINT32)pMT->GetClassIndex();
3770     }
3771
3772     size_t moduleId = pMT->GetModuleForStatics()->GetModuleID();
3773     addr->addr = (UINT8*)moduleId + DomainLocalModule::GetOffsetOfDataBlob() + clsIndex;
3774     addr->accessType = IAT_VALUE;
3775     *offset = 0;
3776
3777     EE_TO_JIT_TRANSITION_LEAF();
3778
3779     return true;
3780 }
3781
3782 /*********************************************************************/
3783 bool CEEInfo::getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr)
3784 {
3785     CONTRACTL {
3786         NOTHROW;
3787         GC_NOTRIGGER;
3788         MODE_PREEMPTIVE;
3789     } CONTRACTL_END;
3790
3791     JIT_TO_EE_TRANSITION_LEAF();
3792
3793     TypeHandle clsTypeHandle(cls);
3794     PTR_MethodTable pMT = clsTypeHandle.AsMethodTable();
3795
3796     GCX_COOP();
3797     addr->addr = isGc ? pMT->GetGCStaticsBasePointer() : pMT->GetNonGCStaticsBasePointer();
3798     addr->accessType = IAT_VALUE;
3799
3800     EE_TO_JIT_TRANSITION_LEAF();
3801
3802     return true;
3803 }
3804
3805 /*********************************************************************/
3806 bool CEEInfo::isValueClass(CORINFO_CLASS_HANDLE clsHnd)
3807 {
3808     CONTRACTL {
3809         NOTHROW;
3810         GC_NOTRIGGER;
3811         MODE_PREEMPTIVE;
3812     } CONTRACTL_END;
3813
3814     bool ret = false;
3815
3816     JIT_TO_EE_TRANSITION_LEAF();
3817
3818     _ASSERTE(clsHnd);
3819
3820     ret = TypeHandle(clsHnd).IsValueType();
3821
3822     EE_TO_JIT_TRANSITION_LEAF();
3823
3824     return ret;
3825 }
3826
3827 /*********************************************************************/
3828 // Decides how the JIT should do the optimization to inline the check for
3829 //     GetTypeFromHandle(handle) == obj.GetType()
3830 //     GetTypeFromHandle(X) == GetTypeFromHandle(Y)
3831 //
3832 // This will enable to use directly the typehandle instead of going through getClassByHandle
3833 CorInfoInlineTypeCheck CEEInfo::canInlineTypeCheck(CORINFO_CLASS_HANDLE clsHnd, CorInfoInlineTypeCheckSource source)
3834 {
3835     LIMITED_METHOD_CONTRACT;
3836     return CORINFO_INLINE_TYPECHECK_PASS;
3837 }
3838
3839 /*********************************************************************/
3840 uint32_t CEEInfo::getClassAttribs (CORINFO_CLASS_HANDLE clsHnd)
3841 {
3842     CONTRACTL {
3843         THROWS;
3844         GC_TRIGGERS;
3845         MODE_PREEMPTIVE;
3846     } CONTRACTL_END;
3847
3848     // <REVISIT_TODO>@todo FIX need to really fetch the class attributes.  at present
3849     // we don't need to because the JIT only cares in the case of COM classes</REVISIT_TODO>
3850     uint32_t ret = 0;
3851
3852     JIT_TO_EE_TRANSITION();
3853
3854     ret = getClassAttribsInternal(clsHnd);
3855
3856     EE_TO_JIT_TRANSITION();
3857
3858     return ret;
3859 }
3860
3861 /*********************************************************************/
3862 uint32_t CEEInfo::getClassAttribsInternal (CORINFO_CLASS_HANDLE clsHnd)
3863 {
3864     STANDARD_VM_CONTRACT;
3865
3866     DWORD ret = 0;
3867
3868     _ASSERTE(clsHnd);
3869
3870     TypeHandle     VMClsHnd(clsHnd);
3871
3872     // Byrefs should only occur in method and local signatures, which are accessed
3873     // using ICorClassInfo and ICorClassInfo.getChildType.
3874     // So getClassAttribs() should not be called for byrefs
3875
3876     if (VMClsHnd.IsByRef())
3877     {
3878         _ASSERTE(!"Did findClass() return a Byref?");
3879         COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3880     }
3881     else if (VMClsHnd.IsGenericVariable())
3882     {
3883         //@GENERICSVER: for now, type variables simply report "variable".
3884         ret |= CORINFO_FLG_GENERIC_TYPE_VARIABLE;
3885     }
3886     else
3887     {
3888         MethodTable *pMT = VMClsHnd.GetMethodTable();
3889
3890         if (!pMT)
3891         {
3892             _ASSERTE(!"Did findClass() return a Byref?");
3893             COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3894         }
3895
3896         EEClass * pClass = pMT->GetClass();
3897
3898         // The array flag is used to identify the faked-up methods on
3899         // array types, i.e. .ctor, Get, Set and Address
3900         if (pMT->IsArray())
3901             ret |= CORINFO_FLG_ARRAY;
3902
3903         if (pMT->IsInterface())
3904             ret |= CORINFO_FLG_INTERFACE;
3905
3906         if (pMT->HasComponentSize())
3907             ret |= CORINFO_FLG_VAROBJSIZE;
3908
3909         if (VMClsHnd.IsValueType())
3910         {
3911             ret |= CORINFO_FLG_VALUECLASS;
3912
3913             if (pMT->IsByRefLike())
3914                 ret |= CORINFO_FLG_BYREF_LIKE;
3915
3916             if (pClass->IsUnsafeValueClass())
3917                 ret |= CORINFO_FLG_UNSAFE_VALUECLASS;
3918         }
3919         if (pClass->HasExplicitFieldOffsetLayout() && pClass->HasOverlaidField())
3920             ret |= CORINFO_FLG_OVERLAPPING_FIELDS;
3921
3922         if (pClass->IsInlineArray())
3923             ret |= CORINFO_FLG_INDEXABLE_FIELDS;
3924
3925         if (VMClsHnd.IsCanonicalSubtype())
3926             ret |= CORINFO_FLG_SHAREDINST;
3927
3928         if (pMT->HasVariance())
3929             ret |= CORINFO_FLG_VARIANCE;
3930
3931         if (pMT->ContainsPointers() || pMT == g_TypedReferenceMT)
3932             ret |= CORINFO_FLG_CONTAINS_GC_PTR;
3933
3934         if (pMT->IsDelegate())
3935             ret |= CORINFO_FLG_DELEGATE;
3936
3937         if (pClass->IsBeforeFieldInit())
3938             ret |= CORINFO_FLG_BEFOREFIELDINIT;
3939
3940         if (pClass->IsAbstract())
3941             ret |= CORINFO_FLG_ABSTRACT;
3942
3943         if (pClass->IsSealed())
3944             ret |= CORINFO_FLG_FINAL;
3945
3946         if (pMT->IsIntrinsicType())
3947             ret |= CORINFO_FLG_INTRINSIC_TYPE;
3948     }
3949
3950     return ret;
3951 }
3952
3953 /*********************************************************************/
3954 //
3955 // See code:CorInfoFlag#ClassConstructionFlags  for details.
3956 //
3957 CorInfoInitClassResult CEEInfo::initClass(
3958             CORINFO_FIELD_HANDLE    field,
3959             CORINFO_METHOD_HANDLE   method,
3960             CORINFO_CONTEXT_HANDLE  context)
3961 {
3962     CONTRACTL {
3963         THROWS;
3964         GC_TRIGGERS;
3965         MODE_PREEMPTIVE;
3966     } CONTRACTL_END;
3967
3968     DWORD result = CORINFO_INITCLASS_NOT_REQUIRED;
3969
3970     JIT_TO_EE_TRANSITION();
3971     {
3972
3973     FieldDesc * pFD = (FieldDesc *)field;
3974     _ASSERTE(pFD == NULL || pFD->IsStatic());
3975
3976     MethodDesc* pMD = (method != NULL) ? (MethodDesc*)method : m_pMethodBeingCompiled;
3977
3978     TypeHandle typeToInitTH = (pFD != NULL) ? pFD->GetEnclosingMethodTable() : GetTypeFromContext(context);
3979
3980     MethodDesc *methodBeingCompiled = m_pMethodBeingCompiled;
3981
3982     MethodTable *pTypeToInitMT = typeToInitTH.AsMethodTable();
3983
3984     if (pTypeToInitMT->IsClassInited())
3985     {
3986         // If the type is initialized there really is nothing to do.
3987         result = CORINFO_INITCLASS_INITIALIZED;
3988         goto exit;
3989     }
3990
3991     if (pTypeToInitMT->IsGlobalClass())
3992     {
3993         // For both jitted and ngen code the global class is always considered initialized
3994         result = CORINFO_INITCLASS_NOT_REQUIRED;
3995         goto exit;
3996     }
3997
3998     if (pFD == NULL)
3999     {
4000         if (pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4001         {
4002             // We can wait for field accesses to run .cctor
4003             result = CORINFO_INITCLASS_NOT_REQUIRED;
4004             goto exit;
4005         }
4006
4007         // Run .cctor on statics & constructors
4008         if (pMD->IsStatic())
4009         {
4010             // Except don't class construct on .cctor - it would be circular
4011             if (pMD->IsClassConstructor())
4012             {
4013                 result = CORINFO_INITCLASS_NOT_REQUIRED;
4014                 goto exit;
4015             }
4016         }
4017         else
4018         // According to the spec, we should be able to do this optimization for both reference and valuetypes.
4019         // To maintain backward compatibility, we are doing it for reference types only.
4020         // We don't do this for interfaces though, as those don't have instance constructors.
4021         if (!pMD->IsCtor() && !pTypeToInitMT->IsValueType() && !pTypeToInitMT->IsInterface())
4022         {
4023             // For instance methods of types with precise-initialization
4024             // semantics, we can assume that the .ctor triggered the
4025             // type initialization.
4026             // This does not hold for NULL "this" object. However, the spec does
4027             // not require that case to work.
4028             result = CORINFO_INITCLASS_NOT_REQUIRED;
4029             goto exit;
4030         }
4031     }
4032
4033     if (pTypeToInitMT->IsSharedByGenericInstantiations())
4034     {
4035         if ((pFD == NULL) && (method != NULL) && (context == METHOD_BEING_COMPILED_CONTEXT()))
4036         {
4037             _ASSERTE(pTypeToInitMT == methodBeingCompiled->GetMethodTable());
4038             // If we're inling a call to a method in our own type, then we should already
4039             // have triggered the .cctor when caller was itself called.
4040             result = CORINFO_INITCLASS_NOT_REQUIRED;
4041             goto exit;
4042         }
4043
4044         // Shared generic code has to use helper. Moreover, tell JIT not to inline since
4045         // inlining of generic dictionary lookups is not supported.
4046         result = CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE;
4047         goto exit;
4048     }
4049
4050     //
4051     // Try to prove that the initialization is not necessary because of nesting
4052     //
4053
4054     if (pFD == NULL)
4055     {
4056         // Handled above
4057         _ASSERTE(!pTypeToInitMT->GetClass()->IsBeforeFieldInit());
4058
4059         if (method != NULL && pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4060         {
4061             // If we're inling a call to a method in our own type, then we should already
4062             // have triggered the .cctor when caller was itself called.
4063             result = CORINFO_INITCLASS_NOT_REQUIRED;
4064             goto exit;
4065         }
4066     }
4067     else
4068     {
4069         // This optimization may cause static fields in reference types to be accessed without cctor being triggered
4070         // for NULL "this" object. It does not conform with what the spec says. However, we have been historically
4071         // doing it for perf reasons.
4072         if (!pTypeToInitMT->IsValueType() && !pTypeToInitMT->IsInterface() && !pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4073         {
4074             if (pTypeToInitMT == GetTypeFromContext(context).AsMethodTable() || pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4075             {
4076                 // The class will be initialized by the time we access the field.
4077                 result = CORINFO_INITCLASS_NOT_REQUIRED;
4078                 goto exit;
4079             }
4080         }
4081
4082         // If we are currently compiling the class constructor for this static field access then we can skip the initClass
4083         if (methodBeingCompiled->GetMethodTable() == pTypeToInitMT && methodBeingCompiled->IsStatic() && methodBeingCompiled->IsClassConstructor())
4084         {
4085             // The class will be initialized by the time we access the field.
4086             result = CORINFO_INITCLASS_NOT_REQUIRED;
4087             goto exit;
4088         }
4089     }
4090
4091     //
4092     // Optimizations for domain specific code
4093     //
4094
4095     // Allocate space for the local class if necessary, but don't trigger
4096     // class construction.
4097     DomainLocalModule *pModule = pTypeToInitMT->GetDomainLocalModule();
4098     pModule->PopulateClass(pTypeToInitMT);
4099
4100     if (pTypeToInitMT->IsClassInited())
4101     {
4102         result = CORINFO_INITCLASS_INITIALIZED;
4103         goto exit;
4104     }
4105
4106     result = CORINFO_INITCLASS_USE_HELPER;
4107     }
4108 exit: ;
4109     EE_TO_JIT_TRANSITION();
4110
4111     return (CorInfoInitClassResult)result;
4112 }
4113
4114
4115
4116 void CEEInfo::classMustBeLoadedBeforeCodeIsRun (CORINFO_CLASS_HANDLE typeToLoadHnd)
4117 {
4118     CONTRACTL {
4119         NOTHROW;
4120         GC_NOTRIGGER;
4121         MODE_PREEMPTIVE;
4122     } CONTRACTL_END;
4123
4124     JIT_TO_EE_TRANSITION_LEAF();
4125
4126     TypeHandle th = TypeHandle(typeToLoadHnd);
4127
4128     // Type handles returned to JIT at runtime are always fully loaded. Verify that it is the case.
4129     _ASSERTE(th.IsFullyLoaded());
4130
4131     EE_TO_JIT_TRANSITION_LEAF();
4132 }
4133
4134 /*********************************************************************/
4135 void CEEInfo::methodMustBeLoadedBeforeCodeIsRun (CORINFO_METHOD_HANDLE methHnd)
4136 {
4137     CONTRACTL {
4138         NOTHROW;
4139         GC_NOTRIGGER;
4140         MODE_PREEMPTIVE;
4141     } CONTRACTL_END;
4142
4143     JIT_TO_EE_TRANSITION_LEAF();
4144
4145     MethodDesc *pMD = (MethodDesc*) methHnd;
4146
4147     // MethodDescs returned to JIT at runtime are always fully loaded. Verify that it is the case.
4148     _ASSERTE(pMD->GetMethodTable()->IsFullyLoaded());
4149
4150     EE_TO_JIT_TRANSITION_LEAF();
4151 }
4152
4153 /*********************************************************************/
4154 CORINFO_METHOD_HANDLE CEEInfo::mapMethodDeclToMethodImpl(CORINFO_METHOD_HANDLE methHnd)
4155 {
4156     CONTRACTL {
4157         THROWS;
4158         GC_TRIGGERS;
4159         MODE_PREEMPTIVE;
4160     } CONTRACTL_END;
4161
4162     CORINFO_METHOD_HANDLE result = NULL;
4163
4164     JIT_TO_EE_TRANSITION();
4165
4166     MethodDesc *pMD = GetMethod(methHnd);
4167     pMD = MethodTable::MapMethodDeclToMethodImpl(pMD);
4168     result = (CORINFO_METHOD_HANDLE) pMD;
4169
4170     EE_TO_JIT_TRANSITION();
4171
4172     return result;
4173 }
4174
4175 /*********************************************************************/
4176 CORINFO_CLASS_HANDLE CEEInfo::getBuiltinClass(CorInfoClassId classId)
4177 {
4178     CONTRACTL {
4179         THROWS;
4180         GC_TRIGGERS;
4181         MODE_PREEMPTIVE;
4182     } CONTRACTL_END;
4183
4184     CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE) 0;
4185
4186     JIT_TO_EE_TRANSITION();
4187
4188     switch (classId)
4189     {
4190     case CLASSID_SYSTEM_OBJECT:
4191         result = CORINFO_CLASS_HANDLE(g_pObjectClass);
4192         break;
4193     case CLASSID_TYPED_BYREF:
4194         result = CORINFO_CLASS_HANDLE(g_TypedReferenceMT);
4195         break;
4196     case CLASSID_TYPE_HANDLE:
4197         result = CORINFO_CLASS_HANDLE(CoreLibBinder::GetClass(CLASS__TYPE_HANDLE));
4198         break;
4199     case CLASSID_FIELD_HANDLE:
4200         result = CORINFO_CLASS_HANDLE(CoreLibBinder::GetClass(CLASS__FIELD_HANDLE));
4201         break;
4202     case CLASSID_METHOD_HANDLE:
4203         result = CORINFO_CLASS_HANDLE(CoreLibBinder::GetClass(CLASS__METHOD_HANDLE));
4204         break;
4205     case CLASSID_ARGUMENT_HANDLE:
4206         result = CORINFO_CLASS_HANDLE(CoreLibBinder::GetClass(CLASS__ARGUMENT_HANDLE));
4207         break;
4208     case CLASSID_STRING:
4209         result = CORINFO_CLASS_HANDLE(g_pStringClass);
4210         break;
4211     case CLASSID_RUNTIME_TYPE:
4212         result = CORINFO_CLASS_HANDLE(g_pRuntimeTypeClass);
4213         break;
4214     default:
4215         _ASSERTE(!"NYI: unknown classId");
4216         break;
4217     }
4218
4219     EE_TO_JIT_TRANSITION();
4220
4221     return result;
4222 }
4223
4224
4225
4226 /*********************************************************************/
4227 CorInfoType CEEInfo::getTypeForPrimitiveValueClass(
4228         CORINFO_CLASS_HANDLE clsHnd)
4229 {
4230     CONTRACTL {
4231         THROWS;
4232         GC_TRIGGERS;
4233         MODE_PREEMPTIVE;
4234     } CONTRACTL_END;
4235
4236     CorInfoType result = CORINFO_TYPE_UNDEF;
4237
4238     JIT_TO_EE_TRANSITION();
4239
4240     TypeHandle th(clsHnd);
4241     _ASSERTE (!th.IsGenericVariable());
4242
4243     CorElementType elementType = th.GetVerifierCorElementType();
4244     if (CorIsPrimitiveType(elementType))
4245     {
4246         result = asCorInfoType(elementType);
4247     }
4248     EE_TO_JIT_TRANSITION();
4249
4250     return result;
4251 }
4252
4253 /*********************************************************************/
4254 CorInfoType CEEInfo::getTypeForPrimitiveNumericClass(
4255         CORINFO_CLASS_HANDLE clsHnd)
4256 {
4257     CONTRACTL{
4258         NOTHROW;
4259         GC_NOTRIGGER;
4260         MODE_PREEMPTIVE;
4261     } CONTRACTL_END;
4262
4263     CorInfoType result = CORINFO_TYPE_UNDEF;
4264
4265     JIT_TO_EE_TRANSITION_LEAF();
4266
4267     TypeHandle th(clsHnd);
4268     _ASSERTE (!th.IsGenericVariable());
4269
4270     CorElementType ty = th.GetSignatureCorElementType();
4271     switch (ty)
4272     {
4273     case ELEMENT_TYPE_I1:
4274         result = CORINFO_TYPE_BYTE;
4275         break;
4276     case ELEMENT_TYPE_U1:
4277         result = CORINFO_TYPE_UBYTE;
4278         break;
4279     case ELEMENT_TYPE_I2:
4280         result = CORINFO_TYPE_SHORT;
4281         break;
4282     case ELEMENT_TYPE_U2:
4283         result = CORINFO_TYPE_USHORT;
4284         break;
4285     case ELEMENT_TYPE_I4:
4286         result = CORINFO_TYPE_INT;
4287         break;
4288     case ELEMENT_TYPE_U4:
4289         result = CORINFO_TYPE_UINT;
4290         break;
4291     case ELEMENT_TYPE_I8:
4292         result = CORINFO_TYPE_LONG;
4293         break;
4294     case ELEMENT_TYPE_U8:
4295         result = CORINFO_TYPE_ULONG;
4296         break;
4297     case ELEMENT_TYPE_R4:
4298         result = CORINFO_TYPE_FLOAT;
4299         break;
4300     case ELEMENT_TYPE_R8:
4301         result = CORINFO_TYPE_DOUBLE;
4302         break;
4303     case ELEMENT_TYPE_I:
4304         result = CORINFO_TYPE_NATIVEINT;
4305         break;
4306     case ELEMENT_TYPE_U:
4307         result = CORINFO_TYPE_NATIVEUINT;
4308         break;
4309
4310     default:
4311         // Error case, we will return CORINFO_TYPE_UNDEF
4312         break;
4313     }
4314
4315     JIT_TO_EE_TRANSITION_LEAF();
4316
4317     return result;
4318 }
4319
4320
4321 void CEEInfo::getGSCookie(GSCookie * pCookieVal, GSCookie ** ppCookieVal)
4322 {
4323     CONTRACTL {
4324         THROWS;
4325         GC_TRIGGERS;
4326         MODE_PREEMPTIVE;
4327     } CONTRACTL_END;
4328
4329     JIT_TO_EE_TRANSITION();
4330
4331     if (pCookieVal)
4332     {
4333         *pCookieVal = GetProcessGSCookie();
4334         *ppCookieVal = NULL;
4335     }
4336     else
4337     {
4338         *ppCookieVal = GetProcessGSCookiePtr();
4339     }
4340
4341     EE_TO_JIT_TRANSITION();
4342 }
4343
4344
4345 /*********************************************************************/
4346 // TRUE if child is a subtype of parent
4347 // if parent is an interface, then does child implement / extend parent
4348 bool CEEInfo::canCast(
4349         CORINFO_CLASS_HANDLE        child,
4350         CORINFO_CLASS_HANDLE        parent)
4351 {
4352     CONTRACTL {
4353         THROWS;
4354         GC_TRIGGERS;
4355         MODE_PREEMPTIVE;
4356     } CONTRACTL_END;
4357
4358     bool result = false;
4359
4360     JIT_TO_EE_TRANSITION();
4361
4362     result = !!((TypeHandle)child).CanCastTo((TypeHandle)parent);
4363
4364     EE_TO_JIT_TRANSITION();
4365
4366     return result;
4367 }
4368
4369 /*********************************************************************/
4370 // See if a cast from fromClass to toClass will succeed, fail, or needs
4371 // to be resolved at runtime.
4372 TypeCompareState CEEInfo::compareTypesForCast(
4373         CORINFO_CLASS_HANDLE        fromClass,
4374         CORINFO_CLASS_HANDLE        toClass)
4375 {
4376     CONTRACTL {
4377         THROWS;
4378         GC_TRIGGERS;
4379         MODE_PREEMPTIVE;
4380     } CONTRACTL_END;
4381
4382     TypeCompareState result = TypeCompareState::May;
4383
4384     JIT_TO_EE_TRANSITION();
4385
4386     TypeHandle fromHnd = (TypeHandle) fromClass;
4387     TypeHandle toHnd = (TypeHandle) toClass;
4388
4389 #ifdef FEATURE_COMINTEROP
4390     // If casting from a com object class, don't try to optimize.
4391     if (fromHnd.IsComObjectType())
4392     {
4393         result = TypeCompareState::May;
4394     }
4395     else
4396 #endif // FEATURE_COMINTEROP
4397
4398     // If casting from ICastable or IDynamicInterfaceCastable, don't try to optimize
4399     if (fromHnd.GetMethodTable()->IsICastable() || fromHnd.GetMethodTable()->IsIDynamicInterfaceCastable())
4400     {
4401         result = TypeCompareState::May;
4402     }
4403     // If casting to Nullable<T>, don't try to optimize
4404     else if (Nullable::IsNullableType(toHnd))
4405     {
4406         result = TypeCompareState::May;
4407     }
4408     // If the types are not shared, we can check directly.
4409     else if (!fromHnd.IsCanonicalSubtype() && !toHnd.IsCanonicalSubtype())
4410     {
4411         result = fromHnd.CanCastTo(toHnd) ? TypeCompareState::Must : TypeCompareState::MustNot;
4412     }
4413     // Casting from a shared type to an unshared type.
4414     else if (fromHnd.IsCanonicalSubtype() && !toHnd.IsCanonicalSubtype())
4415     {
4416         // Only handle casts to interface types for now
4417         if (toHnd.IsInterface())
4418         {
4419             // Do a preliminary check.
4420             BOOL canCast = fromHnd.CanCastTo(toHnd);
4421
4422             // Pass back positive results unfiltered. The unknown type
4423             // parameters in fromClass did not come into play.
4424             if (canCast)
4425             {
4426                 result = TypeCompareState::Must;
4427             }
4428             // We have __Canon parameter(s) in fromClass, somewhere.
4429             //
4430             // In CanCastTo, these __Canon(s) won't match the interface or
4431             // instantiated types on the interface, so CanCastTo may
4432             // return false negatives.
4433             //
4434             // Only report MustNot if the fromClass is not __Canon
4435             // and the interface is not instantiated; then there is
4436             // no way for the fromClass __Canon(s) to confuse things.
4437             //
4438             //    __Canon       -> IBar             May
4439             //    IFoo<__Canon> -> IFoo<string>     May
4440             //    IFoo<__Canon> -> IBar             MustNot
4441             //
4442             else if (fromHnd == TypeHandle(g_pCanonMethodTableClass))
4443             {
4444                 result = TypeCompareState::May;
4445             }
4446             else if (toHnd.HasInstantiation())
4447             {
4448                 result = TypeCompareState::May;
4449             }
4450             else
4451             {
4452                 result = TypeCompareState::MustNot;
4453             }
4454         }
4455     }
4456
4457     EE_TO_JIT_TRANSITION();
4458
4459     return result;
4460 }
4461
4462 /*********************************************************************/
4463 // See if types represented by cls1 and cls2 compare equal, not
4464 // equal, or the comparison needs to be resolved at runtime.
4465 TypeCompareState CEEInfo::compareTypesForEquality(
4466         CORINFO_CLASS_HANDLE        cls1,
4467         CORINFO_CLASS_HANDLE        cls2)
4468 {
4469     CONTRACTL {
4470         THROWS;
4471         GC_TRIGGERS;
4472         MODE_PREEMPTIVE;
4473     } CONTRACTL_END;
4474
4475     TypeCompareState result = TypeCompareState::May;
4476
4477     JIT_TO_EE_TRANSITION();
4478
4479     TypeHandle hnd1 = (TypeHandle) cls1;
4480     TypeHandle hnd2 = (TypeHandle) cls2;
4481
4482     // If neither type is a canonical subtype, type handle comparison suffices
4483     if (!hnd1.IsCanonicalSubtype() && !hnd2.IsCanonicalSubtype())
4484     {
4485         result = (hnd1 == hnd2 ? TypeCompareState::Must : TypeCompareState::MustNot);
4486     }
4487     // If either or both types are canonical subtypes, we can sometimes prove inequality.
4488     else
4489     {
4490         // If either is a value type then the types cannot
4491         // be equal unless the type defs are the same.
4492         if (hnd1.IsValueType() || hnd2.IsValueType())
4493         {
4494             if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
4495             {
4496                 result = TypeCompareState::MustNot;
4497             }
4498         }
4499         // If we have two ref types that are not __Canon, then the
4500         // types cannot be equal unless the type defs are the same.
4501         else
4502         {
4503             TypeHandle canonHnd = TypeHandle(g_pCanonMethodTableClass);
4504             if ((hnd1 != canonHnd) && (hnd2 != canonHnd))
4505             {
4506                 if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
4507                 {
4508                     result = TypeCompareState::MustNot;
4509                 }
4510             }
4511         }
4512     }
4513
4514     EE_TO_JIT_TRANSITION();
4515
4516     return result;
4517 }
4518
4519
4520 /*********************************************************************/
4521 static BOOL isMoreSpecificTypeHelper(
4522        CORINFO_CLASS_HANDLE        cls1,
4523        CORINFO_CLASS_HANDLE        cls2)
4524 {
4525     CONTRACTL {
4526         THROWS;
4527         GC_TRIGGERS;
4528         MODE_PREEMPTIVE;
4529     } CONTRACTL_END;
4530
4531     TypeHandle hnd1 = TypeHandle(cls1);
4532     TypeHandle hnd2 = TypeHandle(cls2);
4533
4534     // We can't really reason about equivalent types. Just
4535     // assume the new type is not more specific.
4536     if (hnd1.HasTypeEquivalence() || hnd2.HasTypeEquivalence())
4537     {
4538         return FALSE;
4539     }
4540
4541     // If we have a mixture of shared and unshared types,
4542     // consider the unshared type as more specific.
4543     BOOL isHnd1CanonSubtype = hnd1.IsCanonicalSubtype();
4544     BOOL isHnd2CanonSubtype = hnd2.IsCanonicalSubtype();
4545     if (isHnd1CanonSubtype != isHnd2CanonSubtype)
4546     {
4547         // Only one of hnd1 and hnd2 is shared.
4548         // hdn2 is more specific if hnd1 is the shared type.
4549         return isHnd1CanonSubtype;
4550     }
4551
4552     // Otherwise both types are either shared or not shared.
4553     // Look for a common parent type.
4554     TypeHandle merged = TypeHandle::MergeTypeHandlesToCommonParent(hnd1, hnd2);
4555
4556     // If the common parent is hnd1, then hnd2 is more specific.
4557     return merged == hnd1;
4558 }
4559
4560 // Returns true if cls2 is known to be a more specific type
4561 // than cls1 (a subtype or more restrictive shared type).
4562 bool CEEInfo::isMoreSpecificType(
4563         CORINFO_CLASS_HANDLE        cls1,
4564         CORINFO_CLASS_HANDLE        cls2)
4565 {
4566     CONTRACTL {
4567         THROWS;
4568         GC_TRIGGERS;
4569         MODE_PREEMPTIVE;
4570     } CONTRACTL_END;
4571
4572     bool result = false;
4573
4574     JIT_TO_EE_TRANSITION();
4575
4576     result = isMoreSpecificTypeHelper(cls1, cls2);
4577
4578     EE_TO_JIT_TRANSITION();
4579     return result;
4580 }
4581
4582 /*********************************************************************/
4583 // Returns TypeCompareState::Must if cls is known to be an enum.
4584 // For enums with known exact type returns the underlying
4585 // type in underlyingType when the provided pointer is
4586 // non-NULL.
4587 // Returns TypeCompareState::May when a runtime check is required.
4588 TypeCompareState CEEInfo::isEnum(
4589         CORINFO_CLASS_HANDLE        cls,
4590         CORINFO_CLASS_HANDLE*       underlyingType)
4591 {
4592     CONTRACTL {
4593         THROWS;
4594         GC_TRIGGERS;
4595         MODE_PREEMPTIVE;
4596     } CONTRACTL_END;
4597
4598     TypeCompareState result = TypeCompareState::May;
4599
4600     if (underlyingType != nullptr)
4601     {
4602         *underlyingType = nullptr;
4603     }
4604
4605     JIT_TO_EE_TRANSITION_LEAF();
4606
4607     TypeHandle th(cls);
4608
4609     _ASSERTE(!th.IsNull());
4610
4611     if (!th.IsGenericVariable())
4612     {
4613         if (!th.IsTypeDesc() && th.AsMethodTable()->IsEnum())
4614         {
4615             result = TypeCompareState::Must;
4616             if (underlyingType != nullptr)
4617             {
4618                 CorElementType elemType = th.AsMethodTable()->GetInternalCorElementType();
4619                 TypeHandle underlyingHandle(CoreLibBinder::GetElementType(elemType));
4620                 *underlyingType = CORINFO_CLASS_HANDLE(underlyingHandle.AsPtr());
4621             }
4622         }
4623         else
4624         {
4625             result = TypeCompareState::MustNot;
4626         }
4627     }
4628
4629     EE_TO_JIT_TRANSITION_LEAF();
4630     return result;
4631 }
4632
4633 /*********************************************************************/
4634 // Given a class handle, returns the Parent type.
4635 // For COMObjectType, it returns Class Handle of System.Object.
4636 // Returns 0 if System.Object is passed in.
4637 CORINFO_CLASS_HANDLE CEEInfo::getParentType(
4638             CORINFO_CLASS_HANDLE    cls)
4639 {
4640     CONTRACTL {
4641         THROWS;
4642         GC_TRIGGERS;
4643         MODE_PREEMPTIVE;
4644     } CONTRACTL_END;
4645
4646     CORINFO_CLASS_HANDLE result = NULL;
4647
4648     JIT_TO_EE_TRANSITION();
4649
4650     TypeHandle th(cls);
4651
4652     _ASSERTE(!th.IsNull());
4653     _ASSERTE(!th.IsGenericVariable());
4654
4655     TypeHandle thParent = th.GetParent();
4656
4657 #ifdef FEATURE_COMINTEROP
4658     // If we encounter __ComObject in the hierarchy, we need to skip it
4659     // since this hierarchy is introduced by the EE, but won't be present
4660     // in the metadata.
4661     if (!thParent.IsNull() && IsComObjectClass(thParent))
4662     {
4663         result = (CORINFO_CLASS_HANDLE) g_pObjectClass;
4664     }
4665     else
4666 #endif // FEATURE_COMINTEROP
4667     {
4668         result = CORINFO_CLASS_HANDLE(thParent.AsPtr());
4669     }
4670
4671     EE_TO_JIT_TRANSITION();
4672
4673     return result;
4674 }
4675
4676
4677 /*********************************************************************/
4678 // Returns the CorInfoType of the "child type". If the child type is
4679 // not a primitive type, *clsRet will be set.
4680 // Given an Array of Type Foo, returns Foo.
4681 // Given BYREF Foo, returns Foo
4682 CorInfoType CEEInfo::getChildType (
4683         CORINFO_CLASS_HANDLE       clsHnd,
4684         CORINFO_CLASS_HANDLE       *clsRet
4685         )
4686 {
4687     CONTRACTL {
4688         THROWS;
4689         GC_TRIGGERS;
4690         MODE_PREEMPTIVE;
4691     } CONTRACTL_END;
4692
4693     CorInfoType ret = CORINFO_TYPE_UNDEF;
4694     *clsRet = 0;
4695     TypeHandle  retType = TypeHandle();
4696
4697     JIT_TO_EE_TRANSITION();
4698
4699     TypeHandle th(clsHnd);
4700
4701     _ASSERTE(!th.IsNull());
4702
4703     // BYREF, pointer types
4704     if (th.HasTypeParam())
4705     {
4706         retType = th.GetTypeParam();
4707     }
4708
4709     if (!retType.IsNull()) {
4710         CorElementType type = retType.GetInternalCorElementType();
4711         ret = CEEInfo::asCorInfoType(type,retType, clsRet);
4712
4713         // <REVISIT_TODO>What if this one is a value array ?</REVISIT_TODO>
4714     }
4715
4716     EE_TO_JIT_TRANSITION();
4717
4718     return ret;
4719 }
4720
4721 /*********************************************************************/
4722 // Check if this is a single dimensional, zero based array type
4723 bool CEEInfo::isSDArray(CORINFO_CLASS_HANDLE  cls)
4724 {
4725     CONTRACTL {
4726         THROWS;
4727         GC_TRIGGERS;
4728         MODE_PREEMPTIVE;
4729     } CONTRACTL_END;
4730
4731     bool result = false;
4732
4733     JIT_TO_EE_TRANSITION();
4734
4735     TypeHandle th(cls);
4736
4737     _ASSERTE(!th.IsNull());
4738
4739     if (th.IsArray())
4740     {
4741         // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4742         _ASSERTE(th != TypeHandle(g_pArrayClass));
4743
4744         result = (th.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
4745     }
4746
4747     EE_TO_JIT_TRANSITION();
4748
4749     return result;
4750 }
4751
4752 /*********************************************************************/
4753 // Get the number of dimensions in an array
4754 unsigned CEEInfo::getArrayRank(CORINFO_CLASS_HANDLE  cls)
4755 {
4756     CONTRACTL {
4757         THROWS;
4758         GC_TRIGGERS;
4759         MODE_PREEMPTIVE;
4760     } CONTRACTL_END;
4761
4762     unsigned result = 0;
4763
4764     JIT_TO_EE_TRANSITION();
4765
4766     TypeHandle th(cls);
4767
4768     _ASSERTE(!th.IsNull());
4769
4770     if (th.IsArray())
4771     {
4772         // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4773         _ASSERTE(th != TypeHandle(g_pArrayClass));
4774
4775         result = th.GetRank();
4776     }
4777
4778     EE_TO_JIT_TRANSITION();
4779
4780     return result;
4781 }
4782
4783 /*********************************************************************/
4784 // Get the index of runtime provided array method
4785 CorInfoArrayIntrinsic CEEInfo::getArrayIntrinsicID(CORINFO_METHOD_HANDLE ftn)
4786 {
4787     CONTRACTL {
4788         THROWS;
4789         GC_TRIGGERS;
4790         MODE_PREEMPTIVE;
4791     } CONTRACTL_END;
4792
4793     CorInfoArrayIntrinsic result = CorInfoArrayIntrinsic::ILLEGAL;
4794
4795     JIT_TO_EE_TRANSITION();
4796
4797     MethodDesc* pMD = GetMethod(ftn);
4798
4799     if (pMD->IsArray())
4800     {
4801         DWORD index = ((ArrayMethodDesc*)pMD)->GetArrayFuncIndex();
4802         switch (index)
4803         {
4804             case 0: // ARRAY_FUNC_GET
4805                 result = CorInfoArrayIntrinsic::GET;
4806                 break;
4807             case 1: // ARRAY_FUNC_SET
4808                 result = CorInfoArrayIntrinsic::SET;
4809                 break;
4810             case 2: // ARRAY_FUNC_ADDRESS
4811                 result = CorInfoArrayIntrinsic::ADDRESS;
4812                 break;
4813         }
4814     }
4815
4816     EE_TO_JIT_TRANSITION();
4817
4818     return result;
4819 }
4820
4821 /*********************************************************************/
4822 // Get static field data for an array
4823 // Note that it's OK to return NULL from this method.  This will cause
4824 // the JIT to make a runtime call to InitializeArray instead of doing
4825 // the inline optimization (thus preserving the original behavior).
4826 void * CEEInfo::getArrayInitializationData(
4827             CORINFO_FIELD_HANDLE        field,
4828             uint32_t                    size
4829             )
4830 {
4831     CONTRACTL {
4832         THROWS;
4833         GC_TRIGGERS;
4834         MODE_PREEMPTIVE;
4835     } CONTRACTL_END;
4836
4837     void * result = NULL;
4838
4839     JIT_TO_EE_TRANSITION();
4840
4841     FieldDesc* pField = (FieldDesc*) field;
4842
4843     if (!pField                    ||
4844         !pField->IsRVA()           ||
4845         (pField->LoadSize() < size))
4846     {
4847         result = NULL;
4848     }
4849     else
4850     {
4851         result = pField->GetStaticAddressHandle(NULL);
4852     }
4853
4854     EE_TO_JIT_TRANSITION();
4855
4856     return result;
4857 }
4858
4859 CorInfoIsAccessAllowedResult CEEInfo::canAccessClass(
4860             CORINFO_RESOLVED_TOKEN * pResolvedToken,
4861             CORINFO_METHOD_HANDLE   callerHandle,
4862             CORINFO_HELPER_DESC    *pAccessHelper
4863             )
4864 {
4865     CONTRACTL {
4866         THROWS;
4867         GC_TRIGGERS;
4868         MODE_PREEMPTIVE;
4869     } CONTRACTL_END;
4870
4871     CorInfoIsAccessAllowedResult isAccessAllowed = CORINFO_ACCESS_ALLOWED;
4872
4873     JIT_TO_EE_TRANSITION();
4874
4875     INDEBUG(memset(pAccessHelper, 0xCC, sizeof(*pAccessHelper)));
4876
4877     BOOL doAccessCheck = TRUE;
4878     AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
4879     DynamicResolver * pAccessContext = NULL;
4880
4881     //All access checks must be done on the open instantiation.
4882     MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
4883     TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
4884
4885     TypeHandle pCalleeForSecurity = TypeHandle(pResolvedToken->hClass);
4886     if (pResolvedToken->pTypeSpec != NULL)
4887     {
4888         SigTypeContext typeContext;
4889         SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
4890
4891         SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
4892         pCalleeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
4893     }
4894
4895     while (pCalleeForSecurity.HasTypeParam())
4896     {
4897         pCalleeForSecurity = pCalleeForSecurity.GetTypeParam();
4898     }
4899
4900     if (IsDynamicScope(pResolvedToken->tokenScope))
4901     {
4902         doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope),
4903                                                     &callerTypeForSecurity, &accessCheckType,
4904                                                     &pAccessContext);
4905     }
4906
4907     //Since this is a check against a TypeHandle, there are some things we can stick in a TypeHandle that
4908     //don't require access checks.
4909     if (pCalleeForSecurity.IsGenericVariable())
4910     {
4911         //I don't need to check for access against !!0.
4912         doAccessCheck = FALSE;
4913     }
4914
4915     //Now do the visibility checks
4916     if (doAccessCheck)
4917     {
4918         AccessCheckOptions accessCheckOptions(accessCheckType,
4919                                               pAccessContext,
4920                                               FALSE /*throw on error*/,
4921                                               pCalleeForSecurity.GetMethodTable());
4922
4923         _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
4924         AccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
4925
4926         BOOL canAccessType = ClassLoader::CanAccessClass(&accessContext,
4927                                                          pCalleeForSecurity.GetMethodTable(),
4928                                                          pCalleeForSecurity.GetAssembly(),
4929                                                          accessCheckOptions);
4930
4931         isAccessAllowed = canAccessType ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
4932     }
4933
4934
4935     if (isAccessAllowed != CORINFO_ACCESS_ALLOWED)
4936     {
4937         //These all get the throw helper
4938         pAccessHelper->helperNum = CORINFO_HELP_CLASS_ACCESS_EXCEPTION;
4939         pAccessHelper->numArgs = 2;
4940
4941         pAccessHelper->args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
4942         pAccessHelper->args[1].Set(CORINFO_CLASS_HANDLE(pCalleeForSecurity.AsPtr()));
4943     }
4944
4945     EE_TO_JIT_TRANSITION();
4946     return isAccessAllowed;
4947 }
4948
4949 //---------------------------------------------------------------------------------------
4950 // Given a method descriptor ftnHnd, extract signature information into sigInfo
4951 // Obtain (representative) instantiation information from ftnHnd's owner class
4952 //@GENERICSVER: added explicit owner parameter
4953 // Internal version without JIT-EE transition
4954 static void getMethodSigInternal(
4955     CORINFO_METHOD_HANDLE ftnHnd,
4956     CORINFO_SIG_INFO *    sigRet,
4957     CORINFO_CLASS_HANDLE  owner,
4958     SignatureKind signatureKind)
4959 {
4960     STANDARD_VM_CONTRACT;
4961
4962     MethodDesc * ftn = GetMethod(ftnHnd);
4963
4964     PCCOR_SIGNATURE pSig = NULL;
4965     DWORD           cbSig = 0;
4966     ftn->GetSig(&pSig, &cbSig);
4967
4968     SigTypeContext context(ftn, (TypeHandle)owner);
4969
4970     // Type parameters in the signature are instantiated
4971     // according to the class/method/array instantiation of ftnHnd and owner
4972     ConvToJitSig(
4973         pSig,
4974         cbSig,
4975         GetScopeHandle(ftn),
4976         mdTokenNil,
4977         &context,
4978         CONV_TO_JITSIG_FLAGS_NONE,
4979         sigRet);
4980
4981     //@GENERICS:
4982     // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation
4983     if (ftn->RequiresInstArg())
4984     {
4985         //
4986         // If we are making a virtual call to an instance method on an interface, we need to lie to the JIT.
4987         // The reason being that we already made sure target is always directly callable (through instantiation stubs),
4988         // JIT should not generate shared generics aware call code and insert the secret argument again at the callsite.
4989         // Otherwise we would end up with two secret generic dictionary arguments (since the stub also provides one).
4990         //
4991         BOOL isCallSiteThatGoesThroughInstantiatingStub =
4992             (signatureKind == SK_VIRTUAL_CALLSITE &&
4993             !ftn->IsStatic() &&
4994             ftn->GetMethodTable()->IsInterface()) ||
4995             signatureKind == SK_STATIC_VIRTUAL_CODEPOINTER_CALLSITE;
4996         if (!isCallSiteThatGoesThroughInstantiatingStub)
4997             sigRet->callConv = (CorInfoCallConv) (sigRet->callConv | CORINFO_CALLCONV_PARAMTYPE);
4998     }
4999
5000     // We want the calling convention bit to be consistant with the method attribute bit
5001     _ASSERTE( (IsMdStatic(ftn->GetAttrs()) == 0) == ((sigRet->callConv & CORINFO_CALLCONV_HASTHIS) != 0) );
5002 }
5003
5004 /***********************************************************************/
5005 // return the address of a pointer to a callable stub that will do the
5006 // virtual or interface call
5007 void CEEInfo::getCallInfo(
5008             CORINFO_RESOLVED_TOKEN * pResolvedToken,
5009             CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
5010             CORINFO_METHOD_HANDLE   callerHandle,
5011             CORINFO_CALLINFO_FLAGS  flags,
5012             CORINFO_CALL_INFO      *pResult /*out */)
5013 {
5014     CONTRACTL {
5015         THROWS;
5016         GC_TRIGGERS;
5017         MODE_PREEMPTIVE;
5018     } CONTRACTL_END;
5019
5020     JIT_TO_EE_TRANSITION();
5021
5022     _ASSERTE(CheckPointer(pResult));
5023
5024     INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
5025
5026     pResult->stubLookup.lookupKind.needsRuntimeLookup = false;
5027
5028     MethodDesc* pMD = (MethodDesc *)pResolvedToken->hMethod;
5029     TypeHandle th(pResolvedToken->hClass);
5030
5031     _ASSERTE(pMD);
5032     _ASSERTE((size_t(pMD) & 0x1) == 0);
5033
5034     // Spec says that a callvirt lookup ignores static methods. Since static methods
5035     // can't have the exact same signature as instance methods, a lookup that found
5036     // a static method would have never found an instance method.
5037     if (pMD->IsStatic() && (flags & CORINFO_CALLINFO_CALLVIRT))
5038     {
5039         EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, W("?")));
5040     }
5041
5042     TypeHandle exactType = TypeHandle(pResolvedToken->hClass);
5043
5044     TypeHandle constrainedType;
5045     if (pConstrainedResolvedToken != NULL)
5046     {
5047         constrainedType = TypeHandle(pConstrainedResolvedToken->hClass);
5048     }
5049
5050     BOOL fIsStaticVirtualMethod = (pConstrainedResolvedToken != NULL && pMD->IsInterface() && pMD->IsStatic());
5051
5052     BOOL fResolvedConstraint = FALSE;
5053     BOOL fForceUseRuntimeLookup = FALSE;
5054     BOOL fAbstractSVM = FALSE;
5055
5056     // The below may need to mutate the constrained token, in which case we
5057     // switch to this local copy to avoid mutating the in argument.
5058     CORINFO_RESOLVED_TOKEN constrainedResolvedTokenCopy;
5059
5060     MethodDesc * pMDAfterConstraintResolution = pMD;
5061     if (constrainedType.IsNull())
5062     {
5063         pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5064     }
5065     // <NICE> Things go wrong when this code path is used when verifying generic code.
5066     // It would be nice if we didn't go down this sort of code path when verifying but
5067     // not generating code. </NICE>
5068     else if (constrainedType.ContainsGenericVariables() || exactType.ContainsGenericVariables())
5069     {
5070         // <NICE> It shouldn't really matter what we do here - but the x86 JIT is annoyingly sensitive
5071         // about what we do, since it pretend generic variables are reference types and generates
5072         // an internal JIT tree even when just verifying generic code. </NICE>
5073         if (constrainedType.IsGenericVariable())
5074         {
5075             pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &T --> T
5076         }
5077         else if (constrainedType.IsValueType())
5078         {
5079             pResult->thisTransform = CORINFO_BOX_THIS; // convert 'this' of type &VC<T> --> boxed(VC<T>)
5080         }
5081         else
5082         {
5083             pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &C<T> --> C<T>
5084         }
5085     }
5086     else
5087     {
5088         // We have a "constrained." call.  Try a partial resolve of the constraint call.  Note that this
5089         // will not necessarily resolve the call exactly, since we might be compiling
5090         // shared generic code - it may just resolve it to a candidate suitable for
5091         // JIT compilation, and require a runtime lookup for the actual code pointer
5092         // to call.
5093         if (constrainedType.IsEnum())
5094         {
5095             // Optimize constrained calls to enum's GetHashCode method. TryResolveConstraintMethodApprox would return
5096             // null since the virtual method resolves to System.Enum's implementation and that's a reference type.
5097             // We can't do this for any other method since ToString and Equals have different semantics for enums
5098             // and their underlying type.
5099             if (pMD->GetSlot() == CoreLibBinder::GetMethod(METHOD__OBJECT__GET_HASH_CODE)->GetSlot())
5100             {
5101                 // Pretend this was a "constrained. UnderlyingType" instruction prefix
5102                 constrainedType = TypeHandle(CoreLibBinder::GetElementType(constrainedType.GetVerifierCorElementType()));
5103
5104                 constrainedResolvedTokenCopy = *pConstrainedResolvedToken;
5105                 pConstrainedResolvedToken = &constrainedResolvedTokenCopy;
5106
5107                 // Native image signature encoder will use this field. It needs to match that pretended type, a bogus signature
5108                 // would be produced otherwise.
5109                 pConstrainedResolvedToken->hClass = (CORINFO_CLASS_HANDLE)constrainedType.AsPtr();
5110
5111                 // Clear the token and typespec because of they do not match hClass anymore.
5112                 pConstrainedResolvedToken->token = mdTokenNil;
5113                 pConstrainedResolvedToken->pTypeSpec = NULL;
5114             }
5115         }
5116
5117         MethodDesc * directMethod = constrainedType.GetMethodTable()->TryResolveConstraintMethodApprox(
5118             exactType,
5119             pMD,
5120             &fForceUseRuntimeLookup);
5121         if (directMethod
5122 #ifdef FEATURE_DEFAULT_INTERFACES
5123             && !directMethod->IsInterface() /* Could be a default interface method implementation */
5124 #endif
5125             )
5126         {
5127             // Either
5128             //    1. no constraint resolution at compile time (!directMethod)
5129             // OR 2. no code sharing lookup in call
5130             // OR 3. we have resolved to an instantiating stub
5131
5132             pMDAfterConstraintResolution = directMethod;
5133             _ASSERTE(!pMDAfterConstraintResolution->IsInterface());
5134             fResolvedConstraint = TRUE;
5135             pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5136
5137             exactType = constrainedType;
5138         }
5139 #ifdef FEATURE_DEFAULT_INTERFACES
5140         else if (directMethod && pMD->IsStatic())
5141         {
5142             if (directMethod->IsAbstract())
5143             {
5144                 // This is the result when we call a SVM which is abstract, or re-abstracted
5145                 directMethod = NULL;
5146                 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5147                 fAbstractSVM = true;
5148             }
5149             else
5150             {
5151                 // Default interface implementation of static virtual method
5152                 pMDAfterConstraintResolution = directMethod;
5153                 fResolvedConstraint = TRUE;
5154                 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5155                 exactType = directMethod->GetMethodTable();
5156             }
5157         }
5158 #endif
5159         else  if (constrainedType.IsValueType())
5160         {
5161             pResult->thisTransform = CORINFO_BOX_THIS;
5162         }
5163         else if (!fIsStaticVirtualMethod)
5164         {
5165             pResult->thisTransform = CORINFO_DEREF_THIS;
5166         }
5167         else
5168         {
5169             pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5170         }
5171     }
5172
5173     //
5174     // Initialize callee context used for inlining and instantiation arguments
5175     //
5176
5177     MethodDesc * pTargetMD = pMDAfterConstraintResolution;
5178     DWORD dwTargetMethodAttrs = pTargetMD->GetAttrs();
5179
5180     pResult->exactContextNeedsRuntimeLookup = (fIsStaticVirtualMethod && !fResolvedConstraint && !constrainedType.IsNull() && constrainedType.IsCanonicalSubtype());
5181
5182     if (pTargetMD->HasMethodInstantiation())
5183     {
5184         pResult->contextHandle = MAKE_METHODCONTEXT(pTargetMD);
5185         if (pTargetMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(pTargetMD->GetMethodInstantiation()))
5186         {
5187             pResult->exactContextNeedsRuntimeLookup = TRUE;
5188         }
5189     }
5190     else
5191     {
5192         if (!exactType.IsTypeDesc() && !pTargetMD->IsArray())
5193         {
5194             // Because of .NET's notion of base calls, exactType may point to a sub-class
5195             // of the actual class that defines pTargetMD.  If the JIT decides to inline, it is
5196             // important that they 'match', so we fix exactType here.
5197             exactType = pTargetMD->GetExactDeclaringType(exactType.AsMethodTable());
5198             _ASSERTE(!exactType.IsNull());
5199         }
5200
5201         pResult->contextHandle = MAKE_CLASSCONTEXT(exactType.AsPtr());
5202         if (exactType.IsSharedByGenericInstantiations())
5203         {
5204             pResult->exactContextNeedsRuntimeLookup = TRUE;
5205         }
5206
5207         // Use main method as the context as long as the methods are called on the same type
5208         if (pResult->exactContextNeedsRuntimeLookup &&
5209             pResolvedToken->tokenContext == METHOD_BEING_COMPILED_CONTEXT() &&
5210             constrainedType.IsNull() &&
5211             exactType == m_pMethodBeingCompiled->GetMethodTable() &&
5212             ((pResolvedToken->cbTypeSpec  == 0) || IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec))))
5213         {
5214             // The typespec signature should be only missing for dynamic methods
5215             _ASSERTE((pResolvedToken->cbTypeSpec != 0) || m_pMethodBeingCompiled->IsDynamicMethod());
5216
5217             pResult->contextHandle = METHOD_BEING_COMPILED_CONTEXT();
5218         }
5219     }
5220
5221     //
5222     // Determine whether to perform direct call
5223     //
5224
5225     bool directCall = false;
5226     bool resolvedCallVirt = false;
5227
5228     if ((flags & CORINFO_CALLINFO_LDFTN) && (!fIsStaticVirtualMethod || fResolvedConstraint))
5229     {
5230         // Since the ldvirtftn instruction resolves types
5231         // at run-time we do this earlier than ldftn. The
5232         // ldftn scenario is handled later when the fixed
5233         // address is requested by in the JIT.
5234         // See getFunctionFixedEntryPoint().
5235         //
5236         // Using ldftn or ldvirtftn on a Generic method
5237         // requires early type loading since instantiation
5238         // occurs at run-time as opposed to JIT time. The
5239         // GC special cases Generic types and relaxes the
5240         // loaded type constraint to permit Generic types
5241         // that are loaded with Canon as opposed to being
5242         // instantiated with an actual type.
5243         if ((flags & CORINFO_CALLINFO_CALLVIRT)
5244             || pTargetMD->HasMethodInstantiation())
5245         {
5246             pTargetMD->PrepareForUseAsAFunctionPointer();
5247         }
5248
5249         directCall = true;
5250     }
5251     else
5252     // Static methods are always direct calls
5253     if (pTargetMD->IsStatic() && (!fIsStaticVirtualMethod || fResolvedConstraint))
5254     {
5255         directCall = true;
5256     }
5257     else
5258     if ((!fIsStaticVirtualMethod && !(flags & CORINFO_CALLINFO_CALLVIRT)) || fResolvedConstraint)
5259     {
5260         directCall = true;
5261     }
5262     else
5263     {
5264         bool devirt;
5265         if (pTargetMD->GetMethodTable()->IsInterface())
5266         {
5267             // Handle interface methods specially because the Sealed bit has no meaning on interfaces.
5268             devirt = !IsMdVirtual(dwTargetMethodAttrs);
5269         }
5270         else
5271         {
5272             devirt = !IsMdVirtual(dwTargetMethodAttrs) || IsMdFinal(dwTargetMethodAttrs) || pTargetMD->GetMethodTable()->IsSealed();
5273         }
5274
5275         if (devirt)
5276         {
5277             resolvedCallVirt = true;
5278             directCall = true;
5279         }
5280     }
5281
5282     if (directCall)
5283     {
5284         // Direct calls to abstract methods are not allowed
5285         if (IsMdAbstract(dwTargetMethodAttrs) &&
5286             // Compensate for always treating delegates as direct calls above
5287             !(((flags & CORINFO_CALLINFO_LDFTN) && (flags & CORINFO_CALLINFO_CALLVIRT) && !resolvedCallVirt))
5288             && !(IsMdStatic(dwTargetMethodAttrs) && fForceUseRuntimeLookup))
5289         {
5290             COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL);
5291         }
5292
5293         bool allowInstParam = (flags & CORINFO_CALLINFO_ALLOWINSTPARAM);
5294
5295         // If the target method is resolved via constrained static virtual dispatch
5296         // And it requires an instParam, we do not have the generic dictionary infrastructure
5297         // to load the correct generic context arg via EmbedGenericHandle.
5298         // Instead, force the call to go down the CORINFO_CALL_CODE_POINTER code path
5299         // which should have somewhat inferior performance. This should only actually happen in the case
5300         // of shared generic code calling a shared generic implementation method, which should be rare.
5301         //
5302         // An alternative design would be to add a new generic dictionary entry kind to hold the MethodDesc
5303         // of the constrained target instead, and use that in some circumstances; however, implementation of
5304         // that design requires refactoring variuos parts of the JIT interface as well as
5305         // TryResolveConstraintMethodApprox. In particular we would need to be abled to embed a constrained lookup
5306         // via EmbedGenericHandle, as well as decide in TryResolveConstraintMethodApprox if the call can be made
5307         // via a single use of CORINFO_CALL_CODE_POINTER, or would be better done with a CORINFO_CALL + embedded
5308         // constrained generic handle, or if there is a case where we would want to use both a CORINFO_CALL and
5309         // embedded constrained generic handle. Given the current expected high performance use case of this feature
5310         // which is generic numerics which will always resolve to exact valuetypes, it is not expected that
5311         // the complexity involved would be worth the risk. Other scenarios are not expected to be as performance
5312         // sensitive.
5313         if (IsMdStatic(dwTargetMethodAttrs) && constrainedType != NULL && pResult->exactContextNeedsRuntimeLookup)
5314         {
5315             allowInstParam = FALSE;
5316         }
5317
5318         // Create instantiating stub if necessary
5319         if (!allowInstParam && pTargetMD->RequiresInstArg())
5320         {
5321             pTargetMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pTargetMD,
5322                 exactType.AsMethodTable(),
5323                 FALSE /* forceBoxedEntryPoint */,
5324                 pTargetMD->GetMethodInstantiation(),
5325                 FALSE /* allowInstParam */);
5326         }
5327
5328         // We don't allow a JIT to call the code directly if a runtime lookup is
5329         // needed. This is the case if
5330         //     1. the scan of the call token indicated that it involves code sharing
5331         // AND 2. the method is an instantiating stub
5332         //
5333         // In these cases the correct instantiating stub is only found via a runtime lookup.
5334         //
5335         // Note that most JITs don't call instantiating stubs directly if they can help it -
5336         // they call the underlying shared code and provide the type context parameter
5337         // explicitly. However
5338         //    (a) some JITs may call instantiating stubs (it makes the JIT simpler) and
5339         //    (b) if the method is a remote stub then the EE will force the
5340         //        call through an instantiating stub and
5341         //    (c) constraint calls that require runtime context lookup are never resolved
5342         //        to underlying shared generic code
5343
5344         bool unresolvedLdVirtFtn = (flags & CORINFO_CALLINFO_LDFTN) && (flags & CORINFO_CALLINFO_CALLVIRT) && !resolvedCallVirt;
5345
5346         if (((pResult->exactContextNeedsRuntimeLookup && pTargetMD->IsInstantiatingStub() && (!allowInstParam || fResolvedConstraint)) || fForceUseRuntimeLookup))
5347         {
5348             _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5349
5350             pResult->kind = CORINFO_CALL_CODE_POINTER;
5351
5352             DictionaryEntryKind entryKind;
5353             if (constrainedType.IsNull() || ((flags & CORINFO_CALLINFO_CALLVIRT) && !constrainedType.IsValueType()))
5354             {
5355                 // For reference types, the constrained type does not affect method resolution on a callvirt, and if there is no
5356                 // constraint, it doesn't effect it either
5357                 entryKind = MethodEntrySlot;
5358             }
5359             else
5360             {
5361                 // constrained. callvirt case where the constraint type is a valuetype
5362                 // OR
5363                 // constrained. call or constrained. ldftn case
5364                 entryKind = ConstrainedMethodEntrySlot;
5365             }
5366             ComputeRuntimeLookupForSharedGenericToken(entryKind,
5367                                                         pResolvedToken,
5368                                                         pConstrainedResolvedToken,
5369                                                         pMD,
5370                                                         &pResult->codePointerLookup);
5371         }
5372         else
5373         {
5374             if (allowInstParam && pTargetMD->IsInstantiatingStub())
5375             {
5376                 pTargetMD = pTargetMD->GetWrappedMethodDesc();
5377             }
5378
5379             pResult->kind = CORINFO_CALL;
5380         }
5381         pResult->nullInstanceCheck = resolvedCallVirt;
5382     }
5383     // All virtual calls which take method instantiations must
5384     // currently be implemented by an indirect call via a runtime-lookup
5385     // function pointer
5386     else if (pTargetMD->HasMethodInstantiation() && !fIsStaticVirtualMethod)
5387     {
5388         pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;  // stub dispatch can't handle generic method calls yet
5389         pResult->nullInstanceCheck = TRUE;
5390     }
5391     // Non-interface dispatches go through the vtable.
5392     else if (!pTargetMD->IsInterface() && !fIsStaticVirtualMethod)
5393     {
5394         pResult->kind = CORINFO_VIRTUALCALL_VTABLE;
5395         pResult->nullInstanceCheck = TRUE;
5396     }
5397     else
5398     {
5399         // No need to null check - the dispatch code will deal with null this.
5400         pResult->nullInstanceCheck = FALSE;
5401 #ifdef STUB_DISPATCH_PORTABLE
5402         pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5403 #else // STUB_DISPATCH_PORTABLE
5404         pResult->kind = CORINFO_VIRTUALCALL_STUB;
5405         if (fIsStaticVirtualMethod)
5406         {
5407             pResult->kind = CORINFO_CALL_CODE_POINTER;
5408         }
5409
5410         // We can't make stub calls when we need exact information
5411         // for interface calls from shared code.
5412
5413         if (pResult->exactContextNeedsRuntimeLookup)
5414         {
5415             _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5416
5417             ComputeRuntimeLookupForSharedGenericToken(fIsStaticVirtualMethod ? ConstrainedMethodEntrySlot : DispatchStubAddrSlot,
5418                                                         pResolvedToken,
5419                                                         pConstrainedResolvedToken,
5420                                                         pMD,
5421                                                         &pResult->stubLookup);
5422         }
5423         else
5424         {
5425             BYTE * indcell = NULL;
5426
5427             // We shouldn't be using GetLoaderAllocator here because for LCG, we need to get the
5428             // VirtualCallStubManager from where the stub will be used.
5429             // For normal methods there is no difference.
5430             LoaderAllocator *pLoaderAllocator = m_pMethodBeingCompiled->GetLoaderAllocator();
5431             VirtualCallStubManager *pMgr = pLoaderAllocator->GetVirtualCallStubManager();
5432
5433             PCODE addr = pMgr->GetCallStub(exactType, pTargetMD);
5434
5435             // Now we want to indirect through a cell so that updates can take place atomically.
5436             if (m_pMethodBeingCompiled->IsLCGMethod())
5437             {
5438                 // LCG methods should use recycled indcells to prevent leaks.
5439                 indcell = pMgr->GenerateStubIndirection(addr, TRUE);
5440
5441                 // Add it to the per DM list so that we can recycle them when the resolver is finalized
5442                 LCGMethodResolver *pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetLCGMethodResolver();
5443                 pResolver->AddToUsedIndCellList(indcell);
5444             }
5445             else
5446             {
5447                 // Normal methods should avoid recycled cells to preserve the locality of all indcells
5448                 // used by one method.
5449                 indcell = pMgr->GenerateStubIndirection(addr, FALSE);
5450             }
5451
5452             // We use an indirect call
5453             pResult->stubLookup.constLookup.accessType = IAT_PVALUE;
5454             pResult->stubLookup.constLookup.addr = indcell;
5455         }
5456 #endif // STUB_DISPATCH_PORTABLE
5457     }
5458
5459     pResult->hMethod = CORINFO_METHOD_HANDLE(pTargetMD);
5460
5461     pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5462     MethodDesc* callerMethod = (MethodDesc*)callerHandle;
5463     if ((flags & CORINFO_CALLINFO_SECURITYCHECKS)
5464         && RequiresAccessCheck(pResolvedToken->tokenScope))
5465     {
5466         //Our type system doesn't always represent the target exactly with the MethodDesc.  In all cases,
5467         //carry around the parent MethodTable for both Caller and Callee.
5468         TypeHandle calleeTypeForSecurity = TypeHandle(pResolvedToken->hClass);
5469         MethodDesc * pCalleeForSecurity = pMD;
5470
5471         MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle); //Should this be the open MD?
5472
5473         if (pCallerForSecurity->HasClassOrMethodInstantiation())
5474         {
5475             _ASSERTE(!IsDynamicScope(pResolvedToken->tokenScope));
5476
5477             SigTypeContext typeContext;
5478             SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
5479             _ASSERTE(!typeContext.IsEmpty());
5480
5481             //If the caller is generic, load the open type and resolve the token again.  Use that for the access
5482             //checks.  If we don't do this then we can't tell the difference between:
5483             //
5484             //BadGeneric<T> containing a methodspec for InaccessibleType::member (illegal)
5485             //and
5486             //BadGeneric<T> containing a methodspec for !!0::member instantiated over InaccessibleType (legal)
5487
5488             if (pResolvedToken->pTypeSpec != NULL)
5489             {
5490                 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
5491                 calleeTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5492
5493                 // typeHnd can be a variable type
5494                 if (calleeTypeForSecurity.GetMethodTable() == NULL)
5495                 {
5496                     COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
5497                 }
5498             }
5499
5500             if (pCalleeForSecurity->IsArray())
5501             {
5502                 // FindOrCreateAssociatedMethodDesc won't remap array method desc because of array base type
5503                 // is not part of instantiation. We have to special case it.
5504                 pCalleeForSecurity = calleeTypeForSecurity.GetMethodTable()->GetParallelMethodDesc(pCalleeForSecurity);
5505             }
5506             else if (pResolvedToken->pMethodSpec != NULL)
5507             {
5508                 uint32_t nGenericMethodArgs = 0;
5509                 CQuickBytes qbGenericMethodArgs;
5510                 TypeHandle *genericMethodArgs = NULL;
5511
5512                 SigPointer sp(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
5513
5514                 BYTE etype;
5515                 IfFailThrow(sp.GetByte(&etype));
5516
5517                 // Load the generic method instantiation
5518                 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, (Module *)pResolvedToken->tokenScope);
5519
5520                 IfFailThrow(sp.GetData(&nGenericMethodArgs));
5521
5522                 DWORD cbAllocSize = 0;
5523                 if (!ClrSafeInt<DWORD>::multiply(nGenericMethodArgs, sizeof(TypeHandle), cbAllocSize))
5524                 {
5525                     COMPlusThrowHR(COR_E_OVERFLOW);
5526                 }
5527
5528                 genericMethodArgs = reinterpret_cast<TypeHandle *>(qbGenericMethodArgs.AllocThrows(cbAllocSize));
5529
5530                 for (uint32_t i = 0; i < nGenericMethodArgs; i++)
5531                 {
5532                     genericMethodArgs[i] = sp.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5533                     _ASSERTE (!genericMethodArgs[i].IsNull());
5534                     IfFailThrow(sp.SkipExactlyOne());
5535                 }
5536
5537                 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(genericMethodArgs, nGenericMethodArgs), FALSE);
5538             }
5539             else if (pResolvedToken->pTypeSpec != NULL)
5540             {
5541                 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(), TRUE);
5542             }
5543         }
5544
5545         TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5546
5547         //Passed various link-time checks.  Now do access checks.
5548
5549         BOOL doAccessCheck = TRUE;
5550         BOOL canAccessMethod = TRUE;
5551         AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
5552         DynamicResolver * pAccessContext = NULL;
5553
5554         callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5555         if (pCallerForSecurity->IsDynamicMethod())
5556         {
5557             doAccessCheck = ModifyCheckForDynamicMethod(pCallerForSecurity->AsDynamicMethodDesc()->GetResolver(),
5558                                                         &callerTypeForSecurity,
5559                                                         &accessCheckType, &pAccessContext);
5560         }
5561
5562         pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5563
5564         if (doAccessCheck)
5565         {
5566             AccessCheckOptions accessCheckOptions(accessCheckType,
5567                                                   pAccessContext,
5568                                                   FALSE,
5569                                                   pCalleeForSecurity);
5570
5571             _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5572             AccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5573
5574             canAccessMethod = ClassLoader::CanAccess(&accessContext,
5575                                                      calleeTypeForSecurity.GetMethodTable(),
5576                                                      calleeTypeForSecurity.GetAssembly(),
5577                                                      pCalleeForSecurity->GetAttrs(),
5578                                                      pCalleeForSecurity,
5579                                                      NULL,
5580                                                      accessCheckOptions
5581                                                     );
5582
5583             // If we were allowed access to the exact method, but it is on a type that has a type parameter
5584             // (for instance an array), we need to ensure that we also have access to the type parameter.
5585             if (canAccessMethod && calleeTypeForSecurity.HasTypeParam())
5586             {
5587                 TypeHandle typeParam = calleeTypeForSecurity.GetTypeParam();
5588                 while (typeParam.HasTypeParam())
5589                 {
5590                     typeParam = typeParam.GetTypeParam();
5591                 }
5592
5593                 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5594                 AccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5595
5596                 MethodTable* pTypeParamMT = typeParam.GetMethodTable();
5597
5598                 // No access check is need for Var, MVar, or FnPtr.
5599                 if (pTypeParamMT != NULL)
5600                     canAccessMethod = ClassLoader::CanAccessClass(&accessContext,
5601                                                                   pTypeParamMT,
5602                                                                   typeParam.GetAssembly(),
5603                                                                   accessCheckOptions);
5604             }
5605
5606             pResult->accessAllowed = canAccessMethod ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
5607             if (!canAccessMethod)
5608             {
5609                 //Check failed, fill in the throw exception helper.
5610                 pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_METHOD_ACCESS_EXCEPTION;
5611                 pResult->callsiteCalloutHelper.numArgs = 2;
5612
5613                 pResult->callsiteCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5614                 pResult->callsiteCalloutHelper.args[1].Set(CORINFO_METHOD_HANDLE(pCalleeForSecurity));
5615             }
5616         }
5617     }
5618
5619     //We're pretty much done at this point.  Let's grab the rest of the information that the jit is going to
5620     //need.
5621     pResult->classFlags = getClassAttribsInternal(pResolvedToken->hClass);
5622
5623     pResult->methodFlags = getMethodAttribsInternal(pResult->hMethod);
5624
5625     SignatureKind signatureKind;
5626     if (flags & CORINFO_CALLINFO_CALLVIRT && !(pResult->kind == CORINFO_CALL))
5627     {
5628         signatureKind = SK_VIRTUAL_CALLSITE;
5629     }
5630     else if ((pResult->kind == CORINFO_CALL_CODE_POINTER) && IsMdVirtual(dwTargetMethodAttrs) && IsMdStatic(dwTargetMethodAttrs))
5631     {
5632         signatureKind = SK_STATIC_VIRTUAL_CODEPOINTER_CALLSITE;
5633     }
5634     else
5635     {
5636         signatureKind = SK_CALLSITE;
5637     }
5638     getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL, signatureKind);
5639     if (fIsStaticVirtualMethod && !fResolvedConstraint)
5640     {
5641         if (pResult->exactContextNeedsRuntimeLookup)
5642         {
5643             // Runtime lookup for static virtual methods always returns exact call addresses not requiring the instantiation argument
5644             pResult->sig.callConv = (CorInfoCallConv)(pResult->sig.callConv & ~CORINFO_CALLCONV_PARAMTYPE);
5645         }
5646         else
5647         {
5648             // Unresolved static virtual method in the absence of shared generics means
5649             // that the runtime needs to throw when reaching the call. SVM resolution within
5650             // shared generics is covered by the ConstrainedMethodEntrySlot dictionary entry.
5651             pResult->kind = CORINFO_CALL;
5652             pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL;
5653             if (fAbstractSVM)
5654             {
5655                 pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_THROW_ENTRYPOINT_NOT_FOUND_EXCEPTION;
5656             }
5657             else
5658             {
5659                 pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_THROW_AMBIGUOUS_RESOLUTION_EXCEPTION;
5660             }
5661             pResult->callsiteCalloutHelper.numArgs = 3;
5662             pResult->callsiteCalloutHelper.args[0].methodHandle = (CORINFO_METHOD_HANDLE)pMD;
5663             pResult->callsiteCalloutHelper.args[0].argType = CORINFO_HELPER_ARG_TYPE_Method;
5664             pResult->callsiteCalloutHelper.args[1].classHandle = (CORINFO_CLASS_HANDLE)th.AsMethodTable();
5665             pResult->callsiteCalloutHelper.args[1].argType = CORINFO_HELPER_ARG_TYPE_Class;
5666             pResult->callsiteCalloutHelper.args[2].classHandle = (CORINFO_CLASS_HANDLE)constrainedType.AsMethodTable();
5667             pResult->callsiteCalloutHelper.args[2].argType = CORINFO_HELPER_ARG_TYPE_Class;
5668         }
5669     }
5670
5671     pResult->wrapperDelegateInvoke = FALSE;
5672
5673     if (m_pMethodBeingCompiled->IsDynamicMethod())
5674     {
5675         auto pMD = m_pMethodBeingCompiled->AsDynamicMethodDesc();
5676         if (pMD->IsILStub() && pMD->IsWrapperDelegateStub())
5677         {
5678             pResult->wrapperDelegateInvoke = TRUE;
5679         }
5680     }
5681
5682     EE_TO_JIT_TRANSITION();
5683 }
5684
5685
5686 /***********************************************************************/
5687 unsigned CEEInfo::getClassDomainID (CORINFO_CLASS_HANDLE clsHnd,
5688                                     void **ppIndirection)
5689 {
5690     CONTRACTL {
5691         THROWS;
5692         GC_TRIGGERS;
5693         MODE_PREEMPTIVE;
5694     } CONTRACTL_END;
5695
5696     unsigned result = 0;
5697
5698     if (ppIndirection != NULL)
5699         *ppIndirection = NULL;
5700
5701     JIT_TO_EE_TRANSITION();
5702
5703     TypeHandle  VMClsHnd(clsHnd);
5704
5705     if (VMClsHnd.AsMethodTable()->IsDynamicStatics())
5706     {
5707         result = (unsigned)VMClsHnd.AsMethodTable()->GetModuleDynamicEntryID();
5708     }
5709     else
5710     {
5711         result = (unsigned)VMClsHnd.AsMethodTable()->GetClassIndex();
5712     }
5713
5714     EE_TO_JIT_TRANSITION();
5715
5716     return result;
5717 }
5718
5719 //---------------------------------------------------------------------------------------
5720 //
5721 // Used by the JIT to determine whether the profiler or IBC is tracking object
5722 // allocations
5723 //
5724 // Return Value:
5725 //    bool indicating whether the profiler or IBC is tracking object allocations
5726 //
5727 // Notes:
5728 //    Normally, a profiler would just directly call the inline helper to determine
5729 //    whether the profiler set the relevant event flag (e.g.,
5730 //    CORProfilerTrackAllocationsEnabled). However, this wrapper also asks whether we're
5731 //    running for IBC instrumentation or enabling the object allocated ETW event. If so,
5732 //    we treat that the same as if the profiler requested allocation information, so that
5733 //    the JIT will still use the profiling-friendly object allocation jit helper, so the
5734 //    allocations can be tracked.
5735 //
5736
5737 bool __stdcall TrackAllocationsEnabled()
5738 {
5739     CONTRACTL
5740     {
5741         NOTHROW;
5742         GC_NOTRIGGER;
5743         MODE_ANY;
5744     }
5745     CONTRACTL_END;
5746
5747     return (
5748         FALSE
5749 #ifdef PROFILING_SUPPORTED
5750         || CORProfilerTrackAllocationsEnabled()
5751 #endif // PROFILING_SUPPORTED
5752 #ifdef FEATURE_EVENT_TRACE
5753         || ETW::TypeSystemLog::IsHeapAllocEventEnabled()
5754 #endif // FEATURE_EVENT_TRACE
5755         );
5756 }
5757
5758 /***********************************************************************/
5759 CorInfoHelpFunc CEEInfo::getNewHelper(CORINFO_CLASS_HANDLE classHandle, bool* pHasSideEffects)
5760 {
5761     CONTRACTL {
5762         THROWS;
5763         GC_TRIGGERS;
5764         MODE_PREEMPTIVE;
5765     } CONTRACTL_END;
5766
5767     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5768
5769     JIT_TO_EE_TRANSITION();
5770
5771     TypeHandle  VMClsHnd(classHandle);
5772
5773     if(VMClsHnd.IsTypeDesc())
5774     {
5775         COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateFunctionPointer"));
5776     }
5777
5778     if(VMClsHnd.IsAbstract())
5779     {
5780         COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateAbstractClass"));
5781     }
5782
5783     MethodTable* pMT = VMClsHnd.AsMethodTable();
5784     result = getNewHelperStatic(pMT, pHasSideEffects);
5785
5786     _ASSERTE(result != CORINFO_HELP_UNDEF);
5787
5788     EE_TO_JIT_TRANSITION();
5789
5790     return result;
5791 }
5792
5793 /***********************************************************************/
5794 CorInfoHelpFunc CEEInfo::getNewHelperStatic(MethodTable * pMT, bool * pHasSideEffects)
5795 {
5796     STANDARD_VM_CONTRACT;
5797
5798
5799     // Slow helper is the default
5800     CorInfoHelpFunc helper = CORINFO_HELP_NEWFAST;
5801     BOOL hasFinalizer = pMT->HasFinalizer();
5802     BOOL isComObjectType = pMT->IsComObjectType();
5803
5804     if (isComObjectType)
5805     {
5806         *pHasSideEffects = true;
5807     }
5808     else
5809     {
5810         *pHasSideEffects = !!hasFinalizer;
5811     }
5812
5813     if (isComObjectType)
5814     {
5815         // Use slow helper
5816         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5817     }
5818     else
5819     if ((pMT->GetBaseSize() >= LARGE_OBJECT_SIZE) ||
5820         hasFinalizer)
5821     {
5822         // Use slow helper
5823         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5824     }
5825     else
5826     // don't call the super-optimized one since that does not check
5827     // for GCStress
5828     if (GCStress<cfg_alloc>::IsEnabled())
5829     {
5830         // Use slow helper
5831         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5832     }
5833     else
5834 #ifdef _LOGALLOC
5835 #ifdef LOGGING
5836     // Super fast version doesn't do logging
5837     if (LoggingOn(LF_GCALLOC, LL_INFO10))
5838     {
5839         // Use slow helper
5840         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5841     }
5842     else
5843 #endif // LOGGING
5844 #endif // _LOGALLOC
5845     // Don't use the SFAST allocator when tracking object allocations,
5846     // so we don't have to instrument it.
5847     if (TrackAllocationsEnabled())
5848     {
5849         // Use slow helper
5850         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5851     }
5852     else
5853 #ifdef FEATURE_64BIT_ALIGNMENT
5854     // @ARMTODO: Force all 8-byte alignment requiring allocations down one slow path. As performance
5855     // measurements dictate we can spread these out to faster, more specialized helpers later.
5856     if (pMT->RequiresAlign8())
5857     {
5858         // Use slow helper
5859         _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5860     }
5861     else
5862 #endif
5863     {
5864         // Use the fast helper when all conditions are met
5865         helper = CORINFO_HELP_NEWSFAST;
5866     }
5867
5868 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
5869     // If we are use the fast allocator we also may need the
5870     // specialized varion for align8
5871     if (pMT->GetClass()->IsAlign8Candidate() &&
5872         (helper == CORINFO_HELP_NEWSFAST))
5873     {
5874         helper = CORINFO_HELP_NEWSFAST_ALIGN8;
5875     }
5876 #endif // FEATURE_DOUBLE_ALIGNMENT_HINT
5877
5878     return helper;
5879 }
5880
5881 /***********************************************************************/
5882 // <REVIEW> this only works for shared generic code because all the
5883 // helpers are actually the same. If they were different then things might
5884 // break because the same helper would end up getting used for different but
5885 // representation-compatible arrays (e.g. one with a default constructor
5886 // and one without) </REVIEW>
5887 CorInfoHelpFunc CEEInfo::getNewArrHelper (CORINFO_CLASS_HANDLE arrayClsHnd)
5888 {
5889     CONTRACTL {
5890         THROWS;
5891         GC_TRIGGERS;
5892         MODE_PREEMPTIVE;
5893     } CONTRACTL_END;
5894
5895     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5896
5897     JIT_TO_EE_TRANSITION();
5898
5899     TypeHandle arrayType(arrayClsHnd);
5900
5901     result = getNewArrHelperStatic(arrayType);
5902
5903     _ASSERTE(result != CORINFO_HELP_UNDEF);
5904
5905     EE_TO_JIT_TRANSITION();
5906
5907     return result;
5908 }
5909
5910 /***********************************************************************/
5911 CorInfoHelpFunc CEEInfo::getNewArrHelperStatic(TypeHandle clsHnd)
5912 {
5913     STANDARD_VM_CONTRACT;
5914
5915     _ASSERTE(clsHnd.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
5916
5917     if (GCStress<cfg_alloc>::IsEnabled())
5918     {
5919         return CORINFO_HELP_NEWARR_1_DIRECT;
5920     }
5921
5922     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5923
5924     TypeHandle thElemType = clsHnd.GetArrayElementTypeHandle();
5925     CorElementType elemType = thElemType.GetInternalCorElementType();
5926
5927     // This is if we're asked for newarr !0 when verifying generic code
5928     // Of course ideally you wouldn't even be generating code when
5929     // simply doing verification (we run the JIT importer in import-only
5930     // mode), but importing does more than one would like so we try to be
5931     // tolerant when asked for non-sensical helpers.
5932     if (CorTypeInfo::IsGenericVariable(elemType))
5933     {
5934         result = CORINFO_HELP_NEWARR_1_OBJ;
5935     }
5936     else if (CorTypeInfo::IsObjRef(elemType))
5937     {
5938         // It is an array of object refs
5939         result = CORINFO_HELP_NEWARR_1_OBJ;
5940     }
5941     else
5942     {
5943         // These cases always must use the slow helper
5944         if (
5945 #ifdef FEATURE_64BIT_ALIGNMENT
5946             thElemType.RequiresAlign8() ||
5947 #endif
5948             (elemType == ELEMENT_TYPE_VOID) ||
5949             LoggingOn(LF_GCALLOC, LL_INFO10) ||
5950             TrackAllocationsEnabled())
5951         {
5952             // Use the slow helper
5953             result = CORINFO_HELP_NEWARR_1_DIRECT;
5954         }
5955 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
5956         else if (elemType == ELEMENT_TYPE_R8)
5957         {
5958             // Use the Align8 fast helper
5959             result = CORINFO_HELP_NEWARR_1_ALIGN8;
5960         }
5961 #endif
5962         else
5963         {
5964             // Yea, we can do it the fast way!
5965             result = CORINFO_HELP_NEWARR_1_VC;
5966         }
5967     }
5968
5969     return result;
5970 }
5971
5972 /***********************************************************************/
5973 CorInfoHelpFunc CEEInfo::getCastingHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fThrowing)
5974 {
5975     CONTRACTL {
5976         THROWS;
5977         GC_TRIGGERS;
5978         MODE_PREEMPTIVE;
5979     } CONTRACTL_END;
5980
5981     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5982
5983     JIT_TO_EE_TRANSITION();
5984
5985     bool fClassMustBeRestored;
5986     result = getCastingHelperStatic(TypeHandle(pResolvedToken->hClass), fThrowing, &fClassMustBeRestored);
5987     if (fClassMustBeRestored)
5988         classMustBeLoadedBeforeCodeIsRun(pResolvedToken->hClass);
5989
5990     EE_TO_JIT_TRANSITION();
5991
5992     return result;
5993 }
5994
5995 /***********************************************************************/
5996 CorInfoHelpFunc CEEInfo::getCastingHelperStatic(TypeHandle clsHnd, bool fThrowing, bool * pfClassMustBeRestored)
5997 {
5998     STANDARD_VM_CONTRACT;
5999
6000     // Slow helper is the default
6001     int helper = CORINFO_HELP_ISINSTANCEOFANY;
6002
6003     *pfClassMustBeRestored = false;
6004
6005     if (clsHnd == TypeHandle(g_pCanonMethodTableClass))
6006     {
6007         // In shared code just use the catch-all helper for type variables, as the same
6008         // code may be used for interface/array/class instantiations
6009         //
6010         // We may be able to take advantage of constraints to select a specialized helper.
6011         // This optimizations does not seem to be warranted at the moment.
6012         _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6013     }
6014     else
6015     if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasVariance())
6016     {
6017         // Casting to variant type requires the type to be fully loaded
6018         *pfClassMustBeRestored = true;
6019
6020         _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6021     }
6022     else
6023     if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasTypeEquivalence())
6024     {
6025         // If the type can be equivalent with something, use the slow helper
6026         // Note: if the type of the instance is the one marked as equivalent, it will be
6027         // caught by the fast helpers in the same way as they catch transparent proxies.
6028         _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6029     }
6030     else
6031     if (clsHnd.IsInterface())
6032     {
6033         // If it is a non-variant interface, use the fast interface helper
6034         helper = CORINFO_HELP_ISINSTANCEOFINTERFACE;
6035     }
6036     else
6037     if (clsHnd.IsArray())
6038     {
6039         if (clsHnd.GetInternalCorElementType() != ELEMENT_TYPE_SZARRAY)
6040         {
6041             // Casting to multidimensional array type requires restored pointer to EEClass to fetch rank
6042             *pfClassMustBeRestored = true;
6043         }
6044
6045         // If it is an array, use the fast array helper
6046         helper = CORINFO_HELP_ISINSTANCEOFARRAY;
6047     }
6048     else
6049     if (!clsHnd.IsTypeDesc() && !Nullable::IsNullableType(clsHnd))
6050     {
6051         // If it is a non-variant class, use the fast class helper
6052         helper = CORINFO_HELP_ISINSTANCEOFCLASS;
6053     }
6054     else
6055     {
6056         // Otherwise, use the slow helper
6057         _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6058     }
6059
6060     if (fThrowing)
6061     {
6062         const int delta = CORINFO_HELP_CHKCASTANY - CORINFO_HELP_ISINSTANCEOFANY;
6063
6064         static_assert_no_msg(CORINFO_HELP_CHKCASTINTERFACE
6065             == CORINFO_HELP_ISINSTANCEOFINTERFACE + delta);
6066         static_assert_no_msg(CORINFO_HELP_CHKCASTARRAY
6067             == CORINFO_HELP_ISINSTANCEOFARRAY + delta);
6068         static_assert_no_msg(CORINFO_HELP_CHKCASTCLASS
6069             == CORINFO_HELP_ISINSTANCEOFCLASS + delta);
6070
6071         helper += delta;
6072     }
6073
6074     return (CorInfoHelpFunc)helper;
6075 }
6076
6077 /***********************************************************************/
6078 CorInfoHelpFunc CEEInfo::getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd)
6079 {
6080     CONTRACTL {
6081         NOTHROW;
6082         GC_NOTRIGGER;
6083         MODE_PREEMPTIVE;
6084     } CONTRACTL_END;
6085
6086     CorInfoHelpFunc result = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
6087
6088     JIT_TO_EE_TRANSITION_LEAF();
6089
6090     TypeHandle cls(clsHnd);
6091     MethodTable* pMT = cls.AsMethodTable();
6092
6093     if (pMT->IsDynamicStatics())
6094     {
6095         _ASSERTE(!cls.ContainsGenericVariables());
6096         _ASSERTE(pMT->GetModuleDynamicEntryID() != (unsigned) -1);
6097
6098         result = CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
6099     }
6100
6101     EE_TO_JIT_TRANSITION_LEAF();
6102
6103     return result;
6104 }
6105
6106 /***********************************************************************/
6107 CorInfoHelpFunc CEEInfo::getUnBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6108 {
6109     LIMITED_METHOD_CONTRACT;
6110
6111     classMustBeLoadedBeforeCodeIsRun(clsHnd);
6112
6113     TypeHandle VMClsHnd(clsHnd);
6114     if (Nullable::IsNullableType(VMClsHnd))
6115         return CORINFO_HELP_UNBOX_NULLABLE;
6116
6117     return CORINFO_HELP_UNBOX;
6118 }
6119
6120 /***********************************************************************/
6121 CORINFO_OBJECT_HANDLE CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd)
6122 {
6123     CONTRACTL{
6124         THROWS;
6125         GC_TRIGGERS;
6126         MODE_PREEMPTIVE;
6127     } CONTRACTL_END;
6128
6129     CORINFO_OBJECT_HANDLE pointer = NULL;
6130
6131     JIT_TO_EE_TRANSITION();
6132
6133     TypeHandle typeHnd(clsHnd);
6134     if (!typeHnd.IsCanonicalSubtype() && typeHnd.IsManagedClassObjectPinned())
6135     {
6136         GCX_COOP();
6137         // ManagedClassObject is frozen here
6138         pointer = (CORINFO_OBJECT_HANDLE)OBJECTREFToObject(typeHnd.GetManagedClassObject());
6139         _ASSERT(GCHeapUtilities::GetGCHeap()->IsInFrozenSegment((Object*)pointer));
6140     }
6141
6142     EE_TO_JIT_TRANSITION();
6143
6144     return pointer;
6145 }
6146
6147
6148 /***********************************************************************/
6149 bool CEEInfo::isObjectImmutable(CORINFO_OBJECT_HANDLE objHandle)
6150 {
6151     CONTRACTL{
6152         THROWS;
6153         GC_TRIGGERS;
6154         MODE_PREEMPTIVE;
6155     } CONTRACTL_END;
6156
6157     _ASSERT(objHandle != NULL);
6158
6159     bool isImmutable = false;
6160
6161     JIT_TO_EE_TRANSITION();
6162
6163     GCX_COOP();
6164     OBJECTREF obj = getObjectFromJitHandle(objHandle);
6165     MethodTable* type = obj->GetMethodTable();
6166
6167     if (type->IsString() || type == g_pRuntimeTypeClass)
6168     {
6169         // These types are always immutable
6170         isImmutable = true;
6171     }
6172     else if (type->IsArray() && ((ArrayBase*)OBJECTREFToObject(obj))->GetComponentSize() == 0)
6173     {
6174         // Empty arrays are always immutable
6175         isImmutable = true;
6176     }
6177     else if (type->IsDelegate() || type->GetNumInstanceFields() == 0)
6178     {
6179         // Delegates and types without fields are always immutable
6180         isImmutable = true;
6181     }
6182
6183     EE_TO_JIT_TRANSITION();
6184
6185     return isImmutable;
6186 }
6187
6188 /***********************************************************************/
6189 bool CEEInfo::getStringChar(CORINFO_OBJECT_HANDLE obj, int index, uint16_t* value)
6190 {
6191     CONTRACTL{
6192         THROWS;
6193         GC_TRIGGERS;
6194         MODE_PREEMPTIVE;
6195     } CONTRACTL_END;
6196
6197     _ASSERT(obj != NULL);
6198
6199     bool result = false;
6200
6201     JIT_TO_EE_TRANSITION();
6202
6203     GCX_COOP();
6204     OBJECTREF objRef = getObjectFromJitHandle(obj);
6205     MethodTable* type = objRef->GetMethodTable();
6206     if (type->IsString())
6207     {
6208         STRINGREF strRef = (STRINGREF)objRef;
6209         if (strRef->GetStringLength() > (DWORD)index)
6210         {
6211             *value = strRef->GetBuffer()[index];
6212             result = true;
6213         }
6214     }
6215
6216     EE_TO_JIT_TRANSITION();
6217
6218     return result;
6219 }
6220
6221 /***********************************************************************/
6222 CORINFO_CLASS_HANDLE CEEInfo::getObjectType(CORINFO_OBJECT_HANDLE objHandle)
6223 {
6224     CONTRACTL{
6225         THROWS;
6226         GC_TRIGGERS;
6227         MODE_PREEMPTIVE;
6228     } CONTRACTL_END;
6229
6230     _ASSERT(objHandle != NULL);
6231
6232     CORINFO_CLASS_HANDLE handle = NULL;
6233
6234     JIT_TO_EE_TRANSITION();
6235
6236     GCX_COOP();
6237     OBJECTREF obj = getObjectFromJitHandle(objHandle);
6238     handle = (CORINFO_CLASS_HANDLE)obj->GetMethodTable();
6239
6240     EE_TO_JIT_TRANSITION();
6241
6242     return handle;
6243 }
6244
6245 /***********************************************************************/
6246 bool CEEInfo::getReadyToRunHelper(
6247         CORINFO_RESOLVED_TOKEN *        pResolvedToken,
6248         CORINFO_LOOKUP_KIND *           pGenericLookupKind,
6249         CorInfoHelpFunc                 id,
6250         CORINFO_CONST_LOOKUP *          pLookup
6251         )
6252 {
6253     LIMITED_METHOD_CONTRACT;
6254     UNREACHABLE();      // only called during NGen
6255 }
6256
6257 /***********************************************************************/
6258 void CEEInfo::getReadyToRunDelegateCtorHelper(
6259         CORINFO_RESOLVED_TOKEN * pTargetMethod,
6260         mdToken                  targetConstraint,
6261         CORINFO_CLASS_HANDLE     delegateType,
6262         CORINFO_LOOKUP *   pLookup
6263         )
6264 {
6265     LIMITED_METHOD_CONTRACT;
6266     UNREACHABLE();      // only called during NGen
6267 }
6268
6269 /***********************************************************************/
6270 // see code:Nullable#NullableVerification
6271
6272 CORINFO_CLASS_HANDLE  CEEInfo::getTypeForBox(CORINFO_CLASS_HANDLE  cls)
6273 {
6274     LIMITED_METHOD_CONTRACT;
6275
6276     TypeHandle VMClsHnd(cls);
6277     if (Nullable::IsNullableType(VMClsHnd)) {
6278         VMClsHnd = VMClsHnd.AsMethodTable()->GetInstantiation()[0];
6279     }
6280     return static_cast<CORINFO_CLASS_HANDLE>(VMClsHnd.AsPtr());
6281 }
6282
6283 /***********************************************************************/
6284 // see code:Nullable#NullableVerification
6285 CorInfoHelpFunc CEEInfo::getBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6286 {
6287     CONTRACTL {
6288         THROWS;
6289         GC_TRIGGERS;
6290         MODE_PREEMPTIVE;
6291     } CONTRACTL_END;
6292
6293     CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6294
6295     JIT_TO_EE_TRANSITION();
6296
6297     TypeHandle VMClsHnd(clsHnd);
6298     if (Nullable::IsNullableType(VMClsHnd))
6299     {
6300         result = CORINFO_HELP_BOX_NULLABLE;
6301     }
6302     else
6303     {
6304         if (VMClsHnd.IsTypeDesc() || !VMClsHnd.IsValueType())
6305             COMPlusThrow(kInvalidOperationException,W("InvalidOperation_TypeCannotBeBoxed"));
6306
6307         // we shouldn't allow boxing of types that contains stack pointers
6308         // csc and vbc already disallow it.
6309         if (VMClsHnd.AsMethodTable()->IsByRefLike())
6310             COMPlusThrow(kInvalidProgramException,W("NotSupported_ByRefLike"));
6311
6312         result = CORINFO_HELP_BOX;
6313     }
6314
6315     EE_TO_JIT_TRANSITION();
6316
6317     return result;
6318 }
6319
6320 /***********************************************************************/
6321 // registers a vararg sig & returns a class-specific cookie for it.
6322
6323 CORINFO_VARARGS_HANDLE CEEInfo::getVarArgsHandle(CORINFO_SIG_INFO *sig,
6324                                                  void **ppIndirection)
6325 {
6326     CONTRACTL {
6327         THROWS;
6328         GC_TRIGGERS;
6329         MODE_PREEMPTIVE;
6330     } CONTRACTL_END;
6331
6332     CORINFO_VARARGS_HANDLE result = NULL;
6333
6334     if (ppIndirection != NULL)
6335         *ppIndirection = NULL;
6336
6337     JIT_TO_EE_TRANSITION();
6338
6339     Module* module = GetModule(sig->scope);
6340
6341     result = CORINFO_VARARGS_HANDLE(module->GetVASigCookie(Signature(sig->pSig, sig->cbSig)));
6342
6343     EE_TO_JIT_TRANSITION();
6344
6345     return result;
6346 }
6347
6348 bool CEEInfo::canGetVarArgsHandle(CORINFO_SIG_INFO *sig)
6349 {
6350     LIMITED_METHOD_CONTRACT;
6351     return true;
6352 }
6353
6354 /***********************************************************************/
6355 unsigned CEEInfo::getMethodHash (CORINFO_METHOD_HANDLE ftnHnd)
6356 {
6357     CONTRACTL {
6358         THROWS;
6359         GC_TRIGGERS;
6360         MODE_PREEMPTIVE;
6361     } CONTRACTL_END;
6362
6363     unsigned result = 0;
6364
6365     JIT_TO_EE_TRANSITION();
6366
6367     MethodDesc* ftn = GetMethod(ftnHnd);
6368
6369     result = (unsigned) ftn->GetStableHash();
6370
6371     EE_TO_JIT_TRANSITION();
6372
6373     return result;
6374 }
6375
6376 /***********************************************************************/
6377 size_t CEEInfo::printMethodName(CORINFO_METHOD_HANDLE ftnHnd, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize)
6378 {
6379     CONTRACTL {
6380         THROWS;
6381         GC_NOTRIGGER;
6382         MODE_PREEMPTIVE;
6383     } CONTRACTL_END;
6384
6385     size_t bytesWritten = 0;
6386
6387     JIT_TO_EE_TRANSITION();
6388
6389     MethodDesc* ftn = GetMethod(ftnHnd);
6390     const char* ftnName = ftn->GetName();
6391
6392     size_t len = strlen(ftnName);
6393     if (bufferSize > 0)
6394     {
6395         bytesWritten = min(len, bufferSize - 1);
6396         memcpy(buffer, ftnName, bytesWritten);
6397         buffer[bytesWritten] = '\0';
6398     }
6399
6400     if (pRequiredBufferSize != NULL)
6401     {
6402         *pRequiredBufferSize = len + 1;
6403     }
6404
6405     EE_TO_JIT_TRANSITION();
6406
6407     return bytesWritten;
6408 }
6409
6410 const char* CEEInfo::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftnHnd, const char** className, const char** namespaceName, const char **enclosingClassName)
6411 {
6412     CONTRACTL {
6413         THROWS;
6414         GC_TRIGGERS;
6415         MODE_PREEMPTIVE;
6416     } CONTRACTL_END;
6417
6418     const char* result = NULL;
6419
6420     JIT_TO_EE_TRANSITION();
6421
6422     if (className != NULL)
6423     {
6424         *className = NULL;
6425     }
6426
6427     if (namespaceName != NULL)
6428     {
6429         *namespaceName = NULL;
6430     }
6431
6432     if (enclosingClassName != NULL)
6433     {
6434         *enclosingClassName = NULL;
6435     }
6436
6437     MethodDesc *ftn = GetMethod(ftnHnd);
6438     mdMethodDef token = ftn->GetMemberDef();
6439
6440     if (!IsNilToken(token))
6441     {
6442         MethodTable* pMT = ftn->GetMethodTable();
6443         IMDInternalImport* pMDImport = pMT->GetMDImport();
6444
6445         IfFailThrow(pMDImport->GetNameOfMethodDef(token, &result));
6446         if (className != NULL || namespaceName != NULL)
6447         {
6448             IfFailThrow(pMDImport->GetNameOfTypeDef(pMT->GetCl(), className, namespaceName));
6449         }
6450         // Query enclosingClassName when the method is in a nested class
6451         // and get the namespace of enclosing classes (nested class's namespace is empty)
6452         if ((enclosingClassName != NULL || namespaceName != NULL) && pMT->GetClass()->IsNested())
6453         {
6454             IfFailThrow(pMDImport->GetNameOfTypeDef(pMT->GetEnclosingCl(), enclosingClassName, namespaceName));
6455         }
6456     }
6457
6458     EE_TO_JIT_TRANSITION();
6459
6460     return result;
6461 }
6462
6463 /*********************************************************************/
6464 const char* CEEInfo::getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName)
6465 {
6466     CONTRACTL {
6467         THROWS;
6468         GC_TRIGGERS;
6469         MODE_PREEMPTIVE;
6470     } CONTRACTL_END;
6471
6472     const char* result = NULL;
6473     const char* namespaceResult = NULL;
6474
6475     JIT_TO_EE_TRANSITION();
6476     TypeHandle VMClsHnd(cls);
6477
6478     if (!VMClsHnd.IsTypeDesc())
6479     {
6480         result = VMClsHnd.AsMethodTable()->GetFullyQualifiedNameInfo(&namespaceResult);
6481     }
6482
6483     if (namespaceName != NULL)
6484     {
6485         *namespaceName = namespaceResult;
6486     }
6487
6488     EE_TO_JIT_TRANSITION();
6489
6490     return result;
6491 }
6492
6493 /*********************************************************************/
6494 CORINFO_CLASS_HANDLE CEEInfo::getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index)
6495 {
6496     CONTRACTL {
6497         THROWS;
6498         GC_TRIGGERS;
6499         MODE_PREEMPTIVE;
6500     } CONTRACTL_END;
6501
6502     CORINFO_CLASS_HANDLE result = NULL;
6503
6504     JIT_TO_EE_TRANSITION_LEAF();
6505
6506     TypeHandle VMClsHnd(cls);
6507     Instantiation inst = VMClsHnd.GetInstantiation();
6508     TypeHandle typeArg = index < inst.GetNumArgs() ? inst[index] : NULL;
6509     result = CORINFO_CLASS_HANDLE(typeArg.AsPtr());
6510
6511     EE_TO_JIT_TRANSITION_LEAF();
6512
6513     return result;
6514 }
6515
6516 /*********************************************************************/
6517 bool CEEInfo::isIntrinsic(CORINFO_METHOD_HANDLE ftn)
6518 {
6519     CONTRACTL {
6520         NOTHROW;
6521         GC_NOTRIGGER;
6522         MODE_PREEMPTIVE;
6523     } CONTRACTL_END;
6524
6525     bool ret = false;
6526
6527     JIT_TO_EE_TRANSITION_LEAF();
6528
6529     _ASSERTE(ftn);
6530
6531     MethodDesc *pMD = (MethodDesc*)ftn;
6532     ret = pMD->IsIntrinsic();
6533
6534     EE_TO_JIT_TRANSITION_LEAF();
6535
6536     return ret;
6537 }
6538
6539 /*********************************************************************/
6540 uint32_t CEEInfo::getMethodAttribs (CORINFO_METHOD_HANDLE ftn)
6541 {
6542     CONTRACTL {
6543         THROWS;
6544         GC_TRIGGERS;
6545         MODE_PREEMPTIVE;
6546     } CONTRACTL_END;
6547
6548     DWORD result = 0;
6549
6550     JIT_TO_EE_TRANSITION();
6551
6552     result = getMethodAttribsInternal(ftn);
6553
6554     EE_TO_JIT_TRANSITION();
6555
6556     return result;
6557 }
6558
6559 /*********************************************************************/
6560 DWORD CEEInfo::getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftn)
6561 {
6562     STANDARD_VM_CONTRACT;
6563
6564 /*
6565     returns method attribute flags (defined in corhdr.h)
6566
6567     NOTE: This doesn't return certain method flags
6568     (mdAssem, mdFamANDAssem, mdFamORAssem, mdPrivateScope)
6569 */
6570
6571     MethodDesc* pMD = GetMethod(ftn);
6572
6573     if (pMD->IsLCGMethod())
6574     {
6575         return CORINFO_FLG_STATIC | CORINFO_FLG_DONT_INLINE;
6576     }
6577
6578     DWORD result = 0;
6579
6580     DWORD attribs = pMD->GetAttrs();
6581
6582     if (IsMdFamily(attribs))
6583         result |= CORINFO_FLG_PROTECTED;
6584     if (IsMdStatic(attribs))
6585         result |= CORINFO_FLG_STATIC;
6586     if (pMD->IsSynchronized())
6587         result |= CORINFO_FLG_SYNCH;
6588     if (pMD->IsFCall())
6589         result |= CORINFO_FLG_NOGCCHECK;
6590     if (pMD->IsIntrinsic() || pMD->IsArray())
6591         result |= CORINFO_FLG_INTRINSIC;
6592     if (IsMdVirtual(attribs))
6593         result |= CORINFO_FLG_VIRTUAL;
6594     if (IsMdAbstract(attribs))
6595         result |= CORINFO_FLG_ABSTRACT;
6596     if (IsMdRTSpecialName(attribs))
6597     {
6598         LPCUTF8 pName = pMD->GetName();
6599         if (IsMdInstanceInitializer(attribs, pName) ||
6600             IsMdClassConstructor(attribs, pName))
6601             result |= CORINFO_FLG_CONSTRUCTOR;
6602     }
6603
6604     //
6605     // See if we need to embed a .cctor call at the head of the
6606     // method body.
6607     //
6608
6609     MethodTable* pMT = pMD->GetMethodTable();
6610
6611     // method or class might have the final bit
6612     if (IsMdFinal(attribs) || pMT->IsSealed())
6613     {
6614         result |= CORINFO_FLG_FINAL;
6615     }
6616
6617     if (pMD->IsEnCAddedMethod())
6618     {
6619         result |= CORINFO_FLG_EnC;
6620     }
6621
6622     if (pMD->IsSharedByGenericInstantiations())
6623     {
6624         result |= CORINFO_FLG_SHAREDINST;
6625     }
6626
6627     if (pMD->IsNDirect())
6628     {
6629         result |= CORINFO_FLG_PINVOKE;
6630     }
6631
6632     if (IsMdRequireSecObject(attribs))
6633     {
6634         // Assume all methods marked as DynamicSecurity are
6635         // marked that way because they use StackCrawlMark to identify
6636         // the caller.
6637         // See comments in canInline or canTailCall
6638         result |= CORINFO_FLG_DONT_INLINE_CALLER;
6639     }
6640
6641     // Check for the aggressive optimization directive. AggressiveOptimization only makes sense for IL methods.
6642     DWORD ilMethodImplAttribs = 0;
6643     if (pMD->IsIL())
6644     {
6645         ilMethodImplAttribs = pMD->GetImplAttrs();
6646         if (IsMiAggressiveOptimization(ilMethodImplAttribs))
6647         {
6648             result |= CORINFO_FLG_AGGRESSIVE_OPT;
6649         }
6650     }
6651
6652     // Check for an inlining directive.
6653     if (pMD->IsNotInline())
6654     {
6655         /* Function marked as not inlineable */
6656         result |= CORINFO_FLG_DONT_INLINE;
6657     }
6658     // AggressiveInlining only makes sense for IL methods.
6659     else if (pMD->IsIL() && IsMiAggressiveInlining(ilMethodImplAttribs))
6660     {
6661         result |= CORINFO_FLG_FORCEINLINE;
6662     }
6663
6664     if (pMT->IsDelegate() && ((DelegateEEClass*)(pMT->GetClass()))->GetInvokeMethod() == pMD)
6665     {
6666         // This is now used to emit efficient invoke code for any delegate invoke,
6667         // including multicast.
6668         result |= CORINFO_FLG_DELEGATE_INVOKE;
6669     }
6670
6671     if (!g_pConfig->TieredCompilation_QuickJitForLoops())
6672     {
6673         result |= CORINFO_FLG_DISABLE_TIER0_FOR_LOOPS;
6674     }
6675
6676     return result;
6677 }
6678
6679 /*********************************************************************/
6680 void CEEInfo::setMethodAttribs (
6681         CORINFO_METHOD_HANDLE ftnHnd,
6682         CorInfoMethodRuntimeFlags attribs)
6683 {
6684     CONTRACTL {
6685         THROWS;
6686         GC_TRIGGERS;
6687         MODE_PREEMPTIVE;
6688     } CONTRACTL_END;
6689
6690     JIT_TO_EE_TRANSITION();
6691
6692     MethodDesc* ftn = GetMethod(ftnHnd);
6693
6694     if (attribs & CORINFO_FLG_BAD_INLINEE)
6695     {
6696         ftn->SetNotInline(true);
6697     }
6698
6699     if (attribs & (CORINFO_FLG_SWITCHED_TO_OPTIMIZED | CORINFO_FLG_SWITCHED_TO_MIN_OPT))
6700     {
6701         PrepareCodeConfig *config = GetThread()->GetCurrentPrepareCodeConfig();
6702         if (config != nullptr)
6703         {
6704             if (attribs & CORINFO_FLG_SWITCHED_TO_MIN_OPT)
6705             {
6706                 _ASSERTE(!ftn->IsJitOptimizationDisabled());
6707                 config->SetJitSwitchedToMinOpt();
6708             }
6709 #ifdef FEATURE_TIERED_COMPILATION
6710             else if (attribs & CORINFO_FLG_SWITCHED_TO_OPTIMIZED)
6711             {
6712                 _ASSERTE(ftn->IsEligibleForTieredCompilation());
6713                 config->SetJitSwitchedToOptimized();
6714             }
6715 #endif
6716         }
6717     }
6718
6719     EE_TO_JIT_TRANSITION();
6720 }
6721
6722 /*********************************************************************/
6723
6724 void getMethodInfoILMethodHeaderHelper(
6725     COR_ILMETHOD_DECODER* header,
6726     CORINFO_METHOD_INFO* methInfo
6727     )
6728 {
6729     LIMITED_METHOD_CONTRACT;
6730
6731     methInfo->ILCode          = const_cast<BYTE*>(header->Code);
6732     methInfo->ILCodeSize      = header->GetCodeSize();
6733     methInfo->maxStack        = static_cast<unsigned short>(header->GetMaxStack());
6734     methInfo->EHcount         = static_cast<unsigned short>(header->EHCount());
6735
6736     methInfo->options         =
6737         (CorInfoOptions)((header->GetFlags() & CorILMethod_InitLocals) ? CORINFO_OPT_INIT_LOCALS : 0) ;
6738 }
6739
6740 mdToken FindGenericMethodArgTypeSpec(IMDInternalImport* pInternalImport)
6741 {
6742     STANDARD_VM_CONTRACT;
6743
6744     HENUMInternalHolder hEnumTypeSpecs(pInternalImport);
6745     mdToken token;
6746
6747     static const BYTE signature[] = { ELEMENT_TYPE_MVAR, 0 };
6748
6749     hEnumTypeSpecs.EnumAllInit(mdtTypeSpec);
6750     while (hEnumTypeSpecs.EnumNext(&token))
6751     {
6752         PCCOR_SIGNATURE pSig;
6753         ULONG cbSig;
6754         IfFailThrow(pInternalImport->GetTypeSpecFromToken(token, &pSig, &cbSig));
6755         if (cbSig == sizeof(signature) && memcmp(pSig, signature, cbSig) == 0)
6756             return token;
6757     }
6758
6759     COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6760 }
6761
6762 static void setILIntrinsicMethodInfo(CORINFO_METHOD_INFO* methInfo,uint8_t* ilcode, int ilsize, int maxstack)
6763 {
6764     methInfo->ILCode = ilcode;
6765     methInfo->ILCodeSize = ilsize;
6766     methInfo->maxStack = maxstack;
6767     methInfo->EHcount = 0;
6768     methInfo->options = (CorInfoOptions)0;
6769 }
6770
6771 /*********************************************************************
6772
6773 IL is the most efficient and portable way to implement certain low level methods
6774 in CoreLib. Unfortunately, there is no good way to link IL into CoreLib today.
6775 Until we find a good way to link IL into CoreLib, we will provide the IL implementation here.
6776
6777 - All IL intrinsincs are members of System.Runtime.CompilerServices.JitHelpers class
6778 - All IL intrinsincs should be kept very simple. Implement the minimal reusable version of
6779 unsafe construct and depend on inlining to do the rest.
6780 - The C# implementation of the IL intrinsic should be good enough for functionalily. Everything should work
6781 correctly (but slower) if the IL intrinsics are removed.
6782
6783 *********************************************************************/
6784
6785 bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
6786                                            CORINFO_METHOD_INFO * methInfo)
6787 {
6788     STANDARD_VM_CONTRACT;
6789
6790     _ASSERTE(CoreLibBinder::IsClass(ftn->GetMethodTable(), CLASS__UNSAFE));
6791
6792     mdMethodDef tk = ftn->GetMemberDef();
6793
6794     if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__AS_POINTER)->GetMemberDef())
6795     {
6796         // Return the argument that was passed in.
6797         static const BYTE ilcode[] =
6798         {
6799             CEE_LDARG_0,
6800             CEE_CONV_U,
6801             CEE_RET
6802         };
6803
6804         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 1);
6805
6806         return true;
6807     }
6808     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef() ||
6809              tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__OBJECT_AS)->GetMemberDef() ||
6810              tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__AS_REF_IN)->GetMemberDef())
6811     {
6812         // Return the argument that was passed in.
6813         static const BYTE ilcode[] =
6814         {
6815             CEE_LDARG_0,
6816             CEE_RET
6817         };
6818
6819         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 1);
6820
6821         return true;
6822     }
6823     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD)->GetMemberDef() ||
6824              tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_ADD)->GetMemberDef())
6825     {
6826         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
6827
6828         static const BYTE ilcode[] =
6829         {
6830             CEE_LDARG_0,
6831             CEE_LDARG_1,
6832             CEE_PREFIX1, (CEE_SIZEOF & 0xFF), (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6833             CEE_CONV_I,
6834             CEE_MUL,
6835             CEE_ADD,
6836             CEE_RET
6837         };
6838
6839         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
6840
6841         return true;
6842     }
6843     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INTPTR_ADD)->GetMemberDef() ||
6844              tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_UINTPTR_ADD)->GetMemberDef())
6845     {
6846         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
6847
6848         static const BYTE ilcode[] =
6849         {
6850             CEE_LDARG_0,
6851             CEE_LDARG_1,
6852             CEE_PREFIX1, (CEE_SIZEOF & 0xFF), (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6853             CEE_MUL,
6854             CEE_ADD,
6855             CEE_RET
6856         };
6857
6858         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
6859
6860         return true;
6861     }
6862     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INTPTR_ADD_BYTE_OFFSET)->GetMemberDef() ||
6863         tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_UINTPTR_ADD_BYTE_OFFSET)->GetMemberDef())
6864     {
6865         static const BYTE ilcode[] =
6866         {
6867             CEE_LDARG_0,
6868             CEE_LDARG_1,
6869             CEE_ADD,
6870             CEE_RET
6871         };
6872
6873         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
6874
6875         return true;
6876     }
6877     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_ARE_SAME)->GetMemberDef())
6878     {
6879         // Compare the two arguments
6880         static const BYTE ilcode[] =
6881         {
6882             CEE_LDARG_0,
6883             CEE_LDARG_1,
6884             CEE_PREFIX1, (CEE_CEQ & 0xFF),
6885             CEE_RET
6886         };
6887
6888         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
6889
6890         return true;
6891     }
6892     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_BYREF_COPY)->GetMemberDef() ||
6893         tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_PTR_COPY)->GetMemberDef())
6894     {
6895         _ASSERTE(ftn->HasMethodInstantiation());
6896         Instantiation inst = ftn->GetMethodInstantiation();
6897         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
6898         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
6899
6900         static const BYTE ilcode[] =
6901         {
6902             CEE_LDARG_0,
6903             CEE_LDARG_1,
6904             CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6905             CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6906             CEE_RET
6907         };
6908
6909         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
6910
6911         return true;
6912     }
6913     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_COPY_BLOCK)->GetMemberDef() ||
6914         tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_COPY_BLOCK)->GetMemberDef())
6915     {
6916         static const BYTE ilcode[] =
6917         {
6918             CEE_LDARG_0,
6919             CEE_LDARG_1,
6920             CEE_LDARG_2,
6921             CEE_PREFIX1, (CEE_CPBLK & 0xFF),
6922             CEE_RET
6923         };
6924
6925         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
6926
6927         return true;
6928     }
6929     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_COPY_BLOCK_UNALIGNED)->GetMemberDef() ||
6930         tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_COPY_BLOCK_UNALIGNED)->GetMemberDef())
6931     {
6932         static const BYTE ilcode[] =
6933         {
6934             CEE_LDARG_0,
6935             CEE_LDARG_1,
6936             CEE_LDARG_2,
6937             CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 0x01,
6938             CEE_PREFIX1, (CEE_CPBLK & 0xFF),
6939             CEE_RET
6940         };
6941
6942         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
6943
6944         return true;
6945     }
6946     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_GREATER_THAN)->GetMemberDef())
6947     {
6948         // Compare the two arguments
6949         static const BYTE ilcode[] =
6950         {
6951             CEE_LDARG_0,
6952             CEE_LDARG_1,
6953             CEE_PREFIX1, (CEE_CGT_UN & 0xFF),
6954             CEE_RET
6955         };
6956
6957         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
6958
6959         return true;
6960     }
6961     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_LESS_THAN)->GetMemberDef())
6962     {
6963         // Compare the two arguments
6964         static const BYTE ilcode[] =
6965         {
6966             CEE_LDARG_0,
6967             CEE_LDARG_1,
6968             CEE_PREFIX1, (CEE_CLT_UN & 0xFF),
6969             CEE_RET
6970         };
6971
6972         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
6973
6974         return true;
6975     }
6976     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_NULLREF)->GetMemberDef())
6977     {
6978         static const BYTE ilcode[] =
6979         {
6980             CEE_LDC_I4_0,
6981             CEE_CONV_U,
6982             CEE_RET
6983         };
6984
6985         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 1);
6986
6987         return true;
6988     }
6989     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_NULL)->GetMemberDef())
6990     {
6991         // 'ldnull' opcode would produce type o, and we can't compare & against o (ECMA-335, Table III.4).
6992         // However, we can compare & against native int, so we'll use that instead.
6993
6994         static const BYTE ilcode[] =
6995         {
6996             CEE_LDARG_0,
6997             CEE_LDC_I4_0,
6998             CEE_CONV_U,
6999             CEE_PREFIX1, (CEE_CEQ & 0xFF),
7000             CEE_RET
7001         };
7002
7003         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7004
7005         return true;
7006     }
7007     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INIT_BLOCK)->GetMemberDef() ||
7008             tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_INIT_BLOCK)->GetMemberDef())
7009     {
7010         static const BYTE ilcode[] =
7011         {
7012             CEE_LDARG_0,
7013             CEE_LDARG_1,
7014             CEE_LDARG_2,
7015             CEE_PREFIX1, (CEE_INITBLK & 0xFF),
7016             CEE_RET
7017         };
7018
7019         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
7020
7021         return true;
7022     }
7023     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INIT_BLOCK_UNALIGNED)->GetMemberDef() ||
7024             tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_INIT_BLOCK_UNALIGNED)->GetMemberDef())
7025     {
7026         static const BYTE ilcode[] =
7027         {
7028             CEE_LDARG_0,
7029             CEE_LDARG_1,
7030             CEE_LDARG_2,
7031             CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 0x01,
7032             CEE_PREFIX1, (CEE_INITBLK & 0xFF),
7033             CEE_RET
7034         };
7035
7036         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
7037
7038         return true;
7039     }
7040     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_BYTE_OFFSET)->GetMemberDef())
7041     {
7042         static const BYTE ilcode[] =
7043         {
7044             CEE_LDARG_1,
7045             CEE_LDARG_0,
7046             CEE_SUB,
7047             CEE_RET
7048         };
7049
7050         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7051
7052         return true;
7053     }
7054     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_READ_UNALIGNED)->GetMemberDef() ||
7055              tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_READ_UNALIGNED)->GetMemberDef())
7056     {
7057         _ASSERTE(ftn->HasMethodInstantiation());
7058         Instantiation inst = ftn->GetMethodInstantiation();
7059         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7060         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7061
7062         static const BYTE ilcode[] =
7063         {
7064             CEE_LDARG_0,
7065             CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
7066             CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7067             CEE_RET
7068         };
7069
7070         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7071
7072         return true;
7073     }
7074     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_WRITE_UNALIGNED)->GetMemberDef() ||
7075              tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_WRITE_UNALIGNED)->GetMemberDef())
7076     {
7077         _ASSERTE(ftn->HasMethodInstantiation());
7078         Instantiation inst = ftn->GetMethodInstantiation();
7079         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7080         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7081
7082         static const BYTE ilcode[] =
7083         {
7084             CEE_LDARG_0,
7085             CEE_LDARG_1,
7086             CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
7087             CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7088             CEE_RET
7089         };
7090
7091         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7092
7093         return true;
7094     }
7095     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__READ)->GetMemberDef())
7096     {
7097         _ASSERTE(ftn->HasMethodInstantiation());
7098         Instantiation inst = ftn->GetMethodInstantiation();
7099         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7100         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7101
7102         static const BYTE ilcode[] =
7103         {
7104             CEE_LDARG_0,
7105             CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7106             CEE_RET
7107         };
7108
7109         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7110
7111         return true;
7112     }
7113     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__SKIPINIT)->GetMemberDef())
7114     {
7115         static const BYTE ilcode[] =
7116         {
7117             CEE_RET
7118         };
7119
7120         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 0);
7121
7122         return true;
7123     }
7124     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INT_SUBTRACT)->GetMemberDef() ||
7125              tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_INT_SUBTRACT)->GetMemberDef())
7126     {
7127         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7128
7129         static const BYTE ilcode[] =
7130         {
7131             CEE_LDARG_0,
7132             CEE_LDARG_1,
7133             CEE_PREFIX1, (CEE_SIZEOF & 0xFF), (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7134             CEE_CONV_I,
7135             CEE_MUL,
7136             CEE_SUB,
7137             CEE_RET
7138         };
7139
7140         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
7141
7142         return true;
7143     }
7144     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INTPTR_SUBTRACT)->GetMemberDef() ||
7145              tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_UINTPTR_SUBTRACT)->GetMemberDef())
7146     {
7147         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7148
7149         static const BYTE ilcode[] =
7150         {
7151             CEE_LDARG_0,
7152             CEE_LDARG_1,
7153             CEE_PREFIX1, (CEE_SIZEOF & 0xFF), (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7154             CEE_MUL,
7155             CEE_SUB,
7156             CEE_RET
7157         };
7158
7159         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
7160
7161         return true;
7162     }
7163     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INTPTR_SUBTRACT_BYTE_OFFSET)->GetMemberDef() ||
7164         tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_UINTPTR_SUBTRACT_BYTE_OFFSET)->GetMemberDef())
7165     {
7166         static const BYTE ilcode[] =
7167         {
7168             CEE_LDARG_0,
7169             CEE_LDARG_1,
7170             CEE_SUB,
7171             CEE_RET
7172         };
7173
7174         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7175
7176         return true;
7177     }
7178     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__WRITE)->GetMemberDef())
7179     {
7180         _ASSERTE(ftn->HasMethodInstantiation());
7181         Instantiation inst = ftn->GetMethodInstantiation();
7182         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7183         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7184
7185         static const BYTE ilcode[] =
7186         {
7187             CEE_LDARG_0,
7188             CEE_LDARG_1,
7189             CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7190             CEE_RET
7191         };
7192
7193         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7194
7195         return true;
7196     }
7197     else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__UNBOX)->GetMemberDef())
7198     {
7199         _ASSERTE(ftn->HasMethodInstantiation());
7200         Instantiation inst = ftn->GetMethodInstantiation();
7201         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7202         mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7203
7204         static const BYTE ilcode[] =
7205         {
7206             CEE_LDARG_0,
7207             CEE_UNBOX, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7208             CEE_RET
7209         };
7210
7211         setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7212
7213         return true;
7214     }
7215
7216     return false;
7217 }
7218
7219 bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn,
7220                                                 CORINFO_METHOD_INFO * methInfo)
7221 {
7222     STANDARD_VM_CONTRACT;
7223
7224     _ASSERTE(CoreLibBinder::IsClass(ftn->GetMethodTable(), CLASS__INTERLOCKED));
7225
7226     // We are only interested if ftn's token and CompareExchange<T> token match
7227     if (ftn->GetMemberDef() != CoreLibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_T)->GetMemberDef())
7228         return false;
7229
7230     // Get MethodDesc for non-generic System.Threading.Interlocked.CompareExchange()
7231     MethodDesc* cmpxchgObject = CoreLibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_OBJECT);
7232
7233     // Setup up the body of the method
7234     static BYTE il[] = {
7235                           CEE_LDARG_0,
7236                           CEE_LDARG_1,
7237                           CEE_LDARG_2,
7238                           CEE_CALL,0,0,0,0,
7239                           CEE_RET
7240                         };
7241
7242     // Get the token for non-generic System.Threading.Interlocked.CompareExchange(), and patch [target]
7243     mdMethodDef cmpxchgObjectToken = cmpxchgObject->GetMemberDef();
7244     il[4] = (BYTE)((int)cmpxchgObjectToken >> 0);
7245     il[5] = (BYTE)((int)cmpxchgObjectToken >> 8);
7246     il[6] = (BYTE)((int)cmpxchgObjectToken >> 16);
7247     il[7] = (BYTE)((int)cmpxchgObjectToken >> 24);
7248
7249     // Initialize methInfo
7250     methInfo->ILCode = const_cast<BYTE*>(il);
7251     methInfo->ILCodeSize = sizeof(il);
7252     methInfo->maxStack = 3;
7253     methInfo->EHcount = 0;
7254     methInfo->options = (CorInfoOptions)0;
7255
7256     return true;
7257 }
7258
7259 bool IsBitwiseEquatable(TypeHandle typeHandle, MethodTable * methodTable)
7260 {
7261     if (!methodTable->IsValueType() ||
7262         !CanCompareBitsOrUseFastGetHashCode(methodTable))
7263     {
7264         return false;
7265     }
7266
7267     // CanCompareBitsOrUseFastGetHashCode checks for an object.Equals override.
7268     // We also need to check for an IEquatable<T> implementation.
7269     Instantiation inst(&typeHandle, 1);
7270     if (typeHandle.CanCastTo(TypeHandle(CoreLibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(inst)))
7271     {
7272         return false;
7273     }
7274
7275     return true;
7276 }
7277
7278 bool getILIntrinsicImplementationForRuntimeHelpers(MethodDesc * ftn,
7279     CORINFO_METHOD_INFO * methInfo)
7280 {
7281     STANDARD_VM_CONTRACT;
7282
7283     _ASSERTE(CoreLibBinder::IsClass(ftn->GetMethodTable(), CLASS__RUNTIME_HELPERS));
7284
7285     mdMethodDef tk = ftn->GetMemberDef();
7286
7287     if (tk == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_REFERENCE_OR_CONTAINS_REFERENCES)->GetMemberDef())
7288     {
7289         _ASSERTE(ftn->HasMethodInstantiation());
7290         Instantiation inst = ftn->GetMethodInstantiation();
7291
7292         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7293         TypeHandle typeHandle = inst[0];
7294         MethodTable * methodTable = typeHandle.GetMethodTable();
7295
7296         static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
7297         static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };
7298
7299         if (!methodTable->IsValueType() || methodTable->ContainsPointers())
7300         {
7301             methInfo->ILCode = const_cast<BYTE*>(returnTrue);
7302         }
7303         else
7304         {
7305             methInfo->ILCode = const_cast<BYTE*>(returnFalse);
7306         }
7307
7308         methInfo->ILCodeSize = sizeof(returnTrue);
7309         methInfo->maxStack = 1;
7310         methInfo->EHcount = 0;
7311         methInfo->options = (CorInfoOptions)0;
7312         return true;
7313     }
7314
7315     if (tk == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_BITWISE_EQUATABLE)->GetMemberDef())
7316     {
7317         _ASSERTE(ftn->HasMethodInstantiation());
7318         Instantiation inst = ftn->GetMethodInstantiation();
7319
7320         _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7321         TypeHandle typeHandle = inst[0];
7322         MethodTable * methodTable = typeHandle.GetMethodTable();
7323
7324         static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
7325         static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };
7326
7327         // Ideally we could detect automatically whether a type is trivially equatable
7328         // (i.e., its operator == could be implemented via memcmp). The best we can do
7329         // for now is hardcode a list of known supported types and then also include anything
7330         // that doesn't provide its own object.Equals override / IEquatable<T> implementation.
7331         // n.b. This doesn't imply that the type's CompareTo method can be memcmp-implemented,
7332         // as a method like CompareTo may need to take a type's signedness into account.
7333
7334         if (methodTable == CoreLibBinder::GetClass(CLASS__BOOLEAN)
7335             || methodTable == CoreLibBinder::GetClass(CLASS__BYTE)
7336             || methodTable == CoreLibBinder::GetClass(CLASS__SBYTE)
7337             || methodTable == CoreLibBinder::GetClass(CLASS__CHAR)
7338             || methodTable == CoreLibBinder::GetClass(CLASS__INT16)
7339             || methodTable == CoreLibBinder::GetClass(CLASS__UINT16)
7340             || methodTable == CoreLibBinder::GetClass(CLASS__INT32)
7341             || methodTable == CoreLibBinder::GetClass(CLASS__UINT32)
7342             || methodTable == CoreLibBinder::GetClass(CLASS__INT64)
7343             || methodTable == CoreLibBinder::GetClass(CLASS__UINT64)
7344             || methodTable == CoreLibBinder::GetClass(CLASS__INTPTR)
7345             || methodTable == CoreLibBinder::GetClass(CLASS__UINTPTR)
7346             || methodTable == CoreLibBinder::GetClass(CLASS__RUNE)
7347             || methodTable->IsEnum()
7348             || IsBitwiseEquatable(typeHandle, methodTable))
7349         {
7350             methInfo->ILCode = const_cast<BYTE*>(returnTrue);
7351         }
7352         else
7353         {
7354             methInfo->ILCode = const_cast<BYTE*>(returnFalse);
7355         }
7356
7357         methInfo->ILCodeSize = sizeof(returnTrue);
7358         methInfo->maxStack = 1;
7359         methInfo->EHcount = 0;
7360         methInfo->options = (CorInfoOptions)0;
7361         return true;
7362     }
7363
7364     if (tk == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__GET_METHOD_TABLE)->GetMemberDef())
7365     {
7366         mdToken tokRawData = CoreLibBinder::GetField(FIELD__RAW_DATA__DATA)->GetMemberDef();
7367
7368         // In the CLR, an object is laid out as follows.
7369         // [ object_header || MethodTable* (64-bit pointer) || instance_data ]
7370         //                    ^                                ^-- ref <theObj>.firstField points here
7371         //                    `-- <theObj> reference (type O) points here
7372         //
7373         // So essentially what we want to do is to turn an object reference (type O) into a
7374         // native int&, then dereference it to get the MethodTable*. (Essentially, an object
7375         // reference is a MethodTable**.) Per ECMA-335, Sec. III.1.5, we can add
7376         // (but not subtract) a & and an int32 to produce a &. So we'll get a reference to
7377         // <theObj>.firstField (type &), then back up one pointer length to get a value of
7378         // essentially type (MethodTable*)&. Both of these are legal GC-trackable references
7379         // to <theObj>, regardless of <theObj>'s actual length.
7380
7381         static BYTE ilcode[] = { CEE_LDARG_0,         // stack contains [ O ] = <theObj>
7382                                  CEE_LDFLDA,0,0,0,0,  // stack contains [ & ] = ref <theObj>.firstField
7383                                  CEE_LDC_I4_S,(BYTE)(-TARGET_POINTER_SIZE), // stack contains [ &, int32 ] = -IntPtr.Size
7384                                  CEE_ADD,             // stack contains [ & ] = ref <theObj>.methodTablePtr
7385                                  CEE_LDIND_I,         // stack contains [ native int ] = <theObj>.methodTablePtr
7386                                  CEE_RET };
7387
7388         ilcode[2] = (BYTE)(tokRawData);
7389         ilcode[3] = (BYTE)(tokRawData >> 8);
7390         ilcode[4] = (BYTE)(tokRawData >> 16);
7391         ilcode[5] = (BYTE)(tokRawData >> 24);
7392
7393         methInfo->ILCode = const_cast<BYTE*>(ilcode);
7394         methInfo->ILCodeSize = sizeof(ilcode);
7395         methInfo->maxStack = 2;
7396         methInfo->EHcount = 0;
7397         methInfo->options = (CorInfoOptions)0;
7398         return true;
7399     }
7400
7401     if (tk == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__ENUM_EQUALS)->GetMemberDef())
7402     {
7403         // Normally we would follow the above pattern and unconditionally replace the IL,
7404         // relying on generic type constraints to guarantee that it will only ever be instantiated
7405         // on the type/size of argument we expect.
7406         //
7407         // However C#/CLR does not support restricting a generic type to be an Enum, so the best
7408         // we can do is constrain it to be a value type.  This is fine for run time, since we only
7409         // ever create instantiations on 4 byte or less Enums. But during NGen we may compile instantiations
7410         // on other value types (to be specific, every value type instatiation of EqualityComparer
7411         // because of its TypeDependencyAttribute; here again we would like to restrict this to
7412         // 4 byte or less Enums but cannot).
7413         //
7414         // This IL is invalid for those instantiations, and replacing it would lead to all sorts of
7415         // errors at NGen time.  So we only replace it for instantiations where it would be valid,
7416         // leaving the others, which we should never execute, with the C# implementation of throwing.
7417
7418         _ASSERTE(ftn->HasMethodInstantiation());
7419         Instantiation inst = ftn->GetMethodInstantiation();
7420
7421         _ASSERTE(inst.GetNumArgs() == 1);
7422         CorElementType et = inst[0].GetVerifierCorElementType();
7423         if (et == ELEMENT_TYPE_I4 ||
7424             et == ELEMENT_TYPE_U4 ||
7425             et == ELEMENT_TYPE_I2 ||
7426             et == ELEMENT_TYPE_U2 ||
7427             et == ELEMENT_TYPE_I1 ||
7428             et == ELEMENT_TYPE_U1 ||
7429             et == ELEMENT_TYPE_I8 ||
7430             et == ELEMENT_TYPE_U8)
7431         {
7432             static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CEQ & 0xFF), CEE_RET };
7433             methInfo->ILCode = const_cast<BYTE*>(ilcode);
7434             methInfo->ILCodeSize = sizeof(ilcode);
7435             methInfo->maxStack = 2;
7436             methInfo->EHcount = 0;
7437             methInfo->options = (CorInfoOptions)0;
7438             return true;
7439         }
7440     }
7441     else if (tk == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__ENUM_COMPARE_TO)->GetMemberDef())
7442     {
7443         // The comment above on why this is not an unconditional replacement.  This case handles
7444         // Enums backed by 8 byte values.
7445
7446         _ASSERTE(ftn->HasMethodInstantiation());
7447         Instantiation inst = ftn->GetMethodInstantiation();
7448
7449         _ASSERTE(inst.GetNumArgs() == 1);
7450         CorElementType et = inst[0].GetVerifierCorElementType();
7451         if (et == ELEMENT_TYPE_I4 ||
7452             et == ELEMENT_TYPE_U4 ||
7453             et == ELEMENT_TYPE_I2 ||
7454             et == ELEMENT_TYPE_U2 ||
7455             et == ELEMENT_TYPE_I1 ||
7456             et == ELEMENT_TYPE_U1 ||
7457             et == ELEMENT_TYPE_I8 ||
7458             et == ELEMENT_TYPE_U8)
7459         {
7460             static BYTE ilcode[8][9];
7461
7462             TypeHandle thUnderlyingType = CoreLibBinder::GetElementType(et);
7463
7464             TypeHandle thIComparable = TypeHandle(CoreLibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(Instantiation(&thUnderlyingType, 1));
7465
7466             MethodDesc* pCompareToMD = thUnderlyingType.AsMethodTable()->GetMethodDescForInterfaceMethod(
7467                 thIComparable, CoreLibBinder::GetMethod(METHOD__ICOMPARABLEGENERIC__COMPARE_TO), TRUE /* throwOnConflict */);
7468
7469             // Call CompareTo method on the primitive type
7470             int tokCompareTo = pCompareToMD->GetMemberDef();
7471
7472             unsigned int index = (et - ELEMENT_TYPE_I1);
7473             _ASSERTE(index < ARRAY_SIZE(ilcode));
7474
7475             ilcode[index][0] = CEE_LDARGA_S;
7476             ilcode[index][1] = 0;
7477             ilcode[index][2] = CEE_LDARG_1;
7478             ilcode[index][3] = CEE_CALL;
7479             ilcode[index][4] = (BYTE)(tokCompareTo);
7480             ilcode[index][5] = (BYTE)(tokCompareTo >> 8);
7481             ilcode[index][6] = (BYTE)(tokCompareTo >> 16);
7482             ilcode[index][7] = (BYTE)(tokCompareTo >> 24);
7483             ilcode[index][8] = CEE_RET;
7484
7485             methInfo->ILCode = const_cast<BYTE*>(ilcode[index]);
7486             methInfo->ILCodeSize = sizeof(ilcode[index]);
7487             methInfo->maxStack = 2;
7488             methInfo->EHcount = 0;
7489             methInfo->options = (CorInfoOptions)0;
7490             return true;
7491         }
7492     }
7493
7494     return false;
7495 }
7496
7497 bool getILIntrinsicImplementationForActivator(MethodDesc* ftn,
7498     CORINFO_METHOD_INFO* methInfo,
7499     SigPointer* pSig)
7500 {
7501     STANDARD_VM_CONTRACT;
7502
7503     _ASSERTE(CoreLibBinder::IsClass(ftn->GetMethodTable(), CLASS__ACTIVATOR));
7504
7505     // We are only interested if ftn's token and CreateInstance<T> token match
7506     if (ftn->GetMemberDef() != CoreLibBinder::GetMethod(METHOD__ACTIVATOR__CREATE_INSTANCE_OF_T)->GetMemberDef())
7507         return false;
7508
7509     _ASSERTE(ftn->HasMethodInstantiation());
7510     Instantiation inst = ftn->GetMethodInstantiation();
7511
7512     _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7513     TypeHandle typeHandle = inst[0];
7514     MethodTable* methodTable = typeHandle.GetMethodTable();
7515
7516     if (!methodTable->IsValueType() || methodTable->HasDefaultConstructor())
7517         return false;
7518
7519     // Replace the body with implementation that just returns "default"
7520     MethodDesc* createDefaultInstance = CoreLibBinder::GetMethod(METHOD__ACTIVATOR__CREATE_DEFAULT_INSTANCE_OF_T);
7521     COR_ILMETHOD_DECODER header(createDefaultInstance->GetILHeader(FALSE), createDefaultInstance->GetMDImport(), NULL);
7522     getMethodInfoILMethodHeaderHelper(&header, methInfo);
7523     *pSig = SigPointer(header.LocalVarSig, header.cbLocalVarSig);
7524
7525     return true;
7526 }
7527
7528 //---------------------------------------------------------------------------------------
7529 //
7530
7531 class MethodInfoHelperContext final
7532 {
7533 public:
7534     MethodDesc* Method;
7535     COR_ILMETHOD_DECODER* Header;
7536     DynamicResolver* TransientResolver;
7537
7538     MethodInfoHelperContext(MethodDesc* pMD, _In_opt_ COR_ILMETHOD_DECODER* header = NULL)
7539         : Method{ pMD }
7540         , Header{ header }
7541         , TransientResolver{}
7542     {
7543         LIMITED_METHOD_CONTRACT;
7544         _ASSERTE(pMD != NULL);
7545     }
7546
7547     MethodInfoHelperContext(const MethodInfoHelperContext&) = delete;
7548     MethodInfoHelperContext(MethodInfoHelperContext&& other) = delete;
7549
7550     ~MethodInfoHelperContext()
7551     {
7552         STANDARD_VM_CONTRACT;
7553         delete TransientResolver;
7554     }
7555
7556     MethodInfoHelperContext& operator=(const MethodInfoHelperContext&) = delete;
7557     MethodInfoHelperContext& operator=(MethodInfoHelperContext&& other) = delete;
7558
7559     bool HasTransientMethodDetails() const
7560     {
7561         LIMITED_METHOD_CONTRACT;
7562         return TransientResolver != NULL;
7563     }
7564
7565     CORINFO_MODULE_HANDLE CreateScopeHandle() const
7566     {
7567         LIMITED_METHOD_CONTRACT;
7568         _ASSERTE(HasTransientMethodDetails());
7569         return MakeDynamicScope(TransientResolver);
7570     }
7571
7572     // This operation transfers any ownership to a
7573     // TransientMethodDetails instance.
7574     TransientMethodDetails CreateTransientMethodDetails()
7575     {
7576         STANDARD_VM_CONTRACT;
7577         _ASSERTE(HasTransientMethodDetails());
7578
7579         CORINFO_MODULE_HANDLE handle = CreateScopeHandle();
7580         TransientResolver = NULL;
7581         return TransientMethodDetails{ Method, Header, handle };
7582     }
7583
7584     void UpdateWith(const TransientMethodDetails& details)
7585     {
7586         LIMITED_METHOD_CONTRACT;
7587         Header = details.Header;
7588         TransientResolver = details.Scope != NULL ? GetDynamicResolver(details.Scope) : NULL;
7589     }
7590
7591     void TakeOwnership(TransientMethodDetails details)
7592     {
7593         LIMITED_METHOD_CONTRACT;
7594         UpdateWith(details);
7595
7596         // Default initialize local instance since we are
7597         // taking ownership of the transient method details.
7598         details = {};
7599     }
7600 };
7601
7602 static void getMethodInfoHelper(
7603     MethodInfoHelperContext& cxt,
7604     CORINFO_METHOD_INFO* methInfo,
7605     CORINFO_CONTEXT_HANDLE exactContext = NULL)
7606 {
7607     STANDARD_VM_CONTRACT;
7608     _ASSERTE(methInfo != NULL);
7609
7610     MethodDesc* ftn      = cxt.Method;
7611     methInfo->ftn        = (CORINFO_METHOD_HANDLE)ftn;
7612     methInfo->regionKind = CORINFO_REGION_JIT;
7613
7614     CORINFO_MODULE_HANDLE scopeHnd = NULL;
7615
7616     /* Grab information from the IL header */
7617     PCCOR_SIGNATURE pLocalSig   = NULL;
7618     uint32_t        cbLocalSig  = 0;
7619
7620     // Having a header means there is backing IL for the method.
7621     if (NULL != cxt.Header)
7622     {
7623         scopeHnd = cxt.HasTransientMethodDetails()
7624             ? cxt.CreateScopeHandle()
7625             : GetScopeHandle(ftn);
7626         bool fILIntrinsic = false;
7627
7628         MethodTable * pMT  = ftn->GetMethodTable();
7629
7630         if (ftn->IsIntrinsic())
7631         {
7632             if (CoreLibBinder::IsClass(pMT, CLASS__UNSAFE))
7633             {
7634                 fILIntrinsic = getILIntrinsicImplementationForUnsafe(ftn, methInfo);
7635             }
7636             else if (CoreLibBinder::IsClass(pMT, CLASS__INTERLOCKED))
7637             {
7638                 fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo);
7639             }
7640             else if (CoreLibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS))
7641             {
7642                 fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo);
7643             }
7644             else if (CoreLibBinder::IsClass(pMT, CLASS__ACTIVATOR))
7645             {
7646                 SigPointer localSig;
7647                 fILIntrinsic = getILIntrinsicImplementationForActivator(ftn, methInfo, &localSig);
7648                 if (fILIntrinsic)
7649                 {
7650                     localSig.GetSignature(&pLocalSig, &cbLocalSig);
7651                 }
7652             }
7653         }
7654
7655         if (!fILIntrinsic)
7656         {
7657             getMethodInfoILMethodHeaderHelper(cxt.Header, methInfo);
7658             pLocalSig = cxt.Header->LocalVarSig;
7659             cbLocalSig = cxt.Header->cbLocalVarSig;
7660         }
7661     }
7662     else if (ftn->IsDynamicMethod())
7663     {
7664         DynamicResolver* pResolver = ftn->AsDynamicMethodDesc()->GetResolver();
7665         scopeHnd = MakeDynamicScope(pResolver);
7666
7667         unsigned int EHCount;
7668         methInfo->ILCode = pResolver->GetCodeInfo(&methInfo->ILCodeSize,
7669                                                   &methInfo->maxStack,
7670                                                   &methInfo->options,
7671                                                   &EHCount);
7672         methInfo->EHcount = (unsigned short)EHCount;
7673         SigPointer localSig = pResolver->GetLocalSig();
7674         localSig.GetSignature(&pLocalSig, &cbLocalSig);
7675     }
7676     else
7677     {
7678         if (!ftn->TryGenerateUnsafeAccessor(&cxt.TransientResolver, &cxt.Header))
7679             ThrowHR(COR_E_BADIMAGEFORMAT);
7680
7681         scopeHnd = cxt.CreateScopeHandle();
7682
7683         _ASSERTE(cxt.Header != NULL);
7684         getMethodInfoILMethodHeaderHelper(cxt.Header, methInfo);
7685         pLocalSig = cxt.Header->LocalVarSig;
7686         cbLocalSig = cxt.Header->cbLocalVarSig;
7687     }
7688
7689     _ASSERTE(scopeHnd != NULL);
7690     methInfo->scope = scopeHnd;
7691     methInfo->options = (CorInfoOptions)(((UINT32)methInfo->options) |
7692                             ((ftn->AcquiresInstMethodTableFromThis() ? CORINFO_GENERICS_CTXT_FROM_THIS : 0) |
7693                              (ftn->RequiresInstMethodTableArg() ? CORINFO_GENERICS_CTXT_FROM_METHODTABLE : 0) |
7694                              (ftn->RequiresInstMethodDescArg() ? CORINFO_GENERICS_CTXT_FROM_METHODDESC : 0)));
7695
7696     // EEJitManager::ResolveEHClause and CrawlFrame::GetExactGenericInstantiations
7697     // need to be able to get to CORINFO_GENERICS_CTXT_MASK if there are any
7698     // catch clauses like "try {} catch(MyException<T> e) {}".
7699     // Such constructs are rare, and having to extend the lifetime of variable
7700     // for such cases is reasonable
7701
7702     if (methInfo->options & CORINFO_GENERICS_CTXT_MASK)
7703     {
7704 #if defined(PROFILING_SUPPORTED)
7705         BOOL fProfilerRequiresGenericsContextForEnterLeave = FALSE;
7706         {
7707             BEGIN_PROFILER_CALLBACK(CORProfilerPresent());
7708             if ((&g_profControlBlock)->RequiresGenericsContextForEnterLeave())
7709             {
7710                 fProfilerRequiresGenericsContextForEnterLeave = TRUE;
7711             }
7712             END_PROFILER_CALLBACK();
7713         }
7714         if (fProfilerRequiresGenericsContextForEnterLeave)
7715         {
7716             methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7717         }
7718 #endif // defined(PROFILING_SUPPORTED)
7719     }
7720
7721     PCCOR_SIGNATURE pSig = NULL;
7722     DWORD           cbSig = 0;
7723     ftn->GetSig(&pSig, &cbSig);
7724
7725     SigTypeContext context;
7726
7727     if (exactContext == NULL || exactContext == METHOD_BEING_COMPILED_CONTEXT())
7728     {
7729         SigTypeContext::InitTypeContext(ftn, &context);
7730     }
7731     else if (((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD)
7732     {
7733         MethodDesc* contextMD = (MethodDesc*)((size_t)exactContext & ~CORINFO_CONTEXTFLAGS_MASK);
7734         SigTypeContext::InitTypeContext(contextMD, &context);
7735     }
7736     else
7737     {
7738         _ASSERT(((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS);
7739         TypeHandle th = TypeHandle((CORINFO_CLASS_HANDLE)((size_t)exactContext & ~CORINFO_CONTEXTFLAGS_MASK));
7740         SigTypeContext::InitTypeContext(th, &context);
7741     }
7742
7743     /* Fetch the method signature */
7744     // Type parameters in the signature should be instantiated according to the
7745     // class/method/array instantiation of ftnHnd
7746     ConvToJitSig(
7747         pSig,
7748         cbSig,
7749         methInfo->scope,
7750         mdTokenNil,
7751         &context,
7752         CONV_TO_JITSIG_FLAGS_NONE,
7753         &methInfo->args);
7754
7755     // Shared generic or static per-inst methods and shared methods on generic structs
7756     // take an extra argument representing their instantiation
7757     if (ftn->RequiresInstArg())
7758         methInfo->args.callConv = (CorInfoCallConv)(methInfo->args.callConv | CORINFO_CALLCONV_PARAMTYPE);
7759
7760     _ASSERTE((IsMdStatic(ftn->GetAttrs()) == 0) == ((methInfo->args.callConv & CORINFO_CALLCONV_HASTHIS) != 0));
7761
7762     /* And its local variables */
7763     // Type parameters in the signature should be instantiated according to the
7764     // class/method/array instantiation of ftnHnd
7765     ConvToJitSig(
7766         pLocalSig,
7767         cbLocalSig,
7768         methInfo->scope,
7769         mdTokenNil,
7770         &context,
7771         CONV_TO_JITSIG_FLAGS_LOCALSIG,
7772         &methInfo->locals);
7773 } // getMethodInfoHelper
7774
7775 //---------------------------------------------------------------------------------------
7776 //
7777 bool
7778 CEEInfo::getMethodInfo(
7779     CORINFO_METHOD_HANDLE ftnHnd,
7780     CORINFO_METHOD_INFO * methInfo,
7781     CORINFO_CONTEXT_HANDLE context)
7782 {
7783     CONTRACTL {
7784         THROWS;
7785         GC_TRIGGERS;
7786         MODE_PREEMPTIVE;
7787     } CONTRACTL_END;
7788
7789     bool result = false;
7790
7791     JIT_TO_EE_TRANSITION();
7792
7793     MethodDesc * ftn = GetMethod(ftnHnd);
7794
7795     // Get the IL header
7796     MethodInfoHelperContext cxt{ ftn };
7797     if (ftn->IsDynamicMethod())
7798     {
7799         getMethodInfoHelper(cxt, methInfo, context);
7800         result = true;
7801     }
7802     else if (!ftn->IsWrapperStub() && ftn->HasILHeader())
7803     {
7804         COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
7805         cxt.Header = &header;
7806         getMethodInfoHelper(cxt, methInfo, context);
7807         result = true;
7808     }
7809     else if (ftn->IsIL() && ftn->GetRVA() == 0)
7810     {
7811         // We will either find or create transient method details.
7812         _ASSERTE(!cxt.HasTransientMethodDetails());
7813
7814         // IL methods with no RVA indicate there is no implementation defined in metadata.
7815         // Check if we previously generated details/implementation for this method.
7816         TransientMethodDetails* detailsMaybe = NULL;
7817         if (FindTransientMethodDetails(ftn, &detailsMaybe))
7818             cxt.UpdateWith(*detailsMaybe);
7819
7820         getMethodInfoHelper(cxt, methInfo);
7821
7822         // If we have transient method details we need to handle
7823         // the lifetime of the details.
7824         if (cxt.HasTransientMethodDetails())
7825         {
7826             // If we didn't find transient details, but we have them
7827             // after getting method info, store them for cleanup.
7828             if (detailsMaybe == NULL)
7829                 AddTransientMethodDetails(cxt.CreateTransientMethodDetails());
7830
7831             // Reset the context because ownership has either been
7832             // transferred or was found in this instance.
7833             cxt.UpdateWith({});
7834         }
7835
7836         result = true;
7837     }
7838
7839     if (result)
7840     {
7841         LOG((LF_JIT, LL_INFO100000, "Getting method info (possible inline) %s::%s%s\n",
7842             ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
7843     }
7844
7845     EE_TO_JIT_TRANSITION();
7846
7847     return result;
7848 }
7849
7850 bool CEEInfo::haveSameMethodDefinition(
7851     CORINFO_METHOD_HANDLE meth1Hnd,
7852     CORINFO_METHOD_HANDLE meth2Hnd)
7853 {
7854     CONTRACTL {
7855         NOTHROW;
7856         GC_NOTRIGGER;
7857         MODE_PREEMPTIVE;
7858     } CONTRACTL_END;
7859
7860     bool result = false;
7861
7862     JIT_TO_EE_TRANSITION_LEAF();
7863
7864     MethodDesc* meth1 = GetMethod(meth1Hnd);
7865     MethodDesc* meth2 = GetMethod(meth2Hnd);
7866     result = meth1->HasSameMethodDefAs(meth2);
7867
7868     EE_TO_JIT_TRANSITION_LEAF();
7869
7870     return result;
7871 }
7872
7873 /*************************************************************
7874  * Check if the caller and calle are in the same assembly
7875  * i.e. do not inline across assemblies
7876  *************************************************************/
7877
7878 CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller,
7879                                   CORINFO_METHOD_HANDLE hCallee)
7880 {
7881     CONTRACTL {
7882         THROWS;
7883         GC_TRIGGERS;
7884         MODE_PREEMPTIVE;
7885     } CONTRACTL_END;
7886
7887     CorInfoInline result = INLINE_PASS;  // By default we pass.
7888                                          // Do not set pass in the rest of the method.
7889     const char *  szFailReason = NULL;   // for reportInlineDecision
7890
7891     JIT_TO_EE_TRANSITION();
7892
7893     // This does not work in the multi-threaded case
7894 #if 0
7895     // Caller should check this condition first
7896     _ASSERTE(!(CORINFO_FLG_DONT_INLINE & getMethodAttribsInternal(hCallee)));
7897 #endif
7898
7899     MethodDesc* pCaller = GetMethod(hCaller);
7900     MethodDesc* pCallee = GetMethod(hCallee);
7901
7902     if (pCallee->IsNoMetadata())
7903     {
7904         result = INLINE_FAIL;
7905         szFailReason = "Inlinee is NoMetadata";
7906         goto exit;
7907     }
7908
7909 #ifdef DEBUGGING_SUPPORTED
7910
7911     // If the callee wants debuggable code, don't allow it to be inlined
7912
7913     {
7914         // Combining the next two lines, and eliminating jitDebuggerFlags, leads to bad codegen in x86 Release builds using Visual C++ 19.00.24215.1.
7915         CORJIT_FLAGS jitDebuggerFlags = GetDebuggerCompileFlags(pCallee->GetModule(), CORJIT_FLAGS());
7916         if (jitDebuggerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE))
7917         {
7918             result = INLINE_NEVER;
7919             szFailReason = "Inlinee is debuggable";
7920             goto exit;
7921         }
7922     }
7923 #endif
7924
7925     // The original caller is the current method
7926     MethodDesc *  pOrigCaller;
7927     pOrigCaller = m_pMethodBeingCompiled;
7928     Module *      pOrigCallerModule;
7929     pOrigCallerModule = pOrigCaller->GetLoaderModule();
7930
7931     if (pCallee->IsNotInline())
7932     {
7933         result = INLINE_NEVER;
7934         szFailReason = "Inlinee is marked as no inline";
7935         goto exit;
7936     }
7937
7938     // Also check to see if the method requires a security object.  This means they call demand and
7939     // shouldn't be inlined.
7940     if (IsMdRequireSecObject(pCallee->GetAttrs()))
7941     {
7942         result = INLINE_NEVER;
7943         szFailReason = "Inlinee requires a security object (or contains StackCrawlMark)";
7944         goto exit;
7945     }
7946
7947     // If the method is MethodImpl'd by another method within the same type, then we have
7948     // an issue that the importer will import the wrong body. In this case, we'll just
7949     // disallow inlining because getFunctionEntryPoint will do the right thing.
7950     {
7951         MethodDesc  *pMDDecl = pCallee;
7952         MethodTable *pMT     = pMDDecl->GetMethodTable();
7953         MethodDesc  *pMDImpl = pMT->MapMethodDeclToMethodImpl(pMDDecl);
7954
7955         if (pMDDecl != pMDImpl)
7956         {
7957             result = INLINE_NEVER;
7958             szFailReason = "Inlinee is MethodImpl'd by another method within the same type";
7959             goto exit;
7960         }
7961     }
7962
7963 #ifdef PROFILING_SUPPORTED
7964     if (CORProfilerPresent())
7965     {
7966         // #rejit
7967         //
7968         // Currently the rejit path is the only path which sets this.
7969         // If we get more reasons to set this then we may need to change
7970         // the failure reason message or disambiguate them.
7971         if (!m_allowInlining)
7972         {
7973             result = INLINE_FAIL;
7974             szFailReason = "ReJIT request disabled inlining from caller";
7975             goto exit;
7976         }
7977
7978         // If the profiler has set a mask preventing inlining, always return
7979         // false to the jit.
7980         if (CORProfilerDisableInlining())
7981         {
7982             result = INLINE_FAIL;
7983             szFailReason = "Profiler disabled inlining globally";
7984             goto exit;
7985         }
7986
7987 #if defined(FEATURE_REJIT) && !defined(DACCESS_COMPILE)
7988         if (CORProfilerEnableRejit())
7989         {
7990             CodeVersionManager* pCodeVersionManager = pCallee->GetCodeVersionManager();
7991             CodeVersionManager::LockHolder codeVersioningLockHolder;
7992             ILCodeVersion ilVersion = pCodeVersionManager->GetActiveILCodeVersion(pCallee);
7993             if (ilVersion.GetRejitState() != ILCodeVersion::kStateActive || !ilVersion.HasDefaultIL())
7994             {
7995                 result = INLINE_FAIL;
7996                 szFailReason = "ReJIT methods cannot be inlined.";
7997                 goto exit;
7998             }
7999         }
8000 #endif // defined(FEATURE_REJIT) && !defined(DACCESS_COMPILE)
8001
8002         // If the profiler wishes to be notified of JIT events and the result from
8003         // the above tests will cause a function to be inlined, we need to tell the
8004         // profiler that this inlining is going to take place, and give them a
8005         // chance to prevent it.
8006         {
8007             BEGIN_PROFILER_CALLBACK(CORProfilerTrackJITInfo());
8008             if (pCaller->IsILStub() || pCallee->IsILStub())
8009             {
8010                 // do nothing
8011             }
8012             else
8013             {
8014                 BOOL fShouldInline;
8015                 HRESULT hr = (&g_profControlBlock)->JITInlining(
8016                     (FunctionID)pCaller,
8017                     (FunctionID)pCallee,
8018                     &fShouldInline);
8019
8020                 if (SUCCEEDED(hr) && !fShouldInline)
8021                 {
8022                     result = INLINE_FAIL;
8023                     szFailReason = "Profiler disabled inlining locally";
8024                     goto exit;
8025                 }
8026             }
8027             END_PROFILER_CALLBACK();
8028         }
8029     }
8030 #endif // PROFILING_SUPPORTED
8031
8032 exit: ;
8033
8034     EE_TO_JIT_TRANSITION();
8035
8036     if (dontInline(result))
8037     {
8038         // If you hit this assert, it means you added a new way to prevent inlining
8039         // without documenting it for ETW!
8040         _ASSERTE(szFailReason != NULL);
8041         reportInliningDecision(hCaller, hCallee, result, szFailReason);
8042     }
8043
8044     return result;
8045 }
8046
8047 void CEEInfo::beginInlining(CORINFO_METHOD_HANDLE inlinerHnd,
8048                             CORINFO_METHOD_HANDLE inlineeHnd)
8049 {
8050     // do nothing
8051 }
8052
8053 void CEEInfo::reportInliningDecision (CORINFO_METHOD_HANDLE inlinerHnd,
8054                                       CORINFO_METHOD_HANDLE inlineeHnd,
8055                                       CorInfoInline inlineResult,
8056                                       const char * reason)
8057 {
8058     STATIC_CONTRACT_THROWS;
8059     STATIC_CONTRACT_GC_TRIGGERS;
8060
8061     JIT_TO_EE_TRANSITION();
8062
8063 #ifdef _DEBUG
8064     if (LoggingOn(LF_JIT, LL_INFO100000))
8065     {
8066         SString currentMethodName;
8067         currentMethodName.AppendUTF8(m_pMethodBeingCompiled->GetModule()->GetPEAssembly()->GetSimpleName());
8068         currentMethodName.Append(L'/');
8069         TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled, TypeString::FormatBasic);
8070
8071         SString inlineeMethodName;
8072         if (GetMethod(inlineeHnd))
8073         {
8074             inlineeMethodName.AppendUTF8(GetMethod(inlineeHnd)->GetModule()->GetPEAssembly()->GetSimpleName());
8075             inlineeMethodName.Append(L'/');
8076             TypeString::AppendMethodInternal(inlineeMethodName, GetMethod(inlineeHnd), TypeString::FormatBasic);
8077         }
8078         else
8079         {
8080             inlineeMethodName.AppendASCII( "<null>" );
8081         }
8082
8083         SString inlinerMethodName;
8084         if (GetMethod(inlinerHnd))
8085         {
8086             inlinerMethodName.AppendUTF8(GetMethod(inlinerHnd)->GetModule()->GetPEAssembly()->GetSimpleName());
8087             inlinerMethodName.Append(L'/');
8088             TypeString::AppendMethodInternal(inlinerMethodName, GetMethod(inlinerHnd), TypeString::FormatBasic);
8089         }
8090         else
8091         {
8092             inlinerMethodName.AppendASCII("<null>");
8093         }
8094
8095         if (dontInline(inlineResult))
8096         {
8097             LOG((LF_JIT, LL_INFO100000,
8098                  "While compiling '%s', inline of '%s' into '%s' failed because: '%s'.\n",
8099                  currentMethodName.GetUTF8(), inlineeMethodName.GetUTF8(),
8100                  inlinerMethodName.GetUTF8(), reason));
8101         }
8102         else if(inlineResult == INLINE_PASS)
8103         {
8104             LOG((LF_JIT, LL_INFO100000, "While compiling '%s', inline of '%s' into '%s' succeeded.\n",
8105                  currentMethodName.GetUTF8(), inlineeMethodName.GetUTF8(),
8106                  inlinerMethodName.GetUTF8()));
8107
8108         }
8109     }
8110 #endif //_DEBUG
8111
8112     //I'm gonna duplicate this code because the format is slightly different.  And LoggingOn is debug only.
8113     if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
8114                                      TRACE_LEVEL_VERBOSE,
8115                                      CLR_JITTRACING_KEYWORD) &&
8116         (inlineResult <= INLINE_PASS)) // Only report pass, and failure inliner information. The various informative reports such as INLINE_CHECK_CAN_INLINE_SUCCESS are not to be reported via ETW
8117     {
8118         SString methodBeingCompiledNames[3];
8119         SString inlinerNames[3];
8120         SString inlineeNames[3];
8121         MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8122 #define GMI(pMD, strArray) \
8123         do { \
8124             if (pMD) { \
8125                 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8126             } else {  \
8127                 (strArray)[0].Set(W("<null>")); \
8128                 (strArray)[1].Set(W("<null>")); \
8129                 (strArray)[2].Set(W("<null>")); \
8130             } } while (0)
8131
8132         GMI(methodBeingCompiled, methodBeingCompiledNames);
8133         GMI(GetMethod(inlinerHnd), inlinerNames);
8134         GMI(GetMethod(inlineeHnd), inlineeNames);
8135 #undef GMI
8136         if (dontInline(inlineResult))
8137         {
8138             const char * str = (reason ? reason : "");
8139             SString strReason;
8140             strReason.SetUTF8(str);
8141
8142
8143             FireEtwMethodJitInliningFailed(methodBeingCompiledNames[0].GetUnicode(),
8144                                            methodBeingCompiledNames[1].GetUnicode(),
8145                                            methodBeingCompiledNames[2].GetUnicode(),
8146                                            inlinerNames[0].GetUnicode(),
8147                                            inlinerNames[1].GetUnicode(),
8148                                            inlinerNames[2].GetUnicode(),
8149                                            inlineeNames[0].GetUnicode(),
8150                                            inlineeNames[1].GetUnicode(),
8151                                            inlineeNames[2].GetUnicode(),
8152                                            inlineResult == INLINE_NEVER,
8153                                            strReason.GetUnicode(),
8154                                            GetClrInstanceId());
8155         }
8156         else if(inlineResult == INLINE_PASS)
8157         {
8158             FireEtwMethodJitInliningSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8159                                               methodBeingCompiledNames[1].GetUnicode(),
8160                                               methodBeingCompiledNames[2].GetUnicode(),
8161                                               inlinerNames[0].GetUnicode(),
8162                                               inlinerNames[1].GetUnicode(),
8163                                               inlinerNames[2].GetUnicode(),
8164                                               inlineeNames[0].GetUnicode(),
8165                                               inlineeNames[1].GetUnicode(),
8166                                               inlineeNames[2].GetUnicode(),
8167                                               GetClrInstanceId());
8168         }
8169
8170     }
8171
8172
8173 #if defined FEATURE_REJIT && !defined(DACCESS_COMPILE)
8174     if(inlineResult == INLINE_PASS)
8175     {
8176         // We don't want to track the chain of methods, so intentionally use m_pMethodBeingCompiled
8177         // to just track the methods that pCallee is eventually inlined in
8178         MethodDesc *pCallee = GetMethod(inlineeHnd);
8179         MethodDesc *pCaller = m_pMethodBeingCompiled;
8180         pCallee->GetModule()->AddInlining(pCaller, pCallee);
8181
8182         if (CORProfilerEnableRejit())
8183         {
8184             // If ReJIT is enabled, there is a chance that a race happened where the profiler
8185             // requested a ReJIT on a method, but before the ReJIT occurred an inlining happened.
8186             // If we end up reporting an inlining on a method with non-default IL it means the race
8187             // happened and we need to manually request ReJIT for it since it was missed.
8188             CodeVersionManager* pCodeVersionManager = pCallee->GetCodeVersionManager();
8189             CodeVersionManager::LockHolder codeVersioningLockHolder;
8190             ILCodeVersion ilVersion = pCodeVersionManager->GetActiveILCodeVersion(pCallee);
8191             if (ilVersion.GetRejitState() != ILCodeVersion::kStateActive || !ilVersion.HasDefaultIL())
8192             {
8193                 ModuleID modId = pCaller->GetModule()->GetModuleID();
8194                 mdMethodDef methodDef = pCaller->GetMemberDef();
8195                 ReJitManager::RequestReJIT(1, &modId, &methodDef, static_cast<COR_PRF_REJIT_FLAGS>(0));
8196             }
8197         }
8198     }
8199 #endif // defined FEATURE_REJIT && !defined(DACCESS_COMPILE)
8200
8201     EE_TO_JIT_TRANSITION();
8202 }
8203
8204
8205 /*************************************************************
8206  * Similar to above, but perform check for tail call
8207  * eligibility. The callee can be passed as NULL if not known
8208  * (calli and callvirt).
8209  *************************************************************/
8210
8211 bool CEEInfo::canTailCall (CORINFO_METHOD_HANDLE hCaller,
8212                            CORINFO_METHOD_HANDLE hDeclaredCallee,
8213                            CORINFO_METHOD_HANDLE hExactCallee,
8214                            bool fIsTailPrefix)
8215 {
8216     CONTRACTL {
8217         THROWS;
8218         GC_TRIGGERS;
8219         MODE_PREEMPTIVE;
8220     } CONTRACTL_END;
8221
8222     bool result = false;
8223     const char * szFailReason = NULL;
8224
8225     JIT_TO_EE_TRANSITION();
8226
8227     // See comments in canInline above.
8228
8229     MethodDesc* pCaller = GetMethod(hCaller);
8230     MethodDesc* pDeclaredCallee = GetMethod(hDeclaredCallee);
8231     MethodDesc* pExactCallee = GetMethod(hExactCallee);
8232
8233     _ASSERTE(pCaller->GetModule());
8234     _ASSERTE(pCaller->GetModule()->GetClassLoader());
8235
8236     _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule());
8237     _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule()->GetClassLoader());
8238
8239     if (!fIsTailPrefix)
8240     {
8241         mdMethodDef callerToken = pCaller->GetMemberDef();
8242
8243         // We don't want to tailcall the entrypoint for an application; JIT64 will sometimes
8244         // do this for simple entrypoints and it results in a rather confusing debugging
8245         // experience.
8246         if (callerToken == pCaller->GetModule()->GetEntryPointToken())
8247         {
8248             result = false;
8249             szFailReason = "Caller is the entry point";
8250             goto exit;
8251         }
8252
8253         if (!pCaller->IsNoMetadata())
8254         {
8255             // Do not tailcall from methods that are marked as noinline (people often use no-inline
8256             // to mean "I want to always see this method in stacktrace")
8257             DWORD dwImplFlags = 0;
8258             IfFailThrow(pCaller->GetMDImport()->GetMethodImplProps(callerToken, NULL, &dwImplFlags));
8259
8260             if (IsMiNoInlining(dwImplFlags))
8261             {
8262                 result = false;
8263                 szFailReason = "Caller is marked as no inline";
8264                 goto exit;
8265             }
8266         }
8267
8268         // Methods with StackCrawlMark depend on finding their caller on the stack.
8269         // If we tail call one of these guys, they get confused.  For lack of
8270         // a better way of identifying them, we use DynamicSecurity attribute to identify
8271         // them. We have an assert in canInline that ensures all StackCrawlMark
8272         // methods are appropriately marked.
8273         //
8274         if ((pExactCallee != NULL) && IsMdRequireSecObject(pExactCallee->GetAttrs()))
8275         {
8276             result = false;
8277             szFailReason = "Callee might have a StackCrawlMark.LookForMyCaller";
8278             goto exit;
8279         }
8280     }
8281
8282
8283     result = true;
8284
8285 exit: ;
8286
8287     EE_TO_JIT_TRANSITION();
8288
8289     if (!result)
8290     {
8291         // If you hit this assert, it means you added a new way to prevent tail calls
8292         // without documenting it for ETW!
8293         _ASSERTE(szFailReason != NULL);
8294         reportTailCallDecision(hCaller, hExactCallee, fIsTailPrefix, TAILCALL_FAIL, szFailReason);
8295     }
8296
8297     return result;
8298 }
8299
8300 void CEEInfo::reportTailCallDecision (CORINFO_METHOD_HANDLE callerHnd,
8301                                      CORINFO_METHOD_HANDLE calleeHnd,
8302                                      bool fIsTailPrefix,
8303                                      CorInfoTailCall tailCallResult,
8304                                      const char * reason)
8305 {
8306     STATIC_CONTRACT_THROWS;
8307     STATIC_CONTRACT_GC_TRIGGERS;
8308
8309     JIT_TO_EE_TRANSITION();
8310
8311     //put code here.  Make sure to report the method being compiled in addition to inliner and inlinee.
8312 #ifdef _DEBUG
8313     if (LoggingOn(LF_JIT, LL_INFO100000))
8314     {
8315         SString currentMethodName;
8316         TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled,
8317                                          TypeString::FormatBasic);
8318
8319         SString calleeMethodName;
8320         if (GetMethod(calleeHnd))
8321         {
8322             TypeString::AppendMethodInternal(calleeMethodName, GetMethod(calleeHnd),
8323                                              TypeString::FormatBasic);
8324         }
8325         else
8326         {
8327             calleeMethodName.AppendASCII( "<null>" );
8328         }
8329
8330         SString callerMethodName;
8331         if (GetMethod(callerHnd))
8332         {
8333             TypeString::AppendMethodInternal(callerMethodName, GetMethod(callerHnd),
8334                                              TypeString::FormatBasic);
8335         }
8336         else
8337         {
8338             callerMethodName.AppendASCII( "<null>" );
8339         }
8340         if (tailCallResult == TAILCALL_FAIL)
8341         {
8342             LOG((LF_JIT, LL_INFO100000,
8343                  "While compiling '%s', %splicit tail call from '%s' to '%s' failed because: '%s'.\n",
8344                  currentMethodName.GetUTF8(), fIsTailPrefix ? "ex" : "im",
8345                  callerMethodName.GetUTF8(), calleeMethodName.GetUTF8(), reason));
8346         }
8347         else
8348         {
8349             static const char * const tailCallType[] = {
8350                 "optimized tail call", "recursive loop", "helper assisted tailcall"
8351             };
8352             _ASSERTE(tailCallResult >= 0 && (size_t)tailCallResult < ARRAY_SIZE(tailCallType));
8353             LOG((LF_JIT, LL_INFO100000,
8354                  "While compiling '%s', %splicit tail call from '%s' to '%s' generated as a %s.\n",
8355                  currentMethodName.GetUTF8(), fIsTailPrefix ? "ex" : "im",
8356                  callerMethodName.GetUTF8(), calleeMethodName.GetUTF8(), tailCallType[tailCallResult]));
8357
8358         }
8359     }
8360 #endif //_DEBUG
8361
8362     // I'm gonna duplicate this code because the format is slightly different.  And LoggingOn is debug only.
8363     if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
8364                                      TRACE_LEVEL_VERBOSE,
8365                                      CLR_JITTRACING_KEYWORD))
8366     {
8367         SString methodBeingCompiledNames[3];
8368         SString callerNames[3];
8369         SString calleeNames[3];
8370         MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8371 #define GMI(pMD, strArray) \
8372         do { \
8373             if (pMD) { \
8374                 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8375             } else {  \
8376                 (strArray)[0].Set(W("<null>")); \
8377                 (strArray)[1].Set(W("<null>")); \
8378                 (strArray)[2].Set(W("<null>")); \
8379             } } while (0)
8380
8381         GMI(methodBeingCompiled, methodBeingCompiledNames);
8382         GMI(GetMethod(callerHnd), callerNames);
8383         GMI(GetMethod(calleeHnd), calleeNames);
8384 #undef GMI
8385         if (tailCallResult == TAILCALL_FAIL)
8386         {
8387             const char * str = (reason ? reason : "");
8388             SString strReason;
8389             strReason.SetUTF8(str);
8390
8391             FireEtwMethodJitTailCallFailed(methodBeingCompiledNames[0].GetUnicode(),
8392                                            methodBeingCompiledNames[1].GetUnicode(),
8393                                            methodBeingCompiledNames[2].GetUnicode(),
8394                                            callerNames[0].GetUnicode(),
8395                                            callerNames[1].GetUnicode(),
8396                                            callerNames[2].GetUnicode(),
8397                                            calleeNames[0].GetUnicode(),
8398                                            calleeNames[1].GetUnicode(),
8399                                            calleeNames[2].GetUnicode(),
8400                                            fIsTailPrefix,
8401                                            strReason.GetUnicode(),
8402                                            GetClrInstanceId());
8403         }
8404         else
8405         {
8406             FireEtwMethodJitTailCallSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8407                                               methodBeingCompiledNames[1].GetUnicode(),
8408                                               methodBeingCompiledNames[2].GetUnicode(),
8409                                               callerNames[0].GetUnicode(),
8410                                               callerNames[1].GetUnicode(),
8411                                               callerNames[2].GetUnicode(),
8412                                               calleeNames[0].GetUnicode(),
8413                                               calleeNames[1].GetUnicode(),
8414                                               calleeNames[2].GetUnicode(),
8415                                               fIsTailPrefix,
8416                                               tailCallResult,
8417                                               GetClrInstanceId());
8418         }
8419
8420     }
8421
8422
8423     EE_TO_JIT_TRANSITION();
8424 }
8425
8426 static void getEHinfoHelper(
8427     CORINFO_METHOD_HANDLE   ftnHnd,
8428     unsigned                EHnumber,
8429     CORINFO_EH_CLAUSE*      clause,
8430     COR_ILMETHOD_DECODER*   pILHeader)
8431 {
8432     STANDARD_VM_CONTRACT;
8433
8434     _ASSERTE(CheckPointer(pILHeader->EH));
8435     _ASSERTE(EHnumber < pILHeader->EH->EHCount());
8436
8437     COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
8438     const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo;
8439     ehInfo = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)pILHeader->EH->EHClause(EHnumber, &ehClause);
8440
8441     clause->Flags = (CORINFO_EH_CLAUSE_FLAGS)ehInfo->GetFlags();
8442     clause->TryOffset = ehInfo->GetTryOffset();
8443     clause->TryLength = ehInfo->GetTryLength();
8444     clause->HandlerOffset = ehInfo->GetHandlerOffset();
8445     clause->HandlerLength = ehInfo->GetHandlerLength();
8446     if ((clause->Flags & CORINFO_EH_CLAUSE_FILTER) == 0)
8447         clause->ClassToken = ehInfo->GetClassToken();
8448     else
8449         clause->FilterOffset = ehInfo->GetFilterOffset();
8450 }
8451
8452 /*********************************************************************/
8453 // get individual exception handler
8454 void CEEInfo::getEHinfo(
8455             CORINFO_METHOD_HANDLE ftnHnd,
8456             unsigned      EHnumber,
8457             CORINFO_EH_CLAUSE* clause)
8458 {
8459     CONTRACTL {
8460         THROWS;
8461         GC_TRIGGERS;
8462         MODE_PREEMPTIVE;
8463     } CONTRACTL_END;
8464
8465     JIT_TO_EE_TRANSITION();
8466
8467     MethodDesc * ftn          = GetMethod(ftnHnd);
8468
8469     if (IsDynamicMethodHandle(ftnHnd))
8470     {
8471         GetMethod(ftnHnd)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
8472     }
8473     else
8474     {
8475         COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
8476         getEHinfoHelper(ftnHnd, EHnumber, clause, &header);
8477     }
8478
8479     EE_TO_JIT_TRANSITION();
8480 }
8481
8482 //---------------------------------------------------------------------------------------
8483 //
8484 void
8485 CEEInfo::getMethodSig(
8486     CORINFO_METHOD_HANDLE ftnHnd,
8487     CORINFO_SIG_INFO *    sigRet,
8488     CORINFO_CLASS_HANDLE  owner)
8489 {
8490     CONTRACTL {
8491         THROWS;
8492         GC_TRIGGERS;
8493         MODE_PREEMPTIVE;
8494     } CONTRACTL_END;
8495
8496     JIT_TO_EE_TRANSITION();
8497
8498     getMethodSigInternal(ftnHnd, sigRet, owner, SK_NOT_CALLSITE);
8499
8500     EE_TO_JIT_TRANSITION();
8501 }
8502
8503 //---------------------------------------------------------------------------------------
8504 //
8505 //@GENERICSVER: for a method desc in a typical instantiation of a generic class,
8506 // this will return the typical instantiation of the generic class,
8507 // but only provided type variables are never shared.
8508 // The JIT verifier relies on this behaviour to extract the typical class from an instantiated method's typical method handle.
8509 //
8510 CORINFO_CLASS_HANDLE
8511 CEEInfo::getMethodClass(
8512     CORINFO_METHOD_HANDLE methodHnd)
8513 {
8514     CONTRACTL {
8515         THROWS;
8516         GC_TRIGGERS;
8517         MODE_PREEMPTIVE;
8518     } CONTRACTL_END;
8519
8520     CORINFO_CLASS_HANDLE result = NULL;
8521
8522     JIT_TO_EE_TRANSITION();
8523
8524     MethodDesc* method = GetMethod(methodHnd);
8525
8526     if (method->IsDynamicMethod())
8527     {
8528         DynamicResolver::SecurityControlFlags securityControlFlags = DynamicResolver::Default;
8529         TypeHandle typeOwner;
8530
8531         DynamicResolver* pResolver = method->AsDynamicMethodDesc()->GetResolver();
8532         pResolver->GetJitContext(&securityControlFlags, &typeOwner);
8533
8534         if (!typeOwner.IsNull() && (method == pResolver->GetDynamicMethod()))
8535         {
8536             result = CORINFO_CLASS_HANDLE(typeOwner.AsPtr());
8537         }
8538     }
8539
8540     if (result == NULL)
8541     {
8542         TypeHandle th = TypeHandle(method->GetMethodTable());
8543
8544         result = CORINFO_CLASS_HANDLE(th.AsPtr());
8545     }
8546
8547     EE_TO_JIT_TRANSITION();
8548
8549     return result;
8550 }
8551
8552 /*********************************************************************/
8553 bool CEEInfo::isIntrinsicType(CORINFO_CLASS_HANDLE classHnd)
8554 {
8555     CONTRACTL {
8556         NOTHROW;
8557         GC_NOTRIGGER;
8558         MODE_PREEMPTIVE;
8559     } CONTRACTL_END;
8560
8561     bool result = false;
8562     JIT_TO_EE_TRANSITION_LEAF();
8563
8564     TypeHandle VMClsHnd(classHnd);
8565     PTR_MethodTable methodTable = VMClsHnd.GetMethodTable();
8566     result = methodTable->IsIntrinsicType();
8567
8568     EE_TO_JIT_TRANSITION_LEAF();
8569     return result;
8570 }
8571
8572 /*********************************************************************/
8573 void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd,
8574                                      unsigned * pOffsetOfIndirection,
8575                                      unsigned * pOffsetAfterIndirection,
8576                                      bool * isRelative)
8577 {
8578     CONTRACTL {
8579         NOTHROW;
8580         GC_NOTRIGGER;
8581         MODE_PREEMPTIVE;
8582     } CONTRACTL_END;
8583
8584     JIT_TO_EE_TRANSITION_LEAF();
8585
8586     MethodDesc* method = GetMethod(methodHnd);
8587
8588     //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8589     _ASSERTE(!method->HasMethodInstantiation());
8590
8591     _ASSERTE(MethodTable::GetVtableOffset() < 256);  // a rough sanity check
8592
8593     // better be in the vtable
8594     _ASSERTE(method->GetSlot() < method->GetMethodTable()->GetNumVirtuals());
8595
8596     *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * TARGET_POINTER_SIZE /* sizeof(MethodTable::VTableIndir_t) */;
8597     *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * TARGET_POINTER_SIZE /* sizeof(MethodTable::VTableIndir2_t) */;
8598     *isRelative = false;
8599
8600     EE_TO_JIT_TRANSITION_LEAF();
8601 }
8602
8603 /*********************************************************************/
8604 bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
8605 {
8606     CONTRACTL {
8607         THROWS;
8608         GC_TRIGGERS;
8609         MODE_PREEMPTIVE;
8610     } CONTRACTL_END;
8611
8612     // Initialize OUT fields
8613     info->devirtualizedMethod = NULL;
8614     info->requiresInstMethodTableArg = false;
8615     info->exactContext = NULL;
8616     memset(&info->resolvedTokenDevirtualizedMethod, 0, sizeof(info->resolvedTokenDevirtualizedMethod));
8617     memset(&info->resolvedTokenDevirtualizedUnboxedMethod, 0, sizeof(info->resolvedTokenDevirtualizedUnboxedMethod));
8618
8619     MethodDesc* pBaseMD = GetMethod(info->virtualMethod);
8620     MethodTable* pBaseMT = pBaseMD->GetMethodTable();
8621
8622     // Method better be from a fully loaded class
8623     _ASSERTE(pBaseMT->IsFullyLoaded());
8624
8625     //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8626     _ASSERTE(!pBaseMD->HasMethodInstantiation());
8627
8628     // Method better be virtual
8629     _ASSERTE(pBaseMD->IsVirtual());
8630
8631     MethodDesc* pDevirtMD = nullptr;
8632
8633     TypeHandle ObjClassHnd(info->objClass);
8634     MethodTable* pObjMT = ObjClassHnd.GetMethodTable();
8635     _ASSERTE(pObjMT->IsRestored() && pObjMT->IsFullyLoaded());
8636
8637     // Can't devirtualize from __Canon.
8638     if (ObjClassHnd == TypeHandle(g_pCanonMethodTableClass))
8639     {
8640         info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
8641         return false;
8642     }
8643
8644     if (pBaseMT->IsInterface())
8645     {
8646
8647 #ifdef FEATURE_COMINTEROP
8648         // Don't try and devirtualize com interface calls.
8649         if (pObjMT->IsComObjectType())
8650         {
8651             info->detail = CORINFO_DEVIRTUALIZATION_FAILED_COM;
8652             return false;
8653         }
8654 #endif // FEATURE_COMINTEROP
8655
8656         if (info->context != nullptr)
8657         {
8658             pBaseMT = GetTypeFromContext(info->context).GetMethodTable();
8659         }
8660
8661         // Interface call devirtualization.
8662         //
8663         // We must ensure that pObjMT actually implements the
8664         // interface corresponding to pBaseMD.
8665         if (!pObjMT->CanCastToInterface(pBaseMT))
8666         {
8667             info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CAST;
8668             return false;
8669         }
8670
8671         // For generic interface methods we must have context to
8672         // safely devirtualize.
8673         if (info->context != nullptr)
8674         {
8675             // If the derived class is a shared class, make sure the
8676             // owner class is too.
8677             if (pObjMT->IsSharedByGenericInstantiations())
8678             {
8679                 MethodTable* pCanonBaseMT = pBaseMT->GetCanonicalMethodTable();
8680
8681                 // Check to see if the derived class implements multiple variants of a matching interface.
8682                 // If so, we cannot predict exactly which implementation is in use here.
8683                 MethodTable::InterfaceMapIterator it = pObjMT->IterateInterfaceMap();
8684                 int canonicallyMatchingInterfacesFound = 0;
8685                 while (it.Next())
8686                 {
8687                     if (it.GetInterface(pObjMT)->GetCanonicalMethodTable() == pCanonBaseMT)
8688                     {
8689                         canonicallyMatchingInterfacesFound++;
8690                         if (canonicallyMatchingInterfacesFound > 1)
8691                         {
8692                             // Multiple canonically identical interfaces found when attempting to devirtualize an inexact interface dispatch
8693                             info->detail = CORINFO_DEVIRTUALIZATION_MULTIPLE_IMPL;
8694                             return false;
8695                         }
8696                     }
8697                 }
8698             }
8699
8700             pDevirtMD = pObjMT->GetMethodDescForInterfaceMethod(TypeHandle(pBaseMT), pBaseMD, FALSE /* throwOnConflict */);
8701         }
8702         else if (!pBaseMD->HasClassOrMethodInstantiation())
8703         {
8704             pDevirtMD = pObjMT->GetMethodDescForInterfaceMethod(pBaseMD, FALSE /* throwOnConflict */);
8705         }
8706
8707         if (pDevirtMD == nullptr)
8708         {
8709             info->detail = CORINFO_DEVIRTUALIZATION_FAILED_LOOKUP;
8710             return false;
8711         }
8712
8713         // If we devirtualized into a default interface method on a generic type, we should actually return an
8714         // instantiating stub but this is not happening.
8715         // Making this work is tracked by https://github.com/dotnet/runtime/issues/9588
8716         if (pDevirtMD->GetMethodTable()->IsInterface() && pDevirtMD->HasClassInstantiation())
8717         {
8718             info->detail = CORINFO_DEVIRTUALIZATION_FAILED_DIM;
8719             return false;
8720         }
8721     }
8722     else
8723     {
8724         // Virtual call devirtualization.
8725         //
8726         // The derived class should be a subclass of the base class.
8727         MethodTable* pCheckMT = pObjMT;
8728
8729         while (pCheckMT != nullptr)
8730         {
8731             if (pCheckMT->HasSameTypeDefAs(pBaseMT))
8732             {
8733                 break;
8734             }
8735
8736             pCheckMT = pCheckMT->GetParentMethodTable();
8737         }
8738
8739         if (pCheckMT == nullptr)
8740         {
8741             info->detail = CORINFO_DEVIRTUALIZATION_FAILED_SUBCLASS;
8742             return false;
8743         }
8744
8745         // The base method should be in the base vtable
8746         WORD slot = pBaseMD->GetSlot();
8747         _ASSERTE(slot < pBaseMT->GetNumVirtuals());
8748
8749         // Fetch the method that would be invoked if the class were
8750         // exactly derived class. It is up to the jit to determine whether
8751         // directly calling this method is correct.
8752         pDevirtMD = pObjMT->GetMethodDescForSlot(slot);
8753
8754         // If the derived method's slot does not match the vtable slot,
8755         // bail on devirtualization, as the method was installed into
8756         // the vtable slot via an explicit override and even if the
8757         // method is final, the slot may not be.
8758         //
8759         // Note the jit could still safely devirtualize if it had an exact
8760         // class, but such cases are likely rare.
8761         WORD dslot = pDevirtMD->GetSlot();
8762
8763         if (dslot != slot)
8764         {
8765             info->detail = CORINFO_DEVIRTUALIZATION_FAILED_SLOT;
8766             return false;
8767         }
8768     }
8769
8770     // Determine the exact class.
8771     //
8772     // We may fail to get an exact context if the method is a default
8773     // interface method. If so, we'll use the method's class.
8774     //
8775     MethodTable* pApproxMT = pDevirtMD->GetMethodTable();
8776     MethodTable* pExactMT = pApproxMT;
8777
8778     if (pApproxMT->IsInterface())
8779     {
8780         // As noted above, we can't yet handle generic interfaces
8781         // with default methods.
8782         _ASSERTE(!pDevirtMD->HasClassInstantiation());
8783
8784     }
8785     else
8786     {
8787         pExactMT = pDevirtMD->GetExactDeclaringType(pObjMT);
8788     }
8789
8790     // Success! Pass back the results.
8791     //
8792     info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) pDevirtMD;
8793     info->exactContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT);
8794     info->requiresInstMethodTableArg = false;
8795     info->detail = CORINFO_DEVIRTUALIZATION_SUCCESS;
8796
8797     return true;
8798 }
8799
8800 bool CEEInfo::resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info)
8801 {
8802     CONTRACTL {
8803         THROWS;
8804         GC_TRIGGERS;
8805         MODE_PREEMPTIVE;
8806     } CONTRACTL_END;
8807
8808     bool result = false;
8809
8810     JIT_TO_EE_TRANSITION();
8811
8812     result = resolveVirtualMethodHelper(info);
8813
8814     EE_TO_JIT_TRANSITION();
8815
8816     return result;
8817 }
8818
8819 /*********************************************************************/
8820 CORINFO_METHOD_HANDLE CEEInfo::getUnboxedEntry(
8821     CORINFO_METHOD_HANDLE ftn,
8822     bool* requiresInstMethodTableArg)
8823 {
8824     CONTRACTL {
8825         THROWS;
8826         GC_TRIGGERS;
8827         MODE_PREEMPTIVE;
8828     } CONTRACTL_END;
8829
8830     CORINFO_METHOD_HANDLE result = NULL;
8831
8832     JIT_TO_EE_TRANSITION();
8833
8834     MethodDesc* pMD = GetMethod(ftn);
8835     bool requiresInstMTArg = false;
8836
8837     if (pMD->IsUnboxingStub())
8838     {
8839         MethodTable* pMT = pMD->GetMethodTable();
8840         MethodDesc* pUnboxedMD = pMT->GetUnboxedEntryPointMD(pMD);
8841
8842         result = (CORINFO_METHOD_HANDLE)pUnboxedMD;
8843         requiresInstMTArg = !!pUnboxedMD->RequiresInstMethodTableArg();
8844     }
8845
8846     *requiresInstMethodTableArg = requiresInstMTArg;
8847
8848     EE_TO_JIT_TRANSITION();
8849
8850     return result;
8851 }
8852
8853 /*********************************************************************/
8854 void CEEInfo::expandRawHandleIntrinsic(
8855     CORINFO_RESOLVED_TOKEN *        pResolvedToken,
8856     CORINFO_GENERICHANDLE_RESULT *  pResult)
8857 {
8858     LIMITED_METHOD_CONTRACT;
8859     UNREACHABLE();      // only called with NativeAOT.
8860 }
8861
8862 /*********************************************************************/
8863 CORINFO_CLASS_HANDLE CEEInfo::getDefaultComparerClass(CORINFO_CLASS_HANDLE elemType)
8864 {
8865     CONTRACTL {
8866         THROWS;
8867         GC_TRIGGERS;
8868         MODE_PREEMPTIVE;
8869     } CONTRACTL_END;
8870
8871     CORINFO_CLASS_HANDLE result = NULL;
8872
8873     JIT_TO_EE_TRANSITION();
8874
8875     result = getDefaultComparerClassHelper(elemType);
8876
8877     EE_TO_JIT_TRANSITION();
8878
8879     return result;
8880 }
8881
8882 CORINFO_CLASS_HANDLE CEEInfo::getDefaultComparerClassHelper(CORINFO_CLASS_HANDLE elemType)
8883 {
8884     CONTRACTL {
8885         THROWS;
8886         GC_TRIGGERS;
8887         MODE_PREEMPTIVE;
8888     } CONTRACTL_END;
8889
8890     TypeHandle elemTypeHnd(elemType);
8891
8892     // Mirrors the logic in BCL's CompareHelpers.CreateDefaultComparer
8893     // And in compile.cpp's SpecializeComparer
8894     //
8895     // We need to find the appropriate instantiation
8896     Instantiation inst(&elemTypeHnd, 1);
8897
8898     // Nullable<T>
8899     if (Nullable::IsNullableType(elemTypeHnd))
8900     {
8901         Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
8902         TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__NULLABLE_COMPARER)).Instantiate(nullableInst);
8903         return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8904     }
8905
8906     // We need to special case the Enum comparers based on their underlying type to avoid boxing
8907     if (elemTypeHnd.IsEnum())
8908     {
8909         TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__ENUM_COMPARER)).Instantiate(inst);
8910         return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8911     }
8912
8913     if (elemTypeHnd.IsCanonicalSubtype())
8914     {
8915         return NULL;
8916     }
8917
8918     // If T implements IComparable<T>
8919     if (elemTypeHnd.CanCastTo(TypeHandle(CoreLibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(inst)))
8920     {
8921         TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__GENERIC_COMPARER)).Instantiate(inst);
8922         return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8923     }
8924
8925     // Default case
8926     TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__OBJECT_COMPARER)).Instantiate(inst);
8927
8928     return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8929 }
8930
8931 /*********************************************************************/
8932 CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE elemType)
8933 {
8934     CONTRACTL {
8935         THROWS;
8936         GC_TRIGGERS;
8937         MODE_PREEMPTIVE;
8938     } CONTRACTL_END;
8939
8940     CORINFO_CLASS_HANDLE result = NULL;
8941
8942     JIT_TO_EE_TRANSITION();
8943
8944     result = getDefaultEqualityComparerClassHelper(elemType);
8945
8946     EE_TO_JIT_TRANSITION();
8947
8948     return result;
8949 }
8950
8951 CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLASS_HANDLE elemType)
8952 {
8953     CONTRACTL {
8954         THROWS;
8955         GC_TRIGGERS;
8956         MODE_PREEMPTIVE;
8957     } CONTRACTL_END;
8958
8959     // Mirrors the logic in BCL's CompareHelpers.CreateDefaultEqualityComparer
8960     // And in compile.cpp's SpecializeEqualityComparer
8961     TypeHandle elemTypeHnd(elemType);
8962
8963     // Mirrors the logic in BCL's CompareHelpers.CreateDefaultComparer
8964     // And in compile.cpp's SpecializeComparer
8965     //
8966     // We need to find the appropriate instantiation
8967     Instantiation inst(&elemTypeHnd, 1);
8968
8969     // Nullable<T>
8970     if (Nullable::IsNullableType(elemTypeHnd))
8971     {
8972         Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
8973         TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__NULLABLE_EQUALITYCOMPARER)).Instantiate(nullableInst);
8974         return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8975     }
8976
8977     // Enum
8978     //
8979     // We need to special case the Enum comparers based on their underlying type,
8980     // to avoid boxing and call the correct versions of GetHashCode.
8981     if (elemTypeHnd.IsEnum())
8982     {
8983         TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__ENUM_EQUALITYCOMPARER)).Instantiate(inst);
8984         return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8985     }
8986
8987     if (elemTypeHnd.IsCanonicalSubtype())
8988     {
8989         return NULL;
8990     }
8991
8992     // If T implements IEquatable<T>
8993     if (elemTypeHnd.CanCastTo(TypeHandle(CoreLibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(inst)))
8994     {
8995         TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__GENERIC_EQUALITYCOMPARER)).Instantiate(inst);
8996         return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8997     }
8998
8999     // Default case
9000     TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__OBJECT_EQUALITYCOMPARER)).Instantiate(inst);
9001
9002     return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
9003 }
9004
9005 /*********************************************************************/
9006 void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE  ftnHnd,
9007                                     CORINFO_CONST_LOOKUP * pResult,
9008                                     CORINFO_ACCESS_FLAGS   accessFlags)
9009 {
9010     CONTRACTL {
9011         THROWS;
9012         GC_TRIGGERS;
9013         MODE_PREEMPTIVE;
9014     } CONTRACTL_END;
9015
9016     void* ret = NULL;
9017     InfoAccessType accessType = IAT_VALUE;
9018
9019     JIT_TO_EE_TRANSITION();
9020
9021     MethodDesc * ftn = GetMethod(ftnHnd);
9022 #if defined(FEATURE_GDBJIT)
9023     MethodDesc * orig_ftn = ftn;
9024 #endif
9025
9026     // Resolve methodImpl.
9027     ftn = ftn->GetMethodTable()->MapMethodDeclToMethodImpl(ftn);
9028
9029     if (!ftn->IsFCall() && ftn->IsVersionableWithPrecode() && (ftn->GetPrecodeType() == PRECODE_FIXUP) && !ftn->IsPointingToStableNativeCode())
9030     {
9031         ret = ((FixupPrecode*)ftn->GetOrCreatePrecode())->GetTargetSlot();
9032         accessType = IAT_PVALUE;
9033     }
9034     else
9035     {
9036         ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags);
9037
9038         // TryGetMultiCallableAddrOfCode returns NULL if indirect access is desired
9039         if (ret == NULL)
9040         {
9041             // should never get here for EnC methods or if interception via remoting stub is required
9042             _ASSERTE(!ftn->InEnCEnabledModule());
9043
9044             ret = (void *)ftn->GetAddrOfSlot();
9045
9046             accessType = IAT_PVALUE;
9047         }
9048     }
9049
9050 #if defined(FEATURE_GDBJIT)
9051     CalledMethod * pCM = new CalledMethod(orig_ftn, ret, m_pCalledMethods);
9052     m_pCalledMethods = pCM;
9053 #endif
9054
9055     EE_TO_JIT_TRANSITION();
9056
9057     _ASSERTE(ret != NULL);
9058
9059     pResult->accessType = accessType;
9060     pResult->addr = ret;
9061 }
9062
9063 /*********************************************************************/
9064 void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE   ftn,
9065                                          bool isUnsafeFunctionPointer,
9066                                          CORINFO_CONST_LOOKUP *  pResult)
9067 {
9068     CONTRACTL {
9069         THROWS;
9070         GC_TRIGGERS;
9071         MODE_PREEMPTIVE;
9072     } CONTRACTL_END;
9073
9074     JIT_TO_EE_TRANSITION();
9075
9076     MethodDesc * pMD = GetMethod(ftn);
9077
9078     if (isUnsafeFunctionPointer)
9079         pMD->PrepareForUseAsAFunctionPointer();
9080
9081     pResult->accessType = IAT_VALUE;
9082     pResult->addr = (void*)pMD->GetMultiCallableAddrOfCode();
9083
9084     EE_TO_JIT_TRANSITION();
9085 }
9086
9087 /*********************************************************************/
9088 size_t CEEInfo::printFieldName(CORINFO_FIELD_HANDLE fieldHnd, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize)
9089 {
9090     CONTRACTL {
9091         THROWS;
9092         GC_NOTRIGGER;
9093         MODE_PREEMPTIVE;
9094     } CONTRACTL_END;
9095
9096     size_t bytesWritten = 0;
9097     JIT_TO_EE_TRANSITION();
9098
9099     FieldDesc* field = (FieldDesc*) fieldHnd;
9100     const char* fieldName = field->GetName();
9101
9102     size_t len = strlen(fieldName);
9103     if (bufferSize > 0)
9104     {
9105         bytesWritten = min(len, bufferSize - 1);
9106         memcpy(buffer, fieldName, len);
9107         buffer[bytesWritten] = '\0';
9108     }
9109
9110     if (pRequiredBufferSize != NULL)
9111     {
9112         *pRequiredBufferSize = len + 1;
9113     }
9114
9115     EE_TO_JIT_TRANSITION();
9116
9117     return bytesWritten;
9118 }
9119
9120 /*********************************************************************/
9121 // Get the type that declares the field
9122 CORINFO_CLASS_HANDLE CEEInfo::getFieldClass (CORINFO_FIELD_HANDLE fieldHnd)
9123 {
9124     CONTRACTL {
9125         NOTHROW;
9126         GC_NOTRIGGER;
9127         MODE_PREEMPTIVE;
9128     } CONTRACTL_END;
9129
9130     CORINFO_CLASS_HANDLE result = NULL;
9131
9132     JIT_TO_EE_TRANSITION_LEAF();
9133
9134     FieldDesc* field = (FieldDesc*) fieldHnd;
9135     result = CORINFO_CLASS_HANDLE(field->GetApproxEnclosingMethodTable());
9136
9137     EE_TO_JIT_TRANSITION_LEAF();
9138
9139     return result;
9140 }
9141
9142 /*********************************************************************/
9143 // Returns the basic type of the field (not the type that declares the field)
9144 //
9145 // pTypeHnd - Optional. If not null then on return, for reference and value types,
9146 //            *pTypeHnd will contain the normalized type of the field.
9147 // owner - Optional. For resolving in a generic context
9148
9149 CorInfoType CEEInfo::getFieldType (CORINFO_FIELD_HANDLE fieldHnd,
9150                                    CORINFO_CLASS_HANDLE* pTypeHnd,
9151                                    CORINFO_CLASS_HANDLE owner)
9152 {
9153     CONTRACTL {
9154         THROWS;
9155         GC_TRIGGERS;
9156         MODE_PREEMPTIVE;
9157     } CONTRACTL_END;
9158
9159     CorInfoType result = CORINFO_TYPE_UNDEF;
9160
9161     JIT_TO_EE_TRANSITION();
9162
9163     result = getFieldTypeInternal(fieldHnd, pTypeHnd, owner);
9164
9165     EE_TO_JIT_TRANSITION();
9166
9167     return result;
9168 }
9169
9170 /*********************************************************************/
9171 CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd,
9172                                            CORINFO_CLASS_HANDLE* pTypeHnd,
9173                                            CORINFO_CLASS_HANDLE owner)
9174 {
9175     STANDARD_VM_CONTRACT;
9176
9177     if (pTypeHnd != nullptr)
9178     {
9179         *pTypeHnd = 0;
9180     }
9181
9182     TypeHandle clsHnd = TypeHandle();
9183     FieldDesc* field = (FieldDesc*) fieldHnd;
9184     CorElementType type   = field->GetFieldType();
9185     if (!CorTypeInfo::IsPrimitiveType(type))
9186     {
9187         PCCOR_SIGNATURE sig;
9188         DWORD sigCount;
9189         CorCallingConvention conv;
9190
9191         field->GetSig(&sig, &sigCount);
9192
9193         conv = (CorCallingConvention)CorSigUncompressCallingConv(sig);
9194         _ASSERTE(isCallConv(conv, IMAGE_CEE_CS_CALLCONV_FIELD));
9195
9196         SigPointer ptr(sig, sigCount);
9197
9198         // For verifying code involving generics, use the class instantiation
9199         // of the optional owner (to provide exact, not representative,
9200         // type information)
9201         SigTypeContext typeContext(field, (TypeHandle)owner);
9202
9203         clsHnd = ptr.GetTypeHandleThrowing(field->GetModule(), &typeContext);
9204         _ASSERTE(!clsHnd.IsNull());
9205
9206         // I believe it doesn't make any diff. if this is GetInternalCorElementType
9207         // or GetSignatureCorElementType.
9208         type = clsHnd.GetSignatureCorElementType();
9209     }
9210
9211     return CEEInfo::asCorInfoType(type, clsHnd, pTypeHnd);
9212 }
9213
9214 /*********************************************************************/
9215 unsigned CEEInfo::getFieldOffset (CORINFO_FIELD_HANDLE fieldHnd)
9216 {
9217     CONTRACTL {
9218         THROWS;
9219         GC_TRIGGERS;
9220         MODE_PREEMPTIVE;
9221     } CONTRACTL_END;
9222
9223     unsigned result = (unsigned) -1;
9224
9225     JIT_TO_EE_TRANSITION();
9226
9227     FieldDesc* field = (FieldDesc*) fieldHnd;
9228
9229     // GetOffset() does not include the size of Object
9230     result = field->GetOffset();
9231
9232     // So if it is not a value class, add the Object into it
9233     if (field->IsStatic())
9234     {
9235         Module* pModule = field->GetModule();
9236         if (field->IsRVA() && pModule->IsRvaFieldTls(field->GetOffset()))
9237         {
9238             result = pModule->GetFieldTlsOffset(field->GetOffset());
9239         }
9240     }
9241     else if (!field->GetApproxEnclosingMethodTable()->IsValueType())
9242     {
9243         result += OBJECT_SIZE;
9244     }
9245
9246     EE_TO_JIT_TRANSITION();
9247
9248     return result;
9249 }
9250
9251 /*********************************************************************/
9252 uint32_t CEEInfo::getFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE fieldHnd, void **ppIndirection)
9253 {
9254     CONTRACTL {
9255         THROWS;
9256         GC_TRIGGERS;
9257         MODE_PREEMPTIVE;
9258     } CONTRACTL_END;
9259
9260     uint32_t result = 0;
9261
9262     if (ppIndirection != NULL)
9263         *ppIndirection = NULL;
9264
9265     JIT_TO_EE_TRANSITION();
9266
9267     FieldDesc* field = (FieldDesc*) fieldHnd;
9268     Module* module = field->GetModule();
9269
9270     _ASSERTE(field->IsRVA());       // Only RVA statics can be thread local
9271     _ASSERTE(module->IsRvaFieldTls(field->GetOffset()));
9272
9273     result = module->GetTlsIndex();
9274
9275     EE_TO_JIT_TRANSITION();
9276
9277     return result;
9278 }
9279
9280 void *CEEInfo::allocateArray(size_t cBytes)
9281 {
9282     CONTRACTL {
9283         THROWS;
9284         GC_TRIGGERS;
9285         MODE_PREEMPTIVE;
9286     } CONTRACTL_END;
9287
9288     void * result = NULL;
9289
9290     JIT_TO_EE_TRANSITION();
9291
9292     result = new BYTE [cBytes];
9293
9294     EE_TO_JIT_TRANSITION();
9295
9296     return result;
9297 }
9298
9299 void CEEInfo::freeArrayInternal(void* array)
9300 {
9301     CONTRACTL {
9302         NOTHROW;
9303         GC_NOTRIGGER;
9304         MODE_PREEMPTIVE;
9305     } CONTRACTL_END;
9306
9307     delete [] ((BYTE*) array);
9308 }
9309
9310 void CEEInfo::freeArray(void *array)
9311 {
9312     CONTRACTL {
9313         NOTHROW;
9314         GC_NOTRIGGER;
9315         MODE_PREEMPTIVE;
9316     } CONTRACTL_END;
9317
9318     JIT_TO_EE_TRANSITION();
9319
9320     freeArrayInternal(array);
9321
9322     EE_TO_JIT_TRANSITION();
9323 }
9324
9325 void CEEInfo::getBoundaries(CORINFO_METHOD_HANDLE ftn,
9326                                unsigned int *cILOffsets, uint32_t **pILOffsets,
9327                                ICorDebugInfo::BoundaryTypes *implicitBoundaries)
9328 {
9329     CONTRACTL {
9330         THROWS;
9331         GC_TRIGGERS;
9332         MODE_PREEMPTIVE;
9333     } CONTRACTL_END;
9334
9335     JIT_TO_EE_TRANSITION();
9336
9337 #ifdef DEBUGGING_SUPPORTED
9338     if (g_pDebugInterface)
9339     {
9340         g_pDebugInterface->getBoundaries(GetMethod(ftn), cILOffsets, (DWORD**)pILOffsets,
9341                                      implicitBoundaries);
9342     }
9343     else
9344     {
9345         *cILOffsets = 0;
9346         *pILOffsets = NULL;
9347         *implicitBoundaries = ICorDebugInfo::DEFAULT_BOUNDARIES;
9348     }
9349 #endif // DEBUGGING_SUPPORTED
9350
9351     EE_TO_JIT_TRANSITION();
9352 }
9353
9354 void CEEInfo::getVars(CORINFO_METHOD_HANDLE ftn, ULONG32 *cVars, ICorDebugInfo::ILVarInfo **vars,
9355                          bool *extendOthers)
9356 {
9357     CONTRACTL {
9358         THROWS;
9359         GC_TRIGGERS;
9360         MODE_PREEMPTIVE;
9361     } CONTRACTL_END;
9362
9363     JIT_TO_EE_TRANSITION();
9364
9365 #ifdef DEBUGGING_SUPPORTED
9366     if (g_pDebugInterface)
9367     {
9368         g_pDebugInterface->getVars(GetMethod(ftn), cVars, vars, extendOthers);
9369     }
9370     else
9371     {
9372         *cVars = 0;
9373         *vars = NULL;
9374
9375         // Just tell the JIT to extend everything.
9376         *extendOthers = true;
9377     }
9378 #endif // DEBUGGING_SUPPORTED
9379
9380     EE_TO_JIT_TRANSITION();
9381 }
9382
9383 /*********************************************************************/
9384 CORINFO_ARG_LIST_HANDLE CEEInfo::getArgNext(CORINFO_ARG_LIST_HANDLE args)
9385 {
9386     CONTRACTL {
9387         THROWS;
9388         GC_TRIGGERS;
9389         MODE_PREEMPTIVE;
9390     } CONTRACTL_END;
9391
9392     CORINFO_ARG_LIST_HANDLE result = NULL;
9393
9394     JIT_TO_EE_TRANSITION();
9395
9396     SigPointer ptr((unsigned __int8*) args);
9397     IfFailThrow(ptr.SkipExactlyOne());
9398
9399     result = (CORINFO_ARG_LIST_HANDLE) ptr.GetPtr();
9400
9401     EE_TO_JIT_TRANSITION();
9402
9403     return result;
9404 }
9405
9406
9407 /*********************************************************************/
9408
9409 CorInfoTypeWithMod CEEInfo::getArgType (
9410         CORINFO_SIG_INFO*       sig,
9411         CORINFO_ARG_LIST_HANDLE args,
9412         CORINFO_CLASS_HANDLE*   vcTypeRet
9413         )
9414 {
9415     CONTRACTL {
9416         THROWS;
9417         GC_TRIGGERS;
9418         MODE_PREEMPTIVE;
9419     } CONTRACTL_END;
9420
9421     CorInfoTypeWithMod result = CorInfoTypeWithMod(CORINFO_TYPE_UNDEF);
9422
9423     JIT_TO_EE_TRANSITION();
9424
9425    _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args && (BYTE*) args < (BYTE*) sig->pSig + sig->cbSig);
9426    _ASSERTE((BYTE*) sig->args <= (BYTE*) args);
9427     INDEBUG(*vcTypeRet = CORINFO_CLASS_HANDLE((size_t)INVALID_POINTER_CC));
9428
9429     SigPointer ptr((unsigned __int8*) args);
9430     CorElementType eType;
9431     IfFailThrow(ptr.PeekElemType(&eType));
9432     while (eType == ELEMENT_TYPE_PINNED)
9433     {
9434         result = CORINFO_TYPE_MOD_PINNED;
9435         IfFailThrow(ptr.GetElemType(NULL));
9436         IfFailThrow(ptr.PeekElemType(&eType));
9437     }
9438
9439     // Now read off the "real" element type after taking any instantiations into consideration
9440     SigTypeContext typeContext;
9441     GetTypeContext(&sig->sigInst,&typeContext);
9442
9443     Module* pModule = GetModule(sig->scope);
9444
9445     CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9446
9447     TypeHandle typeHnd = TypeHandle();
9448     switch (type) {
9449       case ELEMENT_TYPE_VAR :
9450       case ELEMENT_TYPE_MVAR :
9451       case ELEMENT_TYPE_VALUETYPE :
9452       case ELEMENT_TYPE_TYPEDBYREF :
9453       case ELEMENT_TYPE_INTERNAL :
9454       {
9455             typeHnd = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9456             _ASSERTE(!typeHnd.IsNull());
9457
9458             CorElementType normType = typeHnd.GetInternalCorElementType();
9459
9460             // if we are looking up a value class, don't morph it to a refernece type
9461             // (This can only happen in illegal IL)
9462             if (!CorTypeInfo::IsObjRef(normType) || type != ELEMENT_TYPE_VALUETYPE)
9463             {
9464                 type = normType;
9465             }
9466         }
9467         break;
9468
9469     case ELEMENT_TYPE_PTR:
9470         // Load the type eagerly under debugger to make the eval work
9471         if (CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
9472         {
9473             // NOTE: in some IJW cases, when the type pointed at is unmanaged,
9474             // the GetTypeHandle may fail, because there is no TypeDef for such type.
9475             // Usage of GetTypeHandleThrowing would lead to class load exception
9476             TypeHandle thPtr = ptr.GetTypeHandleNT(pModule, &typeContext);
9477             if(!thPtr.IsNull())
9478             {
9479                 classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(thPtr.AsPtr()));
9480             }
9481         }
9482         break;
9483
9484     case ELEMENT_TYPE_VOID:
9485         // void is not valid in local sigs
9486         if (sig->flags & CORINFO_SIGFLAG_IS_LOCAL_SIG)
9487             COMPlusThrowHR(COR_E_INVALIDPROGRAM);
9488         break;
9489
9490     case ELEMENT_TYPE_END:
9491            COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9492         break;
9493
9494     default:
9495         break;
9496     }
9497
9498     result = CorInfoTypeWithMod(result | CEEInfo::asCorInfoType(type, typeHnd, vcTypeRet));
9499     EE_TO_JIT_TRANSITION();
9500
9501     return result;
9502 }
9503
9504 // Now the implementation is only focused on the float fields info,
9505 // while a struct-arg has no more than two fields and total size is no larger than two-pointer-size.
9506 // These depends on the platform's ABI rules.
9507 //
9508 // The returned value's encoding details how a struct argument uses float registers:
9509 // see the enum `StructFloatFieldInfoFlags`.
9510 uint32_t CEEInfo::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls)
9511 {
9512     CONTRACTL {
9513         NOTHROW;
9514         GC_NOTRIGGER;
9515         MODE_PREEMPTIVE;
9516     } CONTRACTL_END;
9517
9518     JIT_TO_EE_TRANSITION_LEAF();
9519
9520     uint32_t size = STRUCT_NO_FLOAT_FIELD;
9521
9522 #if defined(TARGET_LOONGARCH64)
9523     size = (uint32_t)MethodTable::GetLoongArch64PassStructInRegisterFlags(TypeHandle(cls));
9524 #endif
9525
9526     EE_TO_JIT_TRANSITION_LEAF();
9527
9528     return size;
9529 }
9530
9531 uint32_t CEEInfo::getRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls)
9532 {
9533     CONTRACTL {
9534         NOTHROW;
9535         GC_NOTRIGGER;
9536         MODE_PREEMPTIVE;
9537     } CONTRACTL_END;
9538
9539     JIT_TO_EE_TRANSITION_LEAF();
9540
9541     uint32_t size = STRUCT_NO_FLOAT_FIELD;
9542
9543 #if defined(TARGET_RISCV64)
9544     size = (uint32_t)MethodTable::GetRiscV64PassStructInRegisterFlags(TypeHandle(cls));
9545 #endif // TARGET_RISCV64
9546
9547     EE_TO_JIT_TRANSITION_LEAF();
9548
9549     return size;
9550 }
9551
9552 /*********************************************************************/
9553
9554 int CEEInfo::getExactClasses (
9555         CORINFO_CLASS_HANDLE  baseType,
9556         int                   maxExactClasses,
9557         CORINFO_CLASS_HANDLE* exactClsRet
9558         )
9559 {
9560     CONTRACTL {
9561         NOTHROW;
9562         GC_NOTRIGGER;
9563         MODE_ANY;
9564     } CONTRACTL_END;
9565
9566     int exactClassesCount = 0;
9567
9568     JIT_TO_EE_TRANSITION();
9569
9570     // This function is currently implemented only on NativeAOT
9571     // but can be implemented for CoreCLR as well (e.g. for internal types)
9572
9573     EE_TO_JIT_TRANSITION();
9574
9575     return exactClassesCount;
9576 }
9577
9578 /*********************************************************************/
9579
9580 CORINFO_CLASS_HANDLE CEEInfo::getArgClass (
9581     CORINFO_SIG_INFO*       sig,
9582     CORINFO_ARG_LIST_HANDLE args
9583     )
9584 {
9585     CONTRACTL {
9586         THROWS;
9587         GC_TRIGGERS;
9588         MODE_PREEMPTIVE;
9589     } CONTRACTL_END;
9590
9591     CORINFO_CLASS_HANDLE result = NULL;
9592
9593     JIT_TO_EE_TRANSITION();
9594
9595     // make certain we dont have a completely wacked out sig pointer
9596     _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args);
9597     _ASSERTE((BYTE*) sig->args <= (BYTE*) args && (BYTE*) args < &((BYTE*) sig->args)[0x10000*5]);
9598
9599     Module* pModule = GetModule(sig->scope);
9600
9601     SigPointer ptr((unsigned __int8*) args);
9602
9603     CorElementType eType;
9604     IfFailThrow(ptr.PeekElemType(&eType));
9605
9606     while (eType == ELEMENT_TYPE_PINNED)
9607     {
9608         IfFailThrow(ptr.GetElemType(NULL));
9609         IfFailThrow(ptr.PeekElemType(&eType));
9610     }
9611     // Now read off the "real" element type after taking any instantiations into consideration
9612     SigTypeContext typeContext;
9613     GetTypeContext(&sig->sigInst, &typeContext);
9614     CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9615
9616     if (!CorTypeInfo::IsPrimitiveType(type)) {
9617         TypeHandle th = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9618         result = CORINFO_CLASS_HANDLE(th.AsPtr());
9619     }
9620
9621     EE_TO_JIT_TRANSITION();
9622
9623     return result;
9624 }
9625
9626 /*********************************************************************/
9627
9628 CorInfoHFAElemType CEEInfo::getHFAType(CORINFO_CLASS_HANDLE hClass)
9629 {
9630     CONTRACTL {
9631         THROWS;
9632         GC_TRIGGERS;
9633         MODE_PREEMPTIVE;
9634     } CONTRACTL_END;
9635
9636     CorInfoHFAElemType result = CORINFO_HFA_ELEM_NONE;
9637
9638     JIT_TO_EE_TRANSITION();
9639
9640     TypeHandle VMClsHnd(hClass);
9641
9642     result = VMClsHnd.GetHFAType();
9643
9644     EE_TO_JIT_TRANSITION();
9645
9646     return result;
9647 }
9648
9649 namespace
9650 {
9651     CorInfoCallConvExtension getUnmanagedCallConvForSig(CORINFO_MODULE_HANDLE mod, PCCOR_SIGNATURE pSig, DWORD cbSig, bool* pSuppressGCTransition)
9652     {
9653         STANDARD_VM_CONTRACT;
9654
9655         SigParser parser(pSig, cbSig);
9656         uint32_t rawCallConv;
9657         if (FAILED(parser.GetCallingConv(&rawCallConv)))
9658         {
9659             COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9660         }
9661         switch ((CorCallingConvention)rawCallConv)
9662         {
9663         case IMAGE_CEE_CS_CALLCONV_DEFAULT:
9664             _ASSERTE_MSG(false, "bad callconv");
9665             return CorInfoCallConvExtension::Managed;
9666         case IMAGE_CEE_CS_CALLCONV_C:
9667             return CorInfoCallConvExtension::C;
9668         case IMAGE_CEE_CS_CALLCONV_STDCALL:
9669             return CorInfoCallConvExtension::Stdcall;
9670         case IMAGE_CEE_CS_CALLCONV_THISCALL:
9671             return CorInfoCallConvExtension::Thiscall;
9672         case IMAGE_CEE_CS_CALLCONV_FASTCALL:
9673             return CorInfoCallConvExtension::Fastcall;
9674         case IMAGE_CEE_CS_CALLCONV_UNMANAGED:
9675         {
9676             CallConvBuilder builder;
9677             UINT errorResID;
9678             HRESULT hr = CallConv::TryGetUnmanagedCallingConventionFromModOpt(mod, pSig, cbSig, &builder, &errorResID);
9679
9680             if (FAILED(hr))
9681                 COMPlusThrowHR(hr, errorResID);
9682
9683             CorInfoCallConvExtension callConvLocal = builder.GetCurrentCallConv();
9684             if (callConvLocal == CallConvBuilder::UnsetValue)
9685             {
9686                 callConvLocal = CallConv::GetDefaultUnmanagedCallingConvention();
9687             }
9688
9689             *pSuppressGCTransition = builder.IsCurrentCallConvModSet(CallConvBuilder::CALL_CONV_MOD_SUPPRESSGCTRANSITION);
9690             return callConvLocal;
9691         }
9692         case IMAGE_CEE_CS_CALLCONV_NATIVEVARARG:
9693             return CorInfoCallConvExtension::C;
9694         default:
9695             _ASSERTE_MSG(false, "bad callconv");
9696             return CorInfoCallConvExtension::Managed;
9697         }
9698     }
9699
9700     CorInfoCallConvExtension getUnmanagedCallConvForMethod(MethodDesc* pMD, bool* pSuppressGCTransition)
9701     {
9702         STANDARD_VM_CONTRACT;
9703
9704         uint32_t methodCallConv;
9705         PCCOR_SIGNATURE pSig;
9706         DWORD cbSig;
9707         pMD->GetSig(&pSig, &cbSig);
9708         if (FAILED(SigParser(pSig, cbSig).GetCallingConv(&methodCallConv)))
9709         {
9710             COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9711         }
9712
9713         if (methodCallConv == CORINFO_CALLCONV_DEFAULT || methodCallConv == CORINFO_CALLCONV_VARARG)
9714         {
9715             _ASSERTE(pMD->IsNDirect() || pMD->HasUnmanagedCallersOnlyAttribute());
9716             if (pMD->IsNDirect())
9717             {
9718                 CorInfoCallConvExtension unmanagedCallConv;
9719                 NDirect::GetCallingConvention_IgnoreErrors(pMD, &unmanagedCallConv, pSuppressGCTransition);
9720                 return unmanagedCallConv;
9721             }
9722             else
9723             {
9724                 CorInfoCallConvExtension unmanagedCallConv;
9725                 if (CallConv::TryGetCallingConventionFromUnmanagedCallersOnly(pMD, &unmanagedCallConv))
9726                 {
9727                     if (methodCallConv == IMAGE_CEE_CS_CALLCONV_VARARG)
9728                     {
9729                         return CorInfoCallConvExtension::C;
9730                     }
9731                     return unmanagedCallConv;
9732                 }
9733                 return CallConv::GetDefaultUnmanagedCallingConvention();
9734             }
9735         }
9736         else
9737         {
9738             return getUnmanagedCallConvForSig(GetScopeHandle(pMD->GetModule()), pSig, cbSig, pSuppressGCTransition);
9739         }
9740     }
9741 }
9742
9743 /*********************************************************************/
9744
9745     // return the entry point calling convention for any of the following
9746     // - a P/Invoke
9747     // - a method marked with UnmanagedCallersOnly
9748     // - a function pointer with the CORINFO_CALLCONV_UNMANAGED calling convention.
9749 CorInfoCallConvExtension CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition)
9750 {
9751     CONTRACTL {
9752         THROWS;
9753         GC_TRIGGERS;
9754         MODE_PREEMPTIVE;
9755     } CONTRACTL_END;
9756
9757     CorInfoCallConvExtension callConv = CorInfoCallConvExtension::Managed;
9758
9759     JIT_TO_EE_TRANSITION();
9760
9761     if (pSuppressGCTransition)
9762     {
9763         *pSuppressGCTransition = false;
9764     }
9765
9766     if (method)
9767     {
9768         callConv = getUnmanagedCallConvForMethod(GetMethod(method), pSuppressGCTransition);
9769     }
9770     else
9771     {
9772         _ASSERTE(callSiteSig != nullptr);
9773         callConv = getUnmanagedCallConvForSig(callSiteSig->scope, callSiteSig->pSig, callSiteSig->cbSig, pSuppressGCTransition);
9774     }
9775
9776     EE_TO_JIT_TRANSITION();
9777
9778     return callConv;
9779 }
9780
9781 /*********************************************************************/
9782 bool CEEInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig)
9783 {
9784     CONTRACTL {
9785         THROWS;
9786         GC_TRIGGERS;
9787         MODE_PREEMPTIVE;
9788     } CONTRACTL_END;
9789
9790     bool result = false;
9791
9792     JIT_TO_EE_TRANSITION();
9793
9794     if (method == NULL)
9795     {
9796         // check the call site signature
9797         result = NDirect::MarshalingRequired(
9798                     NULL,
9799                     callSiteSig->pSig,
9800                     GetModule(callSiteSig->scope));
9801     }
9802     else
9803     {
9804         MethodDesc* ftn = GetMethod(method);
9805         _ASSERTE(ftn->IsNDirect());
9806         NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9807
9808 #if defined(HAS_NDIRECT_IMPORT_PRECODE)
9809         if (pMD->IsVarArg())
9810         {
9811             // Varag P/Invoke must not be inlined because its NDirectMethodDesc
9812             // does not contain a meaningful stack size (it is call site specific).
9813             // See code:InlinedCallFrame.UpdateRegDisplay where this is needed.
9814             result = TRUE;
9815         }
9816         else if (pMD->MarshalingRequired())
9817         {
9818             // This is not a no-marshal signature.
9819             result = TRUE;
9820         }
9821         else
9822         {
9823             // This is a no-marshal non-vararg signature.
9824             result = FALSE;
9825         }
9826 #else
9827         // Marshalling is required to lazy initialize the indirection cell
9828         // without NDirectImportPrecode.
9829         result = TRUE;
9830 #endif
9831     }
9832
9833     PrepareCodeConfig *config = GetThread()->GetCurrentPrepareCodeConfig();
9834     if (config != nullptr && config->IsForMulticoreJit())
9835     {
9836         bool suppressGCTransition = false;
9837         CorInfoCallConvExtension unmanagedCallConv = getUnmanagedCallConv(method, callSiteSig, &suppressGCTransition);
9838
9839         if (suppressGCTransition)
9840         {
9841             // MultiCoreJit thread can't inline PInvoke with SuppressGCTransitionAttribute,
9842             // because it can't be resolved in mcj thread
9843             result = TRUE;
9844         }
9845     }
9846
9847     EE_TO_JIT_TRANSITION();
9848
9849     return result;
9850 }
9851
9852 /*********************************************************************/
9853 // Generate a cookie based on the signature that would needs to be passed
9854 // to CORINFO_HELP_PINVOKE_CALLI
9855 LPVOID CEEInfo::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig,
9856                                             void **ppIndirection)
9857 {
9858     WRAPPER_NO_CONTRACT;
9859
9860     return getVarArgsHandle(szMetaSig, ppIndirection);
9861 }
9862
9863 bool CEEInfo::canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig)
9864 {
9865     LIMITED_METHOD_CONTRACT;
9866     return true;
9867 }
9868
9869
9870 // Check any constraints on method type arguments
9871 bool CEEInfo::satisfiesMethodConstraints(
9872     CORINFO_CLASS_HANDLE        parent,
9873     CORINFO_METHOD_HANDLE       method)
9874 {
9875     CONTRACTL {
9876         THROWS;
9877         GC_TRIGGERS;
9878         MODE_PREEMPTIVE;
9879     } CONTRACTL_END;
9880
9881     bool result = false;
9882
9883     JIT_TO_EE_TRANSITION();
9884
9885     _ASSERTE(parent != NULL);
9886     _ASSERTE(method != NULL);
9887     result = !!GetMethod(method)->SatisfiesMethodConstraints(TypeHandle(parent));
9888
9889     EE_TO_JIT_TRANSITION();
9890
9891     return result;
9892 }
9893
9894
9895 /*********************************************************************/
9896 // return address of fixup area for late-bound N/Direct calls.
9897 void CEEInfo::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method,
9898                                         CORINFO_CONST_LOOKUP *pLookup)
9899 {
9900     CONTRACTL {
9901         THROWS;
9902         GC_TRIGGERS;
9903         MODE_PREEMPTIVE;
9904     } CONTRACTL_END;
9905
9906     JIT_TO_EE_TRANSITION();
9907
9908     MethodDesc* pMD = GetMethod(method);
9909     _ASSERTE(pMD->IsNDirect());
9910
9911     NDirectMethodDesc* pNMD = reinterpret_cast<NDirectMethodDesc*>(pMD);
9912
9913     void* pIndirection;
9914     if (NDirectMethodDesc::TryGetResolvedNDirectTarget(pNMD, &pIndirection))
9915     {
9916         pLookup->accessType = IAT_VALUE;
9917         pLookup->addr = pIndirection;
9918     }
9919     else
9920     {
9921         pLookup->accessType = IAT_PVALUE;
9922         pLookup->addr = (LPVOID)&(pNMD->GetWriteableData()->m_pNDirectTarget);
9923     }
9924
9925     EE_TO_JIT_TRANSITION();
9926 }
9927
9928 /*********************************************************************/
9929 CORINFO_JUST_MY_CODE_HANDLE CEEInfo::getJustMyCodeHandle(
9930                 CORINFO_METHOD_HANDLE       method,
9931                 CORINFO_JUST_MY_CODE_HANDLE**ppIndirection)
9932 {
9933     CONTRACTL {
9934         NOTHROW;
9935         GC_NOTRIGGER;
9936         MODE_PREEMPTIVE;
9937     } CONTRACTL_END;
9938
9939     CORINFO_JUST_MY_CODE_HANDLE result = NULL;
9940
9941     if (ppIndirection)
9942         *ppIndirection = NULL;
9943
9944     JIT_TO_EE_TRANSITION_LEAF();
9945
9946     // Get the flag from the debugger.
9947     MethodDesc* ftn = GetMethod(method);
9948     DWORD * pFlagAddr = NULL;
9949
9950     if (g_pDebugInterface)
9951     {
9952         pFlagAddr = g_pDebugInterface->GetJMCFlagAddr(ftn->GetModule());
9953     }
9954
9955     result = (CORINFO_JUST_MY_CODE_HANDLE) pFlagAddr;
9956
9957     EE_TO_JIT_TRANSITION_LEAF();
9958
9959     return result;
9960 }
9961
9962 /*********************************************************************/
9963 void InlinedCallFrame::GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo *pInfo)
9964 {
9965     LIMITED_METHOD_CONTRACT;
9966
9967     pInfo->size                          = sizeof(GSCookie) + sizeof(InlinedCallFrame);
9968
9969     pInfo->offsetOfGSCookie              = 0;
9970     pInfo->offsetOfFrameVptr             = sizeof(GSCookie);
9971     pInfo->offsetOfFrameLink             = sizeof(GSCookie) + Frame::GetOffsetOfNextLink();
9972     pInfo->offsetOfCallSiteSP            = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallSiteSP);
9973     pInfo->offsetOfCalleeSavedFP         = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCalleeSavedFP);
9974     pInfo->offsetOfCallTarget            = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_Datum);
9975     pInfo->offsetOfReturnAddress         = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallerReturnAddress);
9976 #ifdef TARGET_ARM
9977     pInfo->offsetOfSPAfterProlog         = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pSPAfterProlog);
9978 #endif // TARGET_ARM
9979 }
9980
9981 CORINFO_OS getClrVmOs()
9982 {
9983 #ifdef TARGET_OSX
9984     return CORINFO_MACOS;
9985 #elif defined(TARGET_UNIX)
9986     return CORINFO_UNIX;
9987 #else
9988     return CORINFO_WINNT;
9989 #endif
9990 }
9991
9992 /*********************************************************************/
9993 // Return details about EE internal data structures
9994 void CEEInfo::getEEInfo(CORINFO_EE_INFO *pEEInfoOut)
9995 {
9996     CONTRACTL {
9997         THROWS;
9998         GC_TRIGGERS;
9999         MODE_PREEMPTIVE;
10000     } CONTRACTL_END;
10001
10002     INDEBUG(memset(pEEInfoOut, 0xCC, sizeof(*pEEInfoOut)));
10003
10004     JIT_TO_EE_TRANSITION();
10005
10006     InlinedCallFrame::GetEEInfo(&pEEInfoOut->inlinedCallFrameInfo);
10007
10008     // Offsets into the Thread structure
10009     pEEInfoOut->offsetOfThreadFrame = Thread::GetOffsetOfCurrentFrame();
10010     pEEInfoOut->offsetOfGCState     = Thread::GetOffsetOfGCFlag();
10011
10012 #ifndef CROSSBITNESS_COMPILE
10013     // The assertions must hold in every non-crossbitness scenario
10014     _ASSERTE(OFFSETOF__DelegateObject__target       == DelegateObject::GetOffsetOfTarget());
10015     _ASSERTE(OFFSETOF__DelegateObject__methodPtr    == DelegateObject::GetOffsetOfMethodPtr());
10016     _ASSERTE(OFFSETOF__DelegateObject__methodPtrAux == DelegateObject::GetOffsetOfMethodPtrAux());
10017     _ASSERTE(OFFSETOF__PtrArray__m_Array_           == PtrArray::GetDataOffset());
10018 #endif
10019
10020     // Delegate offsets
10021     pEEInfoOut->offsetOfDelegateInstance    = OFFSETOF__DelegateObject__target;
10022     pEEInfoOut->offsetOfDelegateFirstTarget = OFFSETOF__DelegateObject__methodPtr;
10023
10024     // Wrapper delegate offsets
10025     pEEInfoOut->offsetOfWrapperDelegateIndirectCell = OFFSETOF__DelegateObject__methodPtrAux;
10026
10027     pEEInfoOut->sizeOfReversePInvokeFrame = TARGET_POINTER_SIZE * READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits;
10028
10029     // The following assert doesn't work in cross-bitness scenarios since the pointer size differs.
10030 #if (defined(TARGET_64BIT) && defined(HOST_64BIT)) || (defined(TARGET_32BIT) && defined(HOST_32BIT))
10031     _ASSERTE(sizeof(ReversePInvokeFrame) <= pEEInfoOut->sizeOfReversePInvokeFrame);
10032 #endif
10033
10034     pEEInfoOut->osPageSize = GetOsPageSize();
10035     pEEInfoOut->maxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
10036     pEEInfoOut->targetAbi = CORINFO_CORECLR_ABI;
10037     pEEInfoOut->osType = getClrVmOs();
10038
10039     EE_TO_JIT_TRANSITION();
10040 }
10041
10042 const char16_t * CEEInfo::getJitTimeLogFilename()
10043 {
10044     CONTRACTL {
10045         THROWS;
10046         GC_TRIGGERS;
10047         MODE_PREEMPTIVE;
10048     } CONTRACTL_END;
10049
10050     LPCWSTR result = NULL;
10051
10052     JIT_TO_EE_TRANSITION();
10053     result = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitTimeLogFile);
10054     EE_TO_JIT_TRANSITION();
10055
10056     return (const char16_t *)result;
10057 }
10058
10059
10060
10061     // Return details about EE internal data structures
10062 uint32_t CEEInfo::getThreadTLSIndex(void **ppIndirection)
10063 {
10064     CONTRACTL {
10065         THROWS;
10066         GC_TRIGGERS;
10067         MODE_PREEMPTIVE;
10068     } CONTRACTL_END;
10069
10070     uint32_t result = (uint32_t)-1;
10071
10072     if (ppIndirection != NULL)
10073         *ppIndirection = NULL;
10074
10075     return result;
10076 }
10077
10078
10079 int32_t * CEEInfo::getAddrOfCaptureThreadGlobal(void **ppIndirection)
10080 {
10081     CONTRACTL {
10082         NOTHROW;
10083         GC_NOTRIGGER;
10084         MODE_PREEMPTIVE;
10085     } CONTRACTL_END;
10086
10087     int32_t * result = NULL;
10088
10089     if (ppIndirection != NULL)
10090         *ppIndirection = NULL;
10091
10092     JIT_TO_EE_TRANSITION_LEAF();
10093
10094     result = (int32_t *)&g_TrapReturningThreads;
10095
10096     EE_TO_JIT_TRANSITION_LEAF();
10097
10098     return result;
10099 }
10100
10101
10102 // This method is called from CEEInfo::FilterException which
10103 // is run as part of the SEH filter clause for the JIT.
10104 // It is fatal to throw an exception while running a SEH filter clause
10105 // so our contract is NOTHROW, NOTRIGGER.
10106 //
10107 LONG EEFilterException(struct _EXCEPTION_POINTERS *pExceptionPointers, void *unused)
10108 {
10109     CONTRACTL {
10110         NOTHROW;
10111         GC_NOTRIGGER;
10112     } CONTRACTL_END;
10113
10114     int result = 0;
10115
10116     JIT_TO_EE_TRANSITION_LEAF();
10117
10118     unsigned code = pExceptionPointers->ExceptionRecord->ExceptionCode;
10119
10120 #ifdef _DEBUG
10121     if (code == EXCEPTION_ACCESS_VIOLATION)
10122     {
10123         static int hit = 0;
10124         if (hit++ == 0)
10125         {
10126             _ASSERTE(!"Access violation while Jitting!");
10127             // If you set the debugger to catch access violations and 'go'
10128             // you will get back to the point at which the access violation occurred
10129             result = EXCEPTION_CONTINUE_EXECUTION;
10130         }
10131         else
10132         {
10133             result = EXCEPTION_CONTINUE_SEARCH;
10134         }
10135     }
10136     else
10137 #endif // _DEBUG
10138     // No one should be catching breakpoint
10139     // Similarly the JIT doesn't know how to reset the guard page, so it shouldn't
10140     // be catching a hard stack overflow
10141     if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP || code == EXCEPTION_STACK_OVERFLOW)
10142     {
10143         result = EXCEPTION_CONTINUE_SEARCH;
10144     }
10145     else if (!IsComPlusException(pExceptionPointers->ExceptionRecord))
10146     {
10147         result = EXCEPTION_EXECUTE_HANDLER;
10148     }
10149     else
10150     {
10151         GCX_COOP();
10152
10153         // This is actually the LastThrown exception object.
10154         OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10155
10156         if (throwable != NULL)
10157         {
10158             struct
10159             {
10160                 OBJECTREF oLastThrownObject;
10161             } _gc;
10162
10163             ZeroMemory(&_gc, sizeof(_gc));
10164
10165             // Setup the throwables
10166             _gc.oLastThrownObject = throwable;
10167
10168             GCPROTECT_BEGIN(_gc);
10169
10170             // Don't catch ThreadAbort and other uncatchable exceptions
10171             if (IsUncatchable(&_gc.oLastThrownObject))
10172                 result = EXCEPTION_CONTINUE_SEARCH;
10173             else
10174                 result = EXCEPTION_EXECUTE_HANDLER;
10175
10176             GCPROTECT_END();
10177         }
10178     }
10179
10180     EE_TO_JIT_TRANSITION_LEAF();
10181
10182     return result;
10183 }
10184
10185 // This code is called if FilterException chose to handle the exception.
10186 void CEEInfo::HandleException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10187 {
10188     CONTRACTL {
10189         NOTHROW;
10190         GC_NOTRIGGER;
10191     } CONTRACTL_END;
10192
10193     JIT_TO_EE_TRANSITION_LEAF();
10194
10195     if (IsComPlusException(pExceptionPointers->ExceptionRecord))
10196     {
10197         GCX_COOP();
10198
10199         // This is actually the LastThrown exception object.
10200         OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10201
10202         if (throwable != NULL)
10203         {
10204             struct
10205             {
10206                 OBJECTREF oLastThrownObject;
10207                 OBJECTREF oCurrentThrowable;
10208             } _gc;
10209
10210             ZeroMemory(&_gc, sizeof(_gc));
10211
10212             PTR_Thread pCurThread = GetThread();
10213
10214             // Setup the throwables
10215             _gc.oLastThrownObject = throwable;
10216
10217             // This will be NULL if no managed exception is active. Otherwise,
10218             // it will reference the active throwable.
10219             _gc.oCurrentThrowable = pCurThread->GetThrowable();
10220
10221             GCPROTECT_BEGIN(_gc);
10222
10223             // JIT does not use or reference managed exceptions at all and simply swallows them,
10224             // or lets them fly through so that they will either get caught in managed code, the VM
10225             // or will go unhandled.
10226             //
10227             // Blind swallowing of managed exceptions can break the semantic of "which exception handler"
10228             // gets to process the managed exception first. The expected handler is managed code exception
10229             // handler (e.g. COMPlusFrameHandler on x86 and ProcessCLRException on 64bit) which will setup
10230             // the exception tracker for the exception that will enable the expected sync between the
10231             // LastThrownObject (LTO), setup in RaiseTheExceptionInternalOnly, and the exception tracker.
10232             //
10233             // However, JIT can break this by swallowing the managed exception before managed code exception
10234             // handler gets a chance to setup an exception tracker for it. Since there is no cleanup
10235             // done for the swallowed exception as part of the unwind (because no exception tracker may have been setup),
10236             // we need to reset the LTO, if it is out of sync from the active throwable.
10237             //
10238             // Hence, check if the LastThrownObject and active-exception throwable are in sync or not.
10239             // If not, bring them in sync.
10240             //
10241             // Example
10242             // -------
10243             // It is possible that an exception was already in progress and while processing it (e.g.
10244             // invoking finally block), we invoked JIT that had another managed exception @ JIT-EE transition boundary
10245             // that is swallowed by the JIT before managed code exception handler sees it. This breaks the sync between
10246             // LTO and the active exception in the exception tracker.
10247             if (_gc.oCurrentThrowable != _gc.oLastThrownObject)
10248             {
10249                 // Update the LTO.
10250                 //
10251                 // Note: Incase of OOM, this will get set to OOM instance.
10252                 pCurThread->SafeSetLastThrownObject(_gc.oCurrentThrowable);
10253             }
10254
10255             GCPROTECT_END();
10256         }
10257     }
10258
10259     EE_TO_JIT_TRANSITION_LEAF();
10260 }
10261
10262 CORINFO_MODULE_HANDLE CEEInfo::embedModuleHandle(CORINFO_MODULE_HANDLE handle,
10263                                                  void **ppIndirection)
10264 {
10265     CONTRACTL {
10266         NOTHROW;
10267         GC_NOTRIGGER;
10268         MODE_PREEMPTIVE;
10269         PRECONDITION(!IsDynamicScope(handle));
10270     }
10271     CONTRACTL_END;
10272
10273     if (ppIndirection != NULL)
10274         *ppIndirection = NULL;
10275
10276     JIT_TO_EE_TRANSITION_LEAF();
10277
10278     EE_TO_JIT_TRANSITION_LEAF();
10279
10280     return handle;
10281 }
10282
10283 CORINFO_CLASS_HANDLE CEEInfo::embedClassHandle(CORINFO_CLASS_HANDLE handle,
10284                                                void **ppIndirection)
10285 {
10286     CONTRACTL {
10287         NOTHROW;
10288         GC_NOTRIGGER;
10289         MODE_PREEMPTIVE;
10290     }
10291     CONTRACTL_END;
10292
10293     if (ppIndirection != NULL)
10294         *ppIndirection = NULL;
10295
10296     JIT_TO_EE_TRANSITION_LEAF();
10297
10298     EE_TO_JIT_TRANSITION_LEAF();
10299
10300     return handle;
10301 }
10302
10303 CORINFO_FIELD_HANDLE CEEInfo::embedFieldHandle(CORINFO_FIELD_HANDLE handle,
10304                                                void **ppIndirection)
10305 {
10306     CONTRACTL {
10307         NOTHROW;
10308         GC_NOTRIGGER;
10309         MODE_PREEMPTIVE;
10310     }
10311     CONTRACTL_END;
10312
10313     if (ppIndirection != NULL)
10314         *ppIndirection = NULL;
10315
10316     JIT_TO_EE_TRANSITION_LEAF();
10317
10318     EE_TO_JIT_TRANSITION_LEAF();
10319
10320     return handle;
10321 }
10322
10323 CORINFO_METHOD_HANDLE CEEInfo::embedMethodHandle(CORINFO_METHOD_HANDLE handle,
10324                                                  void **ppIndirection)
10325 {
10326     CONTRACTL {
10327         NOTHROW;
10328         GC_NOTRIGGER;
10329         MODE_PREEMPTIVE;
10330     }
10331     CONTRACTL_END;
10332
10333     if (ppIndirection != NULL)
10334         *ppIndirection = NULL;
10335
10336     JIT_TO_EE_TRANSITION_LEAF();
10337
10338     EE_TO_JIT_TRANSITION_LEAF();
10339
10340     return handle;
10341 }
10342
10343 /*********************************************************************/
10344 void CEEInfo::setJitFlags(const CORJIT_FLAGS& jitFlags)
10345 {
10346     LIMITED_METHOD_CONTRACT;
10347
10348     m_jitFlags = jitFlags;
10349 }
10350
10351 /*********************************************************************/
10352 uint32_t CEEInfo::getJitFlags(CORJIT_FLAGS* jitFlags, uint32_t sizeInBytes)
10353 {
10354     CONTRACTL {
10355         NOTHROW;
10356         GC_NOTRIGGER;
10357         MODE_PREEMPTIVE;
10358     } CONTRACTL_END;
10359
10360     JIT_TO_EE_TRANSITION_LEAF();
10361
10362     _ASSERTE(sizeInBytes >= sizeof(m_jitFlags));
10363     *jitFlags = m_jitFlags;
10364
10365     EE_TO_JIT_TRANSITION_LEAF();
10366
10367     return sizeof(m_jitFlags);
10368 }
10369
10370 /*********************************************************************/
10371 #if !defined(TARGET_UNIX)
10372
10373 struct RunWithErrorTrapFilterParam
10374 {
10375     ICorDynamicInfo* m_corInfo;
10376     void (*m_function)(void*);
10377     void* m_param;
10378     EXCEPTION_POINTERS m_exceptionPointers;
10379 };
10380
10381 static LONG RunWithErrorTrapFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
10382 {
10383     WRAPPER_NO_CONTRACT;
10384
10385     auto* param = reinterpret_cast<RunWithErrorTrapFilterParam*>(theParam);
10386     param->m_exceptionPointers = *exceptionPointers;
10387     return EEFilterException(exceptionPointers, nullptr);
10388 }
10389
10390 #endif // !defined(TARGET_UNIX)
10391
10392 bool CEEInfo::runWithSPMIErrorTrap(void (*function)(void*), void* param)
10393 {
10394     // No dynamic contract here because SEH is used
10395     STATIC_CONTRACT_THROWS;
10396     STATIC_CONTRACT_GC_TRIGGERS;
10397     STATIC_CONTRACT_MODE_PREEMPTIVE;
10398
10399     // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
10400     //       transitions into the EE proper should occur either via JIT/EE
10401     //       interface calls made by `function`.
10402
10403     // As we aren't SPMI, we don't need to do anything other than call the function.
10404
10405     function(param);
10406     return true;
10407 }
10408
10409 bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param)
10410 {
10411     // No dynamic contract here because SEH is used
10412     STATIC_CONTRACT_THROWS;
10413     STATIC_CONTRACT_GC_TRIGGERS;
10414     STATIC_CONTRACT_MODE_PREEMPTIVE;
10415
10416     // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
10417     //       transitions into the EE proper should occur either via the call to
10418     //       `EEFilterException` (which is appropriately marked) or via JIT/EE
10419     //       interface calls made by `function`.
10420
10421     bool success = true;
10422
10423 #if !defined(TARGET_UNIX)
10424
10425     RunWithErrorTrapFilterParam trapParam;
10426     trapParam.m_corInfo = this;
10427     trapParam.m_function = function;
10428     trapParam.m_param = param;
10429
10430     PAL_TRY(RunWithErrorTrapFilterParam*, pTrapParam, &trapParam)
10431     {
10432         pTrapParam->m_function(pTrapParam->m_param);
10433     }
10434     PAL_EXCEPT_FILTER(RunWithErrorTrapFilter)
10435     {
10436         HandleException(&trapParam.m_exceptionPointers);
10437         success = false;
10438     }
10439     PAL_ENDTRY
10440
10441 #else // !defined(TARGET_UNIX)
10442
10443     // We shouldn't need PAL_TRY on *nix: any exceptions that we are able to catch
10444     // ought to originate from the runtime itself and should be catchable inside of
10445     // EX_TRY/EX_CATCH, including emulated SEH exceptions.
10446     EX_TRY
10447     {
10448         function(param);
10449     }
10450     EX_CATCH
10451     {
10452         success = false;
10453     }
10454     EX_END_CATCH(RethrowTerminalExceptions);
10455
10456 #endif
10457
10458     return success;
10459 }
10460
10461 /*********************************************************************/
10462 int CEEInfo::doAssert(const char* szFile, int iLine, const char* szExpr)
10463 {
10464     STATIC_CONTRACT_THROWS;
10465     STATIC_CONTRACT_GC_TRIGGERS;
10466     STATIC_CONTRACT_MODE_PREEMPTIVE;
10467     STATIC_CONTRACT_DEBUG_ONLY;
10468
10469     int result = 0;
10470
10471     JIT_TO_EE_TRANSITION();
10472
10473
10474 #ifdef _DEBUG
10475     BEGIN_DEBUG_ONLY_CODE;
10476     if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitThrowOnAssertionFailure) != 0)
10477     {
10478         SString output;
10479         output.Printf(
10480             "JIT assert failed:\n"
10481             "%s\n"
10482             "    File: %s Line: %d\n",
10483             szExpr, szFile, iLine);
10484         COMPlusThrowNonLocalized(kInvalidProgramException, output.GetUnicode());
10485     }
10486
10487     result = _DbgBreakCheck(szFile, iLine, szExpr);
10488     END_DEBUG_ONLY_CODE;
10489 #else // !_DEBUG
10490     result = 1;   // break into debugger
10491 #endif // !_DEBUG
10492
10493
10494     EE_TO_JIT_TRANSITION();
10495
10496     return result;
10497 }
10498
10499 void CEEInfo::reportFatalError(CorJitResult result)
10500 {
10501     STATIC_CONTRACT_THROWS;
10502     STATIC_CONTRACT_GC_TRIGGERS;
10503     STATIC_CONTRACT_MODE_PREEMPTIVE;
10504
10505     JIT_TO_EE_TRANSITION_LEAF();
10506
10507     STRESS_LOG2(LF_JIT,LL_ERROR, "Jit reported error 0x%x while compiling 0x%p\n",
10508                 (int)result, (INT_PTR)getMethodBeingCompiled());
10509
10510     EE_TO_JIT_TRANSITION_LEAF();
10511 }
10512
10513 bool CEEInfo::logMsg(unsigned level, const char* fmt, va_list args)
10514 {
10515     STATIC_CONTRACT_THROWS;
10516     STATIC_CONTRACT_GC_TRIGGERS;
10517     STATIC_CONTRACT_MODE_PREEMPTIVE;
10518     STATIC_CONTRACT_DEBUG_ONLY;
10519
10520     bool result = false;
10521
10522     JIT_TO_EE_TRANSITION_LEAF();
10523
10524 #ifdef LOGGING
10525     if (LoggingOn(LF_JIT, level))
10526     {
10527         LogSpewValist(LF_JIT, level, (char*) fmt, args);
10528         result = true;
10529     }
10530 #endif // LOGGING
10531
10532     EE_TO_JIT_TRANSITION_LEAF();
10533
10534     return result;
10535 }
10536
10537
10538 /*********************************************************************/
10539
10540 void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc    ftnNum,         /* IN  */
10541                                void **            ppIndirection)  /* OUT */
10542 {
10543     CONTRACTL {
10544         NOTHROW;
10545         GC_NOTRIGGER;
10546         MODE_PREEMPTIVE;
10547     } CONTRACTL_END;
10548
10549     void* result = NULL;
10550
10551     if (ppIndirection != NULL)
10552         *ppIndirection = NULL;
10553
10554     JIT_TO_EE_TRANSITION_LEAF();
10555
10556     _ASSERTE(ftnNum < CORINFO_HELP_COUNT);
10557
10558     void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10559
10560     size_t dynamicFtnNum = ((size_t)pfnHelper - 1);
10561     if (dynamicFtnNum < DYNAMIC_CORINFO_HELP_COUNT)
10562     {
10563 #ifdef _PREFAST_
10564 #pragma warning(push)
10565 #pragma warning(disable:26001) // "Bounds checked above using the underflow trick"
10566 #endif /*_PREFAST_ */
10567
10568 #if defined(TARGET_AMD64)
10569         // To avoid using a jump stub we always call certain helpers using an indirect call.
10570         // Because when using a direct call and the target is father away than 2^31 bytes,
10571         // the direct call instead goes to a jump stub which jumps to the jit helper.
10572         // However in this process the jump stub will corrupt RAX.
10573         //
10574         // The set of helpers for which RAX must be preserved are profiler probes, CFG dispatcher
10575         // and the STOP_FOR_GC helper which maps to JIT_RareDisableHelper.
10576         // In the case of the STOP_FOR_GC helper RAX can be holding a function return value.
10577         //
10578         if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_STOP_FOR_GC    ||
10579             dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER ||
10580             dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE ||
10581             dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL ||
10582             dynamicFtnNum == DYNAMIC_CORINFO_HELP_DISPATCH_INDIRECT_CALL)
10583         {
10584             _ASSERTE(ppIndirection != NULL);
10585             *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10586             return NULL;
10587         }
10588 #endif
10589
10590         if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_ISINSTANCEOFINTERFACE ||
10591             dynamicFtnNum == DYNAMIC_CORINFO_HELP_ISINSTANCEOFANY ||
10592             dynamicFtnNum == DYNAMIC_CORINFO_HELP_ISINSTANCEOFARRAY ||
10593             dynamicFtnNum == DYNAMIC_CORINFO_HELP_ISINSTANCEOFCLASS ||
10594             dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTANY ||
10595             dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTARRAY ||
10596             dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTINTERFACE ||
10597             dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTCLASS ||
10598             dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTCLASS_SPECIAL ||
10599             dynamicFtnNum == DYNAMIC_CORINFO_HELP_UNBOX)
10600         {
10601             Precode* pPrecode = Precode::GetPrecodeFromEntryPoint((PCODE)hlpDynamicFuncTable[dynamicFtnNum].pfnHelper);
10602             _ASSERTE(pPrecode->GetType() == PRECODE_FIXUP);
10603             *ppIndirection = ((FixupPrecode*)pPrecode)->GetTargetSlot();
10604             return NULL;
10605         }
10606
10607         pfnHelper = hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10608
10609 #ifdef _PREFAST_
10610 #pragma warning(pop)
10611 #endif /*_PREFAST_*/
10612     }
10613
10614     _ASSERTE(pfnHelper);
10615
10616     result = (LPVOID)GetEEFuncEntryPoint(pfnHelper);
10617
10618     EE_TO_JIT_TRANSITION_LEAF();
10619
10620     return result;
10621 }
10622
10623 PCODE CEEJitInfo::getHelperFtnStatic(CorInfoHelpFunc ftnNum)
10624 {
10625     LIMITED_METHOD_CONTRACT;
10626
10627     void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10628
10629     // If pfnHelper is an index into the dynamic helper table, it should be less
10630     // than DYNAMIC_CORINFO_HELP_COUNT.  In this case we need to find the actual pfnHelper
10631     // using an extra indirection.  Note the special case
10632     // where pfnHelper==0 where pfnHelper-1 will underflow and we will avoid the indirection.
10633     if (((size_t)pfnHelper - 1) < DYNAMIC_CORINFO_HELP_COUNT)
10634     {
10635         pfnHelper = hlpDynamicFuncTable[((size_t)pfnHelper - 1)].pfnHelper;
10636     }
10637
10638     _ASSERTE(pfnHelper != NULL);
10639
10640     return GetEEFuncEntryPoint(pfnHelper);
10641 }
10642
10643 // Wrapper around CEEInfo::GetProfilingHandle.  The first time this is called for a
10644 // method desc, it calls through to EEToProfInterfaceImpl::EEFunctionIDMappe and caches the
10645 // result in CEEJitInfo::GetProfilingHandleCache.  Thereafter, this wrapper regurgitates the cached values
10646 // rather than calling into CEEInfo::GetProfilingHandle each time.  This avoids
10647 // making duplicate calls into the profiler's FunctionIDMapper callback.
10648 void CEEJitInfo::GetProfilingHandle(bool                      *pbHookFunction,
10649                                     void                     **pProfilerHandle,
10650                                     bool                      *pbIndirectedHandles)
10651 {
10652     CONTRACTL {
10653         THROWS;
10654         GC_TRIGGERS;
10655         MODE_PREEMPTIVE;
10656     } CONTRACTL_END;
10657
10658     _ASSERTE(pbHookFunction != NULL);
10659     _ASSERTE(pProfilerHandle != NULL);
10660     _ASSERTE(pbIndirectedHandles != NULL);
10661
10662     if (!m_gphCache.m_bGphIsCacheValid)
10663     {
10664 #ifdef PROFILING_SUPPORTED
10665         JIT_TO_EE_TRANSITION();
10666
10667         // Cache not filled in, so make our first and only call to CEEInfo::GetProfilingHandle here
10668
10669         // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
10670         // they shouldnever come here as they are called out in GetCompileFlag
10671         _ASSERTE(!m_pMethodBeingCompiled->IsNoMetadata());
10672
10673         // We pass in the typical method definition to the function mapper because in
10674         // Whidbey all the profiling API transactions are done in terms of typical
10675         // method definitions not instantiations.
10676         BOOL bHookFunction = TRUE;
10677         void * profilerHandle = m_pMethodBeingCompiled;
10678
10679         {
10680             BEGIN_PROFILER_CALLBACK(CORProfilerFunctionIDMapperEnabled());
10681             profilerHandle = (void *)(&g_profControlBlock)->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction);
10682             END_PROFILER_CALLBACK();
10683         }
10684
10685         m_gphCache.m_pvGphProfilerHandle = profilerHandle;
10686         m_gphCache.m_bGphHookFunction = (bHookFunction != FALSE);
10687         m_gphCache.m_bGphIsCacheValid = true;
10688
10689         EE_TO_JIT_TRANSITION();
10690 #endif //PROFILING_SUPPORTED
10691     }
10692
10693     // Our cache of these values are bitfield bools, but the interface requires
10694     // bool.  So to avoid setting aside a staging area on the stack for these
10695     // values, we filled them in directly in the if (not cached yet) case.
10696     *pbHookFunction = (m_gphCache.m_bGphHookFunction != false);
10697
10698     // At this point, the remaining values must be in the cache by now, so use them
10699     *pProfilerHandle = m_gphCache.m_pvGphProfilerHandle;
10700
10701     //
10702     // This is the JIT case, which is never indirected.
10703     //
10704     *pbIndirectedHandles = false;
10705 }
10706
10707 /*********************************************************************/
10708 void CEEJitInfo::WriteCodeBytes()
10709 {
10710     LIMITED_METHOD_CONTRACT;
10711
10712 #ifdef USE_INDIRECT_CODEHEADER
10713     if (m_pRealCodeHeader != NULL)
10714     {
10715         // Restore the read only version of the real code header
10716         m_CodeHeaderRW->SetRealCodeHeader(m_pRealCodeHeader);
10717         m_pRealCodeHeader = NULL;
10718     }
10719 #endif // USE_INDIRECT_CODEHEADER
10720
10721     if (m_CodeHeaderRW != m_CodeHeader)
10722     {
10723         ExecutableWriterHolder<void> codeWriterHolder((void *)m_CodeHeader, m_codeWriteBufferSize);
10724         memcpy(codeWriterHolder.GetRW(), m_CodeHeaderRW, m_codeWriteBufferSize);
10725     }
10726 }
10727
10728 /*********************************************************************/
10729 void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr)
10730 {
10731     CONTRACTL {
10732         NOTHROW;
10733         GC_TRIGGERS;
10734     } CONTRACTL_END;
10735
10736     // The RemoveJitData call below requires the m_CodeHeader to be valid, so we need to write
10737     // the code bytes to the target memory location.
10738     WriteCodeBytes();
10739
10740     CodeHeader* pCodeHeader = m_CodeHeader;
10741     if (pCodeHeader)
10742         jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len);
10743 }
10744
10745 /*********************************************************************/
10746 void CEEJitInfo::WriteCode(EEJitManager * jitMgr)
10747 {
10748     CONTRACTL {
10749         THROWS;
10750         GC_TRIGGERS;
10751     } CONTRACTL_END;
10752
10753 #ifdef FEATURE_INTERPRETER
10754     // TODO: the InterpterCEEInfo doesn't support features about W^X.
10755     // see also #53173
10756     if (m_pCodeHeap == nullptr) return;
10757 #endif
10758
10759     WriteCodeBytes();
10760
10761     // Now that the code header was written to the final location, publish the code via the nibble map
10762     jitMgr->NibbleMapSet(m_pCodeHeap, m_CodeHeader->GetCodeStartAddress(), TRUE);
10763
10764 #if defined(TARGET_AMD64)
10765     // Publish the new unwind information in a way that the ETW stack crawler can find
10766     _ASSERTE(m_usedUnwindInfos == m_totalUnwindInfos);
10767     UnwindInfoTable::PublishUnwindInfoForMethod(m_moduleBase, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos);
10768 #endif // defined(TARGET_AMD64)
10769
10770 }
10771
10772
10773 /*********************************************************************/
10774 // Route jit information to the Jit Debug store.
10775 void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, uint32_t cMap,
10776                                ICorDebugInfo::OffsetMapping *pMap)
10777 {
10778     CONTRACTL {
10779         THROWS;
10780         GC_TRIGGERS;
10781         MODE_PREEMPTIVE;
10782     } CONTRACTL_END;
10783
10784     JIT_TO_EE_TRANSITION();
10785
10786     // We receive ownership of the array
10787     _ASSERTE(m_pOffsetMapping == NULL && m_iOffsetMapping == 0);
10788     m_iOffsetMapping = cMap;
10789     m_pOffsetMapping = pMap;
10790
10791     EE_TO_JIT_TRANSITION();
10792 }
10793
10794 void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, uint32_t cVars, ICorDebugInfo::NativeVarInfo *vars)
10795 {
10796     CONTRACTL {
10797         THROWS;
10798         GC_TRIGGERS;
10799         MODE_PREEMPTIVE;
10800     } CONTRACTL_END;
10801
10802     JIT_TO_EE_TRANSITION();
10803
10804     // We receive ownership of the array
10805     _ASSERTE(m_pNativeVarInfo == NULL && m_iNativeVarInfo == 0);
10806     m_iNativeVarInfo = cVars;
10807     m_pNativeVarInfo = vars;
10808
10809     EE_TO_JIT_TRANSITION();
10810 }
10811
10812 void CEEJitInfo::reportRichMappings(
10813         ICorDebugInfo::InlineTreeNode*    inlineTreeNodes,
10814         uint32_t                          numInlineTreeNodes,
10815         ICorDebugInfo::RichOffsetMapping* mappings,
10816         uint32_t                          numMappings)
10817 {
10818     CONTRACTL {
10819         NOTHROW;
10820         GC_NOTRIGGER;
10821         MODE_PREEMPTIVE;
10822     } CONTRACTL_END;
10823
10824     JIT_TO_EE_TRANSITION();
10825
10826     if (m_jitManager->IsStoringRichDebugInfo())
10827     {
10828         m_inlineTreeNodes = inlineTreeNodes;
10829         m_numInlineTreeNodes = numInlineTreeNodes;
10830         m_richOffsetMappings = mappings;
10831         m_numRichOffsetMappings = numMappings;
10832     }
10833     else
10834     {
10835         freeArrayInternal(inlineTreeNodes);
10836         freeArrayInternal(mappings);
10837     }
10838
10839     EE_TO_JIT_TRANSITION();
10840 }
10841
10842 void CEEJitInfo::setPatchpointInfo(PatchpointInfo* patchpointInfo)
10843 {
10844     CONTRACTL {
10845         THROWS;
10846         GC_TRIGGERS;
10847         MODE_PREEMPTIVE;
10848     } CONTRACTL_END;
10849
10850     JIT_TO_EE_TRANSITION();
10851
10852 #ifdef FEATURE_ON_STACK_REPLACEMENT
10853     // We receive ownership of the array
10854     _ASSERTE(m_pPatchpointInfoFromJit == NULL);
10855     m_pPatchpointInfoFromJit = patchpointInfo;
10856 #else
10857     UNREACHABLE();
10858 #endif
10859
10860     EE_TO_JIT_TRANSITION();
10861 }
10862
10863 PatchpointInfo* CEEJitInfo::getOSRInfo(unsigned* ilOffset)
10864 {
10865     CONTRACTL {
10866         THROWS;
10867         GC_TRIGGERS;
10868         MODE_PREEMPTIVE;
10869     } CONTRACTL_END;
10870
10871     PatchpointInfo* result = NULL;
10872     *ilOffset = 0;
10873
10874     JIT_TO_EE_TRANSITION();
10875
10876 #ifdef FEATURE_ON_STACK_REPLACEMENT
10877     result = m_pPatchpointInfoFromRuntime;
10878     *ilOffset = m_ilOffset;
10879 #endif
10880
10881     EE_TO_JIT_TRANSITION();
10882
10883     return result;
10884 }
10885
10886 void CEEJitInfo::CompressDebugInfo()
10887 {
10888     CONTRACTL {
10889         THROWS;
10890         GC_TRIGGERS;
10891         MODE_PREEMPTIVE;
10892     } CONTRACTL_END;
10893
10894 #ifdef FEATURE_ON_STACK_REPLACEMENT
10895     PatchpointInfo* patchpointInfo = m_pPatchpointInfoFromJit;
10896 #else
10897     PatchpointInfo* patchpointInfo = NULL;
10898 #endif
10899
10900     // Don't track JIT info for DynamicMethods.
10901     if (m_pMethodBeingCompiled->IsDynamicMethod() && !g_pConfig->GetTrackDynamicMethodDebugInfo())
10902     {
10903         _ASSERTE(patchpointInfo == NULL);
10904         return;
10905     }
10906
10907     if ((m_iOffsetMapping == 0) && (m_iNativeVarInfo == 0) && (patchpointInfo == NULL) && (m_numInlineTreeNodes == 0) && (m_numRichOffsetMappings == 0))
10908         return;
10909
10910     JIT_TO_EE_TRANSITION();
10911
10912     EX_TRY
10913     {
10914         BOOL writeFlagByte = FALSE;
10915 #ifdef FEATURE_ON_STACK_REPLACEMENT
10916         writeFlagByte = TRUE;
10917 #endif
10918         if (m_jitManager->IsStoringRichDebugInfo())
10919             writeFlagByte = TRUE;
10920
10921         PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars(
10922             m_pOffsetMapping, m_iOffsetMapping,
10923             m_pNativeVarInfo, m_iNativeVarInfo,
10924             patchpointInfo,
10925             m_inlineTreeNodes, m_numInlineTreeNodes,
10926             m_richOffsetMappings, m_numRichOffsetMappings,
10927             writeFlagByte,
10928             m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap());
10929
10930         m_CodeHeaderRW->SetDebugInfo(pDebugInfo);
10931     }
10932     EX_CATCH
10933     {
10934         // Just ignore exceptions here. The debugger's structures will still be in a consistent state.
10935     }
10936     EX_END_CATCH(SwallowAllExceptions)
10937
10938     EE_TO_JIT_TRANSITION();
10939 }
10940
10941 void reservePersonalityRoutineSpace(uint32_t &unwindSize)
10942 {
10943 #if defined(TARGET_X86)
10944     // Do nothing
10945 #elif defined(TARGET_AMD64)
10946     // Add space for personality routine, it must be 4-byte aligned.
10947     // Everything in the UNWIND_INFO up to the variable-sized UnwindCodes
10948     // array has already had its size included in unwindSize by the caller.
10949     unwindSize += sizeof(ULONG);
10950
10951     // Note that the count of unwind codes (2 bytes each) is stored as a UBYTE
10952     // So the largest size could be 510 bytes, plus the header and language
10953     // specific stuff.  This can't overflow.
10954
10955     _ASSERTE(FitsInU4(unwindSize + sizeof(ULONG)));
10956     unwindSize = (ULONG)(ALIGN_UP(unwindSize, sizeof(ULONG)));
10957 #elif defined(TARGET_ARM) || defined(TARGET_ARM64)
10958     // The JIT passes in a 4-byte aligned block of unwind data.
10959     _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
10960
10961     // Add space for personality routine, it must be 4-byte aligned.
10962     unwindSize += sizeof(ULONG);
10963 #elif defined(TARGET_LOONGARCH64)
10964     // The JIT passes in a 4-byte aligned block of unwind data.
10965     _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
10966
10967     // Add space for personality routine, it must be 4-byte aligned.
10968     unwindSize += sizeof(ULONG);
10969 #elif defined(TARGET_RISCV64)
10970     // The JIT passes in a 4-byte aligned block of unwind data.
10971     _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
10972
10973     // Add space for personality routine, it must be 4-byte aligned.
10974     unwindSize += sizeof(ULONG);
10975 #else
10976     PORTABILITY_ASSERT("reservePersonalityRoutineSpace");
10977 #endif // !defined(TARGET_AMD64)
10978
10979 }
10980 // Reserve memory for the method/funclet's unwind information.
10981 // Note that this must be called before allocMem. It should be
10982 // called once for the main method, once for every funclet, and
10983 // once for every block of cold code for which allocUnwindInfo
10984 // will be called.
10985 //
10986 // This is necessary because jitted code must allocate all the
10987 // memory needed for the unwindInfo at the allocMem call.
10988 // For prejitted code we split up the unwinding information into
10989 // separate sections .rdata and .pdata.
10990 //
10991 void CEEJitInfo::reserveUnwindInfo(bool isFunclet, bool isColdCode, uint32_t unwindSize)
10992 {
10993 #ifdef FEATURE_EH_FUNCLETS
10994     CONTRACTL {
10995         NOTHROW;
10996         GC_NOTRIGGER;
10997         MODE_PREEMPTIVE;
10998     }
10999     CONTRACTL_END;
11000
11001     JIT_TO_EE_TRANSITION_LEAF();
11002
11003     CONSISTENCY_CHECK_MSG(!isColdCode, "Hot/Cold splitting is not supported in jitted code");
11004     _ASSERTE_MSG(m_theUnwindBlock == NULL,
11005         "reserveUnwindInfo() can only be called before allocMem(), but allocMem() has already been called. "
11006         "This may indicate the JIT has hit a NO_WAY assert after calling allocMem(), and is re-JITting. "
11007         "Set DOTNET_JitBreakOnBadCode=1 and rerun to get the real error.");
11008
11009     uint32_t currentSize  = unwindSize;
11010
11011     reservePersonalityRoutineSpace(currentSize);
11012
11013     m_totalUnwindSize += currentSize;
11014
11015     m_totalUnwindInfos++;
11016
11017     EE_TO_JIT_TRANSITION_LEAF();
11018 #else // FEATURE_EH_FUNCLETS
11019     LIMITED_METHOD_CONTRACT;
11020     // Dummy implementation to make cross-platform altjit work
11021 #endif // FEATURE_EH_FUNCLETS
11022 }
11023
11024 // Allocate and initialize the .rdata and .pdata for this method or
11025 // funclet and get the block of memory needed for the machine specific
11026 // unwind information (the info for crawling the stack frame).
11027 // Note that allocMem must be called first.
11028 //
11029 // The pHotCode parameter points at the first byte of the code of the method
11030 // The startOffset and endOffset are the region (main or funclet) that
11031 // we are to allocate and create .rdata and .pdata for.
11032 // The pUnwindBlock is copied and contains the .pdata unwind area
11033 //
11034 // Parameters:
11035 //
11036 //    pHotCode        main method code buffer, always filled in
11037 //    pColdCode       always NULL for jitted code
11038 //    startOffset     start of code block, relative to pHotCode
11039 //    endOffset       end of code block, relative to pHotCode
11040 //    unwindSize      size of unwind info pointed to by pUnwindBlock
11041 //    pUnwindBlock    pointer to unwind info
11042 //    funcKind        type of funclet (main method code, handler, filter)
11043 //
11044 void CEEJitInfo::allocUnwindInfo (
11045         uint8_t *           pHotCode,              /* IN */
11046         uint8_t *           pColdCode,             /* IN */
11047         uint32_t            startOffset,           /* IN */
11048         uint32_t            endOffset,             /* IN */
11049         uint32_t            unwindSize,            /* IN */
11050         uint8_t *           pUnwindBlock,          /* IN */
11051         CorJitFuncKind      funcKind               /* IN */
11052         )
11053 {
11054 #ifdef FEATURE_EH_FUNCLETS
11055     CONTRACTL {
11056         THROWS;
11057         GC_TRIGGERS;
11058         MODE_PREEMPTIVE;
11059         PRECONDITION(m_theUnwindBlock != NULL);
11060         PRECONDITION(m_usedUnwindSize < m_totalUnwindSize);
11061         PRECONDITION(m_usedUnwindInfos < m_totalUnwindInfos);
11062         PRECONDITION(endOffset <= m_codeSize);
11063     } CONTRACTL_END;
11064
11065     CONSISTENCY_CHECK_MSG(pColdCode == NULL, "Hot/Cold code splitting not supported for jitted code");
11066
11067     JIT_TO_EE_TRANSITION();
11068
11069     //
11070     // We add one callback-type dynamic function table per range section.
11071     // Therefore, the RUNTIME_FUNCTION info is always relative to the
11072     // image base contained in the dynamic function table, which happens
11073     // to be the LowAddress of the range section.  The JIT has no
11074     // knowledge of the range section, so it gives us offsets that are
11075     // relative to the beginning of the method (pHotCode) and we allocate
11076     // and initialize the RUNTIME_FUNCTION data and record its location
11077     // in this function.
11078     //
11079
11080     if (funcKind != CORJIT_FUNC_ROOT)
11081     {
11082         // The main method should be emitted before funclets
11083         _ASSERTE(m_usedUnwindInfos > 0);
11084     }
11085
11086     PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeaderRW->GetUnwindInfo(m_usedUnwindInfos);
11087
11088     m_usedUnwindInfos++;
11089
11090     // Make sure that the RUNTIME_FUNCTION is aligned on a DWORD sized boundary
11091     _ASSERTE(IS_ALIGNED(pRuntimeFunction, sizeof(DWORD)));
11092
11093
11094     size_t writeableOffset = (BYTE *)m_CodeHeaderRW - (BYTE *)m_CodeHeader;
11095     UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *) &(m_theUnwindBlock[m_usedUnwindSize]);
11096     UNWIND_INFO * pUnwindInfoRW = (UNWIND_INFO *)((BYTE*)pUnwindInfo + writeableOffset);
11097
11098     m_usedUnwindSize += unwindSize;
11099
11100     reservePersonalityRoutineSpace(m_usedUnwindSize);
11101
11102     _ASSERTE(m_usedUnwindSize <= m_totalUnwindSize);
11103
11104     // Make sure that the UnwindInfo is aligned
11105     _ASSERTE(IS_ALIGNED(pUnwindInfo, sizeof(ULONG)));
11106
11107     /* Calculate Image Relative offset to add to the jit generated unwind offsets */
11108
11109     TADDR baseAddress = m_moduleBase;
11110
11111     size_t currentCodeSizeT = (size_t)pHotCode - baseAddress;
11112
11113     /* Check if currentCodeSizeT offset fits in 32-bits */
11114     if (!FitsInU4(currentCodeSizeT))
11115     {
11116         _ASSERTE(!"Bad currentCodeSizeT");
11117         COMPlusThrowHR(E_FAIL);
11118     }
11119
11120     /* Check if EndAddress offset fits in 32-bit */
11121     if (!FitsInU4(currentCodeSizeT + endOffset))
11122     {
11123         _ASSERTE(!"Bad currentCodeSizeT");
11124         COMPlusThrowHR(E_FAIL);
11125     }
11126
11127     unsigned currentCodeOffset = (unsigned) currentCodeSizeT;
11128
11129     /* Calculate Unwind Info delta */
11130     size_t unwindInfoDeltaT = (size_t) pUnwindInfo - baseAddress;
11131
11132     /* Check if unwindDeltaT offset fits in 32-bits */
11133     if (!FitsInU4(unwindInfoDeltaT))
11134     {
11135         _ASSERTE(!"Bad unwindInfoDeltaT");
11136         COMPlusThrowHR(E_FAIL);
11137     }
11138
11139     unsigned unwindInfoDelta = (unsigned) unwindInfoDeltaT;
11140
11141     RUNTIME_FUNCTION__SetBeginAddress(pRuntimeFunction, currentCodeOffset + startOffset);
11142
11143 #ifdef TARGET_AMD64
11144     pRuntimeFunction->EndAddress        = currentCodeOffset + endOffset;
11145 #endif
11146
11147     RUNTIME_FUNCTION__SetUnwindInfoAddress(pRuntimeFunction, unwindInfoDelta);
11148
11149 #ifdef _DEBUG
11150     if (funcKind != CORJIT_FUNC_ROOT)
11151     {
11152         // Check the new funclet doesn't overlap any existing funclet.
11153
11154         for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++)
11155         {
11156             PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeaderRW->GetUnwindInfo(iUnwindInfo);
11157             _ASSERTE((   RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress + writeableOffset)
11158                      || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress + writeableOffset) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction)));
11159         }
11160     }
11161 #endif // _DEBUG
11162
11163     memcpy(pUnwindInfoRW, pUnwindBlock, unwindSize);
11164
11165 #if defined(TARGET_X86)
11166
11167     // Do NOTHING
11168
11169 #elif defined(TARGET_AMD64)
11170
11171     pUnwindInfoRW->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
11172
11173     ULONG * pPersonalityRoutineRW = (ULONG*)ALIGN_UP(&(pUnwindInfoRW->UnwindCode[pUnwindInfoRW->CountOfUnwindCodes]), sizeof(ULONG));
11174     *pPersonalityRoutineRW = ExecutionManager::GetCLRPersonalityRoutineValue();
11175
11176 #elif defined(TARGET_ARM64)
11177
11178     *(LONG *)pUnwindInfoRW |= (1 << 20); // X bit
11179
11180     ULONG * pPersonalityRoutineRW = (ULONG*)((BYTE *)pUnwindInfoRW + ALIGN_UP(unwindSize, sizeof(ULONG)));
11181     *pPersonalityRoutineRW = ExecutionManager::GetCLRPersonalityRoutineValue();
11182
11183 #elif defined(TARGET_ARM)
11184
11185     *(LONG *)pUnwindInfoRW |= (1 << 20); // X bit
11186
11187     ULONG * pPersonalityRoutineRW = (ULONG*)((BYTE *)pUnwindInfoRW + ALIGN_UP(unwindSize, sizeof(ULONG)));
11188     *pPersonalityRoutineRW = (TADDR)ProcessCLRException - baseAddress;
11189
11190 #elif defined(TARGET_LOONGARCH64)
11191
11192     *(LONG *)pUnwindInfoRW |= (1 << 20); // X bit
11193
11194     ULONG * pPersonalityRoutineRW = (ULONG*)((BYTE *)pUnwindInfoRW + ALIGN_UP(unwindSize, sizeof(ULONG)));
11195     *pPersonalityRoutineRW = ExecutionManager::GetCLRPersonalityRoutineValue();
11196
11197 #elif defined(TARGET_RISCV64)
11198     *(LONG *)pUnwindInfoRW |= (1 << 20); // X bit
11199
11200     ULONG * pPersonalityRoutineRW = (ULONG*)((BYTE *)pUnwindInfoRW + ALIGN_UP(unwindSize, sizeof(ULONG)));
11201     *pPersonalityRoutineRW = ExecutionManager::GetCLRPersonalityRoutineValue();
11202
11203 #endif
11204
11205     EE_TO_JIT_TRANSITION();
11206 #else // FEATURE_EH_FUNCLETS
11207     LIMITED_METHOD_CONTRACT;
11208     // Dummy implementation to make cross-platform altjit work
11209 #endif // FEATURE_EH_FUNCLETS
11210 }
11211
11212 void CEEJitInfo::recordCallSite(uint32_t              instrOffset,
11213                                 CORINFO_SIG_INFO *    callSig,
11214                                 CORINFO_METHOD_HANDLE methodHandle)
11215 {
11216     // Currently, only testing tools use this method. The EE itself doesn't need record this information.
11217     // N.B. The memory that callSig points to is managed by the JIT and isn't guaranteed to be around after
11218     // this function returns, so future implementations should copy the sig info if they want it to persist.
11219     LIMITED_METHOD_CONTRACT;
11220 }
11221
11222 // This is a variant for AMD64 or other machines that
11223 // cannot always hold the destination address in a 32-bit location
11224 // A relocation is recorded if we are pre-jitting.
11225 // A jump thunk may be inserted if we are jitting
11226
11227 void CEEJitInfo::recordRelocation(void * location,
11228                                   void * locationRW,
11229                                   void * target,
11230                                   WORD   fRelocType,
11231                                   INT32  addlDelta)
11232 {
11233     CONTRACTL {
11234         THROWS;
11235         GC_TRIGGERS;
11236         MODE_PREEMPTIVE;
11237     } CONTRACTL_END;
11238
11239 #ifdef HOST_64BIT
11240     JIT_TO_EE_TRANSITION();
11241
11242     INT64 delta;
11243
11244     switch (fRelocType)
11245     {
11246     case IMAGE_REL_BASED_DIR64:
11247         // Write 64-bits into location
11248         *((UINT64 *) locationRW) = (UINT64) target;
11249         break;
11250
11251 #ifdef TARGET_AMD64
11252     case IMAGE_REL_BASED_REL32:
11253         {
11254             target = (BYTE *)target + addlDelta;
11255
11256             INT32 * fixupLocation = (INT32 *) location;
11257             INT32 * fixupLocationRW = (INT32 *) locationRW;
11258             BYTE * baseAddr = (BYTE *)fixupLocation + sizeof(INT32);
11259
11260             delta  = (INT64)((BYTE *)target - baseAddr);
11261
11262             //
11263             // Do we need to insert a jump stub to make the source reach the target?
11264             //
11265             // Note that we cannot stress insertion of jump stub by inserting it unconditionally. JIT records the relocations
11266             // for intra-module jumps and calls. It does not expect the register used by the jump stub to be trashed.
11267             //
11268             if (!FitsInI4(delta))
11269             {
11270                 if (m_fAllowRel32)
11271                 {
11272                     //
11273                     // When m_fAllowRel32 == TRUE, the JIT will use REL32s for both data addresses and direct code targets.
11274                     // Since we cannot tell what the relocation is for, we have to defensively retry.
11275                     //
11276                     m_fJumpStubOverflow = TRUE;
11277                     delta = 0;
11278                 }
11279                 else
11280                 {
11281                     //
11282                     // When m_fAllowRel32 == FALSE, the JIT will use a REL32s for direct code targets only.
11283                     // Use jump stub.
11284                     //
11285                     delta = rel32UsingJumpStub(fixupLocation, (PCODE)target, m_pMethodBeingCompiled, NULL, false /* throwOnOutOfMemoryWithinRange */);
11286                     if (delta == 0)
11287                     {
11288                         // This forces the JIT to retry the method, which allows us to reserve more space for jump stubs and have a higher chance that
11289                         // we will find space for them.
11290                         m_fJumpStubOverflow = TRUE;
11291                     }
11292
11293                     // Keep track of conservative estimate of how much memory may be needed by jump stubs. We will use it to reserve extra memory
11294                     // on retry to increase chances that the retry succeeds.
11295                     m_reserveForJumpStubs = max(0x400, m_reserveForJumpStubs + 0x10);
11296                 }
11297             }
11298
11299             LOG((LF_JIT, LL_INFO100000, "Encoded a PCREL32 at" FMT_ADDR "to" FMT_ADDR "+%d,  delta is 0x%04x\n",
11300                  DBG_ADDR(fixupLocation), DBG_ADDR(target), addlDelta, delta));
11301
11302             // Write the 32-bits pc-relative delta into location
11303             *fixupLocationRW = (INT32) delta;
11304         }
11305         break;
11306 #endif // TARGET_AMD64
11307
11308 #ifdef TARGET_ARM64
11309     case IMAGE_REL_ARM64_BRANCH26:   // 26 bit offset << 2 & sign ext, for B and BL
11310         {
11311             _ASSERTE(addlDelta == 0);
11312
11313             PCODE branchTarget  = (PCODE) target;
11314             _ASSERTE((branchTarget & 0x3) == 0);   // the low two bits must be zero
11315
11316             PCODE fixupLocation = (PCODE) location;
11317             PCODE fixupLocationRW = (PCODE) locationRW;
11318             _ASSERTE((fixupLocation & 0x3) == 0);  // the low two bits must be zero
11319
11320             delta = (INT64)(branchTarget - fixupLocation);
11321             _ASSERTE((delta & 0x3) == 0);          // the low two bits must be zero
11322
11323             UINT32 branchInstr = *((UINT32*) fixupLocationRW);
11324             branchInstr &= 0xFC000000;  // keep bits 31-26
11325             _ASSERTE((branchInstr & 0x7FFFFFFF) == 0x14000000);  // Must be B or BL
11326
11327             //
11328             // Do we need to insert a jump stub to make the source reach the target?
11329             //
11330             //
11331             if (!FitsInRel28(delta))
11332             {
11333                 // Use jump stub.
11334                 //
11335                 TADDR baseAddr = (TADDR)fixupLocation;
11336                 TADDR loAddr   = baseAddr - 0x08000000;   // -2^27
11337                 TADDR hiAddr   = baseAddr + 0x07FFFFFF;   // +2^27-1
11338
11339                 // Check for the wrap around cases
11340                 if (loAddr > baseAddr)
11341                     loAddr = UINT64_MIN; // overflow
11342                 if (hiAddr < baseAddr)
11343                     hiAddr = UINT64_MAX; // overflow
11344
11345                 PCODE jumpStubAddr = ExecutionManager::jumpStub(m_pMethodBeingCompiled,
11346                                                                 (PCODE)  target,
11347                                                                 (BYTE *) loAddr,
11348                                                                 (BYTE *) hiAddr,
11349                                                                 NULL,
11350                                                                 false);
11351
11352                 // Keep track of conservative estimate of how much memory may be needed by jump stubs. We will use it to reserve extra memory
11353                 // on retry to increase chances that the retry succeeds.
11354                 m_reserveForJumpStubs = max(0x400, m_reserveForJumpStubs + 2*BACK_TO_BACK_JUMP_ALLOCATE_SIZE);
11355
11356                 if (jumpStubAddr == 0)
11357                 {
11358                     // This forces the JIT to retry the method, which allows us to reserve more space for jump stubs and have a higher chance that
11359                     // we will find space for them.
11360                     m_fJumpStubOverflow = TRUE;
11361                     break;
11362                 }
11363
11364                 delta = (INT64)(jumpStubAddr - fixupLocation);
11365
11366                 if (!FitsInRel28(delta))
11367                 {
11368                     _ASSERTE(!"jump stub was not in expected range");
11369                     EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
11370                 }
11371
11372                 LOG((LF_JIT, LL_INFO100000, "Using JumpStub at" FMT_ADDR "that jumps to" FMT_ADDR "\n",
11373                      DBG_ADDR(jumpStubAddr), DBG_ADDR(target)));
11374             }
11375
11376             LOG((LF_JIT, LL_INFO100000, "Encoded a BRANCH26 at" FMT_ADDR "to" FMT_ADDR ",  delta is 0x%04x\n",
11377                  DBG_ADDR(fixupLocation), DBG_ADDR(target), delta));
11378
11379             _ASSERTE(FitsInRel28(delta));
11380
11381             PutArm64Rel28((UINT32*) fixupLocationRW, (INT32)delta);
11382         }
11383         break;
11384
11385     case IMAGE_REL_ARM64_PAGEBASE_REL21:
11386         {
11387             _ASSERTE(addlDelta == 0);
11388
11389             // Write the 21 bits pc-relative page address into location.
11390             INT64 targetPage = (INT64)target & 0xFFFFFFFFFFFFF000LL;
11391             INT64 locationPage = (INT64)location & 0xFFFFFFFFFFFFF000LL;
11392             INT64 relPage = (INT64)(targetPage - locationPage);
11393             INT32 imm21 = (INT32)(relPage >> 12) & 0x1FFFFF;
11394             PutArm64Rel21((UINT32 *)locationRW, imm21);
11395         }
11396         break;
11397
11398     case IMAGE_REL_ARM64_PAGEOFFSET_12A:
11399         {
11400             _ASSERTE(addlDelta == 0);
11401
11402             // Write the 12 bits page offset into location.
11403             INT32 imm12 = (INT32)(SIZE_T)target & 0xFFFLL;
11404             PutArm64Rel12((UINT32 *)locationRW, imm12);
11405         }
11406         break;
11407
11408 #endif // TARGET_ARM64
11409
11410     default:
11411         _ASSERTE(!"Unknown reloc type");
11412         break;
11413     }
11414
11415     EE_TO_JIT_TRANSITION();
11416 #else // HOST_64BIT
11417     JIT_TO_EE_TRANSITION_LEAF();
11418
11419     // Nothing to do on 32-bit
11420
11421     EE_TO_JIT_TRANSITION_LEAF();
11422 #endif // HOST_64BIT
11423 }
11424
11425 // Get a hint for whether the relocation kind to use for the target address.
11426 // Note that this is currently a best-guess effort as we do not know exactly
11427 // where the jitted code will end up at. Instead we try to keep executable code
11428 // and static fields in a preferred memory region and base the decision on this
11429 // region.
11430 //
11431 // If we guess wrong we will recover in recordRelocation if we notice that we
11432 // cannot actually use the kind of reloc: in that case we will rejit the
11433 // function and turn off the use of those relocs in the future. This scheme
11434 // works based on two assumptions:
11435 //
11436 // 1) The JIT will ask about relocs only for memory that was allocated by the
11437 //    loader heap in the preferred region.
11438 // 2) The loader heap allocates memory in the preferred region in a circular fashion;
11439 //    the region itself might be larger than 2 GB, but the current compilation should
11440 //    only be hitting the preferred region within 2 GB.
11441 //
11442 // Under these assumptions we should only hit the "recovery" case once the
11443 // preferred range is actually full.
11444 WORD CEEJitInfo::getRelocTypeHint(void * target)
11445 {
11446     CONTRACTL {
11447         THROWS;
11448         GC_TRIGGERS;
11449         MODE_PREEMPTIVE;
11450     } CONTRACTL_END;
11451
11452 #ifdef TARGET_AMD64
11453     if (m_fAllowRel32)
11454     {
11455         if (ExecutableAllocator::IsPreferredExecutableRange(target))
11456             return IMAGE_REL_BASED_REL32;
11457     }
11458 #endif // TARGET_AMD64
11459
11460     // No hints
11461     return (WORD)-1;
11462 }
11463
11464 uint32_t CEEJitInfo::getExpectedTargetArchitecture()
11465 {
11466     LIMITED_METHOD_CONTRACT;
11467
11468     return IMAGE_FILE_MACHINE_NATIVE;
11469 }
11470
11471 void CEEInfo::JitProcessShutdownWork()
11472 {
11473     LIMITED_METHOD_CONTRACT;
11474
11475     EEJitManager* jitMgr = ExecutionManager::GetEEJitManager();
11476
11477     // If we didn't load the JIT, there is no work to do.
11478     if (jitMgr->m_jit != NULL)
11479     {
11480         // Do the shutdown work.
11481         jitMgr->m_jit->ProcessShutdownWork(this);
11482     }
11483
11484 #ifdef ALLOW_SXS_JIT
11485     if (jitMgr->m_alternateJit != NULL)
11486     {
11487         jitMgr->m_alternateJit->ProcessShutdownWork(this);
11488     }
11489 #endif // ALLOW_SXS_JIT
11490 }
11491
11492 /*********************************************************************/
11493 InfoAccessType CEEJitInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
11494                                                   mdToken metaTok,
11495                                                   void **ppValue)
11496 {
11497     CONTRACTL {
11498         THROWS;
11499         GC_TRIGGERS;
11500         MODE_PREEMPTIVE;
11501     } CONTRACTL_END;
11502
11503     InfoAccessType result = IAT_PVALUE;
11504
11505     JIT_TO_EE_TRANSITION();
11506
11507     _ASSERTE(ppValue != NULL);
11508
11509     if (IsDynamicScope(scopeHnd))
11510     {
11511         *ppValue = (LPVOID)GetDynamicResolver(scopeHnd)->ConstructStringLiteral(metaTok);
11512     }
11513     else
11514     {
11515         // If ConstructStringLiteral returns a pinned reference we can return it by value (IAT_VALUE)
11516         void* ppPinnedString = nullptr;
11517         void** ptr = (void**)ConstructStringLiteral(scopeHnd, metaTok, &ppPinnedString);
11518
11519         if (ppPinnedString != nullptr)
11520         {
11521             *ppValue = ppPinnedString;
11522             result = IAT_VALUE;
11523         }
11524         else
11525         {
11526             *ppValue = (void*)ptr;
11527         }
11528     }
11529
11530     EE_TO_JIT_TRANSITION();
11531
11532     return result;
11533 }
11534
11535 /*********************************************************************/
11536 InfoAccessType CEEJitInfo::emptyStringLiteral(void ** ppValue)
11537 {
11538     CONTRACTL {
11539         THROWS;
11540         GC_TRIGGERS;
11541         MODE_PREEMPTIVE;
11542     } CONTRACTL_END;
11543
11544     InfoAccessType result = IAT_PVALUE;
11545
11546     JIT_TO_EE_TRANSITION();
11547     void* pinnedStr = nullptr;
11548     void* pinnedStrHandlePtr = StringObject::GetEmptyStringRefPtr(&pinnedStr);
11549
11550     if (pinnedStr != nullptr)
11551     {
11552         *ppValue = pinnedStr;
11553         result = IAT_VALUE;
11554     }
11555     else
11556     {
11557         *ppValue = pinnedStrHandlePtr;
11558     }
11559
11560     EE_TO_JIT_TRANSITION();
11561
11562     return result;
11563 }
11564
11565 bool CEEInfo::getStaticObjRefContent(OBJECTREF obj, uint8_t* buffer, bool ignoreMovableObjects)
11566 {
11567     CONTRACTL {
11568         THROWS;
11569         GC_TRIGGERS;
11570         MODE_COOPERATIVE;
11571     } CONTRACTL_END;
11572
11573
11574     if (obj == NULL)
11575     {
11576         // GC handle is null
11577         memset(buffer, 0, sizeof(CORINFO_OBJECT_HANDLE));
11578         return true;
11579     }
11580     else if (!ignoreMovableObjects || GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(OBJECTREFToObject(obj)))
11581     {
11582         CORINFO_OBJECT_HANDLE handle = getJitHandleForObject(obj);
11583         memcpy(buffer, &handle, sizeof(CORINFO_OBJECT_HANDLE));
11584         return true;
11585     }
11586     return false;
11587 }
11588
11589 bool CEEInfo::getStaticFieldContent(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects)
11590 {
11591     CONTRACTL {
11592         THROWS;
11593         GC_TRIGGERS;
11594         MODE_PREEMPTIVE;
11595     } CONTRACTL_END;
11596
11597     _ASSERT(fieldHnd != NULL);
11598     _ASSERT(buffer != NULL);
11599     _ASSERT(bufferSize > 0);
11600     _ASSERT(valueOffset >= 0);
11601
11602     bool result = false;
11603
11604     JIT_TO_EE_TRANSITION();
11605
11606     FieldDesc* field = (FieldDesc*)fieldHnd;
11607     _ASSERTE(field->IsStatic());
11608
11609     MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
11610     _ASSERTE(!pEnclosingMT->IsSharedByGenericInstantiations());
11611     _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
11612
11613     // Allocate space for the local class if necessary, but don't trigger
11614     // class construction.
11615     DomainLocalModule* pLocalModule = pEnclosingMT->GetDomainLocalModule();
11616     pLocalModule->PopulateClass(pEnclosingMT);
11617
11618     if (!field->IsThreadStatic() && pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
11619     {
11620         if (field->IsObjRef())
11621         {
11622             GCX_COOP();
11623
11624             _ASSERT(!field->IsRVA());
11625             _ASSERT(valueOffset == 0); // there is no point in returning a chunk of a gc handle
11626             _ASSERT((UINT)bufferSize == field->GetSize());
11627
11628             result = getStaticObjRefContent(field->GetStaticOBJECTREF(), buffer, ignoreMovableObjects);
11629         }
11630         else
11631         {
11632             UINT size = field->GetSize();
11633             _ASSERTE(size > 0);
11634
11635             if (size >= (UINT)bufferSize && valueOffset >= 0 && (UINT)valueOffset <= size - (UINT)bufferSize)
11636             {
11637                 bool useMemcpy = false;
11638
11639                 // For structs containing GC pointers we want to make sure those GC pointers belong to FOH
11640                 // so we expect valueOffset to be a real field offset (same for bufferSize)
11641                 if (!field->IsRVA() && field->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
11642                 {
11643                     TypeHandle structType = field->GetFieldTypeHandleThrowing();
11644                     PTR_MethodTable structTypeMT = structType.AsMethodTable();
11645                     if (!structTypeMT->ContainsPointers())
11646                     {
11647                         // Fast-path: no GC pointers in the struct, we can use memcpy
11648                         useMemcpy = true;
11649                     }
11650                     else
11651                     {
11652                         // The struct contains GC pointer(s), but we still can use memcpy if we don't intersect with them.
11653                         unsigned numSlots = (structType.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE;
11654                         CQuickBytes gcPtrs;
11655                         BYTE* ptr = static_cast<BYTE*>(gcPtrs.AllocThrows(numSlots));
11656                         CEEInfo::getClassGClayoutStatic(structType, ptr);
11657
11658                         _ASSERT(numSlots > 0);
11659
11660                         useMemcpy = true;
11661                         for (unsigned i = 0; i < numSlots; i++)
11662                         {
11663                             if (ptr[i] == TYPE_GC_NONE)
11664                             {
11665                                 // Not a GC slot
11666                                 continue;
11667                             }
11668
11669                             const unsigned gcSlotBegin = i * TARGET_POINTER_SIZE;
11670                             const unsigned gcSlotEnd = gcSlotBegin + TARGET_POINTER_SIZE;
11671
11672                             if (gcSlotBegin >= (unsigned)valueOffset && gcSlotEnd <= (unsigned)(valueOffset + bufferSize))
11673                             {
11674                                 // GC slot intersects with our valueOffset + bufferSize - we can't use memcpy...
11675                                 useMemcpy = false;
11676
11677                                 // ...unless we're interested in that GC slot's value itself
11678                                 if (gcSlotBegin == (unsigned)valueOffset && gcSlotEnd == (unsigned)(valueOffset + bufferSize) && ptr[i] == TYPE_GC_REF)
11679                                 {
11680                                     GCX_COOP();
11681
11682                                     size_t baseAddr = (size_t)field->GetCurrentStaticAddress();
11683
11684                                     _ASSERT((UINT)bufferSize == sizeof(CORINFO_OBJECT_HANDLE));
11685                                     result = getStaticObjRefContent(ObjectToOBJECTREF(*(Object**)((uint8_t*)baseAddr + gcSlotBegin)), buffer, ignoreMovableObjects);
11686                                 }
11687
11688                                 // We had an intersection with a gc slot - no point in looking futher.
11689                                 break;
11690                             }
11691                         }
11692                     }
11693                 }
11694                 else
11695                 {
11696                     // RVA data, no gc pointers
11697                     useMemcpy = true;
11698                 }
11699
11700                 if (useMemcpy)
11701                 {
11702                     _ASSERT(!result);
11703                     result = true;
11704                     GCX_COOP();
11705                     size_t baseAddr = (size_t)field->GetCurrentStaticAddress();
11706                     _ASSERT(baseAddr != 0);
11707                     memcpy(buffer, (uint8_t*)baseAddr + valueOffset, bufferSize);
11708                 }
11709             }
11710         }
11711     }
11712
11713     EE_TO_JIT_TRANSITION();
11714
11715     return result;
11716 }
11717
11718 bool CEEInfo::getObjectContent(CORINFO_OBJECT_HANDLE handle, uint8_t* buffer, int bufferSize, int valueOffset)
11719 {
11720     CONTRACTL {
11721         THROWS;
11722         GC_TRIGGERS;
11723         MODE_PREEMPTIVE;
11724     } CONTRACTL_END;
11725
11726     _ASSERT(handle != NULL);
11727     _ASSERT(buffer != NULL);
11728     _ASSERT(bufferSize > 0);
11729     _ASSERT(valueOffset >= 0);
11730
11731     bool result = false;
11732
11733     JIT_TO_EE_TRANSITION();
11734
11735     GCX_COOP();
11736     OBJECTREF objRef = getObjectFromJitHandle(handle);
11737     _ASSERTE(objRef != NULL);
11738
11739     // TODO: support types containing GC pointers
11740     if (bufferSize + valueOffset <= (int)objRef->GetSize())
11741     {
11742         Object* obj = OBJECTREFToObject(objRef);
11743         PTR_MethodTable type = obj->GetMethodTable();
11744         if (type->ContainsPointers())
11745         {
11746             // RuntimeType has a gc field (object m_keepAlive), but if the object is in a frozen segment
11747             // it means that field is always nullptr so we can read any part of the object:
11748             if (type == g_pRuntimeTypeClass && GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
11749             {
11750                 memcpy(buffer, (uint8_t*)obj + valueOffset, bufferSize);
11751                 result = true;
11752             }
11753         }
11754         else
11755         {
11756             memcpy(buffer, (uint8_t*)obj + valueOffset, bufferSize);
11757             result = true;
11758         }
11759     }
11760
11761     EE_TO_JIT_TRANSITION();
11762
11763     return result;
11764 }
11765
11766 /*********************************************************************/
11767 CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
11768                                                             bool* pIsSpeculative)
11769 {
11770     CONTRACTL {
11771         THROWS;
11772         GC_TRIGGERS;
11773         MODE_PREEMPTIVE;
11774     } CONTRACTL_END;
11775
11776     CORINFO_CLASS_HANDLE result = NULL;
11777
11778     if (pIsSpeculative != NULL)
11779     {
11780         *pIsSpeculative = true;
11781     }
11782
11783     JIT_TO_EE_TRANSITION();
11784
11785     FieldDesc* field = (FieldDesc*) fieldHnd;
11786     bool isClassInitialized = false;
11787
11788     // We're only interested in ref class typed static fields
11789     // where the field handle specifies a unique location.
11790     if (field->IsStatic() && field->IsObjRef() && !field->IsThreadStatic())
11791     {
11792         MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
11793
11794         if (!pEnclosingMT->IsSharedByGenericInstantiations())
11795         {
11796             // Allocate space for the local class if necessary, but don't trigger
11797             // class construction.
11798             DomainLocalModule *pLocalModule = pEnclosingMT->GetDomainLocalModule();
11799             pLocalModule->PopulateClass(pEnclosingMT);
11800
11801             GCX_COOP();
11802
11803             OBJECTREF fieldObj = field->GetStaticOBJECTREF();
11804             VALIDATEOBJECTREF(fieldObj);
11805
11806             // Check for initialization before looking at the value
11807             isClassInitialized = !!pEnclosingMT->IsClassInited();
11808
11809             if (fieldObj != NULL)
11810             {
11811                 MethodTable *pObjMT = fieldObj->GetMethodTable();
11812
11813                 // TODO: Check if the jit is allowed to embed this handle in jitted code.
11814                 // Note for the initonly cases it probably won't embed.
11815                 result = (CORINFO_CLASS_HANDLE) pObjMT;
11816             }
11817         }
11818     }
11819
11820     // Did we find a class?
11821     if (result != NULL)
11822     {
11823         // Figure out what to report back.
11824         bool isResultImmutable = isClassInitialized && IsFdInitOnly(field->GetAttributes());
11825
11826         if (pIsSpeculative != NULL)
11827         {
11828             // Caller is ok with potentially mutable results.
11829             *pIsSpeculative = !isResultImmutable;
11830         }
11831         else
11832         {
11833             // Caller only wants to see immutable results.
11834             if (!isResultImmutable)
11835             {
11836                 result = NULL;
11837             }
11838         }
11839     }
11840
11841     EE_TO_JIT_TRANSITION();
11842
11843     return result;
11844 }
11845
11846 /*********************************************************************/
11847 static void *GetClassSync(MethodTable *pMT)
11848 {
11849     STANDARD_VM_CONTRACT;
11850
11851     GCX_COOP();
11852
11853     OBJECTREF ref = pMT->GetManagedClassObject();
11854     return (void*)ref->GetSyncBlock()->GetMonitor();
11855 }
11856
11857 /*********************************************************************/
11858 void* CEEJitInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
11859                                 void **ppIndirection)
11860 {
11861     CONTRACTL {
11862         THROWS;
11863         GC_TRIGGERS;
11864         MODE_PREEMPTIVE;
11865     } CONTRACTL_END;
11866
11867     void * result = NULL;
11868
11869     if (ppIndirection != NULL)
11870         *ppIndirection = NULL;
11871
11872     JIT_TO_EE_TRANSITION();
11873
11874     result = GetClassSync((GetMethod(ftnHnd))->GetMethodTable());
11875
11876     EE_TO_JIT_TRANSITION();
11877
11878     return result;
11879 }
11880
11881 /*********************************************************************/
11882 HRESULT CEEJitInfo::allocPgoInstrumentationBySchema(
11883             CORINFO_METHOD_HANDLE ftnHnd, /* IN */
11884             PgoInstrumentationSchema* pSchema, /* IN/OUT */
11885             uint32_t countSchemaItems, /* IN */
11886             uint8_t** pInstrumentationData /* OUT */
11887             )
11888 {
11889     CONTRACTL {
11890         THROWS;
11891         GC_TRIGGERS;
11892         MODE_PREEMPTIVE;
11893     } CONTRACTL_END;
11894
11895     HRESULT hr = E_FAIL;
11896
11897     JIT_TO_EE_TRANSITION();
11898
11899     // We need to know the code size. Typically we can get the code size
11900     // from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so
11901     // for that case we need to use DynamicResolver to get the code size.
11902
11903     unsigned codeSize = 0;
11904     if (m_pMethodBeingCompiled->IsDynamicMethod())
11905     {
11906         unsigned stackSize, ehSize;
11907         CorInfoOptions options;
11908         DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver();
11909         pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize);
11910     }
11911     else
11912     {
11913         codeSize = m_ILHeader->GetCodeSize();
11914     }
11915
11916 #ifdef FEATURE_PGO
11917     hr = PgoManager::allocPgoInstrumentationBySchema(m_pMethodBeingCompiled, pSchema, countSchemaItems, pInstrumentationData);
11918 #else
11919     _ASSERTE(!"allocMethodBlockCounts not implemented on CEEJitInfo!");
11920     hr = E_NOTIMPL;
11921 #endif // !FEATURE_PGO
11922
11923     EE_TO_JIT_TRANSITION();
11924
11925     return hr;
11926 }
11927
11928 // Consider implementing getBBProfileData on CEEJitInfo.  This will allow us
11929 // to use profile info in codegen for non zapped images.
11930 HRESULT CEEJitInfo::getPgoInstrumentationResults(
11931             CORINFO_METHOD_HANDLE      ftnHnd,
11932             PgoInstrumentationSchema **pSchema,                    // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes)
11933             uint32_t *                 pCountSchemaItems,          // pointer to the count schema items
11934             uint8_t **                 pInstrumentationData,       // pointer to the actual instrumentation data (pointer will not remain valid after jit completes)
11935             PgoSource *                pPgoSource                  // source of pgo data
11936             )
11937 {
11938     CONTRACTL {
11939         THROWS;
11940         GC_TRIGGERS;
11941         MODE_PREEMPTIVE;
11942     } CONTRACTL_END;
11943
11944     HRESULT hr = E_FAIL;
11945     *pCountSchemaItems = 0;
11946     *pInstrumentationData = NULL;
11947     *pPgoSource = PgoSource::Unknown;
11948
11949     JIT_TO_EE_TRANSITION();
11950
11951 #ifdef FEATURE_PGO
11952
11953     MethodDesc* pMD = (MethodDesc*)ftnHnd;
11954     ComputedPgoData* pDataCur = m_foundPgoData;
11955
11956     // Search linked list of previously found pgo information
11957     for (; pDataCur != nullptr; pDataCur = pDataCur->m_next)
11958     {
11959         if (pDataCur->m_pMD == pMD)
11960         {
11961             break;
11962         }
11963     }
11964
11965     if (pDataCur == nullptr)
11966     {
11967         // If not found in previous list, gather it here, and add to linked list
11968         NewHolder<ComputedPgoData> newPgoData = new ComputedPgoData(pMD);
11969         newPgoData->m_next = m_foundPgoData;
11970         m_foundPgoData = newPgoData;
11971         newPgoData.SuppressRelease();
11972
11973         newPgoData->m_hr = PgoManager::getPgoInstrumentationResults(pMD, &newPgoData->m_allocatedData, &newPgoData->m_schema,
11974             &newPgoData->m_cSchemaElems, &newPgoData->m_pInstrumentationData, &newPgoData->m_pgoSource);
11975         pDataCur = m_foundPgoData;
11976     }
11977
11978     *pSchema = pDataCur->m_schema;
11979     *pCountSchemaItems = pDataCur->m_cSchemaElems;
11980     *pInstrumentationData = pDataCur->m_pInstrumentationData;
11981     *pPgoSource = pDataCur->m_pgoSource;
11982     hr = pDataCur->m_hr;
11983 #else
11984     _ASSERTE(!"getPgoInstrumentationResults not implemented on CEEJitInfo!");
11985     hr = E_NOTIMPL;
11986 #endif
11987
11988     EE_TO_JIT_TRANSITION();
11989
11990     return hr;
11991 }
11992
11993 void CEEJitInfo::allocMem (AllocMemArgs *pArgs)
11994 {
11995     CONTRACTL {
11996         THROWS;
11997         GC_TRIGGERS;
11998         MODE_PREEMPTIVE;
11999     } CONTRACTL_END;
12000
12001     JIT_TO_EE_TRANSITION();
12002
12003     _ASSERTE(pArgs->coldCodeSize == 0);
12004     if (pArgs->coldCodeBlock)
12005     {
12006         pArgs->coldCodeBlock = NULL;
12007     }
12008
12009     ULONG codeSize      = pArgs->hotCodeSize;
12010     void **codeBlock    = &pArgs->hotCodeBlock;
12011     void **codeBlockRW  = &pArgs->hotCodeBlockRW;
12012
12013     S_SIZE_T totalSize = S_SIZE_T(codeSize);
12014
12015     size_t roDataAlignment = sizeof(void*);
12016     if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_RODATA_64BYTE_ALIGN)!= 0)
12017     {
12018         roDataAlignment = 64;
12019     }
12020     else if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_RODATA_32BYTE_ALIGN)!= 0)
12021     {
12022         roDataAlignment = 32;
12023     }
12024     else if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN)!= 0)
12025     {
12026         roDataAlignment = 16;
12027     }
12028     else if (pArgs->roDataSize >= 8)
12029     {
12030         roDataAlignment = 8;
12031     }
12032     if (pArgs->roDataSize > 0)
12033     {
12034         size_t codeAlignment = sizeof(void*);
12035
12036         if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_32BYTE_ALIGN) != 0)
12037         {
12038             codeAlignment = 32;
12039         }
12040         else if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN) != 0)
12041         {
12042             codeAlignment = 16;
12043         }
12044         totalSize.AlignUp(codeAlignment);
12045
12046         if (roDataAlignment > codeAlignment) {
12047             // Add padding to align read-only data.
12048             totalSize += (roDataAlignment - codeAlignment);
12049         }
12050         totalSize += pArgs->roDataSize;
12051     }
12052
12053 #ifdef FEATURE_EH_FUNCLETS
12054     totalSize.AlignUp(sizeof(DWORD));
12055     totalSize += m_totalUnwindSize;
12056 #endif
12057
12058     _ASSERTE(m_CodeHeader == 0 &&
12059             // The jit-compiler sometimes tries to compile a method a second time
12060             // if it failed the first time. In such a situation, m_CodeHeader may
12061             // have already been assigned. Its OK to ignore this assert in such a
12062             // situation - we will leak some memory, but that is acceptable
12063             // since this should happen very rarely.
12064             "Note that this may fire if the JITCompiler tries to recompile a method");
12065
12066     if( totalSize.IsOverflow() )
12067     {
12068         COMPlusThrowHR(CORJIT_OUTOFMEM);
12069     }
12070
12071     if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, MethodJitMemoryAllocatedForCode))
12072     {
12073         ULONGLONG ullMethodIdentifier = 0;
12074         ULONGLONG ullModuleID = 0;
12075
12076         if (m_pMethodBeingCompiled)
12077         {
12078             Module* pModule = m_pMethodBeingCompiled->GetModule();
12079             ullModuleID = (ULONGLONG)(TADDR)pModule;
12080             ullMethodIdentifier = (ULONGLONG)m_pMethodBeingCompiled;
12081         }
12082
12083         FireEtwMethodJitMemoryAllocatedForCode(ullMethodIdentifier, ullModuleID,
12084             pArgs->hotCodeSize + pArgs->coldCodeSize, pArgs->roDataSize, totalSize.Value(), pArgs->flag, GetClrInstanceId());
12085     }
12086
12087     m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap
12088 #ifdef USE_INDIRECT_CODEHEADER
12089                           , &m_pRealCodeHeader
12090 #endif
12091 #ifdef FEATURE_EH_FUNCLETS
12092                           , m_totalUnwindInfos
12093 #endif
12094                           );
12095
12096 #ifdef FEATURE_EH_FUNCLETS
12097     m_moduleBase = m_pCodeHeap->GetModuleBase();
12098 #endif
12099
12100     BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress();
12101     size_t writeableOffset = (BYTE *)m_CodeHeaderRW - (BYTE *)m_CodeHeader;
12102
12103     *codeBlock = current;
12104     *codeBlockRW = current + writeableOffset;
12105     current += codeSize;
12106
12107     if (pArgs->roDataSize > 0)
12108     {
12109         current = (BYTE *)ALIGN_UP(current, roDataAlignment);
12110         pArgs->roDataBlock = current;
12111         pArgs->roDataBlockRW = current + writeableOffset;
12112         current += pArgs->roDataSize;
12113     }
12114     else
12115     {
12116         pArgs->roDataBlock = NULL;
12117         pArgs->roDataBlockRW = NULL;
12118     }
12119
12120 #ifdef FEATURE_EH_FUNCLETS
12121     current = (BYTE *)ALIGN_UP(current, sizeof(DWORD));
12122
12123     m_theUnwindBlock = current;
12124     current += m_totalUnwindSize;
12125 #endif
12126
12127     _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value());
12128
12129 #ifdef _DEBUG
12130     m_codeSize = codeSize;
12131 #endif  // _DEBUG
12132
12133     EE_TO_JIT_TRANSITION();
12134 }
12135
12136 /*********************************************************************/
12137 void * CEEJitInfo::allocGCInfo (size_t size)
12138 {
12139     CONTRACTL {
12140         THROWS;
12141         GC_TRIGGERS;
12142         MODE_PREEMPTIVE;
12143     } CONTRACTL_END;
12144
12145     void * block = NULL;
12146
12147     JIT_TO_EE_TRANSITION();
12148
12149     _ASSERTE(m_CodeHeaderRW != 0);
12150     _ASSERTE(m_CodeHeaderRW->GetGCInfo() == 0);
12151
12152 #ifdef HOST_64BIT
12153     if (size & 0xFFFFFFFF80000000LL)
12154     {
12155         COMPlusThrowHR(CORJIT_OUTOFMEM);
12156     }
12157 #endif // HOST_64BIT
12158
12159     block = m_jitManager->allocGCInfo(m_CodeHeaderRW,(DWORD)size, &m_GCinfo_len);
12160     if (!block)
12161     {
12162         COMPlusThrowHR(CORJIT_OUTOFMEM);
12163     }
12164
12165     _ASSERTE(m_CodeHeaderRW->GetGCInfo() != 0 && block == m_CodeHeaderRW->GetGCInfo());
12166
12167     EE_TO_JIT_TRANSITION();
12168
12169     return block;
12170 }
12171
12172 /*********************************************************************/
12173 void CEEJitInfo::setEHcount (
12174         unsigned      cEH)
12175 {
12176     CONTRACTL {
12177         THROWS;
12178         GC_TRIGGERS;
12179         MODE_PREEMPTIVE;
12180     } CONTRACTL_END;
12181
12182     JIT_TO_EE_TRANSITION();
12183
12184     _ASSERTE(cEH != 0);
12185     _ASSERTE(m_CodeHeaderRW != 0);
12186     _ASSERTE(m_CodeHeaderRW->GetEHInfo() == 0);
12187
12188     EE_ILEXCEPTION* ret;
12189     ret = m_jitManager->allocEHInfo(m_CodeHeaderRW,cEH, &m_EHinfo_len);
12190     _ASSERTE(ret);      // allocEHInfo throws if there's not enough memory
12191
12192     _ASSERTE(m_CodeHeaderRW->GetEHInfo() != 0 && m_CodeHeaderRW->GetEHInfo()->EHCount() == cEH);
12193
12194     EE_TO_JIT_TRANSITION();
12195 }
12196
12197 /*********************************************************************/
12198 void CEEJitInfo::setEHinfo (
12199         unsigned      EHnumber,
12200         const CORINFO_EH_CLAUSE* clause)
12201 {
12202     CONTRACTL {
12203         THROWS;
12204         GC_TRIGGERS;
12205         MODE_PREEMPTIVE;
12206     } CONTRACTL_END;
12207
12208     JIT_TO_EE_TRANSITION();
12209
12210     // <REVISIT_TODO> Fix make the Code Manager EH clauses EH_INFO+</REVISIT_TODO>
12211     _ASSERTE(m_CodeHeaderRW->GetEHInfo() != 0 && EHnumber < m_CodeHeaderRW->GetEHInfo()->EHCount());
12212
12213     EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeaderRW->GetEHInfo()->EHClause(EHnumber);
12214
12215     pEHClause->TryStartPC     = clause->TryOffset;
12216     pEHClause->TryEndPC       = clause->TryLength;
12217     pEHClause->HandlerStartPC = clause->HandlerOffset;
12218     pEHClause->HandlerEndPC   = clause->HandlerLength;
12219     pEHClause->ClassToken     = clause->ClassToken;
12220     pEHClause->Flags          = (CorExceptionFlag)clause->Flags;
12221
12222     LOG((LF_EH, LL_INFO1000000, "Setting EH clause #%d for %s::%s\n", EHnumber, m_pMethodBeingCompiled->m_pszDebugClassName, m_pMethodBeingCompiled->m_pszDebugMethodName));
12223     LOG((LF_EH, LL_INFO1000000, "    Flags         : 0x%08lx  ->  0x%08lx\n",            clause->Flags,         pEHClause->Flags));
12224     LOG((LF_EH, LL_INFO1000000, "    TryOffset     : 0x%08lx  ->  0x%08lx (startpc)\n",  clause->TryOffset,     pEHClause->TryStartPC));
12225     LOG((LF_EH, LL_INFO1000000, "    TryLength     : 0x%08lx  ->  0x%08lx (endpc)\n",    clause->TryLength,     pEHClause->TryEndPC));
12226     LOG((LF_EH, LL_INFO1000000, "    HandlerOffset : 0x%08lx  ->  0x%08lx\n",            clause->HandlerOffset, pEHClause->HandlerStartPC));
12227     LOG((LF_EH, LL_INFO1000000, "    HandlerLength : 0x%08lx  ->  0x%08lx\n",            clause->HandlerLength, pEHClause->HandlerEndPC));
12228     LOG((LF_EH, LL_INFO1000000, "    ClassToken    : 0x%08lx  ->  0x%08lx\n",            clause->ClassToken,    pEHClause->ClassToken));
12229     LOG((LF_EH, LL_INFO1000000, "    FilterOffset  : 0x%08lx  ->  0x%08lx\n",            clause->FilterOffset,  pEHClause->FilterOffset));
12230
12231     if (m_pMethodBeingCompiled->IsDynamicMethod() &&
12232         ((pEHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) == 0) &&
12233         (clause->ClassToken != NULL))
12234     {
12235         MethodDesc * pMD; FieldDesc * pFD;
12236         m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver()->ResolveToken(clause->ClassToken, (TypeHandle *)&pEHClause->TypeHandle, &pMD, &pFD);
12237         SetHasCachedTypeHandle(pEHClause);
12238         LOG((LF_EH, LL_INFO1000000, "  CachedTypeHandle: 0x%08lx  ->  0x%08lx\n",        clause->ClassToken,    pEHClause->TypeHandle));
12239     }
12240
12241     EE_TO_JIT_TRANSITION();
12242 }
12243
12244 /*********************************************************************/
12245 // get individual exception handler
12246 void CEEJitInfo::getEHinfo(
12247                               CORINFO_METHOD_HANDLE  ftn,      /* IN  */
12248                               unsigned               EHnumber, /* IN  */
12249                               CORINFO_EH_CLAUSE*     clause)   /* OUT */
12250 {
12251     CONTRACTL {
12252         THROWS;
12253         GC_TRIGGERS;
12254         MODE_PREEMPTIVE;
12255     } CONTRACTL_END;
12256
12257     JIT_TO_EE_TRANSITION();
12258
12259     if (IsDynamicMethodHandle(ftn))
12260     {
12261         GetMethod(ftn)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
12262     }
12263     else
12264     {
12265         _ASSERTE(ftn == CORINFO_METHOD_HANDLE(m_pMethodBeingCompiled));  // For now only support if the method being jitted
12266         getEHinfoHelper(ftn, EHnumber, clause, m_ILHeader);
12267     }
12268
12269     EE_TO_JIT_TRANSITION();
12270 }
12271
12272
12273
12274
12275 #ifdef FEATURE_INTERPRETER
12276 static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr,
12277                                                       CEEInfo *comp,
12278                                                       struct CORINFO_METHOD_INFO *info,
12279                                                       unsigned flags,
12280                                                       BYTE **nativeEntry,
12281                                                       ULONG *nativeSizeOfCode)
12282 {
12283     STATIC_CONTRACT_THROWS;
12284     STATIC_CONTRACT_GC_TRIGGERS;
12285     STATIC_CONTRACT_MODE_PREEMPTIVE;
12286
12287     SString namespaceOrClassName, methodName, methodSignature;
12288     // Fire an ETW event to mark the beginning of JIT'ing
12289     ETW::MethodLog::MethodJitting(reinterpret_cast<MethodDesc*>(info->ftn), NULL, &namespaceOrClassName, &methodName, &methodSignature);
12290
12291     CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode);
12292
12293     // Logically, it would seem that the end-of-JITting ETW even should go here, but it must come after the native code has been
12294     // set for the given method desc, which happens in a caller.
12295
12296     return ret;
12297 }
12298 #endif // FEATURE_INTERPRETER
12299
12300 //
12301 // Helper function because can't have dtors in BEGIN_SO_TOLERANT_CODE.
12302 //
12303 CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr,
12304                                  CEEInfo *comp,
12305                                  struct CORINFO_METHOD_INFO *info,
12306                                  CORJIT_FLAGS jitFlags,
12307                                  BYTE **nativeEntry,
12308                                  uint32_t *nativeSizeOfCode)
12309 {
12310     STATIC_CONTRACT_THROWS;
12311     STATIC_CONTRACT_GC_TRIGGERS;
12312     STATIC_CONTRACT_MODE_PREEMPTIVE;
12313
12314     CorJitResult ret = CORJIT_SKIPPED;   // Note that CORJIT_SKIPPED is an error exit status code
12315
12316 #if defined(ALLOW_SXS_JIT)
12317     if (FAILED(ret) && jitMgr->m_alternateJit)
12318     {
12319         CORJIT_FLAGS altJitFlags = jitFlags;
12320         altJitFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_ALT_JIT);
12321         comp->setJitFlags(altJitFlags);
12322         ret = jitMgr->m_alternateJit->compileMethod( comp,
12323                                                      info,
12324                                                      CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12325                                                      nativeEntry,
12326                                                      nativeSizeOfCode);
12327
12328         // If we failed to jit, then fall back to the primary Jit.
12329         if (FAILED(ret))
12330         {
12331             ((CEEJitInfo*)comp)->BackoutJitData(jitMgr);
12332             ((CEEJitInfo*)comp)->ResetForJitRetry();
12333             ret = CORJIT_SKIPPED;
12334         }
12335     }
12336 #endif // defined(ALLOW_SXS_JIT)
12337     comp->setJitFlags(jitFlags);
12338
12339 #ifdef FEATURE_INTERPRETER
12340     static ConfigDWORD s_InterpreterFallback;
12341     static ConfigDWORD s_ForceInterpreter;
12342
12343     bool isInterpreterStub   = false;
12344     bool interpreterFallback = (s_InterpreterFallback.val(CLRConfig::INTERNAL_InterpreterFallback) != 0);
12345     bool forceInterpreter    = (s_ForceInterpreter.val(CLRConfig::INTERNAL_ForceInterpreter) != 0);
12346
12347     if (interpreterFallback == false)
12348     {
12349         // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
12350         // (We assume that importation is completely architecture-independent, or at least nearly so.)
12351         if (FAILED(ret) &&
12352             (forceInterpreter || !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE)))
12353         {
12354             if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
12355             {
12356                 isInterpreterStub = true;
12357             }
12358         }
12359     }
12360
12361     if (FAILED(ret) && jitMgr->m_jit)
12362     {
12363         ret = CompileMethodWithEtwWrapper(jitMgr,
12364                                           comp,
12365                                           info,
12366                                           CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12367                                           nativeEntry,
12368                                           nativeSizeOfCode);
12369     }
12370
12371     if (interpreterFallback == true)
12372     {
12373         // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
12374         // (We assume that importation is completely architecture-independent, or at least nearly so.)
12375         if (FAILED(ret) &&
12376             (forceInterpreter || !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE)))
12377         {
12378             if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
12379             {
12380                 isInterpreterStub = true;
12381             }
12382         }
12383     }
12384 #else
12385     if (FAILED(ret))
12386     {
12387         ret = jitMgr->m_jit->compileMethod( comp,
12388                                             info,
12389                                             CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12390                                             nativeEntry,
12391                                             nativeSizeOfCode);
12392     }
12393 #endif // FEATURE_INTERPRETER
12394
12395     // Cleanup any internal data structures allocated
12396     // such as IL code after a successful JIT compile
12397     // If the JIT fails we keep the IL around and will
12398     // try reJIT the same IL.  VSW 525059
12399     //
12400     if (SUCCEEDED(ret) && !((CEEJitInfo*)comp)->JitAgain())
12401     {
12402         ((CEEJitInfo*)comp)->CompressDebugInfo();
12403
12404 #ifdef FEATURE_INTERPRETER
12405         // We do this cleanup in the prestub, where we know whether the method
12406         // has been interpreted.
12407 #else
12408         comp->MethodCompileComplete(info->ftn);
12409 #endif // FEATURE_INTERPRETER
12410     }
12411
12412
12413 #if defined(FEATURE_GDBJIT)
12414     bool isJittedEntry = SUCCEEDED(ret) && *nativeEntry != NULL;
12415
12416 #ifdef FEATURE_INTERPRETER
12417     isJittedEntry &= !isInterpreterStub;
12418 #endif // FEATURE_INTERPRETER
12419
12420     if (isJittedEntry)
12421     {
12422         CodeHeader* pCH = ((CodeHeader*)((PCODE)*nativeEntry & ~1)) - 1;
12423         pCH->SetCalledMethods((PTR_VOID)comp->GetCalledMethods());
12424     }
12425 #endif
12426
12427     return ret;
12428 }
12429
12430
12431 /*********************************************************************/
12432 CorJitResult invokeCompileMethod(EEJitManager *jitMgr,
12433                                  CEEInfo *comp,
12434                                  struct CORINFO_METHOD_INFO *info,
12435                                  CORJIT_FLAGS jitFlags,
12436                                  BYTE **nativeEntry,
12437                                  uint32_t *nativeSizeOfCode)
12438 {
12439     CONTRACTL {
12440         THROWS;
12441         GC_TRIGGERS;
12442         MODE_COOPERATIVE;
12443     } CONTRACTL_END;
12444     //
12445     // The JIT runs in preemptive mode
12446     //
12447
12448     GCX_PREEMP();
12449
12450     CorJitResult ret = invokeCompileMethodHelper(jitMgr, comp, info, jitFlags, nativeEntry, nativeSizeOfCode);
12451
12452     //
12453     // Verify that we are still in preemptive mode when we return
12454     // from the JIT
12455     //
12456
12457     _ASSERTE(GetThread()->PreemptiveGCDisabled() == FALSE);
12458
12459     return ret;
12460 }
12461
12462 /*********************************************************************/
12463 // Figures out the compile flags that are used by both JIT and NGen
12464
12465 /* static */ CORJIT_FLAGS CEEInfo::GetBaseCompileFlags(MethodDesc * ftn)
12466 {
12467      CONTRACTL {
12468         THROWS;
12469         GC_TRIGGERS;
12470     } CONTRACTL_END;
12471
12472     //
12473     // Figure out the code quality flags
12474     //
12475
12476     CORJIT_FLAGS flags;
12477     if (g_pConfig->JitFramed())
12478         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12479
12480     // Set flags based on method's ImplFlags.
12481     if (!ftn->IsNoMetadata())
12482     {
12483          DWORD dwImplFlags = 0;
12484          IfFailThrow(ftn->GetMDImport()->GetMethodImplProps(ftn->GetMemberDef(), NULL, &dwImplFlags));
12485
12486          if (IsMiNoOptimization(dwImplFlags))
12487          {
12488              flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12489          }
12490
12491          // Always emit frames for methods marked no-inline (see #define ETW_EBP_FRAMED in the JIT)
12492          if (IsMiNoInlining(dwImplFlags))
12493          {
12494              flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12495          }
12496     }
12497
12498     if (ftn->HasUnmanagedCallersOnlyAttribute())
12499     {
12500         // If the stub was generated by the runtime, don't validate
12501         // it for UnmanagedCallersOnlyAttribute usage. There are cases
12502         // where the validation doesn't handle all of the cases we can
12503         // permit during stub generation (e.g. Vector2 returns).
12504         if (!ftn->IsILStub())
12505             COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(ftn);
12506
12507         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_REVERSE_PINVOKE);
12508
12509         // If we're a reverse IL stub, we need to use the TrackTransitions variant
12510         // so we have the target MethodDesc entrypoint to tell the debugger about.
12511         if (CORProfilerTrackTransitions() || ftn->IsILStub())
12512         {
12513             flags.Set(CORJIT_FLAGS::CORJIT_FLAG_TRACK_TRANSITIONS);
12514         }
12515     }
12516
12517     return flags;
12518 }
12519
12520 /*********************************************************************/
12521 // Figures out (some of) the flags to use to compile the method
12522 // Returns the new set to use
12523
12524 CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags)
12525 {
12526     STANDARD_VM_CONTRACT;
12527
12528     //Right now if we don't have a debug interface on CoreCLR, we can't generate debug info.  So, in those
12529     //cases don't attempt it.
12530     if (!g_pDebugInterface)
12531         return flags;
12532
12533 #ifdef DEBUGGING_SUPPORTED
12534
12535 #ifdef _DEBUG
12536     if (g_pConfig->GenDebuggableCode())
12537         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12538 #endif // _DEBUG
12539
12540 #ifdef EnC_SUPPORTED
12541     if (pModule->IsEditAndContinueEnabled())
12542     {
12543         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_EnC);
12544     }
12545 #endif // EnC_SUPPORTED
12546
12547     // Debug info is always tracked
12548     flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12549 #endif // DEBUGGING_SUPPORTED
12550
12551     if (CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
12552     {
12553         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12554     }
12555
12556     return flags;
12557 }
12558
12559 static CORJIT_FLAGS GetCompileFlags(PrepareCodeConfig* prepareConfig, MethodDesc* ftn, CORINFO_METHOD_INFO* methodInfo)
12560 {
12561     STANDARD_VM_CONTRACT;
12562     _ASSERTE(prepareConfig != NULL);
12563     _ASSERTE(ftn != NULL);
12564     _ASSERTE(methodInfo->regionKind ==  CORINFO_REGION_JIT);
12565
12566     CORJIT_FLAGS flags = prepareConfig->GetJitCompilationFlags();
12567
12568     //
12569     // Get the compile flags that are shared between JIT and NGen
12570     //
12571     flags.Add(CEEInfo::GetBaseCompileFlags(ftn));
12572
12573     //
12574     // Get CPU specific flags
12575     //
12576     flags.Add(ExecutionManager::GetEEJitManager()->GetCPUCompileFlags());
12577
12578     //
12579     // Find the debugger and profiler related flags
12580     //
12581
12582 #ifdef DEBUGGING_SUPPORTED
12583     flags.Add(GetDebuggerCompileFlags(ftn->GetModule(), flags));
12584 #endif
12585
12586 #ifdef PROFILING_SUPPORTED
12587     if (CORProfilerTrackEnterLeave() && !ftn->IsNoMetadata())
12588         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE);
12589
12590     if (CORProfilerTrackTransitions())
12591         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_NO_PINVOKE_INLINE);
12592 #endif // PROFILING_SUPPORTED
12593
12594     // Don't allow allocations on FOH from collectible contexts to avoid memory leaks
12595     if (!ftn->GetLoaderAllocator()->CanUnload())
12596     {
12597         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FROZEN_ALLOC_ALLOWED);
12598     }
12599
12600     // Set optimization flags
12601     if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT))
12602     {
12603         unsigned optType = g_pConfig->GenOptimizeType();
12604         _ASSERTE(optType <= OPT_RANDOM);
12605
12606         if (optType == OPT_RANDOM)
12607             optType = methodInfo->ILCodeSize % OPT_RANDOM;
12608
12609         if (g_pConfig->JitMinOpts())
12610         {
12611             flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12612         }
12613         else
12614         {
12615             if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER0))
12616                 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBOPT);
12617         }
12618
12619         if (optType == OPT_SIZE)
12620         {
12621             flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SIZE_OPT);
12622         }
12623         else if (optType == OPT_SPEED)
12624         {
12625             flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SPEED_OPT);
12626         }
12627     }
12628
12629     if (IsDynamicScope(methodInfo->scope))
12630     {
12631         // no debug info available for IL stubs
12632         if (!g_pConfig->GetTrackDynamicMethodDebugInfo())
12633             flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12634
12635         DynamicResolver* pResolver = GetDynamicResolver(methodInfo->scope);
12636         flags.Add(pResolver->GetJitFlags());
12637     }
12638
12639 #ifdef ARM_SOFTFP
12640     flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SOFTFP_ABI);
12641 #endif // ARM_SOFTFP
12642
12643 #ifdef FEATURE_PGO
12644
12645     if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ReadPGOData) > 0)
12646     {
12647         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBOPT);
12648     }
12649     else if (g_pConfig->TieredPGO() && flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER1))
12650     {
12651         flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBOPT);
12652     }
12653
12654 #endif
12655
12656     return flags;
12657 }
12658
12659 // ********************************************************************
12660
12661 // Throw the right type of exception for the given JIT result
12662
12663 void ThrowExceptionForJit(HRESULT res)
12664 {
12665     CONTRACTL
12666     {
12667         THROWS;
12668         GC_NOTRIGGER;
12669         MODE_ANY;
12670     }
12671     CONTRACTL_END;
12672     switch (res)
12673     {
12674         case CORJIT_OUTOFMEM:
12675             COMPlusThrowOM();
12676             break;
12677
12678         case CORJIT_INTERNALERROR:
12679             COMPlusThrow(kInvalidProgramException, (UINT) IDS_EE_JIT_COMPILER_ERROR);
12680             break;
12681
12682         case CORJIT_BADCODE:
12683         case CORJIT_IMPLLIMITATION:
12684         default:
12685             COMPlusThrow(kInvalidProgramException);
12686             break;
12687     }
12688  }
12689
12690 // ********************************************************************
12691 //#define PERF_TRACK_METHOD_JITTIMES
12692 #ifdef TARGET_AMD64
12693 BOOL g_fAllowRel32 = TRUE;
12694 #endif
12695
12696
12697 // ********************************************************************
12698 //                  README!!
12699 // ********************************************************************
12700
12701 // The reason that this is named UnsafeJitFunction is that this helper
12702 // method is not thread safe!  When multiple threads get in here for
12703 // the same pMD, ALL of them MUST return the SAME value.
12704 // To insure that this happens you must call MakeJitWorker.
12705 // It creates a DeadlockAware list of methods being jitted and prevents us
12706 // from trying to jit the same method more that once.
12707 //
12708 // Calls to this method that occur to check if inlining can occur on x86,
12709 // are OK since they discard the return value of this method.
12710 PCODE UnsafeJitFunction(PrepareCodeConfig* config,
12711                         _In_opt_ COR_ILMETHOD_DECODER* ILHeader,
12712                         _In_ CORJIT_FLAGS* pJitFlags,
12713                         _In_opt_ ULONG* pSizeOfCode)
12714 {
12715     STANDARD_VM_CONTRACT;
12716     _ASSERTE(config != NULL);
12717     _ASSERTE(pJitFlags != NULL);
12718
12719     NativeCodeVersion nativeCodeVersion = config->GetCodeVersion();
12720     MethodDesc* ftn = nativeCodeVersion.GetMethodDesc();
12721
12722     PCODE ret = NULL;
12723     NormalizedTimer timer;
12724     int64_t c100nsTicksInJit = 0;
12725
12726     COOPERATIVE_TRANSITION_BEGIN();
12727
12728     timer.Start();
12729
12730     EEJitManager *jitMgr = ExecutionManager::GetEEJitManager();
12731     if (!jitMgr->LoadJIT())
12732     {
12733 #ifdef ALLOW_SXS_JIT
12734         if (!jitMgr->IsMainJitLoaded())
12735         {
12736             // Don't want to throw InvalidProgram from here.
12737             EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12738         }
12739         if (!jitMgr->IsAltJitLoaded())
12740         {
12741             // Don't want to throw InvalidProgram from here.
12742             EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load alternative JIT compiler"));
12743         }
12744 #else // ALLOW_SXS_JIT
12745         // Don't want to throw InvalidProgram from here.
12746         EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12747 #endif // ALLOW_SXS_JIT
12748     }
12749
12750 #ifdef _DEBUG
12751     // This is here so we can see the name and class easily in the debugger
12752
12753     LPCUTF8 cls  = ftn->GetMethodTable()->GetDebugClassName();
12754     LPCUTF8 name = ftn->GetName();
12755
12756     if (ftn->IsNoMetadata())
12757     {
12758         if (ftn->IsILStub())
12759         {
12760             LOG((LF_JIT, LL_INFO10000, "{ Jitting IL Stub }\n"));
12761         }
12762         else
12763         {
12764             LOG((LF_JIT, LL_INFO10000, "{ Jitting dynamic method }\n"));
12765         }
12766     }
12767     else
12768     {
12769         SString methodString;
12770         if (LoggingOn(LF_JIT, LL_INFO10000))
12771             TypeString::AppendMethodDebug(methodString, ftn);
12772
12773         LOG((LF_JIT, LL_INFO10000, "{ Jitting method (%p) %s %s\n", ftn, methodString.GetUTF8(), ftn->m_pszDebugMethodSignature));
12774     }
12775 #endif // _DEBUG
12776
12777     MethodInfoHelperContext cxt{ ftn, ILHeader };
12778     CORINFO_METHOD_INFO methodInfo;
12779     getMethodInfoHelper(cxt, &methodInfo);
12780
12781     // If it's generic then we can only enter through an instantiated MethodDesc
12782     _ASSERTE(!ftn->IsGenericMethodDefinition());
12783
12784     // method attributes and signature are consistant
12785     _ASSERTE(!!ftn->IsStatic() == ((methodInfo.args.callConv & CORINFO_CALLCONV_HASTHIS) == 0));
12786
12787     *pJitFlags = GetCompileFlags(config, ftn, &methodInfo);
12788
12789 #if defined(TARGET_AMD64) || defined(TARGET_ARM64)
12790     BOOL fForceJumpStubOverflow = FALSE;
12791
12792 #ifdef _DEBUG
12793     // Always exercise the overflow codepath with force relocs
12794     if (PEDecoder::GetForceRelocs())
12795         fForceJumpStubOverflow = TRUE;
12796 #endif
12797
12798 #if defined(TARGET_AMD64)
12799     BOOL fAllowRel32 = (g_fAllowRel32 | fForceJumpStubOverflow) && g_pConfig->JitEnableOptionalRelocs();
12800 #endif
12801
12802     size_t reserveForJumpStubs = 0;
12803
12804 #endif // defined(TARGET_AMD64) || defined(TARGET_ARM64)
12805
12806     while (true)
12807     {
12808         CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, !pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING));
12809
12810 #if defined(TARGET_AMD64) || defined(TARGET_ARM64)
12811 #if defined(TARGET_AMD64)
12812         if (fForceJumpStubOverflow)
12813             jitInfo.SetJumpStubOverflow(fAllowRel32);
12814         jitInfo.SetAllowRel32(fAllowRel32);
12815 #else
12816         if (fForceJumpStubOverflow)
12817             jitInfo.SetJumpStubOverflow(fForceJumpStubOverflow);
12818 #endif
12819         jitInfo.SetReserveForJumpStubs(reserveForJumpStubs);
12820 #endif // defined(TARGET_AMD64) || defined(TARGET_ARM64)
12821
12822 #ifdef FEATURE_ON_STACK_REPLACEMENT
12823         // If this is an OSR jit request, grab the OSR info so we can pass it to the jit
12824         if (pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_OSR))
12825         {
12826             unsigned ilOffset = 0;
12827             PatchpointInfo* patchpointInfo = nativeCodeVersion.GetOSRInfo(&ilOffset);
12828             jitInfo.SetOSRInfo(patchpointInfo, ilOffset);
12829         }
12830 #endif // FEATURE_ON_STACK_REPLACEMENT
12831
12832         if (cxt.HasTransientMethodDetails())
12833             jitInfo.AddTransientMethodDetails(cxt.CreateTransientMethodDetails());
12834
12835         MethodDesc * pMethodForSecurity = jitInfo.GetMethodForSecurity(methodInfo.ftn);
12836
12837         //Since the check could trigger a demand, we have to do this every time.
12838         //This is actually an overly complicated way to make sure that a method can access all its arguments
12839         //and its return type.
12840         AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
12841         TypeHandle ownerTypeForSecurity = TypeHandle(pMethodForSecurity->GetMethodTable());
12842         DynamicResolver *pAccessContext = NULL;
12843         BOOL doAccessCheck = TRUE;
12844         if (pMethodForSecurity->IsDynamicMethod())
12845         {
12846             doAccessCheck = ModifyCheckForDynamicMethod(pMethodForSecurity->AsDynamicMethodDesc()->GetResolver(),
12847                                                         &ownerTypeForSecurity,
12848                                                         &accessCheckType, &pAccessContext);
12849         }
12850         if (doAccessCheck)
12851         {
12852             AccessCheckOptions accessCheckOptions(accessCheckType,
12853                                                   pAccessContext,
12854                                                   TRUE /*Throw on error*/,
12855                                                   pMethodForSecurity);
12856
12857             AccessCheckContext accessContext(pMethodForSecurity, ownerTypeForSecurity.GetMethodTable());
12858
12859             // We now do an access check from pMethodForSecurity to pMethodForSecurity, its sole purpose is to
12860             // verify that pMethodForSecurity/ownerTypeForSecurity has access to all its parameters.
12861
12862             // ownerTypeForSecurity.GetMethodTable() can be null if the pMethodForSecurity is a DynamicMethod
12863             // associated with a TypeDesc (Array, Ptr, Ref, or FnPtr). That doesn't make any sense, but we will
12864             // just do an access check from a NULL context which means only public types are accessible.
12865             if (!ClassLoader::CanAccess(&accessContext,
12866                                         ownerTypeForSecurity.GetMethodTable(),
12867                                         ownerTypeForSecurity.GetAssembly(),
12868                                         pMethodForSecurity->GetAttrs(),
12869                                         pMethodForSecurity,
12870                                         NULL,
12871                                         accessCheckOptions))
12872             {
12873                 EX_THROW(EEMethodException, (pMethodForSecurity));
12874             }
12875         }
12876
12877         CorJitResult res;
12878         PBYTE nativeEntry;
12879         uint32_t sizeOfCode;
12880
12881         {
12882             GCX_COOP();
12883
12884             /* There is a double indirection to call compileMethod  - can we
12885                improve this with the new structure? */
12886
12887 #ifdef PERF_TRACK_METHOD_JITTIMES
12888             //Because we're not calling QPC enough.  I'm not going to track times if we're just importing.
12889             LARGE_INTEGER methodJitTimeStart = {0};
12890             QueryPerformanceCounter (&methodJitTimeStart);
12891
12892 #endif
12893             LOG((LF_CORDB, LL_EVERYTHING, "Calling invokeCompileMethod...\n"));
12894
12895             res = invokeCompileMethod(jitMgr,
12896                                       &jitInfo,
12897                                       &methodInfo,
12898                                       *pJitFlags,
12899                                       &nativeEntry,
12900                                       &sizeOfCode);
12901
12902             LOG((LF_CORDB, LL_EVERYTHING, "Got through invokeCompileMethod\n"));
12903
12904 #if FEATURE_PERFMAP
12905             // Save the code size so that it can be reported to the perfmap.
12906             if (pSizeOfCode != NULL)
12907             {
12908                 *pSizeOfCode = sizeOfCode;
12909             }
12910 #endif
12911
12912 #ifdef PERF_TRACK_METHOD_JITTIMES
12913             //store the time in the string buffer.  Module name and token are unique enough.  Also, do not
12914             //capture importing time, just actual compilation time.
12915             {
12916                 LARGE_INTEGER methodJitTimeStop;
12917                 QueryPerformanceCounter(&methodJitTimeStop);
12918
12919                 SString moduleName;
12920                 ftn->GetModule()->GetDomainAssembly()->GetPEAssembly()->GetPathOrCodeBase(moduleName);
12921
12922                 SString codeBase;
12923                 codeBase.AppendPrintf("%s,0x%x,%d,%d\n",
12924                                  moduleName.GetUTF8(), //module name
12925                                  ftn->GetMemberDef(), //method token
12926                                  (unsigned)(methodJitTimeStop.QuadPart - methodJitTimeStart.QuadPart), //cycle count
12927                                  methodInfo.ILCodeSize //il size
12928                                 );
12929                 OutputDebugStringUtf8(codeBase.GetUTF8());
12930             }
12931 #endif // PERF_TRACK_METHOD_JITTIMES
12932
12933         }
12934
12935         LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s  %s }\n",cls,name, ftn->m_pszDebugMethodSignature));
12936
12937         if (SUCCEEDED(res))
12938         {
12939             jitInfo.WriteCode(jitMgr);
12940 #if defined(DEBUGGING_SUPPORTED)
12941             //
12942             // Notify the debugger that we have successfully jitted the function
12943             //
12944             if (g_pDebugInterface)
12945             {
12946                 if (!jitInfo.JitAgain())
12947                 {
12948                     g_pDebugInterface->JITComplete(nativeCodeVersion, (TADDR)nativeEntry);
12949                 }
12950             }
12951 #endif // DEBUGGING_SUPPORTED
12952         }
12953         else
12954         {
12955             jitInfo.BackoutJitData(jitMgr);
12956             ThrowExceptionForJit(res);
12957         }
12958
12959         if (!nativeEntry)
12960             COMPlusThrow(kInvalidProgramException);
12961
12962 #if (defined(TARGET_AMD64) || defined(TARGET_ARM64))
12963         if (jitInfo.IsJumpStubOverflow())
12964         {
12965             // Backout and try again with fAllowRel32 == FALSE.
12966             jitInfo.BackoutJitData(jitMgr);
12967
12968 #ifdef TARGET_AMD64
12969             // Disallow rel32 relocs in future.
12970             g_fAllowRel32 = FALSE;
12971
12972             fAllowRel32 = FALSE;
12973 #endif // TARGET_AMD64
12974 #ifdef TARGET_ARM64
12975             fForceJumpStubOverflow = FALSE;
12976 #endif // TARGET_ARM64
12977
12978             reserveForJumpStubs = jitInfo.GetReserveForJumpStubs();
12979
12980             // Get any transient method details and take ownership
12981             // from the JITInfo instance. We are going to be recreating
12982             // a new JITInfo and will reuse these details there.
12983             TransientMethodDetails details = jitInfo.RemoveTransientMethodDetails(ftn);
12984             cxt.TakeOwnership(std::move(details));
12985             continue;
12986         }
12987 #endif // (TARGET_AMD64 || TARGET_ARM64)
12988
12989         LOG((LF_JIT, LL_INFO10000,
12990             "Jitted Entry at" FMT_ADDR "method %s::%s %s\n", DBG_ADDR(nativeEntry),
12991              ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
12992
12993 #ifdef _DEBUG
12994         LPCUTF8 pszDebugClassName = ftn->m_pszDebugClassName;
12995         LPCUTF8 pszDebugMethodName = ftn->m_pszDebugMethodName;
12996         LPCUTF8 pszDebugMethodSignature = ftn->m_pszDebugMethodSignature;
12997 #elif 0
12998         LPCUTF8 pszNamespace;
12999         LPCUTF8 pszDebugClassName = ftn->GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace);
13000         LPCUTF8 pszDebugMethodName = ftn->GetName();
13001         LPCUTF8 pszDebugMethodSignature = "";
13002 #endif
13003
13004         //DbgPrintf("Jitted Entry at" FMT_ADDR "method %s::%s %s size %08x\n", DBG_ADDR(nativeEntry),
13005         //          pszDebugClassName, pszDebugMethodName, pszDebugMethodSignature, sizeOfCode);
13006
13007         // For dynamic method, the code memory may be reused, thus we are passing in the hasCodeExecutedBefore set to true
13008         ClrFlushInstructionCache(nativeEntry, sizeOfCode, /* hasCodeExecutedBefore */ true);
13009         ret = (PCODE)nativeEntry;
13010
13011 #ifdef TARGET_ARM
13012         ret |= THUMB_CODE;
13013 #endif
13014
13015         // We are done
13016         break;
13017     }
13018
13019 #ifdef _DEBUG
13020     static BOOL fHeartbeat = -1;
13021
13022     if (fHeartbeat == -1)
13023         fHeartbeat = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitHeartbeat);
13024
13025     if (fHeartbeat)
13026         printf(".");
13027 #endif // _DEBUG
13028
13029     timer.Stop();
13030     c100nsTicksInJit = timer.Elapsed100nsTicks();
13031
13032     InterlockedExchangeAdd64((LONG64*)&g_c100nsTicksInJit, c100nsTicksInJit);
13033     t_c100nsTicksInJitForThread += c100nsTicksInJit;
13034
13035     InterlockedExchangeAdd64((LONG64*)&g_cbILJitted, methodInfo.ILCodeSize);
13036     t_cbILJittedForThread += methodInfo.ILCodeSize;
13037
13038     InterlockedIncrement64((LONG64*)&g_cMethodsJitted);
13039     t_cMethodsJittedForThread++;
13040
13041     COOPERATIVE_TRANSITION_END();
13042     return ret;
13043 }
13044
13045 #ifdef FEATURE_READYTORUN
13046 CorInfoHelpFunc MapReadyToRunHelper(ReadyToRunHelper helperNum)
13047 {
13048     LIMITED_METHOD_CONTRACT;
13049
13050     switch (helperNum)
13051     {
13052 #define HELPER(readyToRunHelper, corInfoHelpFunc, flags) \
13053     case readyToRunHelper:                                  return corInfoHelpFunc;
13054 #include "readytorunhelpers.h"
13055
13056     case READYTORUN_HELPER_GetString:                       return CORINFO_HELP_STRCNS;
13057
13058     default:                                                return CORINFO_HELP_UNDEF;
13059     }
13060 }
13061
13062 void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap)
13063 {
13064     STANDARD_VM_CONTRACT;
13065
13066     ZeroMemory(pGCRefMap, cbGCRefMap);
13067
13068     if (!pMT->ContainsPointers())
13069         return;
13070
13071     CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
13072     CGCDescSeries* cur = map->GetHighestSeries();
13073     CGCDescSeries* last = map->GetLowestSeries();
13074     DWORD size = pMT->GetBaseSize();
13075     _ASSERTE(cur >= last);
13076
13077     do
13078     {
13079         // offset to embedded references in this series must be
13080         // adjusted by the VTable pointer, when in the unboxed state.
13081         size_t offset = cur->GetSeriesOffset() - TARGET_POINTER_SIZE;
13082         size_t offsetStop = offset + cur->GetSeriesSize() + size;
13083         while (offset < offsetStop)
13084         {
13085             size_t bit = offset / TARGET_POINTER_SIZE;
13086
13087             size_t index = bit / 8;
13088             _ASSERTE(index < cbGCRefMap);
13089             pGCRefMap[index] |= (1 << (bit & 7));
13090
13091             offset += TARGET_POINTER_SIZE;
13092         }
13093         cur--;
13094     } while (cur >= last);
13095 }
13096
13097 //
13098 // Type layout check verifies that there was no incompatible change in the value type layout.
13099 // If there was one, we will fall back to JIT instead of using the pre-generated code from the ready to run image.
13100 // This should be rare situation. Changes in value type layout not common.
13101 //
13102 // The following properties of the value type layout are checked:
13103 // - Size
13104 // - HFA-ness (on platform that support HFAs)
13105 // - Alignment
13106 // - Position of GC references
13107 //
13108 BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob, BOOL printDiff)
13109 {
13110     STANDARD_VM_CONTRACT;
13111
13112     SigPointer p(pBlob);
13113     IfFailThrow(p.SkipExactlyOne());
13114
13115     uint32_t dwFlags;
13116     IfFailThrow(p.GetData(&dwFlags));
13117
13118     BOOL result = TRUE;
13119
13120     // Size is checked unconditionally
13121     uint32_t dwExpectedSize;
13122     IfFailThrow(p.GetData(&dwExpectedSize));
13123
13124     DWORD dwActualSize = pMT->GetNumInstanceFieldBytes();
13125     if (dwExpectedSize != dwActualSize)
13126     {
13127         if (printDiff)
13128         {
13129             result = FALSE;
13130
13131             DefineFullyQualifiedNameForClass();
13132             printf("Type %s: expected size 0x%08x, actual size 0x%08x\n",
13133                 GetFullyQualifiedNameForClass(pMT), dwExpectedSize, dwActualSize);
13134         }
13135         else
13136         {
13137             return FALSE;
13138         }
13139     }
13140
13141 #ifdef FEATURE_HFA
13142     if (dwFlags & READYTORUN_LAYOUT_HFA)
13143     {
13144         uint32_t dwExpectedHFAType;
13145         IfFailThrow(p.GetData(&dwExpectedHFAType));
13146
13147         DWORD dwActualHFAType = pMT->GetHFAType();
13148         if (dwExpectedHFAType != dwActualHFAType)
13149         {
13150             if (printDiff)
13151             {
13152                 result = FALSE;
13153
13154                 DefineFullyQualifiedNameForClass();
13155                 printf("Type %s: expected HFA type %08x, actual %08x\n",
13156                     GetFullyQualifiedNameForClass(pMT), dwExpectedHFAType, dwActualHFAType);
13157             }
13158             else
13159             {
13160                 return FALSE;
13161             }
13162         }
13163     }
13164     else
13165     {
13166         if (pMT->IsHFA())
13167         {
13168             if (printDiff)
13169             {
13170                 result = FALSE;
13171
13172                 DefineFullyQualifiedNameForClass();
13173                 printf("Type %s: type is HFA but READYTORUN_LAYOUT_HFA flag is not set\n",
13174                     GetFullyQualifiedNameForClass(pMT));
13175             }
13176             else
13177             {
13178                 return FALSE;
13179             }
13180         }
13181     }
13182 #else
13183     _ASSERTE(!(dwFlags & READYTORUN_LAYOUT_HFA));
13184 #endif
13185
13186     if (dwFlags & READYTORUN_LAYOUT_Alignment)
13187     {
13188         uint32_t dwExpectedAlignment = TARGET_POINTER_SIZE;
13189         if (!(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
13190         {
13191             IfFailThrow(p.GetData(&dwExpectedAlignment));
13192         }
13193
13194         DWORD dwActualAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
13195         if (dwExpectedAlignment != dwActualAlignment)
13196         {
13197             if (printDiff)
13198             {
13199                 result = FALSE;
13200
13201                 DefineFullyQualifiedNameForClass();
13202                 printf("Type %s: expected alignment 0x%08x, actual 0x%08x\n",
13203                     GetFullyQualifiedNameForClass(pMT), dwExpectedAlignment, dwActualAlignment);
13204             }
13205             else
13206             {
13207                 return FALSE;
13208             }
13209         }
13210
13211     }
13212
13213     if (dwFlags & READYTORUN_LAYOUT_GCLayout)
13214     {
13215         if (dwFlags & READYTORUN_LAYOUT_GCLayout_Empty)
13216         {
13217             if (pMT->ContainsPointers())
13218             {
13219                 if (printDiff)
13220                 {
13221                     result = FALSE;
13222
13223                     DefineFullyQualifiedNameForClass();
13224                     printf("Type %s contains pointers but READYTORUN_LAYOUT_GCLayout_Empty is set\n",
13225                         GetFullyQualifiedNameForClass(pMT));
13226                 }
13227                 else
13228                 {
13229                     return FALSE;
13230                 }
13231             }
13232         }
13233         else
13234         {
13235             size_t cbGCRefMap = (dwActualSize / TARGET_POINTER_SIZE + 7) / 8;
13236             _ASSERTE(cbGCRefMap > 0);
13237
13238             BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
13239
13240             ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
13241
13242             if (memcmp(pGCRefMap, p.GetPtr(), cbGCRefMap) != 0)
13243             {
13244                 if (printDiff)
13245                 {
13246                     result = FALSE;
13247
13248                     DefineFullyQualifiedNameForClass();
13249                     printf("Type %s: GC refmap content doesn't match\n",
13250                         GetFullyQualifiedNameForClass(pMT));
13251                 }
13252                 else
13253                 {
13254                     return FALSE;
13255                 }
13256             }
13257         }
13258     }
13259
13260     return result;
13261 }
13262
13263 #endif // FEATURE_READYTORUN
13264
13265 bool IsInstructionSetSupported(CORJIT_FLAGS jitFlags, ReadyToRunInstructionSet r2rInstructionSet)
13266 {
13267     CORINFO_InstructionSet instructionSet = InstructionSetFromR2RInstructionSet(r2rInstructionSet);
13268     return jitFlags.IsSet(instructionSet);
13269 }
13270
13271 BOOL LoadDynamicInfoEntry(Module *currentModule,
13272                           RVA fixupRva,
13273                           SIZE_T *entry,
13274                           BOOL mayUsePrecompiledNDirectMethods)
13275 {
13276     STANDARD_VM_CONTRACT;
13277
13278     PCCOR_SIGNATURE pBlob = currentModule->GetNativeFixupBlobData(fixupRva);
13279
13280     BYTE kind = *pBlob++;
13281
13282     ModuleBase * pInfoModule = currentModule;
13283
13284     if (kind & ENCODE_MODULE_OVERRIDE)
13285     {
13286         pInfoModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13287         kind &= ~ENCODE_MODULE_OVERRIDE;
13288     }
13289
13290     MethodDesc * pMD = NULL;
13291
13292     PCCOR_SIGNATURE pSig;
13293     DWORD cSig;
13294
13295     size_t result = 0;
13296
13297     switch (kind)
13298     {
13299     case ENCODE_MODULE_HANDLE:
13300         result = (size_t)pInfoModule;
13301         break;
13302
13303     case ENCODE_TYPE_HANDLE:
13304     case ENCODE_TYPE_DICTIONARY:
13305         {
13306             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13307
13308             if (!th.IsTypeDesc())
13309             {
13310                 if (currentModule->IsReadyToRun())
13311                 {
13312                     // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13313                     th.AsMethodTable()->EnsureInstanceActive();
13314                 }
13315             }
13316
13317             result = (size_t)th.AsPtr();
13318         }
13319         break;
13320
13321     case ENCODE_METHOD_HANDLE:
13322     case ENCODE_METHOD_DICTIONARY:
13323         {
13324             MethodDesc * pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13325
13326             if (currentModule->IsReadyToRun())
13327             {
13328                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13329                 pMD->EnsureActive();
13330             }
13331
13332             result = (size_t)pMD;
13333         }
13334         break;
13335
13336     case ENCODE_FIELD_HANDLE:
13337         result = (size_t) ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13338         break;
13339
13340     case ENCODE_STRING_HANDLE:
13341         {
13342             // We need to update strings atomically (due to NoStringInterning attribute). Note
13343             // that modules with string interning dont really need this, as the hash tables have
13344             // their own locking, but dont add more complexity for what will be the non common
13345             // case.
13346
13347             // We will have to lock and update the entry. (this is really a double check, where
13348             // the first check is done in the caller of this function)
13349             DWORD rid = CorSigUncompressData(pBlob);
13350             if (rid == 0)
13351             {
13352                 // Empty string
13353                 result = (size_t)StringObject::GetEmptyStringRefPtr(nullptr);
13354             }
13355             else
13356             {
13357                 result = (size_t) pInfoModule->ResolveStringRef(TokenFromRid(rid, mdtString));
13358             }
13359         }
13360         break;
13361
13362     case ENCODE_VARARGS_SIG:
13363         {
13364             mdSignature token = TokenFromRid(
13365                                     CorSigUncompressData(pBlob),
13366                                     mdtSignature);
13367
13368             IfFailThrow(pInfoModule->GetMDImport()->GetSigFromToken(token, &cSig, &pSig));
13369
13370             goto VarArgs;
13371         }
13372         break;
13373
13374     case ENCODE_VARARGS_METHODREF:
13375         {
13376             mdSignature token = TokenFromRid(
13377                                     CorSigUncompressData(pBlob),
13378                                     mdtMemberRef);
13379
13380             LPCSTR szName_Ignore;
13381             IfFailThrow(pInfoModule->GetMDImport()->GetNameAndSigOfMemberRef(token, &pSig, &cSig, &szName_Ignore));
13382
13383             goto VarArgs;
13384         }
13385         break;
13386
13387     case ENCODE_VARARGS_METHODDEF:
13388         {
13389             mdSignature token = TokenFromRid(
13390                                     CorSigUncompressData(pBlob),
13391                                     mdtMethodDef);
13392
13393             IfFailThrow(pInfoModule->GetMDImport()->GetSigOfMethodDef(token, &cSig, &pSig));
13394         }
13395         {
13396         VarArgs:
13397             result = (size_t) CORINFO_VARARGS_HANDLE(currentModule->GetVASigCookie(Signature(pSig, cSig)));
13398         }
13399         break;
13400
13401     case ENCODE_METHOD_ENTRY_DEF_TOKEN:
13402         {
13403             mdToken MethodDef = TokenFromRid(CorSigUncompressData(pBlob), mdtMethodDef);
13404             _ASSERTE(pInfoModule->IsFullModule());
13405             pMD = MemberLoader::GetMethodDescFromMethodDef(static_cast<Module*>(pInfoModule), MethodDef, FALSE);
13406
13407             pMD->PrepareForUseAsADependencyOfANativeImage();
13408
13409             if (currentModule->IsReadyToRun())
13410             {
13411                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13412                 pMD->EnsureActive();
13413             }
13414
13415             goto MethodEntry;
13416         }
13417
13418     case ENCODE_METHOD_ENTRY_REF_TOKEN:
13419         {
13420             SigTypeContext typeContext;
13421             mdToken MemberRef = TokenFromRid(CorSigUncompressData(pBlob), mdtMemberRef);
13422             FieldDesc * pFD = NULL;
13423             TypeHandle th;
13424
13425             MemberLoader::GetDescFromMemberRef(pInfoModule, MemberRef, &pMD, &pFD, &typeContext, FALSE /* strict metadata checks */, &th);
13426             _ASSERTE(pMD != NULL);
13427
13428             pMD->PrepareForUseAsADependencyOfANativeImage();
13429
13430             if (currentModule->IsReadyToRun())
13431             {
13432                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13433                 pMD->EnsureActive();
13434             }
13435
13436             goto MethodEntry;
13437         }
13438
13439     case ENCODE_METHOD_ENTRY:
13440         {
13441             pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13442
13443             if (currentModule->IsReadyToRun())
13444             {
13445                 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13446                 pMD->EnsureActive();
13447             }
13448
13449         MethodEntry:
13450             result = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY);
13451         }
13452         break;
13453
13454     case ENCODE_SYNC_LOCK:
13455         {
13456             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13457
13458             result = (size_t) GetClassSync(th.AsMethodTable());
13459         }
13460         break;
13461
13462     case ENCODE_INDIRECT_PINVOKE_TARGET:
13463         {
13464             MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13465
13466             _ASSERTE(pMethod->IsNDirect());
13467             NDirectMethodDesc *pMD = (NDirectMethodDesc*)pMethod;
13468             result = (size_t)(LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
13469         }
13470         break;
13471
13472     case ENCODE_PINVOKE_TARGET:
13473         {
13474             if (mayUsePrecompiledNDirectMethods)
13475             {
13476                 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13477
13478                 _ASSERTE(pMethod->IsNDirect());
13479                 result = (size_t)(LPVOID)NDirectMethodDesc::ResolveAndSetNDirectTarget((NDirectMethodDesc*)pMethod);
13480             }
13481             else
13482             {
13483                 return FALSE;
13484             }
13485         }
13486         break;
13487
13488 #if defined(PROFILING_SUPPORTED)
13489     case ENCODE_PROFILING_HANDLE:
13490         {
13491             MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13492
13493             // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
13494             // they shouldnever come here as they are called out in GetCompileFlag
13495             _ASSERTE(!pMethod->IsNoMetadata());
13496
13497             FunctionID funId = (FunctionID)pMethod;
13498
13499             BOOL bHookFunction = TRUE;
13500             CORINFO_PROFILING_HANDLE profilerHandle = (CORINFO_PROFILING_HANDLE)funId;
13501
13502             {
13503                 BEGIN_PROFILER_CALLBACK(CORProfilerFunctionIDMapperEnabled());
13504                 profilerHandle = (CORINFO_PROFILING_HANDLE)(&g_profControlBlock)->EEFunctionIDMapper(funId, &bHookFunction);
13505                 END_PROFILER_CALLBACK();
13506             }
13507
13508             // Profiling handle is opaque token. It does not have to be aligned thus we can not store it in the same location as token.
13509             *(entry+kZapProfilingHandleImportValueIndexClientData) = (SIZE_T)profilerHandle;
13510
13511             if (bHookFunction)
13512             {
13513                 *(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER].pfnHelper;
13514                 *(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE].pfnHelper;
13515                 *(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL].pfnHelper;
13516             }
13517             else
13518             {
13519                 *(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13520                 *(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13521                 *(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13522             }
13523         }
13524         break;
13525 #endif // PROFILING_SUPPORTED
13526
13527     case ENCODE_FIELD_ADDRESS:
13528         {
13529             FieldDesc *pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13530
13531             pField->GetEnclosingMethodTable()->CheckRestore();
13532
13533             // We can take address of RVA field only since ngened code is domain neutral
13534             _ASSERTE(pField->IsRVA());
13535
13536             result = (size_t)pField->GetStaticAddressHandle(NULL);
13537         }
13538         break;
13539
13540     case ENCODE_VIRTUAL_ENTRY_SLOT:
13541         {
13542             DWORD slot = CorSigUncompressData(pBlob);
13543
13544             TypeHandle ownerType = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13545
13546             LOG((LF_ZAP, LL_INFO100000, "     Fixup stub dispatch\n"));
13547
13548             VirtualCallStubManager * pMgr = currentModule->GetLoaderAllocator()->GetVirtualCallStubManager();
13549
13550             // <REVISIT_TODO>
13551             // We should be generating a stub indirection here, but the zapper already uses one level
13552             // of indirection, i.e. we would have to return IAT_PPVALUE to the JIT, and on the whole the JITs
13553             // aren't quite set up to accept that. Furthermore the call sequences would be different - at
13554             // the moment an indirection cell uses "call [cell-addr]" on x86, and instead we would want the
13555             // euqivalent of "call [[call-addr]]".  This could perhaps be implemented as "call [eax]" </REVISIT_TODO>
13556             result = pMgr->GetCallStub(ownerType, slot);
13557         }
13558         break;
13559
13560     case ENCODE_CLASS_ID_FOR_STATICS:
13561         {
13562             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13563
13564             MethodTable * pMT = th.AsMethodTable();
13565             if (pMT->IsDynamicStatics())
13566             {
13567                 result = pMT->GetModuleDynamicEntryID();
13568             }
13569             else
13570             {
13571                 result = pMT->GetClassIndex();
13572             }
13573         }
13574         break;
13575
13576     case ENCODE_MODULE_ID_FOR_GENERIC_STATICS:
13577         {
13578             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13579
13580             MethodTable * pMT = th.AsMethodTable();
13581
13582             result = pMT->GetModuleForStatics()->GetModuleID();
13583         }
13584         break;
13585
13586 #ifdef FEATURE_READYTORUN
13587     case ENCODE_READYTORUN_HELPER:
13588         {
13589             DWORD helperNum = CorSigUncompressData(pBlob);
13590
13591             CorInfoHelpFunc corInfoHelpFunc = MapReadyToRunHelper((ReadyToRunHelper)helperNum);
13592             if (corInfoHelpFunc != CORINFO_HELP_UNDEF)
13593             {
13594                 result = (size_t)CEEJitInfo::getHelperFtnStatic(corInfoHelpFunc);
13595             }
13596             else
13597             {
13598                 switch (helperNum)
13599                 {
13600                 case READYTORUN_HELPER_Module:
13601                     {
13602                         _ASSERTE(pInfoModule->IsFullModule());
13603                         Module *fullModule = static_cast<Module*>(pInfoModule);
13604                         Module * pPrevious = InterlockedCompareExchangeT((Module **)entry, fullModule, NULL);
13605                         if (pPrevious != pInfoModule && pPrevious != NULL)
13606                             COMPlusThrowHR(COR_E_FILELOAD, IDS_NATIVE_IMAGE_CANNOT_BE_LOADED_MULTIPLE_TIMES, fullModule->GetPath());
13607                         return TRUE;
13608                     }
13609                     break;
13610
13611                 case READYTORUN_HELPER_GSCookie:
13612                     result = (size_t)GetProcessGSCookie();
13613                     break;
13614
13615                 case READYTORUN_HELPER_IndirectTrapThreads:
13616                     result = (size_t)&g_TrapReturningThreads;
13617                     break;
13618
13619                 case READYTORUN_HELPER_DelayLoad_MethodCall:
13620                     result = (size_t)GetEEFuncEntryPoint(DelayLoad_MethodCall);
13621                     break;
13622
13623                 case READYTORUN_HELPER_DelayLoad_Helper:
13624                     result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper);
13625                     break;
13626
13627                 case READYTORUN_HELPER_DelayLoad_Helper_Obj:
13628                     result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_Obj);
13629                     break;
13630
13631                 case READYTORUN_HELPER_DelayLoad_Helper_ObjObj:
13632                     result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_ObjObj);
13633                     break;
13634
13635                 default:
13636                     STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown READYTORUN_HELPER %d\n", helperNum);
13637                     _ASSERTE(!"Unknown READYTORUN_HELPER");
13638                     return FALSE;
13639                 }
13640             }
13641         }
13642         break;
13643
13644     case ENCODE_FIELD_OFFSET:
13645         {
13646             FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13647             _ASSERTE(!pFD->IsStatic());
13648             _ASSERTE(!pFD->IsFieldOfValueType());
13649
13650             DWORD dwOffset = (DWORD)sizeof(Object) + pFD->GetOffset();
13651
13652             if (dwOffset > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13653                 return FALSE;
13654             result = dwOffset;
13655         }
13656         break;
13657
13658     case ENCODE_FIELD_BASE_OFFSET:
13659         {
13660             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13661
13662             MethodTable * pMT = th.AsMethodTable();
13663             _ASSERTE(!pMT->IsValueType());
13664
13665             DWORD dwOffsetBase = ReadyToRunInfo::GetFieldBaseOffset(pMT);
13666             if (dwOffsetBase > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13667                 return FALSE;
13668             result = dwOffsetBase;
13669         }
13670         break;
13671
13672     case ENCODE_CHECK_TYPE_LAYOUT:
13673     case ENCODE_VERIFY_TYPE_LAYOUT:
13674         {
13675             TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13676             MethodTable * pMT = th.AsMethodTable();
13677             _ASSERTE(pMT->IsValueType());
13678
13679             if (!TypeLayoutCheck(pMT, pBlob, /* printDiff */ kind == ENCODE_VERIFY_TYPE_LAYOUT))
13680             {
13681                 if (kind == ENCODE_CHECK_TYPE_LAYOUT)
13682                 {
13683                     return FALSE;
13684                 }
13685                 else
13686                 {
13687                     // Verification failures are failfast events
13688                     DefineFullyQualifiedNameForClass();
13689                     SString fatalErrorString;
13690                     fatalErrorString.Printf("Verify_TypeLayout '%s' failed to verify type layout",
13691                         GetFullyQualifiedNameForClass(pMT));
13692
13693 #ifdef _DEBUG
13694                     {
13695                         _ASSERTE_MSG(false, fatalErrorString.GetUTF8());
13696                         // Run through the type layout logic again, after the assert, makes debugging easy
13697                         TypeLayoutCheck(pMT, pBlob, /* printDiff */ TRUE);
13698                     }
13699 #endif
13700
13701                     EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(-1, fatalErrorString.GetUnicode());
13702                     return FALSE;
13703                 }
13704             }
13705
13706             result = 1;
13707         }
13708         break;
13709
13710     case ENCODE_CHECK_FIELD_OFFSET:
13711         {
13712             DWORD dwExpectedOffset = CorSigUncompressData(pBlob);
13713
13714             FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13715             _ASSERTE(!pFD->IsStatic());
13716
13717             DWORD dwOffset = pFD->GetOffset();
13718             if (!pFD->IsFieldOfValueType())
13719                 dwOffset += sizeof(Object);
13720
13721             if (dwExpectedOffset != dwOffset)
13722                 return FALSE;
13723
13724             result = 1;
13725         }
13726         break;
13727
13728     case ENCODE_VERIFY_FIELD_OFFSET:
13729         {
13730             DWORD baseOffset = CorSigUncompressData(pBlob);
13731             DWORD fieldOffset = CorSigUncompressData(pBlob);
13732             FieldDesc* pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13733             MethodTable *pEnclosingMT = pField->GetApproxEnclosingMethodTable();
13734             pEnclosingMT->CheckRestore();
13735             DWORD actualFieldOffset = pField->GetOffset();
13736             if (!pField->IsStatic() && !pField->IsFieldOfValueType())
13737             {
13738                 actualFieldOffset += sizeof(Object);
13739             }
13740
13741             DWORD actualBaseOffset = 0;
13742             if (!pField->IsStatic() &&
13743                 pEnclosingMT->GetParentMethodTable() != NULL &&
13744                 !pEnclosingMT->IsValueType())
13745             {
13746                 actualBaseOffset = ReadyToRunInfo::GetFieldBaseOffset(pEnclosingMT);
13747             }
13748
13749             if (baseOffset == 0)
13750             {
13751                 // Relative verification of just the field offset when the base class
13752                 // is outside of the current R2R version bubble
13753                 actualFieldOffset -= actualBaseOffset;
13754                 actualBaseOffset = 0;
13755             }
13756
13757             if ((fieldOffset != actualFieldOffset) || (baseOffset != actualBaseOffset))
13758             {
13759                 // Verification failures are failfast events
13760                 DefineFullyQualifiedNameForClass();
13761
13762                 SString fatalErrorString;
13763                 fatalErrorString.Printf("Verify_FieldOffset '%s.%s' Field offset %d!=%d(actual) || baseOffset %d!=%d(actual)",
13764                     GetFullyQualifiedNameForClass(pEnclosingMT),
13765                     pField->GetName(),
13766                     fieldOffset,
13767                     actualFieldOffset,
13768                     baseOffset,
13769                     actualBaseOffset);
13770                 _ASSERTE_MSG(false, fatalErrorString.GetUTF8());
13771
13772                 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(-1, fatalErrorString.GetUnicode());
13773                 return FALSE;
13774             }
13775             result = 1;
13776         }
13777         break;
13778
13779     case ENCODE_VERIFY_VIRTUAL_FUNCTION_OVERRIDE:
13780     case ENCODE_CHECK_VIRTUAL_FUNCTION_OVERRIDE:
13781         {
13782             PCCOR_SIGNATURE updatedSignature = pBlob;
13783
13784             ReadyToRunVirtualFunctionOverrideFlags flags = (ReadyToRunVirtualFunctionOverrideFlags)CorSigUncompressData(updatedSignature);
13785
13786             SigTypeContext typeContext;    // empty context is OK: encoding should not contain type variables.
13787             ZapSig::Context zapSigContext(pInfoModule, (void *)currentModule, ZapSig::NormalTokens);
13788             MethodDesc *pDeclMethod = ZapSig::DecodeMethod(pInfoModule, updatedSignature, &typeContext, &zapSigContext, NULL, NULL, NULL, &updatedSignature, TRUE);
13789             TypeHandle thImpl = ZapSig::DecodeType(currentModule, pInfoModule, updatedSignature, CLASS_LOADED, &updatedSignature);
13790
13791             MethodDesc *pImplMethodCompiler = NULL;
13792
13793             if ((flags & READYTORUN_VIRTUAL_OVERRIDE_VirtualFunctionOverridden) != 0)
13794             {
13795                 pImplMethodCompiler = ZapSig::DecodeMethod(currentModule, pInfoModule, updatedSignature);
13796             }
13797
13798             MethodDesc *pImplMethodRuntime;
13799             if (pDeclMethod->IsInterface())
13800             {
13801                 if (!thImpl.CanCastTo(pDeclMethod->GetMethodTable()))
13802                 {
13803                     MethodTable *pInterfaceTypeCanonical = pDeclMethod->GetMethodTable()->GetCanonicalMethodTable();
13804
13805                     // Its possible for the decl method to need to be found on the only canonically compatible interface on the owning type
13806                     MethodTable::InterfaceMapIterator it = thImpl.GetMethodTable()->IterateInterfaceMap();
13807                     while (it.Next())
13808                     {
13809                         MethodTable *pItfInMap = it.GetInterface(thImpl.GetMethodTable());
13810                         if (pInterfaceTypeCanonical == pItfInMap->GetCanonicalMethodTable())
13811                         {
13812                             pDeclMethod = MethodDesc::FindOrCreateAssociatedMethodDesc(pDeclMethod, pItfInMap, FALSE, pDeclMethod->GetMethodInstantiation(), FALSE, TRUE);
13813                             break;
13814                         }
13815                     }
13816                 }
13817                 DispatchSlot slot = thImpl.GetMethodTable()->FindDispatchSlotForInterfaceMD(pDeclMethod, /*throwOnConflict*/ FALSE);
13818                 pImplMethodRuntime = slot.GetMethodDesc();
13819             }
13820             else
13821             {
13822                 MethodTable *pCheckMT = thImpl.GetMethodTable();
13823                 MethodTable *pBaseMT = pDeclMethod->GetMethodTable();
13824                 WORD slot = pDeclMethod->GetSlot();
13825
13826                 while (pCheckMT != nullptr)
13827                 {
13828                     if (pCheckMT->HasSameTypeDefAs(pBaseMT))
13829                     {
13830                         break;
13831                     }
13832
13833                     pCheckMT = pCheckMT->GetParentMethodTable();
13834                 }
13835
13836                 if (pCheckMT == nullptr)
13837                 {
13838                     pImplMethodRuntime = NULL;
13839                 }
13840                 else if (IsMdFinal(pDeclMethod->GetAttrs()))
13841                 {
13842                     pImplMethodRuntime = pDeclMethod;
13843                 }
13844                 else
13845                 {
13846                     _ASSERTE(slot < pBaseMT->GetNumVirtuals());
13847                     pImplMethodRuntime = thImpl.GetMethodTable()->GetMethodDescForSlot(slot);
13848                 }
13849             }
13850
13851             if (pImplMethodRuntime != pImplMethodCompiler)
13852             {
13853                 if (kind == ENCODE_CHECK_VIRTUAL_FUNCTION_OVERRIDE)
13854                 {
13855                     return FALSE;
13856                 }
13857                 else
13858                 {
13859                     // Verification failures are failfast events
13860                     DefineFullyQualifiedNameForClass();
13861                     SString methodNameDecl;
13862                     SString methodNameImplRuntime(W("(NULL)"));
13863                     SString methodNameImplCompiler(W("(NULL)"));
13864
13865                     pDeclMethod->GetFullMethodInfo(methodNameDecl);
13866
13867                     if (pImplMethodRuntime != NULL)
13868                     {
13869                         methodNameImplRuntime.Clear();
13870                         pImplMethodRuntime->GetFullMethodInfo(methodNameImplRuntime);
13871                     }
13872
13873                     if (pImplMethodCompiler != NULL)
13874                     {
13875                         methodNameImplCompiler.Clear();
13876                         pImplMethodCompiler->GetFullMethodInfo(methodNameImplCompiler);
13877                     }
13878
13879                     SString fatalErrorString;
13880                     fatalErrorString.Printf("Verify_VirtualFunctionOverride Decl Method '%s' on type '%s' is '%s'(actual) instead of expected '%s'(from compiler)",
13881                         methodNameDecl.GetUTF8(),
13882                         GetFullyQualifiedNameForClass(thImpl.GetMethodTable()),
13883                         methodNameImplRuntime.GetUTF8(),
13884                         methodNameImplCompiler.GetUTF8());
13885
13886                     _ASSERTE_MSG(false, fatalErrorString.GetUTF8());
13887                     _ASSERTE(!IsDebuggerPresent() && "Stop on assert here instead of fatal error for ease of live debugging");
13888
13889                     EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(-1, fatalErrorString.GetUnicode());
13890                     return FALSE;
13891
13892                 }
13893             }
13894
13895             result = 1;
13896         }
13897         break;
13898
13899
13900     case ENCODE_CHECK_INSTRUCTION_SET_SUPPORT:
13901         {
13902             DWORD dwInstructionSetCount = CorSigUncompressData(pBlob);
13903             CORJIT_FLAGS corjitFlags = ExecutionManager::GetEEJitManager()->GetCPUCompileFlags();
13904
13905             for (DWORD dwinstructionSetIndex = 0; dwinstructionSetIndex < dwInstructionSetCount; dwinstructionSetIndex++)
13906             {
13907                 DWORD instructionSetEncoded = CorSigUncompressData(pBlob);
13908                 bool mustInstructionSetBeSupported = !!(instructionSetEncoded & 1);
13909                 ReadyToRunInstructionSet instructionSet = (ReadyToRunInstructionSet)(instructionSetEncoded >> 1);
13910                 if (IsInstructionSetSupported(corjitFlags, instructionSet) != mustInstructionSetBeSupported)
13911                 {
13912                     return FALSE;
13913                 }
13914             }
13915             result = 1;
13916         }
13917         break;
13918
13919     case ENCODE_CHECK_IL_BODY:
13920     case ENCODE_VERIFY_IL_BODY:
13921         {
13922             DWORD dwBlobSize = CorSigUncompressData(pBlob);
13923             const uint8_t *const pBlobStart = pBlob;
13924             pBlob += dwBlobSize;
13925             StackSArray<TypeHandle> types;
13926             DWORD cTypes = CorSigUncompressData(pBlob);
13927             bool fail = false;
13928
13929             for (DWORD iType = 0; iType < cTypes && !fail; iType++)
13930             {
13931                 if (kind == ENCODE_CHECK_IL_BODY)
13932                 {
13933                     EX_TRY
13934                     {
13935                         types.Append(ZapSig::DecodeType(currentModule, pInfoModule, pBlob, CLASS_LOAD_APPROXPARENTS, &pBlob));
13936                     }
13937                     EX_CATCH
13938                     {
13939                         fail = true;
13940                     }
13941                     EX_END_CATCH(SwallowAllExceptions)
13942
13943                 }
13944                 else
13945                 {
13946                     types.Append(ZapSig::DecodeType(currentModule, pInfoModule, pBlob, CLASS_LOAD_APPROXPARENTS, &pBlob));
13947                 }
13948             }
13949
13950             MethodDesc *pMDCompare = NULL;
13951
13952             if (!fail)
13953             {
13954                 if (kind == ENCODE_CHECK_IL_BODY)
13955                 {
13956                     EX_TRY
13957                     {
13958                         pMDCompare = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13959                     }
13960                     EX_CATCH
13961                     {
13962                         fail = true;
13963                     }
13964                     EX_END_CATCH(SwallowAllExceptions)
13965                 }
13966                 else
13967                 {
13968                     pMDCompare = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13969                 }
13970             }
13971
13972             ReadyToRunStandaloneMethodMetadata *pMethodMetadata = NULL;
13973             if (!fail)
13974             {
13975                 pMethodMetadata = GetReadyToRunStandaloneMethodMetadata(pMDCompare);
13976                 if (pMethodMetadata == NULL)
13977                     fail = true;
13978
13979                 fail = fail || (pMethodMetadata->cByteData != dwBlobSize);
13980             }
13981
13982             if (!fail)
13983             {
13984                 fail = 0 != memcmp(pBlobStart, pMethodMetadata->pByteData, dwBlobSize);
13985             }
13986
13987             if (!fail)
13988             {
13989                 fail = cTypes != pMethodMetadata->cTypes;
13990             }
13991
13992             if (!fail)
13993             {
13994                 for (COUNT_T i = 0; i < cTypes && !fail; i++)
13995                 {
13996                     fail = types[i] != pMethodMetadata->pTypes[i];
13997                 }
13998             }
13999
14000             if (!fail && !currentModule->GetReadyToRunInfo()->IsForbidProcessMoreILBodyFixups())
14001             {
14002                 result = (size_t)pMDCompare;
14003             }
14004             else
14005             {
14006                 if (kind == ENCODE_CHECK_IL_BODY || (!fail && currentModule->GetReadyToRunInfo()->IsForbidProcessMoreILBodyFixups()))
14007                 {
14008                     return FALSE;
14009                 }
14010                 else
14011                 {
14012                     DefineFullyQualifiedNameForClass();
14013                     SString methodName;
14014                     pMDCompare->GetFullMethodInfo(methodName);
14015                     void* compileTimeTypes = types.OpenRawBuffer();
14016
14017                     int runtimeMethodDataSize = pMethodMetadata != NULL ? (int)pMethodMetadata->cByteData : 0;
14018                     void* runtimeMethodData = pMethodMetadata != NULL ? (void*)pMethodMetadata->pByteData : (void*)NULL;
14019
14020                     int runtimeTypeCount = pMethodMetadata != NULL ? (int)pMethodMetadata->cTypes : 0;
14021                     void* runtimeTypeData = pMethodMetadata != NULL ? (void*)pMethodMetadata->pTypes : (void*)NULL;
14022
14023                     SString fatalErrorString;
14024                     fatalErrorString.Printf("VERIFY_IL_BODY Method '%s' type '%s' does not match IL body expected DEBUGINFO MethodData {%d} {%p} RuntimeMethodData {%d} {%p} Types {%d} {%p} RuntimeTypes {%d} {%p}",
14025                         methodName.GetUTF8(),
14026                         GetFullyQualifiedNameForClass(pMDCompare->GetMethodTable()),
14027                         (int)dwBlobSize, pBlobStart,
14028                         runtimeMethodDataSize, runtimeMethodData,
14029                         (int)cTypes, compileTimeTypes,
14030                         runtimeTypeCount, runtimeTypeData
14031                         );
14032
14033                     _ASSERTE_MSG(false, fatalErrorString.GetUTF8());
14034                     _ASSERTE(!IsDebuggerPresent() && "Stop on assert here instead of fatal error for ease of live debugging");
14035
14036                     EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(-1, fatalErrorString.GetUnicode());
14037                     return FALSE;
14038                 }
14039             }
14040             break;
14041         }
14042 #endif // FEATURE_READYTORUN
14043     default:
14044         STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown FIXUP_BLOB_KIND %d\n", kind);
14045         _ASSERTE(!"Unknown FIXUP_BLOB_KIND");
14046         return FALSE;
14047     }
14048
14049     MemoryBarrier();
14050     *entry = result;
14051
14052     return TRUE;
14053 }
14054
14055 bool CEEInfo::getTailCallHelpersInternal(CORINFO_RESOLVED_TOKEN* callToken,
14056                                          CORINFO_SIG_INFO* sig,
14057                                          CORINFO_GET_TAILCALL_HELPERS_FLAGS flags,
14058                                          CORINFO_TAILCALL_HELPERS* pResult)
14059 {
14060     MethodDesc* pTargetMD = NULL;
14061
14062     if (callToken != NULL)
14063     {
14064         pTargetMD = (MethodDesc*)callToken->hMethod;
14065         _ASSERTE(pTargetMD != NULL);
14066
14067         if (pTargetMD->IsWrapperStub())
14068         {
14069             pTargetMD = pTargetMD->GetWrappedMethodDesc();
14070         }
14071
14072         // We currently do not handle generating the proper call to managed
14073         // varargs methods.
14074         if (pTargetMD->IsVarArg())
14075         {
14076             return false;
14077         }
14078     }
14079
14080     SigTypeContext typeCtx;
14081     GetTypeContext(&sig->sigInst, &typeCtx);
14082
14083     MetaSig msig(sig->pSig, sig->cbSig, GetModule(sig->scope), &typeCtx);
14084
14085     bool isCallvirt = (flags & CORINFO_TAILCALL_IS_CALLVIRT) != 0;
14086     bool isThisArgByRef = (flags & CORINFO_TAILCALL_THIS_ARG_IS_BYREF) != 0;
14087
14088     MethodDesc* pStoreArgsMD;
14089     MethodDesc* pCallTargetMD;
14090     bool needsTarget;
14091
14092     TailCallHelp::CreateTailCallHelperStubs(
14093         m_pMethodBeingCompiled, pTargetMD,
14094         msig, isCallvirt, isThisArgByRef, sig->hasTypeArg(),
14095         &pStoreArgsMD, &needsTarget,
14096         &pCallTargetMD);
14097
14098     unsigned outFlags = 0;
14099     if (needsTarget)
14100     {
14101         outFlags |= CORINFO_TAILCALL_STORE_TARGET;
14102     }
14103
14104     pResult->flags = (CORINFO_TAILCALL_HELPERS_FLAGS)outFlags;
14105     pResult->hStoreArgs = (CORINFO_METHOD_HANDLE)pStoreArgsMD;
14106     pResult->hCallTarget = (CORINFO_METHOD_HANDLE)pCallTargetMD;
14107     pResult->hDispatcher = (CORINFO_METHOD_HANDLE)TailCallHelp::GetOrLoadTailCallDispatcherMD();
14108     return true;
14109 }
14110
14111 bool CEEInfo::getTailCallHelpers(CORINFO_RESOLVED_TOKEN* callToken,
14112                                  CORINFO_SIG_INFO* sig,
14113                                  CORINFO_GET_TAILCALL_HELPERS_FLAGS flags,
14114                                  CORINFO_TAILCALL_HELPERS* pResult)
14115 {
14116     CONTRACTL {
14117         THROWS;
14118         GC_TRIGGERS;
14119         MODE_PREEMPTIVE;
14120     } CONTRACTL_END;
14121
14122     bool success = false;
14123
14124     JIT_TO_EE_TRANSITION();
14125
14126     success = getTailCallHelpersInternal(callToken, sig, flags, pResult);
14127
14128     EE_TO_JIT_TRANSITION();
14129
14130     return success;
14131 }
14132
14133 bool CEEInfo::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert)
14134 {
14135     return false;
14136 }
14137
14138 void CEEInfo::updateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint)
14139 {
14140     // No update necessary, all entry points are tail callable in runtime.
14141 }
14142
14143 void CEEInfo::allocMem (AllocMemArgs *pArgs)
14144 {
14145     LIMITED_METHOD_CONTRACT;
14146     UNREACHABLE();      // only called on derived class.
14147 }
14148
14149 void CEEInfo::reserveUnwindInfo (
14150         bool                isFunclet,             /* IN */
14151         bool                isColdCode,            /* IN */
14152         uint32_t            unwindSize             /* IN */
14153         )
14154 {
14155     LIMITED_METHOD_CONTRACT;
14156     UNREACHABLE();      // only called on derived class.
14157 }
14158
14159 void CEEInfo::allocUnwindInfo (
14160         uint8_t *           pHotCode,              /* IN */
14161         uint8_t *           pColdCode,             /* IN */
14162         uint32_t            startOffset,           /* IN */
14163         uint32_t            endOffset,             /* IN */
14164         uint32_t            unwindSize,            /* IN */
14165         uint8_t *           pUnwindBlock,          /* IN */
14166         CorJitFuncKind      funcKind               /* IN */
14167         )
14168 {
14169     LIMITED_METHOD_CONTRACT;
14170     UNREACHABLE();      // only called on derived class.
14171 }
14172
14173 void * CEEInfo::allocGCInfo (
14174         size_t                  size        /* IN */
14175         )
14176 {
14177     LIMITED_METHOD_CONTRACT;
14178     UNREACHABLE_RET();      // only called on derived class.
14179 }
14180
14181 void CEEInfo::setEHcount (
14182         unsigned             cEH    /* IN */
14183         )
14184 {
14185     LIMITED_METHOD_CONTRACT;
14186     UNREACHABLE();      // only called on derived class.
14187 }
14188
14189 void CEEInfo::setEHinfo (
14190         unsigned             EHnumber,   /* IN  */
14191         const CORINFO_EH_CLAUSE *clause      /* IN */
14192         )
14193 {
14194     LIMITED_METHOD_CONTRACT;
14195     UNREACHABLE();      // only called on derived class.
14196 }
14197
14198 InfoAccessType CEEInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
14199                                                mdToken metaTok,
14200                                                void **ppValue)
14201 {
14202     LIMITED_METHOD_CONTRACT;
14203     UNREACHABLE();      // only called on derived class.
14204 }
14205
14206 InfoAccessType CEEInfo::emptyStringLiteral(void ** ppValue)
14207 {
14208     LIMITED_METHOD_CONTRACT;
14209     UNREACHABLE();      // only called on derived class.
14210 }
14211
14212 CORINFO_CLASS_HANDLE CEEInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
14213                                                          bool* pIsSpeculative)
14214 {
14215     LIMITED_METHOD_CONTRACT;
14216     UNREACHABLE();      // only called on derived class.
14217 }
14218
14219 void* CEEInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
14220                              void **ppIndirection)
14221 {
14222     LIMITED_METHOD_CONTRACT;
14223     UNREACHABLE();      // only called on derived class.
14224 }
14225
14226 HRESULT CEEInfo::allocPgoInstrumentationBySchema(
14227             CORINFO_METHOD_HANDLE ftnHnd, /* IN */
14228             PgoInstrumentationSchema* pSchema, /* IN/OUT */
14229             uint32_t countSchemaItems, /* IN */
14230             uint8_t** pInstrumentationData /* OUT */
14231             )
14232 {
14233     LIMITED_METHOD_CONTRACT;
14234     UNREACHABLE_RET();      // only called on derived class.
14235 }
14236
14237 HRESULT CEEInfo::getPgoInstrumentationResults(
14238             CORINFO_METHOD_HANDLE      ftnHnd,
14239             PgoInstrumentationSchema **pSchema,                    // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes)
14240             uint32_t *                 pCountSchemaItems,          // pointer to the count schema items
14241             uint8_t **                 pInstrumentationData,       // pointer to the actual instrumentation data (pointer will not remain valid after jit completes)
14242             PgoSource *                pPgoSource
14243             )
14244 {
14245     LIMITED_METHOD_CONTRACT;
14246     UNREACHABLE_RET();      // only called on derived class.
14247 }
14248
14249 void CEEInfo::recordCallSite(
14250         uint32_t              instrOffset,  /* IN */
14251         CORINFO_SIG_INFO *    callSig,      /* IN */
14252         CORINFO_METHOD_HANDLE methodHandle  /* IN */
14253         )
14254 {
14255     LIMITED_METHOD_CONTRACT;
14256     UNREACHABLE();      // only called on derived class.
14257 }
14258
14259 void CEEInfo::recordRelocation(
14260         void *                 location,   /* IN  */
14261         void *                 locationRW, /* IN  */
14262         void *                 target,     /* IN  */
14263         WORD                   fRelocType, /* IN  */
14264         INT32                  addlDelta /* IN  */
14265         )
14266 {
14267     LIMITED_METHOD_CONTRACT;
14268     UNREACHABLE();      // only called on derived class.
14269 }
14270
14271 WORD CEEInfo::getRelocTypeHint(void * target)
14272 {
14273     LIMITED_METHOD_CONTRACT;
14274     UNREACHABLE_RET();      // only called on derived class.
14275 }
14276
14277 uint32_t CEEInfo::getExpectedTargetArchitecture()
14278 {
14279     LIMITED_METHOD_CONTRACT;
14280
14281     return IMAGE_FILE_MACHINE_NATIVE;
14282 }
14283
14284 void CEEInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
14285                                ICorDebugInfo::OffsetMapping *pMap)
14286 {
14287     LIMITED_METHOD_CONTRACT;
14288     UNREACHABLE();      // only called on derived class.
14289 }
14290
14291 void CEEInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
14292 {
14293     LIMITED_METHOD_CONTRACT;
14294     UNREACHABLE();      // only called on derived class.
14295 }
14296
14297 void CEEInfo::reportRichMappings(
14298         ICorDebugInfo::InlineTreeNode*    inlineTreeNodes,
14299         uint32_t                          numInlineTreeNodes,
14300         ICorDebugInfo::RichOffsetMapping* mappings,
14301         uint32_t                          numMappings)
14302 {
14303     LIMITED_METHOD_CONTRACT;
14304     UNREACHABLE();      // only called on derived class.
14305 }
14306
14307 void CEEInfo::setPatchpointInfo(PatchpointInfo* patchpointInfo)
14308 {
14309     LIMITED_METHOD_CONTRACT;
14310     UNREACHABLE();      // only called on derived class.
14311 }
14312
14313 PatchpointInfo* CEEInfo::getOSRInfo(unsigned* ilOffset)
14314 {
14315     LIMITED_METHOD_CONTRACT;
14316     UNREACHABLE();      // only called on derived class.
14317 }
14318
14319 void* CEEInfo::getHelperFtn(CorInfoHelpFunc    ftnNum,         /* IN  */
14320                             void **            ppIndirection)  /* OUT */
14321 {
14322     LIMITED_METHOD_CONTRACT;
14323     UNREACHABLE();      // only called on derived class.
14324 }
14325
14326 void CEEInfo::GetProfilingHandle(bool                      *pbHookFunction,
14327                                  void                     **pProfilerHandle,
14328                                  bool                      *pbIndirectedHandles)
14329 {
14330     LIMITED_METHOD_CONTRACT;
14331     UNREACHABLE();      // only called on derived class.
14332 }
14333
14334 bool CEEInfo::notifyInstructionSetUsage(CORINFO_InstructionSet instructionSet,
14335                                         bool supportEnabled)
14336 {
14337     LIMITED_METHOD_CONTRACT;
14338     // Do nothing. This api does not provide value in JIT scenarios and
14339     // crossgen does not utilize the api either.
14340     return supportEnabled;
14341 }
14342
14343 #endif // !DACCESS_COMPILE
14344
14345 EECodeInfo::EECodeInfo()
14346 {
14347     WRAPPER_NO_CONTRACT;
14348
14349     m_codeAddress = NULL;
14350
14351     m_pJM = NULL;
14352     m_pMD = NULL;
14353     m_relOffset = 0;
14354
14355 #ifdef FEATURE_EH_FUNCLETS
14356     m_pFunctionEntry = NULL;
14357 #endif
14358 }
14359
14360 void EECodeInfo::Init(PCODE codeAddress)
14361 {
14362     CONTRACTL {
14363         NOTHROW;
14364         GC_NOTRIGGER;
14365     } CONTRACTL_END;
14366
14367     Init(codeAddress, ExecutionManager::GetScanFlags());
14368 }
14369
14370 void EECodeInfo::Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag)
14371 {
14372     CONTRACTL {
14373         NOTHROW;
14374         GC_NOTRIGGER;
14375     } CONTRACTL_END;
14376
14377     m_codeAddress = codeAddress;
14378
14379     RangeSection * pRS = ExecutionManager::FindCodeRange(codeAddress, scanFlag);
14380     if (pRS == NULL)
14381         goto Invalid;
14382
14383     if (!pRS->_pjit->JitCodeToMethodInfo(pRS, codeAddress, &m_pMD, this))
14384         goto Invalid;
14385
14386     m_pJM = pRS->_pjit;
14387     return;
14388
14389 Invalid:
14390     m_pJM = NULL;
14391     m_pMD = NULL;
14392     m_relOffset = 0;
14393
14394 #ifdef FEATURE_EH_FUNCLETS
14395     m_pFunctionEntry = NULL;
14396 #endif
14397 }
14398
14399 TADDR EECodeInfo::GetSavedMethodCode()
14400 {
14401     CONTRACTL {
14402         // All EECodeInfo methods must be NOTHROW/GC_NOTRIGGER since they can
14403         // be used during GC.
14404         NOTHROW;
14405         GC_NOTRIGGER;
14406         HOST_NOCALLS;
14407         SUPPORTS_DAC;
14408     } CONTRACTL_END;
14409 #ifndef HOST_64BIT
14410 #if defined(HAVE_GCCOVER)
14411
14412     PTR_GCCoverageInfo gcCover = GetNativeCodeVersion().GetGCCoverageInfo();
14413     _ASSERTE (!gcCover || GCStress<cfg_instr>::IsEnabled());
14414     if (GCStress<cfg_instr>::IsEnabled()
14415         && gcCover)
14416     {
14417         _ASSERTE(gcCover->savedCode);
14418
14419         // Make sure we return the TADDR of savedCode here.  The byte array is not marshaled automatically.
14420         // The caller is responsible for any necessary marshaling.
14421         return PTR_TO_MEMBER_TADDR(GCCoverageInfo, gcCover, savedCode);
14422     }
14423 #endif //defined(HAVE_GCCOVER)
14424 #endif
14425
14426     return GetStartAddress();
14427 }
14428
14429 TADDR EECodeInfo::GetStartAddress()
14430 {
14431     CONTRACTL {
14432         NOTHROW;
14433         GC_NOTRIGGER;
14434         HOST_NOCALLS;
14435         SUPPORTS_DAC;
14436     } CONTRACTL_END;
14437
14438     return m_pJM->JitTokenToStartAddress(m_methodToken);
14439 }
14440
14441 NativeCodeVersion EECodeInfo::GetNativeCodeVersion()
14442 {
14443     CONTRACTL
14444     {
14445         NOTHROW;
14446         GC_NOTRIGGER;
14447     }
14448     CONTRACTL_END;
14449
14450     PTR_MethodDesc pMD = PTR_MethodDesc(GetMethodDesc());
14451     if (pMD == NULL)
14452     {
14453         return NativeCodeVersion();
14454     }
14455
14456 #ifdef FEATURE_CODE_VERSIONING
14457     if (pMD->IsVersionable())
14458     {
14459         CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
14460         CodeVersionManager::LockHolder codeVersioningLockHolder;
14461         return pCodeVersionManager->GetNativeCodeVersion(pMD, PINSTRToPCODE(GetStartAddress()));
14462     }
14463 #endif
14464     return NativeCodeVersion(pMD);
14465 }
14466
14467 #if defined(FEATURE_EH_FUNCLETS)
14468
14469 // ----------------------------------------------------------------------------
14470 // EECodeInfo::GetMainFunctionInfo
14471 //
14472 // Description:
14473 //    Simple helper to transform a funclet's EECodeInfo into a parent function EECodeInfo.
14474 //
14475 // Return Value:
14476 //    An EECodeInfo for the start of the main function body (offset 0).
14477 //
14478
14479 EECodeInfo EECodeInfo::GetMainFunctionInfo()
14480 {
14481     LIMITED_METHOD_CONTRACT;
14482     SUPPORTS_DAC;
14483
14484     EECodeInfo result = *this;
14485     result.m_relOffset = 0;
14486     result.m_codeAddress = this->GetStartAddress();
14487     result.m_pFunctionEntry = NULL;
14488
14489     return result;
14490 }
14491
14492 PTR_RUNTIME_FUNCTION EECodeInfo::GetFunctionEntry()
14493 {
14494     LIMITED_METHOD_CONTRACT;
14495     SUPPORTS_DAC;
14496
14497     if (m_pFunctionEntry == NULL)
14498         m_pFunctionEntry = m_pJM->LazyGetFunctionEntry(this);
14499     return m_pFunctionEntry;
14500 }
14501
14502 #if defined(TARGET_AMD64)
14503
14504 BOOL EECodeInfo::HasFrameRegister()
14505 {
14506     LIMITED_METHOD_CONTRACT;
14507
14508     PTR_RUNTIME_FUNCTION pFuncEntry = GetFunctionEntry();
14509     _ASSERTE(pFuncEntry != NULL);
14510
14511     BOOL fHasFrameRegister = FALSE;
14512     PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(GetModuleBase() + pFuncEntry->UnwindData);
14513     if (pUnwindInfo->FrameRegister != 0)
14514     {
14515         fHasFrameRegister = TRUE;
14516         _ASSERTE(pUnwindInfo->FrameRegister == kRBP);
14517     }
14518
14519     return fHasFrameRegister;
14520 }
14521 #endif // defined(TARGET_AMD64)
14522
14523 #endif // defined(FEATURE_EH_FUNCLETS)
14524
14525
14526 #if defined(TARGET_AMD64)
14527 // ----------------------------------------------------------------------------
14528 // EECodeInfo::GetUnwindInfoHelper
14529 //
14530 // Description:
14531 //    Simple helper to return a pointer to the UNWIND_INFO given the offset to the unwind info.
14532 //    On DAC builds, this function will read the memory from the target process and create a host copy.
14533 //
14534 // Arguments:
14535 //    * unwindInfoOffset - This is the offset to the unwind info, relative to the beginning of the code heap
14536 //        for jitted code or to the module base for ngned code. this->GetModuleBase() will return the correct
14537 //        module base.
14538 //
14539 // Return Value:
14540 //    Return a pointer to the UNWIND_INFO.  On DAC builds, this function will create a host copy of the
14541 //    UNWIND_INFO and return a host pointer.  It will correctly read all of the memory for the variable-sized
14542 //    unwind info.
14543 //
14544
14545 UNWIND_INFO * EECodeInfo::GetUnwindInfoHelper(ULONG unwindInfoOffset)
14546 {
14547 #if defined(DACCESS_COMPILE)
14548     return DacGetUnwindInfo(static_cast<TADDR>(this->GetModuleBase() + unwindInfoOffset));
14549 #else  // !DACCESS_COMPILE
14550     UNWIND_INFO * pUnwindInfo = reinterpret_cast<UNWIND_INFO *>(this->GetModuleBase() + unwindInfoOffset);
14551 #if defined(TARGET_AMD64)
14552     if (pUnwindInfo->Flags & UNW_FLAG_CHAININFO)
14553     {
14554         unwindInfoOffset = ((PTR_RUNTIME_FUNCTION)(&(pUnwindInfo->UnwindCode)))->UnwindData;
14555         pUnwindInfo = reinterpret_cast<UNWIND_INFO *>(this->GetModuleBase() + unwindInfoOffset);
14556     }
14557 #endif // TARGET_AMD64
14558     return pUnwindInfo;
14559 #endif // !DACCESS_COMPILE
14560 }
14561
14562 // ----------------------------------------------------------------------------
14563 // EECodeInfo::GetFixedStackSize
14564 //
14565 // Description:
14566 //    Return the fixed stack size of a specified managed method.  This function DOES NOT take current control
14567 //    PC into account.  So the fixed stack size returned by this function is not valid in the prolog or
14568 //    the epilog.
14569 //
14570 // Return Value:
14571 //    Return the fixed stack size.
14572 //
14573 // Notes:
14574 //    * For method with dynamic stack allocations, this function will return the fixed stack size on X64 (the
14575 //        stack size immediately after the prolog), and it will return 0 on IA64. This difference is due to
14576 //        the different unwind info encoding.
14577 //
14578
14579 ULONG EECodeInfo::GetFixedStackSize()
14580 {
14581     WRAPPER_NO_CONTRACT;
14582     SUPPORTS_DAC;
14583
14584     ULONG uFixedStackSize = 0;
14585
14586     ULONG uDummy = 0;
14587     GetOffsetsFromUnwindInfo(&uFixedStackSize, &uDummy);
14588
14589     return uFixedStackSize;
14590 }
14591
14592 #define kRBP    5
14593 // The information returned by this method is only valid if we are not in a prolog or an epilog.
14594 // Since this method is only used for the security stackwalk cache and EnC transition, this assumption is
14595 // valid, since we cannot see these in a prolog or an epilog.
14596 //
14597 // The next assumption is that only rbp is used as a frame register in jitted code.  There is an
14598 // assert below to guard this assumption.
14599 void EECodeInfo::GetOffsetsFromUnwindInfo(ULONG* pRSPOffset, ULONG* pRBPOffset)
14600 {
14601     LIMITED_METHOD_CONTRACT;
14602     SUPPORTS_DAC;
14603
14604     _ASSERTE((pRSPOffset != NULL) && (pRBPOffset != NULL));
14605
14606     // moduleBase is a target address.
14607     TADDR moduleBase = GetModuleBase();
14608
14609     DWORD unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(GetFunctionEntry());
14610
14611     if ((unwindInfo & RUNTIME_FUNCTION_INDIRECT) != 0)
14612     {
14613         unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(PTR_RUNTIME_FUNCTION(moduleBase + (unwindInfo & ~RUNTIME_FUNCTION_INDIRECT)));
14614     }
14615
14616     UNWIND_INFO * pInfo = GetUnwindInfoHelper(unwindInfo);
14617     _ASSERTE((pInfo->Flags & UNW_FLAG_CHAININFO) == 0);
14618
14619     // Either we are not using a frame pointer, or we are using rbp as the frame pointer.
14620     if ( (pInfo->FrameRegister != 0) && (pInfo->FrameRegister != kRBP) )
14621     {
14622         _ASSERTE(!"GetRbpOffset() - non-RBP frame pointer used, violating assumptions of the security stackwalk cache");
14623         DebugBreak();
14624     }
14625
14626     // Walk the unwind info.
14627     ULONG StackOffset     = 0;
14628     ULONG StackSize       = 0;
14629     for (int i = 0; i < pInfo->CountOfUnwindCodes; i++)
14630     {
14631         ULONG UnwindOp = pInfo->UnwindCode[i].UnwindOp;
14632         ULONG OpInfo   = pInfo->UnwindCode[i].OpInfo;
14633
14634         if (UnwindOp == UWOP_SAVE_NONVOL)
14635         {
14636             if (OpInfo == kRBP)
14637             {
14638                 StackOffset = pInfo->UnwindCode[i+1].FrameOffset * 8;
14639             }
14640         }
14641         else if (UnwindOp == UWOP_SAVE_NONVOL_FAR)
14642         {
14643             if (OpInfo == kRBP)
14644             {
14645                 StackOffset  =  pInfo->UnwindCode[i + 1].FrameOffset;
14646                 StackOffset += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14647             }
14648         }
14649         else if (UnwindOp == UWOP_ALLOC_SMALL)
14650         {
14651             StackSize += (OpInfo * 8) + 8;
14652         }
14653         else if (UnwindOp == UWOP_ALLOC_LARGE)
14654         {
14655             ULONG IncrementalStackSize = pInfo->UnwindCode[i + 1].FrameOffset;
14656             if (OpInfo == 0)
14657             {
14658                 IncrementalStackSize *= 8;
14659             }
14660             else
14661             {
14662                 IncrementalStackSize += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14663
14664                 // This is a special opcode.  We need to increment the index by 1 in addition to the normal adjustments.
14665                 i += 1;
14666             }
14667             StackSize += IncrementalStackSize;
14668         }
14669         else if (UnwindOp == UWOP_PUSH_NONVOL)
14670         {
14671             // Because of constraints on epilogs, this unwind opcode is always last in the unwind code array.
14672             // This means that StackSize has been initialized already when we first see this unwind opcode.
14673             // Note that the initial value of StackSize does not include the stack space used for pushes.
14674             // Thus, here we only need to increment StackSize 8 bytes at a time until we see the unwind code for "push rbp".
14675             if (OpInfo == kRBP)
14676             {
14677                 StackOffset = StackSize;
14678             }
14679
14680             StackSize += 8;
14681         }
14682
14683         // Adjust the index into the unwind code array.
14684         i += UnwindOpExtraSlotTable[UnwindOp];
14685     }
14686
14687     *pRSPOffset = StackSize + 8;        // add 8 for the return address
14688     *pRBPOffset = StackOffset;
14689 }
14690 #undef kRBP
14691
14692
14693 #if defined(_DEBUG) && defined(HAVE_GCCOVER)
14694
14695 LPVOID                EECodeInfo::findNextFunclet (LPVOID pvFuncletStart, SIZE_T cbCode, LPVOID *ppvFuncletEnd)
14696 {
14697     CONTRACTL {
14698         NOTHROW;
14699         GC_NOTRIGGER;
14700     } CONTRACTL_END;
14701
14702     while (cbCode > 0)
14703     {
14704         PT_RUNTIME_FUNCTION   pFunctionEntry;
14705         ULONGLONG           uImageBase;
14706 #ifdef TARGET_UNIX
14707         EECodeInfo codeInfo;
14708         codeInfo.Init((PCODE)pvFuncletStart);
14709         pFunctionEntry = codeInfo.GetFunctionEntry();
14710         uImageBase = (ULONGLONG)codeInfo.GetModuleBase();
14711 #else // !TARGET_UNIX
14712         //
14713         // This is GCStress debug only - use the slow OS APIs to enumerate funclets
14714         //
14715
14716         pFunctionEntry = (PT_RUNTIME_FUNCTION) RtlLookupFunctionEntry((ULONGLONG)pvFuncletStart,
14717                               &uImageBase
14718                               AMD64_ARG(NULL)
14719                               );
14720 #endif
14721
14722         if (pFunctionEntry != NULL)
14723         {
14724
14725             _ASSERTE((TADDR)pvFuncletStart == (TADDR)uImageBase + pFunctionEntry->BeginAddress);
14726             _ASSERTE((TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart + cbCode);
14727             *ppvFuncletEnd = (LPVOID)(uImageBase + pFunctionEntry->EndAddress);
14728             return (LPVOID)(uImageBase + pFunctionEntry->BeginAddress);
14729         }
14730
14731         pvFuncletStart = (LPVOID)((TADDR)pvFuncletStart + 1);
14732         cbCode--;
14733     }
14734
14735     return NULL;
14736 }
14737 #endif // defined(_DEBUG) && !defined(HAVE_GCCOVER)
14738 #endif // defined(TARGET_AMD64)