1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // ===========================================================================
5 // File: JITinterface.CPP
8 // ===========================================================================
12 #include "jitinterface.h"
19 #include "virtualcallstub.h"
25 #include "float.h" // for isnan
26 #include "dbginterface.h"
27 #include "dllimport.h"
28 #include "gcheaputilities.h"
29 #include "comdelegate.h"
30 #include "jitperf.h" // to track jit perf
32 #include "eeprofinterfaces.h"
33 #include "perfcounters.h"
34 #ifdef PROFILING_SUPPORTED
35 #include "proftoeeinterfaceimpl.h"
36 #include "eetoprofinterfaceimpl.h"
37 #include "eetoprofinterfaceimpl.inl"
38 #include "profilepriv.h"
42 #include "typestring.h"
43 #include "stackprobe.h"
45 #include "genericdict.h"
47 #include "debuginfostore.h"
49 #include "runtimehandles.h"
50 #include "sigbuilder.h"
54 #endif // HAVE_GCCOVER
56 #include "mdaassistants.h"
60 #include "corcompile.h"
61 #endif // FEATURE_PREJIT
64 #ifdef FEATURE_INTERPRETER
65 #include "interpreter.h"
66 #endif // FEATURE_INTERPRETER
68 #ifdef FEATURE_PERFMAP
72 // The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro
75 #define JIT_TO_EE_TRANSITION() MAKE_CURRENT_THREAD_AVAILABLE_EX(m_pThread); \
76 _ASSERTE(CURRENT_THREAD == GetThread()); \
77 INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE; \
78 COOPERATIVE_TRANSITION_BEGIN(); \
81 #define EE_TO_JIT_TRANSITION() STOP_NON_JIT_PERF(); \
82 COOPERATIVE_TRANSITION_END(); \
83 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE;
85 #define JIT_TO_EE_TRANSITION_LEAF()
86 #define EE_TO_JIT_TRANSITION_LEAF()
89 #if defined(CROSSGEN_COMPILE)
90 static const char *const hlpNameTable[CORINFO_HELP_COUNT] = {
91 #define JITHELPER(code, pfnHelper, sig) #code,
92 #include "jithelpers.h"
96 #ifdef DACCESS_COMPILE
98 // The real definitions are in jithelpers.cpp. However, those files are not included in the DAC build.
99 // Hence, we add them here.
100 GARY_IMPL(VMHELPDEF, hlpFuncTable, CORINFO_HELP_COUNT);
101 GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);
103 #else // DACCESS_COMPILE
105 /*********************************************************************/
107 #if defined(ENABLE_PERF_COUNTERS)
108 LARGE_INTEGER g_lastTimeInJitCompilation;
111 /*********************************************************************/
113 inline CORINFO_MODULE_HANDLE GetScopeHandle(MethodDesc* method)
115 LIMITED_METHOD_CONTRACT;
116 if (method->IsDynamicMethod())
118 return MakeDynamicScope(method->AsDynamicMethodDesc()->GetResolver());
122 return GetScopeHandle(method->GetModule());
126 //This is common refactored code from within several of the access check functions.
127 BOOL ModifyCheckForDynamicMethod(DynamicResolver *pResolver,
128 TypeHandle *pOwnerTypeForSecurity,
129 AccessCheckOptions::AccessCheckType *pAccessCheckType,
130 DynamicResolver** ppAccessContext)
134 PRECONDITION(CheckPointer(pResolver));
135 PRECONDITION(CheckPointer(pOwnerTypeForSecurity));
136 PRECONDITION(CheckPointer(pAccessCheckType));
137 PRECONDITION(CheckPointer(ppAccessContext));
138 PRECONDITION(*pAccessCheckType == AccessCheckOptions::kNormalAccessibilityChecks);
141 BOOL doAccessCheck = TRUE;
143 //Do not blindly initialize fields, since they've already got important values.
144 DynamicResolver::SecurityControlFlags dwSecurityFlags = DynamicResolver::Default;
146 TypeHandle dynamicOwner;
147 pResolver->GetJitContext(&dwSecurityFlags, &dynamicOwner);
148 if (!dynamicOwner.IsNull())
149 *pOwnerTypeForSecurity = dynamicOwner;
151 if (dwSecurityFlags & DynamicResolver::SkipVisibilityChecks)
153 doAccessCheck = FALSE;
155 else if (dwSecurityFlags & DynamicResolver::RestrictedSkipVisibilityChecks)
157 *pAccessCheckType = AccessCheckOptions::kRestrictedMemberAccessNoTransparency;
161 *pAccessCheckType = AccessCheckOptions::kNormalAccessNoTransparency;
164 return doAccessCheck;
167 /*****************************************************************************/
169 // Initialize from data we passed across to the JIT
170 inline static void GetTypeContext(const CORINFO_SIG_INST *info, SigTypeContext *pTypeContext)
172 LIMITED_METHOD_CONTRACT;
173 SigTypeContext::InitTypeContext(
174 Instantiation((TypeHandle *) info->classInst, info->classInstCount),
175 Instantiation((TypeHandle *) info->methInst, info->methInstCount),
179 static MethodDesc* GetMethodFromContext(CORINFO_CONTEXT_HANDLE context)
181 LIMITED_METHOD_CONTRACT;
182 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
188 return GetMethod((CORINFO_METHOD_HANDLE)((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
192 static TypeHandle GetTypeFromContext(CORINFO_CONTEXT_HANDLE context)
194 LIMITED_METHOD_CONTRACT;
195 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
197 return TypeHandle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
201 MethodTable * pMT = GetMethodFromContext(context)->GetMethodTable();
202 return TypeHandle(pMT);
206 // Initialize from a context parameter passed to the JIT and back. This is a parameter
207 // that indicates which method is being jitted.
209 inline static void GetTypeContext(CORINFO_CONTEXT_HANDLE context, SigTypeContext *pTypeContext)
217 PRECONDITION(context != NULL);
220 if (GetMethodFromContext(context))
222 SigTypeContext::InitTypeContext(GetMethodFromContext(context), pTypeContext);
226 SigTypeContext::InitTypeContext(GetTypeFromContext(context), pTypeContext);
230 static BOOL ContextIsShared(CORINFO_CONTEXT_HANDLE context)
232 LIMITED_METHOD_CONTRACT;
233 MethodDesc *pContextMD = GetMethodFromContext(context);
234 if (pContextMD != NULL)
236 return pContextMD->IsSharedByGenericInstantiations();
240 // Type handle contexts are non-shared and are used for inlining of
241 // non-generic methods in generic classes
246 // Returns true if context is providing any generic variables
247 static BOOL ContextIsInstantiated(CORINFO_CONTEXT_HANDLE context)
249 LIMITED_METHOD_CONTRACT;
250 if (GetMethodFromContext(context))
252 return GetMethodFromContext(context)->HasClassOrMethodInstantiation();
256 return GetTypeFromContext(context).HasInstantiation();
260 /*********************************************************************/
261 // This normalizes EE type information into the form expected by the JIT.
263 // If typeHnd contains exact type information, then *clsRet will contain
264 // the normalized CORINFO_CLASS_HANDLE information on return.
267 CorInfoType CEEInfo::asCorInfoType(CorElementType eeType,
268 TypeHandle typeHnd, /* optional in */
269 CORINFO_CLASS_HANDLE *clsRet/* optional out */ ) {
270 CONTRACT(CorInfoType) {
273 PRECONDITION((CorTypeInfo::IsGenericVariable(eeType)) ==
274 (!typeHnd.IsNull() && typeHnd.IsGenericVariable()));
275 PRECONDITION(eeType != ELEMENT_TYPE_GENERICINST);
278 TypeHandle typeHndUpdated = typeHnd;
280 if (!typeHnd.IsNull())
282 CorElementType normType = typeHnd.GetInternalCorElementType();
283 // If we have a type handle, then it has the better type
285 if (eeType == ELEMENT_TYPE_VALUETYPE && !CorTypeInfo::IsObjRef(normType))
288 // Zap the typeHnd when the type _really_ is a primitive
289 // as far as verification is concerned. Returning a null class
290 // handle means it is is a primitive.
292 // Enums are exactly like primitives, even from a verification standpoint,
293 // so we zap the type handle in this case.
295 // However RuntimeTypeHandle etc. are reported as E_T_INT (or something like that)
296 // but don't count as primitives as far as verification is concerned...
298 // To make things stranger, TypedReference returns true for "IsTruePrimitive".
299 // However the JIT likes us to report the type handle in that case.
300 if (!typeHnd.IsTypeDesc() && (
301 (typeHnd.AsMethodTable()->IsTruePrimitive() && typeHnd != TypeHandle(g_TypedReferenceMT))
302 || typeHnd.AsMethodTable()->IsEnum()) )
304 typeHndUpdated = TypeHandle();
309 static const BYTE map[] = {
325 CORINFO_TYPE_PTR, // PTR
327 CORINFO_TYPE_VALUECLASS,
329 CORINFO_TYPE_VAR, // VAR (type variable)
330 CORINFO_TYPE_CLASS, // ARRAY
331 CORINFO_TYPE_CLASS, // WITH
333 CORINFO_TYPE_UNDEF, // VALUEARRAY_UNSUPPORTED
334 CORINFO_TYPE_NATIVEINT, // I
335 CORINFO_TYPE_NATIVEUINT, // U
336 CORINFO_TYPE_UNDEF, // R_UNSUPPORTED
338 // put the correct type when we know our implementation
339 CORINFO_TYPE_PTR, // FNPTR
340 CORINFO_TYPE_CLASS, // OBJECT
341 CORINFO_TYPE_CLASS, // SZARRAY
342 CORINFO_TYPE_VAR, // MVAR
344 CORINFO_TYPE_UNDEF, // CMOD_REQD
345 CORINFO_TYPE_UNDEF, // CMOD_OPT
346 CORINFO_TYPE_UNDEF, // INTERNAL
349 _ASSERTE(sizeof(map) == ELEMENT_TYPE_MAX);
350 _ASSERTE(eeType < (CorElementType) sizeof(map));
351 // spot check of the map
352 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_I4] == CORINFO_TYPE_INT);
353 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_PTR] == CORINFO_TYPE_PTR);
354 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_TYPEDBYREF] == CORINFO_TYPE_REFANY);
356 CorInfoType res = ((unsigned)eeType < ELEMENT_TYPE_MAX) ? ((CorInfoType) map[(unsigned)eeType]) : CORINFO_TYPE_UNDEF;
359 *clsRet = CORINFO_CLASS_HANDLE(typeHndUpdated.AsPtr());
365 inline static CorInfoType toJitType(TypeHandle typeHnd, CORINFO_CLASS_HANDLE *clsRet = NULL)
368 return CEEInfo::asCorInfoType(typeHnd.GetInternalCorElementType(), typeHnd, clsRet);
371 void CheckForEquivalenceAndLoadTypeBeforeCodeIsRun(Module *pModule, mdToken token, Module *pDefModule, mdToken defToken, const SigParser *ptr, SigTypeContext *pTypeContext, void *pData)
381 if (IsTypeDefEquivalent(defToken, pDefModule))
383 SigPointer sigPtr(*ptr);
384 TypeHandle th = sigPtr.GetTypeHandleThrowing(pModule, pTypeContext);
385 ((ICorDynamicInfo *)pData)->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(th.AsPtr()));
389 inline static void TypeEquivalenceFixupSpecificationHelper(ICorDynamicInfo * pCorInfo, MethodDesc *pMD)
391 STANDARD_VM_CONTRACT;
393 // A fixup is necessary to ensure that the parameters to the method are loaded before the method
394 // is called. In these cases we will not perform the appropriate loading when we load parameter
395 // types because with type equivalence, the parameter types at the call site do not necessarily
396 // match that those in the actual function. (They must be equivalent, but not necessarily the same.)
397 // In non-ngen scenarios this code here will force the types to be loaded directly by the call to
398 // HasTypeEquivalentStructParameters.
399 if (!pMD->IsVirtual())
401 if (pMD->HasTypeEquivalentStructParameters())
403 if (IsCompilationProcess())
404 pMD->WalkValueTypeParameters(pMD->GetMethodTable(), CheckForEquivalenceAndLoadTypeBeforeCodeIsRun, pCorInfo);
409 if (pMD->GetMethodTable()->DependsOnEquivalentOrForwardedStructs())
411 if (pMD->HasTypeEquivalentStructParameters())
412 pCorInfo->classMustBeLoadedBeforeCodeIsRun((CORINFO_CLASS_HANDLE)pMD->GetMethodTable());
417 //---------------------------------------------------------------------------------------
420 // The method handle is used to instantiate method and class type parameters
421 // It's also used to determine whether an extra dictionary parameter is required
423 // sig - Input metadata signature
424 // scopeHnd - The signature is to be interpreted in the context of this scope (module)
425 // token - Metadata token used to refer to the signature (may be mdTokenNil for dynamic methods)
426 // sigRet - Resulting output signature in a format that is understood by native compilers
427 // pContextMD - The method with any instantiation information (may be NULL)
428 // localSig - Is it a local variables declaration, or a method signature (with return type, etc).
429 // contextType - The type with any instantiaton information
433 CEEInfo::ConvToJitSig(
434 PCCOR_SIGNATURE pSig,
436 CORINFO_MODULE_HANDLE scopeHnd,
438 CORINFO_SIG_INFO * sigRet,
439 MethodDesc * pContextMD,
441 TypeHandle contextType)
448 SigTypeContext typeContext;
452 SigTypeContext::InitTypeContext(pContextMD, contextType, &typeContext);
456 SigTypeContext::InitTypeContext(contextType, &typeContext);
459 _ASSERTE(CORINFO_CALLCONV_DEFAULT == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_DEFAULT);
460 _ASSERTE(CORINFO_CALLCONV_VARARG == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_VARARG);
461 _ASSERTE(CORINFO_CALLCONV_MASK == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_MASK);
462 _ASSERTE(CORINFO_CALLCONV_HASTHIS == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_HASTHIS);
464 TypeHandle typeHnd = TypeHandle();
467 sigRet->cbSig = cbSig;
468 sigRet->retTypeClass = 0;
469 sigRet->retTypeSigClass = 0;
470 sigRet->scope = scopeHnd;
471 sigRet->token = token;
472 sigRet->sigInst.classInst = (CORINFO_CLASS_HANDLE *) typeContext.m_classInst.GetRawArgs();
473 sigRet->sigInst.classInstCount = (unsigned) typeContext.m_classInst.GetNumArgs();
474 sigRet->sigInst.methInst = (CORINFO_CLASS_HANDLE *) typeContext.m_methodInst.GetRawArgs();
475 sigRet->sigInst.methInstCount = (unsigned) typeContext.m_methodInst.GetNumArgs();
477 SigPointer sig(pSig, cbSig);
481 // This is a method signature which includes calling convention, return type,
484 _ASSERTE(!sig.IsNull());
485 Module * module = GetModule(scopeHnd);
489 IfFailThrow(sig.GetCallingConvInfo(&data));
490 sigRet->callConv = (CorInfoCallConv) data;
493 if ((isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_VARARG)) ||
494 (isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_NATIVEVARARG)))
496 // This signature corresponds to a method that uses varargs, which are not supported.
497 COMPlusThrow(kInvalidProgramException, IDS_EE_VARARG_NOT_SUPPORTED);
499 #endif // PLATFORM_UNIX
501 // Skip number of type arguments
502 if (sigRet->callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
503 IfFailThrow(sig.GetData(NULL));
506 IfFailThrow(sig.GetData(&numArgs));
507 if (numArgs != (unsigned short) numArgs)
508 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
510 sigRet->numArgs = (unsigned short) numArgs;
512 CorElementType type = sig.PeekElemTypeClosed(module, &typeContext);
514 if (!CorTypeInfo::IsPrimitiveType(type))
516 typeHnd = sig.GetTypeHandleThrowing(module, &typeContext);
517 _ASSERTE(!typeHnd.IsNull());
519 // I believe it doesn't make any diff. if this is
520 // GetInternalCorElementType or GetSignatureCorElementType
521 type = typeHnd.GetSignatureCorElementType();
524 sigRet->retType = CEEInfo::asCorInfoType(type, typeHnd, &sigRet->retTypeClass);
525 sigRet->retTypeSigClass = CORINFO_CLASS_HANDLE(typeHnd.AsPtr());
527 IfFailThrow(sig.SkipExactlyOne()); // must to a skip so we skip any class tokens associated with the return type
528 _ASSERTE(sigRet->retType < CORINFO_TYPE_COUNT);
530 sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
534 // This is local variables declaration
536 sigRet->callConv = CORINFO_CALLCONV_DEFAULT;
537 sigRet->retType = CORINFO_TYPE_VOID;
538 sigRet->flags = CORINFO_SIGFLAG_IS_LOCAL_SIG;
543 IfFailThrow(sig.GetCallingConvInfo(&callConv));
544 if (callConv != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG)
546 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_CALLCONV_NOT_LOCAL_SIG);
550 IfFailThrow(sig.GetData(&numArgs));
552 if (numArgs != (unsigned short) numArgs)
553 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
555 sigRet->numArgs = (unsigned short) numArgs;
558 sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
561 _ASSERTE(SigInfoFlagsAreValid(sigRet));
562 } // CEEInfo::ConvToJitSig
564 //---------------------------------------------------------------------------------------
566 CORINFO_CLASS_HANDLE CEEInfo::getTokenTypeAsHandle (CORINFO_RESOLVED_TOKEN * pResolvedToken)
575 CORINFO_CLASS_HANDLE tokenType = NULL;
577 JIT_TO_EE_TRANSITION();
579 _ASSERTE((pResolvedToken->hMethod == NULL) || (pResolvedToken->hField == NULL));
581 BinderClassID classID = CLASS__TYPE_HANDLE;
583 if (pResolvedToken->hMethod != NULL)
585 classID = CLASS__METHOD_HANDLE;
588 if (pResolvedToken->hField != NULL)
590 classID = CLASS__FIELD_HANDLE;
593 tokenType = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(classID));
595 EE_TO_JIT_TRANSITION();
600 /*********************************************************************/
601 size_t CEEInfo::findNameOfToken (
602 CORINFO_MODULE_HANDLE scopeHnd,
604 __out_ecount (FQNameCapacity) char * szFQName,
605 size_t FQNameCapacity)
616 JIT_TO_EE_TRANSITION();
618 if (IsDynamicScope(scopeHnd))
620 strncpy_s (szFQName, FQNameCapacity, "DynamicToken", FQNameCapacity - 1);
621 NameLen = strlen (szFQName);
625 Module* module = (Module *)scopeHnd;
626 NameLen = findNameOfToken(module, metaTOK, szFQName, FQNameCapacity);
629 EE_TO_JIT_TRANSITION();
634 CorInfoCanSkipVerificationResult CEEInfo::canSkipMethodVerification(CORINFO_METHOD_HANDLE ftnHnd)
643 return CORINFO_VERIFICATION_CAN_SKIP;
646 /*********************************************************************/
647 BOOL CEEInfo::shouldEnforceCallvirtRestriction(
648 CORINFO_MODULE_HANDLE scopeHnd)
650 LIMITED_METHOD_CONTRACT;
654 #ifdef FEATURE_READYTORUN_COMPILER
656 // Returns true if assemblies are in the same version bubble
657 // Right now each assembly is in its own version bubble.
658 // If the need arises (i.e. performance issues) we will define sets of assemblies (e.g. all app assemblies)
659 // The main point is that all this logic is concentrated in one place.
661 // NOTICE: If you change this logic to allow multi-assembly version bubbles you
662 // need to consider the impact on diagnostic tools. Currently there is an inlining
663 // table which tracks inliner/inlinee relationships in R2R images but it is not
664 // yet capable of encoding cross-assembly inlines. The scenario where this
665 // may show are instrumenting profilers that want to instrument a given method A
666 // using the ReJit APIs. If method A happens to inlined within method B in another
667 // assembly then the profiler needs to know that so it can rejit B too.
668 // The recommended approach is to upgrade the inlining table (vm\inlinetracking.h\.cpp)
669 // now that presumably R2R images have some way to refer to methods in other
670 // assemblies in their version bubble. Chat with the diagnostics team if you need more
673 // There already is a case where cross-assembly inlining occurs in an
674 // unreported fashion for methods marked NonVersionable. There is a specific
675 // exemption called out for this on ICorProfilerInfo6::EnumNgenModuleMethodsInliningThisMethod
676 // and the impact of the cut was vetted with partners. It would not be appropriate
677 // to increase that unreported set without additional review.
680 bool IsInSameVersionBubble(Assembly * current, Assembly * target)
682 LIMITED_METHOD_CONTRACT;
684 // trivial case: current and target are identical
685 // DO NOT change this without reading the notice above
686 if (current == target)
692 // Returns true if the assemblies defining current and target are in the same version bubble
693 static bool IsInSameVersionBubble(MethodDesc* pCurMD, MethodDesc *pTargetMD)
695 LIMITED_METHOD_CONTRACT;
696 // DO NOT change this without reading the notice above
697 if (IsInSameVersionBubble(pCurMD->GetModule()->GetAssembly(),
698 pTargetMD->GetModule()->GetAssembly()))
702 if (IsReadyToRunCompilation())
704 if (pTargetMD->GetModule()->GetMDImport()->GetCustomAttributeByName(pTargetMD->GetMemberDef(),
705 NONVERSIONABLE_TYPE, NULL, NULL) == S_OK)
714 #endif // FEATURE_READYTORUN_COMPILER
716 static bool CallerAndCalleeInSystemVersionBubble(MethodDesc* pCaller, MethodDesc* pCallee)
718 LIMITED_METHOD_CONTRACT;
720 #ifdef FEATURE_READYTORUN_COMPILER
721 if (IsReadyToRunCompilation())
722 return pCallee->GetModule()->IsSystem() && IsInSameVersionBubble(pCaller, pCallee);
729 /*********************************************************************/
730 CorInfoCanSkipVerificationResult CEEInfo::canSkipVerification(
731 CORINFO_MODULE_HANDLE moduleHnd)
740 return CORINFO_VERIFICATION_CAN_SKIP;
743 /*********************************************************************/
744 // Checks if the given metadata token is valid
745 BOOL CEEInfo::isValidToken (
746 CORINFO_MODULE_HANDLE module,
758 JIT_TO_EE_TRANSITION_LEAF();
760 if (IsDynamicScope(module))
762 // No explicit token validation for dynamic code. Validation is
763 // side-effect of token resolution.
768 result = ((Module *)module)->GetMDImport()->IsValidToken(metaTOK);
771 EE_TO_JIT_TRANSITION_LEAF();
776 /*********************************************************************/
777 // Checks if the given metadata token is valid StringRef
778 BOOL CEEInfo::isValidStringRef (
779 CORINFO_MODULE_HANDLE module,
791 JIT_TO_EE_TRANSITION();
793 if (IsDynamicScope(module))
795 result = GetDynamicResolver(module)->IsValidStringRef(metaTOK);
799 result = ((Module *)module)->CheckStringRef(metaTOK);
804 result = (!FAILED(((Module *)module)->GetMDImport()->GetUserString(metaTOK, &dwCharCount, NULL, &pString)) &&
809 EE_TO_JIT_TRANSITION();
815 size_t CEEInfo::findNameOfToken (Module* module,
817 __out_ecount (FQNameCapacity) char * szFQName,
818 size_t FQNameCapacity)
826 PCCOR_SIGNATURE sig = NULL;
828 LPCUTF8 pszNamespace = NULL;
829 LPCUTF8 pszClassName = NULL;
831 mdToken tokType = TypeFromToken(metaTOK);
836 if (FAILED(module->GetMDImport()->GetNameOfTypeRef(metaTOK, &pszNamespace, &pszClassName)))
838 pszNamespace = pszClassName = "Invalid TypeRef record";
840 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
845 if (FAILED(module->GetMDImport()->GetNameOfTypeDef(metaTOK, &pszClassName, &pszNamespace)))
847 pszClassName = pszNamespace = "Invalid TypeDef record";
849 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
855 if (FAILED(module->GetMDImport()->GetNameOfFieldDef(metaTOK, &szFieldName)))
857 szFieldName = "Invalid FieldDef record";
859 strncpy_s(szFQName, FQNameCapacity, (char*)szFieldName, FQNameCapacity - 1);
865 if (FAILED(module->GetMDImport()->GetNameOfMethodDef(metaTOK, &szMethodName)))
867 szMethodName = "Invalid MethodDef record";
869 strncpy_s(szFQName, FQNameCapacity, (char*)szMethodName, FQNameCapacity - 1);
875 if (FAILED(module->GetMDImport()->GetNameAndSigOfMemberRef((mdMemberRef)metaTOK, &sig, &cSig, &szName)))
877 szName = "Invalid MemberRef record";
879 strncpy_s(szFQName, FQNameCapacity, (char *)szName, FQNameCapacity - 1);
883 sprintf_s(szFQName, FQNameCapacity, "!TK_%x", metaTOK);
888 strncpy_s (szFQName, FQNameCapacity, "<UNKNOWN>", FQNameCapacity - 1);
892 return strlen (szFQName);
895 CorInfoHelpFunc CEEInfo::getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle)
904 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
906 JIT_TO_EE_TRANSITION_LEAF();
908 result = IsDynamicScope(handle) ? CORINFO_HELP_UNDEF : CORINFO_HELP_STRCNS;
910 EE_TO_JIT_TRANSITION_LEAF();
916 CHECK CheckContext(CORINFO_MODULE_HANDLE scopeHnd, CORINFO_CONTEXT_HANDLE context)
918 CHECK_MSG(scopeHnd != NULL, "Illegal null scope");
919 CHECK_MSG(((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK) != NULL, "Illegal null context");
920 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
922 TypeHandle handle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
923 CHECK_MSG(handle.GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
927 MethodDesc* handle = (MethodDesc*) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK);
928 CHECK_MSG(handle->GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
935 static DECLSPEC_NORETURN void ThrowBadTokenException(CORINFO_RESOLVED_TOKEN * pResolvedToken)
937 switch (pResolvedToken->tokenType & CORINFO_TOKENKIND_Mask)
939 case CORINFO_TOKENKIND_Class:
940 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_CLASS_TOKEN);
941 case CORINFO_TOKENKIND_Method:
942 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN);
943 case CORINFO_TOKENKIND_Field:
944 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN);
946 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
950 /*********************************************************************/
951 void CEEInfo::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken)
960 JIT_TO_EE_TRANSITION();
962 _ASSERTE(CheckContext(pResolvedToken->tokenScope, pResolvedToken->tokenContext));
964 pResolvedToken->pTypeSpec = NULL;
965 pResolvedToken->cbTypeSpec = NULL;
966 pResolvedToken->pMethodSpec = NULL;
967 pResolvedToken->cbMethodSpec = NULL;
970 MethodDesc * pMD = NULL;
971 FieldDesc * pFD = NULL;
973 CorInfoTokenKind tokenType = pResolvedToken->tokenType;
975 if (IsDynamicScope(pResolvedToken->tokenScope))
977 GetDynamicResolver(pResolvedToken->tokenScope)->ResolveToken(pResolvedToken->token, &th, &pMD, &pFD);
980 // Check that we got the expected handles and fill in missing data if necessary
983 CorTokenType tkType = (CorTokenType)TypeFromToken(pResolvedToken->token);
987 if ((tkType != mdtMethodDef) && (tkType != mdtMemberRef))
988 ThrowBadTokenException(pResolvedToken);
989 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
990 ThrowBadTokenException(pResolvedToken);
992 th = pMD->GetMethodTable();
994 // "PermitUninstDefOrRef" check
995 if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && pMD->ContainsGenericVariables())
997 COMPlusThrow(kInvalidProgramException);
1000 // if this is a BoxedEntryPointStub get the UnboxedEntryPoint one
1001 if (pMD->IsUnboxingStub())
1003 pMD = pMD->GetMethodTable()->GetUnboxedEntryPointMD(pMD);
1006 // Activate target if required
1007 if (tokenType != CORINFO_TOKENKIND_Ldtoken)
1009 ScanTokenForDynamicScope(pResolvedToken, th, pMD);
1015 if ((tkType != mdtFieldDef) && (tkType != mdtMemberRef))
1016 ThrowBadTokenException(pResolvedToken);
1017 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1018 ThrowBadTokenException(pResolvedToken);
1020 th = pFD->GetApproxEnclosingMethodTable();
1022 if (pFD->IsStatic() && (tokenType != CORINFO_TOKENKIND_Ldtoken))
1024 ScanTokenForDynamicScope(pResolvedToken, th);
1029 if ((tkType != mdtTypeDef) && (tkType != mdtTypeRef))
1030 ThrowBadTokenException(pResolvedToken);
1031 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1032 ThrowBadTokenException(pResolvedToken);
1034 ThrowBadTokenException(pResolvedToken);
1036 if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained)
1038 ScanTokenForDynamicScope(pResolvedToken, th);
1042 _ASSERTE((pMD == NULL) || (pFD == NULL));
1043 _ASSERTE(!th.IsNull());
1045 // "PermitUninstDefOrRef" check
1046 if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && th.ContainsGenericVariables())
1048 COMPlusThrow(kInvalidProgramException);
1051 // The JIT always wants to see normalized typedescs for arrays
1052 if (!th.IsTypeDesc() && th.AsMethodTable()->IsArray())
1054 MethodTable * pMT = th.AsMethodTable();
1056 // Load the TypeDesc for the array type.
1057 DWORD rank = pMT->GetRank();
1058 TypeHandle elemType = pMT->GetApproxArrayElementTypeHandle();
1059 th = ClassLoader::LoadArrayTypeThrowing(elemType, pMT->GetInternalCorElementType(), rank);
1064 unsigned metaTOK = pResolvedToken->token;
1065 Module * pModule = (Module *)pResolvedToken->tokenScope;
1067 switch (TypeFromToken(metaTOK))
1070 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1071 ThrowBadTokenException(pResolvedToken);
1074 DomainFile *pTargetModule = pModule->LoadModule(GetAppDomain(), metaTOK, FALSE /* loadResources */);
1075 if (pTargetModule == NULL)
1076 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1077 th = TypeHandle(pTargetModule->GetModule()->GetGlobalMethodTable());
1079 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1085 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1086 ThrowBadTokenException(pResolvedToken);
1088 th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, metaTOK,
1089 ClassLoader::ThrowIfNotFound,
1090 (tokenType == CORINFO_TOKENKIND_Ldtoken) ?
1091 ClassLoader::PermitUninstDefOrRef : ClassLoader::FailIfUninstDefOrRef);
1096 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1097 ThrowBadTokenException(pResolvedToken);
1099 IfFailThrow(pModule->GetMDImport()->GetTypeSpecFromToken(metaTOK, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec));
1101 SigTypeContext typeContext;
1102 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1104 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1105 th = sigptr.GetTypeHandleThrowing(pModule, &typeContext);
1110 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1111 ThrowBadTokenException(pResolvedToken);
1113 pMD = MemberLoader::GetMethodDescFromMethodDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1115 th = pMD->GetMethodTable();
1119 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1120 ThrowBadTokenException(pResolvedToken);
1122 pFD = MemberLoader::GetFieldDescFromFieldDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1124 th = pFD->GetEnclosingMethodTable();
1129 SigTypeContext typeContext;
1130 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1132 MemberLoader::GetDescFromMemberRef(pModule, metaTOK, &pMD, &pFD, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken),
1133 &th, TRUE, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec);
1135 _ASSERTE((pMD != NULL) ^ (pFD != NULL));
1136 _ASSERTE(!th.IsNull());
1140 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1141 ThrowBadTokenException(pResolvedToken);
1145 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1146 ThrowBadTokenException(pResolvedToken);
1153 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1154 ThrowBadTokenException(pResolvedToken);
1156 SigTypeContext typeContext;
1157 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1159 // We need the method desc to carry exact instantiation, thus allowInstParam == FALSE.
1160 pMD = MemberLoader::GetMethodDescFromMethodSpec(pModule, metaTOK, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken), FALSE /* allowInstParam */,
1161 &th, TRUE, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec, &pResolvedToken->pMethodSpec, &pResolvedToken->cbMethodSpec);
1166 ThrowBadTokenException(pResolvedToken);
1170 // Module dependency tracking
1174 ScanToken(pModule, pResolvedToken, th, pMD);
1179 if (pFD->IsStatic())
1180 ScanToken(pModule, pResolvedToken, th);
1184 // It should not be required to trigger the modules cctors for ldtoken, it is done for backward compatibility only.
1185 if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained || tokenType == CORINFO_TOKENKIND_Ldtoken)
1186 ScanToken(pModule, pResolvedToken, th);
1191 // tokenType specific verification and transformations
1193 CorElementType et = th.GetInternalCorElementType();
1196 case CORINFO_TOKENKIND_Ldtoken:
1197 // Allow everything.
1200 case CORINFO_TOKENKIND_Newarr:
1201 // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1202 if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1203 COMPlusThrow(kInvalidProgramException);
1205 th = ClassLoader::LoadArrayTypeThrowing(th);
1209 // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1210 if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1211 COMPlusThrow(kInvalidProgramException);
1215 // The JIT interface should always return fully loaded types
1216 _ASSERTE(th.IsFullyLoaded());
1218 pResolvedToken->hClass = CORINFO_CLASS_HANDLE(th.AsPtr());
1219 pResolvedToken->hMethod = CORINFO_METHOD_HANDLE(pMD);
1220 pResolvedToken->hField = CORINFO_FIELD_HANDLE(pFD);
1222 EE_TO_JIT_TRANSITION();
1225 /*********************************************************************/
1226 struct TryResolveTokenFilterParam
1229 CORINFO_RESOLVED_TOKEN* m_resolvedToken;
1230 EXCEPTION_POINTERS m_exceptionPointers;
1234 bool isValidTokenForTryResolveToken(CEEInfo* info, CORINFO_RESOLVED_TOKEN* resolvedToken)
1243 if (!info->isValidToken(resolvedToken->tokenScope, resolvedToken->token))
1248 CorInfoTokenKind tokenType = resolvedToken->tokenType;
1249 switch (TypeFromToken(resolvedToken->token))
1255 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1261 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1266 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1271 if ((tokenType & (CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field)) == 0)
1282 LONG EEFilterException(struct _EXCEPTION_POINTERS* exceptionPointers, void* unused);
1284 LONG TryResolveTokenFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
1293 // Backward compatibility: Convert bad image format exceptions thrown while resolving tokens
1294 // to simple true/false successes. This is done for backward compatibility only. Ideally,
1295 // we would always treat bad tokens in the IL stream as fatal errors.
1296 if (exceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1298 auto* param = reinterpret_cast<TryResolveTokenFilterParam*>(theParam);
1299 if (!isValidTokenForTryResolveToken(param->m_this, param->m_resolvedToken))
1301 param->m_exceptionPointers = *exceptionPointers;
1302 return EEFilterException(exceptionPointers, nullptr);
1306 return EXCEPTION_CONTINUE_SEARCH;
1309 bool CEEInfo::tryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
1311 // No dynamic contract here because SEH is used
1312 STATIC_CONTRACT_SO_TOLERANT;
1313 STATIC_CONTRACT_THROWS;
1314 STATIC_CONTRACT_GC_TRIGGERS;
1315 STATIC_CONTRACT_MODE_PREEMPTIVE;
1317 TryResolveTokenFilterParam param;
1318 param.m_this = this;
1319 param.m_resolvedToken = resolvedToken;
1320 param.m_success = true;
1322 PAL_TRY(TryResolveTokenFilterParam*, pParam, ¶m)
1324 pParam->m_this->resolveToken(pParam->m_resolvedToken);
1326 PAL_EXCEPT_FILTER(TryResolveTokenFilter)
1328 if (param.m_exceptionPointers.ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1330 HandleException(¶m.m_exceptionPointers);
1333 param.m_success = false;
1337 return param.m_success;
1340 /*********************************************************************/
1341 // We have a few frequently used constants in mscorlib that are defined as
1342 // readonly static fields for historic reasons. Check for them here and
1343 // allow them to be treated as actual constants by the JIT.
1344 static CORINFO_FIELD_ACCESSOR getFieldIntrinsic(FieldDesc * field)
1346 STANDARD_VM_CONTRACT;
1348 if (MscorlibBinder::GetField(FIELD__STRING__EMPTY) == field)
1350 return CORINFO_FIELD_INTRINSIC_EMPTY_STRING;
1353 if ((MscorlibBinder::GetField(FIELD__INTPTR__ZERO) == field) ||
1354 (MscorlibBinder::GetField(FIELD__UINTPTR__ZERO) == field))
1356 return CORINFO_FIELD_INTRINSIC_ZERO;
1359 if (MscorlibBinder::GetField(FIELD__BITCONVERTER__ISLITTLEENDIAN) == field)
1361 return CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN;
1364 return (CORINFO_FIELD_ACCESSOR)-1;
1367 static CorInfoHelpFunc getGenericStaticsHelper(FieldDesc * pField)
1369 STANDARD_VM_CONTRACT;
1371 int helper = CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE;
1373 if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1374 pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1376 helper = CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1379 if (pField->IsThreadStatic())
1381 const int delta = CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1383 static_assert_no_msg(CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE
1384 == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE + delta);
1386 helper += (CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE);
1389 return (CorInfoHelpFunc)helper;
1392 CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable * pFieldMT)
1394 STANDARD_VM_CONTRACT;
1396 int helper = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
1398 if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1399 pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1401 helper = CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1404 if (pFieldMT->IsDynamicStatics())
1406 const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1408 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS
1409 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1414 if (!pFieldMT->HasClassConstructor() && !pFieldMT->HasBoxedRegularStatics())
1416 const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1418 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR
1419 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1424 if (pField->IsThreadStatic())
1426 const int delta = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1428 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE
1429 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1430 static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR
1431 == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR + delta);
1432 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR
1433 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR + delta);
1434 static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS
1435 == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS + delta);
1436 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS
1437 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS + delta);
1442 return (CorInfoHelpFunc)helper;
1445 static CorInfoHelpFunc getInstanceFieldHelper(FieldDesc * pField, CORINFO_ACCESS_FLAGS flags)
1447 STANDARD_VM_CONTRACT;
1451 CorElementType type = pField->GetFieldType();
1453 if (CorTypeInfo::IsObjRef(type))
1454 helper = CORINFO_HELP_GETFIELDOBJ;
1458 case ELEMENT_TYPE_VALUETYPE:
1459 helper = CORINFO_HELP_GETFIELDSTRUCT;
1461 case ELEMENT_TYPE_I1:
1462 case ELEMENT_TYPE_BOOLEAN:
1463 case ELEMENT_TYPE_U1:
1464 helper = CORINFO_HELP_GETFIELD8;
1466 case ELEMENT_TYPE_I2:
1467 case ELEMENT_TYPE_CHAR:
1468 case ELEMENT_TYPE_U2:
1469 helper = CORINFO_HELP_GETFIELD16;
1471 case ELEMENT_TYPE_I4:
1472 case ELEMENT_TYPE_U4:
1473 IN_TARGET_32BIT(default:)
1474 helper = CORINFO_HELP_GETFIELD32;
1476 case ELEMENT_TYPE_I8:
1477 case ELEMENT_TYPE_U8:
1478 IN_TARGET_64BIT(default:)
1479 helper = CORINFO_HELP_GETFIELD64;
1481 case ELEMENT_TYPE_R4:
1482 helper = CORINFO_HELP_GETFIELDFLOAT;
1484 case ELEMENT_TYPE_R8:
1485 helper = CORINFO_HELP_GETFIELDDOUBLE;
1489 if (flags & CORINFO_ACCESS_SET)
1491 const int delta = CORINFO_HELP_SETFIELDOBJ - CORINFO_HELP_GETFIELDOBJ;
1493 static_assert_no_msg(CORINFO_HELP_SETFIELD8 == CORINFO_HELP_GETFIELD8 + delta);
1494 static_assert_no_msg(CORINFO_HELP_SETFIELD16 == CORINFO_HELP_GETFIELD16 + delta);
1495 static_assert_no_msg(CORINFO_HELP_SETFIELD32 == CORINFO_HELP_GETFIELD32 + delta);
1496 static_assert_no_msg(CORINFO_HELP_SETFIELD64 == CORINFO_HELP_GETFIELD64 + delta);
1497 static_assert_no_msg(CORINFO_HELP_SETFIELDSTRUCT == CORINFO_HELP_GETFIELDSTRUCT + delta);
1498 static_assert_no_msg(CORINFO_HELP_SETFIELDFLOAT == CORINFO_HELP_GETFIELDFLOAT + delta);
1499 static_assert_no_msg(CORINFO_HELP_SETFIELDDOUBLE == CORINFO_HELP_GETFIELDDOUBLE + delta);
1504 return (CorInfoHelpFunc)helper;
1507 /*********************************************************************/
1508 void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken,
1509 CORINFO_METHOD_HANDLE callerHandle,
1510 CORINFO_ACCESS_FLAGS flags,
1511 CORINFO_FIELD_INFO *pResult
1521 JIT_TO_EE_TRANSITION();
1523 _ASSERTE((flags & (CORINFO_ACCESS_GET | CORINFO_ACCESS_SET | CORINFO_ACCESS_ADDRESS | CORINFO_ACCESS_INIT_ARRAY)) != 0);
1525 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
1527 FieldDesc * pField = (FieldDesc*)pResolvedToken->hField;
1528 MethodTable * pFieldMT = pField->GetApproxEnclosingMethodTable();
1530 // Helper to use if the field access requires it
1531 CORINFO_FIELD_ACCESSOR fieldAccessor = (CORINFO_FIELD_ACCESSOR)-1;
1532 DWORD fieldFlags = 0;
1534 pResult->offset = pField->GetOffset();
1535 if (pField->IsStatic())
1537 fieldFlags |= CORINFO_FLG_FIELD_STATIC;
1539 if (pField->IsRVA())
1541 fieldFlags |= CORINFO_FLG_FIELD_UNMANAGED;
1543 Module* module = pFieldMT->GetModule();
1544 if (module->IsRvaFieldTls(pResult->offset))
1546 fieldAccessor = CORINFO_FIELD_STATIC_TLS;
1548 // Provide helper to use if the JIT is not able to emit the TLS access
1550 pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR_TLS;
1552 pResult->offset = module->GetFieldTlsOffset(pResult->offset);
1556 fieldAccessor = CORINFO_FIELD_STATIC_RVA_ADDRESS;
1559 // We are not going through a helper. The constructor has to be triggered explicitly.
1560 if (!pFieldMT->IsClassPreInited())
1561 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1565 // Regular or thread static
1566 CORINFO_FIELD_ACCESSOR intrinsicAccessor;
1568 if (pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1569 fieldFlags |= CORINFO_FLG_FIELD_STATIC_IN_HEAP;
1571 if (pFieldMT->IsSharedByGenericInstantiations())
1573 fieldAccessor = CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER;
1575 pResult->helper = getGenericStaticsHelper(pField);
1578 if (pFieldMT->GetModule()->IsSystem() && (flags & CORINFO_ACCESS_GET) &&
1579 (intrinsicAccessor = getFieldIntrinsic(pField)) != (CORINFO_FIELD_ACCESSOR)-1)
1582 fieldAccessor = intrinsicAccessor;
1585 if (// Domain neutral access.
1586 m_pMethodBeingCompiled->IsDomainNeutral() || m_pMethodBeingCompiled->IsZapped() || IsCompilingForNGen() ||
1587 // Static fields are not pinned in collectible types. We will always access
1588 // them using a helper since the address cannot be embeded into the code.
1589 pFieldMT->Collectible() ||
1590 // We always treat accessing thread statics as if we are in domain neutral code.
1591 pField->IsThreadStatic()
1594 fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
1596 pResult->helper = getSharedStaticsHelper(pField, pFieldMT);
1600 fieldAccessor = CORINFO_FIELD_STATIC_ADDRESS;
1602 // We are not going through a helper. The constructor has to be triggered explicitly.
1603 if (!pFieldMT->IsClassPreInited())
1604 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1609 // Currently, we only this optimization for regular statics, but it
1610 // looks like it may be permissible to do this optimization for
1611 // thread statics as well.
1613 if ((flags & CORINFO_ACCESS_ADDRESS) &&
1614 !pField->IsThreadStatic() &&
1615 (fieldAccessor != CORINFO_FIELD_STATIC_TLS))
1617 fieldFlags |= CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN;
1622 BOOL fInstanceHelper = FALSE;
1624 if (fInstanceHelper)
1626 if (flags & CORINFO_ACCESS_ADDRESS)
1628 fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1630 pResult->helper = CORINFO_HELP_GETFIELDADDR;
1634 fieldAccessor = CORINFO_FIELD_INSTANCE_HELPER;
1636 pResult->helper = getInstanceFieldHelper(pField, flags);
1640 if (pField->IsEnCNew())
1642 fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1644 pResult->helper = CORINFO_HELP_GETFIELDADDR;
1648 fieldAccessor = CORINFO_FIELD_INSTANCE;
1651 // FieldDesc::GetOffset() does not include the size of Object
1652 if (!pFieldMT->IsValueType())
1654 pResult->offset += OBJECT_SIZE;
1658 // TODO: This is touching metadata. Can we avoid it?
1659 DWORD fieldAttribs = pField->GetAttributes();
1661 if (IsFdFamily(fieldAttribs))
1662 fieldFlags |= CORINFO_FLG_FIELD_PROTECTED;
1664 if (IsFdInitOnly(fieldAttribs))
1665 fieldFlags |= CORINFO_FLG_FIELD_FINAL;
1667 pResult->fieldAccessor = fieldAccessor;
1668 pResult->fieldFlags = fieldFlags;
1670 if (!(flags & CORINFO_ACCESS_INLINECHECK))
1672 //get the field's type. Grab the class for structs.
1673 pResult->fieldType = getFieldTypeInternal(pResolvedToken->hField, &pResult->structType, pResolvedToken->hClass);
1676 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
1679 //Since we can't get the special verify-only instantiated FD like we can with MDs, go back to the parent
1680 //of the memberRef and load that one. That should give us the open instantiation.
1682 //If the field we found is owned by a generic type, you have to go back to the signature and reload.
1683 //Otherwise we filled in !0.
1684 TypeHandle fieldTypeForSecurity = TypeHandle(pResolvedToken->hClass);
1685 if (pResolvedToken->pTypeSpec != NULL)
1687 SigTypeContext typeContext;
1688 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
1690 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1691 fieldTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
1693 // typeHnd can be a variable type
1694 if (fieldTypeForSecurity.GetMethodTable() == NULL)
1696 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
1700 BOOL doAccessCheck = TRUE;
1701 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
1703 DynamicResolver * pAccessContext = NULL;
1705 //More in code:CEEInfo::getCallInfo, but the short version is that the caller and callee Descs do
1706 //not completely describe the type.
1707 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
1708 if (IsDynamicScope(pResolvedToken->tokenScope))
1710 doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope), &callerTypeForSecurity,
1711 &accessCheckType, &pAccessContext);
1714 //Now for some link time checks.
1715 //Um... where are the field link demands?
1717 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
1721 //Well, let's check some visibility at least.
1722 AccessCheckOptions accessCheckOptions(accessCheckType,
1727 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
1728 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
1730 BOOL canAccess = ClassLoader::CanAccess(
1732 fieldTypeForSecurity.GetMethodTable(),
1733 fieldTypeForSecurity.GetAssembly(),
1736 (flags & CORINFO_ACCESS_INIT_ARRAY) ? NULL : pField, // For InitializeArray, we don't need tocheck the type of the field.
1737 accessCheckOptions);
1741 //Set up the throw helper
1742 pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL;
1744 pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_EXCEPTION;
1745 pResult->accessCalloutHelper.numArgs = 2;
1747 pResult->accessCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
1748 pResult->accessCalloutHelper.args[1].Set(CORINFO_FIELD_HANDLE(pField));
1750 if (IsCompilingForNGen())
1752 //see code:CEEInfo::getCallInfo for more information.
1753 if (pCallerForSecurity->ContainsGenericVariables())
1754 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
1760 EE_TO_JIT_TRANSITION();
1763 //---------------------------------------------------------------------------------------
1765 bool CEEInfo::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd)
1775 JIT_TO_EE_TRANSITION_LEAF();
1776 FieldDesc* field = (FieldDesc*)fldHnd;
1777 res = (field->IsStatic() != 0);
1778 EE_TO_JIT_TRANSITION_LEAF();
1782 //---------------------------------------------------------------------------------------
1785 CEEInfo::findCallSiteSig(
1786 CORINFO_MODULE_HANDLE scopeHnd,
1787 unsigned sigMethTok,
1788 CORINFO_CONTEXT_HANDLE context,
1789 CORINFO_SIG_INFO * sigRet)
1798 JIT_TO_EE_TRANSITION();
1800 PCCOR_SIGNATURE pSig = NULL;
1803 if (IsDynamicScope(scopeHnd))
1805 DynamicResolver * pResolver = GetDynamicResolver(scopeHnd);
1808 if (TypeFromToken(sigMethTok) == mdtMemberRef)
1810 sig = pResolver->ResolveSignatureForVarArg(sigMethTok);
1814 _ASSERTE(TypeFromToken(sigMethTok) == mdtMethodDef);
1816 TypeHandle classHandle;
1817 MethodDesc * pMD = NULL;
1818 FieldDesc * pFD = NULL;
1820 // in this case a method is asked for its sig. Resolve the method token and get the sig
1821 pResolver->ResolveToken(sigMethTok, &classHandle, &pMD, &pFD);
1823 COMPlusThrow(kInvalidProgramException);
1825 PCCOR_SIGNATURE pSig = NULL;
1827 pMD->GetSig(&pSig, &cbSig);
1828 sig = SigPointer(pSig, cbSig);
1830 context = MAKE_METHODCONTEXT(pMD);
1831 scopeHnd = GetScopeHandle(pMD->GetModule());
1834 sig.GetSignature(&pSig, &cbSig);
1835 sigMethTok = mdTokenNil;
1839 Module * module = (Module *)scopeHnd;
1842 if (TypeFromToken(sigMethTok) == mdtMemberRef)
1844 IfFailThrow(module->GetMDImport()->GetNameAndSigOfMemberRef(sigMethTok, &pSig, &cbSig, &szName));
1846 else if (TypeFromToken(sigMethTok) == mdtMethodDef)
1848 IfFailThrow(module->GetMDImport()->GetSigOfMethodDef(sigMethTok, &cbSig, &pSig));
1852 CEEInfo::ConvToJitSig(
1858 GetMethodFromContext(context),
1860 GetTypeFromContext(context));
1861 EE_TO_JIT_TRANSITION();
1862 } // CEEInfo::findCallSiteSig
1864 //---------------------------------------------------------------------------------------
1868 CORINFO_MODULE_HANDLE scopeHnd,
1870 CORINFO_CONTEXT_HANDLE context,
1871 CORINFO_SIG_INFO * sigRet)
1880 JIT_TO_EE_TRANSITION();
1882 PCCOR_SIGNATURE pSig = NULL;
1885 if (IsDynamicScope(scopeHnd))
1887 SigPointer sig = GetDynamicResolver(scopeHnd)->ResolveSignature(sigTok);
1888 sig.GetSignature(&pSig, &cbSig);
1889 sigTok = mdTokenNil;
1893 Module * module = (Module *)scopeHnd;
1895 // We need to resolve this stand alone sig
1896 IfFailThrow(module->GetMDImport()->GetSigFromToken(
1897 (mdSignature)sigTok,
1902 CEEInfo::ConvToJitSig(
1908 GetMethodFromContext(context),
1910 GetTypeFromContext(context));
1912 EE_TO_JIT_TRANSITION();
1913 } // CEEInfo::findSig
1915 //---------------------------------------------------------------------------------------
1918 CEEInfo::getClassSize(
1919 CORINFO_CLASS_HANDLE clsHnd)
1928 unsigned result = 0;
1930 JIT_TO_EE_TRANSITION_LEAF();
1932 TypeHandle VMClsHnd(clsHnd);
1933 result = VMClsHnd.GetSize();
1935 EE_TO_JIT_TRANSITION_LEAF();
1940 //---------------------------------------------------------------------------------------
1942 // Get the size of a reference type as allocated on the heap. This includes the size of the fields
1943 // (and any padding between the fields) and the size of a method table pointer but doesn't include
1944 // object header size or any padding for minimum size.
1946 CEEInfo::getHeapClassSize(
1947 CORINFO_CLASS_HANDLE clsHnd)
1956 unsigned result = 0;
1958 JIT_TO_EE_TRANSITION_LEAF();
1960 TypeHandle VMClsHnd(clsHnd);
1961 MethodTable* pMT = VMClsHnd.GetMethodTable();
1963 _ASSERTE(!pMT->IsValueType());
1964 _ASSERTE(!pMT->HasComponentSize());
1965 #ifdef FEATURE_READYTORUN_COMPILER
1966 _ASSERTE(!IsReadyToRunCompilation() || pMT->IsInheritanceChainLayoutFixedInCurrentVersionBubble());
1969 // Add OBJECT_SIZE to account for method table pointer.
1970 result = pMT->GetNumInstanceFieldBytes() + OBJECT_SIZE;
1972 EE_TO_JIT_TRANSITION_LEAF();
1976 //---------------------------------------------------------------------------------------
1978 // Return TRUE if an object of this type can be allocated on the stack.
1979 BOOL CEEInfo::canAllocateOnStack(CORINFO_CLASS_HANDLE clsHnd)
1988 BOOL result = FALSE;
1990 JIT_TO_EE_TRANSITION_LEAF();
1992 TypeHandle VMClsHnd(clsHnd);
1993 MethodTable* pMT = VMClsHnd.GetMethodTable();
1995 _ASSERTE(!pMT->IsValueType());
1997 result = !pMT->HasFinalizer();
1999 #ifdef FEATURE_READYTORUN_COMPILER
2000 if (IsReadyToRunCompilation() && !pMT->IsInheritanceChainLayoutFixedInCurrentVersionBubble())
2006 EE_TO_JIT_TRANSITION_LEAF();
2010 unsigned CEEInfo::getClassAlignmentRequirement(CORINFO_CLASS_HANDLE type, BOOL fDoubleAlignHint)
2019 // Default alignment is sizeof(void*)
2020 unsigned result = TARGET_POINTER_SIZE;
2022 JIT_TO_EE_TRANSITION_LEAF();
2024 TypeHandle clsHnd(type);
2026 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
2027 if (fDoubleAlignHint)
2029 MethodTable* pMT = clsHnd.GetMethodTable();
2032 // Return the size of the double align hint. Ignore the actual alignment info account
2033 // so that structs with 64-bit integer fields do not trigger double aligned frames on x86.
2034 if (pMT->GetClass()->IsAlign8Candidate())
2041 result = getClassAlignmentRequirementStatic(clsHnd);
2044 EE_TO_JIT_TRANSITION_LEAF();
2049 unsigned CEEInfo::getClassAlignmentRequirementStatic(TypeHandle clsHnd)
2051 LIMITED_METHOD_CONTRACT;
2053 // Default alignment is sizeof(void*)
2054 unsigned result = TARGET_POINTER_SIZE;
2056 MethodTable * pMT = clsHnd.GetMethodTable();
2060 if (pMT->HasLayout())
2062 EEClassLayoutInfo* pInfo = pMT->GetLayoutInfo();
2064 if (clsHnd.IsNativeValueType())
2066 // if it's the unmanaged view of the managed type, we always use the unmanaged alignment requirement
2067 result = pInfo->m_LargestAlignmentRequirementOfAllMembers;
2070 if (pInfo->IsManagedSequential())
2072 _ASSERTE(!pMT->ContainsPointers());
2074 // if it's managed sequential, we use the managed alignment requirement
2075 result = pInfo->m_ManagedLargestAlignmentRequirementOfAllMembers;
2077 else if (pInfo->IsBlittable())
2079 _ASSERTE(!pMT->ContainsPointers());
2081 // if it's blittable, we use the unmanaged alignment requirement
2082 result = pInfo->m_LargestAlignmentRequirementOfAllMembers;
2086 #ifdef FEATURE_64BIT_ALIGNMENT
2087 if (result < 8 && pMT->RequiresAlign8())
2089 // If the structure contains 64-bit primitive fields and the platform requires 8-byte alignment for
2090 // such fields then make sure we return at least 8-byte alignment. Note that it's technically possible
2091 // to create unmanaged APIs that take unaligned structures containing such fields and this
2092 // unconditional alignment bump would cause us to get the calling convention wrong on platforms such
2093 // as ARM. If we see such cases in the future we'd need to add another control (such as an alignment
2094 // property for the StructLayout attribute or a marshaling directive attribute for p/invoke arguments)
2095 // that allows more precise control. For now we'll go with the likely scenario.
2098 #endif // FEATURE_64BIT_ALIGNMENT
2103 CORINFO_FIELD_HANDLE
2104 CEEInfo::getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num)
2113 CORINFO_FIELD_HANDLE result = NULL;
2115 JIT_TO_EE_TRANSITION_LEAF();
2117 TypeHandle VMClsHnd(clsHnd);
2119 MethodTable* pMT= VMClsHnd.AsMethodTable();
2121 result = (CORINFO_FIELD_HANDLE) ((pMT->GetApproxFieldDescListRaw()) + num);
2123 EE_TO_JIT_TRANSITION_LEAF();
2129 CEEInfo::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod)
2138 mdMethodDef result = 0;
2140 JIT_TO_EE_TRANSITION_LEAF();
2142 MethodDesc* pMD = GetMethod(hMethod);
2144 if (pMD->IsDynamicMethod())
2146 // Dynamic methods do not have tokens
2147 result = mdMethodDefNil;
2151 result = pMD->GetMemberDef();
2154 EE_TO_JIT_TRANSITION_LEAF();
2159 BOOL CEEInfo::checkMethodModifier(CORINFO_METHOD_HANDLE hMethod,
2170 BOOL result = FALSE;
2172 JIT_TO_EE_TRANSITION();
2174 MethodDesc* pMD = GetMethod(hMethod);
2175 Module* pModule = pMD->GetModule();
2177 CorElementType eeType = fOptional ? ELEMENT_TYPE_CMOD_OPT : ELEMENT_TYPE_CMOD_REQD;
2179 // modopts/modreqs for the method are by convention stored on the return type
2180 result = sig.GetReturnProps().HasCustomModifier(pModule, modifier, eeType);
2182 EE_TO_JIT_TRANSITION();
2187 /*********************************************************************/
2188 static unsigned ComputeGCLayout(MethodTable * pMT, BYTE* gcPtrs)
2190 STANDARD_VM_CONTRACT;
2192 unsigned result = 0;
2194 _ASSERTE(pMT->IsValueType());
2196 // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in which
2197 // case the check for g_TypedReferenceMT below would not be necessary
2198 if (pMT == g_TypedReferenceMT || pMT->HasSameTypeDefAs(g_pByReferenceClass))
2200 if (gcPtrs[0] == TYPE_GC_NONE)
2202 gcPtrs[0] = TYPE_GC_BYREF;
2205 else if (gcPtrs[0] != TYPE_GC_BYREF)
2207 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2212 ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
2213 for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
2215 int fieldStartIndex = pFD->GetOffset() / TARGET_POINTER_SIZE;
2217 if (pFD->GetFieldType() != ELEMENT_TYPE_VALUETYPE)
2219 if (pFD->IsObjRef())
2221 if (gcPtrs[fieldStartIndex] == TYPE_GC_NONE)
2223 gcPtrs[fieldStartIndex] = TYPE_GC_REF;
2226 else if (gcPtrs[fieldStartIndex] != TYPE_GC_REF)
2228 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2234 MethodTable * pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
2235 result += ComputeGCLayout(pFieldMT, gcPtrs + fieldStartIndex);
2241 unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
2250 unsigned result = 0;
2252 JIT_TO_EE_TRANSITION();
2254 TypeHandle VMClsHnd(clsHnd);
2256 MethodTable* pMT = VMClsHnd.GetMethodTable();
2258 if (VMClsHnd.IsNativeValueType())
2260 // native value types have no GC pointers
2262 memset(gcPtrs, TYPE_GC_NONE,
2263 (VMClsHnd.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2265 else if (pMT->IsByRefLike())
2267 // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in
2268 // which case the check for g_TypedReferenceMT below would not be necessary
2269 if (pMT == g_TypedReferenceMT)
2271 gcPtrs[0] = TYPE_GC_BYREF;
2272 gcPtrs[1] = TYPE_GC_NONE;
2277 memset(gcPtrs, TYPE_GC_NONE,
2278 (VMClsHnd.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2279 // Note: This case is more complicated than the TypedReference case
2280 // due to ByRefLike structs being included as fields in other value
2281 // types (TypedReference can not be.)
2282 result = ComputeGCLayout(VMClsHnd.AsMethodTable(), gcPtrs);
2287 _ASSERTE(sizeof(BYTE) == 1);
2289 BOOL isValueClass = pMT->IsValueType();
2291 #ifdef FEATURE_READYTORUN_COMPILER
2292 _ASSERTE(isValueClass || !IsReadyToRunCompilation() || pMT->IsInheritanceChainLayoutFixedInCurrentVersionBubble());
2295 unsigned int size = isValueClass ? VMClsHnd.GetSize() : pMT->GetNumInstanceFieldBytes() + OBJECT_SIZE;
2297 // assume no GC pointers at first
2299 memset(gcPtrs, TYPE_GC_NONE,
2300 (size + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2302 // walk the GC descriptors, turning on the correct bits
2303 if (pMT->ContainsPointers())
2305 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
2306 CGCDescSeries * pByValueSeries = map->GetLowestSeries();
2308 for (SIZE_T i = 0; i < map->GetNumSeries(); i++)
2310 // Get offset into the value class of the first pointer field (includes a +Object)
2311 size_t cbSeriesSize = pByValueSeries->GetSeriesSize() + pMT->GetBaseSize();
2312 size_t cbSeriesOffset = pByValueSeries->GetSeriesOffset();
2313 size_t cbOffset = isValueClass ? cbSeriesOffset - OBJECT_SIZE : cbSeriesOffset;
2315 _ASSERTE (cbOffset % TARGET_POINTER_SIZE == 0);
2316 _ASSERTE (cbSeriesSize % TARGET_POINTER_SIZE == 0);
2318 result += (unsigned) (cbSeriesSize / TARGET_POINTER_SIZE);
2319 memset(&gcPtrs[cbOffset / TARGET_POINTER_SIZE], TYPE_GC_REF, cbSeriesSize / TARGET_POINTER_SIZE);
2326 EE_TO_JIT_TRANSITION();
2331 // returns the enregister info for a struct based on type of fields, alignment, etc.
2332 bool CEEInfo::getSystemVAmd64PassStructInRegisterDescriptor(
2333 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
2334 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
2343 #if defined(UNIX_AMD64_ABI_ITF)
2344 JIT_TO_EE_TRANSITION();
2346 _ASSERTE(structPassInRegDescPtr != nullptr);
2347 TypeHandle th(structHnd);
2349 structPassInRegDescPtr->passedInRegisters = false;
2351 // Make sure this is a value type.
2352 if (th.IsValueType())
2354 _ASSERTE((CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeStruct) ||
2355 (CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeTypedReference));
2357 // The useNativeLayout in this case tracks whether the classification
2358 // is for a native layout of the struct or not.
2359 // If the struct has special marshaling it has a native layout.
2360 // In such cases the classifier needs to use the native layout.
2361 // For structs with no native layout, the managed layout should be used
2362 // even if classified for the purposes of marshaling/PInvoke passing.
2363 bool useNativeLayout = false;
2364 MethodTable* methodTablePtr = nullptr;
2365 if (!th.IsTypeDesc())
2367 methodTablePtr = th.AsMethodTable();
2371 _ASSERTE(th.IsNativeValueType());
2373 useNativeLayout = true;
2374 methodTablePtr = th.AsNativeValueType();
2376 _ASSERTE(methodTablePtr != nullptr);
2378 // If we have full support for UNIX_AMD64_ABI, and not just the interface,
2379 // then we've cached whether this is a reg passed struct in the MethodTable, computed during
2380 // MethodTable construction. Otherwise, we are just building in the interface, and we haven't
2381 // computed or cached anything, so we need to compute it now.
2382 #if defined(UNIX_AMD64_ABI)
2383 bool canPassInRegisters = useNativeLayout ? methodTablePtr->GetLayoutInfo()->IsNativeStructPassedInRegisters()
2384 : methodTablePtr->IsRegPassedStruct();
2385 #else // !defined(UNIX_AMD64_ABI)
2386 bool canPassInRegisters = false;
2387 SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2388 if (th.GetSize() <= CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)
2390 canPassInRegisters = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2392 #endif // !defined(UNIX_AMD64_ABI)
2394 if (canPassInRegisters)
2396 #if defined(UNIX_AMD64_ABI)
2397 SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2398 bool result = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2400 // The answer must be true at this point.
2402 #endif // UNIX_AMD64_ABI
2404 structPassInRegDescPtr->passedInRegisters = true;
2406 structPassInRegDescPtr->eightByteCount = helper.eightByteCount;
2407 _ASSERTE(structPassInRegDescPtr->eightByteCount <= CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS);
2409 for (unsigned int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++)
2411 structPassInRegDescPtr->eightByteClassifications[i] = helper.eightByteClassifications[i];
2412 structPassInRegDescPtr->eightByteSizes[i] = helper.eightByteSizes[i];
2413 structPassInRegDescPtr->eightByteOffsets[i] = helper.eightByteOffsets[i];
2417 _ASSERTE(structPassInRegDescPtr->passedInRegisters == canPassInRegisters);
2420 EE_TO_JIT_TRANSITION();
2423 #else // !defined(UNIX_AMD64_ABI_ITF)
2425 #endif // !defined(UNIX_AMD64_ABI_ITF)
2428 /*********************************************************************/
2429 unsigned CEEInfo::getClassNumInstanceFields (CORINFO_CLASS_HANDLE clsHnd)
2438 unsigned result = 0;
2440 JIT_TO_EE_TRANSITION_LEAF();
2442 TypeHandle th(clsHnd);
2444 if (!th.IsTypeDesc())
2446 result = th.AsMethodTable()->GetNumInstanceFields();
2450 // native value types are opaque aggregates with explicit size
2454 EE_TO_JIT_TRANSITION_LEAF();
2460 CorInfoType CEEInfo::asCorInfoType (CORINFO_CLASS_HANDLE clsHnd)
2469 CorInfoType result = CORINFO_TYPE_UNDEF;
2471 JIT_TO_EE_TRANSITION();
2473 TypeHandle VMClsHnd(clsHnd);
2474 result = toJitType(VMClsHnd);
2476 EE_TO_JIT_TRANSITION();
2482 CORINFO_LOOKUP_KIND CEEInfo::getLocationOfThisType(CORINFO_METHOD_HANDLE context)
2491 CORINFO_LOOKUP_KIND result;
2493 /* Initialize fields of result for debug build warning */
2494 result.needsRuntimeLookup = false;
2495 result.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
2497 JIT_TO_EE_TRANSITION();
2499 MethodDesc *pContextMD = GetMethod(context);
2501 // If the method table is not shared, then return CONST
2502 if (!pContextMD->GetMethodTable()->IsSharedByGenericInstantiations())
2504 result.needsRuntimeLookup = false;
2508 result.needsRuntimeLookup = true;
2510 // If we've got a vtable extra argument, go through that
2511 if (pContextMD->RequiresInstMethodTableArg())
2513 result.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
2515 // If we've got an object, go through its vtable
2516 else if (pContextMD->AcquiresInstMethodTableFromThis())
2518 result.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
2520 // Otherwise go through the method-desc argument
2523 _ASSERTE(pContextMD->RequiresInstMethodDescArg());
2524 result.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
2528 EE_TO_JIT_TRANSITION();
2533 CORINFO_METHOD_HANDLE CEEInfo::GetDelegateCtor(
2534 CORINFO_METHOD_HANDLE methHnd,
2535 CORINFO_CLASS_HANDLE clsHnd,
2536 CORINFO_METHOD_HANDLE targetMethodHnd,
2537 DelegateCtorArgs *pCtorData)
2548 // No sense going through the optimized case just for verification and it can cause issues parsing
2549 // uninstantiated generic signatures.
2553 CORINFO_METHOD_HANDLE result = NULL;
2555 JIT_TO_EE_TRANSITION();
2557 MethodDesc *pCurrentCtor = (MethodDesc*)methHnd;
2558 if (!pCurrentCtor->IsFCall())
2564 MethodDesc *pTargetMethod = (MethodDesc*)targetMethodHnd;
2565 TypeHandle delegateType = (TypeHandle)clsHnd;
2567 MethodDesc *pDelegateCtor = COMDelegate::GetDelegateCtor(delegateType, pTargetMethod, pCtorData);
2569 pDelegateCtor = pCurrentCtor;
2570 result = (CORINFO_METHOD_HANDLE)pDelegateCtor;
2573 EE_TO_JIT_TRANSITION();
2578 void CEEInfo::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd)
2587 JIT_TO_EE_TRANSITION();
2589 MethodDesc* pMD = GetMethod(methHnd);
2591 if (pMD->IsDynamicMethod())
2593 pMD->AsDynamicMethodDesc()->GetResolver()->FreeCompileTimeState();
2596 EE_TO_JIT_TRANSITION();
2599 // Given a module scope (scopeHnd), a method handle (context) and an metadata token,
2600 // attempt to load the handle (type, field or method) associated with the token.
2601 // If this is not possible at compile-time (because the method code is shared and the token contains type parameters)
2602 // then indicate how the handle should be looked up at run-time.
2604 // See corinfo.h for more details
2606 void CEEInfo::embedGenericHandle(
2607 CORINFO_RESOLVED_TOKEN * pResolvedToken,
2609 CORINFO_GENERICHANDLE_RESULT *pResult)
2618 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
2620 JIT_TO_EE_TRANSITION();
2622 BOOL fRuntimeLookup;
2623 MethodDesc * pTemplateMD = NULL;
2625 if (!fEmbedParent && pResolvedToken->hMethod != NULL)
2627 MethodDesc * pMD = (MethodDesc *)pResolvedToken->hMethod;
2628 TypeHandle th(pResolvedToken->hClass);
2630 pResult->handleType = CORINFO_HANDLETYPE_METHOD;
2632 Instantiation methodInst = pMD->GetMethodInstantiation();
2634 pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, th.GetMethodTable(), FALSE, methodInst, FALSE);
2636 // Normalize the method handle for reflection
2637 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Ldtoken)
2638 pMD = MethodDesc::FindOrCreateAssociatedMethodDescForReflection(pMD, th, methodInst);
2640 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pMD;
2643 // Runtime lookup is only required for stubs. Regular entrypoints are always the same shared MethodDescs.
2644 fRuntimeLookup = pMD->IsWrapperStub() &&
2645 (pMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(methodInst));
2648 if (!fEmbedParent && pResolvedToken->hField != NULL)
2650 FieldDesc * pFD = (FieldDesc *)pResolvedToken->hField;
2651 TypeHandle th(pResolvedToken->hClass);
2653 pResult->handleType = CORINFO_HANDLETYPE_FIELD;
2655 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pFD;
2657 fRuntimeLookup = th.IsSharedByGenericInstantiations() && pFD->IsStatic();
2661 TypeHandle th(pResolvedToken->hClass);
2663 pResult->handleType = CORINFO_HANDLETYPE_CLASS;
2665 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
2667 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsArray()->GetTemplateMethodTable();
2671 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsPtr();
2674 if (fEmbedParent && pResolvedToken->hMethod != NULL)
2676 MethodDesc * pDeclaringMD = (MethodDesc *)pResolvedToken->hMethod;
2678 if (!pDeclaringMD->GetMethodTable()->HasSameTypeDefAs(th.GetMethodTable()))
2681 // The method type may point to a sub-class of the actual class that declares the method.
2682 // It is important to embed the declaring type in this case.
2685 pTemplateMD = pDeclaringMD;
2687 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pDeclaringMD->GetMethodTable();
2691 // IsSharedByGenericInstantiations would not work here. The runtime lookup is required
2692 // even for standalone generic variables that show up as __Canon here.
2693 fRuntimeLookup = th.IsCanonicalSubtype();
2696 _ASSERTE(pResult->compileTimeHandle);
2699 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
2700 && ContextIsShared(pResolvedToken->tokenContext))
2702 DictionaryEntryKind entryKind = EmptySlot;
2703 switch (pResult->handleType)
2705 case CORINFO_HANDLETYPE_CLASS:
2706 entryKind = (pTemplateMD != NULL) ? DeclaringTypeHandleSlot : TypeHandleSlot;
2708 case CORINFO_HANDLETYPE_METHOD:
2709 entryKind = MethodDescSlot;
2711 case CORINFO_HANDLETYPE_FIELD:
2712 entryKind = FieldDescSlot;
2718 ComputeRuntimeLookupForSharedGenericToken(entryKind,
2726 // If the target is not shared then we've already got our result and
2727 // can simply do a static look up
2728 pResult->lookup.lookupKind.needsRuntimeLookup = false;
2730 pResult->lookup.constLookup.handle = pResult->compileTimeHandle;
2731 pResult->lookup.constLookup.accessType = IAT_VALUE;
2734 EE_TO_JIT_TRANSITION();
2737 void CEEInfo::ScanForModuleDependencies(Module* pModule, SigPointer psig)
2739 STANDARD_VM_CONTRACT;
2741 _ASSERTE(pModule && !pModule->IsSystem());
2743 CorElementType eType;
2744 IfFailThrow(psig.GetElemType(&eType));
2748 case ELEMENT_TYPE_GENERICINST:
2750 ScanForModuleDependencies(pModule,psig);
2751 IfFailThrow(psig.SkipExactlyOne());
2754 IfFailThrow(psig.GetData(&ntypars));
2755 for (ULONG i = 0; i < ntypars; i++)
2757 ScanForModuleDependencies(pModule,psig);
2758 IfFailThrow(psig.SkipExactlyOne());
2763 case ELEMENT_TYPE_VALUETYPE:
2764 case ELEMENT_TYPE_CLASS:
2767 IfFailThrow(psig.GetToken(&tk));
2768 if (TypeFromToken(tk) == mdtTypeRef)
2770 Module * pTypeDefModule;
2773 if (ClassLoader::ResolveTokenToTypeDefThrowing(pModule, tk, &pTypeDefModule, &tkTypeDef))
2776 if (!pTypeDefModule->IsSystem() && (pModule != pTypeDefModule))
2778 m_pOverride->addActiveDependency((CORINFO_MODULE_HANDLE)pModule, (CORINFO_MODULE_HANDLE)pTypeDefModule);
2789 void CEEInfo::ScanMethodSpec(Module * pModule, PCCOR_SIGNATURE pMethodSpec, ULONG cbMethodSpec)
2791 STANDARD_VM_CONTRACT;
2793 SigPointer sp(pMethodSpec, cbMethodSpec);
2796 IfFailThrow(sp.GetByte(&etype));
2798 _ASSERT(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST);
2800 ULONG nGenericMethodArgs;
2801 IfFailThrow(sp.GetData(&nGenericMethodArgs));
2803 for (ULONG i = 0; i < nGenericMethodArgs; i++)
2805 ScanForModuleDependencies(pModule,sp);
2806 IfFailThrow(sp.SkipExactlyOne());
2810 BOOL CEEInfo::ScanTypeSpec(Module * pModule, PCCOR_SIGNATURE pTypeSpec, ULONG cbTypeSpec)
2812 STANDARD_VM_CONTRACT;
2814 SigPointer sp(pTypeSpec, cbTypeSpec);
2816 CorElementType eType;
2817 IfFailThrow(sp.GetElemType(&eType));
2819 // Filter out non-instantiated types and typedescs (typevars, arrays, ...)
2820 if (eType != ELEMENT_TYPE_GENERICINST)
2822 // Scanning of the parent chain is required for reference types only.
2823 // Note that the parent chain MUST NOT be scanned for instantiated
2824 // generic variables because of they are not a real dependencies.
2825 return (eType == ELEMENT_TYPE_CLASS);
2828 IfFailThrow(sp.SkipExactlyOne());
2831 IfFailThrow(sp.GetData(&ntypars));
2833 for (ULONG i = 0; i < ntypars; i++)
2835 ScanForModuleDependencies(pModule,sp);
2836 IfFailThrow(sp.SkipExactlyOne());
2842 void CEEInfo::ScanInstantiation(Module * pModule, Instantiation inst)
2844 STANDARD_VM_CONTRACT;
2846 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
2848 TypeHandle th = inst[i];
2849 if (th.IsTypeDesc())
2852 MethodTable * pMT = th.AsMethodTable();
2854 Module * pDefModule = pMT->GetModule();
2856 if (!pDefModule->IsSystem() && (pModule != pDefModule))
2858 m_pOverride->addActiveDependency((CORINFO_MODULE_HANDLE)pModule, (CORINFO_MODULE_HANDLE)pDefModule);
2861 if (pMT->HasInstantiation())
2863 ScanInstantiation(pModule, pMT->GetInstantiation());
2869 // ScanToken is used to track triggers for creation of per-AppDomain state instead, including allocations required for statics and
2870 // triggering of module cctors.
2872 // The basic rule is: There should be no possibility of a shared module that is "active" to have a direct call into a module that
2873 // is not "active". And we don't want to intercept every call during runtime, so during compile time we track static calls and
2874 // everything that can result in new virtual calls.
2876 // The current algorithm (scan the parent type chain and instantiation variables) is more than enough to maintain this invariant.
2877 // One could come up with a more efficient algorithm that still maintains the invariant, but it may introduce backward compatibility
2880 // For efficiency, the implementation leverages the loaded types as much as possible. Unfortunately, we still have to go back to
2881 // metadata when the generic variables could have been substituted via generic context.
2883 void CEEInfo::ScanToken(Module * pModule, CORINFO_RESOLVED_TOKEN * pResolvedToken, TypeHandle th, MethodDesc * pMD)
2885 STANDARD_VM_CONTRACT;
2887 if (pModule->IsSystem())
2894 // Scan method instantiation
2896 if (pMD != NULL && pResolvedToken->pMethodSpec != NULL)
2898 if (ContextIsInstantiated(pResolvedToken->tokenContext))
2900 ScanMethodSpec(pModule, pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
2904 ScanInstantiation(pModule, pMD->GetMethodInstantiation());
2908 if (th.IsTypeDesc())
2911 MethodTable * pMT = th.AsMethodTable();
2914 // Scan type instantiation
2916 if (pResolvedToken->pTypeSpec != NULL)
2918 if (ContextIsInstantiated(pResolvedToken->tokenContext))
2920 if (!ScanTypeSpec(pModule, pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec))
2925 ScanInstantiation(pModule, pMT->GetInstantiation());
2930 // Scan chain of parent types
2934 Module * pDefModule = pMT->GetModule();
2935 if (pDefModule->IsSystem())
2938 if (pModule != pDefModule)
2940 m_pOverride->addActiveDependency((CORINFO_MODULE_HANDLE)pModule, (CORINFO_MODULE_HANDLE)pDefModule);
2943 MethodTable * pParentMT = pMT->GetParentMethodTable();
2944 if (pParentMT == NULL)
2947 if (pParentMT->HasInstantiation())
2949 IMDInternalImport* pInternalImport = pDefModule->GetMDImport();
2952 IfFailThrow(pInternalImport->GetTypeDefProps(pMT->GetCl(), NULL, &tkParent));
2954 if (TypeFromToken(tkParent) == mdtTypeSpec)
2956 PCCOR_SIGNATURE pTypeSpec;
2958 IfFailThrow(pInternalImport->GetTypeSpecFromToken(tkParent, &pTypeSpec, &cbTypeSpec));
2960 ScanTypeSpec(pDefModule, pTypeSpec, cbTypeSpec);
2968 void CEEInfo::ScanTokenForDynamicScope(CORINFO_RESOLVED_TOKEN * pResolvedToken, TypeHandle th, MethodDesc * pMD)
2970 STANDARD_VM_CONTRACT;
2972 if (m_pMethodBeingCompiled->IsLCGMethod())
2974 // The dependency tracking for LCG is irrelevant. Perform immediate activation.
2975 if (pMD != NULL && pMD->HasMethodInstantiation())
2976 pMD->EnsureActive();
2977 if (!th.IsTypeDesc())
2978 th.AsMethodTable()->EnsureInstanceActive();
2982 // Stubs-as-IL have to do regular dependency tracking because they can be shared cross-domain.
2983 Module * pModule = GetDynamicResolver(pResolvedToken->tokenScope)->GetDynamicMethod()->GetModule();
2984 ScanToken(pModule, pResolvedToken, th, pMD);
2987 MethodDesc * CEEInfo::GetMethodForSecurity(CORINFO_METHOD_HANDLE callerHandle)
2989 STANDARD_VM_CONTRACT;
2991 // Cache the cast lookup
2992 if (callerHandle == m_hMethodForSecurity_Key)
2994 return m_pMethodForSecurity_Value;
2997 MethodDesc * pCallerMethod = (MethodDesc *)callerHandle;
2999 //If the caller is generic, load the open type and then load the field again, This allows us to
3000 //differentiate between BadGeneric<T> containing a memberRef for a field of type InaccessibleClass and
3001 //GoodGeneric<T> containing a memberRef for a field of type T instantiated over InaccessibleClass.
3002 MethodDesc * pMethodForSecurity = pCallerMethod->IsILStub() ?
3003 pCallerMethod : pCallerMethod->LoadTypicalMethodDefinition();
3005 m_hMethodForSecurity_Key = callerHandle;
3006 m_pMethodForSecurity_Value = pMethodForSecurity;
3008 return pMethodForSecurity;
3011 // Check that the instantation is <!/!!0, ..., !/!!(n-1)>
3012 static BOOL IsSignatureForTypicalInstantiation(SigPointer sigptr, CorElementType varType, ULONG ntypars)
3014 STANDARD_VM_CONTRACT;
3016 for (ULONG i = 0; i < ntypars; i++)
3018 CorElementType type;
3019 IfFailThrow(sigptr.GetElemType(&type));
3020 if (type != varType)
3024 IfFailThrow(sigptr.GetData(&data));
3033 // Check that methodSpec instantiation is <!!0, ..., !!(n-1)>
3034 static BOOL IsMethodSpecForTypicalInstantation(SigPointer sigptr)
3036 STANDARD_VM_CONTRACT;
3039 IfFailThrow(sigptr.GetByte(&etype));
3040 _ASSERTE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST);
3043 IfFailThrow(sigptr.GetData(&ntypars));
3045 return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_MVAR, ntypars);
3048 // Check that typeSpec instantiation is <!0, ..., !(n-1)>
3049 static BOOL IsTypeSpecForTypicalInstantiation(SigPointer sigptr)
3051 STANDARD_VM_CONTRACT;
3053 CorElementType type;
3054 IfFailThrow(sigptr.GetElemType(&type));
3055 if (type != ELEMENT_TYPE_GENERICINST)
3058 IfFailThrow(sigptr.SkipExactlyOne());
3061 IfFailThrow(sigptr.GetData(&ntypars));
3063 return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_VAR, ntypars);
3066 void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entryKind,
3067 CORINFO_RESOLVED_TOKEN * pResolvedToken,
3068 CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
3069 MethodDesc * pTemplateMD /* for method-based slots */,
3070 CORINFO_LOOKUP *pResultLookup)
3074 PRECONDITION(CheckPointer(pResultLookup));
3078 // We should never get here when we are only verifying
3079 _ASSERTE(!isVerifyOnly());
3081 pResultLookup->lookupKind.needsRuntimeLookup = true;
3082 pResultLookup->lookupKind.runtimeLookupFlags = 0;
3084 CORINFO_RUNTIME_LOOKUP *pResult = &pResultLookup->runtimeLookup;
3085 pResult->signature = NULL;
3087 pResult->indirectFirstOffset = 0;
3088 pResult->indirectSecondOffset = 0;
3090 // Unless we decide otherwise, just do the lookup via a helper function
3091 pResult->indirections = CORINFO_USEHELPER;
3093 MethodDesc *pContextMD = GetMethodFromContext(pResolvedToken->tokenContext);
3094 MethodTable *pContextMT = pContextMD->GetMethodTable();
3096 // Do not bother computing the runtime lookup if we are inlining. The JIT is going
3097 // to abort the inlining attempt anyway.
3098 if (pContextMD != m_pMethodBeingCompiled)
3103 // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup.
3104 // All callers of ComputeRuntimeLookupForSharedGenericToken have to filter out this case. We can't do much about it here.
3105 _ASSERTE(pContextMD->IsSharedByGenericInstantiations());
3107 BOOL fInstrument = FALSE;
3109 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
3110 // This will make sure that when IBC logging is turned on we will go through a version
3111 // of JIT_GenericHandle which logs the access. Note that we still want the dictionaries
3112 // to be populated to prepopulate the types at NGen time.
3113 if (IsCompilingForNGen() &&
3114 GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
3118 #endif // FEATURE_NATIVE_IMAGE_GENERATION
3120 if (pContextMD->RequiresInstMethodDescArg())
3122 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
3126 if (pContextMD->RequiresInstMethodTableArg())
3127 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
3129 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
3132 #ifdef FEATURE_READYTORUN_COMPILER
3133 if (IsReadyToRunCompilation())
3135 pResultLookup->lookupKind.runtimeLookupArgs = NULL;
3139 case DeclaringTypeHandleSlot:
3140 _ASSERTE(pTemplateMD != NULL);
3141 pResultLookup->lookupKind.runtimeLookupArgs = pTemplateMD->GetMethodTable();
3142 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_DeclaringTypeHandle;
3145 case TypeHandleSlot:
3146 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_TypeHandle;
3149 case MethodDescSlot:
3150 case MethodEntrySlot:
3151 case ConstrainedMethodEntrySlot:
3152 case DispatchStubAddrSlot:
3154 if (pTemplateMD != (MethodDesc*)pResolvedToken->hMethod)
3157 if (entryKind == MethodDescSlot)
3158 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_MethodHandle;
3159 else if (entryKind == MethodEntrySlot || entryKind == ConstrainedMethodEntrySlot)
3160 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_MethodEntry;
3162 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_VirtualEntry;
3164 pResultLookup->lookupKind.runtimeLookupArgs = pConstrainedResolvedToken;
3170 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_FieldHandle;
3174 _ASSERTE(!"Unknown dictionary entry kind!");
3175 IfFailThrow(E_FAIL);
3178 // For R2R compilations, we don't generate the dictionary lookup signatures (dictionary lookups are done in a
3179 // different way that is more version resilient... plus we can't have pointers to existing MTs/MDs in the sigs)
3183 // If we've got a method type parameter of any kind then we must look in the method desc arg
3184 if (pContextMD->RequiresInstMethodDescArg())
3186 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG : CORINFO_HELP_RUNTIMEHANDLE_METHOD;
3192 // (1) Naked method type variable: look up directly in instantiation hanging off runtime md
3193 // (2) Reference to method-spec of current method (e.g. a recursive call) i.e. currentmeth<!0,...,!(n-1)>
3194 if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3196 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3197 CorElementType type;
3198 IfFailThrow(sigptr.GetElemType(&type));
3199 if (type == ELEMENT_TYPE_MVAR)
3201 pResult->indirections = 2;
3202 pResult->testForNull = 0;
3203 #ifdef FEATURE_PREJIT
3204 pResult->testForFixup = 1;
3206 pResult->testForFixup = 0;
3208 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3210 if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
3212 pResult->indirectFirstOffset = 1;
3216 IfFailThrow(sigptr.GetData(&data));
3217 pResult->offsets[1] = sizeof(TypeHandle) * data;
3222 else if (entryKind == MethodDescSlot)
3224 // It's the context itself (i.e. a recursive call)
3225 if (!pTemplateMD->HasSameMethodDefAs(pContextMD))
3228 // Now just check that the instantiation is (!!0, ..., !!(n-1))
3229 if (!IsMethodSpecForTypicalInstantation(SigPointer(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)))
3232 // Type instantiation has to match too if there is one
3233 if (pContextMT->HasInstantiation())
3235 TypeHandle thTemplate(pResolvedToken->hClass);
3237 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3240 // This check filters out method instantiation on generic type definition, like G::M<!!0>()
3241 // We may not ever get it here. Filter it out just to be sure...
3242 if (pResolvedToken->pTypeSpec == NULL)
3245 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3249 // Just use the method descriptor that was passed in!
3250 pResult->indirections = 0;
3251 pResult->testForNull = 0;
3252 pResult->testForFixup = 0;
3257 // Otherwise we must just have class type variables
3260 _ASSERTE(pContextMT->GetNumGenericArgs() > 0);
3262 if (pContextMD->RequiresInstMethodTableArg())
3264 // If we've got a vtable extra argument, go through that
3265 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3267 // If we've got an object, go through its vtable
3270 _ASSERTE(pContextMD->AcquiresInstMethodTableFromThis());
3271 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3278 // (1) Naked class type variable: look up directly in instantiation hanging off vtable
3279 // (2) C<!0,...,!(n-1)> where C is the context's class and C is sealed: just return vtable ptr
3280 if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3282 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3283 CorElementType type;
3284 IfFailThrow(sigptr.GetElemType(&type));
3285 if (type == ELEMENT_TYPE_VAR)
3287 pResult->indirections = 3;
3288 pResult->testForNull = 0;
3289 #ifdef FEATURE_PREJIT
3290 pResult->testForFixup = 1;
3292 pResult->testForFixup = 0;
3294 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3295 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3297 IfFailThrow(sigptr.GetData(&data));
3298 pResult->offsets[2] = sizeof(TypeHandle) * data;
3300 if (MethodTable::IsPerInstInfoRelative())
3302 pResult->indirectFirstOffset = 1;
3303 pResult->indirectSecondOffset = 1;
3308 else if (type == ELEMENT_TYPE_GENERICINST &&
3309 (pContextMT->IsSealed() || pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM))
3311 TypeHandle thTemplate(pResolvedToken->hClass);
3313 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3316 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3319 // Just use the vtable pointer itself!
3320 pResult->indirections = 0;
3321 pResult->testForNull = 0;
3322 pResult->testForFixup = 0;
3331 SigBuilder sigBuilder;
3333 sigBuilder.AppendData(entryKind);
3335 if (pResultLookup->lookupKind.runtimeLookupKind != CORINFO_LOOKUP_METHODPARAM)
3337 _ASSERTE(pContextMT->GetNumDicts() > 0);
3338 sigBuilder.AppendData(pContextMT->GetNumDicts() - 1);
3341 Module * pModule = (Module *)pResolvedToken->tokenScope;
3345 case DeclaringTypeHandleSlot:
3346 _ASSERTE(pTemplateMD != NULL);
3347 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3348 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3351 case TypeHandleSlot:
3353 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
3355 if (!IsReadyToRunCompilation())
3357 sigBuilder.AppendElementType((CorElementType)ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
3360 sigBuilder.AppendElementType(ELEMENT_TYPE_SZARRAY);
3363 // Note that we can come here with pResolvedToken->pTypeSpec == NULL for invalid IL that
3364 // directly references __Canon
3365 if (pResolvedToken->pTypeSpec != NULL)
3367 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3368 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3372 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3373 sigBuilder.AppendPointer(pResolvedToken->hClass);
3378 case ConstrainedMethodEntrySlot:
3379 // Encode constrained type token
3380 if (pConstrainedResolvedToken->pTypeSpec != NULL)
3382 SigPointer sigptr(pConstrainedResolvedToken->pTypeSpec, pConstrainedResolvedToken->cbTypeSpec);
3383 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3387 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3388 sigBuilder.AppendPointer(pConstrainedResolvedToken->hClass);
3392 case MethodDescSlot:
3393 case MethodEntrySlot:
3394 case DispatchStubAddrSlot:
3396 // Encode containing type
3397 if (pResolvedToken->pTypeSpec != NULL)
3399 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3400 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3404 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3405 sigBuilder.AppendPointer(pResolvedToken->hClass);
3409 _ASSERTE(pTemplateMD != NULL);
3411 mdMethodDef methodToken = pTemplateMD->GetMemberDef_NoLogging();
3412 DWORD methodFlags = 0;
3414 // Check for non-NULL method spec first. We can encode the method instantiation only if we have one in method spec to start with. Note that there are weird cases
3415 // like instantiating stub for generic method definition that do not have method spec but that won't be caught by the later conditions either.
3416 BOOL fMethodNeedsInstantiation = (pResolvedToken->pMethodSpec != NULL) && pTemplateMD->HasMethodInstantiation() && !pTemplateMD->IsGenericMethodDefinition();
3418 if (pTemplateMD->IsUnboxingStub())
3419 methodFlags |= ENCODE_METHOD_SIG_UnboxingStub;
3420 // Always create instantiating stub for method entry points even if the template does not ask for it. It saves caller
3421 // from creating throw-away instantiating stub.
3422 if (pTemplateMD->IsInstantiatingStub() || (entryKind == MethodEntrySlot))
3423 methodFlags |= ENCODE_METHOD_SIG_InstantiatingStub;
3424 if (fMethodNeedsInstantiation)
3425 methodFlags |= ENCODE_METHOD_SIG_MethodInstantiation;
3426 if (IsNilToken(methodToken))
3428 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3431 if (entryKind == DispatchStubAddrSlot && pTemplateMD->IsVtableMethod())
3433 // Encode the method for dispatch stub using slot to avoid touching the interface method MethodDesc at runtime
3435 // There should be no other flags set if we are encoding the method using slot for virtual stub dispatch
3436 _ASSERTE(methodFlags == 0);
3438 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3441 if (!pTemplateMD->GetModule()->IsInCurrentVersionBubble())
3443 // Using a method defined in another version bubble. We can assume the slot number is stable only for real interface methods.
3444 if (!pTemplateMD->GetMethodTable()->IsInterface() || pTemplateMD->IsStatic() || pTemplateMD->HasMethodInstantiation())
3446 _ASSERTE(!"References to non-interface methods not yet supported in version resilient images");
3447 IfFailThrow(E_FAIL);
3449 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3452 sigBuilder.AppendData(methodFlags);
3454 if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
3456 // Encode method token and its module context (as method's type)
3457 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3458 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3460 sigBuilder.AppendData(RidFromToken(methodToken));
3464 sigBuilder.AppendData(pTemplateMD->GetSlot());
3467 if (fMethodNeedsInstantiation)
3469 SigPointer sigptr(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
3472 IfFailThrow(sigptr.GetByte(&etype));
3474 // Load the generic method instantiation
3475 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, pModule);
3477 DWORD nGenericMethodArgs;
3478 IfFailThrow(sigptr.GetData(&nGenericMethodArgs));
3479 sigBuilder.AppendData(nGenericMethodArgs);
3481 _ASSERTE(nGenericMethodArgs == pTemplateMD->GetNumGenericMethodArgs());
3483 for (DWORD i = 0; i < nGenericMethodArgs; i++)
3485 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3493 if (pResolvedToken->pTypeSpec != NULL)
3495 // Encode containing type
3496 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3497 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3501 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3502 sigBuilder.AppendPointer(pResolvedToken->hClass);
3505 FieldDesc * pField = (FieldDesc *)pResolvedToken->hField;
3506 _ASSERTE(pField != NULL);
3508 DWORD fieldIndex = pField->GetApproxEnclosingMethodTable()->GetIndexForFieldDesc(pField);
3509 sigBuilder.AppendData(fieldIndex);
3517 DictionaryEntrySignatureSource signatureSource = (IsCompilationProcess() ? FromZapImage : FromJIT);
3519 // It's a method dictionary lookup
3520 if (pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM)
3522 _ASSERTE(pContextMD != NULL);
3523 _ASSERTE(pContextMD->HasMethodInstantiation());
3525 if (DictionaryLayout::FindToken(pContextMD->GetLoaderAllocator(), pContextMD->GetNumGenericMethodArgs(), pContextMD->GetDictionaryLayout(), pResult, &sigBuilder, 1, signatureSource))
3527 pResult->testForNull = 1;
3528 pResult->testForFixup = 0;
3530 // Indirect through dictionary table pointer in InstantiatedMethodDesc
3531 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3533 if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
3535 pResult->indirectFirstOffset = 1;
3540 // It's a class dictionary lookup (CORINFO_LOOKUP_CLASSPARAM or CORINFO_LOOKUP_THISOBJ)
3543 if (DictionaryLayout::FindToken(pContextMT->GetLoaderAllocator(), pContextMT->GetNumGenericArgs(), pContextMT->GetClass()->GetDictionaryLayout(), pResult, &sigBuilder, 2, signatureSource))
3545 pResult->testForNull = 1;
3546 pResult->testForFixup = 0;
3548 // Indirect through dictionary table pointer in vtable
3549 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3551 // Next indirect through the dictionary appropriate to this instantiated type
3552 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3554 if (MethodTable::IsPerInstInfoRelative())
3556 pResult->indirectFirstOffset = 1;
3557 pResult->indirectSecondOffset = 1;
3565 /*********************************************************************/
3566 const char* CEEInfo::getClassName (CORINFO_CLASS_HANDLE clsHnd)
3575 const char* result = NULL;
3577 JIT_TO_EE_TRANSITION();
3579 TypeHandle VMClsHnd(clsHnd);
3580 MethodTable* pMT = VMClsHnd.GetMethodTable();
3588 result = pMT->GetDebugClassName();
3590 // since this is for diagnostic purposes only,
3591 // give up on the namespace, as we don't have a buffer to concat it
3592 // also note this won't show array class names.
3594 result = pMT->GetFullyQualifiedNameInfo(&nameSpace);
3598 EE_TO_JIT_TRANSITION();
3603 /***********************************************************************/
3604 const char* CEEInfo::getHelperName (CorInfoHelpFunc ftnNum)
3611 PRECONDITION(ftnNum >= 0 && ftnNum < CORINFO_HELP_COUNT);
3614 const char* result = NULL;
3616 JIT_TO_EE_TRANSITION_LEAF();
3618 #ifdef CROSSGEN_COMPILE
3619 result = hlpNameTable[ftnNum];
3622 result = hlpFuncTable[ftnNum].name;
3624 result = "AnyJITHelper";
3628 EE_TO_JIT_TRANSITION_LEAF();
3634 /*********************************************************************/
3635 int CEEInfo::appendClassName(__deref_inout_ecount(*pnBufLen) WCHAR** ppBuf,
3637 CORINFO_CLASS_HANDLE clsHnd,
3651 JIT_TO_EE_TRANSITION();
3653 TypeHandle th(clsHnd);
3655 TypeString::AppendType(ss,th,
3656 (fNamespace ? TypeString::FormatNamespace : 0) |
3657 (fFullInst ? TypeString::FormatFullInst : 0) |
3658 (fAssembly ? TypeString::FormatAssembly : 0));
3659 const WCHAR* szString = ss.GetUnicode();
3660 nLen = (int)wcslen(szString);
3663 wcscpy_s(*ppBuf, *pnBufLen, szString );
3664 (*ppBuf)[(*pnBufLen) - 1] = W('\0');
3666 (*pnBufLen) -= nLen;
3669 EE_TO_JIT_TRANSITION();
3674 /*********************************************************************/
3675 CORINFO_MODULE_HANDLE CEEInfo::getClassModule(CORINFO_CLASS_HANDLE clsHnd)
3684 CORINFO_MODULE_HANDLE result = NULL;
3686 JIT_TO_EE_TRANSITION_LEAF();
3688 TypeHandle VMClsHnd(clsHnd);
3690 result = CORINFO_MODULE_HANDLE(VMClsHnd.GetModule());
3692 EE_TO_JIT_TRANSITION_LEAF();
3697 /*********************************************************************/
3698 CORINFO_ASSEMBLY_HANDLE CEEInfo::getModuleAssembly(CORINFO_MODULE_HANDLE modHnd)
3707 CORINFO_ASSEMBLY_HANDLE result = NULL;
3709 JIT_TO_EE_TRANSITION_LEAF();
3711 result = CORINFO_ASSEMBLY_HANDLE(GetModule(modHnd)->GetAssembly());
3713 EE_TO_JIT_TRANSITION_LEAF();
3718 /*********************************************************************/
3719 const char* CEEInfo::getAssemblyName(CORINFO_ASSEMBLY_HANDLE asmHnd)
3728 const char* result = NULL;
3730 JIT_TO_EE_TRANSITION();
3731 result = ((Assembly*)asmHnd)->GetSimpleName();
3732 EE_TO_JIT_TRANSITION();
3737 /*********************************************************************/
3738 void* CEEInfo::LongLifetimeMalloc(size_t sz)
3747 void* result = NULL;
3749 JIT_TO_EE_TRANSITION_LEAF();
3750 result = new (nothrow) char[sz];
3751 EE_TO_JIT_TRANSITION_LEAF();
3756 /*********************************************************************/
3757 void CEEInfo::LongLifetimeFree(void* obj)
3766 JIT_TO_EE_TRANSITION_LEAF();
3767 (operator delete)(obj);
3768 EE_TO_JIT_TRANSITION_LEAF();
3771 /*********************************************************************/
3772 size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_MODULE_HANDLE *pModuleHandle, void **ppIndirection)
3783 JIT_TO_EE_TRANSITION_LEAF();
3785 TypeHandle VMClsHnd(clsHnd);
3786 Module *pModule = VMClsHnd.AsMethodTable()->GetModuleForStatics();
3788 if (ppIndirection != NULL)
3789 *ppIndirection = NULL;
3791 // The zapper needs the module handle. The jit should not use it at all.
3793 *pModuleHandle = CORINFO_MODULE_HANDLE(pModule);
3795 result = pModule->GetModuleID();
3799 EE_TO_JIT_TRANSITION_LEAF();
3804 /*********************************************************************/
3805 BOOL CEEInfo::isValueClass(CORINFO_CLASS_HANDLE clsHnd)
3816 JIT_TO_EE_TRANSITION_LEAF();
3820 // Note that clsHnd.IsValueType() would not return what the JIT expects
3821 // for corner cases like ELEMENT_TYPE_FNPTR
3822 TypeHandle VMClsHnd(clsHnd);
3823 MethodTable * pMT = VMClsHnd.GetMethodTable();
3824 ret = (pMT != NULL) ? pMT->IsValueType() : 0;
3826 EE_TO_JIT_TRANSITION_LEAF();
3831 /*********************************************************************/
3832 // If this method returns true, JIT will do optimization to inline the check for
3833 // GetClassFromHandle(handle) == obj.GetType()
3835 // This will enable to use directly the typehandle instead of going through getClassByHandle
3836 BOOL CEEInfo::canInlineTypeCheckWithObjectVTable (CORINFO_CLASS_HANDLE clsHnd)
3847 JIT_TO_EE_TRANSITION_LEAF();
3851 TypeHandle VMClsHnd(clsHnd);
3853 if (VMClsHnd.IsTypeDesc())
3855 // We can't do this optimization for arrays because of the object methodtable is template methodtable
3859 if (VMClsHnd.AsMethodTable()->IsMarshaledByRef())
3861 // We can't do this optimization for marshalbyrefs because of the object methodtable can be transparent proxy
3865 if (VMClsHnd.AsMethodTable()->IsInterface())
3867 // Object.GetType() should not ever return interface. However, WCF custom remoting proxy does it. Disable this
3868 // optimization for interfaces so that (autogenerated) code that compares Object.GetType() with interface type works
3869 // as expected for WCF custom remoting proxy. Note that this optimization is still not going to work well for custom
3870 // remoting proxies that are even more broken than the WCF one, e.g. returning random non-marshalbyref types
3871 // from Object.GetType().
3875 if (VMClsHnd == TypeHandle(g_pCanonMethodTableClass))
3877 // We can't do this optimization in shared generics code because of we do not know what the actual type is going to be.
3878 // (It can be array, marshalbyref, etc.)
3883 // It is safe to perform this optimization
3887 EE_TO_JIT_TRANSITION_LEAF();
3892 /*********************************************************************/
3893 DWORD CEEInfo::getClassAttribs (CORINFO_CLASS_HANDLE clsHnd)
3902 // <REVISIT_TODO>@todo FIX need to really fetch the class atributes. at present
3903 // we don't need to because the JIT only cares in the case of COM classes</REVISIT_TODO>
3906 JIT_TO_EE_TRANSITION();
3908 ret = getClassAttribsInternal(clsHnd);
3910 EE_TO_JIT_TRANSITION();
3916 /*********************************************************************/
3917 BOOL CEEInfo::isStructRequiringStackAllocRetBuf(CORINFO_CLASS_HANDLE clsHnd)
3928 JIT_TO_EE_TRANSITION_LEAF();
3930 TypeHandle VMClsHnd(clsHnd);
3931 MethodTable * pMT = VMClsHnd.GetMethodTable();
3932 ret = (pMT != NULL && pMT->IsStructRequiringStackAllocRetBuf());
3934 EE_TO_JIT_TRANSITION_LEAF();
3939 /*********************************************************************/
3940 DWORD CEEInfo::getClassAttribsInternal (CORINFO_CLASS_HANDLE clsHnd)
3942 STANDARD_VM_CONTRACT;
3948 TypeHandle VMClsHnd(clsHnd);
3950 // Byrefs should only occur in method and local signatures, which are accessed
3951 // using ICorClassInfo and ICorClassInfo.getChildType.
3952 // So getClassAttribs() should not be called for byrefs
3954 if (VMClsHnd.IsByRef())
3956 _ASSERTE(!"Did findClass() return a Byref?");
3957 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3959 else if (VMClsHnd.IsGenericVariable())
3961 //@GENERICSVER: for now, type variables simply report "variable".
3962 ret |= CORINFO_FLG_GENERIC_TYPE_VARIABLE;
3966 MethodTable *pMT = VMClsHnd.GetMethodTable();
3970 _ASSERTE(!"Did findClass() return a Byref?");
3971 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3974 EEClass * pClass = pMT->GetClass();
3976 // The array flag is used to identify the faked-up methods on
3977 // array types, i.e. .ctor, Get, Set and Address
3979 ret |= CORINFO_FLG_ARRAY;
3981 if (pMT->IsInterface())
3982 ret |= CORINFO_FLG_INTERFACE;
3984 if (pMT->HasComponentSize())
3985 ret |= CORINFO_FLG_VAROBJSIZE;
3987 if (pMT->IsValueType())
3989 ret |= CORINFO_FLG_VALUECLASS;
3991 if (pMT->IsByRefLike())
3992 ret |= CORINFO_FLG_CONTAINS_STACK_PTR;
3994 if ((pClass->IsNotTightlyPacked() && (!pClass->IsManagedSequential() || pClass->HasExplicitSize())) ||
3995 pMT == g_TypedReferenceMT ||
3996 VMClsHnd.IsNativeValueType())
3998 ret |= CORINFO_FLG_CUSTOMLAYOUT;
4001 if (pClass->IsUnsafeValueClass())
4002 ret |= CORINFO_FLG_UNSAFE_VALUECLASS;
4004 if (pClass->HasExplicitFieldOffsetLayout() && pClass->HasOverLayedField())
4005 ret |= CORINFO_FLG_OVERLAPPING_FIELDS;
4006 if (VMClsHnd.IsCanonicalSubtype())
4007 ret |= CORINFO_FLG_SHAREDINST;
4009 if (pMT->HasVariance())
4010 ret |= CORINFO_FLG_VARIANCE;
4012 if (pMT->IsContextful())
4013 ret |= CORINFO_FLG_CONTEXTFUL;
4015 if (pMT->IsMarshaledByRef())
4016 ret |= CORINFO_FLG_MARSHAL_BYREF;
4018 if (pMT->ContainsPointers() || pMT == g_TypedReferenceMT)
4019 ret |= CORINFO_FLG_CONTAINS_GC_PTR;
4021 if (pMT->IsDelegate())
4022 ret |= CORINFO_FLG_DELEGATE;
4024 if (pClass->IsBeforeFieldInit())
4026 if (IsReadyToRunCompilation() && !pMT->GetModule()->IsInCurrentVersionBubble())
4028 // For version resiliency do not allow hoisting static constructors out of loops
4032 ret |= CORINFO_FLG_BEFOREFIELDINIT;
4036 if (pClass->IsAbstract())
4037 ret |= CORINFO_FLG_ABSTRACT;
4039 if (pClass->IsSealed())
4040 ret |= CORINFO_FLG_FINAL;
4042 if (pMT->IsIntrinsicType())
4043 ret |= CORINFO_FLG_INTRINSIC_TYPE;
4049 /*********************************************************************/
4051 // See code:CorInfoFlag#ClassConstructionFlags for details.
4053 CorInfoInitClassResult CEEInfo::initClass(
4054 CORINFO_FIELD_HANDLE field,
4055 CORINFO_METHOD_HANDLE method,
4056 CORINFO_CONTEXT_HANDLE context,
4066 DWORD result = CORINFO_INITCLASS_NOT_REQUIRED;
4068 JIT_TO_EE_TRANSITION();
4071 // Do not bother figuring out the initialization if we are only verifying the method.
4074 result = CORINFO_INITCLASS_NOT_REQUIRED;
4078 FieldDesc * pFD = (FieldDesc *)field;
4079 _ASSERTE(pFD == NULL || pFD->IsStatic());
4081 MethodDesc * pMD = (MethodDesc *)method;
4083 TypeHandle typeToInitTH = (pFD != NULL) ? pFD->GetEnclosingMethodTable() : GetTypeFromContext(context);
4085 MethodDesc *methodBeingCompiled = m_pMethodBeingCompiled;
4087 BOOL fMethodDomainNeutral = methodBeingCompiled->IsDomainNeutral() || methodBeingCompiled->IsZapped() || IsCompilingForNGen();
4089 MethodTable *pTypeToInitMT = typeToInitTH.AsMethodTable();
4091 // This should be the most common early-out case.
4092 if (fMethodDomainNeutral)
4094 if (pTypeToInitMT->IsClassPreInited())
4096 result = CORINFO_INITCLASS_NOT_REQUIRED;
4102 #ifdef CROSSGEN_COMPILE
4104 #else // CROSSGEN_COMPILE
4105 if (pTypeToInitMT->IsClassInited())
4107 // If the type is initialized there really is nothing to do.
4108 result = CORINFO_INITCLASS_INITIALIZED;
4111 #endif // CROSSGEN_COMPILE
4114 if (pTypeToInitMT->IsGlobalClass())
4116 // For both jitted and ngen code the global class is always considered initialized
4117 result = CORINFO_INITCLASS_NOT_REQUIRED;
4121 bool fIgnoreBeforeFieldInit = false;
4125 if (!fIgnoreBeforeFieldInit && pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4127 // We can wait for field accesses to run .cctor
4128 result = CORINFO_INITCLASS_NOT_REQUIRED;
4132 // Run .cctor on statics & constructors
4133 if (pMD->IsStatic())
4135 // Except don't class construct on .cctor - it would be circular
4136 if (pMD->IsClassConstructor())
4138 result = CORINFO_INITCLASS_NOT_REQUIRED;
4143 // According to the spec, we should be able to do this optimization for both reference and valuetypes.
4144 // To maintain backward compatibility, we are doing it for reference types only.
4145 // We don't do this for interfaces though, as those don't have instance constructors.
4146 if (!pMD->IsCtor() && !pTypeToInitMT->IsValueType() && !pTypeToInitMT->IsInterface())
4148 // For instance methods of types with precise-initialization
4149 // semantics, we can assume that the .ctor triggerred the
4150 // type initialization.
4151 // This does not hold for NULL "this" object. However, the spec does
4152 // not require that case to work.
4153 result = CORINFO_INITCLASS_NOT_REQUIRED;
4158 if (pTypeToInitMT->IsSharedByGenericInstantiations())
4160 // Shared generic code has to use helper. Moreover, tell JIT not to inline since
4161 // inlining of generic dictionary lookups is not supported.
4162 result = CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE;
4167 // Try to prove that the initialization is not necessary because of nesting
4173 _ASSERTE(fIgnoreBeforeFieldInit || !pTypeToInitMT->GetClass()->IsBeforeFieldInit());
4175 // Note that jit has both methods the same if asking whether to emit cctor
4176 // for a given method's code (as opposed to inlining codegen).
4177 if (context != MAKE_METHODCONTEXT(methodBeingCompiled) && pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4179 // If we're inling a call to a method in our own type, then we should already
4180 // have triggered the .cctor when caller was itself called.
4181 result = CORINFO_INITCLASS_NOT_REQUIRED;
4187 // This optimization may cause static fields in reference types to be accessed without cctor being triggered
4188 // for NULL "this" object. It does not conform with what the spec says. However, we have been historically
4189 // doing it for perf reasons.
4190 if (!pTypeToInitMT->IsValueType() && !pTypeToInitMT->IsInterface() && !pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4192 if (pTypeToInitMT == GetTypeFromContext(context).AsMethodTable() || pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4194 // The class will be initialized by the time we access the field.
4195 result = CORINFO_INITCLASS_NOT_REQUIRED;
4200 // If we are currently compiling the class constructor for this static field access then we can skip the initClass
4201 if (methodBeingCompiled->GetMethodTable() == pTypeToInitMT && methodBeingCompiled->IsStatic() && methodBeingCompiled->IsClassConstructor())
4203 // The class will be initialized by the time we access the field.
4204 result = CORINFO_INITCLASS_NOT_REQUIRED;
4209 if (fMethodDomainNeutral)
4211 // Well, because of code sharing we can't do anything at coge generation time.
4212 // We have to do it at runtime.
4213 result = CORINFO_INITCLASS_USE_HELPER;
4217 #ifndef CROSSGEN_COMPILE
4219 // Optimizations for domain specific code
4222 // Allocate space for the local class if necessary, but don't trigger
4223 // class construction.
4224 DomainLocalModule *pModule = pTypeToInitMT->GetDomainLocalModule();
4225 pModule->PopulateClass(pTypeToInitMT);
4227 if (pTypeToInitMT->IsClassInited())
4229 result = CORINFO_INITCLASS_INITIALIZED;
4232 #endif // CROSSGEN_COMPILE
4234 result = CORINFO_INITCLASS_USE_HELPER;
4237 EE_TO_JIT_TRANSITION();
4239 return (CorInfoInitClassResult)result;
4244 void CEEInfo::classMustBeLoadedBeforeCodeIsRun (CORINFO_CLASS_HANDLE typeToLoadHnd)
4253 JIT_TO_EE_TRANSITION_LEAF();
4255 TypeHandle th = TypeHandle(typeToLoadHnd);
4257 // Type handles returned to JIT at runtime are always fully loaded. Verify that it is the case.
4258 _ASSERTE(th.IsFullyLoaded());
4260 EE_TO_JIT_TRANSITION_LEAF();
4263 /*********************************************************************/
4264 void CEEInfo::methodMustBeLoadedBeforeCodeIsRun (CORINFO_METHOD_HANDLE methHnd)
4273 JIT_TO_EE_TRANSITION_LEAF();
4275 MethodDesc *pMD = (MethodDesc*) methHnd;
4277 // MethodDescs returned to JIT at runtime are always fully loaded. Verify that it is the case.
4278 _ASSERTE(pMD->IsRestored() && pMD->GetMethodTable()->IsFullyLoaded());
4280 EE_TO_JIT_TRANSITION_LEAF();
4283 /*********************************************************************/
4284 CORINFO_METHOD_HANDLE CEEInfo::mapMethodDeclToMethodImpl(CORINFO_METHOD_HANDLE methHnd)
4293 CORINFO_METHOD_HANDLE result = NULL;
4295 JIT_TO_EE_TRANSITION();
4297 MethodDesc *pMD = GetMethod(methHnd);
4298 pMD = MethodTable::MapMethodDeclToMethodImpl(pMD);
4299 result = (CORINFO_METHOD_HANDLE) pMD;
4301 EE_TO_JIT_TRANSITION();
4306 /*********************************************************************/
4307 CORINFO_CLASS_HANDLE CEEInfo::getBuiltinClass(CorInfoClassId classId)
4316 CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE) 0;
4318 JIT_TO_EE_TRANSITION();
4322 case CLASSID_SYSTEM_OBJECT:
4323 result = CORINFO_CLASS_HANDLE(g_pObjectClass);
4325 case CLASSID_TYPED_BYREF:
4326 result = CORINFO_CLASS_HANDLE(g_TypedReferenceMT);
4328 case CLASSID_TYPE_HANDLE:
4329 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__TYPE_HANDLE));
4331 case CLASSID_FIELD_HANDLE:
4332 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__FIELD_HANDLE));
4334 case CLASSID_METHOD_HANDLE:
4335 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__METHOD_HANDLE));
4337 case CLASSID_ARGUMENT_HANDLE:
4338 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__ARGUMENT_HANDLE));
4340 case CLASSID_STRING:
4341 result = CORINFO_CLASS_HANDLE(g_pStringClass);
4343 case CLASSID_RUNTIME_TYPE:
4344 result = CORINFO_CLASS_HANDLE(g_pRuntimeTypeClass);
4347 _ASSERTE(!"NYI: unknown classId");
4351 EE_TO_JIT_TRANSITION();
4358 /*********************************************************************/
4359 CorInfoType CEEInfo::getTypeForPrimitiveValueClass(
4360 CORINFO_CLASS_HANDLE clsHnd)
4369 CorInfoType result = CORINFO_TYPE_UNDEF;
4371 JIT_TO_EE_TRANSITION();
4373 TypeHandle th(clsHnd);
4374 _ASSERTE (!th.IsGenericVariable());
4376 MethodTable *pMT = th.GetMethodTable();
4377 PREFIX_ASSUME(pMT != NULL);
4379 // Is it a non primitive struct such as
4380 // RuntimeTypeHandle, RuntimeMethodHandle, RuntimeArgHandle?
4381 if (pMT->IsValueType() &&
4382 !pMT->IsTruePrimitive() &&
4385 // default value CORINFO_TYPE_UNDEF is what we want
4389 switch (th.GetInternalCorElementType())
4391 case ELEMENT_TYPE_I1:
4392 case ELEMENT_TYPE_U1:
4393 case ELEMENT_TYPE_BOOLEAN:
4394 result = asCorInfoType(ELEMENT_TYPE_I1);
4397 case ELEMENT_TYPE_I2:
4398 case ELEMENT_TYPE_U2:
4399 case ELEMENT_TYPE_CHAR:
4400 result = asCorInfoType(ELEMENT_TYPE_I2);
4403 case ELEMENT_TYPE_I4:
4404 case ELEMENT_TYPE_U4:
4405 result = asCorInfoType(ELEMENT_TYPE_I4);
4408 case ELEMENT_TYPE_I8:
4409 case ELEMENT_TYPE_U8:
4410 result = asCorInfoType(ELEMENT_TYPE_I8);
4413 case ELEMENT_TYPE_I:
4414 case ELEMENT_TYPE_U:
4415 result = asCorInfoType(ELEMENT_TYPE_I);
4418 case ELEMENT_TYPE_R4:
4419 result = asCorInfoType(ELEMENT_TYPE_R4);
4422 case ELEMENT_TYPE_R8:
4423 result = asCorInfoType(ELEMENT_TYPE_R8);
4426 case ELEMENT_TYPE_VOID:
4427 result = asCorInfoType(ELEMENT_TYPE_VOID);
4430 case ELEMENT_TYPE_PTR:
4431 case ELEMENT_TYPE_FNPTR:
4432 result = asCorInfoType(ELEMENT_TYPE_PTR);
4440 EE_TO_JIT_TRANSITION();
4445 /*********************************************************************/
4446 CorInfoType CEEInfo::getTypeForPrimitiveNumericClass(
4447 CORINFO_CLASS_HANDLE clsHnd)
4456 CorInfoType result = CORINFO_TYPE_UNDEF;
4458 JIT_TO_EE_TRANSITION_LEAF();
4460 TypeHandle th(clsHnd);
4461 _ASSERTE (!th.IsGenericVariable());
4463 CorElementType ty = th.GetSignatureCorElementType();
4466 case ELEMENT_TYPE_I1:
4467 result = CORINFO_TYPE_BYTE;
4469 case ELEMENT_TYPE_U1:
4470 result = CORINFO_TYPE_UBYTE;
4472 case ELEMENT_TYPE_I2:
4473 result = CORINFO_TYPE_SHORT;
4475 case ELEMENT_TYPE_U2:
4476 result = CORINFO_TYPE_USHORT;
4478 case ELEMENT_TYPE_I4:
4479 result = CORINFO_TYPE_INT;
4481 case ELEMENT_TYPE_U4:
4482 result = CORINFO_TYPE_UINT;
4484 case ELEMENT_TYPE_I8:
4485 result = CORINFO_TYPE_LONG;
4487 case ELEMENT_TYPE_U8:
4488 result = CORINFO_TYPE_ULONG;
4490 case ELEMENT_TYPE_R4:
4491 result = CORINFO_TYPE_FLOAT;
4493 case ELEMENT_TYPE_R8:
4494 result = CORINFO_TYPE_DOUBLE;
4498 // Error case, we will return CORINFO_TYPE_UNDEF
4502 JIT_TO_EE_TRANSITION_LEAF();
4508 void CEEInfo::getGSCookie(GSCookie * pCookieVal, GSCookie ** ppCookieVal)
4517 JIT_TO_EE_TRANSITION();
4521 *pCookieVal = GetProcessGSCookie();
4522 *ppCookieVal = NULL;
4526 *ppCookieVal = GetProcessGSCookiePtr();
4529 EE_TO_JIT_TRANSITION();
4533 /*********************************************************************/
4534 // TRUE if child is a subtype of parent
4535 // if parent is an interface, then does child implement / extend parent
4536 BOOL CEEInfo::canCast(
4537 CORINFO_CLASS_HANDLE child,
4538 CORINFO_CLASS_HANDLE parent)
4547 BOOL result = FALSE;
4549 JIT_TO_EE_TRANSITION();
4551 result = ((TypeHandle)child).CanCastTo((TypeHandle)parent);
4553 EE_TO_JIT_TRANSITION();
4558 /*********************************************************************/
4559 // TRUE if cls1 and cls2 are considered equivalent types.
4560 BOOL CEEInfo::areTypesEquivalent(
4561 CORINFO_CLASS_HANDLE cls1,
4562 CORINFO_CLASS_HANDLE cls2)
4571 BOOL result = FALSE;
4573 JIT_TO_EE_TRANSITION();
4575 result = ((TypeHandle)cls1).IsEquivalentTo((TypeHandle)cls2);
4577 EE_TO_JIT_TRANSITION();
4582 /*********************************************************************/
4583 // See if a cast from fromClass to toClass will succeed, fail, or needs
4584 // to be resolved at runtime.
4585 TypeCompareState CEEInfo::compareTypesForCast(
4586 CORINFO_CLASS_HANDLE fromClass,
4587 CORINFO_CLASS_HANDLE toClass)
4596 TypeCompareState result = TypeCompareState::May;
4598 JIT_TO_EE_TRANSITION();
4600 TypeHandle fromHnd = (TypeHandle) fromClass;
4601 TypeHandle toHnd = (TypeHandle) toClass;
4603 #ifdef FEATURE_COMINTEROP
4604 // If casting from a com object class, don't try to optimize.
4605 if (fromHnd.IsComObjectType())
4607 result = TypeCompareState::May;
4610 #endif // FEATURE_COMINTEROP
4612 // If casting from ICastable, don't try to optimize
4613 if (fromHnd.GetMethodTable()->IsICastable())
4615 result = TypeCompareState::May;
4617 // If casting to Nullable<T>, don't try to optimize
4618 else if (Nullable::IsNullableType(toHnd))
4620 result = TypeCompareState::May;
4622 // If the types are not shared, we can check directly.
4623 else if (!fromHnd.IsCanonicalSubtype() && !toHnd.IsCanonicalSubtype())
4625 result = fromHnd.CanCastTo(toHnd) ? TypeCompareState::Must : TypeCompareState::MustNot;
4627 // Casting from a shared type to an unshared type.
4628 else if (fromHnd.IsCanonicalSubtype() && !toHnd.IsCanonicalSubtype())
4630 // Only handle casts to interface types for now
4631 if (toHnd.IsInterface())
4633 // Do a preliminary check.
4634 BOOL canCast = fromHnd.CanCastTo(toHnd);
4636 // Pass back positive results unfiltered. The unknown type
4637 // parameters in fromClass did not come into play.
4640 result = TypeCompareState::Must;
4642 // For negative results, the unknown type parameter in
4643 // fromClass might match some instantiated interface,
4644 // either directly or via variance.
4646 // However, CanCastTo will report failure in such cases since
4647 // __Canon won't match the instantiated type on the
4648 // interface (which can't be __Canon since we screened out
4649 // canonical subtypes for toClass above). So only report
4650 // failure if the interface is not instantiated.
4651 else if (!toHnd.HasInstantiation())
4653 result = TypeCompareState::MustNot;
4658 #ifdef FEATURE_READYTORUN_COMPILER
4659 // In R2R it is a breaking change for a previously positive
4660 // cast to become negative, but not for a previously negative
4661 // cast to become positive. So in R2R a negative result is
4662 // always reported back as May.
4663 if (IsReadyToRunCompilation() && (result == TypeCompareState::MustNot))
4665 result = TypeCompareState::May;
4667 #endif // FEATURE_READYTORUN_COMPILER
4669 EE_TO_JIT_TRANSITION();
4674 /*********************************************************************/
4675 // See if types represented by cls1 and cls2 compare equal, not
4676 // equal, or the comparison needs to be resolved at runtime.
4677 TypeCompareState CEEInfo::compareTypesForEquality(
4678 CORINFO_CLASS_HANDLE cls1,
4679 CORINFO_CLASS_HANDLE cls2)
4688 TypeCompareState result = TypeCompareState::May;
4690 JIT_TO_EE_TRANSITION();
4692 TypeHandle hnd1 = (TypeHandle) cls1;
4693 TypeHandle hnd2 = (TypeHandle) cls2;
4695 // If neither type is a canonical subtype, type handle comparison suffices
4696 if (!hnd1.IsCanonicalSubtype() && !hnd2.IsCanonicalSubtype())
4698 result = (hnd1 == hnd2 ? TypeCompareState::Must : TypeCompareState::MustNot);
4700 // If either or both types are canonical subtypes, we can sometimes prove inequality.
4703 // If either is a value type then the types cannot
4704 // be equal unless the type defs are the same.
4705 if (hnd1.IsValueType() || hnd2.IsValueType())
4707 if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
4709 result = TypeCompareState::MustNot;
4712 // If we have two ref types that are not __Canon, then the
4713 // types cannot be equal unless the type defs are the same.
4716 TypeHandle canonHnd = TypeHandle(g_pCanonMethodTableClass);
4717 if ((hnd1 != canonHnd) && (hnd2 != canonHnd))
4719 if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
4721 result = TypeCompareState::MustNot;
4727 EE_TO_JIT_TRANSITION();
4732 /*********************************************************************/
4733 // returns is the intersection of cls1 and cls2.
4734 CORINFO_CLASS_HANDLE CEEInfo::mergeClasses(
4735 CORINFO_CLASS_HANDLE cls1,
4736 CORINFO_CLASS_HANDLE cls2)
4745 CORINFO_CLASS_HANDLE result = NULL;
4747 JIT_TO_EE_TRANSITION();
4749 TypeHandle merged = TypeHandle::MergeTypeHandlesToCommonParent(TypeHandle(cls1), TypeHandle(cls2));
4752 //Make sure the merge is reflexive in the cases we "support".
4753 TypeHandle hnd1 = TypeHandle(cls1);
4754 TypeHandle hnd2 = TypeHandle(cls2);
4755 TypeHandle reflexive = TypeHandle::MergeTypeHandlesToCommonParent(hnd2, hnd1);
4757 //If both sides are classes than either they have a common non-interface parent (in which case it is
4759 //OR they share a common interface, and it can be order dependent (if they share multiple interfaces
4761 if (!hnd1.IsInterface() && !hnd2.IsInterface())
4763 if (merged.IsInterface())
4765 _ASSERTE(reflexive.IsInterface());
4769 _ASSERTE(merged == reflexive);
4772 //Both results must either be interfaces or classes. They cannot be mixed.
4773 _ASSERTE((!!merged.IsInterface()) == (!!reflexive.IsInterface()));
4775 //If the result of the merge was a class, then the result of the reflexive merge was the same class.
4776 if (!merged.IsInterface())
4778 _ASSERTE(merged == reflexive);
4781 //If both sides are arrays, then the result is either an array or g_pArrayClass. The above is
4782 //actually true about the element type for references types, but I think that that is a little
4783 //excessive for sanity.
4784 if (hnd1.IsArray() && hnd2.IsArray())
4786 _ASSERTE((merged.IsArray() && reflexive.IsArray())
4787 || ((merged == g_pArrayClass) && (reflexive == g_pArrayClass)));
4790 //Can I assert anything about generic variables?
4792 //The results must always be assignable
4793 _ASSERTE(hnd1.CanCastTo(merged) && hnd2.CanCastTo(merged) && hnd1.CanCastTo(reflexive)
4794 && hnd2.CanCastTo(reflexive));
4797 result = CORINFO_CLASS_HANDLE(merged.AsPtr());
4799 EE_TO_JIT_TRANSITION();
4803 /*********************************************************************/
4804 // Given a class handle, returns the Parent type.
4805 // For COMObjectType, it returns Class Handle of System.Object.
4806 // Returns 0 if System.Object is passed in.
4807 CORINFO_CLASS_HANDLE CEEInfo::getParentType(
4808 CORINFO_CLASS_HANDLE cls)
4817 CORINFO_CLASS_HANDLE result = NULL;
4819 JIT_TO_EE_TRANSITION();
4823 _ASSERTE(!th.IsNull());
4824 _ASSERTE(!th.IsGenericVariable());
4826 TypeHandle thParent = th.GetParent();
4828 #ifdef FEATURE_COMINTEROP
4829 // If we encounter __ComObject in the hierarchy, we need to skip it
4830 // since this hierarchy is introduced by the EE, but won't be present
4832 if (!thParent.IsNull() && IsComObjectClass(thParent))
4834 result = (CORINFO_CLASS_HANDLE) g_pObjectClass;
4837 #endif // FEATURE_COMINTEROP
4839 result = CORINFO_CLASS_HANDLE(thParent.AsPtr());
4842 EE_TO_JIT_TRANSITION();
4848 /*********************************************************************/
4849 // Returns the CorInfoType of the "child type". If the child type is
4850 // not a primitive type, *clsRet will be set.
4851 // Given an Array of Type Foo, returns Foo.
4852 // Given BYREF Foo, returns Foo
4853 CorInfoType CEEInfo::getChildType (
4854 CORINFO_CLASS_HANDLE clsHnd,
4855 CORINFO_CLASS_HANDLE *clsRet
4865 CorInfoType ret = CORINFO_TYPE_UNDEF;
4867 TypeHandle retType = TypeHandle();
4869 JIT_TO_EE_TRANSITION();
4871 TypeHandle th(clsHnd);
4873 _ASSERTE(!th.IsNull());
4875 // BYREF, ARRAY types
4876 if (th.IsTypeDesc())
4878 retType = th.AsTypeDesc()->GetTypeParam();
4882 // <REVISIT_TODO> we really should not have this case. arrays type handles
4883 // used in the JIT interface should never be ordinary method tables,
4884 // indeed array type handles should really never be ordinary MTs
4885 // at all. Perhaps we should assert !th.IsTypeDesc() && th.AsMethodTable().IsArray()? </REVISIT_TODO>
4886 MethodTable* pMT= th.AsMethodTable();
4888 retType = pMT->GetApproxArrayElementTypeHandle();
4891 if (!retType.IsNull()) {
4892 CorElementType type = retType.GetInternalCorElementType();
4893 ret = CEEInfo::asCorInfoType(type,retType, clsRet);
4895 // <REVISIT_TODO>What if this one is a value array ?</REVISIT_TODO>
4898 EE_TO_JIT_TRANSITION();
4903 /*********************************************************************/
4904 // Check any constraints on class type arguments
4905 BOOL CEEInfo::satisfiesClassConstraints(CORINFO_CLASS_HANDLE cls)
4914 BOOL result = FALSE;
4916 JIT_TO_EE_TRANSITION();
4918 _ASSERTE(cls != NULL);
4919 result = TypeHandle(cls).SatisfiesClassConstraints();
4921 EE_TO_JIT_TRANSITION();
4926 /*********************************************************************/
4927 // Check if this is a single dimensional array type
4928 BOOL CEEInfo::isSDArray(CORINFO_CLASS_HANDLE cls)
4937 BOOL result = FALSE;
4939 JIT_TO_EE_TRANSITION();
4943 _ASSERTE(!th.IsNull());
4945 if (th.IsArrayType())
4947 // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4948 _ASSERTE(th != TypeHandle(g_pArrayClass));
4950 result = (th.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
4953 EE_TO_JIT_TRANSITION();
4958 /*********************************************************************/
4959 // Get the number of dimensions in an array
4960 unsigned CEEInfo::getArrayRank(CORINFO_CLASS_HANDLE cls)
4969 unsigned result = 0;
4971 JIT_TO_EE_TRANSITION();
4975 _ASSERTE(!th.IsNull());
4977 if (th.IsArrayType())
4979 // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4980 _ASSERTE(th != TypeHandle(g_pArrayClass));
4982 result = th.GetPossiblySharedArrayMethodTable()->GetRank();
4985 EE_TO_JIT_TRANSITION();
4990 /*********************************************************************/
4991 // Get static field data for an array
4992 // Note that it's OK to return NULL from this method. This will cause
4993 // the JIT to make a runtime call to InitializeArray instead of doing
4994 // the inline optimization (thus preserving the original behavior).
4995 void * CEEInfo::getArrayInitializationData(
4996 CORINFO_FIELD_HANDLE field,
5007 void * result = NULL;
5009 JIT_TO_EE_TRANSITION();
5011 FieldDesc* pField = (FieldDesc*) field;
5015 (pField->LoadSize() < size)
5016 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
5017 // This will make sure that when IBC logging is on, the array initialization happens thru
5018 // COMArrayInfo::InitializeArray. This gives a place to put the IBC probe that can help
5019 // separate hold and cold RVA blobs.
5020 || (IsCompilingForNGen() &&
5021 GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
5022 #endif // FEATURE_NATIVE_IMAGE_GENERATION
5029 result = pField->GetStaticAddressHandle(NULL);
5032 EE_TO_JIT_TRANSITION();
5037 CorInfoIsAccessAllowedResult CEEInfo::canAccessClass(
5038 CORINFO_RESOLVED_TOKEN * pResolvedToken,
5039 CORINFO_METHOD_HANDLE callerHandle,
5040 CORINFO_HELPER_DESC *pAccessHelper
5050 CorInfoIsAccessAllowedResult isAccessAllowed = CORINFO_ACCESS_ALLOWED;
5052 JIT_TO_EE_TRANSITION();
5054 INDEBUG(memset(pAccessHelper, 0xCC, sizeof(*pAccessHelper)));
5056 BOOL doAccessCheck = TRUE;
5057 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
5058 DynamicResolver * pAccessContext = NULL;
5060 //All access checks must be done on the open instantiation.
5061 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
5062 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5064 TypeHandle pCalleeForSecurity = TypeHandle(pResolvedToken->hClass);
5065 if (pResolvedToken->pTypeSpec != NULL)
5067 SigTypeContext typeContext;
5068 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
5070 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
5071 pCalleeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5074 while (pCalleeForSecurity.HasTypeParam())
5076 pCalleeForSecurity = pCalleeForSecurity.GetTypeParam();
5079 if (IsDynamicScope(pResolvedToken->tokenScope))
5081 doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope),
5082 &callerTypeForSecurity, &accessCheckType,
5086 //Since this is a check against a TypeHandle, there are some things we can stick in a TypeHandle that
5087 //don't require access checks.
5088 if (pCalleeForSecurity.IsGenericVariable())
5090 //I don't need to check for access against !!0.
5091 doAccessCheck = FALSE;
5094 //Now do the visibility checks
5097 AccessCheckOptions accessCheckOptions(accessCheckType,
5099 FALSE /*throw on error*/,
5100 pCalleeForSecurity.GetMethodTable());
5102 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5103 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5105 BOOL canAccessType = ClassLoader::CanAccessClass(&accessContext,
5106 pCalleeForSecurity.GetMethodTable(),
5107 pCalleeForSecurity.GetAssembly(),
5108 accessCheckOptions);
5110 isAccessAllowed = canAccessType ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
5114 if (isAccessAllowed != CORINFO_ACCESS_ALLOWED)
5116 //These all get the throw helper
5117 pAccessHelper->helperNum = CORINFO_HELP_CLASS_ACCESS_EXCEPTION;
5118 pAccessHelper->numArgs = 2;
5120 pAccessHelper->args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5121 pAccessHelper->args[1].Set(CORINFO_CLASS_HANDLE(pCalleeForSecurity.AsPtr()));
5123 if (IsCompilingForNGen())
5125 //see code:CEEInfo::getCallInfo for more information.
5126 if (pCallerForSecurity->ContainsGenericVariables() || pCalleeForSecurity.ContainsGenericVariables())
5127 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic TypeHandle"));
5131 EE_TO_JIT_TRANSITION();
5132 return isAccessAllowed;
5135 /***********************************************************************/
5136 // return the address of a pointer to a callable stub that will do the
5137 // virtual or interface call
5138 void CEEInfo::getCallInfo(
5139 CORINFO_RESOLVED_TOKEN * pResolvedToken,
5140 CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
5141 CORINFO_METHOD_HANDLE callerHandle,
5142 CORINFO_CALLINFO_FLAGS flags,
5143 CORINFO_CALL_INFO *pResult /*out */)
5152 JIT_TO_EE_TRANSITION();
5154 _ASSERTE(CheckPointer(pResult));
5156 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
5158 pResult->stubLookup.lookupKind.needsRuntimeLookup = false;
5160 MethodDesc* pMD = (MethodDesc *)pResolvedToken->hMethod;
5161 TypeHandle th(pResolvedToken->hClass);
5164 _ASSERTE((size_t(pMD) & 0x1) == 0);
5166 // Spec says that a callvirt lookup ignores static methods. Since static methods
5167 // can't have the exact same signature as instance methods, a lookup that found
5168 // a static method would have never found an instance method.
5169 if (pMD->IsStatic() && (flags & CORINFO_CALLINFO_CALLVIRT))
5171 EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, W("?")));
5174 TypeHandle exactType = TypeHandle(pResolvedToken->hClass);
5176 TypeHandle constrainedType;
5177 if ((flags & CORINFO_CALLINFO_CALLVIRT) && (pConstrainedResolvedToken != NULL))
5179 constrainedType = TypeHandle(pConstrainedResolvedToken->hClass);
5182 BOOL fResolvedConstraint = FALSE;
5183 BOOL fForceUseRuntimeLookup = FALSE;
5185 MethodDesc * pMDAfterConstraintResolution = pMD;
5186 if (constrainedType.IsNull())
5188 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5190 // <NICE> Things go wrong when this code path is used when verifying generic code.
5191 // It would be nice if we didn't go down this sort of code path when verifying but
5192 // not generating code. </NICE>
5193 else if (constrainedType.ContainsGenericVariables() || exactType.ContainsGenericVariables())
5195 // <NICE> It shouldn't really matter what we do here - but the x86 JIT is annoyingly sensitive
5196 // about what we do, since it pretend generic variables are reference types and generates
5197 // an internal JIT tree even when just verifying generic code. </NICE>
5198 if (constrainedType.IsGenericVariable())
5200 pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &T --> T
5202 else if (constrainedType.IsValueType())
5204 pResult->thisTransform = CORINFO_BOX_THIS; // convert 'this' of type &VC<T> --> boxed(VC<T>)
5208 pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &C<T> --> C<T>
5213 // We have a "constrained." call. Try a partial resolve of the constraint call. Note that this
5214 // will not necessarily resolve the call exactly, since we might be compiling
5215 // shared generic code - it may just resolve it to a candidate suitable for
5216 // JIT compilation, and require a runtime lookup for the actual code pointer
5218 if (constrainedType.IsEnum())
5220 // Optimize constrained calls to enum's GetHashCode method. TryResolveConstraintMethodApprox would return
5221 // null since the virtual method resolves to System.Enum's implementation and that's a reference type.
5222 // We can't do this for any other method since ToString and Equals have different semantics for enums
5223 // and their underlying type.
5224 if (pMD->GetSlot() == MscorlibBinder::GetMethod(METHOD__OBJECT__GET_HASH_CODE)->GetSlot())
5226 // Pretend this was a "constrained. UnderlyingType" instruction prefix
5227 constrainedType = TypeHandle(MscorlibBinder::GetElementType(constrainedType.GetVerifierCorElementType()));
5229 // Native image signature encoder will use this field. It needs to match that pretended type, a bogus signature
5230 // would be produced otherwise.
5231 pConstrainedResolvedToken->hClass = (CORINFO_CLASS_HANDLE)constrainedType.AsPtr();
5233 // Clear the token and typespec because of they do not match hClass anymore.
5234 pConstrainedResolvedToken->token = mdTokenNil;
5235 pConstrainedResolvedToken->pTypeSpec = NULL;
5239 MethodDesc * directMethod = constrainedType.GetMethodTable()->TryResolveConstraintMethodApprox(
5242 &fForceUseRuntimeLookup);
5246 // 1. no constraint resolution at compile time (!directMethod)
5247 // OR 2. no code sharing lookup in call
5248 // OR 3. we have have resolved to an instantiating stub
5250 pMDAfterConstraintResolution = directMethod;
5251 _ASSERTE(!pMDAfterConstraintResolution->IsInterface());
5252 fResolvedConstraint = TRUE;
5253 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5255 exactType = constrainedType;
5257 else if (constrainedType.IsValueType())
5259 pResult->thisTransform = CORINFO_BOX_THIS;
5263 pResult->thisTransform = CORINFO_DEREF_THIS;
5268 // Initialize callee context used for inlining and instantiation arguments
5271 MethodDesc * pTargetMD = pMDAfterConstraintResolution;
5273 if (pTargetMD->HasMethodInstantiation())
5275 pResult->contextHandle = MAKE_METHODCONTEXT(pTargetMD);
5276 pResult->exactContextNeedsRuntimeLookup = pTargetMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(pTargetMD->GetMethodInstantiation());
5280 if (!exactType.IsTypeDesc())
5282 // Because of .NET's notion of base calls, exactType may point to a sub-class
5283 // of the actual class that defines pTargetMD. If the JIT decides to inline, it is
5284 // important that they 'match', so we fix exactType here.
5285 #ifdef FEATURE_READYTORUN_COMPILER
5286 if (IsReadyToRunCompilation() &&
5288 !IsInSameVersionBubble((MethodDesc*)callerHandle, pTargetMD))
5290 // For version resilient code we can only inline within the same version bubble;
5291 // we "repair" the precise types only for those callees.
5292 // The above condition needs to stay in sync with CEEInfo::canInline
5298 exactType = pTargetMD->GetExactDeclaringType(exactType.AsMethodTable());
5299 _ASSERTE(!exactType.IsNull());
5303 pResult->contextHandle = MAKE_CLASSCONTEXT(exactType.AsPtr());
5304 pResult->exactContextNeedsRuntimeLookup = exactType.IsSharedByGenericInstantiations();
5308 // Determine whether to perform direct call
5311 bool directCall = false;
5312 bool resolvedCallVirt = false;
5313 bool callVirtCrossingVersionBubble = false;
5315 // Delegate targets are always treated as direct calls here. (It would be nice to clean it up...).
5316 if (flags & CORINFO_CALLINFO_LDFTN)
5318 if (m_pOverride != NULL)
5319 TypeEquivalenceFixupSpecificationHelper(m_pOverride, pTargetMD);
5323 // Static methods are always direct calls
5324 if (pTargetMD->IsStatic())
5329 // Backwards compat: calls to abstract interface methods are treated as callvirt
5330 if (pTargetMD->GetMethodTable()->IsInterface() && pTargetMD->IsAbstract())
5335 if (!(flags & CORINFO_CALLINFO_CALLVIRT) || fResolvedConstraint)
5343 #ifdef FEATURE_READYTORUN_COMPILER
5345 // if we are generating version resilient code
5347 // caller/callee are in different version bubbles
5348 // we have to apply more restrictive rules
5349 // These rules are related to the "inlining rules" as far as the
5350 // boundaries of a version bubble are concerned.
5352 if (IsReadyToRunCompilation() &&
5354 !IsInSameVersionBubble((MethodDesc*)callerHandle, pTargetMD)
5357 // For version resiliency we won't de-virtualize all final/sealed method calls. Because during a
5358 // servicing event it is legal to unseal a method or type.
5360 // Note that it is safe to devirtualize in the following cases, since a servicing event cannot later modify it
5361 // 1) Callvirt on a virtual final method of a value type - since value types are sealed types as per ECMA spec
5362 // 2) Delegate.Invoke() - since a Delegate is a sealed class as per ECMA spec
5363 // 3) JIT intrinsics - since they have pre-defined behavior
5364 devirt = pTargetMD->GetMethodTable()->IsValueType() ||
5365 (pTargetMD->GetMethodTable()->IsDelegate() && ((DelegateEEClass*)(pTargetMD->GetMethodTable()->GetClass()))->GetInvokeMethod() == pMD) ||
5366 (pTargetMD->IsFCall() && ECall::GetIntrinsicID(pTargetMD) != CORINFO_INTRINSIC_Illegal);
5368 callVirtCrossingVersionBubble = true;
5372 if (pTargetMD->GetMethodTable()->IsInterface())
5374 // Handle interface methods specially because the Sealed bit has no meaning on interfaces.
5375 devirt = !IsMdVirtual(pTargetMD->GetAttrs());
5379 DWORD dwMethodAttrs = pTargetMD->GetAttrs();
5380 devirt = !IsMdVirtual(dwMethodAttrs) || IsMdFinal(dwMethodAttrs) || pTargetMD->GetMethodTable()->IsSealed();
5385 resolvedCallVirt = true;
5392 bool allowInstParam = (flags & CORINFO_CALLINFO_ALLOWINSTPARAM);
5394 // Create instantiating stub if necesary
5395 if (!allowInstParam && pTargetMD->RequiresInstArg())
5397 pTargetMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pTargetMD,
5398 exactType.AsMethodTable(),
5399 FALSE /* forceBoxedEntryPoint */,
5400 pTargetMD->GetMethodInstantiation(),
5401 FALSE /* allowInstParam */);
5404 // We don't allow a JIT to call the code directly if a runtime lookup is
5405 // needed. This is the case if
5406 // 1. the scan of the call token indicated that it involves code sharing
5407 // AND 2. the method is an instantiating stub
5409 // In these cases the correct instantiating stub is only found via a runtime lookup.
5411 // Note that most JITs don't call instantiating stubs directly if they can help it -
5412 // they call the underlying shared code and provide the type context parameter
5413 // explicitly. However
5414 // (a) some JITs may call instantiating stubs (it makes the JIT simpler) and
5415 // (b) if the method is a remote stub then the EE will force the
5416 // call through an instantiating stub and
5417 // (c) constraint calls that require runtime context lookup are never resolved
5418 // to underlying shared generic code
5420 if (((pResult->exactContextNeedsRuntimeLookup && pTargetMD->IsInstantiatingStub() && (!allowInstParam || fResolvedConstraint)) || fForceUseRuntimeLookup)
5421 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
5422 && ContextIsShared(pResolvedToken->tokenContext))
5424 _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5425 pResult->kind = CORINFO_CALL_CODE_POINTER;
5427 // For reference types, the constrained type does not affect method resolution
5428 DictionaryEntryKind entryKind = (!constrainedType.IsNull() && constrainedType.IsValueType()) ? ConstrainedMethodEntrySlot : MethodEntrySlot;
5430 ComputeRuntimeLookupForSharedGenericToken(entryKind,
5432 pConstrainedResolvedToken,
5434 &pResult->codePointerLookup);
5438 if (allowInstParam && pTargetMD->IsInstantiatingStub())
5440 pTargetMD = pTargetMD->GetWrappedMethodDesc();
5443 pResult->kind = CORINFO_CALL;
5445 if (IsReadyToRunCompilation())
5447 // Compensate for always treating delegates as direct calls above
5448 if ((flags & CORINFO_CALLINFO_LDFTN) && (flags & CORINFO_CALLINFO_CALLVIRT) && !resolvedCallVirt)
5450 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5454 pResult->nullInstanceCheck = resolvedCallVirt;
5456 // All virtual calls which take method instantiations must
5457 // currently be implemented by an indirect call via a runtime-lookup
5459 else if (pTargetMD->HasMethodInstantiation())
5461 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN; // stub dispatch can't handle generic method calls yet
5462 pResult->nullInstanceCheck = TRUE;
5464 // Non-interface dispatches go through the vtable.
5465 else if (!pTargetMD->IsInterface())
5467 pResult->kind = CORINFO_VIRTUALCALL_VTABLE;
5468 pResult->nullInstanceCheck = TRUE;
5470 // We'll special virtual calls to target methods in the corelib assembly when compiling in R2R mode, and generate fragile-NI-like callsites for improved performance. We
5471 // can do that because today we'll always service the corelib assembly and the runtime in one bundle. Any caller in the corelib version bubble can benefit from this
5472 // performance optimization.
5473 if (IsReadyToRunCompilation() && !CallerAndCalleeInSystemVersionBubble((MethodDesc*)callerHandle, pTargetMD))
5475 pResult->kind = CORINFO_VIRTUALCALL_STUB;
5480 if (IsReadyToRunCompilation())
5482 // Insert explicit null checks for cross-version bubble non-interface calls.
5483 // It is required to handle null checks properly for non-virtual <-> virtual change between versions
5484 pResult->nullInstanceCheck = !!(callVirtCrossingVersionBubble && !pTargetMD->IsInterface());
5488 // No need to null check - the dispatch code will deal with null this.
5489 pResult->nullInstanceCheck = FALSE;
5491 #ifdef STUB_DISPATCH_PORTABLE
5492 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5493 #else // STUB_DISPATCH_PORTABLE
5494 pResult->kind = CORINFO_VIRTUALCALL_STUB;
5496 // We can't make stub calls when we need exact information
5497 // for interface calls from shared code.
5499 if (// If the token is not shared then we don't need a runtime lookup
5500 pResult->exactContextNeedsRuntimeLookup
5501 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
5502 && ContextIsShared(pResolvedToken->tokenContext))
5504 _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5506 ComputeRuntimeLookupForSharedGenericToken(DispatchStubAddrSlot,
5510 &pResult->stubLookup);
5514 BYTE * indcell = NULL;
5516 if (!(flags & CORINFO_CALLINFO_KINDONLY) && !isVerifyOnly())
5518 #ifndef CROSSGEN_COMPILE
5519 // We shouldn't be using GetLoaderAllocator here because for LCG, we need to get the
5520 // VirtualCallStubManager from where the stub will be used.
5521 // For normal methods there is no difference.
5522 LoaderAllocator *pLoaderAllocator = m_pMethodBeingCompiled->GetLoaderAllocatorForCode();
5523 VirtualCallStubManager *pMgr = pLoaderAllocator->GetVirtualCallStubManager();
5525 PCODE addr = pMgr->GetCallStub(exactType, pTargetMD);
5526 _ASSERTE(pMgr->isStub(addr));
5528 // Now we want to indirect through a cell so that updates can take place atomically.
5529 if (m_pMethodBeingCompiled->IsLCGMethod())
5531 // LCG methods should use recycled indcells to prevent leaks.
5532 indcell = pMgr->GenerateStubIndirection(addr, TRUE);
5534 // Add it to the per DM list so that we can recycle them when the resolver is finalized
5535 LCGMethodResolver *pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetLCGMethodResolver();
5536 pResolver->AddToUsedIndCellList(indcell);
5540 // Normal methods should avoid recycled cells to preserve the locality of all indcells
5541 // used by one method.
5542 indcell = pMgr->GenerateStubIndirection(addr, FALSE);
5544 #else // CROSSGEN_COMPILE
5545 // This path should be unreachable during crossgen
5547 #endif // CROSSGEN_COMPILE
5550 // We use an indirect call
5551 pResult->stubLookup.constLookup.accessType = IAT_PVALUE;
5552 pResult->stubLookup.constLookup.addr = indcell;
5554 #endif // STUB_DISPATCH_PORTABLE
5557 pResult->hMethod = CORINFO_METHOD_HANDLE(pTargetMD);
5559 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5560 if ((flags & CORINFO_CALLINFO_SECURITYCHECKS) &&
5561 !((MethodDesc *)callerHandle)->IsILStub()) // IL stubs can access everything, don't bother doing access checks
5563 //Our type system doesn't always represent the target exactly with the MethodDesc. In all cases,
5564 //carry around the parent MethodTable for both Caller and Callee.
5565 TypeHandle calleeTypeForSecurity = TypeHandle(pResolvedToken->hClass);
5566 MethodDesc * pCalleeForSecurity = pMD;
5568 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle); //Should this be the open MD?
5570 if (pCallerForSecurity->HasClassOrMethodInstantiation())
5572 _ASSERTE(!IsDynamicScope(pResolvedToken->tokenScope));
5574 SigTypeContext typeContext;
5575 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
5576 _ASSERTE(!typeContext.IsEmpty());
5578 //If the caller is generic, load the open type and resolve the token again. Use that for the access
5579 //checks. If we don't do this then we can't tell the difference between:
5581 //BadGeneric<T> containing a methodspec for InaccessibleType::member (illegal)
5583 //BadGeneric<T> containing a methodspec for !!0::member instantiated over InaccessibleType (legal)
5585 if (pResolvedToken->pTypeSpec != NULL)
5587 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
5588 calleeTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5590 // typeHnd can be a variable type
5591 if (calleeTypeForSecurity.GetMethodTable() == NULL)
5593 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
5597 if (pCalleeForSecurity->IsArray())
5599 // FindOrCreateAssociatedMethodDesc won't remap array method desc because of array base type
5600 // is not part of instantiation. We have to special case it.
5601 pCalleeForSecurity = calleeTypeForSecurity.GetMethodTable()->GetParallelMethodDesc(pCalleeForSecurity);
5604 if (pResolvedToken->pMethodSpec != NULL)
5606 DWORD nGenericMethodArgs = 0;
5607 CQuickBytes qbGenericMethodArgs;
5608 TypeHandle *genericMethodArgs = NULL;
5610 SigPointer sp(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
5613 IfFailThrow(sp.GetByte(&etype));
5615 // Load the generic method instantiation
5616 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, (Module *)pResolvedToken->tokenScope);
5618 IfFailThrow(sp.GetData(&nGenericMethodArgs));
5620 DWORD cbAllocSize = 0;
5621 if (!ClrSafeInt<DWORD>::multiply(nGenericMethodArgs, sizeof(TypeHandle), cbAllocSize))
5623 COMPlusThrowHR(COR_E_OVERFLOW);
5626 genericMethodArgs = reinterpret_cast<TypeHandle *>(qbGenericMethodArgs.AllocThrows(cbAllocSize));
5628 for (DWORD i = 0; i < nGenericMethodArgs; i++)
5630 genericMethodArgs[i] = sp.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5631 _ASSERTE (!genericMethodArgs[i].IsNull());
5632 IfFailThrow(sp.SkipExactlyOne());
5635 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(genericMethodArgs, nGenericMethodArgs), FALSE);
5638 if (pResolvedToken->pTypeSpec != NULL)
5640 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(), TRUE);
5644 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5646 //Passed various link-time checks. Now do access checks.
5648 BOOL doAccessCheck = TRUE;
5649 BOOL canAccessMethod = TRUE;
5650 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
5651 DynamicResolver * pAccessContext = NULL;
5653 callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5654 if (pCallerForSecurity->IsDynamicMethod())
5656 doAccessCheck = ModifyCheckForDynamicMethod(pCallerForSecurity->AsDynamicMethodDesc()->GetResolver(),
5657 &callerTypeForSecurity,
5658 &accessCheckType, &pAccessContext);
5661 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5665 AccessCheckOptions accessCheckOptions(accessCheckType,
5668 pCalleeForSecurity);
5670 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5671 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5673 canAccessMethod = ClassLoader::CanAccess(&accessContext,
5674 calleeTypeForSecurity.GetMethodTable(),
5675 calleeTypeForSecurity.GetAssembly(),
5676 pCalleeForSecurity->GetAttrs(),
5682 // If we were allowed access to the exact method, but it is on a type that has a type parameter
5683 // (for instance an array), we need to ensure that we also have access to the type parameter.
5684 if (canAccessMethod && calleeTypeForSecurity.HasTypeParam())
5686 TypeHandle typeParam = calleeTypeForSecurity.GetTypeParam();
5687 while (typeParam.HasTypeParam())
5689 typeParam = typeParam.GetTypeParam();
5692 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5693 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5695 MethodTable* pTypeParamMT = typeParam.GetMethodTable();
5697 // No access check is need for Var, MVar, or FnPtr.
5698 if (pTypeParamMT != NULL)
5699 canAccessMethod = ClassLoader::CanAccessClass(&accessContext,
5701 typeParam.GetAssembly(),
5702 accessCheckOptions);
5705 pResult->accessAllowed = canAccessMethod ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
5706 if (!canAccessMethod)
5708 //Check failed, fill in the throw exception helper.
5709 pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_METHOD_ACCESS_EXCEPTION;
5710 pResult->callsiteCalloutHelper.numArgs = 2;
5712 pResult->callsiteCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5713 pResult->callsiteCalloutHelper.args[1].Set(CORINFO_METHOD_HANDLE(pCalleeForSecurity));
5715 //We now embed open instantiations in a few places for security callouts (since you can only
5716 //do the security check on the open instantiation). We throw these methods out in
5717 //TriageMethodForZap. In addition, NGen has problems referencing them properly. Just throw out the whole
5718 //method and rejit at runtime.
5719 if (IsCompilingForNGen())
5721 if (pCallerForSecurity->ContainsGenericVariables()
5722 || pCalleeForSecurity->ContainsGenericVariables())
5724 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
5731 //We're pretty much done at this point. Let's grab the rest of the information that the jit is going to
5733 pResult->classFlags = getClassAttribsInternal(pResolvedToken->hClass);
5735 pResult->methodFlags = getMethodAttribsInternal(pResult->hMethod);
5737 SignatureKind signatureKind = flags & CORINFO_CALLINFO_CALLVIRT ? SK_VIRTUAL_CALLSITE : SK_CALLSITE;
5738 getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL, signatureKind);
5740 if (flags & CORINFO_CALLINFO_VERIFICATION)
5742 if (pResult->hMethod != pResolvedToken->hMethod)
5744 pResult->verMethodFlags = getMethodAttribsInternal(pResolvedToken->hMethod);
5745 getMethodSigInternal(pResolvedToken->hMethod, &pResult->verSig, pResolvedToken->hClass);
5749 pResult->verMethodFlags = pResult->methodFlags;
5750 pResult->verSig = pResult->sig;
5754 pResult->secureDelegateInvoke = FALSE;
5756 #ifdef FEATURE_STUBS_AS_IL
5757 if (m_pMethodBeingCompiled->IsDynamicMethod())
5759 auto pMD = m_pMethodBeingCompiled->AsDynamicMethodDesc();
5760 if (pMD->IsILStub() && pMD->IsSecureDelegateStub())
5762 pResult->secureDelegateInvoke = TRUE;
5767 EE_TO_JIT_TRANSITION();
5770 BOOL CEEInfo::canAccessFamily(CORINFO_METHOD_HANDLE hCaller,
5771 CORINFO_CLASS_HANDLE hInstanceType)
5773 WRAPPER_NO_CONTRACT;
5777 //Since this is only for verification, I don't need to do the demand.
5778 JIT_TO_EE_TRANSITION();
5780 TypeHandle targetType = TypeHandle(hInstanceType);
5781 TypeHandle accessingType = TypeHandle(GetMethod(hCaller)->GetMethodTable());
5782 AccessCheckOptions::AccessCheckType accessCheckOptions = AccessCheckOptions::kNormalAccessibilityChecks;
5783 DynamicResolver* pIgnored;
5784 BOOL doCheck = TRUE;
5785 if (GetMethod(hCaller)->IsDynamicMethod())
5787 //If this is a DynamicMethod, perform the check from the type to which the DynamicMethod was
5790 //If this is a dynamic method, don't do this check. If they specified SkipVisibilityChecks
5791 //(ModifyCheckForDynamicMethod returned false), we should obviously skip the check for the C++
5792 //protected rule (since we skipped all the other visibility checks). If they specified
5793 //RestrictedSkipVisibilityChecks, then they're a "free" DynamicMethod. This check is meaningless
5794 //(i.e. it would always fail). We've already done a demand for access to the member. Let that be
5796 doCheck = ModifyCheckForDynamicMethod(GetMethod(hCaller)->AsDynamicMethodDesc()->GetResolver(),
5797 &accessingType, &accessCheckOptions, &pIgnored);
5798 if (accessCheckOptions == AccessCheckOptions::kRestrictedMemberAccess
5799 || accessCheckOptions == AccessCheckOptions::kRestrictedMemberAccessNoTransparency
5806 ret = ClassLoader::CanAccessFamilyVerification(accessingType, targetType);
5813 EE_TO_JIT_TRANSITION();
5816 void CEEInfo::ThrowExceptionForHelper(const CORINFO_HELPER_DESC * throwHelper)
5825 JIT_TO_EE_TRANSITION();
5827 _ASSERTE(throwHelper->args[0].argType == CORINFO_HELPER_ARG_TYPE_Method);
5828 MethodDesc *pCallerMD = GetMethod(throwHelper->args[0].methodHandle);
5830 StaticAccessCheckContext accessContext(pCallerMD);
5832 switch (throwHelper->helperNum)
5834 case CORINFO_HELP_METHOD_ACCESS_EXCEPTION:
5836 _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Method);
5837 ThrowMethodAccessException(&accessContext, GetMethod(throwHelper->args[1].methodHandle));
5840 case CORINFO_HELP_FIELD_ACCESS_EXCEPTION:
5842 _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Field);
5843 ThrowFieldAccessException(&accessContext, reinterpret_cast<FieldDesc *>(throwHelper->args[1].fieldHandle));
5846 case CORINFO_HELP_CLASS_ACCESS_EXCEPTION:
5848 _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Class);
5849 TypeHandle typeHnd(throwHelper->args[1].classHandle);
5850 ThrowTypeAccessException(&accessContext, typeHnd.GetMethodTable());
5855 _ASSERTE(!"Unknown access exception type");
5857 EE_TO_JIT_TRANSITION();
5861 BOOL CEEInfo::isRIDClassDomainID(CORINFO_CLASS_HANDLE cls)
5870 BOOL result = FALSE;
5872 JIT_TO_EE_TRANSITION();
5874 TypeHandle VMClsHnd(cls);
5876 result = !VMClsHnd.AsMethodTable()->IsDynamicStatics();
5878 EE_TO_JIT_TRANSITION();
5884 /***********************************************************************/
5885 unsigned CEEInfo::getClassDomainID (CORINFO_CLASS_HANDLE clsHnd,
5886 void **ppIndirection)
5895 unsigned result = 0;
5897 if (ppIndirection != NULL)
5898 *ppIndirection = NULL;
5900 JIT_TO_EE_TRANSITION();
5902 TypeHandle VMClsHnd(clsHnd);
5904 if (VMClsHnd.AsMethodTable()->IsDynamicStatics())
5906 result = (unsigned)VMClsHnd.AsMethodTable()->GetModuleDynamicEntryID();
5910 result = (unsigned)VMClsHnd.AsMethodTable()->GetClassIndex();
5913 EE_TO_JIT_TRANSITION();
5918 //---------------------------------------------------------------------------------------
5920 // Used by the JIT to determine whether the profiler or IBC is tracking object
5924 // bool indicating whether the profiler or IBC is tracking object allocations
5927 // Normally, a profiler would just directly call the inline helper to determine
5928 // whether the profiler set the relevant event flag (e.g.,
5929 // CORProfilerTrackAllocationsEnabled). However, this wrapper also asks whether we're
5930 // running for IBC instrumentation or enabling the object allocated ETW event. If so,
5931 // we treat that the same as if the profiler requested allocation information, so that
5932 // the JIT will still use the profiling-friendly object allocation jit helper, so the
5933 // allocations can be tracked.
5936 bool __stdcall TrackAllocationsEnabled()
5947 (g_IBCLogger.InstrEnabled() != FALSE)
5948 #ifdef PROFILING_SUPPORTED
5949 || CORProfilerTrackAllocationsEnabled()
5950 #endif // PROFILING_SUPPORTED
5951 #ifdef FEATURE_EVENT_TRACE
5952 || ETW::TypeSystemLog::IsHeapAllocEventEnabled()
5953 #endif // FEATURE_EVENT_TRACE
5957 /***********************************************************************/
5958 CorInfoHelpFunc CEEInfo::getNewHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_METHOD_HANDLE callerHandle)
5967 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5969 JIT_TO_EE_TRANSITION();
5971 TypeHandle VMClsHnd(pResolvedToken->hClass);
5973 if(VMClsHnd.IsTypeDesc())
5975 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateFunctionPointer"));
5978 if(VMClsHnd.IsAbstract())
5980 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateAbstractClass"));
5983 MethodTable* pMT = VMClsHnd.AsMethodTable();
5984 result = getNewHelperStatic(pMT);
5986 _ASSERTE(result != CORINFO_HELP_UNDEF);
5988 EE_TO_JIT_TRANSITION();
5993 /***********************************************************************/
5994 CorInfoHelpFunc CEEInfo::getNewHelperStatic(MethodTable * pMT)
5996 STANDARD_VM_CONTRACT;
5999 // Slow helper is the default
6000 CorInfoHelpFunc helper = CORINFO_HELP_NEWFAST;
6003 if (pMT->IsComObjectType())
6006 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6009 if ((pMT->GetBaseSize() >= LARGE_OBJECT_SIZE) ||
6010 pMT->HasFinalizer())
6013 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6016 // don't call the super-optimized one since that does not check
6018 if (GCStress<cfg_alloc>::IsEnabled())
6021 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6026 // Super fast version doesn't do logging
6027 if (LoggingOn(LF_GCALLOC, LL_INFO10))
6030 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6035 // Don't use the SFAST allocator when tracking object allocations,
6036 // so we don't have to instrument it.
6037 if (TrackAllocationsEnabled())
6040 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6043 #ifdef FEATURE_64BIT_ALIGNMENT
6044 // @ARMTODO: Force all 8-byte alignment requiring allocations down one slow path. As performance
6045 // measurements dictate we can spread these out to faster, more specialized helpers later.
6046 if (pMT->RequiresAlign8())
6049 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
6054 // Use the fast helper when all conditions are met
6055 helper = CORINFO_HELP_NEWSFAST;
6058 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
6059 // If we are use the the fast allocator we also may need the
6060 // specialized varion for align8
6061 if (pMT->GetClass()->IsAlign8Candidate() &&
6062 (helper == CORINFO_HELP_NEWSFAST))
6064 helper = CORINFO_HELP_NEWSFAST_ALIGN8;
6066 #endif // FEATURE_DOUBLE_ALIGNMENT_HINT
6071 /***********************************************************************/
6072 // <REVIEW> this only works for shared generic code because all the
6073 // helpers are actually the same. If they were different then things might
6074 // break because the same helper would end up getting used for different but
6075 // representation-compatible arrays (e.g. one with a default constructor
6076 // and one without) </REVIEW>
6077 CorInfoHelpFunc CEEInfo::getNewArrHelper (CORINFO_CLASS_HANDLE arrayClsHnd)
6086 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6088 JIT_TO_EE_TRANSITION();
6090 TypeHandle arrayType(arrayClsHnd);
6092 result = getNewArrHelperStatic(arrayType);
6094 _ASSERTE(result != CORINFO_HELP_UNDEF);
6096 EE_TO_JIT_TRANSITION();
6101 /***********************************************************************/
6102 CorInfoHelpFunc CEEInfo::getNewArrHelperStatic(TypeHandle clsHnd)
6104 STANDARD_VM_CONTRACT;
6106 ArrayTypeDesc* arrayTypeDesc = clsHnd.AsArray();
6107 _ASSERTE(arrayTypeDesc->GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
6109 if (GCStress<cfg_alloc>::IsEnabled())
6111 return CORINFO_HELP_NEWARR_1_DIRECT;
6114 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6116 TypeHandle thElemType = arrayTypeDesc->GetTypeParam();
6117 CorElementType elemType = thElemType.GetInternalCorElementType();
6119 // This is if we're asked for newarr !0 when verifying generic code
6120 // Of course ideally you wouldn't even be generating code when
6121 // simply doing verification (we run the JIT importer in import-only
6122 // mode), but importing does more than one would like so we try to be
6123 // tolerant when asked for non-sensical helpers.
6124 if (CorTypeInfo::IsGenericVariable(elemType))
6126 result = CORINFO_HELP_NEWARR_1_OBJ;
6128 else if (CorTypeInfo::IsObjRef(elemType))
6130 // It is an array of object refs
6131 result = CORINFO_HELP_NEWARR_1_OBJ;
6135 // These cases always must use the slow helper
6137 #ifdef FEATURE_64BIT_ALIGNMENT
6138 thElemType.RequiresAlign8() ||
6140 (elemType == ELEMENT_TYPE_VOID) ||
6141 LoggingOn(LF_GCALLOC, LL_INFO10) ||
6142 TrackAllocationsEnabled())
6144 // Use the slow helper
6145 result = CORINFO_HELP_NEWARR_1_DIRECT;
6147 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
6148 else if (elemType == ELEMENT_TYPE_R8)
6150 // Use the Align8 fast helper
6151 result = CORINFO_HELP_NEWARR_1_ALIGN8;
6156 // Yea, we can do it the fast way!
6157 result = CORINFO_HELP_NEWARR_1_VC;
6164 /***********************************************************************/
6165 CorInfoHelpFunc CEEInfo::getCastingHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fThrowing)
6175 return fThrowing ? CORINFO_HELP_CHKCASTANY : CORINFO_HELP_ISINSTANCEOFANY;
6177 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6179 JIT_TO_EE_TRANSITION();
6181 bool fClassMustBeRestored;
6182 result = getCastingHelperStatic(TypeHandle(pResolvedToken->hClass), fThrowing, &fClassMustBeRestored);
6183 if (fClassMustBeRestored && m_pOverride != NULL)
6184 m_pOverride->classMustBeLoadedBeforeCodeIsRun(pResolvedToken->hClass);
6186 EE_TO_JIT_TRANSITION();
6191 /***********************************************************************/
6192 CorInfoHelpFunc CEEInfo::getCastingHelperStatic(TypeHandle clsHnd, bool fThrowing, bool * pfClassMustBeRestored)
6194 STANDARD_VM_CONTRACT;
6196 // Slow helper is the default
6197 int helper = CORINFO_HELP_ISINSTANCEOFANY;
6199 *pfClassMustBeRestored = false;
6201 if (clsHnd == TypeHandle(g_pCanonMethodTableClass))
6203 // In shared code just use the catch-all helper for type variables, as the same
6204 // code may be used for interface/array/class instantiations
6206 // We may be able to take advantage of constraints to select a specialized helper.
6207 // This optimizations does not seem to be warranted at the moment.
6208 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6211 if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasVariance())
6213 // Casting to variant type requires the type to be fully loaded
6214 *pfClassMustBeRestored = true;
6216 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6219 if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasTypeEquivalence())
6221 // If the type can be equivalent with something, use the slow helper
6222 // Note: if the type of the instance is the one marked as equivalent, it will be
6223 // caught by the fast helpers in the same way as they catch transparent proxies.
6224 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6227 if (clsHnd.IsInterface())
6229 // If it is a non-variant interface, use the fast interface helper
6230 helper = CORINFO_HELP_ISINSTANCEOFINTERFACE;
6233 if (clsHnd.IsArray())
6235 if (clsHnd.AsArray()->GetInternalCorElementType() != ELEMENT_TYPE_SZARRAY)
6237 // Casting to multidimensional array type requires restored pointer to EEClass to fetch rank
6238 *pfClassMustBeRestored = true;
6241 // If it is an array, use the fast array helper
6242 helper = CORINFO_HELP_ISINSTANCEOFARRAY;
6245 if (!clsHnd.IsTypeDesc() && !Nullable::IsNullableType(clsHnd))
6247 // If it is a non-variant class, use the fast class helper
6248 helper = CORINFO_HELP_ISINSTANCEOFCLASS;
6252 // Otherwise, use the slow helper
6253 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6256 #ifdef FEATURE_PREJIT
6257 BOOL t1, t2, forceInstr;
6258 SystemDomain::GetCompilationOverrides(&t1, &t2, &forceInstr);
6261 // If we're compiling for instrumentation, use the slowest but instrumented cast helper
6262 helper = CORINFO_HELP_ISINSTANCEOFANY;
6268 const int delta = CORINFO_HELP_CHKCASTANY - CORINFO_HELP_ISINSTANCEOFANY;
6270 static_assert_no_msg(CORINFO_HELP_CHKCASTINTERFACE
6271 == CORINFO_HELP_ISINSTANCEOFINTERFACE + delta);
6272 static_assert_no_msg(CORINFO_HELP_CHKCASTARRAY
6273 == CORINFO_HELP_ISINSTANCEOFARRAY + delta);
6274 static_assert_no_msg(CORINFO_HELP_CHKCASTCLASS
6275 == CORINFO_HELP_ISINSTANCEOFCLASS + delta);
6280 return (CorInfoHelpFunc)helper;
6283 /***********************************************************************/
6284 CorInfoHelpFunc CEEInfo::getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd)
6293 CorInfoHelpFunc result = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
6295 JIT_TO_EE_TRANSITION_LEAF();
6297 TypeHandle cls(clsHnd);
6298 MethodTable* pMT = cls.AsMethodTable();
6300 if (pMT->IsDynamicStatics())
6302 _ASSERTE(!cls.ContainsGenericVariables());
6303 _ASSERTE(pMT->GetModuleDynamicEntryID() != (unsigned) -1);
6305 result = CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
6308 EE_TO_JIT_TRANSITION_LEAF();
6313 /***********************************************************************/
6314 CorInfoHelpFunc CEEInfo::getUnBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6316 LIMITED_METHOD_CONTRACT;
6318 if (m_pOverride != NULL)
6319 m_pOverride->classMustBeLoadedBeforeCodeIsRun(clsHnd);
6321 TypeHandle VMClsHnd(clsHnd);
6322 if (Nullable::IsNullableType(VMClsHnd))
6323 return CORINFO_HELP_UNBOX_NULLABLE;
6325 return CORINFO_HELP_UNBOX;
6328 /***********************************************************************/
6329 bool CEEInfo::getReadyToRunHelper(
6330 CORINFO_RESOLVED_TOKEN * pResolvedToken,
6331 CORINFO_LOOKUP_KIND * pGenericLookupKind,
6333 CORINFO_CONST_LOOKUP * pLookup
6336 LIMITED_METHOD_CONTRACT;
6337 UNREACHABLE(); // only called during NGen
6340 /***********************************************************************/
6341 void CEEInfo::getReadyToRunDelegateCtorHelper(
6342 CORINFO_RESOLVED_TOKEN * pTargetMethod,
6343 CORINFO_CLASS_HANDLE delegateType,
6344 CORINFO_LOOKUP * pLookup
6347 LIMITED_METHOD_CONTRACT;
6348 UNREACHABLE(); // only called during NGen
6351 /***********************************************************************/
6352 // see code:Nullable#NullableVerification
6354 CORINFO_CLASS_HANDLE CEEInfo::getTypeForBox(CORINFO_CLASS_HANDLE cls)
6356 LIMITED_METHOD_CONTRACT;
6358 TypeHandle VMClsHnd(cls);
6359 if (Nullable::IsNullableType(VMClsHnd)) {
6360 VMClsHnd = VMClsHnd.AsMethodTable()->GetInstantiation()[0];
6362 return static_cast<CORINFO_CLASS_HANDLE>(VMClsHnd.AsPtr());
6365 /***********************************************************************/
6366 // see code:Nullable#NullableVerification
6367 CorInfoHelpFunc CEEInfo::getBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6376 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6378 JIT_TO_EE_TRANSITION();
6380 TypeHandle VMClsHnd(clsHnd);
6381 if (Nullable::IsNullableType(VMClsHnd))
6383 result = CORINFO_HELP_BOX_NULLABLE;
6387 if(VMClsHnd.IsTypeDesc())
6388 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_TypeCannotBeBoxed"));
6390 // we shouldn't allow boxing of types that contains stack pointers
6391 // csc and vbc already disallow it.
6392 if (VMClsHnd.AsMethodTable()->IsByRefLike())
6393 COMPlusThrow(kInvalidProgramException,W("NotSupported_ByRefLike"));
6395 result = CORINFO_HELP_BOX;
6398 EE_TO_JIT_TRANSITION();
6403 /***********************************************************************/
6404 CorInfoHelpFunc CEEInfo::getSecurityPrologHelper(CORINFO_METHOD_HANDLE ftn)
6413 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6415 JIT_TO_EE_TRANSITION();
6417 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6418 // This will make sure that when IBC logging is on, we call the slow helper with IBC probe
6419 if (IsCompilingForNGen() &&
6420 GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
6422 result = CORINFO_HELP_SECURITY_PROLOG_FRAMED;
6424 #endif // FEATURE_NATIVE_IMAGE_GENERATION
6426 if (result == CORINFO_HELP_UNDEF)
6428 result = CORINFO_HELP_SECURITY_PROLOG;
6431 EE_TO_JIT_TRANSITION();
6436 /***********************************************************************/
6437 // registers a vararg sig & returns a class-specific cookie for it.
6439 CORINFO_VARARGS_HANDLE CEEInfo::getVarArgsHandle(CORINFO_SIG_INFO *sig,
6440 void **ppIndirection)
6449 CORINFO_VARARGS_HANDLE result = NULL;
6451 if (ppIndirection != NULL)
6452 *ppIndirection = NULL;
6454 JIT_TO_EE_TRANSITION();
6456 Module* module = GetModule(sig->scope);
6458 result = CORINFO_VARARGS_HANDLE(module->GetVASigCookie(Signature(sig->pSig, sig->cbSig)));
6460 EE_TO_JIT_TRANSITION();
6465 bool CEEInfo::canGetVarArgsHandle(CORINFO_SIG_INFO *sig)
6467 LIMITED_METHOD_CONTRACT;
6471 /***********************************************************************/
6472 unsigned CEEInfo::getMethodHash (CORINFO_METHOD_HANDLE ftnHnd)
6481 unsigned result = 0;
6483 JIT_TO_EE_TRANSITION();
6485 MethodDesc* ftn = GetMethod(ftnHnd);
6487 result = (unsigned) ftn->GetStableHash();
6489 EE_TO_JIT_TRANSITION();
6494 /***********************************************************************/
6495 const char* CEEInfo::getMethodName (CORINFO_METHOD_HANDLE ftnHnd, const char** scopeName)
6504 const char* result = NULL;
6506 JIT_TO_EE_TRANSITION();
6510 ftn = GetMethod(ftnHnd);
6514 if (ftn->IsLCGMethod())
6516 *scopeName = "DynamicClass";
6518 else if (ftn->IsILStub())
6520 *scopeName = ILStubResolver::GetStubClassName(ftn);
6524 MethodTable * pMT = ftn->GetMethodTable();
6526 #ifdef FEATURE_SYMDIFF
6527 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SymDiffDump))
6531 ssClsNameBuff.Clear();
6532 ssClsNameBuff.SetUTF8(pMT->GetDebugClassName());
6535 pMT->_GetFullyQualifiedNameForClassNestedAware(ssClsNameBuff);
6540 // Calling _GetFullyQualifiedNameForClass in chk build is very expensive
6541 // since it construct the class name everytime we call this method. In chk
6542 // builds we already have a cheaper way to get the class name -
6543 // GetDebugClassName - which doesn't calculate the class name everytime.
6544 // This results in huge saving in Ngen time for checked builds.
6545 ssClsNameBuff.Clear();
6546 ssClsNameBuff.SetUTF8(pMT->GetDebugClassName());
6548 #ifdef FEATURE_SYMDIFF
6551 // Append generic instantiation at the end
6552 Instantiation inst = pMT->GetInstantiation();
6553 if (!inst.IsEmpty())
6554 TypeString::AppendInst(ssClsNameBuff, inst);
6556 *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
6558 // since this is for diagnostic purposes only,
6559 // give up on the namespace, as we don't have a buffer to concat it
6560 // also note this won't show array class names.
6562 *scopeName= pMT->GetFullyQualifiedNameInfo(&nameSpace);
6567 result = ftn->GetName();
6569 EE_TO_JIT_TRANSITION();
6574 const char* CEEInfo::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftnHnd, const char** className, const char** namespaceName)
6583 const char* result = NULL;
6584 const char* classResult = NULL;
6585 const char* namespaceResult = NULL;
6587 JIT_TO_EE_TRANSITION();
6589 MethodDesc *ftn = GetMethod(ftnHnd);
6590 mdMethodDef token = ftn->GetMemberDef();
6592 if (!IsNilToken(token))
6594 if (!FAILED(ftn->GetMDImport()->GetNameOfMethodDef(token, &result)))
6596 MethodTable* pMT = ftn->GetMethodTable();
6597 classResult = pMT->GetFullyQualifiedNameInfo(&namespaceResult);
6601 if (className != NULL)
6603 *className = classResult;
6606 if (namespaceName != NULL)
6608 *namespaceName = namespaceResult;
6611 EE_TO_JIT_TRANSITION();
6616 /*********************************************************************/
6617 const char* CEEInfo::getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName)
6626 const char* result = NULL;
6627 const char* namespaceResult = NULL;
6629 JIT_TO_EE_TRANSITION();
6630 TypeHandle VMClsHnd(cls);
6632 if (!VMClsHnd.IsTypeDesc())
6634 result = VMClsHnd.AsMethodTable()->GetFullyQualifiedNameInfo(&namespaceResult);
6637 if (namespaceName != NULL)
6639 *namespaceName = namespaceResult;
6642 EE_TO_JIT_TRANSITION();
6647 /*********************************************************************/
6648 CORINFO_CLASS_HANDLE CEEInfo::getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index)
6657 CORINFO_CLASS_HANDLE result = NULL;
6659 JIT_TO_EE_TRANSITION_LEAF();
6661 TypeHandle VMClsHnd(cls);
6662 Instantiation inst = VMClsHnd.GetInstantiation();
6663 TypeHandle typeArg = index < inst.GetNumArgs() ? inst[index] : NULL;
6664 result = CORINFO_CLASS_HANDLE(typeArg.AsPtr());
6666 EE_TO_JIT_TRANSITION_LEAF();
6671 /*********************************************************************/
6672 DWORD CEEInfo::getMethodAttribs (CORINFO_METHOD_HANDLE ftn)
6683 JIT_TO_EE_TRANSITION();
6685 result = getMethodAttribsInternal(ftn);
6687 EE_TO_JIT_TRANSITION();
6692 /*********************************************************************/
6693 DWORD CEEInfo::getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftn)
6695 STANDARD_VM_CONTRACT;
6698 returns method attribute flags (defined in corhdr.h)
6700 NOTE: This doesn't return certain method flags
6701 (mdAssem, mdFamANDAssem, mdFamORAssem, mdPrivateScope)
6704 MethodDesc* pMD = GetMethod(ftn);
6706 if (pMD->IsLCGMethod())
6708 return CORINFO_FLG_STATIC | CORINFO_FLG_DONT_INLINE | CORINFO_FLG_NOSECURITYWRAP;
6711 DWORD result = CORINFO_FLG_NOSECURITYWRAP;
6713 // <REVISIT_TODO>@todo: can we git rid of CORINFO_FLG_ stuff and just include cor.h?</REVISIT_TODO>
6715 DWORD attribs = pMD->GetAttrs();
6717 if (IsMdFamily(attribs))
6718 result |= CORINFO_FLG_PROTECTED;
6719 if (IsMdStatic(attribs))
6720 result |= CORINFO_FLG_STATIC;
6721 if (pMD->IsSynchronized())
6722 result |= CORINFO_FLG_SYNCH;
6723 if (pMD->IsFCallOrIntrinsic())
6724 result |= CORINFO_FLG_NOGCCHECK | CORINFO_FLG_INTRINSIC;
6725 if (pMD->IsJitIntrinsic())
6726 result |= CORINFO_FLG_JIT_INTRINSIC;
6727 if (IsMdVirtual(attribs))
6728 result |= CORINFO_FLG_VIRTUAL;
6729 if (IsMdAbstract(attribs))
6730 result |= CORINFO_FLG_ABSTRACT;
6731 if (IsMdRTSpecialName(attribs))
6733 LPCUTF8 pName = pMD->GetName();
6734 if (IsMdInstanceInitializer(attribs, pName) ||
6735 IsMdClassConstructor(attribs, pName))
6736 result |= CORINFO_FLG_CONSTRUCTOR;
6740 // See if we need to embed a .cctor call at the head of the
6744 MethodTable* pMT = pMD->GetMethodTable();
6746 // method or class might have the final bit
6747 if (IsMdFinal(attribs) || pMT->IsSealed())
6749 result |= CORINFO_FLG_FINAL;
6752 if (pMD->IsEnCAddedMethod())
6754 result |= CORINFO_FLG_EnC;
6757 if (pMD->IsSharedByGenericInstantiations())
6759 result |= CORINFO_FLG_SHAREDINST;
6762 if (pMD->IsNDirect())
6764 result |= CORINFO_FLG_PINVOKE;
6767 if (IsMdRequireSecObject(attribs))
6769 // Assume all methods marked as DynamicSecurity are
6770 // marked that way because they use StackCrawlMark to identify
6772 // See comments in canInline or canTailCall
6773 result |= CORINFO_FLG_DONT_INLINE_CALLER;
6776 // Check for the aggressive optimization directive. AggressiveOptimization only makes sense for IL methods.
6777 DWORD ilMethodImplAttribs = 0;
6780 ilMethodImplAttribs = pMD->GetImplAttrs();
6781 if (IsMiAggressiveOptimization(ilMethodImplAttribs))
6783 result |= CORINFO_FLG_AGGRESSIVE_OPT;
6787 // Check for an inlining directive.
6788 if (pMD->IsNotInline())
6790 /* Function marked as not inlineable */
6791 result |= CORINFO_FLG_DONT_INLINE;
6793 // AggressiveInlining only makes sense for IL methods.
6794 else if (pMD->IsIL() && IsMiAggressiveInlining(ilMethodImplAttribs))
6796 result |= CORINFO_FLG_FORCEINLINE;
6799 if (pMT->IsDelegate() && ((DelegateEEClass*)(pMT->GetClass()))->GetInvokeMethod() == pMD)
6801 // This is now used to emit efficient invoke code for any delegate invoke,
6802 // including multicast.
6803 result |= CORINFO_FLG_DELEGATE_INVOKE;
6809 /*********************************************************************/
6810 void CEEInfo::setMethodAttribs (
6811 CORINFO_METHOD_HANDLE ftnHnd,
6812 CorInfoMethodRuntimeFlags attribs)
6821 JIT_TO_EE_TRANSITION();
6823 MethodDesc* ftn = GetMethod(ftnHnd);
6825 if (attribs & CORINFO_FLG_BAD_INLINEE)
6827 BOOL fCacheInliningHint = TRUE;
6829 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6830 if (IsCompilationProcess())
6832 // Since we are running managed code during NGen the inlining hint may be
6833 // changing underneeth us as the code is JITed. We need to prevent the inlining
6834 // hints from changing once we start to use them to place IL in the image.
6835 if (!g_pCEECompileInfo->IsCachingOfInliningHintsEnabled())
6837 fCacheInliningHint = FALSE;
6841 // Don't cache inlining hints inside mscorlib during NGen of other assemblies,
6842 // since mscorlib is loaded domain neutral and will survive worker process recycling,
6843 // causing determinism problems.
6844 Module * pModule = ftn->GetModule();
6845 if (pModule->IsSystem() && pModule->HasNativeImage())
6847 fCacheInliningHint = FALSE;
6853 if (fCacheInliningHint)
6855 ftn->SetNotInline(true);
6859 EE_TO_JIT_TRANSITION();
6862 /*********************************************************************/
6864 void getMethodInfoILMethodHeaderHelper(
6865 COR_ILMETHOD_DECODER* header,
6866 CORINFO_METHOD_INFO* methInfo
6869 LIMITED_METHOD_CONTRACT;
6871 methInfo->ILCode = const_cast<BYTE*>(header->Code);
6872 methInfo->ILCodeSize = header->GetCodeSize();
6873 methInfo->maxStack = static_cast<unsigned short>(header->GetMaxStack());
6874 methInfo->EHcount = static_cast<unsigned short>(header->EHCount());
6877 (CorInfoOptions)((header->GetFlags() & CorILMethod_InitLocals) ? CORINFO_OPT_INIT_LOCALS : 0) ;
6880 mdToken FindGenericMethodArgTypeSpec(IMDInternalImport* pInternalImport)
6882 STANDARD_VM_CONTRACT;
6884 HENUMInternalHolder hEnumTypeSpecs(pInternalImport);
6887 static const BYTE signature[] = { ELEMENT_TYPE_MVAR, 0 };
6889 hEnumTypeSpecs.EnumAllInit(mdtTypeSpec);
6890 while (hEnumTypeSpecs.EnumNext(&token))
6892 PCCOR_SIGNATURE pSig;
6894 IfFailThrow(pInternalImport->GetTypeSpecFromToken(token, &pSig, &cbSig));
6895 if (cbSig == sizeof(signature) && memcmp(pSig, signature, cbSig) == 0)
6899 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6902 /*********************************************************************
6904 IL is the most efficient and portable way to implement certain low level methods
6905 in mscorlib.dll. Unfortunately, there is no good way to link IL into mscorlib.dll today.
6906 Until we find a good way to link IL into mscorlib.dll, we will provide the IL implementation here.
6908 - All IL intrinsincs are members of System.Runtime.CompilerServices.JitHelpers class
6909 - All IL intrinsincs should be kept very simple. Implement the minimal reusable version of
6910 unsafe construct and depend on inlining to do the rest.
6911 - The C# implementation of the IL intrinsic should be good enough for functionalily. Everything should work
6912 correctly (but slower) if the IL intrinsics are removed.
6914 *********************************************************************/
6916 bool getILIntrinsicImplementation(MethodDesc * ftn,
6917 CORINFO_METHOD_INFO * methInfo)
6919 STANDARD_VM_CONTRACT;
6921 // Precondition: ftn is a method in mscorlib
6922 _ASSERTE(ftn->GetModule()->IsSystem());
6924 mdMethodDef tk = ftn->GetMemberDef();
6926 // Compare tokens to cover all generic instantiations
6927 // The body of the first method is simply ret Arg0. The second one first casts the arg to I4.
6929 if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_CAST_TO_STACKPTR)->GetMemberDef())
6931 // Return the argument that was passed in converted to IntPtr
6932 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I, CEE_RET };
6933 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6934 methInfo->ILCodeSize = sizeof(ilcode);
6935 methInfo->maxStack = 1;
6936 methInfo->EHcount = 0;
6937 methInfo->options = (CorInfoOptions)0;
6940 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST)->GetMemberDef())
6942 // Normally we would follow the above pattern and unconditionally replace the IL,
6943 // relying on generic type constraints to guarantee that it will only ever be instantiated
6944 // on the type/size of argument we expect.
6946 // However C#/CLR does not support restricting a generic type to be an Enum, so the best
6947 // we can do is constrain it to be a value type. This is fine for run time, since we only
6948 // ever create instantiations on 4 byte or less Enums. But during NGen we may compile instantiations
6949 // on other value types (to be specific, every value type instatiation of EqualityComparer
6950 // because of its TypeDependencyAttribute; here again we would like to restrict this to
6951 // 4 byte or less Enums but cannot).
6953 // This IL is invalid for those instantiations, and replacing it would lead to all sorts of
6954 // errors at NGen time. So we only replace it for instantiations where it would be valid,
6955 // leaving the others, which we should never execute, with the C# implementation of throwing.
6957 _ASSERTE(ftn->HasMethodInstantiation());
6958 Instantiation inst = ftn->GetMethodInstantiation();
6960 _ASSERTE(inst.GetNumArgs() == 1);
6961 CorElementType et = inst[0].GetVerifierCorElementType();
6962 if (et == ELEMENT_TYPE_I4 ||
6963 et == ELEMENT_TYPE_U4 ||
6964 et == ELEMENT_TYPE_I2 ||
6965 et == ELEMENT_TYPE_U2 ||
6966 et == ELEMENT_TYPE_I1 ||
6967 et == ELEMENT_TYPE_U1)
6969 // Cast to I4 and return the argument that was passed in.
6970 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I4, CEE_RET };
6971 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6972 methInfo->ILCodeSize = sizeof(ilcode);
6973 methInfo->maxStack = 1;
6974 methInfo->EHcount = 0;
6975 methInfo->options = (CorInfoOptions)0;
6979 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG)->GetMemberDef())
6981 // The the comment above on why this is is not an unconditional replacement. This case handles
6982 // Enums backed by 8 byte values.
6984 _ASSERTE(ftn->HasMethodInstantiation());
6985 Instantiation inst = ftn->GetMethodInstantiation();
6987 _ASSERTE(inst.GetNumArgs() == 1);
6988 CorElementType et = inst[0].GetVerifierCorElementType();
6989 if (et == ELEMENT_TYPE_I8 ||
6990 et == ELEMENT_TYPE_U8)
6992 // Cast to I8 and return the argument that was passed in.
6993 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I8, CEE_RET };
6994 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6995 methInfo->ILCodeSize = sizeof(ilcode);
6996 methInfo->maxStack = 1;
6997 methInfo->EHcount = 0;
6998 methInfo->options = (CorInfoOptions)0;
7002 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__GET_RAW_SZ_ARRAY_DATA)->GetMemberDef())
7004 mdToken tokArrayPinningHelper = MscorlibBinder::GetField(FIELD__ARRAY_PINNING_HELPER__M_ARRAY_DATA)->GetMemberDef();
7006 static BYTE ilcode[] = { CEE_LDARG_0,
7010 ilcode[2] = (BYTE)(tokArrayPinningHelper);
7011 ilcode[3] = (BYTE)(tokArrayPinningHelper >> 8);
7012 ilcode[4] = (BYTE)(tokArrayPinningHelper >> 16);
7013 ilcode[5] = (BYTE)(tokArrayPinningHelper >> 24);
7015 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7016 methInfo->ILCodeSize = sizeof(ilcode);
7017 methInfo->maxStack = 1;
7018 methInfo->EHcount = 0;
7019 methInfo->options = (CorInfoOptions)0;
7026 bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
7027 CORINFO_METHOD_INFO * methInfo)
7029 STANDARD_VM_CONTRACT;
7031 // Precondition: ftn is a method in mscorlib
7032 _ASSERTE(ftn->GetModule()->IsSystem());
7034 mdMethodDef tk = ftn->GetMemberDef();
7036 if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_POINTER)->GetMemberDef())
7038 // Return the argument that was passed in.
7039 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_U, CEE_RET };
7040 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7041 methInfo->ILCodeSize = sizeof(ilcode);
7042 methInfo->maxStack = 1;
7043 methInfo->EHcount = 0;
7044 methInfo->options = (CorInfoOptions)0;
7047 if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__SIZEOF)->GetMemberDef())
7049 _ASSERTE(ftn->HasMethodInstantiation());
7050 Instantiation inst = ftn->GetMethodInstantiation();
7052 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7053 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7055 static BYTE ilcode[] = { CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0, CEE_RET };
7057 ilcode[2] = (BYTE)(tokGenericArg);
7058 ilcode[3] = (BYTE)(tokGenericArg >> 8);
7059 ilcode[4] = (BYTE)(tokGenericArg >> 16);
7060 ilcode[5] = (BYTE)(tokGenericArg >> 24);
7062 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7063 methInfo->ILCodeSize = sizeof(ilcode);
7064 methInfo->maxStack = 1;
7065 methInfo->EHcount = 0;
7066 methInfo->options = (CorInfoOptions)0;
7069 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef() ||
7070 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__OBJECT_AS)->GetMemberDef() ||
7071 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_REF_POINTER)->GetMemberDef() ||
7072 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_REF_IN)->GetMemberDef())
7074 // Return the argument that was passed in.
7075 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
7076 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7077 methInfo->ILCodeSize = sizeof(ilcode);
7078 methInfo->maxStack = 1;
7079 methInfo->EHcount = 0;
7080 methInfo->options = (CorInfoOptions)0;
7083 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD)->GetMemberDef() ||
7084 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_ADD)->GetMemberDef())
7086 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7088 static BYTE ilcode[] = { CEE_LDARG_1,
7089 CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0,
7096 ilcode[3] = (BYTE)(tokGenericArg);
7097 ilcode[4] = (BYTE)(tokGenericArg >> 8);
7098 ilcode[5] = (BYTE)(tokGenericArg >> 16);
7099 ilcode[6] = (BYTE)(tokGenericArg >> 24);
7101 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7102 methInfo->ILCodeSize = sizeof(ilcode);
7103 methInfo->maxStack = 2;
7104 methInfo->EHcount = 0;
7105 methInfo->options = (CorInfoOptions)0;
7108 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_INTPTR_ADD)->GetMemberDef())
7110 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7112 static BYTE ilcode[] = { CEE_LDARG_1,
7113 CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0,
7119 ilcode[3] = (BYTE)(tokGenericArg);
7120 ilcode[4] = (BYTE)(tokGenericArg >> 8);
7121 ilcode[5] = (BYTE)(tokGenericArg >> 16);
7122 ilcode[6] = (BYTE)(tokGenericArg >> 24);
7124 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7125 methInfo->ILCodeSize = sizeof(ilcode);
7126 methInfo->maxStack = 2;
7127 methInfo->EHcount = 0;
7128 methInfo->options = (CorInfoOptions)0;
7131 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD_BYTE_OFFSET)->GetMemberDef())
7133 static BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_ADD, CEE_RET };
7135 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7136 methInfo->ILCodeSize = sizeof(ilcode);
7137 methInfo->maxStack = 2;
7138 methInfo->EHcount = 0;
7139 methInfo->options = (CorInfoOptions)0;
7142 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ARE_SAME)->GetMemberDef())
7144 // Compare the two arguments
7145 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CEQ & 0xFF), CEE_RET };
7146 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7147 methInfo->ILCodeSize = sizeof(ilcode);
7148 methInfo->maxStack = 2;
7149 methInfo->EHcount = 0;
7150 methInfo->options = (CorInfoOptions)0;
7153 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_GREATER_THAN)->GetMemberDef())
7155 // Compare the two arguments
7156 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CGT_UN & 0xFF), CEE_RET };
7157 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7158 methInfo->ILCodeSize = sizeof(ilcode);
7159 methInfo->maxStack = 2;
7160 methInfo->EHcount = 0;
7161 methInfo->options = (CorInfoOptions)0;
7164 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_LESS_THAN)->GetMemberDef())
7166 // Compare the two arguments
7167 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CLT_UN & 0xFF), CEE_RET };
7168 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7169 methInfo->ILCodeSize = sizeof(ilcode);
7170 methInfo->maxStack = 2;
7171 methInfo->EHcount = 0;
7172 methInfo->options = (CorInfoOptions)0;
7175 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_INIT_BLOCK_UNALIGNED)->GetMemberDef())
7177 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_LDARG_2, CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 0x01, CEE_PREFIX1, (CEE_INITBLK & 0xFF), CEE_RET };
7178 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7179 methInfo->ILCodeSize = sizeof(ilcode);
7180 methInfo->maxStack = 3;
7181 methInfo->EHcount = 0;
7182 methInfo->options = (CorInfoOptions)0;
7185 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_BYTE_OFFSET)->GetMemberDef())
7187 static const BYTE ilcode[] =
7195 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7196 methInfo->ILCodeSize = sizeof(ilcode);
7197 methInfo->maxStack = 2;
7198 methInfo->EHcount = 0;
7199 methInfo->options = (CorInfoOptions)0;
7202 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_READ_UNALIGNED)->GetMemberDef() ||
7203 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_READ_UNALIGNED)->GetMemberDef())
7205 _ASSERTE(ftn->HasMethodInstantiation());
7206 Instantiation inst = ftn->GetMethodInstantiation();
7207 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7208 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7210 static const BYTE ilcode[]
7213 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
7214 CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7218 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7219 methInfo->ILCodeSize = sizeof(ilcode);
7220 methInfo->maxStack = 2;
7221 methInfo->EHcount = 0;
7222 methInfo->options = (CorInfoOptions)0;
7225 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_WRITE_UNALIGNED)->GetMemberDef() ||
7226 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_WRITE_UNALIGNED)->GetMemberDef())
7228 _ASSERTE(ftn->HasMethodInstantiation());
7229 Instantiation inst = ftn->GetMethodInstantiation();
7230 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7231 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7233 static const BYTE ilcode[]
7237 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
7238 CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7242 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7243 methInfo->ILCodeSize = sizeof(ilcode);
7244 methInfo->maxStack = 2;
7245 methInfo->EHcount = 0;
7246 methInfo->options = (CorInfoOptions)0;
7253 bool getILIntrinsicImplementationForVolatile(MethodDesc * ftn,
7254 CORINFO_METHOD_INFO * methInfo)
7256 STANDARD_VM_CONTRACT;
7259 // This replaces the implementations of Volatile.* in mscorlib with more efficient ones.
7260 // We do this because we cannot otherwise express these in C#. What we *want* to do is
7261 // to treat the byref args to these methods as "volatile." In pseudo-C#, this would look
7264 // int Read(ref volatile int location)
7269 // However, C# does not yet provide a way to declare a byref as "volatile." So instead,
7270 // we substitute raw IL bodies for these methods that use the correct volatile instructions.
7273 // Precondition: ftn is a method in mscorlib in the System.Threading.Volatile class
7274 _ASSERTE(ftn->GetModule()->IsSystem());
7275 _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__VOLATILE));
7276 _ASSERTE(strcmp(ftn->GetMethodTable()->GetClass()->GetDebugClassName(), "System.Threading.Volatile") == 0);
7278 const size_t VolatileMethodBodySize = 6;
7280 struct VolatileMethodImpl
7282 BinderMethodID methodId;
7283 BYTE body[VolatileMethodBodySize];
7286 #define VOLATILE_IMPL(type, loadinst, storeinst) \
7288 METHOD__VOLATILE__READ_##type, \
7291 CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7293 CEE_NOP, /*pad to VolatileMethodBodySize bytes*/ \
7298 METHOD__VOLATILE__WRITE_##type, \
7302 CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7308 static const VolatileMethodImpl volatileImpls[] =
7310 VOLATILE_IMPL(T, CEE_LDIND_REF, CEE_STIND_REF)
7311 VOLATILE_IMPL(Bool, CEE_LDIND_I1, CEE_STIND_I1)
7312 VOLATILE_IMPL(Int, CEE_LDIND_I4, CEE_STIND_I4)
7313 VOLATILE_IMPL(IntPtr, CEE_LDIND_I, CEE_STIND_I)
7314 VOLATILE_IMPL(UInt, CEE_LDIND_U4, CEE_STIND_I4)
7315 VOLATILE_IMPL(UIntPtr, CEE_LDIND_I, CEE_STIND_I)
7316 VOLATILE_IMPL(SByt, CEE_LDIND_I1, CEE_STIND_I1)
7317 VOLATILE_IMPL(Byte, CEE_LDIND_U1, CEE_STIND_I1)
7318 VOLATILE_IMPL(Shrt, CEE_LDIND_I2, CEE_STIND_I2)
7319 VOLATILE_IMPL(UShrt, CEE_LDIND_U2, CEE_STIND_I2)
7320 VOLATILE_IMPL(Flt, CEE_LDIND_R4, CEE_STIND_R4)
7323 // Ordinary volatile loads and stores only guarantee atomicity for pointer-sized (or smaller) data.
7324 // So, on 32-bit platforms we must use Interlocked operations instead for the 64-bit types.
7325 // The implementation in mscorlib already does this, so we will only substitute a new
7326 // IL body if we're running on a 64-bit platform.
7328 IN_TARGET_64BIT(VOLATILE_IMPL(Long, CEE_LDIND_I8, CEE_STIND_I8))
7329 IN_TARGET_64BIT(VOLATILE_IMPL(ULong, CEE_LDIND_I8, CEE_STIND_I8))
7330 IN_TARGET_64BIT(VOLATILE_IMPL(Dbl, CEE_LDIND_R8, CEE_STIND_R8))
7333 mdMethodDef md = ftn->GetMemberDef();
7334 for (unsigned i = 0; i < NumItems(volatileImpls); i++)
7336 if (md == MscorlibBinder::GetMethod(volatileImpls[i].methodId)->GetMemberDef())
7338 methInfo->ILCode = const_cast<BYTE*>(volatileImpls[i].body);
7339 methInfo->ILCodeSize = VolatileMethodBodySize;
7340 methInfo->maxStack = 2;
7341 methInfo->EHcount = 0;
7342 methInfo->options = (CorInfoOptions)0;
7350 bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn,
7351 CORINFO_METHOD_INFO * methInfo)
7353 STANDARD_VM_CONTRACT;
7355 // Precondition: ftn is a method in mscorlib in the System.Threading.Interlocked class
7356 _ASSERTE(ftn->GetModule()->IsSystem());
7357 _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__INTERLOCKED));
7359 // We are only interested if ftn's token and CompareExchange<T> token match
7360 if (ftn->GetMemberDef() != MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_T)->GetMemberDef())
7363 // Get MethodDesc for System.Threading.Interlocked.CompareExchangeFast()
7364 MethodDesc* cmpxchgFast = MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_OBJECT);
7366 // The MethodDesc lookup must not fail, and it should have the name "CompareExchangeFast"
7367 _ASSERTE(cmpxchgFast != NULL);
7368 _ASSERTE(strcmp(cmpxchgFast->GetName(), "CompareExchange") == 0);
7370 // Setup up the body of the method
7371 static BYTE il[] = {
7379 // Get the token for System.Threading.Interlocked.CompareExchangeFast(), and patch [target]
7380 mdMethodDef cmpxchgFastToken = cmpxchgFast->GetMemberDef();
7381 il[4] = (BYTE)((int)cmpxchgFastToken >> 0);
7382 il[5] = (BYTE)((int)cmpxchgFastToken >> 8);
7383 il[6] = (BYTE)((int)cmpxchgFastToken >> 16);
7384 il[7] = (BYTE)((int)cmpxchgFastToken >> 24);
7386 // Initialize methInfo
7387 methInfo->ILCode = const_cast<BYTE*>(il);
7388 methInfo->ILCodeSize = sizeof(il);
7389 methInfo->maxStack = 3;
7390 methInfo->EHcount = 0;
7391 methInfo->options = (CorInfoOptions)0;
7396 bool getILIntrinsicImplementationForRuntimeHelpers(MethodDesc * ftn,
7397 CORINFO_METHOD_INFO * methInfo)
7399 STANDARD_VM_CONTRACT;
7401 // Precondition: ftn is a method in mscorlib
7402 _ASSERTE(ftn->GetModule()->IsSystem());
7404 mdMethodDef tk = ftn->GetMemberDef();
7406 if (tk == MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_REFERENCE_OR_CONTAINS_REFERENCES)->GetMemberDef())
7408 _ASSERTE(ftn->HasMethodInstantiation());
7409 Instantiation inst = ftn->GetMethodInstantiation();
7411 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7412 TypeHandle typeHandle = inst[0];
7413 MethodTable * methodTable = typeHandle.GetMethodTable();
7415 static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
7416 static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };
7418 if (!methodTable->IsValueType() || methodTable->ContainsPointers())
7420 methInfo->ILCode = const_cast<BYTE*>(returnTrue);
7424 methInfo->ILCode = const_cast<BYTE*>(returnFalse);
7427 methInfo->ILCodeSize = sizeof(returnTrue);
7428 methInfo->maxStack = 1;
7429 methInfo->EHcount = 0;
7430 methInfo->options = (CorInfoOptions)0;
7437 //---------------------------------------------------------------------------------------
7441 getMethodInfoHelper(
7443 CORINFO_METHOD_HANDLE ftnHnd,
7444 COR_ILMETHOD_DECODER * header,
7445 CORINFO_METHOD_INFO * methInfo)
7447 STANDARD_VM_CONTRACT;
7449 _ASSERTE(ftn == GetMethod(ftnHnd));
7451 methInfo->ftn = ftnHnd;
7452 methInfo->scope = GetScopeHandle(ftn);
7453 methInfo->regionKind = CORINFO_REGION_JIT;
7455 // For Jitted code the regionKind is JIT;
7456 // For Ngen-ed code the zapper will set this to HOT or COLD, if we
7457 // are using IBC data to partition methods into Hot/Cold regions
7459 /* Grab information from the IL header */
7461 PCCOR_SIGNATURE pLocalSig = NULL;
7462 DWORD cbLocalSig = 0;
7466 bool fILIntrinsic = false;
7468 MethodTable * pMT = ftn->GetMethodTable();
7470 if (pMT->GetModule()->IsSystem())
7472 if (MscorlibBinder::IsClass(pMT, CLASS__JIT_HELPERS))
7474 fILIntrinsic = getILIntrinsicImplementation(ftn, methInfo);
7476 else if (MscorlibBinder::IsClass(pMT, CLASS__UNSAFE))
7478 fILIntrinsic = getILIntrinsicImplementationForUnsafe(ftn, methInfo);
7480 else if (MscorlibBinder::IsClass(pMT, CLASS__INTERLOCKED))
7482 fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo);
7484 else if (MscorlibBinder::IsClass(pMT, CLASS__VOLATILE))
7486 fILIntrinsic = getILIntrinsicImplementationForVolatile(ftn, methInfo);
7488 else if (MscorlibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS))
7490 fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo);
7496 getMethodInfoILMethodHeaderHelper(header, methInfo);
7497 pLocalSig = header->LocalVarSig;
7498 cbLocalSig = header->cbLocalVarSig;
7503 _ASSERTE(ftn->IsDynamicMethod());
7505 DynamicResolver * pResolver = ftn->AsDynamicMethodDesc()->GetResolver();
7506 unsigned int EHCount;
7507 methInfo->ILCode = pResolver->GetCodeInfo(&methInfo->ILCodeSize,
7508 &methInfo->maxStack,
7511 methInfo->EHcount = (unsigned short)EHCount;
7512 SigPointer localSig = pResolver->GetLocalSig();
7513 localSig.GetSignature(&pLocalSig, &cbLocalSig);
7516 methInfo->options = (CorInfoOptions)(((UINT32)methInfo->options) |
7517 ((ftn->AcquiresInstMethodTableFromThis() ? CORINFO_GENERICS_CTXT_FROM_THIS : 0) |
7518 (ftn->RequiresInstMethodTableArg() ? CORINFO_GENERICS_CTXT_FROM_METHODTABLE : 0) |
7519 (ftn->RequiresInstMethodDescArg() ? CORINFO_GENERICS_CTXT_FROM_METHODDESC : 0)));
7521 // EEJitManager::ResolveEHClause and CrawlFrame::GetExactGenericInstantiations
7522 // need to be able to get to CORINFO_GENERICS_CTXT_MASK if there are any
7523 // catch clauses like "try {} catch(MyException<T> e) {}".
7524 // Such constructs are rare, and having to extend the lifetime of variable
7525 // for such cases is reasonable
7527 if (methInfo->options & CORINFO_GENERICS_CTXT_MASK)
7529 #if defined(PROFILING_SUPPORTED)
7530 BOOL fProfilerRequiresGenericsContextForEnterLeave = FALSE;
7532 BEGIN_PIN_PROFILER(CORProfilerPresent());
7533 if (g_profControlBlock.pProfInterface->RequiresGenericsContextForEnterLeave())
7535 fProfilerRequiresGenericsContextForEnterLeave = TRUE;
7539 if (fProfilerRequiresGenericsContextForEnterLeave)
7541 methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7544 #endif // defined(PROFILING_SUPPORTED)
7546 // Check all the exception clauses
7548 if (ftn->IsDynamicMethod())
7550 // @TODO: how do we detect the need to mark this flag?
7554 COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
7556 for (unsigned i = 0; i < methInfo->EHcount; i++)
7558 const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo =
7559 (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)header->EH->EHClause(i, &ehClause);
7561 // Is it a typed catch clause?
7562 if (ehInfo->GetFlags() != COR_ILEXCEPTION_CLAUSE_NONE)
7565 // Check if we catch "C<T>" ?
7567 DWORD catchTypeToken = ehInfo->GetClassToken();
7568 if (TypeFromToken(catchTypeToken) != mdtTypeSpec)
7571 PCCOR_SIGNATURE pSig;
7573 IfFailThrow(ftn->GetMDImport()->GetTypeSpecFromToken(catchTypeToken, &pSig, &cSig));
7575 SigPointer psig(pSig, cSig);
7577 SigTypeContext sigTypeContext(ftn);
7578 if (psig.IsPolyType(&sigTypeContext) & hasSharableVarsMask)
7580 methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7588 PCCOR_SIGNATURE pSig = NULL;
7590 ftn->GetSig(&pSig, &cbSig);
7592 /* Fetch the method signature */
7593 // Type parameters in the signature should be instantiated according to the
7594 // class/method/array instantiation of ftnHnd
7595 CEEInfo::ConvToJitSig(
7598 GetScopeHandle(ftn),
7604 // Shared generic or static per-inst methods and shared methods on generic structs
7605 // take an extra argument representing their instantiation
7606 if (ftn->RequiresInstArg())
7607 methInfo->args.callConv = (CorInfoCallConv)(methInfo->args.callConv | CORINFO_CALLCONV_PARAMTYPE);
7609 _ASSERTE((IsMdStatic(ftn->GetAttrs()) == 0) == ((methInfo->args.callConv & CORINFO_CALLCONV_HASTHIS) != 0));
7611 /* And its local variables */
7612 // Type parameters in the signature should be instantiated according to the
7613 // class/method/array instantiation of ftnHnd
7614 CEEInfo::ConvToJitSig(
7617 GetScopeHandle(ftn),
7622 } // getMethodInfoHelper
7624 //---------------------------------------------------------------------------------------
7627 CEEInfo::getMethodInfo(
7628 CORINFO_METHOD_HANDLE ftnHnd,
7629 CORINFO_METHOD_INFO * methInfo)
7638 bool result = false;
7640 JIT_TO_EE_TRANSITION();
7642 MethodDesc * ftn = GetMethod(ftnHnd);
7644 if (!ftn->IsDynamicMethod() && (!ftn->IsIL() || !ftn->GetRVA() || ftn->IsWrapperStub()))
7646 /* Return false if not IL or has no code */
7651 /* Get the IL header */
7653 if (ftn->IsDynamicMethod())
7655 getMethodInfoHelper(ftn, ftnHnd, NULL, methInfo);
7659 COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
7661 getMethodInfoHelper(ftn, ftnHnd, &header, methInfo);
7664 LOG((LF_JIT, LL_INFO100000, "Getting method info (possible inline) %s::%s%s\n",
7665 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
7670 EE_TO_JIT_TRANSITION();
7677 /************************************************************************
7678 Return true when ftn contains a local of type CLASS__STACKCRAWMARK
7681 bool containsStackCrawlMarkLocal(MethodDesc* ftn)
7683 STANDARD_VM_CONTRACT;
7685 COR_ILMETHOD* ilHeader = ftn->GetILHeader();
7688 COR_ILMETHOD_DECODER header(ilHeader, ftn->GetMDImport(), NULL);
7690 if (header.LocalVarSig == NULL)
7693 SigPointer ptr(header.LocalVarSig, header.cbLocalVarSig);
7695 IfFailThrow(ptr.GetData(NULL)); // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
7698 IfFailThrow(ptr.GetData(&numLocals));
7700 for(ULONG i = 0; i < numLocals; i++)
7702 CorElementType eType;
7703 IfFailThrow(ptr.PeekElemType(&eType));
7704 if (eType != ELEMENT_TYPE_VALUETYPE)
7706 IfFailThrow(ptr.SkipExactlyOne());
7710 IfFailThrow(ptr.GetElemType(NULL));
7713 IfFailThrow(ptr.GetToken(&token));
7715 // We are inside mscorlib - simple token match is sufficient
7716 if (token == MscorlibBinder::GetClass(CLASS__STACKCRAWMARK)->GetCl())
7725 /*************************************************************
7726 * Check if the caller and calle are in the same assembly
7727 * i.e. do not inline across assemblies
7728 *************************************************************/
7730 CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller,
7731 CORINFO_METHOD_HANDLE hCallee,
7732 DWORD* pRestrictions)
7741 CorInfoInline result = INLINE_PASS; // By default we pass.
7742 // Do not set pass in the rest of the method.
7743 DWORD dwRestrictions = 0; // By default, no restrictions
7744 const char * szFailReason = NULL; // for reportInlineDecision
7746 JIT_TO_EE_TRANSITION();
7748 // This does not work in the multi-threaded case
7750 // Caller should check this condition first
7751 _ASSERTE(!(CORINFO_FLG_DONT_INLINE & getMethodAttribsInternal(hCallee)));
7754 MethodDesc* pCaller = GetMethod(hCaller);
7755 MethodDesc* pCallee = GetMethod(hCallee);
7757 if (pCallee->IsNoMetadata())
7759 result = INLINE_FAIL;
7760 szFailReason = "Inlinee is NoMetadata";
7764 #ifdef DEBUGGING_SUPPORTED
7766 // If the callee wants debuggable code, don't allow it to be inlined
7769 // Combining the next two lines, and eliminating jitDebuggerFlags, leads to bad codegen in x86 Release builds using Visual C++ 19.00.24215.1.
7770 CORJIT_FLAGS jitDebuggerFlags = GetDebuggerCompileFlags(pCallee->GetModule(), CORJIT_FLAGS());
7771 if (jitDebuggerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE))
7773 result = INLINE_NEVER;
7774 szFailReason = "Inlinee is debuggable";
7780 // The orginal caller is the current method
7781 MethodDesc * pOrigCaller;
7782 pOrigCaller = m_pMethodBeingCompiled;
7783 Module * pOrigCallerModule;
7784 pOrigCallerModule = pOrigCaller->GetLoaderModule();
7786 if (pCallee->IsNotInline())
7788 result = INLINE_NEVER;
7789 szFailReason = "Inlinee is marked as no inline";
7793 // Also check to see if the method requires a security object. This means they call demand and
7794 // shouldn't be inlined.
7795 if (IsMdRequireSecObject(pCallee->GetAttrs()))
7797 result = INLINE_NEVER;
7798 szFailReason = "Inlinee requires a security object (or contains StackCrawlMark)";
7802 // If the method is MethodImpl'd by another method within the same type, then we have
7803 // an issue that the importer will import the wrong body. In this case, we'll just
7804 // disallow inlining because getFunctionEntryPoint will do the right thing.
7806 MethodDesc *pMDDecl = pCallee;
7807 MethodTable *pMT = pMDDecl->GetMethodTable();
7808 MethodDesc *pMDImpl = pMT->MapMethodDeclToMethodImpl(pMDDecl);
7810 if (pMDDecl != pMDImpl)
7812 result = INLINE_NEVER;
7813 szFailReason = "Inlinee is MethodImpl'd by another method within the same type";
7819 // Perform the Cross-Assembly inlining checks
7822 Module * pCalleeModule = pCallee->GetModule();
7824 #ifdef FEATURE_PREJIT
7825 Assembly * pCalleeAssembly = pCalleeModule->GetAssembly();
7829 // Make sure that all methods with StackCrawlMark are marked as IsMdRequireSecObject
7831 if (pCalleeAssembly->IsSystem())
7833 _ASSERTE(!containsStackCrawlMarkLocal(pCallee));
7837 // To allow for servicing of Ngen images we want to disable most
7838 // Cross-Assembly inlining except for the cases that we explicitly allow.
7840 if (IsCompilingForNGen())
7842 // This is an canInline call at Ngen time
7845 Assembly * pOrigCallerAssembly = pOrigCallerModule->GetAssembly();
7847 if (pCalleeAssembly == pOrigCallerAssembly)
7849 // Within the same assembly
7850 // we can freely inline with no restrictions
7854 #ifdef FEATURE_READYTORUN_COMPILER
7855 // No inlinining for version resilient code except if in the same version bubble
7856 // If this condition changes, please make the corresponding change
7857 // in getCallInfo, too.
7858 if (IsReadyToRunCompilation() &&
7860 !IsInSameVersionBubble(pCaller, pCallee)
7863 result = INLINE_NEVER;
7864 szFailReason = "Cross-module inlining in version resilient code";
7870 #endif // FEATURE_PREJIT
7872 // TODO: We can probably be smarter here if the caller is jitted, as we will
7873 // know for sure if the inlinee has really no string interning active (currently
7874 // it's only on in the ngen case (besides requiring the attribute)), but this is getting
7875 // too subtle. Will only do if somebody screams about it, as bugs here are going to
7877 if ((pOrigCallerModule != pCalleeModule) && pCalleeModule->IsNoStringInterning())
7879 dwRestrictions |= INLINE_NO_CALLEE_LDSTR;
7883 #ifdef PROFILING_SUPPORTED
7884 if (CORProfilerPresent())
7888 // Currently the rejit path is the only path which sets this.
7889 // If we get more reasons to set this then we may need to change
7890 // the failure reason message or disambiguate them.
7891 if (!m_allowInlining)
7893 result = INLINE_FAIL;
7894 szFailReason = "ReJIT request disabled inlining from caller";
7898 // If the profiler has set a mask preventing inlining, always return
7899 // false to the jit.
7900 if (CORProfilerDisableInlining())
7902 result = INLINE_FAIL;
7903 szFailReason = "Profiler disabled inlining globally";
7907 // If the profiler wishes to be notified of JIT events and the result from
7908 // the above tests will cause a function to be inlined, we need to tell the
7909 // profiler that this inlining is going to take place, and give them a
7910 // chance to prevent it.
7912 BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo());
7913 if (pCaller->IsILStub() || pCallee->IsILStub())
7921 HRESULT hr = g_profControlBlock.pProfInterface->JITInlining(
7922 (FunctionID)pCaller,
7923 (FunctionID)pCallee,
7926 if (SUCCEEDED(hr) && !fShouldInline)
7928 result = INLINE_FAIL;
7929 szFailReason = "Profiler disabled inlining locally";
7936 #endif // PROFILING_SUPPORTED
7940 EE_TO_JIT_TRANSITION();
7942 if (result == INLINE_PASS && dwRestrictions)
7946 *pRestrictions = dwRestrictions;
7950 // If the jitter didn't want to know about restrictions, it shouldn't be inlining
7951 result = INLINE_FAIL;
7952 szFailReason = "Inlinee has restrictions the JIT doesn't want";
7959 // Denied inlining, makes no sense to pass out restrictions,
7964 if (dontInline(result))
7966 // If you hit this assert, it means you added a new way to prevent inlining
7967 // without documenting it for ETW!
7968 _ASSERTE(szFailReason != NULL);
7969 reportInliningDecision(hCaller, hCallee, result, szFailReason);
7975 void CEEInfo::reportInliningDecision (CORINFO_METHOD_HANDLE inlinerHnd,
7976 CORINFO_METHOD_HANDLE inlineeHnd,
7977 CorInfoInline inlineResult,
7978 const char * reason)
7980 STATIC_CONTRACT_THROWS;
7981 STATIC_CONTRACT_GC_TRIGGERS;
7982 STATIC_CONTRACT_SO_TOLERANT;
7984 JIT_TO_EE_TRANSITION();
7987 if (LoggingOn(LF_JIT, LL_INFO100000))
7989 SString currentMethodName;
7990 currentMethodName.AppendUTF8(m_pMethodBeingCompiled->GetModule_NoLogging()->GetFile()->GetSimpleName());
7991 currentMethodName.Append(L'/');
7992 TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled, TypeString::FormatBasic);
7994 SString inlineeMethodName;
7995 if (GetMethod(inlineeHnd))
7997 inlineeMethodName.AppendUTF8(GetMethod(inlineeHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
7998 inlineeMethodName.Append(L'/');
7999 TypeString::AppendMethodInternal(inlineeMethodName, GetMethod(inlineeHnd), TypeString::FormatBasic);
8003 inlineeMethodName.AppendASCII( "<null>" );
8006 SString inlinerMethodName;
8007 if (GetMethod(inlinerHnd))
8009 inlinerMethodName.AppendUTF8(GetMethod(inlinerHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
8010 inlinerMethodName.Append(L'/');
8011 TypeString::AppendMethodInternal(inlinerMethodName, GetMethod(inlinerHnd), TypeString::FormatBasic);
8015 inlinerMethodName.AppendASCII("<null>");
8018 if (dontInline(inlineResult))
8020 LOG((LF_JIT, LL_INFO100000,
8021 "While compiling '%S', inline of '%S' into '%S' failed because: '%s'.\n",
8022 currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
8023 inlinerMethodName.GetUnicode(), reason));
8027 LOG((LF_JIT, LL_INFO100000, "While compiling '%S', inline of '%S' into '%S' succeeded.\n",
8028 currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
8029 inlinerMethodName.GetUnicode()));
8035 //I'm gonna duplicate this code because the format is slightly different. And LoggingOn is debug only.
8036 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
8037 TRACE_LEVEL_VERBOSE,
8038 CLR_JITTRACING_KEYWORD))
8040 SString methodBeingCompiledNames[3];
8041 SString inlinerNames[3];
8042 SString inlineeNames[3];
8043 MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8044 #define GMI(pMD, strArray) \
8047 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8049 (strArray)[0].Set(W("<null>")); \
8050 (strArray)[1].Set(W("<null>")); \
8051 (strArray)[2].Set(W("<null>")); \
8054 GMI(methodBeingCompiled, methodBeingCompiledNames);
8055 GMI(GetMethod(inlinerHnd), inlinerNames);
8056 GMI(GetMethod(inlineeHnd), inlineeNames);
8058 if (dontInline(inlineResult))
8060 const char * str = (reason ? reason : "");
8062 strReason.SetANSI(str);
8065 FireEtwMethodJitInliningFailed(methodBeingCompiledNames[0].GetUnicode(),
8066 methodBeingCompiledNames[1].GetUnicode(),
8067 methodBeingCompiledNames[2].GetUnicode(),
8068 inlinerNames[0].GetUnicode(),
8069 inlinerNames[1].GetUnicode(),
8070 inlinerNames[2].GetUnicode(),
8071 inlineeNames[0].GetUnicode(),
8072 inlineeNames[1].GetUnicode(),
8073 inlineeNames[2].GetUnicode(),
8074 inlineResult == INLINE_NEVER,
8075 strReason.GetUnicode(),
8076 GetClrInstanceId());
8080 FireEtwMethodJitInliningSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8081 methodBeingCompiledNames[1].GetUnicode(),
8082 methodBeingCompiledNames[2].GetUnicode(),
8083 inlinerNames[0].GetUnicode(),
8084 inlinerNames[1].GetUnicode(),
8085 inlinerNames[2].GetUnicode(),
8086 inlineeNames[0].GetUnicode(),
8087 inlineeNames[1].GetUnicode(),
8088 inlineeNames[2].GetUnicode(),
8089 GetClrInstanceId());
8094 EE_TO_JIT_TRANSITION();
8098 /*************************************************************
8099 This loads the (formal) declared constraints on the class and method type parameters,
8100 and detects (but does not itself reject) circularities among the class type parameters
8101 and (separately) method type parameters.
8103 It must be called whenever we verify a typical method, ie any method (generic or
8104 nongeneric) in a typical class. It must be called for non-generic methods too,
8105 because their bodies may still mention class type parameters which will need to
8106 have their formal constraints loaded in order to perform type compatibility tests.
8108 We have to rule out cycles like "C<U,T> where T:U, U:T" only to avoid looping
8109 in the verifier (ie the T.CanCast(A) would loop calling U.CanCast(A) then
8110 T.CanCastTo(A) etc.). Since the JIT only tries to walk the hierarchy from a type
8111 a parameter when verifying, it should be safe to JIT unverified, but trusted,
8112 instantiations even in the presence of cycle constraints.
8113 @TODO: It should be possible (and easy) to detect cycles much earlier on by
8114 directly inspecting the metadata. All you have to do is check that, for each
8115 of the n type parameters to a class or method there is no path of length n
8116 obtained by following naked type parameter constraints of the same kind.
8117 This can be detected by looking directly at metadata, without actually loading
8118 the typehandles for the naked type parameters.
8119 *************************************************************/
8121 void CEEInfo::initConstraintsForVerification(CORINFO_METHOD_HANDLE hMethod,
8122 BOOL *pfHasCircularClassConstraints,
8123 BOOL *pfHasCircularMethodConstraints)
8130 PRECONDITION(CheckPointer(pfHasCircularClassConstraints));
8131 PRECONDITION(CheckPointer(pfHasCircularMethodConstraints));
8134 *pfHasCircularClassConstraints = FALSE;
8135 *pfHasCircularMethodConstraints = FALSE;
8137 JIT_TO_EE_TRANSITION();
8139 MethodDesc* pMethod = GetMethod(hMethod);
8140 if (pMethod->IsTypicalMethodDefinition())
8142 // Force a load of the constraints on the type parameters, detecting cyclic bounds
8143 pMethod->LoadConstraintsForTypicalMethodDefinition(pfHasCircularClassConstraints,pfHasCircularMethodConstraints);
8146 EE_TO_JIT_TRANSITION();
8149 /*************************************************************
8150 * Check if a method to be compiled is an instantiation
8151 * of generic code that has already been verified.
8152 * Three possible return values (see corinfo.h)
8153 *************************************************************/
8155 CorInfoInstantiationVerification
8156 CEEInfo::isInstantiationOfVerifiedGeneric(CORINFO_METHOD_HANDLE hMethod)
8165 CorInfoInstantiationVerification result = INSTVER_NOT_INSTANTIATION;
8167 JIT_TO_EE_TRANSITION();
8169 MethodDesc * pMethod = GetMethod(hMethod);
8171 if (!(pMethod->HasClassOrMethodInstantiation()))
8173 result = INSTVER_NOT_INSTANTIATION;
8177 if (pMethod->IsTypicalMethodDefinition())
8179 result = INSTVER_NOT_INSTANTIATION;
8183 result = INSTVER_GENERIC_PASSED_VERIFICATION;
8187 EE_TO_JIT_TRANSITION();
8192 /*************************************************************
8193 * Similar to above, but perform check for tail call
8194 * eligibility. The callee can be passed as NULL if not known
8195 * (calli and callvirt).
8196 *************************************************************/
8198 bool CEEInfo::canTailCall (CORINFO_METHOD_HANDLE hCaller,
8199 CORINFO_METHOD_HANDLE hDeclaredCallee,
8200 CORINFO_METHOD_HANDLE hExactCallee,
8210 bool result = false;
8211 const char * szFailReason = NULL;
8213 JIT_TO_EE_TRANSITION();
8215 // See comments in canInline above.
8217 MethodDesc* pCaller = GetMethod(hCaller);
8218 MethodDesc* pDeclaredCallee = GetMethod(hDeclaredCallee);
8219 MethodDesc* pExactCallee = GetMethod(hExactCallee);
8221 _ASSERTE(pCaller->GetModule());
8222 _ASSERTE(pCaller->GetModule()->GetClassLoader());
8224 _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule());
8225 _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule()->GetClassLoader());
8227 // If the caller is the static constructor (.cctor) of a class which has a ComImport base class
8228 // somewhere up the class hierarchy, then we cannot make the call into a tailcall. See
8229 // RegisterObjectCreationCallback() in ExtensibleClassFactory.cpp for more information.
8230 if (pCaller->IsClassConstructor() &&
8231 pCaller->GetMethodTable()->IsComObjectType())
8234 szFailReason = "Caller is ComImport .cctor";
8240 mdMethodDef callerToken = pCaller->GetMemberDef();
8242 // We don't want to tailcall the entrypoint for an application; JIT64 will sometimes
8243 // do this for simple entrypoints and it results in a rather confusing debugging
8245 if (callerToken == pCaller->GetModule()->GetEntryPointToken())
8248 szFailReason = "Caller is the entry point";
8252 if (!pCaller->IsNoMetadata())
8254 // Do not tailcall from methods that are marked as noinline (people often use no-inline
8255 // to mean "I want to always see this method in stacktrace")
8256 DWORD dwImplFlags = 0;
8257 IfFailThrow(pCaller->GetMDImport()->GetMethodImplProps(callerToken, NULL, &dwImplFlags));
8259 if (IsMiNoInlining(dwImplFlags))
8262 szFailReason = "Caller is marked as no inline";
8267 // Methods with StackCrawlMark depend on finding their caller on the stack.
8268 // If we tail call one of these guys, they get confused. For lack of
8269 // a better way of identifying them, we use DynamicSecurity attribute to identify
8270 // them. We have an assert in canInline that ensures all StackCrawlMark
8271 // methods are appropriately marked.
8273 if ((pExactCallee != NULL) && IsMdRequireSecObject(pExactCallee->GetAttrs()))
8276 szFailReason = "Callee might have a StackCrawlMark.LookForMyCaller";
8286 EE_TO_JIT_TRANSITION();
8290 // If you hit this assert, it means you added a new way to prevent tail calls
8291 // without documenting it for ETW!
8292 _ASSERTE(szFailReason != NULL);
8293 reportTailCallDecision(hCaller, hExactCallee, fIsTailPrefix, TAILCALL_FAIL, szFailReason);
8299 void CEEInfo::reportTailCallDecision (CORINFO_METHOD_HANDLE callerHnd,
8300 CORINFO_METHOD_HANDLE calleeHnd,
8302 CorInfoTailCall tailCallResult,
8303 const char * reason)
8305 STATIC_CONTRACT_THROWS;
8306 STATIC_CONTRACT_GC_TRIGGERS;
8307 STATIC_CONTRACT_SO_TOLERANT;
8309 JIT_TO_EE_TRANSITION();
8311 //put code here. Make sure to report the method being compiled in addition to inliner and inlinee.
8313 if (LoggingOn(LF_JIT, LL_INFO100000))
8315 SString currentMethodName;
8316 TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled,
8317 TypeString::FormatBasic);
8319 SString calleeMethodName;
8320 if (GetMethod(calleeHnd))
8322 TypeString::AppendMethodInternal(calleeMethodName, GetMethod(calleeHnd),
8323 TypeString::FormatBasic);
8327 calleeMethodName.AppendASCII( "<null>" );
8330 SString callerMethodName;
8331 if (GetMethod(callerHnd))
8333 TypeString::AppendMethodInternal(callerMethodName, GetMethod(callerHnd),
8334 TypeString::FormatBasic);
8338 callerMethodName.AppendASCII( "<null>" );
8340 if (tailCallResult == TAILCALL_FAIL)
8342 LOG((LF_JIT, LL_INFO100000,
8343 "While compiling '%S', %Splicit tail call from '%S' to '%S' failed because: '%s'.\n",
8344 currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8345 callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), reason));
8349 static const char * const tailCallType[] = {
8350 "optimized tail call", "recursive loop", "helper assisted tailcall"
8352 _ASSERTE(tailCallResult >= 0 && (size_t)tailCallResult < _countof(tailCallType));
8353 LOG((LF_JIT, LL_INFO100000,
8354 "While compiling '%S', %Splicit tail call from '%S' to '%S' generated as a %s.\n",
8355 currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8356 callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), tailCallType[tailCallResult]));
8362 // I'm gonna duplicate this code because the format is slightly different. And LoggingOn is debug only.
8363 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
8364 TRACE_LEVEL_VERBOSE,
8365 CLR_JITTRACING_KEYWORD))
8367 SString methodBeingCompiledNames[3];
8368 SString callerNames[3];
8369 SString calleeNames[3];
8370 MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8371 #define GMI(pMD, strArray) \
8374 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8376 (strArray)[0].Set(W("<null>")); \
8377 (strArray)[1].Set(W("<null>")); \
8378 (strArray)[2].Set(W("<null>")); \
8381 GMI(methodBeingCompiled, methodBeingCompiledNames);
8382 GMI(GetMethod(callerHnd), callerNames);
8383 GMI(GetMethod(calleeHnd), calleeNames);
8385 if (tailCallResult == TAILCALL_FAIL)
8387 const char * str = (reason ? reason : "");
8389 strReason.SetANSI(str);
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(),
8401 strReason.GetUnicode(),
8402 GetClrInstanceId());
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(),
8417 GetClrInstanceId());
8423 EE_TO_JIT_TRANSITION();
8426 void CEEInfo::getEHinfoHelper(
8427 CORINFO_METHOD_HANDLE ftnHnd,
8429 CORINFO_EH_CLAUSE* clause,
8430 COR_ILMETHOD_DECODER* pILHeader)
8432 STANDARD_VM_CONTRACT;
8434 _ASSERTE(CheckPointer(pILHeader->EH));
8435 _ASSERTE(EHnumber < pILHeader->EH->EHCount());
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);
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();
8449 clause->FilterOffset = ehInfo->GetFilterOffset();
8452 /*********************************************************************/
8453 // get individual exception handler
8454 void CEEInfo::getEHinfo(
8455 CORINFO_METHOD_HANDLE ftnHnd,
8457 CORINFO_EH_CLAUSE* clause)
8466 JIT_TO_EE_TRANSITION();
8468 MethodDesc * ftn = GetMethod(ftnHnd);
8470 if (IsDynamicMethodHandle(ftnHnd))
8472 GetMethod(ftnHnd)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
8476 COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
8477 getEHinfoHelper(ftnHnd, EHnumber, clause, &header);
8480 EE_TO_JIT_TRANSITION();
8483 //---------------------------------------------------------------------------------------
8486 CEEInfo::getMethodSig(
8487 CORINFO_METHOD_HANDLE ftnHnd,
8488 CORINFO_SIG_INFO * sigRet,
8489 CORINFO_CLASS_HANDLE owner)
8498 JIT_TO_EE_TRANSITION();
8500 getMethodSigInternal(ftnHnd, sigRet, owner);
8502 EE_TO_JIT_TRANSITION();
8505 //---------------------------------------------------------------------------------------
8508 CEEInfo::getMethodSigInternal(
8509 CORINFO_METHOD_HANDLE ftnHnd,
8510 CORINFO_SIG_INFO * sigRet,
8511 CORINFO_CLASS_HANDLE owner,
8512 SignatureKind signatureKind)
8514 STANDARD_VM_CONTRACT;
8516 MethodDesc * ftn = GetMethod(ftnHnd);
8518 PCCOR_SIGNATURE pSig = NULL;
8520 ftn->GetSig(&pSig, &cbSig);
8522 // Type parameters in the signature are instantiated
8523 // according to the class/method/array instantiation of ftnHnd and owner
8524 CEEInfo::ConvToJitSig(
8527 GetScopeHandle(ftn),
8535 // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation
8536 if (ftn->RequiresInstArg())
8539 // If we are making a virtual call to an instance method on an interface, we need to lie to the JIT.
8540 // The reason being that we already made sure target is always directly callable (through instantiation stubs),
8541 // JIT should not generate shared generics aware call code and insert the secret argument again at the callsite.
8542 // Otherwise we would end up with two secret generic dictionary arguments (since the stub also provides one).
8544 BOOL isCallSiteThatGoesThroughInstantiatingStub =
8545 signatureKind == SK_VIRTUAL_CALLSITE &&
8547 ftn->GetMethodTable()->IsInterface();
8548 if (!isCallSiteThatGoesThroughInstantiatingStub)
8549 sigRet->callConv = (CorInfoCallConv) (sigRet->callConv | CORINFO_CALLCONV_PARAMTYPE);
8552 // We want the calling convention bit to be consistant with the method attribute bit
8553 _ASSERTE( (IsMdStatic(ftn->GetAttrs()) == 0) == ((sigRet->callConv & CORINFO_CALLCONV_HASTHIS) != 0) );
8556 //---------------------------------------------------------------------------------------
8558 //@GENERICSVER: for a method desc in a typical instantiation of a generic class,
8559 // this will return the typical instantiation of the generic class,
8560 // but only provided type variables are never shared.
8561 // The JIT verifier relies on this behaviour to extract the typical class from an instantiated method's typical method handle.
8563 CORINFO_CLASS_HANDLE
8564 CEEInfo::getMethodClass(
8565 CORINFO_METHOD_HANDLE methodHnd)
8574 CORINFO_CLASS_HANDLE result = NULL;
8576 JIT_TO_EE_TRANSITION();
8578 MethodDesc* method = GetMethod(methodHnd);
8580 if (method->IsDynamicMethod())
8582 DynamicResolver::SecurityControlFlags securityControlFlags = DynamicResolver::Default;
8583 TypeHandle typeOwner;
8585 DynamicResolver* pResolver = method->AsDynamicMethodDesc()->GetResolver();
8586 pResolver->GetJitContext(&securityControlFlags, &typeOwner);
8588 if (!typeOwner.IsNull() && (method == pResolver->GetDynamicMethod()))
8590 result = CORINFO_CLASS_HANDLE(typeOwner.AsPtr());
8596 TypeHandle th = TypeHandle(method->GetMethodTable());
8598 result = CORINFO_CLASS_HANDLE(th.AsPtr());
8601 EE_TO_JIT_TRANSITION();
8606 /***********************************************************************/
8607 CORINFO_MODULE_HANDLE CEEInfo::getMethodModule (CORINFO_METHOD_HANDLE methodHnd)
8616 CORINFO_MODULE_HANDLE result = NULL;
8618 JIT_TO_EE_TRANSITION_LEAF();
8620 MethodDesc* method = GetMethod(methodHnd);
8622 if (method->IsDynamicMethod())
8624 // this should never be called, thus the assert, I don't know if the (non existent) caller
8625 // expects the Module or the scope
8630 result = (CORINFO_MODULE_HANDLE) method->GetModule();
8633 EE_TO_JIT_TRANSITION_LEAF();
8638 /*********************************************************************/
8639 CorInfoIntrinsics CEEInfo::getIntrinsicID(CORINFO_METHOD_HANDLE methodHnd,
8649 CorInfoIntrinsics result = CORINFO_INTRINSIC_Illegal;
8651 JIT_TO_EE_TRANSITION();
8653 if (pMustExpand != NULL)
8655 *pMustExpand = false;
8658 MethodDesc* method = GetMethod(methodHnd);
8660 if (method->IsArray())
8662 ArrayMethodDesc * arrMethod = (ArrayMethodDesc *)method;
8663 result = arrMethod->GetIntrinsicID();
8666 if (method->IsFCall())
8668 result = ECall::GetIntrinsicID(method);
8672 MethodTable * pMT = method->GetMethodTable();
8673 if (pMT->GetModule()->IsSystem() && pMT->IsByRefLike())
8675 if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
8677 // ByReference<T> has just two methods: constructor and Value property
8678 if (method->IsCtor())
8680 result = CORINFO_INTRINSIC_ByReference_Ctor;
8684 _ASSERTE(strcmp(method->GetName(), "get_Value") == 0);
8685 result = CORINFO_INTRINSIC_ByReference_Value;
8687 if (pMustExpand != nullptr)
8689 *pMustExpand = true;
8692 else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__SPAN)))
8694 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__SPAN__GET_ITEM)))
8696 result = CORINFO_INTRINSIC_Span_GetItem;
8699 else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__READONLY_SPAN)))
8701 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__READONLY_SPAN__GET_ITEM)))
8703 result = CORINFO_INTRINSIC_ReadOnlySpan_GetItem;
8709 EE_TO_JIT_TRANSITION();
8714 /*********************************************************************/
8715 // TODO: This method should probably be renamed to something like "isSIMDType"
8716 bool CEEInfo::isInSIMDModule(CORINFO_CLASS_HANDLE classHnd)
8725 bool result = false;
8726 JIT_TO_EE_TRANSITION_LEAF();
8728 TypeHandle VMClsHnd(classHnd);
8729 PTR_MethodTable methodTable = VMClsHnd.GetMethodTable();
8730 if (methodTable->GetAssembly()->IsSIMDVectorAssembly())
8734 else if (methodTable->IsIntrinsicType())
8736 LPCUTF8 namespaceName;
8737 LPCUTF8 className = methodTable->GetFullyQualifiedNameInfo(&namespaceName);
8739 if (strcmp(className, "Vector`1") == 0 || strcmp(className, "Vector") == 0)
8741 assert(strcmp(namespaceName, "System.Numerics") == 0);
8746 EE_TO_JIT_TRANSITION_LEAF();
8751 /*********************************************************************/
8752 void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd,
8753 unsigned * pOffsetOfIndirection,
8754 unsigned * pOffsetAfterIndirection,
8764 JIT_TO_EE_TRANSITION_LEAF();
8766 MethodDesc* method = GetMethod(methodHnd);
8768 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8769 _ASSERTE(!method->HasMethodInstantiation());
8771 _ASSERTE(MethodTable::GetVtableOffset() < 256); // a rough sanity check
8773 // better be in the vtable
8774 _ASSERTE(method->GetSlot() < method->GetMethodTable()->GetNumVirtuals());
8776 *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * TARGET_POINTER_SIZE /* sizeof(MethodTable::VTableIndir_t) */;
8777 *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * TARGET_POINTER_SIZE /* sizeof(MethodTable::VTableIndir2_t) */;
8778 *isRelative = MethodTable::VTableIndir_t::isRelative ? 1 : 0;
8779 _ASSERTE(MethodTable::VTableIndir_t::isRelative == MethodTable::VTableIndir2_t::isRelative);
8781 EE_TO_JIT_TRANSITION_LEAF();
8784 /*********************************************************************/
8785 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethodHelper(CORINFO_METHOD_HANDLE baseMethod,
8786 CORINFO_CLASS_HANDLE derivedClass,
8787 CORINFO_CONTEXT_HANDLE ownerType)
8795 MethodDesc* pBaseMD = GetMethod(baseMethod);
8796 MethodTable* pBaseMT = pBaseMD->GetMethodTable();
8798 // Method better be from a fully loaded class
8799 _ASSERTE(pBaseMD->IsRestored() && pBaseMT->IsFullyLoaded());
8801 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8802 _ASSERTE(!pBaseMD->HasMethodInstantiation());
8804 // Method better be virtual
8805 _ASSERTE(pBaseMD->IsVirtual());
8807 MethodDesc* pDevirtMD = nullptr;
8809 TypeHandle DerivedClsHnd(derivedClass);
8810 MethodTable* pDerivedMT = DerivedClsHnd.GetMethodTable();
8811 _ASSERTE(pDerivedMT->IsRestored() && pDerivedMT->IsFullyLoaded());
8813 // Can't devirtualize from __Canon.
8814 if (DerivedClsHnd == TypeHandle(g_pCanonMethodTableClass))
8819 if (pBaseMT->IsInterface())
8822 #ifdef FEATURE_COMINTEROP
8823 // Don't try and devirtualize com interface calls.
8824 if (pDerivedMT->IsComObjectType())
8828 #endif // FEATURE_COMINTEROP
8830 // Interface call devirtualization.
8832 // We must ensure that pDerivedMT actually implements the
8833 // interface corresponding to pBaseMD.
8834 if (!pDerivedMT->CanCastToInterface(pBaseMT))
8839 // For generic interface methods we must have an ownerType to
8840 // safely devirtualize.
8841 if (ownerType != nullptr)
8843 TypeHandle OwnerClsHnd = GetTypeFromContext(ownerType);
8844 MethodTable* pOwnerMT = OwnerClsHnd.GetMethodTable();
8846 // If the derived class is a shared class, make sure the
8847 // owner class is too.
8848 if (pDerivedMT->IsSharedByGenericInstantiations())
8850 pOwnerMT = pOwnerMT->GetCanonicalMethodTable();
8853 // In a try block because the interface method resolution might end up being
8854 // ambiguous (diamond inheritance case of default interface methods).
8857 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(TypeHandle(pOwnerMT), pBaseMD);
8862 EX_END_CATCH(RethrowTransientExceptions)
8864 else if (!pBaseMD->HasClassOrMethodInstantiation())
8866 // In a try block because the interface method resolution might end up being
8867 // ambiguous (diamond inheritance case of default interface methods).
8870 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(pBaseMD);
8875 EX_END_CATCH(RethrowTransientExceptions)
8878 if (pDevirtMD == nullptr)
8883 // If we devirtualized into a default interface method on a generic type, we should actually return an
8884 // instantiating stub but this is not happening.
8885 // Making this work is tracked by https://github.com/dotnet/coreclr/issues/15977
8886 if (pDevirtMD->GetMethodTable()->IsInterface() && pDevirtMD->HasClassInstantiation())
8893 // Virtual call devirtualization.
8895 // The derived class should be a subclass of the the base class.
8896 MethodTable* pCheckMT = pDerivedMT;
8898 while (pCheckMT != nullptr)
8900 if (pCheckMT->HasSameTypeDefAs(pBaseMT))
8905 pCheckMT = pCheckMT->GetParentMethodTable();
8908 if (pCheckMT == nullptr)
8913 // The base method should be in the base vtable
8914 WORD slot = pBaseMD->GetSlot();
8915 _ASSERTE(slot < pBaseMT->GetNumVirtuals());
8917 // Fetch the method that would be invoked if the class were
8918 // exactly derived class. It is up to the jit to determine whether
8919 // directly calling this method is correct.
8920 pDevirtMD = pDerivedMT->GetMethodDescForSlot(slot);
8922 // If the derived method's slot does not match the vtable slot,
8923 // bail on devirtualization, as the method was installed into
8924 // the vtable slot via an explicit override and even if the
8925 // method is final, the slot may not be.
8927 // Note the jit could still safely devirtualize if it had an exact
8928 // class, but such cases are likely rare.
8929 WORD dslot = pDevirtMD->GetSlot();
8937 _ASSERTE(pDevirtMD->IsRestored());
8939 #ifdef FEATURE_READYTORUN_COMPILER
8940 // Check if devirtualization is dependent upon cross-version
8941 // bubble information and if so, disallow it.
8942 if (IsReadyToRunCompilation())
8944 MethodDesc* callerMethod = m_pMethodBeingCompiled;
8945 Assembly* pCallerAssembly = callerMethod->GetModule()->GetAssembly();
8947 IsInSameVersionBubble(pCallerAssembly , pDevirtMD->GetModule()->GetAssembly())
8948 && IsInSameVersionBubble(pCallerAssembly , pDerivedMT->GetAssembly());
8957 return (CORINFO_METHOD_HANDLE) pDevirtMD;
8960 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethod(CORINFO_METHOD_HANDLE methodHnd,
8961 CORINFO_CLASS_HANDLE derivedClass,
8962 CORINFO_CONTEXT_HANDLE ownerType)
8971 CORINFO_METHOD_HANDLE result = nullptr;
8973 JIT_TO_EE_TRANSITION();
8975 result = resolveVirtualMethodHelper(methodHnd, derivedClass, ownerType);
8977 EE_TO_JIT_TRANSITION();
8982 /*********************************************************************/
8983 CORINFO_METHOD_HANDLE CEEInfo::getUnboxedEntry(
8984 CORINFO_METHOD_HANDLE ftn,
8985 bool* requiresInstMethodTableArg)
8994 CORINFO_METHOD_HANDLE result = NULL;
8996 JIT_TO_EE_TRANSITION();
8998 MethodDesc* pMD = GetMethod(ftn);
8999 bool requiresInstMTArg = false;
9001 if (pMD->IsUnboxingStub())
9003 MethodTable* pMT = pMD->GetMethodTable();
9004 MethodDesc* pUnboxedMD = pMT->GetUnboxedEntryPointMD(pMD);
9006 result = (CORINFO_METHOD_HANDLE)pUnboxedMD;
9007 requiresInstMTArg = !!pUnboxedMD->RequiresInstMethodTableArg();
9010 if (requiresInstMethodTableArg != NULL)
9012 *requiresInstMethodTableArg = requiresInstMTArg;
9015 EE_TO_JIT_TRANSITION();
9020 /*********************************************************************/
9021 void CEEInfo::expandRawHandleIntrinsic(
9022 CORINFO_RESOLVED_TOKEN * pResolvedToken,
9023 CORINFO_GENERICHANDLE_RESULT * pResult)
9025 LIMITED_METHOD_CONTRACT;
9026 UNREACHABLE(); // only called with CoreRT.
9029 /*********************************************************************/
9030 CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE elemType)
9039 CORINFO_CLASS_HANDLE result = NULL;
9041 JIT_TO_EE_TRANSITION();
9043 result = getDefaultEqualityComparerClassHelper(elemType);
9045 EE_TO_JIT_TRANSITION();
9050 CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLASS_HANDLE elemType)
9059 // Mirrors the logic in BCL's CompareHelpers.CreateDefaultEqualityComparer
9060 // And in compile.cpp's SpecializeEqualityComparer
9061 TypeHandle elemTypeHnd(elemType);
9063 // Special case for byte
9064 if (elemTypeHnd.AsMethodTable()->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__ELEMENT_TYPE_U1)))
9066 return CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__BYTE_EQUALITYCOMPARER));
9069 // Else we'll need to find the appropriate instantation
9070 Instantiation inst(&elemTypeHnd, 1);
9072 // If T implements IEquatable<T>
9073 if (elemTypeHnd.CanCastTo(TypeHandle(MscorlibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(inst)))
9075 TypeHandle resultTh = ((TypeHandle)MscorlibBinder::GetClass(CLASS__GENERIC_EQUALITYCOMPARER)).Instantiate(inst);
9076 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
9080 if (Nullable::IsNullableType(elemTypeHnd))
9082 Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
9083 TypeHandle nullableComparer = TypeHandle(MscorlibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(nullableInst);
9084 if (nullableInst[0].CanCastTo(nullableComparer))
9086 return CORINFO_CLASS_HANDLE(nullableComparer.GetMethodTable());
9092 // We need to special case the Enum comparers based on their underlying type,
9093 // to avoid boxing and call the correct versions of GetHashCode.
9094 if (elemTypeHnd.IsEnum())
9096 MethodTable* targetClass = NULL;
9097 CorElementType normType = elemTypeHnd.GetVerifierCorElementType();
9101 case ELEMENT_TYPE_I1:
9102 case ELEMENT_TYPE_I2:
9103 case ELEMENT_TYPE_U1:
9104 case ELEMENT_TYPE_U2:
9105 case ELEMENT_TYPE_I4:
9106 case ELEMENT_TYPE_U4:
9108 targetClass = MscorlibBinder::GetClass(CLASS__ENUM_EQUALITYCOMPARER);
9112 case ELEMENT_TYPE_I8:
9113 case ELEMENT_TYPE_U8:
9115 targetClass = MscorlibBinder::GetClass(CLASS__LONG_ENUM_EQUALITYCOMPARER);
9123 if (targetClass != NULL)
9125 TypeHandle resultTh = ((TypeHandle)targetClass->GetCanonicalMethodTable()).Instantiate(inst);
9126 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
9131 TypeHandle resultTh = ((TypeHandle)MscorlibBinder::GetClass(CLASS__OBJECT_EQUALITYCOMPARER)).Instantiate(inst);
9133 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
9136 /*********************************************************************/
9137 void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd,
9138 CORINFO_CONST_LOOKUP * pResult,
9139 CORINFO_ACCESS_FLAGS accessFlags)
9149 InfoAccessType accessType = IAT_VALUE;
9151 JIT_TO_EE_TRANSITION();
9153 MethodDesc * ftn = GetMethod(ftnHnd);
9154 #if defined(FEATURE_GDBJIT)
9155 MethodDesc * orig_ftn = ftn;
9158 // Resolve methodImpl.
9159 ftn = ftn->GetMethodTable()->MapMethodDeclToMethodImpl(ftn);
9161 ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags);
9163 // TryGetMultiCallableAddrOfCode returns NULL if indirect access is desired
9166 // should never get here for EnC methods or if interception via remoting stub is required
9167 _ASSERTE(!ftn->IsEnCMethod());
9169 ret = (void *)ftn->GetAddrOfSlot();
9171 if (MethodTable::VTableIndir2_t::isRelative
9172 && ftn->IsVtableSlot())
9174 accessType = IAT_RELPVALUE;
9178 accessType = IAT_PVALUE;
9183 #if defined(FEATURE_GDBJIT)
9184 CalledMethod * pCM = new CalledMethod(orig_ftn, ret, m_pCalledMethods);
9185 m_pCalledMethods = pCM;
9188 EE_TO_JIT_TRANSITION();
9190 _ASSERTE(ret != NULL);
9192 pResult->accessType = accessType;
9193 pResult->addr = ret;
9196 /*********************************************************************/
9197 void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn,
9198 CORINFO_CONST_LOOKUP * pResult)
9207 JIT_TO_EE_TRANSITION();
9209 MethodDesc * pMD = GetMethod(ftn);
9211 pResult->accessType = IAT_VALUE;
9214 #ifndef CROSSGEN_COMPILE
9215 // If LDFTN target has [NativeCallable] attribute , then create a UMEntryThunk.
9216 if (pMD->HasNativeCallableAttribute())
9218 pResult->addr = (void*)COMDelegate::ConvertToCallback(pMD);
9221 #endif //CROSSGEN_COMPILE
9223 pResult->addr = (void *)pMD->GetMultiCallableAddrOfCode();
9225 EE_TO_JIT_TRANSITION();
9228 /*********************************************************************/
9229 const char* CEEInfo::getFieldName (CORINFO_FIELD_HANDLE fieldHnd, const char** scopeName)
9238 const char* result = NULL;
9240 JIT_TO_EE_TRANSITION();
9242 FieldDesc* field = (FieldDesc*) fieldHnd;
9245 TypeHandle t = TypeHandle(field->GetApproxEnclosingMethodTable());
9250 t.GetName(ssClsNameBuff);
9251 *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
9253 // since this is for diagnostic purposes only,
9254 // give up on the namespace, as we don't have a buffer to concat it
9255 // also note this won't show array class names.
9257 *scopeName= t.GetMethodTable()->GetFullyQualifiedNameInfo(&nameSpace);
9262 result = field->GetName();
9264 EE_TO_JIT_TRANSITION();
9269 /*********************************************************************/
9270 // Get the type that declares the field
9271 CORINFO_CLASS_HANDLE CEEInfo::getFieldClass (CORINFO_FIELD_HANDLE fieldHnd)
9280 CORINFO_CLASS_HANDLE result = NULL;
9282 JIT_TO_EE_TRANSITION_LEAF();
9284 FieldDesc* field = (FieldDesc*) fieldHnd;
9285 result = CORINFO_CLASS_HANDLE(field->GetApproxEnclosingMethodTable());
9287 EE_TO_JIT_TRANSITION_LEAF();
9292 /*********************************************************************/
9293 // Returns the basic type of the field (not the the type that declares the field)
9295 // pTypeHnd - Optional. If not null then on return, for reference and value types,
9296 // *pTypeHnd will contain the normalized type of the field.
9297 // owner - Optional. For resolving in a generic context
9299 CorInfoType CEEInfo::getFieldType (CORINFO_FIELD_HANDLE fieldHnd,
9300 CORINFO_CLASS_HANDLE* pTypeHnd,
9301 CORINFO_CLASS_HANDLE owner)
9310 CorInfoType result = CORINFO_TYPE_UNDEF;
9312 JIT_TO_EE_TRANSITION();
9314 result = getFieldTypeInternal(fieldHnd, pTypeHnd, owner);
9316 EE_TO_JIT_TRANSITION();
9321 /*********************************************************************/
9322 CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd,
9323 CORINFO_CLASS_HANDLE* pTypeHnd,
9324 CORINFO_CLASS_HANDLE owner)
9326 STANDARD_VM_CONTRACT;
9328 if (pTypeHnd != nullptr)
9333 TypeHandle clsHnd = TypeHandle();
9334 FieldDesc* field = (FieldDesc*) fieldHnd;
9335 CorElementType type = field->GetFieldType();
9337 // <REVISIT_TODO>TODO should not burn the time to do this for anything but Value Classes</REVISIT_TODO>
9338 _ASSERTE(type != ELEMENT_TYPE_BYREF);
9340 if (type == ELEMENT_TYPE_I)
9342 PTR_MethodTable enclosingMethodTable = field->GetApproxEnclosingMethodTable();
9343 if (enclosingMethodTable->IsByRefLike() && enclosingMethodTable->HasSameTypeDefAs(g_pByReferenceClass))
9345 _ASSERTE(field->GetOffset() == 0);
9346 return CORINFO_TYPE_BYREF;
9350 if (!CorTypeInfo::IsPrimitiveType(type))
9352 PCCOR_SIGNATURE sig;
9354 CorCallingConvention conv;
9356 field->GetSig(&sig, &sigCount);
9358 conv = (CorCallingConvention)CorSigUncompressCallingConv(sig);
9359 _ASSERTE(isCallConv(conv, IMAGE_CEE_CS_CALLCONV_FIELD));
9361 SigPointer ptr(sig, sigCount);
9363 // For verifying code involving generics, use the class instantiation
9364 // of the optional owner (to provide exact, not representative,
9365 // type information)
9366 SigTypeContext typeContext(field, (TypeHandle)owner);
9368 clsHnd = ptr.GetTypeHandleThrowing(field->GetModule(), &typeContext);
9369 _ASSERTE(!clsHnd.IsNull());
9371 // I believe it doesn't make any diff. if this is GetInternalCorElementType
9372 // or GetSignatureCorElementType.
9373 type = clsHnd.GetSignatureCorElementType();
9376 return CEEInfo::asCorInfoType(type, clsHnd, pTypeHnd);
9379 /*********************************************************************/
9380 unsigned CEEInfo::getFieldOffset (CORINFO_FIELD_HANDLE fieldHnd)
9389 unsigned result = (unsigned) -1;
9391 JIT_TO_EE_TRANSITION();
9393 FieldDesc* field = (FieldDesc*) fieldHnd;
9395 // GetOffset() does not include the size of Object
9396 result = field->GetOffset();
9398 // So if it is not a value class, add the Object into it
9399 if (field->IsStatic())
9401 Module* pModule = field->GetModule();
9402 if (field->IsRVA() && pModule->IsRvaFieldTls(field->GetOffset()))
9404 result = pModule->GetFieldTlsOffset(field->GetOffset());
9407 else if (!field->GetApproxEnclosingMethodTable()->IsValueType())
9409 result += OBJECT_SIZE;
9412 EE_TO_JIT_TRANSITION();
9417 /*********************************************************************/
9418 bool CEEInfo::isWriteBarrierHelperRequired(CORINFO_FIELD_HANDLE field)
9427 bool fHelperRequired = false;
9429 JIT_TO_EE_TRANSITION();
9431 FieldDesc * pField = (FieldDesc *)field;
9433 // TODO: jit64 should be switched to the same plan as the i386 jits - use
9434 // getClassGClayout to figure out the need for writebarrier helper, and inline the copying.
9435 // Once this happens, USE_WRITE_BARRIER_HELPERS and CORINFO_FLG_WRITE_BARRIER_HELPER can be removed.
9436 CorElementType type = pField->GetFieldType();
9438 if(CorTypeInfo::IsObjRef(type))
9439 fHelperRequired = true;
9440 else if (type == ELEMENT_TYPE_VALUETYPE)
9442 TypeHandle th = pField->GetFieldTypeHandleThrowing();
9443 _ASSERTE(!th.IsNull());
9444 if(th.GetMethodTable()->ContainsPointers())
9445 fHelperRequired = true;
9448 EE_TO_JIT_TRANSITION();
9450 return fHelperRequired;
9453 /*********************************************************************/
9454 DWORD CEEInfo::getFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE fieldHnd, void **ppIndirection)
9465 if (ppIndirection != NULL)
9466 *ppIndirection = NULL;
9468 JIT_TO_EE_TRANSITION();
9470 FieldDesc* field = (FieldDesc*) fieldHnd;
9471 Module* module = field->GetModule();
9473 _ASSERTE(field->IsRVA()); // Only RVA statics can be thread local
9474 _ASSERTE(module->IsRvaFieldTls(field->GetOffset()));
9476 result = module->GetTlsIndex();
9478 EE_TO_JIT_TRANSITION();
9483 void *CEEInfo::allocateArray(ULONG cBytes)
9492 void * result = NULL;
9494 JIT_TO_EE_TRANSITION();
9496 result = new BYTE [cBytes];
9498 EE_TO_JIT_TRANSITION();
9503 void CEEInfo::freeArray(void *array)
9512 JIT_TO_EE_TRANSITION();
9514 delete [] ((BYTE*) array);
9516 EE_TO_JIT_TRANSITION();
9519 void CEEInfo::getBoundaries(CORINFO_METHOD_HANDLE ftn,
9520 unsigned int *cILOffsets, DWORD **pILOffsets,
9521 ICorDebugInfo::BoundaryTypes *implicitBoundaries)
9530 JIT_TO_EE_TRANSITION();
9532 #ifdef DEBUGGING_SUPPORTED
9533 if (g_pDebugInterface && !IsCompilationProcess())
9535 g_pDebugInterface->getBoundaries(GetMethod(ftn), cILOffsets, pILOffsets,
9536 implicitBoundaries);
9542 *implicitBoundaries = ICorDebugInfo::DEFAULT_BOUNDARIES;
9544 #endif // DEBUGGING_SUPPORTED
9546 EE_TO_JIT_TRANSITION();
9549 void CEEInfo::getVars(CORINFO_METHOD_HANDLE ftn, ULONG32 *cVars, ICorDebugInfo::ILVarInfo **vars,
9559 JIT_TO_EE_TRANSITION();
9561 #ifdef DEBUGGING_SUPPORTED
9562 if (g_pDebugInterface && !IsCompilationProcess())
9564 g_pDebugInterface->getVars(GetMethod(ftn), cVars, vars, extendOthers);
9571 // Just tell the JIT to extend everything.
9572 *extendOthers = true;
9574 #endif // DEBUGGING_SUPPORTED
9576 EE_TO_JIT_TRANSITION();
9579 /*********************************************************************/
9580 CORINFO_ARG_LIST_HANDLE CEEInfo::getArgNext(CORINFO_ARG_LIST_HANDLE args)
9589 CORINFO_ARG_LIST_HANDLE result = NULL;
9591 JIT_TO_EE_TRANSITION();
9593 SigPointer ptr((unsigned __int8*) args);
9594 IfFailThrow(ptr.SkipExactlyOne());
9596 result = (CORINFO_ARG_LIST_HANDLE) ptr.GetPtr();
9598 EE_TO_JIT_TRANSITION();
9604 /*********************************************************************/
9606 CorInfoTypeWithMod CEEInfo::getArgType (
9607 CORINFO_SIG_INFO* sig,
9608 CORINFO_ARG_LIST_HANDLE args,
9609 CORINFO_CLASS_HANDLE* vcTypeRet
9619 CorInfoTypeWithMod result = CorInfoTypeWithMod(CORINFO_TYPE_UNDEF);
9621 JIT_TO_EE_TRANSITION();
9623 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args && (BYTE*) args < (BYTE*) sig->pSig + sig->cbSig);
9624 _ASSERTE((BYTE*) sig->args <= (BYTE*) args);
9625 INDEBUG(*vcTypeRet = CORINFO_CLASS_HANDLE((size_t)INVALID_POINTER_CC));
9627 SigPointer ptr((unsigned __int8*) args);
9628 CorElementType eType;
9629 IfFailThrow(ptr.PeekElemType(&eType));
9630 while (eType == ELEMENT_TYPE_PINNED)
9632 result = CORINFO_TYPE_MOD_PINNED;
9633 IfFailThrow(ptr.GetElemType(NULL));
9634 IfFailThrow(ptr.PeekElemType(&eType));
9637 // Now read off the "real" element type after taking any instantiations into consideration
9638 SigTypeContext typeContext;
9639 GetTypeContext(&sig->sigInst,&typeContext);
9641 Module* pModule = GetModule(sig->scope);
9643 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9645 TypeHandle typeHnd = TypeHandle();
9647 case ELEMENT_TYPE_VAR :
9648 case ELEMENT_TYPE_MVAR :
9649 case ELEMENT_TYPE_VALUETYPE :
9650 case ELEMENT_TYPE_TYPEDBYREF :
9651 case ELEMENT_TYPE_INTERNAL :
9653 typeHnd = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9654 _ASSERTE(!typeHnd.IsNull());
9656 CorElementType normType = typeHnd.GetInternalCorElementType();
9658 // if we are looking up a value class, don't morph it to a refernece type
9659 // (This can only happen in illegal IL)
9660 if (!CorTypeInfo::IsObjRef(normType) || type != ELEMENT_TYPE_VALUETYPE)
9667 case ELEMENT_TYPE_PTR:
9668 // Load the type eagerly under debugger to make the eval work
9669 if (!isVerifyOnly() && CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
9671 // NOTE: in some IJW cases, when the type pointed at is unmanaged,
9672 // the GetTypeHandle may fail, because there is no TypeDef for such type.
9673 // Usage of GetTypeHandleThrowing would lead to class load exception
9674 TypeHandle thPtr = ptr.GetTypeHandleNT(pModule, &typeContext);
9677 m_pOverride->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(thPtr.AsPtr()));
9682 case ELEMENT_TYPE_VOID:
9683 // void is not valid in local sigs
9684 if (sig->flags & CORINFO_SIGFLAG_IS_LOCAL_SIG)
9685 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
9688 case ELEMENT_TYPE_END:
9689 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9696 result = CorInfoTypeWithMod(result | CEEInfo::asCorInfoType(type, typeHnd, vcTypeRet));
9697 EE_TO_JIT_TRANSITION();
9702 /*********************************************************************/
9704 CORINFO_CLASS_HANDLE CEEInfo::getArgClass (
9705 CORINFO_SIG_INFO* sig,
9706 CORINFO_ARG_LIST_HANDLE args
9716 CORINFO_CLASS_HANDLE result = NULL;
9718 JIT_TO_EE_TRANSITION();
9720 // make certain we dont have a completely wacked out sig pointer
9721 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args);
9722 _ASSERTE((BYTE*) sig->args <= (BYTE*) args && (BYTE*) args < &((BYTE*) sig->args)[0x10000*5]);
9724 Module* pModule = GetModule(sig->scope);
9726 SigPointer ptr((unsigned __int8*) args);
9728 CorElementType eType;
9729 IfFailThrow(ptr.PeekElemType(&eType));
9731 while (eType == ELEMENT_TYPE_PINNED)
9733 IfFailThrow(ptr.GetElemType(NULL));
9734 IfFailThrow(ptr.PeekElemType(&eType));
9736 // Now read off the "real" element type after taking any instantiations into consideration
9737 SigTypeContext typeContext;
9738 GetTypeContext(&sig->sigInst, &typeContext);
9739 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9741 if (!CorTypeInfo::IsPrimitiveType(type)) {
9742 TypeHandle th = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9743 result = CORINFO_CLASS_HANDLE(th.AsPtr());
9746 EE_TO_JIT_TRANSITION();
9751 /*********************************************************************/
9753 CorInfoType CEEInfo::getHFAType(CORINFO_CLASS_HANDLE hClass)
9762 CorInfoType result = CORINFO_TYPE_UNDEF;
9764 JIT_TO_EE_TRANSITION();
9766 TypeHandle VMClsHnd(hClass);
9768 result = asCorInfoType(VMClsHnd.GetHFAType());
9770 EE_TO_JIT_TRANSITION();
9775 /*********************************************************************/
9777 // return the unmanaged calling convention for a PInvoke
9778 CorInfoUnmanagedCallConv CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method)
9787 CorInfoUnmanagedCallConv result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9789 JIT_TO_EE_TRANSITION();
9791 MethodDesc* pMD = NULL;
9792 pMD = GetMethod(method);
9793 _ASSERTE(pMD->IsNDirect());
9798 PInvokeStaticSigInfo sigInfo(pMD, PInvokeStaticSigInfo::NO_THROW_ON_ERROR);
9800 switch (sigInfo.GetCallConv()) {
9801 case pmCallConvCdecl:
9802 result = CORINFO_UNMANAGED_CALLCONV_C;
9804 case pmCallConvStdcall:
9805 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9807 case pmCallConvThiscall:
9808 result = CORINFO_UNMANAGED_CALLCONV_THISCALL;
9811 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9816 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9818 EX_END_CATCH(SwallowAllExceptions)
9819 #else // !_TARGET_X86_
9821 // we have only one calling convention
9823 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9824 #endif // !_TARGET_X86_
9826 EE_TO_JIT_TRANSITION();
9831 /*********************************************************************/
9832 BOOL NDirectMethodDesc::ComputeMarshalingRequired()
9834 WRAPPER_NO_CONTRACT;
9836 return NDirect::MarshalingRequired(this);
9839 /*********************************************************************/
9840 BOOL CEEInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig)
9849 BOOL result = FALSE;
9851 JIT_TO_EE_TRANSITION();
9855 MethodDesc* ftn = GetMethod(method);
9856 _ASSERTE(ftn->IsNDirect());
9857 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9859 #if defined(HAS_NDIRECT_IMPORT_PRECODE)
9860 if (pMD->IsVarArg())
9862 // Varag P/Invoke must not be inlined because its NDirectMethodDesc
9863 // does not contain a meaningful stack size (it is call site specific).
9864 // See code:InlinedCallFrame.UpdateRegDisplay where this is needed.
9867 else if (pMD->MarshalingRequired())
9869 // This is not a no-marshal signature.
9874 // This is a no-marshal non-vararg signature.
9878 // Marshalling is required to lazy initialize the indirection cell
9879 // without NDirectImportPrecode.
9885 // check the call site signature
9886 result = NDirect::MarshalingRequired(
9889 GetModule(callSiteSig->scope));
9892 EE_TO_JIT_TRANSITION();
9897 /*********************************************************************/
9898 // Generate a cookie based on the signature that would needs to be passed
9899 // to CORINFO_HELP_PINVOKE_CALLI
9900 LPVOID CEEInfo::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig,
9901 void **ppIndirection)
9903 WRAPPER_NO_CONTRACT;
9905 return getVarArgsHandle(szMetaSig, ppIndirection);
9908 bool CEEInfo::canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig)
9910 LIMITED_METHOD_CONTRACT;
9915 // Check any constraints on method type arguments
9916 BOOL CEEInfo::satisfiesMethodConstraints(
9917 CORINFO_CLASS_HANDLE parent,
9918 CORINFO_METHOD_HANDLE method)
9927 BOOL result = FALSE;
9929 JIT_TO_EE_TRANSITION();
9931 _ASSERTE(parent != NULL);
9932 _ASSERTE(method != NULL);
9933 result = GetMethod(method)->SatisfiesMethodConstraints(TypeHandle(parent));
9935 EE_TO_JIT_TRANSITION();
9942 /*********************************************************************/
9943 // Given a delegate target class, a target method parent class, a target method,
9944 // a delegate class, check if the method signature is compatible with the Invoke method of the delegate
9945 // (under the typical instantiation of any free type variables in the memberref signatures).
9947 // objCls should be NULL if the target object is NULL
9948 //@GENERICSVER: new (suitable for generics)
9949 BOOL CEEInfo::isCompatibleDelegate(
9950 CORINFO_CLASS_HANDLE objCls,
9951 CORINFO_CLASS_HANDLE methodParentCls,
9952 CORINFO_METHOD_HANDLE method,
9953 CORINFO_CLASS_HANDLE delegateCls,
9954 BOOL* pfIsOpenDelegate)
9963 BOOL result = FALSE;
9965 JIT_TO_EE_TRANSITION();
9967 _ASSERTE(method != NULL);
9968 _ASSERTE(delegateCls != NULL);
9970 TypeHandle delegateClsHnd = (TypeHandle) delegateCls;
9972 _ASSERTE(delegateClsHnd.GetMethodTable()->IsDelegate());
9974 TypeHandle methodParentHnd = (TypeHandle) (methodParentCls);
9975 MethodDesc* pMDFtn = GetMethod(method);
9976 TypeHandle objClsHnd(objCls);
9980 result = COMDelegate::ValidateCtor(objClsHnd, methodParentHnd, pMDFtn, delegateClsHnd, pfIsOpenDelegate);
9985 EX_END_CATCH(SwallowAllExceptions)
9987 EE_TO_JIT_TRANSITION();
9992 /*********************************************************************/
9993 // return the unmanaged target *if method has already been prelinked.*
9994 void* CEEInfo::getPInvokeUnmanagedTarget(CORINFO_METHOD_HANDLE method,
9995 void **ppIndirection)
10004 // Not expected to work due to multicore and tiered JIT potentially needing
10005 // to call managed cctors
10008 if (ppIndirection != NULL)
10010 *ppIndirection = NULL;
10016 /*********************************************************************/
10017 // return address of fixup area for late-bound N/Direct calls.
10018 void* CEEInfo::getAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE method,
10019 void **ppIndirection)
10028 void * result = NULL;
10030 if (ppIndirection != NULL)
10031 *ppIndirection = NULL;
10033 JIT_TO_EE_TRANSITION_LEAF();
10035 MethodDesc* ftn = GetMethod(method);
10036 _ASSERTE(ftn->IsNDirect());
10037 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
10039 result = (LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
10041 EE_TO_JIT_TRANSITION_LEAF();
10046 /*********************************************************************/
10047 // return address of fixup area for late-bound N/Direct calls.
10048 void CEEInfo::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method,
10049 CORINFO_CONST_LOOKUP *pLookup)
10051 WRAPPER_NO_CONTRACT;
10053 void *pIndirection;
10054 pLookup->accessType = IAT_PVALUE;
10055 pLookup->addr = getAddressOfPInvokeFixup(method, &pIndirection);
10056 _ASSERTE(pIndirection == NULL);
10059 /*********************************************************************/
10060 CORINFO_JUST_MY_CODE_HANDLE CEEInfo::getJustMyCodeHandle(
10061 CORINFO_METHOD_HANDLE method,
10062 CORINFO_JUST_MY_CODE_HANDLE**ppIndirection)
10071 CORINFO_JUST_MY_CODE_HANDLE result = NULL;
10074 *ppIndirection = NULL;
10076 JIT_TO_EE_TRANSITION_LEAF();
10078 // Get the flag from the debugger.
10079 MethodDesc* ftn = GetMethod(method);
10080 DWORD * pFlagAddr = NULL;
10082 if (g_pDebugInterface)
10084 pFlagAddr = g_pDebugInterface->GetJMCFlagAddr(ftn->GetModule());
10087 result = (CORINFO_JUST_MY_CODE_HANDLE) pFlagAddr;
10089 EE_TO_JIT_TRANSITION_LEAF();
10094 /*********************************************************************/
10095 void InlinedCallFrame::GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo *pInfo)
10097 LIMITED_METHOD_CONTRACT;
10099 pInfo->size = sizeof(GSCookie) + sizeof(InlinedCallFrame);
10101 pInfo->offsetOfGSCookie = 0;
10102 pInfo->offsetOfFrameVptr = sizeof(GSCookie);
10103 pInfo->offsetOfFrameLink = sizeof(GSCookie) + Frame::GetOffsetOfNextLink();
10104 pInfo->offsetOfCallSiteSP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallSiteSP);
10105 pInfo->offsetOfCalleeSavedFP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCalleeSavedFP);
10106 pInfo->offsetOfCallTarget = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_Datum);
10107 pInfo->offsetOfReturnAddress = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallerReturnAddress);
10110 /*********************************************************************/
10111 // Return details about EE internal data structures
10112 void CEEInfo::getEEInfo(CORINFO_EE_INFO *pEEInfoOut)
10121 INDEBUG(memset(pEEInfoOut, 0xCC, sizeof(*pEEInfoOut)));
10123 JIT_TO_EE_TRANSITION();
10125 if (!IsReadyToRunCompilation())
10127 InlinedCallFrame::GetEEInfo(&pEEInfoOut->inlinedCallFrameInfo);
10129 // Offsets into the Thread structure
10130 pEEInfoOut->offsetOfThreadFrame = Thread::GetOffsetOfCurrentFrame();
10131 pEEInfoOut->offsetOfGCState = Thread::GetOffsetOfGCFlag();
10135 // inlinedCallFrameInfo is not used for R2R compilation
10136 ZeroMemory(&pEEInfoOut->inlinedCallFrameInfo, sizeof(pEEInfoOut->inlinedCallFrameInfo));
10138 pEEInfoOut->offsetOfThreadFrame = (DWORD)-1;
10139 pEEInfoOut->offsetOfGCState = (DWORD)-1;
10142 #ifndef CROSSBITNESS_COMPILE
10143 // The assertions must hold in every non-crossbitness scenario
10144 _ASSERTE(OFFSETOF__DelegateObject__target == DelegateObject::GetOffsetOfTarget());
10145 _ASSERTE(OFFSETOF__DelegateObject__methodPtr == DelegateObject::GetOffsetOfMethodPtr());
10146 _ASSERTE(OFFSETOF__DelegateObject__methodPtrAux == DelegateObject::GetOffsetOfMethodPtrAux());
10147 _ASSERTE(OFFSETOF__PtrArray__m_Array_ == PtrArray::GetDataOffset());
10150 // Delegate offsets
10151 pEEInfoOut->offsetOfDelegateInstance = OFFSETOF__DelegateObject__target;
10152 pEEInfoOut->offsetOfDelegateFirstTarget = OFFSETOF__DelegateObject__methodPtr;
10154 // Secure delegate offsets
10155 pEEInfoOut->offsetOfSecureDelegateIndirectCell = OFFSETOF__DelegateObject__methodPtrAux;
10157 // Remoting offsets
10158 pEEInfoOut->offsetOfTransparentProxyRP = (DWORD)-1;
10159 pEEInfoOut->offsetOfRealProxyServer = (DWORD)-1;
10161 pEEInfoOut->offsetOfObjArrayData = OFFSETOF__PtrArray__m_Array_;
10163 pEEInfoOut->sizeOfReversePInvokeFrame = (DWORD)-1;
10165 pEEInfoOut->osPageSize = GetOsPageSize();
10166 pEEInfoOut->maxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
10167 pEEInfoOut->targetAbi = CORINFO_CORECLR_ABI;
10169 pEEInfoOut->osType = CORINFO_WINNT;
10171 // hardcode OS version to 0.0.0. These fields can be removed from JITEE interface
10172 pEEInfoOut->osMajor = 0;
10173 pEEInfoOut->osMinor = 0;
10174 pEEInfoOut->osBuild = 0;
10176 EE_TO_JIT_TRANSITION();
10179 LPCWSTR CEEInfo::getJitTimeLogFilename()
10188 LPCWSTR result = NULL;
10190 JIT_TO_EE_TRANSITION();
10191 result = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitTimeLogFile);
10192 EE_TO_JIT_TRANSITION();
10199 // Return details about EE internal data structures
10200 DWORD CEEInfo::getThreadTLSIndex(void **ppIndirection)
10209 DWORD result = (DWORD)-1;
10211 if (ppIndirection != NULL)
10212 *ppIndirection = NULL;
10217 const void * CEEInfo::getInlinedCallFrameVptr(void **ppIndirection)
10226 void * result = NULL;
10228 if (ppIndirection != NULL)
10229 *ppIndirection = NULL;
10231 JIT_TO_EE_TRANSITION_LEAF();
10233 #ifndef CROSSGEN_COMPILE
10234 result = (void*)InlinedCallFrame::GetMethodFrameVPtr();
10236 result = (void*)0x43210;
10239 EE_TO_JIT_TRANSITION_LEAF();
10244 LONG * CEEInfo::getAddrOfCaptureThreadGlobal(void **ppIndirection)
10253 LONG * result = NULL;
10255 if (ppIndirection != NULL)
10256 *ppIndirection = NULL;
10258 JIT_TO_EE_TRANSITION_LEAF();
10260 result = (LONG *)&g_TrapReturningThreads;
10262 EE_TO_JIT_TRANSITION_LEAF();
10269 HRESULT CEEInfo::GetErrorHRESULT(struct _EXCEPTION_POINTERS *pExceptionPointers)
10280 //This function is called from the JIT64 exception filter during PEVerify. Because it is a filter, it
10281 //can be "called" from a NOTHROW region in the case of StackOverflow. Security::MapToHR throws
10282 //internally, but it catches all exceptions. Therefore, none of the children can cause an exception to
10283 //percolate out of this function (except for Stack Overflow). Obviously I can't explain most of this to
10284 //the Contracts system, and I can't add this CONTRACT_VIOLATION to the filter in Jit64.
10285 CONTRACT_VIOLATION(ThrowsViolation);
10287 JIT_TO_EE_TRANSITION();
10291 OBJECTREF throwable = GetThread()->LastThrownObject();
10292 hr = GetExceptionHResult(throwable);
10294 EE_TO_JIT_TRANSITION();
10300 ULONG CEEInfo::GetErrorMessage(__inout_ecount(bufferLength) LPWSTR buffer, ULONG bufferLength)
10311 #ifndef CROSSGEN_COMPILE
10312 JIT_TO_EE_TRANSITION();
10316 OBJECTREF throwable = GetThread()->LastThrownObject();
10318 if (throwable != NULL)
10322 result = GetExceptionMessage(throwable, buffer, bufferLength);
10327 EX_END_CATCH(SwallowAllExceptions)
10330 EE_TO_JIT_TRANSITION();
10336 // This method is called from CEEInfo::FilterException which
10337 // is run as part of the SEH filter clause for the JIT.
10338 // It is fatal to throw an exception while running a SEH filter clause
10339 // so our contract is NOTHROW, NOTRIGGER.
10341 LONG EEFilterException(struct _EXCEPTION_POINTERS *pExceptionPointers, void *unused)
10351 JIT_TO_EE_TRANSITION_LEAF();
10353 VALIDATE_BACKOUT_STACK_CONSUMPTION;
10355 unsigned code = pExceptionPointers->ExceptionRecord->ExceptionCode;
10358 if (code == EXCEPTION_ACCESS_VIOLATION)
10360 static int hit = 0;
10363 _ASSERTE(!"Access violation while Jitting!");
10364 // If you set the debugger to catch access violations and 'go'
10365 // you will get back to the point at which the access violation occurred
10366 result = EXCEPTION_CONTINUE_EXECUTION;
10370 result = EXCEPTION_CONTINUE_SEARCH;
10375 // No one should be catching breakpoint
10376 // Similarly the JIT doesn't know how to reset the guard page, so it shouldn't
10377 // be catching a hard stack overflow
10378 if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP || code == EXCEPTION_STACK_OVERFLOW)
10380 result = EXCEPTION_CONTINUE_SEARCH;
10382 #ifdef CROSSGEN_COMPILE
10385 result = EXCEPTION_EXECUTE_HANDLER;
10388 else if (!IsComPlusException(pExceptionPointers->ExceptionRecord))
10390 result = EXCEPTION_EXECUTE_HANDLER;
10396 // This is actually the LastThrown exception object.
10397 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10399 if (throwable != NULL)
10403 OBJECTREF oLastThrownObject;
10406 ZeroMemory(&_gc, sizeof(_gc));
10408 // Setup the throwables
10409 _gc.oLastThrownObject = throwable;
10411 GCPROTECT_BEGIN(_gc);
10413 // Don't catch ThreadAbort and other uncatchable exceptions
10414 if (IsUncatchable(&_gc.oLastThrownObject))
10415 result = EXCEPTION_CONTINUE_SEARCH;
10417 result = EXCEPTION_EXECUTE_HANDLER;
10424 EE_TO_JIT_TRANSITION_LEAF();
10429 int CEEInfo::FilterException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10431 WRAPPER_NO_CONTRACT;
10432 return EEFilterException(pExceptionPointers, nullptr);
10435 // This code is called if FilterException chose to handle the exception.
10436 void CEEInfo::HandleException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10444 JIT_TO_EE_TRANSITION_LEAF();
10446 #ifndef CROSSGEN_COMPILE
10447 if (IsComPlusException(pExceptionPointers->ExceptionRecord))
10451 // This is actually the LastThrown exception object.
10452 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10454 if (throwable != NULL)
10458 OBJECTREF oLastThrownObject;
10459 OBJECTREF oCurrentThrowable;
10462 ZeroMemory(&_gc, sizeof(_gc));
10464 PTR_Thread pCurThread = GetThread();
10466 // Setup the throwables
10467 _gc.oLastThrownObject = throwable;
10469 // This will be NULL if no managed exception is active. Otherwise,
10470 // it will reference the active throwable.
10471 _gc.oCurrentThrowable = pCurThread->GetThrowable();
10473 GCPROTECT_BEGIN(_gc);
10475 // JIT does not use or reference managed exceptions at all and simply swallows them,
10476 // or lets them fly through so that they will either get caught in managed code, the VM
10477 // or will go unhandled.
10479 // Blind swallowing of managed exceptions can break the semantic of "which exception handler"
10480 // gets to process the managed exception first. The expected handler is managed code exception
10481 // handler (e.g. COMPlusFrameHandler on x86 and ProcessCLRException on 64bit) which will setup
10482 // the exception tracker for the exception that will enable the expected sync between the
10483 // LastThrownObject (LTO), setup in RaiseTheExceptionInternalOnly, and the exception tracker.
10485 // However, JIT can break this by swallowing the managed exception before managed code exception
10486 // handler gets a chance to setup an exception tracker for it. Since there is no cleanup
10487 // done for the swallowed exception as part of the unwind (because no exception tracker may have been setup),
10488 // we need to reset the LTO, if it is out of sync from the active throwable.
10490 // Hence, check if the LastThrownObject and active-exception throwable are in sync or not.
10491 // If not, bring them in sync.
10495 // It is possible that an exception was already in progress and while processing it (e.g.
10496 // invoking finally block), we invoked JIT that had another managed exception @ JIT-EE transition boundary
10497 // that is swallowed by the JIT before managed code exception handler sees it. This breaks the sync between
10498 // LTO and the active exception in the exception tracker.
10499 if (_gc.oCurrentThrowable != _gc.oLastThrownObject)
10503 // Note: Incase of OOM, this will get set to OOM instance.
10504 pCurThread->SafeSetLastThrownObject(_gc.oCurrentThrowable);
10512 EE_TO_JIT_TRANSITION_LEAF();
10515 void ThrowExceptionForJit(HRESULT res);
10517 void CEEInfo::ThrowExceptionForJitResult(
10527 JIT_TO_EE_TRANSITION();
10529 if (!SUCCEEDED(result))
10530 ThrowExceptionForJit(result);
10532 EE_TO_JIT_TRANSITION();
10536 CORINFO_MODULE_HANDLE CEEInfo::embedModuleHandle(CORINFO_MODULE_HANDLE handle,
10537 void **ppIndirection)
10544 PRECONDITION(!IsDynamicScope(handle));
10548 if (ppIndirection != NULL)
10549 *ppIndirection = NULL;
10551 JIT_TO_EE_TRANSITION_LEAF();
10553 EE_TO_JIT_TRANSITION_LEAF();
10558 CORINFO_CLASS_HANDLE CEEInfo::embedClassHandle(CORINFO_CLASS_HANDLE handle,
10559 void **ppIndirection)
10569 if (ppIndirection != NULL)
10570 *ppIndirection = NULL;
10572 JIT_TO_EE_TRANSITION_LEAF();
10574 EE_TO_JIT_TRANSITION_LEAF();
10579 CORINFO_FIELD_HANDLE CEEInfo::embedFieldHandle(CORINFO_FIELD_HANDLE handle,
10580 void **ppIndirection)
10590 if (ppIndirection != NULL)
10591 *ppIndirection = NULL;
10593 JIT_TO_EE_TRANSITION_LEAF();
10595 EE_TO_JIT_TRANSITION_LEAF();
10600 CORINFO_METHOD_HANDLE CEEInfo::embedMethodHandle(CORINFO_METHOD_HANDLE handle,
10601 void **ppIndirection)
10611 if (ppIndirection != NULL)
10612 *ppIndirection = NULL;
10614 JIT_TO_EE_TRANSITION_LEAF();
10616 EE_TO_JIT_TRANSITION_LEAF();
10621 /*********************************************************************/
10622 void CEEInfo::setJitFlags(const CORJIT_FLAGS& jitFlags)
10624 LIMITED_METHOD_CONTRACT;
10626 m_jitFlags = jitFlags;
10629 /*********************************************************************/
10630 DWORD CEEInfo::getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes)
10639 JIT_TO_EE_TRANSITION_LEAF();
10641 _ASSERTE(sizeInBytes >= sizeof(m_jitFlags));
10642 *jitFlags = m_jitFlags;
10644 EE_TO_JIT_TRANSITION_LEAF();
10646 return sizeof(m_jitFlags);
10649 /*********************************************************************/
10650 #if !defined(PLATFORM_UNIX)
10652 struct RunWithErrorTrapFilterParam
10654 ICorDynamicInfo* m_corInfo;
10655 void (*m_function)(void*);
10657 EXCEPTION_POINTERS m_exceptionPointers;
10660 static LONG RunWithErrorTrapFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
10662 WRAPPER_NO_CONTRACT;
10664 auto* param = reinterpret_cast<RunWithErrorTrapFilterParam*>(theParam);
10665 param->m_exceptionPointers = *exceptionPointers;
10666 return param->m_corInfo->FilterException(exceptionPointers);
10669 #endif // !defined(PLATFORM_UNIX)
10671 bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param)
10673 // No dynamic contract here because SEH is used
10674 STATIC_CONTRACT_THROWS;
10675 STATIC_CONTRACT_GC_TRIGGERS;
10676 STATIC_CONTRACT_SO_TOLERANT;
10677 STATIC_CONTRACT_MODE_PREEMPTIVE;
10679 // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
10680 // transitions into the EE proper should occur either via the call to
10681 // `EEFilterException` (which is appropriately marked) or via JIT/EE
10682 // interface calls made by `function`.
10684 bool success = true;
10686 #if !defined(PLATFORM_UNIX)
10688 RunWithErrorTrapFilterParam trapParam;
10689 trapParam.m_corInfo = m_pOverride == nullptr ? this : m_pOverride;
10690 trapParam.m_function = function;
10691 trapParam.m_param = param;
10693 PAL_TRY(RunWithErrorTrapFilterParam*, pTrapParam, &trapParam)
10695 pTrapParam->m_function(pTrapParam->m_param);
10697 PAL_EXCEPT_FILTER(RunWithErrorTrapFilter)
10699 HandleException(&trapParam.m_exceptionPointers);
10704 #else // !defined(PLATFORM_UNIX)
10706 // We shouldn't need PAL_TRY on *nix: any exceptions that we are able to catch
10707 // ought to originate from the runtime itself and should be catchable inside of
10708 // EX_TRY/EX_CATCH, including emulated SEH exceptions.
10717 EX_END_CATCH(RethrowTerminalExceptions);
10724 /*********************************************************************/
10725 IEEMemoryManager* CEEInfo::getMemoryManager()
10734 IEEMemoryManager* result = NULL;
10736 JIT_TO_EE_TRANSITION_LEAF();
10738 result = GetEEMemoryManager();
10740 EE_TO_JIT_TRANSITION_LEAF();
10745 /*********************************************************************/
10746 int CEEInfo::doAssert(const char* szFile, int iLine, const char* szExpr)
10748 STATIC_CONTRACT_SO_TOLERANT;
10749 STATIC_CONTRACT_THROWS;
10750 STATIC_CONTRACT_GC_TRIGGERS;
10751 STATIC_CONTRACT_MODE_PREEMPTIVE;
10752 STATIC_CONTRACT_DEBUG_ONLY;
10756 JIT_TO_EE_TRANSITION();
10758 #ifdef CROSSGEN_COMPILE
10759 ThrowHR(COR_E_INVALIDPROGRAM);
10763 BEGIN_DEBUG_ONLY_CODE;
10764 result = _DbgBreakCheck(szFile, iLine, szExpr);
10765 END_DEBUG_ONLY_CODE;
10767 result = 1; // break into debugger
10772 EE_TO_JIT_TRANSITION();
10777 void CEEInfo::reportFatalError(CorJitResult result)
10779 STATIC_CONTRACT_SO_TOLERANT;
10780 STATIC_CONTRACT_THROWS;
10781 STATIC_CONTRACT_GC_TRIGGERS;
10782 STATIC_CONTRACT_MODE_PREEMPTIVE;
10784 JIT_TO_EE_TRANSITION_LEAF();
10786 STRESS_LOG2(LF_JIT,LL_ERROR, "Jit reported error 0x%x while compiling 0x%p\n",
10787 (int)result, (INT_PTR)getMethodBeingCompiled());
10789 EE_TO_JIT_TRANSITION_LEAF();
10792 BOOL CEEInfo::logMsg(unsigned level, const char* fmt, va_list args)
10794 STATIC_CONTRACT_SO_TOLERANT;
10795 STATIC_CONTRACT_THROWS;
10796 STATIC_CONTRACT_GC_TRIGGERS;
10797 STATIC_CONTRACT_MODE_PREEMPTIVE;
10798 STATIC_CONTRACT_DEBUG_ONLY;
10800 BOOL result = FALSE;
10802 JIT_TO_EE_TRANSITION_LEAF();
10805 if (LoggingOn(LF_JIT, level))
10807 LogSpewValist(LF_JIT, level, (char*) fmt, args);
10812 EE_TO_JIT_TRANSITION_LEAF();
10817 void CEEInfo::yieldExecution()
10819 WRAPPER_NO_CONTRACT;
10823 #ifndef CROSSGEN_COMPILE
10825 /*********************************************************************/
10827 void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
10828 void ** ppIndirection) /* OUT */
10837 void* result = NULL;
10839 if (ppIndirection != NULL)
10840 *ppIndirection = NULL;
10842 JIT_TO_EE_TRANSITION_LEAF();
10844 _ASSERTE(ftnNum < CORINFO_HELP_COUNT);
10846 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10848 size_t dynamicFtnNum = ((size_t)pfnHelper - 1);
10849 if (dynamicFtnNum < DYNAMIC_CORINFO_HELP_COUNT)
10852 #pragma warning(push)
10853 #pragma warning(disable:26001) // "Bounds checked above using the underflow trick"
10854 #endif /*_PREFAST_ */
10856 #if defined(_TARGET_AMD64_)
10857 // To avoid using a jump stub we always call certain helpers using an indirect call.
10858 // Because when using a direct call and the target is father away than 2^31 bytes,
10859 // the direct call instead goes to a jump stub which jumps to the jit helper.
10860 // However in this process the jump stub will corrupt RAX.
10862 // The set of helpers for which RAX must be preserved are the profiler probes
10863 // and the STOP_FOR_GC helper which maps to JIT_RareDisableHelper.
10864 // In the case of the STOP_FOR_GC helper RAX can be holding a function return value.
10866 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_STOP_FOR_GC ||
10867 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER ||
10868 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE ||
10869 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL)
10871 _ASSERTE(ppIndirection != NULL);
10872 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10877 #if defined(ENABLE_FAST_GCPOLL_HELPER)
10878 //always call this indirectly so that we can swap GC Poll helpers.
10879 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_POLL_GC)
10881 _ASSERTE(ppIndirection != NULL);
10882 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10887 pfnHelper = hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10890 #pragma warning(pop)
10891 #endif /*_PREFAST_*/
10894 _ASSERTE(pfnHelper);
10896 result = (LPVOID)GetEEFuncEntryPoint(pfnHelper);
10898 EE_TO_JIT_TRANSITION_LEAF();
10903 PCODE CEEJitInfo::getHelperFtnStatic(CorInfoHelpFunc ftnNum)
10905 LIMITED_METHOD_CONTRACT;
10907 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10909 // If pfnHelper is an index into the dynamic helper table, it should be less
10910 // than DYNAMIC_CORINFO_HELP_COUNT. In this case we need to find the actual pfnHelper
10911 // using an extra indirection. Note the special case
10912 // where pfnHelper==0 where pfnHelper-1 will underflow and we will avoid the indirection.
10913 if (((size_t)pfnHelper - 1) < DYNAMIC_CORINFO_HELP_COUNT)
10915 pfnHelper = hlpDynamicFuncTable[((size_t)pfnHelper - 1)].pfnHelper;
10918 _ASSERTE(pfnHelper != NULL);
10920 return GetEEFuncEntryPoint(pfnHelper);
10923 void CEEJitInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
10928 PRECONDITION(CheckPointer(moduleFrom));
10929 PRECONDITION(!IsDynamicScope(moduleFrom));
10930 PRECONDITION(CheckPointer(moduleTo));
10931 PRECONDITION(!IsDynamicScope(moduleTo));
10932 PRECONDITION(moduleFrom != moduleTo);
10936 // This is only called internaly. JIT-EE transition is not needed.
10937 // JIT_TO_EE_TRANSITION();
10939 Module *dependency = (Module *)moduleTo;
10940 _ASSERTE(!dependency->IsSystem());
10942 if (m_pMethodBeingCompiled->IsLCGMethod())
10944 // The context module of the m_pMethodBeingCompiled is irrelevant. Rather than tracking
10945 // the dependency, we just do immediate activation.
10946 dependency->EnsureActive();
10950 #ifdef FEATURE_LOADER_OPTIMIZATION
10951 Module *context = (Module *)moduleFrom;
10953 // Record active dependency for loader.
10954 context->AddActiveDependency(dependency, FALSE);
10956 dependency->EnsureActive();
10960 // EE_TO_JIT_TRANSITION();
10964 // Wrapper around CEEInfo::GetProfilingHandle. The first time this is called for a
10965 // method desc, it calls through to EEToProfInterfaceImpl::EEFunctionIDMappe and caches the
10966 // result in CEEJitInfo::GetProfilingHandleCache. Thereafter, this wrapper regurgitates the cached values
10967 // rather than calling into CEEInfo::GetProfilingHandle each time. This avoids
10968 // making duplicate calls into the profiler's FunctionIDMapper callback.
10969 void CEEJitInfo::GetProfilingHandle(BOOL *pbHookFunction,
10970 void **pProfilerHandle,
10971 BOOL *pbIndirectedHandles)
10980 _ASSERTE(pbHookFunction != NULL);
10981 _ASSERTE(pProfilerHandle != NULL);
10982 _ASSERTE(pbIndirectedHandles != NULL);
10984 if (!m_gphCache.m_bGphIsCacheValid)
10986 #ifdef PROFILING_SUPPORTED
10987 JIT_TO_EE_TRANSITION();
10989 // Cache not filled in, so make our first and only call to CEEInfo::GetProfilingHandle here
10991 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
10992 // they shouldnever come here as they are called out in GetCompileFlag
10993 _ASSERTE(!m_pMethodBeingCompiled->IsNoMetadata());
10995 // We pass in the typical method definition to the function mapper because in
10996 // Whidbey all the profiling API transactions are done in terms of typical
10997 // method definitions not instantiations.
10998 BOOL bHookFunction = TRUE;
10999 void * profilerHandle = m_pMethodBeingCompiled;
11002 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
11003 profilerHandle = (void *)g_profControlBlock.pProfInterface->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction);
11004 END_PIN_PROFILER();
11007 m_gphCache.m_pvGphProfilerHandle = profilerHandle;
11008 m_gphCache.m_bGphHookFunction = (bHookFunction != FALSE);
11009 m_gphCache.m_bGphIsCacheValid = true;
11011 EE_TO_JIT_TRANSITION();
11012 #endif //PROFILING_SUPPORTED
11015 // Our cache of these values are bitfield bools, but the interface requires
11016 // BOOL. So to avoid setting aside a staging area on the stack for these
11017 // values, we filled them in directly in the if (not cached yet) case.
11018 *pbHookFunction = (m_gphCache.m_bGphHookFunction != false);
11020 // At this point, the remaining values must be in the cache by now, so use them
11021 *pProfilerHandle = m_gphCache.m_pvGphProfilerHandle;
11024 // This is the JIT case, which is never indirected.
11026 *pbIndirectedHandles = FALSE;
11029 /*********************************************************************/
11030 void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr)
11037 CodeHeader* pCodeHeader = GetCodeHeader();
11039 jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len);
11042 /*********************************************************************/
11043 // Route jit information to the Jit Debug store.
11044 void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
11045 ICorDebugInfo::OffsetMapping *pMap)
11054 JIT_TO_EE_TRANSITION();
11056 // We receive ownership of the array
11057 _ASSERTE(m_pOffsetMapping == NULL && m_iOffsetMapping == 0);
11058 m_iOffsetMapping = cMap;
11059 m_pOffsetMapping = pMap;
11061 EE_TO_JIT_TRANSITION();
11064 void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
11073 JIT_TO_EE_TRANSITION();
11075 // We receive ownership of the array
11076 _ASSERTE(m_pNativeVarInfo == NULL && m_iNativeVarInfo == 0);
11077 m_iNativeVarInfo = cVars;
11078 m_pNativeVarInfo = vars;
11080 EE_TO_JIT_TRANSITION();
11083 void CEEJitInfo::CompressDebugInfo()
11092 // Don't track JIT info for DynamicMethods.
11093 if (m_pMethodBeingCompiled->IsDynamicMethod())
11096 if (m_iOffsetMapping == 0 && m_iNativeVarInfo == 0)
11099 JIT_TO_EE_TRANSITION();
11103 PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars(
11104 m_pOffsetMapping, m_iOffsetMapping,
11105 m_pNativeVarInfo, m_iNativeVarInfo,
11107 m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap());
11109 GetCodeHeader()->SetDebugInfo(pDebugInfo);
11113 // Just ignore exceptions here. The debugger's structures will still be in a consistent state.
11115 EX_END_CATCH(SwallowAllExceptions)
11117 EE_TO_JIT_TRANSITION();
11120 void reservePersonalityRoutineSpace(ULONG &unwindSize)
11122 #if defined(_TARGET_X86_)
11124 #elif defined(_TARGET_AMD64_)
11125 // Add space for personality routine, it must be 4-byte aligned.
11126 // Everything in the UNWIND_INFO up to the variable-sized UnwindCodes
11127 // array has already had its size included in unwindSize by the caller.
11128 unwindSize += sizeof(ULONG);
11130 // Note that the count of unwind codes (2 bytes each) is stored as a UBYTE
11131 // So the largest size could be 510 bytes, plus the header and language
11132 // specific stuff. This can't overflow.
11134 _ASSERTE(FitsInU4(unwindSize + sizeof(ULONG)));
11135 unwindSize = (ULONG)(ALIGN_UP(unwindSize, sizeof(ULONG)));
11136 #elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
11137 // The JIT passes in a 4-byte aligned block of unwind data.
11138 _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
11140 // Add space for personality routine, it must be 4-byte aligned.
11141 unwindSize += sizeof(ULONG);
11143 PORTABILITY_ASSERT("reservePersonalityRoutineSpace");
11144 #endif // !defined(_TARGET_AMD64_)
11147 // Reserve memory for the method/funclet's unwind information.
11148 // Note that this must be called before allocMem. It should be
11149 // called once for the main method, once for every funclet, and
11150 // once for every block of cold code for which allocUnwindInfo
11153 // This is necessary because jitted code must allocate all the
11154 // memory needed for the unwindInfo at the allocMem call.
11155 // For prejitted code we split up the unwinding information into
11156 // separate sections .rdata and .pdata.
11158 void CEEJitInfo::reserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize)
11160 #ifdef WIN64EXCEPTIONS
11169 JIT_TO_EE_TRANSITION_LEAF();
11171 CONSISTENCY_CHECK_MSG(!isColdCode, "Hot/Cold splitting is not supported in jitted code");
11172 _ASSERTE_MSG(m_theUnwindBlock == NULL,
11173 "reserveUnwindInfo() can only be called before allocMem(), but allocMem() has already been called. "
11174 "This may indicate the JIT has hit a NO_WAY assert after calling allocMem(), and is re-JITting. "
11175 "Set COMPlus_JitBreakOnBadCode=1 and rerun to get the real error.");
11177 ULONG currentSize = unwindSize;
11179 reservePersonalityRoutineSpace(currentSize);
11181 m_totalUnwindSize += currentSize;
11183 m_totalUnwindInfos++;
11185 EE_TO_JIT_TRANSITION_LEAF();
11186 #else // WIN64EXCEPTIONS
11187 LIMITED_METHOD_CONTRACT;
11188 // Dummy implementation to make cross-platform altjit work
11189 #endif // WIN64EXCEPTIONS
11192 // Allocate and initialize the .rdata and .pdata for this method or
11193 // funclet and get the block of memory needed for the machine specific
11194 // unwind information (the info for crawling the stack frame).
11195 // Note that allocMem must be called first.
11197 // The pHotCode parameter points at the first byte of the code of the method
11198 // The startOffset and endOffset are the region (main or funclet) that
11199 // we are to allocate and create .rdata and .pdata for.
11200 // The pUnwindBlock is copied and contains the .pdata unwind area
11204 // pHotCode main method code buffer, always filled in
11205 // pColdCode always NULL for jitted code
11206 // startOffset start of code block, relative to pHotCode
11207 // endOffset end of code block, relative to pHotCode
11208 // unwindSize size of unwind info pointed to by pUnwindBlock
11209 // pUnwindBlock pointer to unwind info
11210 // funcKind type of funclet (main method code, handler, filter)
11212 void CEEJitInfo::allocUnwindInfo (
11213 BYTE * pHotCode, /* IN */
11214 BYTE * pColdCode, /* IN */
11215 ULONG startOffset, /* IN */
11216 ULONG endOffset, /* IN */
11217 ULONG unwindSize, /* IN */
11218 BYTE * pUnwindBlock, /* IN */
11219 CorJitFuncKind funcKind /* IN */
11222 #ifdef WIN64EXCEPTIONS
11228 PRECONDITION(m_theUnwindBlock != NULL);
11229 PRECONDITION(m_usedUnwindSize < m_totalUnwindSize);
11230 PRECONDITION(m_usedUnwindInfos < m_totalUnwindInfos);
11231 PRECONDITION(endOffset <= m_codeSize);
11234 CONSISTENCY_CHECK_MSG(pColdCode == NULL, "Hot/Cold code splitting not supported for jitted code");
11236 JIT_TO_EE_TRANSITION();
11239 // We add one callback-type dynamic function table per range section.
11240 // Therefore, the RUNTIME_FUNCTION info is always relative to the
11241 // image base contained in the dynamic function table, which happens
11242 // to be the LowAddress of the range section. The JIT has no
11243 // knowledge of the range section, so it gives us offsets that are
11244 // relative to the beginning of the method (pHotCode) and we allocate
11245 // and initialize the RUNTIME_FUNCTION data and record its location
11246 // in this function.
11249 if (funcKind != CORJIT_FUNC_ROOT)
11251 // The main method should be emitted before funclets
11252 _ASSERTE(m_usedUnwindInfos > 0);
11255 PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeader->GetUnwindInfo(m_usedUnwindInfos);
11256 m_usedUnwindInfos++;
11258 // Make sure that the RUNTIME_FUNCTION is aligned on a DWORD sized boundary
11259 _ASSERTE(IS_ALIGNED(pRuntimeFunction, sizeof(DWORD)));
11261 UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *) &(m_theUnwindBlock[m_usedUnwindSize]);
11262 m_usedUnwindSize += unwindSize;
11264 reservePersonalityRoutineSpace(m_usedUnwindSize);
11266 _ASSERTE(m_usedUnwindSize <= m_totalUnwindSize);
11268 // Make sure that the UnwindInfo is aligned
11269 _ASSERTE(IS_ALIGNED(pUnwindInfo, sizeof(ULONG)));
11271 /* Calculate Image Relative offset to add to the jit generated unwind offsets */
11273 TADDR baseAddress = m_moduleBase;
11275 size_t currentCodeSizeT = (size_t)pHotCode - baseAddress;
11277 /* Check if currentCodeSizeT offset fits in 32-bits */
11278 if (!FitsInU4(currentCodeSizeT))
11280 _ASSERTE(!"Bad currentCodeSizeT");
11281 COMPlusThrowHR(E_FAIL);
11284 /* Check if EndAddress offset fits in 32-bit */
11285 if (!FitsInU4(currentCodeSizeT + endOffset))
11287 _ASSERTE(!"Bad currentCodeSizeT");
11288 COMPlusThrowHR(E_FAIL);
11291 unsigned currentCodeOffset = (unsigned) currentCodeSizeT;
11293 /* Calculate Unwind Info delta */
11294 size_t unwindInfoDeltaT = (size_t) pUnwindInfo - baseAddress;
11296 /* Check if unwindDeltaT offset fits in 32-bits */
11297 if (!FitsInU4(unwindInfoDeltaT))
11299 _ASSERTE(!"Bad unwindInfoDeltaT");
11300 COMPlusThrowHR(E_FAIL);
11303 unsigned unwindInfoDelta = (unsigned) unwindInfoDeltaT;
11305 RUNTIME_FUNCTION__SetBeginAddress(pRuntimeFunction, currentCodeOffset + startOffset);
11307 #ifdef _TARGET_AMD64_
11308 pRuntimeFunction->EndAddress = currentCodeOffset + endOffset;
11311 RUNTIME_FUNCTION__SetUnwindInfoAddress(pRuntimeFunction, unwindInfoDelta);
11314 if (funcKind != CORJIT_FUNC_ROOT)
11316 // Check the the new funclet doesn't overlap any existing funclet.
11318 for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++)
11320 PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeader->GetUnwindInfo(iUnwindInfo);
11321 _ASSERTE(( RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress)
11322 || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction)));
11327 /* Copy the UnwindBlock */
11328 memcpy(pUnwindInfo, pUnwindBlock, unwindSize);
11330 #if defined(_TARGET_X86_)
11334 #elif defined(_TARGET_AMD64_)
11336 pUnwindInfo->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
11338 ULONG * pPersonalityRoutine = (ULONG*)ALIGN_UP(&(pUnwindInfo->UnwindCode[pUnwindInfo->CountOfUnwindCodes]), sizeof(ULONG));
11339 *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
11341 #elif defined(_TARGET_ARM64_)
11343 *(LONG *)pUnwindInfo |= (1 << 20); // X bit
11345 ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
11346 *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
11348 #elif defined(_TARGET_ARM_)
11350 *(LONG *)pUnwindInfo |= (1 << 20); // X bit
11352 ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
11353 *pPersonalityRoutine = (TADDR)ProcessCLRException - baseAddress;
11357 #if defined(_TARGET_AMD64_)
11358 // Publish the new unwind information in a way that the ETW stack crawler can find
11359 if (m_usedUnwindInfos == m_totalUnwindInfos)
11360 UnwindInfoTable::PublishUnwindInfoForMethod(baseAddress, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos);
11361 #endif // defined(_TARGET_AMD64_)
11363 EE_TO_JIT_TRANSITION();
11364 #else // WIN64EXCEPTIONS
11365 LIMITED_METHOD_CONTRACT;
11366 // Dummy implementation to make cross-platform altjit work
11367 #endif // WIN64EXCEPTIONS
11370 void CEEJitInfo::recordCallSite(ULONG instrOffset,
11371 CORINFO_SIG_INFO * callSig,
11372 CORINFO_METHOD_HANDLE methodHandle)
11374 // Currently, only testing tools use this method. The EE itself doesn't need record this information.
11375 // N.B. The memory that callSig points to is managed by the JIT and isn't guaranteed to be around after
11376 // this function returns, so future implementations should copy the sig info if they want it to persist.
11377 LIMITED_METHOD_CONTRACT;
11380 // This is a variant for AMD64 or other machines that
11381 // cannot always hold the destination address in a 32-bit location
11382 // A relocation is recorded if we are pre-jitting.
11383 // A jump thunk may be inserted if we are jitting
11385 void CEEJitInfo::recordRelocation(void * location,
11399 JIT_TO_EE_TRANSITION();
11403 switch (fRelocType)
11405 case IMAGE_REL_BASED_DIR64:
11406 // Write 64-bits into location
11407 *((UINT64 *) ((BYTE *) location + slot)) = (UINT64) target;
11410 #ifdef _TARGET_AMD64_
11411 case IMAGE_REL_BASED_REL32:
11413 target = (BYTE *)target + addlDelta;
11415 INT32 * fixupLocation = (INT32 *) ((BYTE *) location + slot);
11416 BYTE * baseAddr = (BYTE *)fixupLocation + sizeof(INT32);
11418 delta = (INT64)((BYTE *)target - baseAddr);
11421 // Do we need to insert a jump stub to make the source reach the target?
11423 // Note that we cannot stress insertion of jump stub by inserting it unconditionally. JIT records the relocations
11424 // for intra-module jumps and calls. It does not expect the register used by the jump stub to be trashed.
11426 if (!FitsInI4(delta))
11431 // When m_fAllowRel32 == TRUE, the JIT will use REL32s for both data addresses and direct code targets.
11432 // Since we cannot tell what the relocation is for, we have to defensively retry.
11434 m_fJumpStubOverflow = TRUE;
11440 // When m_fAllowRel32 == FALSE, the JIT will use a REL32s for direct code targets only.
11443 delta = rel32UsingJumpStub(fixupLocation, (PCODE)target, m_pMethodBeingCompiled, NULL, false /* throwOnOutOfMemoryWithinRange */);
11446 // This forces the JIT to retry the method, which allows us to reserve more space for jump stubs and have a higher chance that
11447 // we will find space for them.
11448 m_fJumpStubOverflow = TRUE;
11451 // Keep track of conservative estimate of how much memory may be needed by jump stubs. We will use it to reserve extra memory
11452 // on retry to increase chances that the retry succeeds.
11453 m_reserveForJumpStubs = max(0x400, m_reserveForJumpStubs + 0x10);
11457 LOG((LF_JIT, LL_INFO100000, "Encoded a PCREL32 at" FMT_ADDR "to" FMT_ADDR "+%d, delta is 0x%04x\n",
11458 DBG_ADDR(fixupLocation), DBG_ADDR(target), addlDelta, delta));
11460 // Write the 32-bits pc-relative delta into location
11461 *fixupLocation = (INT32) delta;
11464 #endif // _TARGET_AMD64_
11466 #ifdef _TARGET_ARM64_
11467 case IMAGE_REL_ARM64_BRANCH26: // 26 bit offset << 2 & sign ext, for B and BL
11469 _ASSERTE(slot == 0);
11470 _ASSERTE(addlDelta == 0);
11472 PCODE branchTarget = (PCODE) target;
11473 _ASSERTE((branchTarget & 0x3) == 0); // the low two bits must be zero
11475 PCODE fixupLocation = (PCODE) location;
11476 _ASSERTE((fixupLocation & 0x3) == 0); // the low two bits must be zero
11478 delta = (INT64)(branchTarget - fixupLocation);
11479 _ASSERTE((delta & 0x3) == 0); // the low two bits must be zero
11481 UINT32 branchInstr = *((UINT32*) fixupLocation);
11482 branchInstr &= 0xFC000000; // keep bits 31-26
11483 _ASSERTE((branchInstr & 0x7FFFFFFF) == 0x14000000); // Must be B or BL
11486 // Do we need to insert a jump stub to make the source reach the target?
11489 if (!FitsInRel28(delta))
11493 TADDR baseAddr = (TADDR)fixupLocation;
11494 TADDR loAddr = baseAddr - 0x08000000; // -2^27
11495 TADDR hiAddr = baseAddr + 0x07FFFFFF; // +2^27-1
11497 // Check for the wrap around cases
11498 if (loAddr > baseAddr)
11499 loAddr = UINT64_MIN; // overflow
11500 if (hiAddr < baseAddr)
11501 hiAddr = UINT64_MAX; // overflow
11503 PCODE jumpStubAddr = ExecutionManager::jumpStub(m_pMethodBeingCompiled,
11510 // Keep track of conservative estimate of how much memory may be needed by jump stubs. We will use it to reserve extra memory
11511 // on retry to increase chances that the retry succeeds.
11512 m_reserveForJumpStubs = max(0x400, m_reserveForJumpStubs + 2*BACK_TO_BACK_JUMP_ALLOCATE_SIZE);
11514 if (jumpStubAddr == 0)
11516 // This forces the JIT to retry the method, which allows us to reserve more space for jump stubs and have a higher chance that
11517 // we will find space for them.
11518 m_fJumpStubOverflow = TRUE;
11522 delta = (INT64)(jumpStubAddr - fixupLocation);
11524 if (!FitsInRel28(delta))
11526 _ASSERTE(!"jump stub was not in expected range");
11527 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
11530 LOG((LF_JIT, LL_INFO100000, "Using JumpStub at" FMT_ADDR "that jumps to" FMT_ADDR "\n",
11531 DBG_ADDR(jumpStubAddr), DBG_ADDR(target)));
11534 LOG((LF_JIT, LL_INFO100000, "Encoded a BRANCH26 at" FMT_ADDR "to" FMT_ADDR ", delta is 0x%04x\n",
11535 DBG_ADDR(fixupLocation), DBG_ADDR(target), delta));
11537 _ASSERTE(FitsInRel28(delta));
11539 PutArm64Rel28((UINT32*) fixupLocation, (INT32)delta);
11543 case IMAGE_REL_ARM64_PAGEBASE_REL21:
11545 _ASSERTE(slot == 0);
11546 _ASSERTE(addlDelta == 0);
11548 // Write the 21 bits pc-relative page address into location.
11549 INT64 targetPage = (INT64)target & 0xFFFFFFFFFFFFF000LL;
11550 INT64 locationPage = (INT64)location & 0xFFFFFFFFFFFFF000LL;
11551 INT64 relPage = (INT64)(targetPage - locationPage);
11552 INT32 imm21 = (INT32)(relPage >> 12) & 0x1FFFFF;
11553 PutArm64Rel21((UINT32 *)location, imm21);
11557 case IMAGE_REL_ARM64_PAGEOFFSET_12A:
11559 _ASSERTE(slot == 0);
11560 _ASSERTE(addlDelta == 0);
11562 // Write the 12 bits page offset into location.
11563 INT32 imm12 = (INT32)target & 0xFFFLL;
11564 PutArm64Rel12((UINT32 *)location, imm12);
11568 #endif // _TARGET_ARM64_
11571 _ASSERTE(!"Unknown reloc type");
11575 EE_TO_JIT_TRANSITION();
11577 JIT_TO_EE_TRANSITION_LEAF();
11579 // Nothing to do on 32-bit
11581 EE_TO_JIT_TRANSITION_LEAF();
11585 WORD CEEJitInfo::getRelocTypeHint(void * target)
11594 #ifdef _TARGET_AMD64_
11597 // The JIT calls this method for data addresses only. It always uses REL32s for direct code targets.
11598 if (IsPreferredExecutableRange(target))
11599 return IMAGE_REL_BASED_REL32;
11601 #endif // _TARGET_AMD64_
11607 void CEEJitInfo::getModuleNativeEntryPointRange(void** pStart, void** pEnd)
11617 JIT_TO_EE_TRANSITION_LEAF();
11619 *pStart = *pEnd = 0;
11621 EE_TO_JIT_TRANSITION_LEAF();
11624 DWORD CEEJitInfo::getExpectedTargetArchitecture()
11626 LIMITED_METHOD_CONTRACT;
11628 return IMAGE_FILE_MACHINE_NATIVE;
11631 void CEEInfo::JitProcessShutdownWork()
11633 LIMITED_METHOD_CONTRACT;
11635 EEJitManager* jitMgr = ExecutionManager::GetEEJitManager();
11637 // If we didn't load the JIT, there is no work to do.
11638 if (jitMgr->m_jit != NULL)
11640 // Do the shutdown work.
11641 jitMgr->m_jit->ProcessShutdownWork(this);
11644 #ifdef ALLOW_SXS_JIT
11645 if (jitMgr->m_alternateJit != NULL)
11647 jitMgr->m_alternateJit->ProcessShutdownWork(this);
11649 #endif // ALLOW_SXS_JIT
11652 /*********************************************************************/
11653 InfoAccessType CEEJitInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
11664 InfoAccessType result = IAT_PVALUE;
11666 JIT_TO_EE_TRANSITION();
11668 _ASSERTE(ppValue != NULL);
11670 if (IsDynamicScope(scopeHnd))
11672 *ppValue = (LPVOID)GetDynamicResolver(scopeHnd)->ConstructStringLiteral(metaTok);
11676 *ppValue = (LPVOID)ConstructStringLiteral(scopeHnd, metaTok); // throws
11679 EE_TO_JIT_TRANSITION();
11684 /*********************************************************************/
11685 InfoAccessType CEEJitInfo::emptyStringLiteral(void ** ppValue)
11694 InfoAccessType result = IAT_PVALUE;
11696 if(NingenEnabled())
11702 JIT_TO_EE_TRANSITION();
11703 *ppValue = StringObject::GetEmptyStringRefPtr();
11704 EE_TO_JIT_TRANSITION();
11709 /*********************************************************************/
11710 void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
11711 void **ppIndirection)
11720 void *result = NULL;
11722 if (ppIndirection != NULL)
11723 *ppIndirection = NULL;
11725 // Do not bother with initialization if we are only verifying the method.
11726 if (isVerifyOnly())
11728 return (void *)0x10;
11731 JIT_TO_EE_TRANSITION();
11733 FieldDesc* field = (FieldDesc*) fieldHnd;
11735 MethodTable* pMT = field->GetEnclosingMethodTable();
11737 _ASSERTE(!pMT->ContainsGenericVariables());
11741 if (!field->IsRVA())
11743 // <REVISIT_TODO>@todo: assert that the current method being compiled is unshared</REVISIT_TODO>
11744 // We must not call here for statics of collectible types.
11745 _ASSERTE(!pMT->Collectible());
11747 // Allocate space for the local class if necessary, but don't trigger
11748 // class construction.
11749 DomainLocalModule *pLocalModule = pMT->GetDomainLocalModule();
11750 pLocalModule->PopulateClass(pMT);
11754 base = (void *) field->GetBase();
11757 result = field->GetStaticAddressHandle(base);
11759 EE_TO_JIT_TRANSITION();
11764 /*********************************************************************/
11765 CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
11766 bool* pIsSpeculative)
11775 CORINFO_CLASS_HANDLE result = NULL;
11777 if (pIsSpeculative != NULL)
11779 *pIsSpeculative = true;
11782 // Only examine the field's value if we are producing jitted code.
11783 if (isVerifyOnly() || IsCompilingForNGen() || IsReadyToRunCompilation())
11788 JIT_TO_EE_TRANSITION();
11790 FieldDesc* field = (FieldDesc*) fieldHnd;
11791 bool isClassInitialized = false;
11793 // We're only interested in ref class typed static fields
11794 // where the field handle specifies a unique location.
11795 if (field->IsStatic() && field->IsObjRef() && !field->IsThreadStatic())
11797 MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
11799 if (!pEnclosingMT->IsSharedByGenericInstantiations())
11801 // Allocate space for the local class if necessary, but don't trigger
11802 // class construction.
11803 DomainLocalModule *pLocalModule = pEnclosingMT->GetDomainLocalModule();
11804 pLocalModule->PopulateClass(pEnclosingMT);
11808 OBJECTREF fieldObj = field->GetStaticOBJECTREF();
11809 VALIDATEOBJECTREF(fieldObj);
11811 // Check for initialization before looking at the value
11812 isClassInitialized = !!pEnclosingMT->IsClassInited();
11814 if (fieldObj != NULL)
11816 MethodTable *pObjMT = fieldObj->GetMethodTable();
11818 // TODO: Check if the jit is allowed to embed this handle in jitted code.
11819 // Note for the initonly cases it probably won't embed.
11820 result = (CORINFO_CLASS_HANDLE) pObjMT;
11825 // Did we find a class?
11826 if (result != NULL)
11828 // Figure out what to report back.
11829 bool isResultImmutable = isClassInitialized && IsFdInitOnly(field->GetAttributes());
11831 if (pIsSpeculative != NULL)
11833 // Caller is ok with potentially mutable results.
11834 *pIsSpeculative = !isResultImmutable;
11838 // Caller only wants to see immutable results.
11839 if (!isResultImmutable)
11846 EE_TO_JIT_TRANSITION();
11851 /*********************************************************************/
11852 static void *GetClassSync(MethodTable *pMT)
11854 STANDARD_VM_CONTRACT;
11858 OBJECTREF ref = pMT->GetManagedClassObject();
11859 return (void*)ref->GetSyncBlock()->GetMonitor();
11862 /*********************************************************************/
11863 void* CEEJitInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
11864 void **ppIndirection)
11873 void * result = NULL;
11875 if (ppIndirection != NULL)
11876 *ppIndirection = NULL;
11878 JIT_TO_EE_TRANSITION();
11880 result = GetClassSync((GetMethod(ftnHnd))->GetMethodTable());
11882 EE_TO_JIT_TRANSITION();
11887 /*********************************************************************/
11888 HRESULT CEEJitInfo::allocBBProfileBuffer (
11890 ICorJitInfo::ProfileBuffer ** profileBuffer
11900 HRESULT hr = E_FAIL;
11902 JIT_TO_EE_TRANSITION();
11904 #ifdef FEATURE_PREJIT
11906 // We need to know the code size. Typically we can get the code size
11907 // from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so
11908 // for that case we need to use DynamicResolver to get the code size.
11910 unsigned codeSize = 0;
11911 if (m_pMethodBeingCompiled->IsDynamicMethod())
11913 unsigned stackSize, ehSize;
11914 CorInfoOptions options;
11915 DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver();
11916 pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize);
11920 codeSize = m_ILHeader->GetCodeSize();
11923 *profileBuffer = m_pMethodBeingCompiled->GetLoaderModule()->AllocateProfileBuffer(m_pMethodBeingCompiled->GetMemberDef(), count, codeSize);
11924 hr = (*profileBuffer ? S_OK : E_OUTOFMEMORY);
11925 #else // FEATURE_PREJIT
11926 _ASSERTE(!"allocBBProfileBuffer not implemented on CEEJitInfo!");
11928 #endif // !FEATURE_PREJIT
11930 EE_TO_JIT_TRANSITION();
11935 // Consider implementing getBBProfileData on CEEJitInfo. This will allow us
11936 // to use profile info in codegen for non zapped images.
11937 HRESULT CEEJitInfo::getBBProfileData (
11938 CORINFO_METHOD_HANDLE ftnHnd,
11940 ICorJitInfo::ProfileBuffer ** profileBuffer,
11944 LIMITED_METHOD_CONTRACT;
11945 _ASSERTE(!"getBBProfileData not implemented on CEEJitInfo!");
11949 void CEEJitInfo::allocMem (
11950 ULONG hotCodeSize, /* IN */
11951 ULONG coldCodeSize, /* IN */
11952 ULONG roDataSize, /* IN */
11953 ULONG xcptnsCount, /* IN */
11954 CorJitAllocMemFlag flag, /* IN */
11955 void ** hotCodeBlock, /* OUT */
11956 void ** coldCodeBlock, /* OUT */
11957 void ** roDataBlock /* OUT */
11967 JIT_TO_EE_TRANSITION();
11969 _ASSERTE(coldCodeSize == 0);
11972 *coldCodeBlock = NULL;
11975 ULONG codeSize = hotCodeSize;
11976 void **codeBlock = hotCodeBlock;
11978 S_SIZE_T totalSize = S_SIZE_T(codeSize);
11980 size_t roDataAlignment = sizeof(void*);
11981 if ((flag & CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN)!= 0)
11983 roDataAlignment = 16;
11985 else if (roDataSize >= 8)
11987 roDataAlignment = 8;
11989 if (roDataSize > 0)
11991 size_t codeAlignment = ((flag & CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN)!= 0)
11992 ? 16 : sizeof(void*);
11993 totalSize.AlignUp(codeAlignment);
11994 if (roDataAlignment > codeAlignment) {
11995 // Add padding to align read-only data.
11996 totalSize += (roDataAlignment - codeAlignment);
11998 totalSize += roDataSize;
12001 #ifdef WIN64EXCEPTIONS
12002 totalSize.AlignUp(sizeof(DWORD));
12003 totalSize += m_totalUnwindSize;
12006 _ASSERTE(m_CodeHeader == 0 &&
12007 // The jit-compiler sometimes tries to compile a method a second time
12008 // if it failed the first time. In such a situation, m_CodeHeader may
12009 // have already been assigned. Its OK to ignore this assert in such a
12010 // situation - we will leak some memory, but that is acceptable
12011 // since this should happen very rarely.
12012 "Note that this may fire if the JITCompiler tries to recompile a method");
12014 if( totalSize.IsOverflow() )
12016 COMPlusThrowHR(CORJIT_OUTOFMEM);
12019 m_CodeHeader = m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), flag
12020 #ifdef WIN64EXCEPTIONS
12021 , m_totalUnwindInfos
12026 BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress();
12028 *codeBlock = current;
12029 current += codeSize;
12031 if (roDataSize > 0)
12033 current = (BYTE *)ALIGN_UP(current, roDataAlignment);
12034 *roDataBlock = current;
12035 current += roDataSize;
12039 *roDataBlock = NULL;
12042 #ifdef WIN64EXCEPTIONS
12043 current = (BYTE *)ALIGN_UP(current, sizeof(DWORD));
12045 m_theUnwindBlock = current;
12046 current += m_totalUnwindSize;
12049 _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value());
12052 m_codeSize = codeSize;
12055 EE_TO_JIT_TRANSITION();
12058 /*********************************************************************/
12059 void * CEEJitInfo::allocGCInfo (size_t size)
12068 void * block = NULL;
12070 JIT_TO_EE_TRANSITION();
12072 _ASSERTE(m_CodeHeader != 0);
12073 _ASSERTE(m_CodeHeader->GetGCInfo() == 0);
12076 if (size & 0xFFFFFFFF80000000LL)
12078 COMPlusThrowHR(CORJIT_OUTOFMEM);
12082 block = m_jitManager->allocGCInfo(m_CodeHeader,(DWORD)size, &m_GCinfo_len);
12085 COMPlusThrowHR(CORJIT_OUTOFMEM);
12088 _ASSERTE(m_CodeHeader->GetGCInfo() != 0 && block == m_CodeHeader->GetGCInfo());
12090 EE_TO_JIT_TRANSITION();
12095 /*********************************************************************/
12096 void CEEJitInfo::setEHcount (
12106 JIT_TO_EE_TRANSITION();
12108 _ASSERTE(cEH != 0);
12109 _ASSERTE(m_CodeHeader != 0);
12110 _ASSERTE(m_CodeHeader->GetEHInfo() == 0);
12112 EE_ILEXCEPTION* ret;
12113 ret = m_jitManager->allocEHInfo(m_CodeHeader,cEH, &m_EHinfo_len);
12114 _ASSERTE(ret); // allocEHInfo throws if there's not enough memory
12116 _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && m_CodeHeader->GetEHInfo()->EHCount() == cEH);
12118 EE_TO_JIT_TRANSITION();
12121 /*********************************************************************/
12122 void CEEJitInfo::setEHinfo (
12124 const CORINFO_EH_CLAUSE* clause)
12133 JIT_TO_EE_TRANSITION();
12135 // <REVISIT_TODO> Fix make the Code Manager EH clauses EH_INFO+</REVISIT_TODO>
12136 _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && EHnumber < m_CodeHeader->GetEHInfo()->EHCount());
12138 EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeader->GetEHInfo()->EHClause(EHnumber);
12140 pEHClause->TryStartPC = clause->TryOffset;
12141 pEHClause->TryEndPC = clause->TryLength;
12142 pEHClause->HandlerStartPC = clause->HandlerOffset;
12143 pEHClause->HandlerEndPC = clause->HandlerLength;
12144 pEHClause->ClassToken = clause->ClassToken;
12145 pEHClause->Flags = (CorExceptionFlag)clause->Flags;
12147 LOG((LF_EH, LL_INFO1000000, "Setting EH clause #%d for %s::%s\n", EHnumber, m_pMethodBeingCompiled->m_pszDebugClassName, m_pMethodBeingCompiled->m_pszDebugMethodName));
12148 LOG((LF_EH, LL_INFO1000000, " Flags : 0x%08lx -> 0x%08lx\n", clause->Flags, pEHClause->Flags));
12149 LOG((LF_EH, LL_INFO1000000, " TryOffset : 0x%08lx -> 0x%08lx (startpc)\n", clause->TryOffset, pEHClause->TryStartPC));
12150 LOG((LF_EH, LL_INFO1000000, " TryLength : 0x%08lx -> 0x%08lx (endpc)\n", clause->TryLength, pEHClause->TryEndPC));
12151 LOG((LF_EH, LL_INFO1000000, " HandlerOffset : 0x%08lx -> 0x%08lx\n", clause->HandlerOffset, pEHClause->HandlerStartPC));
12152 LOG((LF_EH, LL_INFO1000000, " HandlerLength : 0x%08lx -> 0x%08lx\n", clause->HandlerLength, pEHClause->HandlerEndPC));
12153 LOG((LF_EH, LL_INFO1000000, " ClassToken : 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->ClassToken));
12154 LOG((LF_EH, LL_INFO1000000, " FilterOffset : 0x%08lx -> 0x%08lx\n", clause->FilterOffset, pEHClause->FilterOffset));
12156 if (m_pMethodBeingCompiled->IsDynamicMethod() &&
12157 ((pEHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) == 0) &&
12158 (clause->ClassToken != NULL))
12160 MethodDesc * pMD; FieldDesc * pFD;
12161 m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver()->ResolveToken(clause->ClassToken, (TypeHandle *)&pEHClause->TypeHandle, &pMD, &pFD);
12162 SetHasCachedTypeHandle(pEHClause);
12163 LOG((LF_EH, LL_INFO1000000, " CachedTypeHandle: 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->TypeHandle));
12166 EE_TO_JIT_TRANSITION();
12169 /*********************************************************************/
12170 // get individual exception handler
12171 void CEEJitInfo::getEHinfo(
12172 CORINFO_METHOD_HANDLE ftn, /* IN */
12173 unsigned EHnumber, /* IN */
12174 CORINFO_EH_CLAUSE* clause) /* OUT */
12183 JIT_TO_EE_TRANSITION();
12185 if (IsDynamicMethodHandle(ftn))
12187 GetMethod(ftn)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
12191 _ASSERTE(ftn == CORINFO_METHOD_HANDLE(m_pMethodBeingCompiled)); // For now only support if the method being jitted
12192 getEHinfoHelper(ftn, EHnumber, clause, m_ILHeader);
12195 EE_TO_JIT_TRANSITION();
12197 #endif // CROSSGEN_COMPILE
12199 #if defined(CROSSGEN_COMPILE)
12200 EXTERN_C ICorJitCompiler* __stdcall getJit();
12201 #endif // defined(CROSSGEN_COMPILE)
12203 #ifdef FEATURE_INTERPRETER
12204 static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr,
12206 struct CORINFO_METHOD_INFO *info,
12208 BYTE **nativeEntry,
12209 ULONG *nativeSizeOfCode)
12211 STATIC_CONTRACT_THROWS;
12212 STATIC_CONTRACT_GC_TRIGGERS;
12213 STATIC_CONTRACT_MODE_PREEMPTIVE;
12214 STATIC_CONTRACT_SO_INTOLERANT;
12216 SString namespaceOrClassName, methodName, methodSignature;
12217 // Fire an ETW event to mark the beginning of JIT'ing
12218 ETW::MethodLog::MethodJitting(reinterpret_cast<MethodDesc*>(info->ftn), &namespaceOrClassName, &methodName, &methodSignature);
12220 CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode);
12222 // Logically, it would seem that the end-of-JITting ETW even should go here, but it must come after the native code has been
12223 // set for the given method desc, which happens in a caller.
12227 #endif // FEATURE_INTERPRETER
12230 // Helper function because can't have dtors in BEGIN_SO_TOLERANT_CODE.
12232 CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr,
12234 struct CORINFO_METHOD_INFO *info,
12235 CORJIT_FLAGS jitFlags,
12236 BYTE **nativeEntry,
12237 ULONG *nativeSizeOfCode)
12239 STATIC_CONTRACT_THROWS;
12240 STATIC_CONTRACT_GC_TRIGGERS;
12241 STATIC_CONTRACT_MODE_PREEMPTIVE;
12242 STATIC_CONTRACT_SO_INTOLERANT;
12244 CorJitResult ret = CORJIT_SKIPPED; // Note that CORJIT_SKIPPED is an error exit status code
12247 comp->setJitFlags(jitFlags);
12249 #ifdef FEATURE_STACK_SAMPLING
12250 // SO_INTOLERANT due to init affecting global state.
12251 static ConfigDWORD s_stackSamplingEnabled;
12252 bool samplingEnabled = (s_stackSamplingEnabled.val(CLRConfig::UNSUPPORTED_StackSamplingEnabled) != 0);
12255 BEGIN_SO_TOLERANT_CODE(GetThread());
12258 #if defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
12259 if (FAILED(ret) && jitMgr->m_alternateJit
12260 #ifdef FEATURE_STACK_SAMPLING
12261 && (!samplingEnabled || (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)))
12265 ret = jitMgr->m_alternateJit->compileMethod( comp,
12267 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12269 nativeSizeOfCode );
12271 #ifdef FEATURE_STACK_SAMPLING
12272 if (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND))
12274 // Don't bother with failures if we couldn't collect a trace.
12277 #endif // FEATURE_STACK_SAMPLING
12279 // If we failed to jit, then fall back to the primary Jit.
12282 // Consider adding this call:
12283 // ((CEEJitInfo*)comp)->BackoutJitData(jitMgr);
12284 ((CEEJitInfo*)comp)->ResetForJitRetry();
12285 ret = CORJIT_SKIPPED;
12288 #endif // defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
12290 #ifdef FEATURE_INTERPRETER
12291 static ConfigDWORD s_InterpreterFallback;
12293 bool isInterpreterStub = false;
12294 bool interpreterFallback = (s_InterpreterFallback.val(CLRConfig::INTERNAL_InterpreterFallback) != 0);
12296 if (interpreterFallback == false)
12298 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
12299 // (We assume that importation is completely architecture-independent, or at least nearly so.)
12300 if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
12302 if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
12304 isInterpreterStub = true;
12309 if (FAILED(ret) && jitMgr->m_jit)
12311 ret = CompileMethodWithEtwWrapper(jitMgr,
12314 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12319 if (interpreterFallback == true)
12321 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
12322 // (We assume that importation is completely architecture-independent, or at least nearly so.)
12323 if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
12325 if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
12327 isInterpreterStub = true;
12334 ret = jitMgr->m_jit->compileMethod( comp,
12336 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12340 #endif // FEATURE_INTERPRETER
12342 #if !defined(CROSSGEN_COMPILE)
12343 // Cleanup any internal data structures allocated
12344 // such as IL code after a successfull JIT compile
12345 // If the JIT fails we keep the IL around and will
12346 // try reJIT the same IL. VSW 525059
12348 if (SUCCEEDED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !((CEEJitInfo*)comp)->JitAgain())
12350 ((CEEJitInfo*)comp)->CompressDebugInfo();
12352 #ifdef FEATURE_INTERPRETER
12353 // We do this cleanup in the prestub, where we know whether the method
12354 // has been interpreted.
12356 comp->MethodCompileComplete(info->ftn);
12357 #endif // FEATURE_INTERPRETER
12359 #endif // !defined(CROSSGEN_COMPILE)
12362 #if defined(FEATURE_GDBJIT)
12363 bool isJittedEntry = SUCCEEDED(ret) && *nativeEntry != NULL;
12365 #ifdef FEATURE_INTERPRETER
12366 isJittedEntry &= !isInterpreterStub;
12367 #endif // FEATURE_INTERPRETER
12371 CodeHeader* pCH = ((CodeHeader*)((PCODE)*nativeEntry & ~1)) - 1;
12372 pCH->SetCalledMethods((PTR_VOID)comp->GetCalledMethods());
12376 END_SO_TOLERANT_CODE;
12382 /*********************************************************************/
12383 CorJitResult invokeCompileMethod(EEJitManager *jitMgr,
12385 struct CORINFO_METHOD_INFO *info,
12386 CORJIT_FLAGS jitFlags,
12387 BYTE **nativeEntry,
12388 ULONG *nativeSizeOfCode)
12396 // The JIT runs in preemptive mode
12401 CorJitResult ret = invokeCompileMethodHelper(jitMgr, comp, info, jitFlags, nativeEntry, nativeSizeOfCode);
12404 // Verify that we are still in preemptive mode when we return
12408 _ASSERTE(GetThread()->PreemptiveGCDisabled() == FALSE);
12413 CorJitResult CallCompileMethodWithSEHWrapper(EEJitManager *jitMgr,
12415 struct CORINFO_METHOD_INFO *info,
12416 CORJIT_FLAGS flags,
12417 BYTE **nativeEntry,
12418 ULONG *nativeSizeOfCode,
12421 // no dynamic contract here because SEH is used, with a finally clause
12422 STATIC_CONTRACT_NOTHROW;
12423 STATIC_CONTRACT_GC_TRIGGERS;
12425 LOG((LF_CORDB, LL_EVERYTHING, "CallCompileMethodWithSEHWrapper called...\n"));
12429 EEJitManager *jitMgr;
12431 struct CORINFO_METHOD_INFO *info;
12432 CORJIT_FLAGS flags;
12433 BYTE **nativeEntry;
12434 ULONG *nativeSizeOfCode;
12438 param.jitMgr = jitMgr;
12441 param.flags = flags;
12442 param.nativeEntry = nativeEntry;
12443 param.nativeSizeOfCode = nativeSizeOfCode;
12445 param.res = CORJIT_INTERNALERROR;
12447 PAL_TRY(Param *, pParam, ¶m)
12450 // Call out to the JIT-compiler
12453 pParam->res = invokeCompileMethod( pParam->jitMgr,
12457 pParam->nativeEntry,
12458 pParam->nativeSizeOfCode);
12462 #if defined(DEBUGGING_SUPPORTED) && !defined(CROSSGEN_COMPILE)
12463 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) &&
12464 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MCJIT_BACKGROUND)
12465 #ifdef FEATURE_STACK_SAMPLING
12466 && !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)
12467 #endif // FEATURE_STACK_SAMPLING
12471 // Notify the debugger that we have successfully jitted the function
12473 if (g_pDebugInterface)
12475 if (param.res == CORJIT_OK && !((CEEJitInfo*)param.comp)->JitAgain())
12477 g_pDebugInterface->JITComplete(ftn, (TADDR)*nativeEntry);
12481 #endif // DEBUGGING_SUPPORTED && !CROSSGEN_COMPILE
12488 /*********************************************************************/
12489 // Figures out the compile flags that are used by both JIT and NGen
12491 /* static */ CORJIT_FLAGS CEEInfo::GetBaseCompileFlags(MethodDesc * ftn)
12499 // Figure out the code quality flags
12502 CORJIT_FLAGS flags;
12503 if (g_pConfig->JitFramed())
12504 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12505 if (g_pConfig->JitAlignLoops())
12506 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_ALIGN_LOOPS);
12507 if (ftn->IsVersionableWithJumpStamp() || g_pConfig->AddRejitNops())
12508 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_REJIT_NOPS);
12509 #ifdef _TARGET_X86_
12510 if (g_pConfig->PInvokeRestoreEsp(ftn->GetModule()->IsPreV4Assembly()))
12511 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PINVOKE_RESTORE_ESP);
12512 #endif // _TARGET_X86_
12514 //See if we should instruct the JIT to emit calls to JIT_PollGC for thread suspension. If we have a
12515 //non-default value in the EE Config, then use that. Otherwise select the platform specific default.
12516 #ifdef FEATURE_ENABLE_GCPOLL
12517 EEConfig::GCPollType pollType = g_pConfig->GetGCPollType();
12518 if (EEConfig::GCPOLL_TYPE_POLL == pollType)
12519 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_CALLS);
12520 else if (EEConfig::GCPOLL_TYPE_INLINE == pollType)
12521 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_INLINE);
12522 #endif //FEATURE_ENABLE_GCPOLL
12524 // Set flags based on method's ImplFlags.
12525 if (!ftn->IsNoMetadata())
12527 DWORD dwImplFlags = 0;
12528 IfFailThrow(ftn->GetMDImport()->GetMethodImplProps(ftn->GetMemberDef(), NULL, &dwImplFlags));
12530 if (IsMiNoOptimization(dwImplFlags))
12532 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12535 // Always emit frames for methods marked no-inline (see #define ETW_EBP_FRAMED in the JIT)
12536 if (IsMiNoInlining(dwImplFlags))
12538 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12545 /*********************************************************************/
12546 // Figures out (some of) the flags to use to compile the method
12547 // Returns the new set to use
12549 CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags)
12551 STANDARD_VM_CONTRACT;
12553 //Right now if we don't have a debug interface on CoreCLR, we can't generate debug info. So, in those
12554 //cases don't attempt it.
12555 if (!g_pDebugInterface)
12558 #ifdef DEBUGGING_SUPPORTED
12561 if (g_pConfig->GenDebuggableCode())
12562 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12565 #ifdef EnC_SUPPORTED
12566 if (pModule->IsEditAndContinueEnabled())
12568 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_EnC);
12570 #endif // EnC_SUPPORTED
12572 // Debug info is always tracked
12573 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12574 #endif // DEBUGGING_SUPPORTED
12576 if (CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
12578 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12581 if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12583 // If we are only verifying the method, dont need any debug info and this
12584 // prevents getVars()/getBoundaries() from being called unnecessarily.
12585 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12586 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12592 CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHOD_INFO * methodInfo)
12594 STANDARD_VM_CONTRACT;
12596 _ASSERTE(methodInfo->regionKind == CORINFO_REGION_JIT);
12599 // Get the compile flags that are shared between JIT and NGen
12601 flags.Add(CEEInfo::GetBaseCompileFlags(ftn));
12604 // Get CPU specific flags
12606 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12608 flags.Add(ExecutionManager::GetEEJitManager()->GetCPUCompileFlags());
12612 // Find the debugger and profiler related flags
12615 #ifdef DEBUGGING_SUPPORTED
12616 flags.Add(GetDebuggerCompileFlags(ftn->GetModule(), flags));
12619 #ifdef PROFILING_SUPPORTED
12620 if (CORProfilerTrackEnterLeave() && !ftn->IsNoMetadata())
12621 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE);
12623 if (CORProfilerTrackTransitions())
12624 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_NO_PINVOKE_INLINE);
12625 #endif // PROFILING_SUPPORTED
12627 // Set optimization flags
12628 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT))
12630 unsigned optType = g_pConfig->GenOptimizeType();
12631 _ASSERTE(optType <= OPT_RANDOM);
12633 if (optType == OPT_RANDOM)
12634 optType = methodInfo->ILCodeSize % OPT_RANDOM;
12636 if (g_pConfig->JitMinOpts())
12637 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12639 if (optType == OPT_SIZE)
12641 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SIZE_OPT);
12643 else if (optType == OPT_SPEED)
12645 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SPEED_OPT);
12649 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12651 if (ftn->IsILStub())
12653 // no debug info available for IL stubs
12654 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12660 // ********************************************************************
12662 // Throw the right type of exception for the given JIT result
12664 void ThrowExceptionForJit(HRESULT res)
12676 case CORJIT_OUTOFMEM:
12680 case CORJIT_INTERNALERROR:
12681 COMPlusThrow(kInvalidProgramException, (UINT) IDS_EE_JIT_COMPILER_ERROR);
12684 case CORJIT_BADCODE:
12686 COMPlusThrow(kInvalidProgramException);
12691 // ********************************************************************
12693 LONG g_JitCount = 0;
12696 //#define PERF_TRACK_METHOD_JITTIMES
12697 #ifdef _TARGET_AMD64_
12698 BOOL g_fAllowRel32 = TRUE;
12702 // ********************************************************************
12704 // ********************************************************************
12706 // The reason that this is named UnsafeJitFunction is that this helper
12707 // method is not thread safe! When multiple threads get in here for
12708 // the same pMD, ALL of them MUST return the SAME value.
12709 // To insure that this happens you must call MakeJitWorker.
12710 // It creates a DeadlockAware list of methods being jitted and prevents us
12711 // from trying to jit the same method more that once.
12713 // Calls to this method that occur to check if inlining can occur on x86,
12714 // are OK since they discard the return value of this method.
12716 PCODE UnsafeJitFunction(MethodDesc* ftn, COR_ILMETHOD_DECODER* ILHeader, CORJIT_FLAGS flags,
12717 ULONG * pSizeOfCode)
12719 STANDARD_VM_CONTRACT;
12723 COOPERATIVE_TRANSITION_BEGIN();
12725 #ifdef FEATURE_PREJIT
12727 if (g_pConfig->RequireZaps() == EEConfig::REQUIRE_ZAPS_ALL &&
12728 ftn->GetModule()->GetDomainFile()->IsZapRequired() &&
12729 PartialNGenStressPercentage() == 0 &&
12730 #ifdef FEATURE_STACK_SAMPLING
12731 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND) &&
12733 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12735 StackSString ss(SString::Ascii, "ZapRequire: JIT compiler invoked for ");
12736 TypeString::AppendMethodInternal(ss, ftn);
12739 // Assert as some test may not check their error codes well. So throwing an
12740 // exception may not cause a test failure (as it should).
12741 StackScratchBuffer scratch;
12742 DbgAssertDialog(__FILE__, __LINE__, (char*)ss.GetUTF8(scratch));
12745 COMPlusThrowNonLocalized(kFileNotFoundException, ss.GetUnicode());
12748 #endif // FEATURE_PREJIT
12750 #ifndef CROSSGEN_COMPILE
12751 EEJitManager *jitMgr = ExecutionManager::GetEEJitManager();
12752 if (!jitMgr->LoadJIT())
12754 #ifdef ALLOW_SXS_JIT
12755 if (!jitMgr->IsMainJitLoaded())
12757 // Don't want to throw InvalidProgram from here.
12758 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12760 if (!jitMgr->IsAltJitLoaded())
12762 // Don't want to throw InvalidProgram from here.
12763 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load alternative JIT compiler"));
12765 #else // ALLOW_SXS_JIT
12766 // Don't want to throw InvalidProgram from here.
12767 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12768 #endif // ALLOW_SXS_JIT
12770 #endif // CROSSGEN_COMPILE
12773 // This is here so we can see the name and class easily in the debugger
12775 LPCUTF8 cls = ftn->GetMethodTable()->GetDebugClassName();
12776 LPCUTF8 name = ftn->GetName();
12778 if (ftn->IsNoMetadata())
12780 if (ftn->IsILStub())
12782 LOG((LF_JIT, LL_INFO10000, "{ Jitting IL Stub }\n"));
12786 LOG((LF_JIT, LL_INFO10000, "{ Jitting dynamic method }\n"));
12791 SString methodString;
12792 if (LoggingOn(LF_JIT, LL_INFO10000))
12793 TypeString::AppendMethodDebug(methodString, ftn);
12795 LOG((LF_JIT, LL_INFO10000, "{ Jitting method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12799 if (!SString::_stricmp(cls,"ENC") &&
12800 (!SString::_stricmp(name,"G")))
12810 CORINFO_METHOD_HANDLE ftnHnd = (CORINFO_METHOD_HANDLE)ftn;
12811 CORINFO_METHOD_INFO methodInfo;
12813 getMethodInfoHelper(ftn, ftnHnd, ILHeader, &methodInfo);
12815 // If it's generic then we can only enter through an instantiated md (unless we're just verifying it)
12816 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || !ftn->IsGenericMethodDefinition());
12818 // If it's an instance method then it must not be entered from a generic class
12819 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || ftn->IsStatic() ||
12820 ftn->GetNumGenericClassArgs() == 0 || ftn->HasClassInstantiation());
12822 // method attributes and signature are consistant
12823 _ASSERTE(!!ftn->IsStatic() == ((methodInfo.args.callConv & CORINFO_CALLCONV_HASTHIS) == 0));
12825 flags = GetCompileFlags(ftn, flags, &methodInfo);
12828 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION))
12830 SString methodString;
12831 if (LoggingOn(LF_VERIFIER, LL_INFO100))
12832 TypeString::AppendMethodDebug(methodString, ftn);
12834 LOG((LF_VERIFIER, LL_INFO100, "{ Will verify method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12838 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
12839 BOOL fForceJumpStubOverflow = FALSE;
12842 // Always exercise the overflow codepath with force relocs
12843 if (PEDecoder::GetForceRelocs())
12844 fForceJumpStubOverflow = TRUE;
12847 #if defined(_TARGET_AMD64_)
12848 BOOL fAllowRel32 = (g_fAllowRel32 | fForceJumpStubOverflow);
12851 size_t reserveForJumpStubs = 0;
12853 #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
12857 #ifndef CROSSGEN_COMPILE
12858 CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY),
12859 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING));
12861 // This path should be only ever used for verification in crossgen and so we should not need EEJitManager
12862 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY));
12863 CEEInfo jitInfo(ftn, true);
12864 EEJitManager *jitMgr = NULL;
12867 #if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)) && !defined(CROSSGEN_COMPILE)
12868 #ifdef _TARGET_AMD64_
12869 if (fForceJumpStubOverflow)
12870 jitInfo.SetJumpStubOverflow(fAllowRel32);
12871 jitInfo.SetAllowRel32(fAllowRel32);
12873 if (fForceJumpStubOverflow)
12874 jitInfo.SetJumpStubOverflow(fForceJumpStubOverflow);
12876 jitInfo.SetReserveForJumpStubs(reserveForJumpStubs);
12879 MethodDesc * pMethodForSecurity = jitInfo.GetMethodForSecurity(ftnHnd);
12881 //Since the check could trigger a demand, we have to do this every time.
12882 //This is actually an overly complicated way to make sure that a method can access all its arguments
12883 //and its return type.
12884 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
12885 TypeHandle ownerTypeForSecurity = TypeHandle(pMethodForSecurity->GetMethodTable());
12886 DynamicResolver *pAccessContext = NULL;
12887 BOOL doAccessCheck = TRUE;
12888 if (pMethodForSecurity->IsDynamicMethod())
12890 doAccessCheck = ModifyCheckForDynamicMethod(pMethodForSecurity->AsDynamicMethodDesc()->GetResolver(),
12891 &ownerTypeForSecurity,
12892 &accessCheckType, &pAccessContext);
12896 AccessCheckOptions accessCheckOptions(accessCheckType,
12898 TRUE /*Throw on error*/,
12899 pMethodForSecurity);
12901 StaticAccessCheckContext accessContext(pMethodForSecurity, ownerTypeForSecurity.GetMethodTable());
12903 // We now do an access check from pMethodForSecurity to pMethodForSecurity, its sole purpose is to
12904 // verify that pMethodForSecurity/ownerTypeForSecurity has access to all its parameters.
12906 // ownerTypeForSecurity.GetMethodTable() can be null if the pMethodForSecurity is a DynamicMethod
12907 // associated with a TypeDesc (Array, Ptr, Ref, or FnPtr). That doesn't make any sense, but we will
12908 // just do an access check from a NULL context which means only public types are accessible.
12909 if (!ClassLoader::CanAccess(&accessContext,
12910 ownerTypeForSecurity.GetMethodTable(),
12911 ownerTypeForSecurity.GetAssembly(),
12912 pMethodForSecurity->GetAttrs(),
12913 pMethodForSecurity,
12915 accessCheckOptions))
12917 EX_THROW(EEMethodException, (pMethodForSecurity));
12928 /* There is a double indirection to call compileMethod - can we
12929 improve this with the new structure? */
12931 #ifdef PERF_TRACK_METHOD_JITTIMES
12932 //Because we're not calling QPC enough. I'm not going to track times if we're just importing.
12933 LARGE_INTEGER methodJitTimeStart = {0};
12934 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12935 QueryPerformanceCounter (&methodJitTimeStart);
12938 #if defined(ENABLE_PERF_COUNTERS)
12942 #if defined(ENABLE_PERF_COUNTERS)
12943 LARGE_INTEGER CycleStart;
12944 QueryPerformanceCounter (&CycleStart);
12945 #endif // defined(ENABLE_PERF_COUNTERS)
12947 // Note on debuggerTrackInfo arg: if we're only importing (ie, verifying/
12948 // checking to make sure we could JIT, but not actually generating code (
12949 // eg, for inlining), then DON'T TELL THE DEBUGGER about this.
12950 res = CallCompileMethodWithSEHWrapper(jitMgr,
12957 LOG((LF_CORDB, LL_EVERYTHING, "Got through CallCompile MethodWithSEHWrapper\n"));
12959 #if FEATURE_PERFMAP
12960 // Save the code size so that it can be reported to the perfmap.
12961 if (pSizeOfCode != NULL)
12963 *pSizeOfCode = sizeOfCode;
12967 #if defined(ENABLE_PERF_COUNTERS)
12968 LARGE_INTEGER CycleStop;
12969 QueryPerformanceCounter(&CycleStop);
12970 GetPerfCounters().m_Jit.timeInJitBase = GetPerfCounters().m_Jit.timeInJit;
12971 GetPerfCounters().m_Jit.timeInJit += static_cast<DWORD>(CycleStop.QuadPart - CycleStart.QuadPart);
12972 GetPerfCounters().m_Jit.cMethodsJitted++;
12973 GetPerfCounters().m_Jit.cbILJitted+=methodInfo.ILCodeSize;
12975 #endif // defined(ENABLE_PERF_COUNTERS)
12977 #if defined(ENABLE_PERF_COUNTERS)
12981 #ifdef PERF_TRACK_METHOD_JITTIMES
12982 //store the time in the string buffer. Module name and token are unique enough. Also, do not
12983 //capture importing time, just actual compilation time.
12984 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12986 LARGE_INTEGER methodJitTimeStop;
12987 QueryPerformanceCounter(&methodJitTimeStop);
12989 ftn->GetModule()->GetDomainFile()->GetFile()->GetCodeBaseOrName(codeBase);
12990 codeBase.AppendPrintf(W(",0x%x,%d,%d\n"),
12991 //(const WCHAR *)codeBase, //module name
12992 ftn->GetMemberDef(), //method token
12993 (unsigned)(methodJitTimeStop.QuadPart - methodJitTimeStart.QuadPart), //cycle count
12994 methodInfo.ILCodeSize //il size
12996 WszOutputDebugString((const WCHAR*)codeBase);
12998 #endif // PERF_TRACK_METHOD_JITTIMES
13002 LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s %s }\n",cls,name, ftn->m_pszDebugMethodSignature));
13004 if (!SUCCEEDED(res))
13006 COUNTER_ONLY(GetPerfCounters().m_Jit.cJitFailures++);
13008 #ifndef CROSSGEN_COMPILE
13009 jitInfo.BackoutJitData(jitMgr);
13012 ThrowExceptionForJit(res);
13015 if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
13022 COMPlusThrow(kInvalidProgramException);
13024 #if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)) && !defined(CROSSGEN_COMPILE)
13025 if (jitInfo.IsJumpStubOverflow())
13027 // Backout and try again with fAllowRel32 == FALSE.
13028 jitInfo.BackoutJitData(jitMgr);
13030 #ifdef _TARGET_AMD64_
13031 // Disallow rel32 relocs in future.
13032 g_fAllowRel32 = FALSE;
13034 fAllowRel32 = FALSE;
13035 #endif // _TARGET_AMD64_
13036 #ifdef _TARGET_ARM64_
13037 fForceJumpStubOverflow = FALSE;
13038 #endif // _TARGET_ARM64_
13040 reserveForJumpStubs = jitInfo.GetReserveForJumpStubs();
13043 #endif // (_TARGET_AMD64_ || _TARGET_ARM64_) && !CROSSGEN_COMPILE
13045 LOG((LF_JIT, LL_INFO10000,
13046 "Jitted Entry at" FMT_ADDR "method %s::%s %s\n", DBG_ADDR(nativeEntry),
13047 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
13049 #if defined(FEATURE_CORESYSTEM)
13052 LPCUTF8 pszDebugClassName = ftn->m_pszDebugClassName;
13053 LPCUTF8 pszDebugMethodName = ftn->m_pszDebugMethodName;
13054 LPCUTF8 pszDebugMethodSignature = ftn->m_pszDebugMethodSignature;
13056 LPCUTF8 pszNamespace;
13057 LPCUTF8 pszDebugClassName = ftn->GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace);
13058 LPCUTF8 pszDebugMethodName = ftn->GetName();
13059 LPCUTF8 pszDebugMethodSignature = "";
13062 //DbgPrintf("Jitted Entry at" FMT_ADDR "method %s::%s %s size %08x\n", DBG_ADDR(nativeEntry),
13063 // pszDebugClassName, pszDebugMethodName, pszDebugMethodSignature, sizeOfCode);
13066 ClrFlushInstructionCache(nativeEntry, sizeOfCode);
13067 ret = (PCODE)nativeEntry;
13069 #ifdef _TARGET_ARM_
13078 FastInterlockIncrement(&g_JitCount);
13079 static BOOL fHeartbeat = -1;
13081 if (fHeartbeat == -1)
13082 fHeartbeat = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitHeartbeat);
13088 COOPERATIVE_TRANSITION_END();
13092 extern "C" unsigned __stdcall PartialNGenStressPercentage()
13094 LIMITED_METHOD_CONTRACT;
13098 static ConfigDWORD partialNGenStress;
13099 DWORD partialNGenStressVal = partialNGenStress.val(CLRConfig::INTERNAL_partialNGenStress);
13100 _ASSERTE(partialNGenStressVal <= 100);
13101 return partialNGenStressVal;
13105 #ifdef FEATURE_PREJIT
13106 /*********************************************************************/
13109 // Table loading functions
13111 void Module::LoadHelperTable()
13113 STANDARD_VM_CONTRACT;
13115 #ifndef CROSSGEN_COMPILE
13117 BYTE * table = (BYTE *) GetNativeImage()->GetNativeHelperTable(&tableSize);
13119 if (tableSize == 0)
13122 EnsureWritableExecutablePages(table, tableSize);
13124 BYTE * curEntry = table;
13125 BYTE * tableEnd = table + tableSize;
13127 #ifdef FEATURE_PERFMAP
13128 PerfMap::LogStubs(__FUNCTION__, GetSimpleName(), (PCODE)table, tableSize);
13132 int iEntryNumber = 0;
13139 while (curEntry < tableEnd)
13141 DWORD dwHelper = *(DWORD *)curEntry;
13143 int iHelper = (USHORT)dwHelper;
13144 _ASSERTE(iHelper < CORINFO_HELP_COUNT);
13146 LOG((LF_JIT, LL_INFO1000000, "JIT helper %3d (%-40s: table @ %p, size 0x%x, entry %3d @ %p, pfnHelper %p)\n",
13147 iHelper, hlpFuncTable[iHelper].name, table, tableSize, iEntryNumber, curEntry, hlpFuncTable[iHelper].pfnHelper));
13149 #if defined(ENABLE_FAST_GCPOLL_HELPER)
13150 // The fast GC poll helper works by calling indirect through a pointer that points to either
13151 // JIT_PollGC or JIT_PollGC_Nop, based on whether we need to poll or not. The JIT_PollGC_Nop
13152 // version is just a "ret". The pointer is stored in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
13153 // See EnableJitGCPoll() and DisableJitGCPoll().
13154 // In NGEN images, we generate a direct call to the helper table. Here, we replace that with
13155 // an indirect jump through the pointer in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
13156 if (iHelper == CORINFO_HELP_POLL_GC)
13158 LOG((LF_JIT, LL_INFO1000000, "JIT helper CORINFO_HELP_POLL_GC (%d); emitting indirect jump to 0x%x\n",
13159 CORINFO_HELP_POLL_GC, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper));
13161 emitJumpInd(curEntry, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper);
13162 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
13165 #endif // ENABLE_FAST_GCPOLL_HELPER
13167 PCODE pfnHelper = CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)iHelper);
13169 if (dwHelper & CORCOMPILE_HELPER_PTR)
13172 // Indirection cell
13175 *(TADDR *)curEntry = pfnHelper;
13177 curEntry = curEntry + sizeof(TADDR);
13185 #if defined(_TARGET_AMD64_)
13186 *curEntry = X86_INSTR_JMP_REL32;
13187 *(INT32 *)(curEntry + 1) = rel32UsingJumpStub((INT32 *)(curEntry + 1), pfnHelper, NULL, GetLoaderAllocator());
13188 #else // all other platforms
13189 emitJump(curEntry, (LPVOID)pfnHelper);
13190 _ASSERTE(HELPER_TABLE_ENTRY_LEN >= JUMP_ALLOCATE_SIZE);
13193 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
13197 // Note that some table entries are sizeof(TADDR) in length, and some are HELPER_TABLE_ENTRY_LEN in length
13202 ClrFlushInstructionCache(table, tableSize);
13203 #endif // CROSSGEN_COMPILE
13206 #ifdef FEATURE_READYTORUN
13207 CorInfoHelpFunc MapReadyToRunHelper(ReadyToRunHelper helperNum)
13209 LIMITED_METHOD_CONTRACT;
13213 #define HELPER(readyToRunHelper, corInfoHelpFunc, flags) \
13214 case readyToRunHelper: return corInfoHelpFunc;
13215 #include "readytorunhelpers.h"
13217 case READYTORUN_HELPER_GetString: return CORINFO_HELP_STRCNS;
13219 default: return CORINFO_HELP_UNDEF;
13223 void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap)
13225 STANDARD_VM_CONTRACT;
13227 ZeroMemory(pGCRefMap, cbGCRefMap);
13229 if (!pMT->ContainsPointers())
13232 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
13233 CGCDescSeries* cur = map->GetHighestSeries();
13234 CGCDescSeries* last = map->GetLowestSeries();
13235 DWORD size = pMT->GetBaseSize();
13236 _ASSERTE(cur >= last);
13240 // offset to embedded references in this series must be
13241 // adjusted by the VTable pointer, when in the unboxed state.
13242 size_t offset = cur->GetSeriesOffset() - TARGET_POINTER_SIZE;
13243 size_t offsetStop = offset + cur->GetSeriesSize() + size;
13244 while (offset < offsetStop)
13246 size_t bit = offset / TARGET_POINTER_SIZE;
13248 size_t index = bit / 8;
13249 _ASSERTE(index < cbGCRefMap);
13250 pGCRefMap[index] |= (1 << (bit & 7));
13252 offset += TARGET_POINTER_SIZE;
13255 } while (cur >= last);
13259 // Type layout check verifies that there was no incompatible change in the value type layout.
13260 // If there was one, we will fall back to JIT instead of using the pre-generated code from the ready to run image.
13261 // This should be rare situation. Changes in value type layout not common.
13263 // The following properties of the value type layout are checked:
13265 // - HFA-ness (on platform that support HFAs)
13267 // - Position of GC references
13269 BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob)
13271 STANDARD_VM_CONTRACT;
13273 SigPointer p(pBlob);
13274 IfFailThrow(p.SkipExactlyOne());
13277 IfFailThrow(p.GetData(&dwFlags));
13279 // Size is checked unconditionally
13280 DWORD dwExpectedSize;
13281 IfFailThrow(p.GetData(&dwExpectedSize));
13283 DWORD dwActualSize = pMT->GetNumInstanceFieldBytes();
13284 if (dwExpectedSize != dwActualSize)
13288 if (dwFlags & READYTORUN_LAYOUT_HFA)
13290 DWORD dwExpectedHFAType;
13291 IfFailThrow(p.GetData(&dwExpectedHFAType));
13293 DWORD dwActualHFAType = pMT->GetHFAType();
13294 if (dwExpectedHFAType != dwActualHFAType)
13303 _ASSERTE(!(dwFlags & READYTORUN_LAYOUT_HFA));
13306 if (dwFlags & READYTORUN_LAYOUT_Alignment)
13308 DWORD dwExpectedAlignment = TARGET_POINTER_SIZE;
13309 if (!(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
13311 IfFailThrow(p.GetData(&dwExpectedAlignment));
13314 DWORD dwActualAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
13315 if (dwExpectedAlignment != dwActualAlignment)
13320 if (dwFlags & READYTORUN_LAYOUT_GCLayout)
13322 if (dwFlags & READYTORUN_LAYOUT_GCLayout_Empty)
13324 if (pMT->ContainsPointers())
13329 size_t cbGCRefMap = (dwActualSize / TARGET_POINTER_SIZE + 7) / 8;
13330 _ASSERTE(cbGCRefMap > 0);
13332 BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
13334 ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
13336 if (memcmp(pGCRefMap, p.GetPtr(), cbGCRefMap) != 0)
13344 #endif // FEATURE_READYTORUN
13346 BOOL LoadDynamicInfoEntry(Module *currentModule,
13350 STANDARD_VM_CONTRACT;
13352 PCCOR_SIGNATURE pBlob = currentModule->GetNativeFixupBlobData(fixupRva);
13354 BYTE kind = *pBlob++;
13356 Module * pInfoModule = currentModule;
13358 if (kind & ENCODE_MODULE_OVERRIDE)
13360 pInfoModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13361 kind &= ~ENCODE_MODULE_OVERRIDE;
13364 MethodDesc * pMD = NULL;
13366 #ifndef CROSSGEN_COMPILE
13367 PCCOR_SIGNATURE pSig;
13369 #endif // CROSSGEN_COMPILE
13375 case ENCODE_MODULE_HANDLE:
13376 result = (size_t)pInfoModule;
13379 case ENCODE_TYPE_HANDLE:
13380 case ENCODE_TYPE_DICTIONARY:
13382 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13384 if (!th.IsTypeDesc())
13386 if (currentModule->IsReadyToRun())
13388 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13389 th.AsMethodTable()->EnsureInstanceActive();
13393 #ifdef FEATURE_WINMD_RESILIENT
13394 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13395 th.AsMethodTable()->EnsureInstanceActive();
13400 result = (size_t)th.AsPtr();
13404 case ENCODE_METHOD_HANDLE:
13405 case ENCODE_METHOD_DICTIONARY:
13407 MethodDesc * pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13409 if (currentModule->IsReadyToRun())
13411 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13412 pMD->EnsureActive();
13415 result = (size_t)pMD;
13419 case ENCODE_FIELD_HANDLE:
13420 result = (size_t) ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13423 #ifndef CROSSGEN_COMPILE
13424 case ENCODE_STRING_HANDLE:
13426 // We need to update strings atomically (due to NoStringInterning attribute). Note
13427 // that modules with string interning dont really need this, as the hash tables have
13428 // their own locking, but dont add more complexity for what will be the non common
13431 // We will have to lock and update the entry. (this is really a double check, where
13432 // the first check is done in the caller of this function)
13433 DWORD rid = CorSigUncompressData(pBlob);
13437 result = (size_t)StringObject::GetEmptyStringRefPtr();
13441 CrstHolder ch(pInfoModule->GetFixupCrst());
13443 if (!CORCOMPILE_IS_POINTER_TAGGED(*entry) && (*entry != NULL))
13445 // We lost the race, just return
13449 // For generic instantiations compiled into the ngen image of some other
13450 // client assembly, we need to ensure that we intern the string
13451 // in the defining assembly.
13452 bool mayNeedToSyncWithFixups = pInfoModule != currentModule;
13454 result = (size_t) pInfoModule->ResolveStringRef(TokenFromRid(rid, mdtString), currentModule->GetDomain(), mayNeedToSyncWithFixups);
13459 case ENCODE_VARARGS_SIG:
13461 mdSignature token = TokenFromRid(
13462 CorSigUncompressData(pBlob),
13465 IfFailThrow(pInfoModule->GetMDImport()->GetSigFromToken(token, &cSig, &pSig));
13471 case ENCODE_VARARGS_METHODREF:
13473 mdSignature token = TokenFromRid(
13474 CorSigUncompressData(pBlob),
13477 LPCSTR szName_Ignore;
13478 IfFailThrow(pInfoModule->GetMDImport()->GetNameAndSigOfMemberRef(token, &pSig, &cSig, &szName_Ignore));
13484 case ENCODE_VARARGS_METHODDEF:
13486 mdSignature token = TokenFromRid(
13487 CorSigUncompressData(pBlob),
13490 IfFailThrow(pInfoModule->GetMDImport()->GetSigOfMethodDef(token, &cSig, &pSig));
13494 result = (size_t) CORINFO_VARARGS_HANDLE(currentModule->GetVASigCookie(Signature(pSig, cSig)));
13498 // ENCODE_METHOD_NATIVECALLABLE_HANDLE is same as ENCODE_METHOD_ENTRY_DEF_TOKEN
13499 // except for AddrOfCode
13500 case ENCODE_METHOD_NATIVE_ENTRY:
13501 case ENCODE_METHOD_ENTRY_DEF_TOKEN:
13503 mdToken MethodDef = TokenFromRid(CorSigUncompressData(pBlob), mdtMethodDef);
13504 pMD = MemberLoader::GetMethodDescFromMethodDef(pInfoModule, MethodDef, FALSE);
13506 pMD->PrepareForUseAsADependencyOfANativeImage();
13508 if (currentModule->IsReadyToRun())
13510 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13511 pMD->EnsureActive();
13517 case ENCODE_METHOD_ENTRY_REF_TOKEN:
13519 SigTypeContext typeContext;
13520 mdToken MemberRef = TokenFromRid(CorSigUncompressData(pBlob), mdtMemberRef);
13521 FieldDesc * pFD = NULL;
13524 MemberLoader::GetDescFromMemberRef(pInfoModule, MemberRef, &pMD, &pFD, &typeContext, FALSE /* strict metadata checks */, &th);
13525 _ASSERTE(pMD != NULL);
13527 pMD->PrepareForUseAsADependencyOfANativeImage();
13529 if (currentModule->IsReadyToRun())
13531 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13532 pMD->EnsureActive();
13536 #ifdef FEATURE_WINMD_RESILIENT
13537 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13538 pMD->EnsureActive();
13545 case ENCODE_METHOD_ENTRY:
13547 pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13549 if (currentModule->IsReadyToRun())
13551 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13552 pMD->EnsureActive();
13556 if (kind == ENCODE_METHOD_NATIVE_ENTRY)
13558 result = COMDelegate::ConvertToCallback(pMD);
13562 result = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY);
13565 #ifndef _TARGET_ARM_
13566 if (CORCOMPILE_IS_PCODE_TAGGED(result))
13568 // There is a rare case where the function entrypoint may not be aligned. This could happen only for FCalls,
13569 // only on x86 and only if we failed to hardbind the fcall (e.g. ngen image for mscorlib.dll does not exist
13570 // and /nodependencies flag for ngen was used). The function entrypoints should be aligned in all other cases.
13572 // We will wrap the unaligned method entrypoint by funcptr stub with aligned entrypoint.
13573 _ASSERTE(pMD->IsFCall());
13574 result = pMD->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pMD);
13580 case ENCODE_SYNC_LOCK:
13582 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13584 result = (size_t) GetClassSync(th.AsMethodTable());
13588 case ENCODE_INDIRECT_PINVOKE_TARGET:
13590 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13592 _ASSERTE(pMethod->IsNDirect());
13593 NDirectMethodDesc *pMD = (NDirectMethodDesc*)pMethod;
13594 result = (size_t)(LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
13598 #if defined(PROFILING_SUPPORTED)
13599 case ENCODE_PROFILING_HANDLE:
13601 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13603 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
13604 // they shouldnever come here as they are called out in GetCompileFlag
13605 _ASSERTE(!pMethod->IsNoMetadata());
13607 FunctionID funId = (FunctionID)pMethod;
13609 BOOL bHookFunction = TRUE;
13610 CORINFO_PROFILING_HANDLE profilerHandle = (CORINFO_PROFILING_HANDLE)funId;
13613 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
13614 profilerHandle = (CORINFO_PROFILING_HANDLE) g_profControlBlock.pProfInterface->EEFunctionIDMapper(funId, &bHookFunction);
13615 END_PIN_PROFILER();
13618 // Profiling handle is opaque token. It does not have to be aligned thus we can not store it in the same location as token.
13619 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexClientData) = (SIZE_T)profilerHandle;
13623 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER].pfnHelper;
13624 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE].pfnHelper;
13625 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL].pfnHelper;
13629 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13630 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13631 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13635 #endif // PROFILING_SUPPORTED
13637 case ENCODE_STATIC_FIELD_ADDRESS:
13639 FieldDesc *pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13641 pField->GetEnclosingMethodTable()->CheckRestore();
13643 // We can take address of RVA field only since ngened code is domain neutral
13644 _ASSERTE(pField->IsRVA());
13646 // Field address is not aligned thus we can not store it in the same location as token.
13647 *EnsureWritablePages(entry+1) = (size_t)pField->GetStaticAddressHandle(NULL);
13651 case ENCODE_VIRTUAL_ENTRY_SLOT:
13653 DWORD slot = CorSigUncompressData(pBlob);
13655 TypeHandle ownerType = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13657 LOG((LF_ZAP, LL_INFO100000, " Fixup stub dispatch\n"));
13659 VirtualCallStubManager * pMgr = currentModule->GetLoaderAllocator()->GetVirtualCallStubManager();
13662 // We should be generating a stub indirection here, but the zapper already uses one level
13663 // of indirection, i.e. we would have to return IAT_PPVALUE to the JIT, and on the whole the JITs
13664 // aren't quite set up to accept that. Furthermore the call sequences would be different - at
13665 // the moment an indirection cell uses "call [cell-addr]" on x86, and instead we would want the
13666 // euqivalent of "call [[call-addr]]". This could perhaps be implemented as "call [eax]" </REVISIT_TODO>
13667 result = pMgr->GetCallStub(ownerType, slot);
13671 case ENCODE_CLASS_ID_FOR_STATICS:
13673 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13675 MethodTable * pMT = th.AsMethodTable();
13676 if (pMT->IsDynamicStatics())
13678 result = pMT->GetModuleDynamicEntryID();
13682 result = pMT->GetClassIndex();
13687 case ENCODE_MODULE_ID_FOR_STATICS:
13689 result = pInfoModule->GetModuleID();
13693 case ENCODE_MODULE_ID_FOR_GENERIC_STATICS:
13695 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13697 MethodTable * pMT = th.AsMethodTable();
13699 result = pMT->GetModuleForStatics()->GetModuleID();
13703 case ENCODE_ACTIVE_DEPENDENCY:
13705 Module* pModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13707 STRESS_LOG3(LF_ZAP,LL_INFO10000,"Modules are: %08x,%08x,%08x",currentModule,pInfoModule,pModule);
13708 pInfoModule->AddActiveDependency(pModule, FALSE);
13712 #ifdef FEATURE_READYTORUN
13713 case ENCODE_READYTORUN_HELPER:
13715 DWORD helperNum = CorSigUncompressData(pBlob);
13717 CorInfoHelpFunc corInfoHelpFunc = MapReadyToRunHelper((ReadyToRunHelper)helperNum);
13718 if (corInfoHelpFunc != CORINFO_HELP_UNDEF)
13720 result = (size_t)CEEJitInfo::getHelperFtnStatic(corInfoHelpFunc);
13726 case READYTORUN_HELPER_Module:
13728 Module * pPrevious = InterlockedCompareExchangeT(EnsureWritablePages((Module **)entry), pInfoModule, NULL);
13729 if (pPrevious != pInfoModule && pPrevious != NULL)
13730 COMPlusThrowHR(COR_E_FILELOAD, IDS_NATIVE_IMAGE_CANNOT_BE_LOADED_MULTIPLE_TIMES, pInfoModule->GetPath());
13735 case READYTORUN_HELPER_GSCookie:
13736 result = (size_t)GetProcessGSCookie();
13739 case READYTORUN_HELPER_DelayLoad_MethodCall:
13740 result = (size_t)GetEEFuncEntryPoint(DelayLoad_MethodCall);
13743 case READYTORUN_HELPER_DelayLoad_Helper:
13744 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper);
13747 case READYTORUN_HELPER_DelayLoad_Helper_Obj:
13748 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_Obj);
13751 case READYTORUN_HELPER_DelayLoad_Helper_ObjObj:
13752 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_ObjObj);
13756 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown READYTORUN_HELPER %d\n", helperNum);
13757 _ASSERTE(!"Unknown READYTORUN_HELPER");
13764 case ENCODE_FIELD_OFFSET:
13766 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13767 _ASSERTE(!pFD->IsStatic());
13768 _ASSERTE(!pFD->IsFieldOfValueType());
13770 DWORD dwOffset = (DWORD)sizeof(Object) + pFD->GetOffset();
13772 if (dwOffset > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13778 case ENCODE_FIELD_BASE_OFFSET:
13780 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13782 MethodTable * pMT = th.AsMethodTable();
13783 _ASSERTE(!pMT->IsValueType());
13785 DWORD dwOffsetBase = ReadyToRunInfo::GetFieldBaseOffset(pMT);
13786 if (dwOffsetBase > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13788 result = dwOffsetBase;
13792 case ENCODE_CHECK_TYPE_LAYOUT:
13794 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13795 MethodTable * pMT = th.AsMethodTable();
13796 _ASSERTE(pMT->IsValueType());
13798 if (!TypeLayoutCheck(pMT, pBlob))
13805 case ENCODE_CHECK_FIELD_OFFSET:
13807 DWORD dwExpectedOffset = CorSigUncompressData(pBlob);
13809 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13810 _ASSERTE(!pFD->IsStatic());
13812 DWORD dwOffset = pFD->GetOffset();
13813 if (!pFD->IsFieldOfValueType())
13814 dwOffset += sizeof(Object);
13816 if (dwExpectedOffset != dwOffset)
13822 #endif // FEATURE_READYTORUN
13824 #endif // CROSSGEN_COMPILE
13827 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown FIXUP_BLOB_KIND %d\n", kind);
13828 _ASSERTE(!"Unknown FIXUP_BLOB_KIND");
13833 *EnsureWritablePages(entry) = result;
13837 #endif // FEATURE_PREJIT
13839 void* CEEInfo::getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig,
13840 CorInfoHelperTailCallSpecialHandling flags)
13851 #if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)) && !defined(FEATURE_PAL)
13853 JIT_TO_EE_TRANSITION();
13855 Stub* pStub = CPUSTUBLINKER::CreateTailCallCopyArgsThunk(pSig, m_pMethodBeingCompiled, flags);
13857 ftn = (void*)pStub->GetEntryPoint();
13859 EE_TO_JIT_TRANSITION();
13861 #endif // (_TARGET_AMD64_ || _TARGET_ARM_) && !FEATURE_PAL
13866 bool CEEInfo::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert)
13871 void CEEInfo::allocMem (
13872 ULONG hotCodeSize, /* IN */
13873 ULONG coldCodeSize, /* IN */
13874 ULONG roDataSize, /* IN */
13875 ULONG xcptnsCount, /* IN */
13876 CorJitAllocMemFlag flag, /* IN */
13877 void ** hotCodeBlock, /* OUT */
13878 void ** coldCodeBlock, /* OUT */
13879 void ** roDataBlock /* OUT */
13882 LIMITED_METHOD_CONTRACT;
13883 UNREACHABLE(); // only called on derived class.
13886 void CEEInfo::reserveUnwindInfo (
13887 BOOL isFunclet, /* IN */
13888 BOOL isColdCode, /* IN */
13889 ULONG unwindSize /* IN */
13892 LIMITED_METHOD_CONTRACT;
13893 UNREACHABLE(); // only called on derived class.
13896 void CEEInfo::allocUnwindInfo (
13897 BYTE * pHotCode, /* IN */
13898 BYTE * pColdCode, /* IN */
13899 ULONG startOffset, /* IN */
13900 ULONG endOffset, /* IN */
13901 ULONG unwindSize, /* IN */
13902 BYTE * pUnwindBlock, /* IN */
13903 CorJitFuncKind funcKind /* IN */
13906 LIMITED_METHOD_CONTRACT;
13907 UNREACHABLE(); // only called on derived class.
13910 void * CEEInfo::allocGCInfo (
13911 size_t size /* IN */
13914 LIMITED_METHOD_CONTRACT;
13915 UNREACHABLE_RET(); // only called on derived class.
13918 void CEEInfo::setEHcount (
13919 unsigned cEH /* IN */
13922 LIMITED_METHOD_CONTRACT;
13923 UNREACHABLE(); // only called on derived class.
13926 void CEEInfo::setEHinfo (
13927 unsigned EHnumber, /* IN */
13928 const CORINFO_EH_CLAUSE *clause /* IN */
13931 LIMITED_METHOD_CONTRACT;
13932 UNREACHABLE(); // only called on derived class.
13935 InfoAccessType CEEInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
13939 LIMITED_METHOD_CONTRACT;
13940 UNREACHABLE(); // only called on derived class.
13943 InfoAccessType CEEInfo::emptyStringLiteral(void ** ppValue)
13945 LIMITED_METHOD_CONTRACT;
13946 _ASSERTE(isVerifyOnly());
13947 *ppValue = (void *)0x10;
13951 void* CEEInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
13952 void **ppIndirection)
13954 LIMITED_METHOD_CONTRACT;
13955 _ASSERTE(isVerifyOnly());
13956 if (ppIndirection != NULL)
13957 *ppIndirection = NULL;
13958 return (void *)0x10;
13961 CORINFO_CLASS_HANDLE CEEInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
13962 bool* pIsSpeculative)
13964 LIMITED_METHOD_CONTRACT;
13965 _ASSERTE(isVerifyOnly());
13966 if (pIsSpeculative != NULL)
13967 *pIsSpeculative = true;
13971 void* CEEInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
13972 void **ppIndirection)
13974 LIMITED_METHOD_CONTRACT;
13975 UNREACHABLE(); // only called on derived class.
13978 HRESULT CEEInfo::allocBBProfileBuffer (
13979 ULONG count, // The number of basic blocks that we have
13980 ProfileBuffer ** profileBuffer
13983 LIMITED_METHOD_CONTRACT;
13984 UNREACHABLE_RET(); // only called on derived class.
13987 HRESULT CEEInfo::getBBProfileData(
13988 CORINFO_METHOD_HANDLE ftnHnd,
13989 ULONG * count, // The number of basic blocks that we have
13990 ProfileBuffer ** profileBuffer,
13994 LIMITED_METHOD_CONTRACT;
13995 UNREACHABLE_RET(); // only called on derived class.
13999 void CEEInfo::recordCallSite(
14000 ULONG instrOffset, /* IN */
14001 CORINFO_SIG_INFO * callSig, /* IN */
14002 CORINFO_METHOD_HANDLE methodHandle /* IN */
14005 LIMITED_METHOD_CONTRACT;
14006 UNREACHABLE(); // only called on derived class.
14009 void CEEInfo::recordRelocation(
14010 void * location, /* IN */
14011 void * target, /* IN */
14012 WORD fRelocType, /* IN */
14013 WORD slotNum, /* IN */
14014 INT32 addlDelta /* IN */
14017 LIMITED_METHOD_CONTRACT;
14018 UNREACHABLE(); // only called on derived class.
14021 WORD CEEInfo::getRelocTypeHint(void * target)
14023 LIMITED_METHOD_CONTRACT;
14024 UNREACHABLE_RET(); // only called on derived class.
14027 void CEEInfo::getModuleNativeEntryPointRange(
14028 void ** pStart, /* OUT */
14029 void ** pEnd /* OUT */
14032 LIMITED_METHOD_CONTRACT;
14033 UNREACHABLE(); // only called on derived class.
14036 DWORD CEEInfo::getExpectedTargetArchitecture()
14038 LIMITED_METHOD_CONTRACT;
14040 return IMAGE_FILE_MACHINE_NATIVE;
14043 void CEEInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
14044 ICorDebugInfo::OffsetMapping *pMap)
14046 LIMITED_METHOD_CONTRACT;
14047 UNREACHABLE(); // only called on derived class.
14050 void CEEInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
14052 LIMITED_METHOD_CONTRACT;
14053 UNREACHABLE(); // only called on derived class.
14056 void* CEEInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
14057 void ** ppIndirection) /* OUT */
14059 LIMITED_METHOD_CONTRACT;
14060 UNREACHABLE(); // only called on derived class.
14063 // Active dependency helpers
14064 void CEEInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
14066 LIMITED_METHOD_CONTRACT;
14067 UNREACHABLE(); // only called on derived class.
14070 void CEEInfo::GetProfilingHandle(BOOL *pbHookFunction,
14071 void **pProfilerHandle,
14072 BOOL *pbIndirectedHandles)
14074 LIMITED_METHOD_CONTRACT;
14075 UNREACHABLE(); // only called on derived class.
14078 #endif // !DACCESS_COMPILE
14080 EECodeInfo::EECodeInfo()
14082 WRAPPER_NO_CONTRACT;
14084 m_codeAddress = NULL;
14090 #ifdef WIN64EXCEPTIONS
14091 m_pFunctionEntry = NULL;
14095 void EECodeInfo::Init(PCODE codeAddress)
14103 Init(codeAddress, ExecutionManager::GetScanFlags());
14106 void EECodeInfo::Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag)
14114 m_codeAddress = codeAddress;
14116 RangeSection * pRS = ExecutionManager::FindCodeRange(codeAddress, scanFlag);
14120 if (!pRS->pjit->JitCodeToMethodInfo(pRS, codeAddress, &m_pMD, this))
14131 #ifdef WIN64EXCEPTIONS
14132 m_pFunctionEntry = NULL;
14136 TADDR EECodeInfo::GetSavedMethodCode()
14139 // All EECodeInfo methods must be NOTHROW/GC_NOTRIGGER since they can
14140 // be used during GC.
14147 #if defined(HAVE_GCCOVER)
14148 _ASSERTE (!m_pMD->m_GcCover || GCStress<cfg_instr>::IsEnabled());
14149 if (GCStress<cfg_instr>::IsEnabled()
14150 && m_pMD->m_GcCover)
14152 _ASSERTE(m_pMD->m_GcCover->savedCode);
14154 // Make sure we return the TADDR of savedCode here. The byte array is not marshaled automatically.
14155 // The caller is responsible for any necessary marshaling.
14156 return PTR_TO_MEMBER_TADDR(GCCoverageInfo, m_pMD->m_GcCover, savedCode);
14158 #endif //defined(HAVE_GCCOVER)
14161 return GetStartAddress();
14164 TADDR EECodeInfo::GetStartAddress()
14173 return m_pJM->JitTokenToStartAddress(m_methodToken);
14176 #if defined(WIN64EXCEPTIONS)
14178 // ----------------------------------------------------------------------------
14179 // EECodeInfo::GetMainFunctionInfo
14182 // Simple helper to transform a funclet's EECodeInfo into a parent function EECodeInfo.
14185 // An EECodeInfo for the start of the main function body (offset 0).
14188 EECodeInfo EECodeInfo::GetMainFunctionInfo()
14190 LIMITED_METHOD_CONTRACT;
14193 EECodeInfo result = *this;
14194 result.m_relOffset = 0;
14195 result.m_codeAddress = this->GetStartAddress();
14196 result.m_pFunctionEntry = NULL;
14201 PTR_RUNTIME_FUNCTION EECodeInfo::GetFunctionEntry()
14203 LIMITED_METHOD_CONTRACT;
14206 if (m_pFunctionEntry == NULL)
14207 m_pFunctionEntry = m_pJM->LazyGetFunctionEntry(this);
14208 return m_pFunctionEntry;
14211 #if defined(_TARGET_AMD64_)
14213 BOOL EECodeInfo::HasFrameRegister()
14215 LIMITED_METHOD_CONTRACT;
14217 PTR_RUNTIME_FUNCTION pFuncEntry = GetFunctionEntry();
14218 _ASSERTE(pFuncEntry != NULL);
14220 BOOL fHasFrameRegister = FALSE;
14221 PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(GetModuleBase() + pFuncEntry->UnwindData);
14222 if (pUnwindInfo->FrameRegister != 0)
14224 fHasFrameRegister = TRUE;
14225 _ASSERTE(pUnwindInfo->FrameRegister == kRBP);
14228 return fHasFrameRegister;
14230 #endif // defined(_TARGET_AMD64_)
14232 #endif // defined(WIN64EXCEPTIONS)
14235 #if defined(_TARGET_AMD64_)
14236 // ----------------------------------------------------------------------------
14237 // EECodeInfo::GetUnwindInfoHelper
14240 // Simple helper to return a pointer to the UNWIND_INFO given the offset to the unwind info.
14241 // On DAC builds, this function will read the memory from the target process and create a host copy.
14244 // * unwindInfoOffset - This is the offset to the unwind info, relative to the beginning of the code heap
14245 // for jitted code or to the module base for ngned code. this->GetModuleBase() will return the correct
14249 // Return a pointer to the UNWIND_INFO. On DAC builds, this function will create a host copy of the
14250 // UNWIND_INFO and return a host pointer. It will correctly read all of the memory for the variable-sized
14254 UNWIND_INFO * EECodeInfo::GetUnwindInfoHelper(ULONG unwindInfoOffset)
14256 #if defined(DACCESS_COMPILE)
14257 return DacGetUnwindInfo(static_cast<TADDR>(this->GetModuleBase() + unwindInfoOffset));
14258 #else // !DACCESS_COMPILE
14259 return reinterpret_cast<UNWIND_INFO *>(this->GetModuleBase() + unwindInfoOffset);
14260 #endif // !DACCESS_COMPILE
14263 // ----------------------------------------------------------------------------
14264 // EECodeInfo::GetFixedStackSize
14267 // Return the fixed stack size of a specified managed method. This function DOES NOT take current control
14268 // PC into account. So the fixed stack size returned by this function is not valid in the prolog or
14272 // Return the fixed stack size.
14275 // * For method with dynamic stack allocations, this function will return the fixed stack size on X64 (the
14276 // stack size immediately after the prolog), and it will return 0 on IA64. This difference is due to
14277 // the different unwind info encoding.
14280 ULONG EECodeInfo::GetFixedStackSize()
14282 WRAPPER_NO_CONTRACT;
14285 ULONG uFixedStackSize = 0;
14288 GetOffsetsFromUnwindInfo(&uFixedStackSize, &uDummy);
14290 return uFixedStackSize;
14294 // The information returned by this method is only valid if we are not in a prolog or an epilog.
14295 // Since this method is only used for the security stackwalk cache, this assumption is valid, since
14296 // we cannot make a call in a prolog or an epilog.
14298 // The next assumption is that only rbp is used as a frame register in jitted code. There is an
14299 // assert below to guard this assumption.
14300 void EECodeInfo::GetOffsetsFromUnwindInfo(ULONG* pRSPOffset, ULONG* pRBPOffset)
14302 LIMITED_METHOD_CONTRACT;
14305 _ASSERTE((pRSPOffset != NULL) && (pRBPOffset != NULL));
14307 // moduleBase is a target address.
14308 TADDR moduleBase = GetModuleBase();
14310 DWORD unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(GetFunctionEntry());
14312 if ((unwindInfo & RUNTIME_FUNCTION_INDIRECT) != 0)
14314 unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(PTR_RUNTIME_FUNCTION(moduleBase + (unwindInfo & ~RUNTIME_FUNCTION_INDIRECT)));
14317 UNWIND_INFO * pInfo = GetUnwindInfoHelper(unwindInfo);
14318 if (pInfo->Flags & UNW_FLAG_CHAININFO)
14320 _ASSERTE(!"GetRbpOffset() - chained unwind info used, violating assumptions of the security stackwalk cache");
14324 // Either we are not using a frame pointer, or we are using rbp as the frame pointer.
14325 if ( (pInfo->FrameRegister != 0) && (pInfo->FrameRegister != kRBP) )
14327 _ASSERTE(!"GetRbpOffset() - non-RBP frame pointer used, violating assumptions of the security stackwalk cache");
14331 // Walk the unwind info.
14332 ULONG StackOffset = 0;
14333 ULONG StackSize = 0;
14334 for (int i = 0; i < pInfo->CountOfUnwindCodes; i++)
14336 ULONG UnwindOp = pInfo->UnwindCode[i].UnwindOp;
14337 ULONG OpInfo = pInfo->UnwindCode[i].OpInfo;
14339 if (UnwindOp == UWOP_SAVE_NONVOL)
14341 if (OpInfo == kRBP)
14343 StackOffset = pInfo->UnwindCode[i+1].FrameOffset * 8;
14346 else if (UnwindOp == UWOP_SAVE_NONVOL_FAR)
14348 if (OpInfo == kRBP)
14350 StackOffset = pInfo->UnwindCode[i + 1].FrameOffset;
14351 StackOffset += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14354 else if (UnwindOp == UWOP_ALLOC_SMALL)
14356 StackSize += (OpInfo * 8) + 8;
14358 else if (UnwindOp == UWOP_ALLOC_LARGE)
14360 ULONG IncrementalStackSize = pInfo->UnwindCode[i + 1].FrameOffset;
14363 IncrementalStackSize *= 8;
14367 IncrementalStackSize += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14369 // This is a special opcode. We need to increment the index by 1 in addition to the normal adjustments.
14372 StackSize += IncrementalStackSize;
14374 else if (UnwindOp == UWOP_PUSH_NONVOL)
14376 // Because of constraints on epilogs, this unwind opcode is always last in the unwind code array.
14377 // This means that StackSize has been initialized already when we first see this unwind opcode.
14378 // Note that the intial value of StackSize does not include the stack space used for pushes.
14379 // Thus, here we only need to increment StackSize 8 bytes at a time until we see the unwind code for "push rbp".
14380 if (OpInfo == kRBP)
14382 StackOffset = StackSize;
14388 // Adjust the index into the unwind code array.
14389 i += UnwindOpExtraSlotTable[UnwindOp];
14392 *pRSPOffset = StackSize + 8; // add 8 for the return address
14393 *pRBPOffset = StackOffset;
14398 #if defined(_DEBUG) && defined(HAVE_GCCOVER)
14400 LPVOID EECodeInfo::findNextFunclet (LPVOID pvFuncletStart, SIZE_T cbCode, LPVOID *ppvFuncletEnd)
14409 PT_RUNTIME_FUNCTION pFunctionEntry;
14410 ULONGLONG uImageBase;
14412 EECodeInfo codeInfo;
14413 codeInfo.Init((PCODE)pvFuncletStart);
14414 pFunctionEntry = codeInfo.GetFunctionEntry();
14415 uImageBase = (ULONGLONG)codeInfo.GetModuleBase();
14416 #else // !FEATURE_PAL
14418 // This is GCStress debug only - use the slow OS APIs to enumerate funclets
14421 pFunctionEntry = (PT_RUNTIME_FUNCTION) RtlLookupFunctionEntry((ULONGLONG)pvFuncletStart,
14427 if (pFunctionEntry != NULL)
14429 #ifdef FEATURE_PREJIT
14430 // workaround: Check for indirect entry that is generated for cold part of main method body.
14431 if ((TADDR)pvFuncletStart < (TADDR)uImageBase + pFunctionEntry->BeginAddress ||
14432 (TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart)
14434 Module * pZapModule = ExecutionManager::FindZapModule((TADDR)pvFuncletStart);
14435 NGenLayoutInfo * pLayoutInfo = pZapModule->GetNGenLayoutInfo();
14437 int ColdFunctionIndex = NativeUnwindInfoLookupTable::LookupUnwindInfoForMethod((DWORD)((TADDR)pvFuncletStart - uImageBase),
14438 pLayoutInfo->m_pRuntimeFunctions[2],
14439 0, pLayoutInfo->m_nRuntimeFunctions[2] - 1);
14441 pFunctionEntry = pLayoutInfo->m_pRuntimeFunctions[2] + ColdFunctionIndex;
14445 _ASSERTE((TADDR)pvFuncletStart == (TADDR)uImageBase + pFunctionEntry->BeginAddress);
14446 _ASSERTE((TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart + cbCode);
14447 *ppvFuncletEnd = (LPVOID)(uImageBase + pFunctionEntry->EndAddress);
14448 return (LPVOID)(uImageBase + pFunctionEntry->BeginAddress);
14451 pvFuncletStart = (LPVOID)((TADDR)pvFuncletStart + 1);
14457 #endif // defined(_DEBUG) && !defined(HAVE_GCCOVER)
14458 #endif // defined(_TARGET_AMD64_)