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"
43 #include "typestring.h"
44 #include "stackprobe.h"
46 #include "genericdict.h"
48 #include "debuginfostore.h"
50 #include "runtimehandles.h"
51 #include "sigbuilder.h"
55 #endif // HAVE_GCCOVER
57 #include "mdaassistants.h"
61 #include "corcompile.h"
62 #endif // FEATURE_PREJIT
65 #ifdef FEATURE_INTERPRETER
66 #include "interpreter.h"
67 #endif // FEATURE_INTERPRETER
69 #ifdef FEATURE_PERFMAP
73 // The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro
76 #define JIT_TO_EE_TRANSITION() MAKE_CURRENT_THREAD_AVAILABLE_EX(m_pThread); \
77 _ASSERTE(CURRENT_THREAD == GetThread()); \
78 INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE; \
79 COOPERATIVE_TRANSITION_BEGIN(); \
82 #define EE_TO_JIT_TRANSITION() STOP_NON_JIT_PERF(); \
83 COOPERATIVE_TRANSITION_END(); \
84 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE;
86 #define JIT_TO_EE_TRANSITION_LEAF()
87 #define EE_TO_JIT_TRANSITION_LEAF()
90 #if defined(CROSSGEN_COMPILE)
91 static const char *const hlpNameTable[CORINFO_HELP_COUNT] = {
92 #define JITHELPER(code, pfnHelper, sig) #code,
93 #include "jithelpers.h"
97 #ifdef DACCESS_COMPILE
99 // The real definitions are in jithelpers.cpp. However, those files are not included in the DAC build.
100 // Hence, we add them here.
101 GARY_IMPL(VMHELPDEF, hlpFuncTable, CORINFO_HELP_COUNT);
102 GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);
104 #else // DACCESS_COMPILE
106 /*********************************************************************/
108 #if defined(ENABLE_PERF_COUNTERS)
109 LARGE_INTEGER g_lastTimeInJitCompilation;
112 /*********************************************************************/
114 inline CORINFO_MODULE_HANDLE GetScopeHandle(MethodDesc* method)
116 LIMITED_METHOD_CONTRACT;
117 if (method->IsDynamicMethod())
119 return MakeDynamicScope(method->AsDynamicMethodDesc()->GetResolver());
123 return GetScopeHandle(method->GetModule());
127 //This is common refactored code from within several of the access check functions.
128 BOOL ModifyCheckForDynamicMethod(DynamicResolver *pResolver,
129 TypeHandle *pOwnerTypeForSecurity,
130 AccessCheckOptions::AccessCheckType *pAccessCheckType,
131 DynamicResolver** ppAccessContext)
135 PRECONDITION(CheckPointer(pResolver));
136 PRECONDITION(CheckPointer(pOwnerTypeForSecurity));
137 PRECONDITION(CheckPointer(pAccessCheckType));
138 PRECONDITION(CheckPointer(ppAccessContext));
139 PRECONDITION(*pAccessCheckType == AccessCheckOptions::kNormalAccessibilityChecks);
142 BOOL doAccessCheck = TRUE;
144 //Do not blindly initialize fields, since they've already got important values.
145 DynamicResolver::SecurityControlFlags dwSecurityFlags = DynamicResolver::Default;
147 TypeHandle dynamicOwner;
148 pResolver->GetJitContext(&dwSecurityFlags, &dynamicOwner);
149 if (!dynamicOwner.IsNull())
150 *pOwnerTypeForSecurity = dynamicOwner;
152 if (dwSecurityFlags & DynamicResolver::SkipVisibilityChecks)
154 doAccessCheck = FALSE;
156 else if (dwSecurityFlags & DynamicResolver::RestrictedSkipVisibilityChecks)
158 *pAccessCheckType = AccessCheckOptions::kRestrictedMemberAccessNoTransparency;
162 *pAccessCheckType = AccessCheckOptions::kNormalAccessNoTransparency;
165 return doAccessCheck;
168 /*****************************************************************************/
170 // Initialize from data we passed across to the JIT
171 inline static void GetTypeContext(const CORINFO_SIG_INST *info, SigTypeContext *pTypeContext)
173 LIMITED_METHOD_CONTRACT;
174 SigTypeContext::InitTypeContext(
175 Instantiation((TypeHandle *) info->classInst, info->classInstCount),
176 Instantiation((TypeHandle *) info->methInst, info->methInstCount),
180 static MethodDesc* GetMethodFromContext(CORINFO_CONTEXT_HANDLE context)
182 LIMITED_METHOD_CONTRACT;
183 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
189 return GetMethod((CORINFO_METHOD_HANDLE)((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
193 static TypeHandle GetTypeFromContext(CORINFO_CONTEXT_HANDLE context)
195 LIMITED_METHOD_CONTRACT;
196 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
198 return TypeHandle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
202 MethodTable * pMT = GetMethodFromContext(context)->GetMethodTable();
203 return TypeHandle(pMT);
207 // Initialize from a context parameter passed to the JIT and back. This is a parameter
208 // that indicates which method is being jitted.
210 inline static void GetTypeContext(CORINFO_CONTEXT_HANDLE context, SigTypeContext *pTypeContext)
218 PRECONDITION(context != NULL);
221 if (GetMethodFromContext(context))
223 SigTypeContext::InitTypeContext(GetMethodFromContext(context), pTypeContext);
227 SigTypeContext::InitTypeContext(GetTypeFromContext(context), pTypeContext);
231 static BOOL ContextIsShared(CORINFO_CONTEXT_HANDLE context)
233 LIMITED_METHOD_CONTRACT;
234 MethodDesc *pContextMD = GetMethodFromContext(context);
235 if (pContextMD != NULL)
237 return pContextMD->IsSharedByGenericInstantiations();
241 // Type handle contexts are non-shared and are used for inlining of
242 // non-generic methods in generic classes
247 // Returns true if context is providing any generic variables
248 static BOOL ContextIsInstantiated(CORINFO_CONTEXT_HANDLE context)
250 LIMITED_METHOD_CONTRACT;
251 if (GetMethodFromContext(context))
253 return GetMethodFromContext(context)->HasClassOrMethodInstantiation();
257 return GetTypeFromContext(context).HasInstantiation();
261 /*********************************************************************/
262 // This normalizes EE type information into the form expected by the JIT.
264 // If typeHnd contains exact type information, then *clsRet will contain
265 // the normalized CORINFO_CLASS_HANDLE information on return.
268 CorInfoType CEEInfo::asCorInfoType(CorElementType eeType,
269 TypeHandle typeHnd, /* optional in */
270 CORINFO_CLASS_HANDLE *clsRet/* optional out */ ) {
271 CONTRACT(CorInfoType) {
274 PRECONDITION((CorTypeInfo::IsGenericVariable(eeType)) ==
275 (!typeHnd.IsNull() && typeHnd.IsGenericVariable()));
276 PRECONDITION(eeType != ELEMENT_TYPE_GENERICINST);
279 TypeHandle typeHndUpdated = typeHnd;
281 if (!typeHnd.IsNull())
283 CorElementType normType = typeHnd.GetInternalCorElementType();
284 // If we have a type handle, then it has the better type
286 if (eeType == ELEMENT_TYPE_VALUETYPE && !CorTypeInfo::IsObjRef(normType))
289 // Zap the typeHnd when the type _really_ is a primitive
290 // as far as verification is concerned. Returning a null class
291 // handle means it is is a primitive.
293 // Enums are exactly like primitives, even from a verification standpoint,
294 // so we zap the type handle in this case.
296 // However RuntimeTypeHandle etc. are reported as E_T_INT (or something like that)
297 // but don't count as primitives as far as verification is concerned...
299 // To make things stranger, TypedReference returns true for "IsTruePrimitive".
300 // However the JIT likes us to report the type handle in that case.
301 if (!typeHnd.IsTypeDesc() && (
302 (typeHnd.AsMethodTable()->IsTruePrimitive() && typeHnd != TypeHandle(g_TypedReferenceMT))
303 || typeHnd.AsMethodTable()->IsEnum()) )
305 typeHndUpdated = TypeHandle();
310 static const BYTE map[] = {
326 CORINFO_TYPE_PTR, // PTR
328 CORINFO_TYPE_VALUECLASS,
330 CORINFO_TYPE_VAR, // VAR (type variable)
331 CORINFO_TYPE_CLASS, // ARRAY
332 CORINFO_TYPE_CLASS, // WITH
334 CORINFO_TYPE_UNDEF, // VALUEARRAY_UNSUPPORTED
335 CORINFO_TYPE_NATIVEINT, // I
336 CORINFO_TYPE_NATIVEUINT, // U
337 CORINFO_TYPE_UNDEF, // R_UNSUPPORTED
339 // put the correct type when we know our implementation
340 CORINFO_TYPE_PTR, // FNPTR
341 CORINFO_TYPE_CLASS, // OBJECT
342 CORINFO_TYPE_CLASS, // SZARRAY
343 CORINFO_TYPE_VAR, // MVAR
345 CORINFO_TYPE_UNDEF, // CMOD_REQD
346 CORINFO_TYPE_UNDEF, // CMOD_OPT
347 CORINFO_TYPE_UNDEF, // INTERNAL
350 _ASSERTE(sizeof(map) == ELEMENT_TYPE_MAX);
351 _ASSERTE(eeType < (CorElementType) sizeof(map));
352 // spot check of the map
353 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_I4] == CORINFO_TYPE_INT);
354 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_PTR] == CORINFO_TYPE_PTR);
355 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_TYPEDBYREF] == CORINFO_TYPE_REFANY);
357 CorInfoType res = ((unsigned)eeType < ELEMENT_TYPE_MAX) ? ((CorInfoType) map[(unsigned)eeType]) : CORINFO_TYPE_UNDEF;
360 *clsRet = CORINFO_CLASS_HANDLE(typeHndUpdated.AsPtr());
366 inline static CorInfoType toJitType(TypeHandle typeHnd, CORINFO_CLASS_HANDLE *clsRet = NULL)
369 return CEEInfo::asCorInfoType(typeHnd.GetInternalCorElementType(), typeHnd, clsRet);
373 void DebugSecurityCalloutStress(CORINFO_METHOD_HANDLE methodBeingCompiledHnd,
374 CorInfoIsAccessAllowedResult& currentAnswer,
375 CorInfoSecurityRuntimeChecks& currentRuntimeChecks)
378 if (currentAnswer != CORINFO_ACCESS_ALLOWED)
382 static ConfigDWORD AlwaysInsertCallout;
383 switch (AlwaysInsertCallout.val(CLRConfig::INTERNAL_Security_AlwaysInsertCallout))
389 default: //2 (or anything else), do so half the time
390 if (((size_t(methodBeingCompiledHnd) / sizeof(void*)) % 64) < 32)
394 currentAnswer = CORINFO_ACCESS_RUNTIME_CHECK;
395 currentRuntimeChecks = CORINFO_ACCESS_SECURITY_NONE;
398 #define DebugSecurityCalloutStress(a, b, c) do {} while(0)
401 void CheckForEquivalenceAndLoadTypeBeforeCodeIsRun(Module *pModule, mdToken token, Module *pDefModule, mdToken defToken, const SigParser *ptr, SigTypeContext *pTypeContext, void *pData)
411 if (IsTypeDefEquivalent(defToken, pDefModule))
413 SigPointer sigPtr(*ptr);
414 TypeHandle th = sigPtr.GetTypeHandleThrowing(pModule, pTypeContext);
415 ((ICorDynamicInfo *)pData)->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(th.AsPtr()));
419 inline static void TypeEquivalenceFixupSpecificationHelper(ICorDynamicInfo * pCorInfo, MethodDesc *pMD)
421 STANDARD_VM_CONTRACT;
423 // A fixup is necessary to ensure that the parameters to the method are loaded before the method
424 // is called. In these cases we will not perform the appropriate loading when we load parameter
425 // types because with type equivalence, the parameter types at the call site do not necessarily
426 // match that those in the actual function. (They must be equivalent, but not necessarily the same.)
427 // In non-ngen scenarios this code here will force the types to be loaded directly by the call to
428 // HasTypeEquivalentStructParameters.
429 if (!pMD->IsVirtual())
431 if (pMD->HasTypeEquivalentStructParameters())
433 if (IsCompilationProcess())
434 pMD->WalkValueTypeParameters(pMD->GetMethodTable(), CheckForEquivalenceAndLoadTypeBeforeCodeIsRun, pCorInfo);
439 if (pMD->GetMethodTable()->DependsOnEquivalentOrForwardedStructs())
441 if (pMD->HasTypeEquivalentStructParameters())
442 pCorInfo->classMustBeLoadedBeforeCodeIsRun((CORINFO_CLASS_HANDLE)pMD->GetMethodTable());
447 //---------------------------------------------------------------------------------------
450 // The method handle is used to instantiate method and class type parameters
451 // It's also used to determine whether an extra dictionary parameter is required
453 // sig - Input metadata signature
454 // scopeHnd - The signature is to be interpreted in the context of this scope (module)
455 // token - Metadata token used to refer to the signature (may be mdTokenNil for dynamic methods)
456 // sigRet - Resulting output signature in a format that is understood by native compilers
457 // pContextMD - The method with any instantiation information (may be NULL)
458 // localSig - Is it a local variables declaration, or a method signature (with return type, etc).
459 // contextType - The type with any instantiaton information
463 CEEInfo::ConvToJitSig(
464 PCCOR_SIGNATURE pSig,
466 CORINFO_MODULE_HANDLE scopeHnd,
468 CORINFO_SIG_INFO * sigRet,
469 MethodDesc * pContextMD,
471 TypeHandle contextType)
478 SigTypeContext typeContext;
482 SigTypeContext::InitTypeContext(pContextMD, contextType, &typeContext);
486 SigTypeContext::InitTypeContext(contextType, &typeContext);
489 _ASSERTE(CORINFO_CALLCONV_DEFAULT == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_DEFAULT);
490 _ASSERTE(CORINFO_CALLCONV_VARARG == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_VARARG);
491 _ASSERTE(CORINFO_CALLCONV_MASK == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_MASK);
492 _ASSERTE(CORINFO_CALLCONV_HASTHIS == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_HASTHIS);
494 TypeHandle typeHnd = TypeHandle();
497 sigRet->cbSig = cbSig;
498 sigRet->retTypeClass = 0;
499 sigRet->retTypeSigClass = 0;
500 sigRet->scope = scopeHnd;
501 sigRet->token = token;
502 sigRet->sigInst.classInst = (CORINFO_CLASS_HANDLE *) typeContext.m_classInst.GetRawArgs();
503 sigRet->sigInst.classInstCount = (unsigned) typeContext.m_classInst.GetNumArgs();
504 sigRet->sigInst.methInst = (CORINFO_CLASS_HANDLE *) typeContext.m_methodInst.GetRawArgs();
505 sigRet->sigInst.methInstCount = (unsigned) typeContext.m_methodInst.GetNumArgs();
507 SigPointer sig(pSig, cbSig);
511 // This is a method signature which includes calling convention, return type,
514 _ASSERTE(!sig.IsNull());
515 Module * module = GetModule(scopeHnd);
519 IfFailThrow(sig.GetCallingConvInfo(&data));
520 sigRet->callConv = (CorInfoCallConv) data;
522 if ((isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_VARARG)) ||
523 (isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_NATIVEVARARG)))
525 // This signature corresponds to a method that uses varargs, which are not supported.
526 COMPlusThrow(kInvalidProgramException, IDS_EE_VARARG_NOT_SUPPORTED);
529 // Skip number of type arguments
530 if (sigRet->callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
531 IfFailThrow(sig.GetData(NULL));
534 IfFailThrow(sig.GetData(&numArgs));
535 if (numArgs != (unsigned short) numArgs)
536 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
538 sigRet->numArgs = (unsigned short) numArgs;
540 CorElementType type = sig.PeekElemTypeClosed(module, &typeContext);
542 if (!CorTypeInfo::IsPrimitiveType(type))
544 typeHnd = sig.GetTypeHandleThrowing(module, &typeContext);
545 _ASSERTE(!typeHnd.IsNull());
547 // I believe it doesn't make any diff. if this is
548 // GetInternalCorElementType or GetSignatureCorElementType
549 type = typeHnd.GetSignatureCorElementType();
552 sigRet->retType = CEEInfo::asCorInfoType(type, typeHnd, &sigRet->retTypeClass);
553 sigRet->retTypeSigClass = CORINFO_CLASS_HANDLE(typeHnd.AsPtr());
555 IfFailThrow(sig.SkipExactlyOne()); // must to a skip so we skip any class tokens associated with the return type
556 _ASSERTE(sigRet->retType < CORINFO_TYPE_COUNT);
558 sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
562 // This is local variables declaration
564 sigRet->callConv = CORINFO_CALLCONV_DEFAULT;
565 sigRet->retType = CORINFO_TYPE_VOID;
566 sigRet->flags = CORINFO_SIGFLAG_IS_LOCAL_SIG;
571 IfFailThrow(sig.GetCallingConvInfo(&callConv));
572 if (callConv != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG)
574 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_CALLCONV_NOT_LOCAL_SIG);
578 IfFailThrow(sig.GetData(&numArgs));
580 if (numArgs != (unsigned short) numArgs)
581 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
583 sigRet->numArgs = (unsigned short) numArgs;
586 sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
589 _ASSERTE(SigInfoFlagsAreValid(sigRet));
590 } // CEEInfo::ConvToJitSig
592 //---------------------------------------------------------------------------------------
594 CORINFO_CLASS_HANDLE CEEInfo::getTokenTypeAsHandle (CORINFO_RESOLVED_TOKEN * pResolvedToken)
603 CORINFO_CLASS_HANDLE tokenType = NULL;
605 JIT_TO_EE_TRANSITION();
607 _ASSERTE((pResolvedToken->hMethod == NULL) || (pResolvedToken->hField == NULL));
609 BinderClassID classID = CLASS__TYPE_HANDLE;
611 if (pResolvedToken->hMethod != NULL)
613 classID = CLASS__METHOD_HANDLE;
616 if (pResolvedToken->hField != NULL)
618 classID = CLASS__FIELD_HANDLE;
621 tokenType = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(classID));
623 EE_TO_JIT_TRANSITION();
628 /*********************************************************************/
629 size_t CEEInfo::findNameOfToken (
630 CORINFO_MODULE_HANDLE scopeHnd,
632 __out_ecount (FQNameCapacity) char * szFQName,
633 size_t FQNameCapacity)
644 JIT_TO_EE_TRANSITION();
646 if (IsDynamicScope(scopeHnd))
648 strncpy_s (szFQName, FQNameCapacity, "DynamicToken", FQNameCapacity - 1);
649 NameLen = strlen (szFQName);
653 Module* module = (Module *)scopeHnd;
654 NameLen = findNameOfToken(module, metaTOK, szFQName, FQNameCapacity);
657 EE_TO_JIT_TRANSITION();
662 CorInfoCanSkipVerificationResult CEEInfo::canSkipMethodVerification(CORINFO_METHOD_HANDLE ftnHnd)
671 return CORINFO_VERIFICATION_CAN_SKIP;
674 /*********************************************************************/
675 BOOL CEEInfo::shouldEnforceCallvirtRestriction(
676 CORINFO_MODULE_HANDLE scopeHnd)
678 LIMITED_METHOD_CONTRACT;
680 // verification rule added in whidbey requiring virtual methods
681 // to be called via callvirt except if certain other rules are
684 if (g_pConfig->LegacyVirtualMethodCallVerification())
691 #ifdef FEATURE_READYTORUN_COMPILER
693 // Returns true if assemblies are in the same version bubble
694 // Right now each assembly is in its own version bubble.
695 // If the need arises (i.e. performance issues) we will define sets of assemblies (e.g. all app assemblies)
696 // The main point is that all this logic is concentrated in one place.
698 // NOTICE: If you change this logic to allow multi-assembly version bubbles you
699 // need to consider the impact on diagnostic tools. Currently there is an inlining
700 // table which tracks inliner/inlinee relationships in R2R images but it is not
701 // yet capable of encoding cross-assembly inlines. The scenario where this
702 // may show are instrumenting profilers that want to instrument a given method A
703 // using the ReJit APIs. If method A happens to inlined within method B in another
704 // assembly then the profiler needs to know that so it can rejit B too.
705 // The recommended approach is to upgrade the inlining table (vm\inlinetracking.h\.cpp)
706 // now that presumably R2R images have some way to refer to methods in other
707 // assemblies in their version bubble. Chat with the diagnostics team if you need more
710 // There already is a case where cross-assembly inlining occurs in an
711 // unreported fashion for methods marked NonVersionable. There is a specific
712 // exemption called out for this on ICorProfilerInfo6::EnumNgenModuleMethodsInliningThisMethod
713 // and the impact of the cut was vetted with partners. It would not be appropriate
714 // to increase that unreported set without additional review.
717 bool IsInSameVersionBubble(Assembly * current, Assembly * target)
719 LIMITED_METHOD_CONTRACT;
721 // trivial case: current and target are identical
722 // DO NOT change this without reading the notice above
723 if (current == target)
729 // Returns true if the assemblies defining current and target are in the same version bubble
730 static bool IsInSameVersionBubble(MethodDesc* pCurMD, MethodDesc *pTargetMD)
732 LIMITED_METHOD_CONTRACT;
733 // DO NOT change this without reading the notice above
734 if (IsInSameVersionBubble(pCurMD->GetModule()->GetAssembly(),
735 pTargetMD->GetModule()->GetAssembly()))
739 if (IsReadyToRunCompilation())
741 if (pTargetMD->GetModule()->GetMDImport()->GetCustomAttributeByName(pTargetMD->GetMemberDef(),
742 NONVERSIONABLE_TYPE, NULL, NULL) == S_OK)
751 #endif // FEATURE_READYTORUN_COMPILER
754 /*********************************************************************/
755 CorInfoCanSkipVerificationResult CEEInfo::canSkipVerification(
756 CORINFO_MODULE_HANDLE moduleHnd)
765 return CORINFO_VERIFICATION_CAN_SKIP;
768 /*********************************************************************/
769 // Checks if the given metadata token is valid
770 BOOL CEEInfo::isValidToken (
771 CORINFO_MODULE_HANDLE module,
783 JIT_TO_EE_TRANSITION_LEAF();
785 if (IsDynamicScope(module))
787 // No explicit token validation for dynamic code. Validation is
788 // side-effect of token resolution.
793 result = ((Module *)module)->GetMDImport()->IsValidToken(metaTOK);
796 EE_TO_JIT_TRANSITION_LEAF();
801 /*********************************************************************/
802 // Checks if the given metadata token is valid StringRef
803 BOOL CEEInfo::isValidStringRef (
804 CORINFO_MODULE_HANDLE module,
816 JIT_TO_EE_TRANSITION();
818 if (IsDynamicScope(module))
820 result = GetDynamicResolver(module)->IsValidStringRef(metaTOK);
824 result = ((Module *)module)->CheckStringRef(metaTOK);
829 result = (!FAILED(((Module *)module)->GetMDImport()->GetUserString(metaTOK, &dwCharCount, NULL, &pString)) &&
834 EE_TO_JIT_TRANSITION();
840 size_t CEEInfo::findNameOfToken (Module* module,
842 __out_ecount (FQNameCapacity) char * szFQName,
843 size_t FQNameCapacity)
851 PCCOR_SIGNATURE sig = NULL;
853 LPCUTF8 pszNamespace = NULL;
854 LPCUTF8 pszClassName = NULL;
856 mdToken tokType = TypeFromToken(metaTOK);
861 if (FAILED(module->GetMDImport()->GetNameOfTypeRef(metaTOK, &pszNamespace, &pszClassName)))
863 pszNamespace = pszClassName = "Invalid TypeRef record";
865 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
870 if (FAILED(module->GetMDImport()->GetNameOfTypeDef(metaTOK, &pszClassName, &pszNamespace)))
872 pszClassName = pszNamespace = "Invalid TypeDef record";
874 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
880 if (FAILED(module->GetMDImport()->GetNameOfFieldDef(metaTOK, &szFieldName)))
882 szFieldName = "Invalid FieldDef record";
884 strncpy_s(szFQName, FQNameCapacity, (char*)szFieldName, FQNameCapacity - 1);
890 if (FAILED(module->GetMDImport()->GetNameOfMethodDef(metaTOK, &szMethodName)))
892 szMethodName = "Invalid MethodDef record";
894 strncpy_s(szFQName, FQNameCapacity, (char*)szMethodName, FQNameCapacity - 1);
900 if (FAILED(module->GetMDImport()->GetNameAndSigOfMemberRef((mdMemberRef)metaTOK, &sig, &cSig, &szName)))
902 szName = "Invalid MemberRef record";
904 strncpy_s(szFQName, FQNameCapacity, (char *)szName, FQNameCapacity - 1);
908 sprintf_s(szFQName, FQNameCapacity, "!TK_%x", metaTOK);
913 strncpy_s (szFQName, FQNameCapacity, "<UNKNOWN>", FQNameCapacity - 1);
917 return strlen (szFQName);
920 CorInfoHelpFunc CEEInfo::getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle)
929 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
931 JIT_TO_EE_TRANSITION_LEAF();
933 result = IsDynamicScope(handle) ? CORINFO_HELP_UNDEF : CORINFO_HELP_STRCNS;
935 EE_TO_JIT_TRANSITION_LEAF();
941 CHECK CheckContext(CORINFO_MODULE_HANDLE scopeHnd, CORINFO_CONTEXT_HANDLE context)
943 CHECK_MSG(scopeHnd != NULL, "Illegal null scope");
944 CHECK_MSG(((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK) != NULL, "Illegal null context");
945 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
947 TypeHandle handle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
948 CHECK_MSG(handle.GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
952 MethodDesc* handle = (MethodDesc*) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK);
953 CHECK_MSG(handle->GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
960 static DECLSPEC_NORETURN void ThrowBadTokenException(CORINFO_RESOLVED_TOKEN * pResolvedToken)
962 switch (pResolvedToken->tokenType & CORINFO_TOKENKIND_Mask)
964 case CORINFO_TOKENKIND_Class:
965 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_CLASS_TOKEN);
966 case CORINFO_TOKENKIND_Method:
967 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN);
968 case CORINFO_TOKENKIND_Field:
969 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN);
971 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
975 /*********************************************************************/
976 void CEEInfo::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken)
985 JIT_TO_EE_TRANSITION();
987 _ASSERTE(CheckContext(pResolvedToken->tokenScope, pResolvedToken->tokenContext));
989 pResolvedToken->pTypeSpec = NULL;
990 pResolvedToken->cbTypeSpec = NULL;
991 pResolvedToken->pMethodSpec = NULL;
992 pResolvedToken->cbMethodSpec = NULL;
995 MethodDesc * pMD = NULL;
996 FieldDesc * pFD = NULL;
998 CorInfoTokenKind tokenType = pResolvedToken->tokenType;
1000 if (IsDynamicScope(pResolvedToken->tokenScope))
1002 GetDynamicResolver(pResolvedToken->tokenScope)->ResolveToken(pResolvedToken->token, &th, &pMD, &pFD);
1005 // Check that we got the expected handles and fill in missing data if necessary
1008 CorTokenType tkType = (CorTokenType)TypeFromToken(pResolvedToken->token);
1012 if ((tkType != mdtMethodDef) && (tkType != mdtMemberRef))
1013 ThrowBadTokenException(pResolvedToken);
1014 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1015 ThrowBadTokenException(pResolvedToken);
1017 th = pMD->GetMethodTable();
1019 // "PermitUninstDefOrRef" check
1020 if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && pMD->ContainsGenericVariables())
1022 COMPlusThrow(kInvalidProgramException);
1025 // if this is a BoxedEntryPointStub get the UnboxedEntryPoint one
1026 if (pMD->IsUnboxingStub())
1028 pMD = pMD->GetMethodTable()->GetUnboxedEntryPointMD(pMD);
1031 // Activate target if required
1032 if (tokenType != CORINFO_TOKENKIND_Ldtoken)
1034 ScanTokenForDynamicScope(pResolvedToken, th, pMD);
1040 if ((tkType != mdtFieldDef) && (tkType != mdtMemberRef))
1041 ThrowBadTokenException(pResolvedToken);
1042 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1043 ThrowBadTokenException(pResolvedToken);
1045 th = pFD->GetApproxEnclosingMethodTable();
1047 if (pFD->IsStatic() && (tokenType != CORINFO_TOKENKIND_Ldtoken))
1049 ScanTokenForDynamicScope(pResolvedToken, th);
1054 if ((tkType != mdtTypeDef) && (tkType != mdtTypeRef))
1055 ThrowBadTokenException(pResolvedToken);
1056 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1057 ThrowBadTokenException(pResolvedToken);
1059 ThrowBadTokenException(pResolvedToken);
1061 if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained)
1063 ScanTokenForDynamicScope(pResolvedToken, th);
1067 _ASSERTE((pMD == NULL) || (pFD == NULL));
1068 _ASSERTE(!th.IsNull());
1070 // "PermitUninstDefOrRef" check
1071 if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && th.ContainsGenericVariables())
1073 COMPlusThrow(kInvalidProgramException);
1076 // The JIT always wants to see normalized typedescs for arrays
1077 if (!th.IsTypeDesc() && th.AsMethodTable()->IsArray())
1079 MethodTable * pMT = th.AsMethodTable();
1081 // Load the TypeDesc for the array type.
1082 DWORD rank = pMT->GetRank();
1083 TypeHandle elemType = pMT->GetApproxArrayElementTypeHandle();
1084 th = ClassLoader::LoadArrayTypeThrowing(elemType, pMT->GetInternalCorElementType(), rank);
1089 unsigned metaTOK = pResolvedToken->token;
1090 Module * pModule = (Module *)pResolvedToken->tokenScope;
1092 switch (TypeFromToken(metaTOK))
1095 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1096 ThrowBadTokenException(pResolvedToken);
1099 DomainFile *pTargetModule = pModule->LoadModule(GetAppDomain(), metaTOK, FALSE /* loadResources */);
1100 if (pTargetModule == NULL)
1101 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1102 th = TypeHandle(pTargetModule->GetModule()->GetGlobalMethodTable());
1104 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1110 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1111 ThrowBadTokenException(pResolvedToken);
1113 th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, metaTOK,
1114 ClassLoader::ThrowIfNotFound,
1115 (tokenType == CORINFO_TOKENKIND_Ldtoken) ?
1116 ClassLoader::PermitUninstDefOrRef : ClassLoader::FailIfUninstDefOrRef);
1121 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1122 ThrowBadTokenException(pResolvedToken);
1124 IfFailThrow(pModule->GetMDImport()->GetTypeSpecFromToken(metaTOK, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec));
1126 SigTypeContext typeContext;
1127 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1129 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1130 th = sigptr.GetTypeHandleThrowing(pModule, &typeContext);
1135 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1136 ThrowBadTokenException(pResolvedToken);
1138 pMD = MemberLoader::GetMethodDescFromMethodDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1140 th = pMD->GetMethodTable();
1144 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1145 ThrowBadTokenException(pResolvedToken);
1147 pFD = MemberLoader::GetFieldDescFromFieldDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1149 th = pFD->GetEnclosingMethodTable();
1154 SigTypeContext typeContext;
1155 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1157 MemberLoader::GetDescFromMemberRef(pModule, metaTOK, &pMD, &pFD, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken),
1158 &th, TRUE, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec);
1160 _ASSERTE((pMD != NULL) ^ (pFD != NULL));
1161 _ASSERTE(!th.IsNull());
1165 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1166 ThrowBadTokenException(pResolvedToken);
1170 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1171 ThrowBadTokenException(pResolvedToken);
1178 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1179 ThrowBadTokenException(pResolvedToken);
1181 SigTypeContext typeContext;
1182 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1184 // We need the method desc to carry exact instantiation, thus allowInstParam == FALSE.
1185 pMD = MemberLoader::GetMethodDescFromMethodSpec(pModule, metaTOK, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken), FALSE /* allowInstParam */,
1186 &th, TRUE, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec, &pResolvedToken->pMethodSpec, &pResolvedToken->cbMethodSpec);
1191 ThrowBadTokenException(pResolvedToken);
1195 // Module dependency tracking
1199 ScanToken(pModule, pResolvedToken, th, pMD);
1204 if (pFD->IsStatic())
1205 ScanToken(pModule, pResolvedToken, th);
1209 // It should not be required to trigger the modules cctors for ldtoken, it is done for backward compatibility only.
1210 if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained || tokenType == CORINFO_TOKENKIND_Ldtoken)
1211 ScanToken(pModule, pResolvedToken, th);
1216 // tokenType specific verification and transformations
1218 CorElementType et = th.GetInternalCorElementType();
1221 case CORINFO_TOKENKIND_Ldtoken:
1222 // Allow everything.
1225 case CORINFO_TOKENKIND_Newarr:
1226 // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1227 if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1228 COMPlusThrow(kInvalidProgramException);
1230 th = ClassLoader::LoadArrayTypeThrowing(th);
1234 // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1235 if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1236 COMPlusThrow(kInvalidProgramException);
1240 // The JIT interface should always return fully loaded types
1241 _ASSERTE(th.IsFullyLoaded());
1243 pResolvedToken->hClass = CORINFO_CLASS_HANDLE(th.AsPtr());
1244 pResolvedToken->hMethod = CORINFO_METHOD_HANDLE(pMD);
1245 pResolvedToken->hField = CORINFO_FIELD_HANDLE(pFD);
1247 EE_TO_JIT_TRANSITION();
1250 /*********************************************************************/
1251 struct TryResolveTokenFilterParam
1254 CORINFO_RESOLVED_TOKEN* m_resolvedToken;
1255 EXCEPTION_POINTERS m_exceptionPointers;
1259 bool isValidTokenForTryResolveToken(CEEInfo* info, CORINFO_RESOLVED_TOKEN* resolvedToken)
1268 if (!info->isValidToken(resolvedToken->tokenScope, resolvedToken->token))
1273 CorInfoTokenKind tokenType = resolvedToken->tokenType;
1274 switch (TypeFromToken(resolvedToken->token))
1280 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1286 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1291 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1296 if ((tokenType & (CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field)) == 0)
1307 LONG EEFilterException(struct _EXCEPTION_POINTERS* exceptionPointers, void* unused);
1309 LONG TryResolveTokenFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
1318 // Backward compatibility: Convert bad image format exceptions thrown while resolving tokens
1319 // to simple true/false successes. This is done for backward compatibility only. Ideally,
1320 // we would always treat bad tokens in the IL stream as fatal errors.
1321 if (exceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1323 auto* param = reinterpret_cast<TryResolveTokenFilterParam*>(theParam);
1324 if (!isValidTokenForTryResolveToken(param->m_this, param->m_resolvedToken))
1326 param->m_exceptionPointers = *exceptionPointers;
1327 return EEFilterException(exceptionPointers, nullptr);
1331 return EXCEPTION_CONTINUE_SEARCH;
1334 bool CEEInfo::tryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
1336 // No dynamic contract here because SEH is used
1337 STATIC_CONTRACT_SO_TOLERANT;
1338 STATIC_CONTRACT_THROWS;
1339 STATIC_CONTRACT_GC_TRIGGERS;
1340 STATIC_CONTRACT_MODE_PREEMPTIVE;
1342 TryResolveTokenFilterParam param;
1343 param.m_this = this;
1344 param.m_resolvedToken = resolvedToken;
1345 param.m_success = true;
1347 PAL_TRY(TryResolveTokenFilterParam*, pParam, ¶m)
1349 pParam->m_this->resolveToken(pParam->m_resolvedToken);
1351 PAL_EXCEPT_FILTER(TryResolveTokenFilter)
1353 if (param.m_exceptionPointers.ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1355 HandleException(¶m.m_exceptionPointers);
1358 param.m_success = false;
1362 return param.m_success;
1365 /*********************************************************************/
1366 // We have a few frequently used constants in mscorlib that are defined as
1367 // readonly static fields for historic reasons. Check for them here and
1368 // allow them to be treated as actual constants by the JIT.
1369 static CORINFO_FIELD_ACCESSOR getFieldIntrinsic(FieldDesc * field)
1371 STANDARD_VM_CONTRACT;
1373 if (MscorlibBinder::GetField(FIELD__STRING__EMPTY) == field)
1375 return CORINFO_FIELD_INTRINSIC_EMPTY_STRING;
1378 if ((MscorlibBinder::GetField(FIELD__INTPTR__ZERO) == field) ||
1379 (MscorlibBinder::GetField(FIELD__UINTPTR__ZERO) == field))
1381 return CORINFO_FIELD_INTRINSIC_ZERO;
1384 if (MscorlibBinder::GetField(FIELD__BITCONVERTER__ISLITTLEENDIAN) == field)
1386 return CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN;
1389 return (CORINFO_FIELD_ACCESSOR)-1;
1392 static CorInfoHelpFunc getGenericStaticsHelper(FieldDesc * pField)
1394 STANDARD_VM_CONTRACT;
1396 int helper = CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE;
1398 if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1399 pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1401 helper = CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1404 if (pField->IsThreadStatic())
1406 const int delta = CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1408 static_assert_no_msg(CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE
1409 == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE + delta);
1411 helper += (CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE);
1414 return (CorInfoHelpFunc)helper;
1417 CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable * pFieldMT)
1419 STANDARD_VM_CONTRACT;
1421 int helper = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
1423 if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1424 pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1426 helper = CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1429 if (pFieldMT->IsDynamicStatics())
1431 const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1433 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS
1434 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1439 if (!pFieldMT->HasClassConstructor() && !pFieldMT->HasBoxedRegularStatics())
1441 const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1443 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR
1444 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1449 if (pField->IsThreadStatic())
1451 const int delta = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1453 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE
1454 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1455 static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR
1456 == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR + delta);
1457 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR
1458 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR + delta);
1459 static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS
1460 == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS + delta);
1461 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS
1462 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS + delta);
1467 return (CorInfoHelpFunc)helper;
1470 static CorInfoHelpFunc getInstanceFieldHelper(FieldDesc * pField, CORINFO_ACCESS_FLAGS flags)
1472 STANDARD_VM_CONTRACT;
1476 CorElementType type = pField->GetFieldType();
1478 if (CorTypeInfo::IsObjRef(type))
1479 helper = CORINFO_HELP_GETFIELDOBJ;
1483 case ELEMENT_TYPE_VALUETYPE:
1484 helper = CORINFO_HELP_GETFIELDSTRUCT;
1486 case ELEMENT_TYPE_I1:
1487 case ELEMENT_TYPE_BOOLEAN:
1488 case ELEMENT_TYPE_U1:
1489 helper = CORINFO_HELP_GETFIELD8;
1491 case ELEMENT_TYPE_I2:
1492 case ELEMENT_TYPE_CHAR:
1493 case ELEMENT_TYPE_U2:
1494 helper = CORINFO_HELP_GETFIELD16;
1496 case ELEMENT_TYPE_I4:
1497 case ELEMENT_TYPE_U4:
1499 helper = CORINFO_HELP_GETFIELD32;
1501 case ELEMENT_TYPE_I8:
1502 case ELEMENT_TYPE_U8:
1504 helper = CORINFO_HELP_GETFIELD64;
1506 case ELEMENT_TYPE_R4:
1507 helper = CORINFO_HELP_GETFIELDFLOAT;
1509 case ELEMENT_TYPE_R8:
1510 helper = CORINFO_HELP_GETFIELDDOUBLE;
1514 if (flags & CORINFO_ACCESS_SET)
1516 const int delta = CORINFO_HELP_SETFIELDOBJ - CORINFO_HELP_GETFIELDOBJ;
1518 static_assert_no_msg(CORINFO_HELP_SETFIELD8 == CORINFO_HELP_GETFIELD8 + delta);
1519 static_assert_no_msg(CORINFO_HELP_SETFIELD16 == CORINFO_HELP_GETFIELD16 + delta);
1520 static_assert_no_msg(CORINFO_HELP_SETFIELD32 == CORINFO_HELP_GETFIELD32 + delta);
1521 static_assert_no_msg(CORINFO_HELP_SETFIELD64 == CORINFO_HELP_GETFIELD64 + delta);
1522 static_assert_no_msg(CORINFO_HELP_SETFIELDSTRUCT == CORINFO_HELP_GETFIELDSTRUCT + delta);
1523 static_assert_no_msg(CORINFO_HELP_SETFIELDFLOAT == CORINFO_HELP_GETFIELDFLOAT + delta);
1524 static_assert_no_msg(CORINFO_HELP_SETFIELDDOUBLE == CORINFO_HELP_GETFIELDDOUBLE + delta);
1529 return (CorInfoHelpFunc)helper;
1532 /*********************************************************************/
1533 void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken,
1534 CORINFO_METHOD_HANDLE callerHandle,
1535 CORINFO_ACCESS_FLAGS flags,
1536 CORINFO_FIELD_INFO *pResult
1546 JIT_TO_EE_TRANSITION();
1548 _ASSERTE((flags & (CORINFO_ACCESS_GET | CORINFO_ACCESS_SET | CORINFO_ACCESS_ADDRESS | CORINFO_ACCESS_INIT_ARRAY)) != 0);
1550 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
1552 FieldDesc * pField = (FieldDesc*)pResolvedToken->hField;
1553 MethodTable * pFieldMT = pField->GetApproxEnclosingMethodTable();
1555 // Helper to use if the field access requires it
1556 CORINFO_FIELD_ACCESSOR fieldAccessor = (CORINFO_FIELD_ACCESSOR)-1;
1557 DWORD fieldFlags = 0;
1559 pResult->offset = pField->GetOffset();
1560 if (pField->IsStatic())
1562 fieldFlags |= CORINFO_FLG_FIELD_STATIC;
1564 if (pField->IsRVA())
1566 fieldFlags |= CORINFO_FLG_FIELD_UNMANAGED;
1568 Module* module = pFieldMT->GetModule();
1569 if (module->IsRvaFieldTls(pResult->offset))
1571 fieldAccessor = CORINFO_FIELD_STATIC_TLS;
1573 // Provide helper to use if the JIT is not able to emit the TLS access
1575 pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR_TLS;
1577 pResult->offset = module->GetFieldTlsOffset(pResult->offset);
1581 fieldAccessor = CORINFO_FIELD_STATIC_RVA_ADDRESS;
1584 // We are not going through a helper. The constructor has to be triggered explicitly.
1585 if (!pFieldMT->IsClassPreInited())
1586 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1589 if (pField->IsContextStatic())
1591 fieldAccessor = CORINFO_FIELD_STATIC_ADDR_HELPER;
1593 pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR_CONTEXT;
1597 // Regular or thread static
1598 CORINFO_FIELD_ACCESSOR intrinsicAccessor;
1600 if (pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1601 fieldFlags |= CORINFO_FLG_FIELD_STATIC_IN_HEAP;
1603 if (pFieldMT->IsSharedByGenericInstantiations())
1605 fieldAccessor = CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER;
1607 pResult->helper = getGenericStaticsHelper(pField);
1610 if (pFieldMT->GetModule()->IsSystem() && (flags & CORINFO_ACCESS_GET) &&
1611 (intrinsicAccessor = getFieldIntrinsic(pField)) != (CORINFO_FIELD_ACCESSOR)-1)
1614 fieldAccessor = intrinsicAccessor;
1617 if (// Domain neutral access.
1618 m_pMethodBeingCompiled->IsDomainNeutral() || m_pMethodBeingCompiled->IsZapped() || IsCompilingForNGen() ||
1619 // Static fields are not pinned in collectible types. We will always access
1620 // them using a helper since the address cannot be embeded into the code.
1621 pFieldMT->Collectible() ||
1622 // We always treat accessing thread statics as if we are in domain neutral code.
1623 pField->IsThreadStatic()
1626 fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
1628 pResult->helper = getSharedStaticsHelper(pField, pFieldMT);
1632 fieldAccessor = CORINFO_FIELD_STATIC_ADDRESS;
1634 // We are not going through a helper. The constructor has to be triggered explicitly.
1635 if (!pFieldMT->IsClassPreInited())
1636 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1641 // Currently, we only this optimization for regular statics, but it
1642 // looks like it may be permissible to do this optimization for
1643 // thread statics as well.
1645 if ((flags & CORINFO_ACCESS_ADDRESS) &&
1646 !pField->IsThreadStatic() &&
1647 !pField->IsContextStatic() &&
1648 (fieldAccessor != CORINFO_FIELD_STATIC_TLS))
1650 fieldFlags |= CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN;
1655 BOOL fInstanceHelper = FALSE;
1657 #if CHECK_APP_DOMAIN_LEAKS
1658 if (g_pConfig->EnableFullDebug()
1659 && pField->IsDangerousAppDomainAgileField()
1660 && CorTypeInfo::IsObjRef(pField->GetFieldType()))
1663 // In a checked field with all checks turned on, we use a helper to enforce the app domain
1666 // <REVISIT_TODO>@todo: we'd like to check this for value type fields as well - we
1667 // just need to add some code to iterate through the fields for
1668 // references during the assignment.
1670 fInstanceHelper = TRUE;
1673 #endif // CHECK_APP_DOMAIN_LEAKS
1675 if (fInstanceHelper)
1677 if (flags & CORINFO_ACCESS_ADDRESS)
1679 fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1681 pResult->helper = CORINFO_HELP_GETFIELDADDR;
1685 fieldAccessor = CORINFO_FIELD_INSTANCE_HELPER;
1687 pResult->helper = getInstanceFieldHelper(pField, flags);
1691 if (pField->IsEnCNew())
1693 fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1695 pResult->helper = CORINFO_HELP_GETFIELDADDR;
1699 fieldAccessor = CORINFO_FIELD_INSTANCE;
1702 // FieldDesc::GetOffset() does not include the size of Object
1703 if (!pFieldMT->IsValueType())
1705 pResult->offset += sizeof(Object);
1709 // TODO: This is touching metadata. Can we avoid it?
1710 DWORD fieldAttribs = pField->GetAttributes();
1712 if (IsFdFamily(fieldAttribs))
1713 fieldFlags |= CORINFO_FLG_FIELD_PROTECTED;
1715 if (IsFdInitOnly(fieldAttribs))
1716 fieldFlags |= CORINFO_FLG_FIELD_FINAL;
1718 pResult->fieldAccessor = fieldAccessor;
1719 pResult->fieldFlags = fieldFlags;
1721 if (!(flags & CORINFO_ACCESS_INLINECHECK))
1723 //get the field's type. Grab the class for structs.
1724 pResult->fieldType = getFieldTypeInternal(pResolvedToken->hField, &pResult->structType, pResolvedToken->hClass);
1727 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
1730 //Since we can't get the special verify-only instantiated FD like we can with MDs, go back to the parent
1731 //of the memberRef and load that one. That should give us the open instantiation.
1733 //If the field we found is owned by a generic type, you have to go back to the signature and reload.
1734 //Otherwise we filled in !0.
1735 TypeHandle fieldTypeForSecurity = TypeHandle(pResolvedToken->hClass);
1736 if (pResolvedToken->pTypeSpec != NULL)
1738 SigTypeContext typeContext;
1739 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
1741 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1742 fieldTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
1744 // typeHnd can be a variable type
1745 if (fieldTypeForSecurity.GetMethodTable() == NULL)
1747 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
1751 BOOL doAccessCheck = TRUE;
1752 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
1754 DynamicResolver * pAccessContext = NULL;
1756 //More in code:CEEInfo::getCallInfo, but the short version is that the caller and callee Descs do
1757 //not completely describe the type.
1758 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
1759 if (IsDynamicScope(pResolvedToken->tokenScope))
1761 doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope), &callerTypeForSecurity,
1762 &accessCheckType, &pAccessContext);
1765 //Now for some link time checks.
1766 //Um... where are the field link demands?
1768 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
1772 //Well, let's check some visibility at least.
1773 AccessCheckOptions accessCheckOptions(accessCheckType,
1778 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
1779 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
1781 BOOL canAccess = ClassLoader::CanAccess(
1783 fieldTypeForSecurity.GetMethodTable(),
1784 fieldTypeForSecurity.GetAssembly(),
1787 (flags & CORINFO_ACCESS_INIT_ARRAY) ? NULL : pField, // For InitializeArray, we don't need tocheck the type of the field.
1788 accessCheckOptions);
1792 //Set up the throw helper
1793 pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL;
1795 pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_EXCEPTION;
1796 pResult->accessCalloutHelper.numArgs = 2;
1798 pResult->accessCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
1799 pResult->accessCalloutHelper.args[1].Set(CORINFO_FIELD_HANDLE(pField));
1801 if (IsCompilingForNGen())
1803 //see code:CEEInfo::getCallInfo for more information.
1804 if (pCallerForSecurity->ContainsGenericVariables())
1805 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
1810 CorInfoIsAccessAllowedResult isAccessAllowed = CORINFO_ACCESS_ALLOWED;
1811 CorInfoSecurityRuntimeChecks runtimeChecks = CORINFO_ACCESS_SECURITY_NONE;
1813 DebugSecurityCalloutStress(getMethodBeingCompiled(), isAccessAllowed, runtimeChecks);
1814 if (isAccessAllowed == CORINFO_ACCESS_RUNTIME_CHECK)
1816 pResult->accessAllowed = isAccessAllowed;
1817 //Explain the callback to the JIT.
1818 pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_CHECK;
1819 pResult->accessCalloutHelper.numArgs = 3;
1821 pResult->accessCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
1823 /* REVISIT_TODO Wed 4/8/2009
1824 * This field handle is not useful on its own. We also need to embed the enclosing class
1827 pResult->accessCalloutHelper.args[1].Set(CORINFO_FIELD_HANDLE(pField));
1829 pResult->accessCalloutHelper.args[2].Set(runtimeChecks);
1831 if (IsCompilingForNGen())
1833 //see code:CEEInfo::getCallInfo for more information.
1834 if (pCallerForSecurity->ContainsGenericVariables())
1835 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
1842 EE_TO_JIT_TRANSITION();
1845 //---------------------------------------------------------------------------------------
1847 bool CEEInfo::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd)
1857 JIT_TO_EE_TRANSITION_LEAF();
1858 FieldDesc* field = (FieldDesc*)fldHnd;
1859 res = (field->IsStatic() != 0);
1860 EE_TO_JIT_TRANSITION_LEAF();
1864 //---------------------------------------------------------------------------------------
1867 CEEInfo::findCallSiteSig(
1868 CORINFO_MODULE_HANDLE scopeHnd,
1869 unsigned sigMethTok,
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 DynamicResolver * pResolver = GetDynamicResolver(scopeHnd);
1890 if (TypeFromToken(sigMethTok) == mdtMemberRef)
1892 sig = pResolver->ResolveSignatureForVarArg(sigMethTok);
1896 _ASSERTE(TypeFromToken(sigMethTok) == mdtMethodDef);
1898 TypeHandle classHandle;
1899 MethodDesc * pMD = NULL;
1900 FieldDesc * pFD = NULL;
1902 // in this case a method is asked for its sig. Resolve the method token and get the sig
1903 pResolver->ResolveToken(sigMethTok, &classHandle, &pMD, &pFD);
1905 COMPlusThrow(kInvalidProgramException);
1907 PCCOR_SIGNATURE pSig = NULL;
1909 pMD->GetSig(&pSig, &cbSig);
1910 sig = SigPointer(pSig, cbSig);
1912 context = MAKE_METHODCONTEXT(pMD);
1913 scopeHnd = GetScopeHandle(pMD->GetModule());
1916 sig.GetSignature(&pSig, &cbSig);
1917 sigMethTok = mdTokenNil;
1921 Module * module = (Module *)scopeHnd;
1924 if (TypeFromToken(sigMethTok) == mdtMemberRef)
1926 IfFailThrow(module->GetMDImport()->GetNameAndSigOfMemberRef(sigMethTok, &pSig, &cbSig, &szName));
1928 else if (TypeFromToken(sigMethTok) == mdtMethodDef)
1930 IfFailThrow(module->GetMDImport()->GetSigOfMethodDef(sigMethTok, &cbSig, &pSig));
1934 CEEInfo::ConvToJitSig(
1940 GetMethodFromContext(context),
1942 GetTypeFromContext(context));
1943 EE_TO_JIT_TRANSITION();
1944 } // CEEInfo::findCallSiteSig
1946 //---------------------------------------------------------------------------------------
1950 CORINFO_MODULE_HANDLE scopeHnd,
1952 CORINFO_CONTEXT_HANDLE context,
1953 CORINFO_SIG_INFO * sigRet)
1962 JIT_TO_EE_TRANSITION();
1964 PCCOR_SIGNATURE pSig = NULL;
1967 if (IsDynamicScope(scopeHnd))
1969 SigPointer sig = GetDynamicResolver(scopeHnd)->ResolveSignature(sigTok);
1970 sig.GetSignature(&pSig, &cbSig);
1971 sigTok = mdTokenNil;
1975 Module * module = (Module *)scopeHnd;
1977 // We need to resolve this stand alone sig
1978 IfFailThrow(module->GetMDImport()->GetSigFromToken(
1979 (mdSignature)sigTok,
1984 CEEInfo::ConvToJitSig(
1990 GetMethodFromContext(context),
1992 GetTypeFromContext(context));
1994 EE_TO_JIT_TRANSITION();
1995 } // CEEInfo::findSig
1997 //---------------------------------------------------------------------------------------
2000 CEEInfo::getClassSize(
2001 CORINFO_CLASS_HANDLE clsHnd)
2010 unsigned result = 0;
2012 JIT_TO_EE_TRANSITION_LEAF();
2014 TypeHandle VMClsHnd(clsHnd);
2015 result = VMClsHnd.GetSize();
2017 EE_TO_JIT_TRANSITION_LEAF();
2022 unsigned CEEInfo::getClassAlignmentRequirement(CORINFO_CLASS_HANDLE type, BOOL fDoubleAlignHint)
2031 // Default alignment is sizeof(void*)
2032 unsigned result = sizeof(void*);
2034 JIT_TO_EE_TRANSITION_LEAF();
2036 TypeHandle clsHnd(type);
2038 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
2039 if (fDoubleAlignHint)
2041 MethodTable* pMT = clsHnd.GetMethodTable();
2044 // Return the size of the double align hint. Ignore the actual alignment info account
2045 // so that structs with 64-bit integer fields do not trigger double aligned frames on x86.
2046 if (pMT->GetClass()->IsAlign8Candidate())
2053 result = getClassAlignmentRequirementStatic(clsHnd);
2056 EE_TO_JIT_TRANSITION_LEAF();
2061 unsigned CEEInfo::getClassAlignmentRequirementStatic(TypeHandle clsHnd)
2063 LIMITED_METHOD_CONTRACT;
2065 // Default alignment is sizeof(void*)
2066 unsigned result = sizeof(void*);
2068 MethodTable * pMT = clsHnd.GetMethodTable();
2072 if (pMT->HasLayout())
2074 EEClassLayoutInfo* pInfo = pMT->GetLayoutInfo();
2076 if (clsHnd.IsNativeValueType())
2078 // if it's the unmanaged view of the managed type, we always use the unmanaged alignment requirement
2079 result = pInfo->m_LargestAlignmentRequirementOfAllMembers;
2082 if (pInfo->IsManagedSequential())
2084 _ASSERTE(!pMT->ContainsPointers());
2086 // if it's managed sequential, we use the managed alignment requirement
2087 result = pInfo->m_ManagedLargestAlignmentRequirementOfAllMembers;
2089 else if (pInfo->IsBlittable())
2091 _ASSERTE(!pMT->ContainsPointers());
2093 // if it's blittable, we use the unmanaged alignment requirement
2094 result = pInfo->m_LargestAlignmentRequirementOfAllMembers;
2098 #ifdef FEATURE_64BIT_ALIGNMENT
2099 if (result < 8 && pMT->RequiresAlign8())
2101 // If the structure contains 64-bit primitive fields and the platform requires 8-byte alignment for
2102 // such fields then make sure we return at least 8-byte alignment. Note that it's technically possible
2103 // to create unmanaged APIs that take unaligned structures containing such fields and this
2104 // unconditional alignment bump would cause us to get the calling convention wrong on platforms such
2105 // as ARM. If we see such cases in the future we'd need to add another control (such as an alignment
2106 // property for the StructLayout attribute or a marshaling directive attribute for p/invoke arguments)
2107 // that allows more precise control. For now we'll go with the likely scenario.
2110 #endif // FEATURE_64BIT_ALIGNMENT
2115 CORINFO_FIELD_HANDLE
2116 CEEInfo::getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num)
2125 CORINFO_FIELD_HANDLE result = NULL;
2127 JIT_TO_EE_TRANSITION_LEAF();
2129 TypeHandle VMClsHnd(clsHnd);
2131 MethodTable* pMT= VMClsHnd.AsMethodTable();
2133 result = (CORINFO_FIELD_HANDLE) ((pMT->GetApproxFieldDescListRaw()) + num);
2135 EE_TO_JIT_TRANSITION_LEAF();
2141 CEEInfo::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod)
2150 mdMethodDef result = 0;
2152 JIT_TO_EE_TRANSITION_LEAF();
2154 MethodDesc* pMD = GetMethod(hMethod);
2156 if (pMD->IsDynamicMethod())
2158 // Dynamic methods do not have tokens
2159 result = mdMethodDefNil;
2163 result = pMD->GetMemberDef();
2166 EE_TO_JIT_TRANSITION_LEAF();
2171 BOOL CEEInfo::checkMethodModifier(CORINFO_METHOD_HANDLE hMethod,
2182 BOOL result = FALSE;
2184 JIT_TO_EE_TRANSITION();
2186 MethodDesc* pMD = GetMethod(hMethod);
2187 Module* pModule = pMD->GetModule();
2189 CorElementType eeType = fOptional ? ELEMENT_TYPE_CMOD_OPT : ELEMENT_TYPE_CMOD_REQD;
2191 // modopts/modreqs for the method are by convention stored on the return type
2192 result = sig.GetReturnProps().HasCustomModifier(pModule, modifier, eeType);
2194 EE_TO_JIT_TRANSITION();
2199 /*********************************************************************/
2200 static unsigned ComputeGCLayout(MethodTable * pMT, BYTE* gcPtrs)
2202 STANDARD_VM_CONTRACT;
2204 unsigned result = 0;
2206 _ASSERTE(pMT->IsValueType());
2208 // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in which
2209 // case the check for g_TypedReferenceMT below would not be necessary
2210 if (pMT == g_TypedReferenceMT || pMT->HasSameTypeDefAs(g_pByReferenceClass))
2212 if (gcPtrs[0] == TYPE_GC_NONE)
2214 gcPtrs[0] = TYPE_GC_BYREF;
2217 else if (gcPtrs[0] != TYPE_GC_BYREF)
2219 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2224 ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
2225 for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
2227 int fieldStartIndex = pFD->GetOffset() / sizeof(void*);
2229 if (pFD->GetFieldType() != ELEMENT_TYPE_VALUETYPE)
2231 if (pFD->IsObjRef())
2233 if (gcPtrs[fieldStartIndex] == TYPE_GC_NONE)
2235 gcPtrs[fieldStartIndex] = TYPE_GC_REF;
2238 else if (gcPtrs[fieldStartIndex] != TYPE_GC_REF)
2240 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2246 MethodTable * pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
2247 result += ComputeGCLayout(pFieldMT, gcPtrs + fieldStartIndex);
2253 unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
2262 unsigned result = 0;
2264 JIT_TO_EE_TRANSITION();
2266 TypeHandle VMClsHnd(clsHnd);
2268 MethodTable* pMT = VMClsHnd.GetMethodTable();
2270 if (pMT->IsByRefLike())
2272 // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in
2273 // which case the check for g_TypedReferenceMT below would not be necessary
2274 if (pMT == g_TypedReferenceMT)
2276 gcPtrs[0] = TYPE_GC_BYREF;
2277 gcPtrs[1] = TYPE_GC_NONE;
2282 memset(gcPtrs, TYPE_GC_NONE,
2283 (VMClsHnd.GetSize() + sizeof(void*) - 1) / sizeof(void*));
2284 // Note: This case is more complicated than the TypedReference case
2285 // due to ByRefLike structs being included as fields in other value
2286 // types (TypedReference can not be.)
2287 result = ComputeGCLayout(VMClsHnd.AsMethodTable(), gcPtrs);
2290 else if (VMClsHnd.IsNativeValueType())
2292 // native value types have no GC pointers
2294 memset(gcPtrs, TYPE_GC_NONE,
2295 (VMClsHnd.GetSize() + sizeof(void*) -1)/ sizeof(void*));
2299 _ASSERTE(pMT->IsValueType());
2300 _ASSERTE(sizeof(BYTE) == 1);
2302 // assume no GC pointers at first
2304 memset(gcPtrs, TYPE_GC_NONE,
2305 (VMClsHnd.GetSize() + sizeof(void*) -1)/ sizeof(void*));
2307 // walk the GC descriptors, turning on the correct bits
2308 if (pMT->ContainsPointers())
2310 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
2311 CGCDescSeries * pByValueSeries = map->GetLowestSeries();
2313 for (SIZE_T i = 0; i < map->GetNumSeries(); i++)
2315 // Get offset into the value class of the first pointer field (includes a +Object)
2316 size_t cbSeriesSize = pByValueSeries->GetSeriesSize() + pMT->GetBaseSize();
2317 size_t cbOffset = pByValueSeries->GetSeriesOffset() - sizeof(Object);
2319 _ASSERTE (cbOffset % sizeof(void*) == 0);
2320 _ASSERTE (cbSeriesSize % sizeof(void*) == 0);
2322 result += (unsigned) (cbSeriesSize / sizeof(void*));
2323 memset(&gcPtrs[cbOffset/sizeof(void*)], TYPE_GC_REF, cbSeriesSize / sizeof(void*));
2330 EE_TO_JIT_TRANSITION();
2335 // returns the enregister info for a struct based on type of fields, alignment, etc.
2336 bool CEEInfo::getSystemVAmd64PassStructInRegisterDescriptor(
2337 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
2338 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
2347 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
2348 JIT_TO_EE_TRANSITION();
2350 _ASSERTE(structPassInRegDescPtr != nullptr);
2351 TypeHandle th(structHnd);
2353 structPassInRegDescPtr->passedInRegisters = false;
2355 // Make sure this is a value type.
2356 if (th.IsValueType())
2358 _ASSERTE((CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeStruct) ||
2359 (CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeTypedReference));
2361 // The useNativeLayout in this case tracks whether the classification
2362 // is for a native layout of the struct or not.
2363 // If the struct has special marshaling it has a native layout.
2364 // In such cases the classifier needs to use the native layout.
2365 // For structs with no native layout, the managed layout should be used
2366 // even if classified for the purposes of marshaling/PInvoke passing.
2367 bool useNativeLayout = false;
2368 MethodTable* methodTablePtr = nullptr;
2369 if (!th.IsTypeDesc())
2371 methodTablePtr = th.AsMethodTable();
2375 _ASSERTE(th.IsNativeValueType());
2377 useNativeLayout = true;
2378 methodTablePtr = th.AsNativeValueType();
2380 _ASSERTE(methodTablePtr != nullptr);
2382 // If we have full support for FEATURE_UNIX_AMD64_STRUCT_PASSING, and not just the interface,
2383 // then we've cached whether this is a reg passed struct in the MethodTable, computed during
2384 // MethodTable construction. Otherwise, we are just building in the interface, and we haven't
2385 // computed or cached anything, so we need to compute it now.
2386 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2387 bool canPassInRegisters = useNativeLayout ? methodTablePtr->GetLayoutInfo()->IsNativeStructPassedInRegisters()
2388 : methodTablePtr->IsRegPassedStruct();
2389 #else // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2390 SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2391 bool canPassInRegisters = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2392 #endif // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2394 if (canPassInRegisters)
2396 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
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 // FEATURE_UNIX_AMD64_STRUCT_PASSING
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(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
2425 #endif // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_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 algoritm (scan the parent type chain and instantiation variables) is more than enough to maintain this invariant.
2877 // One could come up with a more efficient algorithm that still maintains the invariant, but it may introduce backward compatibility
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 #if defined(_TARGET_ARM_)
3136 ThrowHR(E_NOTIMPL); /* TODO - NYI */
3138 pResultLookup->lookupKind.runtimeLookupArgs = NULL;
3142 case DeclaringTypeHandleSlot:
3143 _ASSERTE(pTemplateMD != NULL);
3144 pResultLookup->lookupKind.runtimeLookupArgs = pTemplateMD->GetMethodTable();
3145 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_DeclaringTypeHandle;
3148 case TypeHandleSlot:
3149 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_TypeHandle;
3152 case MethodDescSlot:
3153 case MethodEntrySlot:
3154 case ConstrainedMethodEntrySlot:
3155 case DispatchStubAddrSlot:
3157 if (pTemplateMD != (MethodDesc*)pResolvedToken->hMethod)
3160 if (entryKind == MethodDescSlot)
3161 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_MethodHandle;
3162 else if (entryKind == MethodEntrySlot || entryKind == ConstrainedMethodEntrySlot)
3163 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_MethodEntry;
3165 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_VirtualEntry;
3167 pResultLookup->lookupKind.runtimeLookupArgs = pConstrainedResolvedToken;
3173 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_FieldHandle;
3177 _ASSERTE(!"Unknown dictionary entry kind!");
3178 IfFailThrow(E_FAIL);
3181 // For R2R compilations, we don't generate the dictionary lookup signatures (dictionary lookups are done in a
3182 // different way that is more version resilient... plus we can't have pointers to existing MTs/MDs in the sigs)
3186 // If we've got a method type parameter of any kind then we must look in the method desc arg
3187 if (pContextMD->RequiresInstMethodDescArg())
3189 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG : CORINFO_HELP_RUNTIMEHANDLE_METHOD;
3195 // (1) Naked method type variable: look up directly in instantiation hanging off runtime md
3196 // (2) Reference to method-spec of current method (e.g. a recursive call) i.e. currentmeth<!0,...,!(n-1)>
3197 if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3199 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3200 CorElementType type;
3201 IfFailThrow(sigptr.GetElemType(&type));
3202 if (type == ELEMENT_TYPE_MVAR)
3204 pResult->indirections = 2;
3205 pResult->testForNull = 0;
3206 #ifdef FEATURE_PREJIT
3207 pResult->testForFixup = 1;
3209 pResult->testForFixup = 0;
3211 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3213 if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
3215 pResult->indirectFirstOffset = 1;
3219 IfFailThrow(sigptr.GetData(&data));
3220 pResult->offsets[1] = sizeof(TypeHandle) * data;
3225 else if (entryKind == MethodDescSlot)
3227 // It's the context itself (i.e. a recursive call)
3228 if (!pTemplateMD->HasSameMethodDefAs(pContextMD))
3231 // Now just check that the instantiation is (!!0, ..., !!(n-1))
3232 if (!IsMethodSpecForTypicalInstantation(SigPointer(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)))
3235 // Type instantiation has to match too if there is one
3236 if (pContextMT->HasInstantiation())
3238 TypeHandle thTemplate(pResolvedToken->hClass);
3240 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3243 // This check filters out method instantiation on generic type definition, like G::M<!!0>()
3244 // We may not ever get it here. Filter it out just to be sure...
3245 if (pResolvedToken->pTypeSpec == NULL)
3248 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3252 // Just use the method descriptor that was passed in!
3253 pResult->indirections = 0;
3254 pResult->testForNull = 0;
3255 pResult->testForFixup = 0;
3260 // Otherwise we must just have class type variables
3263 _ASSERTE(pContextMT->GetNumGenericArgs() > 0);
3265 if (pContextMD->RequiresInstMethodTableArg())
3267 // If we've got a vtable extra argument, go through that
3268 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3270 // If we've got an object, go through its vtable
3273 _ASSERTE(pContextMD->AcquiresInstMethodTableFromThis());
3274 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3281 // (1) Naked class type variable: look up directly in instantiation hanging off vtable
3282 // (2) C<!0,...,!(n-1)> where C is the context's class and C is sealed: just return vtable ptr
3283 if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3285 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3286 CorElementType type;
3287 IfFailThrow(sigptr.GetElemType(&type));
3288 if (type == ELEMENT_TYPE_VAR)
3290 pResult->indirections = 3;
3291 pResult->testForNull = 0;
3292 #ifdef FEATURE_PREJIT
3293 pResult->testForFixup = 1;
3295 pResult->testForFixup = 0;
3297 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3298 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3300 IfFailThrow(sigptr.GetData(&data));
3301 pResult->offsets[2] = sizeof(TypeHandle) * data;
3303 if (MethodTable::IsPerInstInfoRelative())
3305 pResult->indirectFirstOffset = 1;
3306 pResult->indirectSecondOffset = 1;
3311 else if (type == ELEMENT_TYPE_GENERICINST &&
3312 (pContextMT->IsSealed() || pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM))
3314 TypeHandle thTemplate(pResolvedToken->hClass);
3316 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3319 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3322 // Just use the vtable pointer itself!
3323 pResult->indirections = 0;
3324 pResult->testForNull = 0;
3325 pResult->testForFixup = 0;
3334 SigBuilder sigBuilder;
3336 sigBuilder.AppendData(entryKind);
3338 if (pResultLookup->lookupKind.runtimeLookupKind != CORINFO_LOOKUP_METHODPARAM)
3340 _ASSERTE(pContextMT->GetNumDicts() > 0);
3341 sigBuilder.AppendData(pContextMT->GetNumDicts() - 1);
3344 Module * pModule = (Module *)pResolvedToken->tokenScope;
3348 case DeclaringTypeHandleSlot:
3349 _ASSERTE(pTemplateMD != NULL);
3350 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3351 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3354 case TypeHandleSlot:
3356 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
3358 if (!IsReadyToRunCompilation())
3360 sigBuilder.AppendElementType((CorElementType)ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
3363 sigBuilder.AppendElementType(ELEMENT_TYPE_SZARRAY);
3366 // Note that we can come here with pResolvedToken->pTypeSpec == NULL for invalid IL that
3367 // directly references __Canon
3368 if (pResolvedToken->pTypeSpec != NULL)
3370 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3371 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3375 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3376 sigBuilder.AppendPointer(pResolvedToken->hClass);
3381 case ConstrainedMethodEntrySlot:
3382 // Encode constrained type token
3383 if (pConstrainedResolvedToken->pTypeSpec != NULL)
3385 SigPointer sigptr(pConstrainedResolvedToken->pTypeSpec, pConstrainedResolvedToken->cbTypeSpec);
3386 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3390 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3391 sigBuilder.AppendPointer(pConstrainedResolvedToken->hClass);
3395 case MethodDescSlot:
3396 case MethodEntrySlot:
3397 case DispatchStubAddrSlot:
3399 // Encode containing type
3400 if (pResolvedToken->pTypeSpec != NULL)
3402 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3403 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3407 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3408 sigBuilder.AppendPointer(pResolvedToken->hClass);
3412 _ASSERTE(pTemplateMD != NULL);
3414 mdMethodDef methodToken = pTemplateMD->GetMemberDef_NoLogging();
3415 DWORD methodFlags = 0;
3417 // Check for non-NULL method spec first. We can encode the method instantiation only if we have one in method spec to start with. Note that there are weird cases
3418 // like instantiating stub for generic method definition that do not have method spec but that won't be caught by the later conditions either.
3419 BOOL fMethodNeedsInstantiation = (pResolvedToken->pMethodSpec != NULL) && pTemplateMD->HasMethodInstantiation() && !pTemplateMD->IsGenericMethodDefinition();
3421 if (pTemplateMD->IsUnboxingStub())
3422 methodFlags |= ENCODE_METHOD_SIG_UnboxingStub;
3423 // Always create instantiating stub for method entry points even if the template does not ask for it. It saves caller
3424 // from creating throw-away instantiating stub.
3425 if (pTemplateMD->IsInstantiatingStub() || (entryKind == MethodEntrySlot))
3426 methodFlags |= ENCODE_METHOD_SIG_InstantiatingStub;
3427 if (fMethodNeedsInstantiation)
3428 methodFlags |= ENCODE_METHOD_SIG_MethodInstantiation;
3429 if (IsNilToken(methodToken))
3431 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3434 if (entryKind == DispatchStubAddrSlot && pTemplateMD->IsVtableMethod())
3436 // Encode the method for dispatch stub using slot to avoid touching the interface method MethodDesc at runtime
3438 // There should be no other flags set if we are encoding the method using slot for virtual stub dispatch
3439 _ASSERTE(methodFlags == 0);
3441 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3444 if (!pTemplateMD->GetModule()->IsInCurrentVersionBubble())
3446 // Using a method defined in another version bubble. We can assume the slot number is stable only for real interface methods.
3447 if (!pTemplateMD->GetMethodTable()->IsInterface() || pTemplateMD->IsStatic() || pTemplateMD->HasMethodInstantiation())
3449 _ASSERTE(!"References to non-interface methods not yet supported in version resilient images");
3450 IfFailThrow(E_FAIL);
3452 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3455 sigBuilder.AppendData(methodFlags);
3457 if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
3459 // Encode method token and its module context (as method's type)
3460 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3461 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3463 sigBuilder.AppendData(RidFromToken(methodToken));
3467 sigBuilder.AppendData(pTemplateMD->GetSlot());
3470 if (fMethodNeedsInstantiation)
3472 SigPointer sigptr(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
3475 IfFailThrow(sigptr.GetByte(&etype));
3477 // Load the generic method instantiation
3478 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, pModule);
3480 DWORD nGenericMethodArgs;
3481 IfFailThrow(sigptr.GetData(&nGenericMethodArgs));
3482 sigBuilder.AppendData(nGenericMethodArgs);
3484 _ASSERTE(nGenericMethodArgs == pTemplateMD->GetNumGenericMethodArgs());
3486 for (DWORD i = 0; i < nGenericMethodArgs; i++)
3488 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3496 if (pResolvedToken->pTypeSpec != NULL)
3498 // Encode containing type
3499 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3500 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3504 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3505 sigBuilder.AppendPointer(pResolvedToken->hClass);
3508 FieldDesc * pField = (FieldDesc *)pResolvedToken->hField;
3509 _ASSERTE(pField != NULL);
3511 DWORD fieldIndex = pField->GetApproxEnclosingMethodTable()->GetIndexForFieldDesc(pField);
3512 sigBuilder.AppendData(fieldIndex);
3520 DictionaryEntrySignatureSource signatureSource = (IsCompilationProcess() ? FromZapImage : FromJIT);
3522 // It's a method dictionary lookup
3523 if (pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM)
3525 _ASSERTE(pContextMD != NULL);
3526 _ASSERTE(pContextMD->HasMethodInstantiation());
3528 if (DictionaryLayout::FindToken(pContextMD->GetLoaderAllocator(), pContextMD->GetNumGenericMethodArgs(), pContextMD->GetDictionaryLayout(), pResult, &sigBuilder, 1, signatureSource))
3530 pResult->testForNull = 1;
3531 pResult->testForFixup = 0;
3533 // Indirect through dictionary table pointer in InstantiatedMethodDesc
3534 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3536 if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
3538 pResult->indirectFirstOffset = 1;
3543 // It's a class dictionary lookup (CORINFO_LOOKUP_CLASSPARAM or CORINFO_LOOKUP_THISOBJ)
3546 if (DictionaryLayout::FindToken(pContextMT->GetLoaderAllocator(), pContextMT->GetNumGenericArgs(), pContextMT->GetClass()->GetDictionaryLayout(), pResult, &sigBuilder, 2, signatureSource))
3548 pResult->testForNull = 1;
3549 pResult->testForFixup = 0;
3551 // Indirect through dictionary table pointer in vtable
3552 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3554 // Next indirect through the dictionary appropriate to this instantiated type
3555 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3557 if (MethodTable::IsPerInstInfoRelative())
3559 pResult->indirectFirstOffset = 1;
3560 pResult->indirectSecondOffset = 1;
3568 /*********************************************************************/
3569 const char* CEEInfo::getClassName (CORINFO_CLASS_HANDLE clsHnd)
3578 const char* result = NULL;
3580 JIT_TO_EE_TRANSITION();
3582 TypeHandle VMClsHnd(clsHnd);
3583 MethodTable* pMT = VMClsHnd.GetMethodTable();
3591 result = pMT->GetDebugClassName();
3593 // since this is for diagnostic purposes only,
3594 // give up on the namespace, as we don't have a buffer to concat it
3595 // also note this won't show array class names.
3597 result = pMT->GetFullyQualifiedNameInfo(&nameSpace);
3601 EE_TO_JIT_TRANSITION();
3606 /***********************************************************************/
3607 const char* CEEInfo::getHelperName (CorInfoHelpFunc ftnNum)
3614 PRECONDITION(ftnNum >= 0 && ftnNum < CORINFO_HELP_COUNT);
3617 const char* result = NULL;
3619 JIT_TO_EE_TRANSITION_LEAF();
3621 #ifdef CROSSGEN_COMPILE
3622 result = hlpNameTable[ftnNum];
3625 result = hlpFuncTable[ftnNum].name;
3627 result = "AnyJITHelper";
3631 EE_TO_JIT_TRANSITION_LEAF();
3637 /*********************************************************************/
3638 int CEEInfo::appendClassName(__deref_inout_ecount(*pnBufLen) WCHAR** ppBuf,
3640 CORINFO_CLASS_HANDLE clsHnd,
3654 JIT_TO_EE_TRANSITION();
3656 TypeHandle th(clsHnd);
3658 TypeString::AppendType(ss,th,
3659 (fNamespace ? TypeString::FormatNamespace : 0) |
3660 (fFullInst ? TypeString::FormatFullInst : 0) |
3661 (fAssembly ? TypeString::FormatAssembly : 0));
3662 const WCHAR* szString = ss.GetUnicode();
3663 nLen = (int)wcslen(szString);
3666 wcscpy_s(*ppBuf, *pnBufLen, szString );
3667 (*ppBuf)[(*pnBufLen) - 1] = W('\0');
3669 (*pnBufLen) -= nLen;
3672 EE_TO_JIT_TRANSITION();
3677 /*********************************************************************/
3678 CORINFO_MODULE_HANDLE CEEInfo::getClassModule(CORINFO_CLASS_HANDLE clsHnd)
3687 CORINFO_MODULE_HANDLE result = NULL;
3689 JIT_TO_EE_TRANSITION_LEAF();
3691 TypeHandle VMClsHnd(clsHnd);
3693 result = CORINFO_MODULE_HANDLE(VMClsHnd.GetModule());
3695 EE_TO_JIT_TRANSITION_LEAF();
3700 /*********************************************************************/
3701 CORINFO_ASSEMBLY_HANDLE CEEInfo::getModuleAssembly(CORINFO_MODULE_HANDLE modHnd)
3710 CORINFO_ASSEMBLY_HANDLE result = NULL;
3712 JIT_TO_EE_TRANSITION_LEAF();
3714 result = CORINFO_ASSEMBLY_HANDLE(GetModule(modHnd)->GetAssembly());
3716 EE_TO_JIT_TRANSITION_LEAF();
3721 /*********************************************************************/
3722 const char* CEEInfo::getAssemblyName(CORINFO_ASSEMBLY_HANDLE asmHnd)
3731 const char* result = NULL;
3733 JIT_TO_EE_TRANSITION();
3734 result = ((Assembly*)asmHnd)->GetSimpleName();
3735 EE_TO_JIT_TRANSITION();
3740 /*********************************************************************/
3741 void* CEEInfo::LongLifetimeMalloc(size_t sz)
3750 void* result = NULL;
3752 JIT_TO_EE_TRANSITION_LEAF();
3753 result = new (nothrow) char[sz];
3754 EE_TO_JIT_TRANSITION_LEAF();
3759 /*********************************************************************/
3760 void CEEInfo::LongLifetimeFree(void* obj)
3769 JIT_TO_EE_TRANSITION_LEAF();
3770 (operator delete)(obj);
3771 EE_TO_JIT_TRANSITION_LEAF();
3774 /*********************************************************************/
3775 size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_MODULE_HANDLE *pModuleHandle, void **ppIndirection)
3786 JIT_TO_EE_TRANSITION_LEAF();
3788 TypeHandle VMClsHnd(clsHnd);
3789 Module *pModule = VMClsHnd.AsMethodTable()->GetModuleForStatics();
3791 if (ppIndirection != NULL)
3792 *ppIndirection = NULL;
3794 // The zapper needs the module handle. The jit should not use it at all.
3796 *pModuleHandle = CORINFO_MODULE_HANDLE(pModule);
3798 result = pModule->GetModuleID();
3802 EE_TO_JIT_TRANSITION_LEAF();
3807 /*********************************************************************/
3808 BOOL CEEInfo::isValueClass(CORINFO_CLASS_HANDLE clsHnd)
3819 JIT_TO_EE_TRANSITION_LEAF();
3823 // Note that clsHnd.IsValueType() would not return what the JIT expects
3824 // for corner cases like ELEMENT_TYPE_FNPTR
3825 TypeHandle VMClsHnd(clsHnd);
3826 MethodTable * pMT = VMClsHnd.GetMethodTable();
3827 ret = (pMT != NULL) ? pMT->IsValueType() : 0;
3829 EE_TO_JIT_TRANSITION_LEAF();
3834 /*********************************************************************/
3835 // If this method returns true, JIT will do optimization to inline the check for
3836 // GetClassFromHandle(handle) == obj.GetType()
3838 // This will enable to use directly the typehandle instead of going through getClassByHandle
3839 BOOL CEEInfo::canInlineTypeCheckWithObjectVTable (CORINFO_CLASS_HANDLE clsHnd)
3850 JIT_TO_EE_TRANSITION_LEAF();
3854 TypeHandle VMClsHnd(clsHnd);
3856 if (VMClsHnd.IsTypeDesc())
3858 // We can't do this optimization for arrays because of the object methodtable is template methodtable
3862 if (VMClsHnd.AsMethodTable()->IsMarshaledByRef())
3864 // We can't do this optimization for marshalbyrefs because of the object methodtable can be transparent proxy
3868 if (VMClsHnd.AsMethodTable()->IsInterface())
3870 // Object.GetType() should not ever return interface. However, WCF custom remoting proxy does it. Disable this
3871 // optimization for interfaces so that (autogenerated) code that compares Object.GetType() with interface type works
3872 // as expected for WCF custom remoting proxy. Note that this optimization is still not going to work well for custom
3873 // remoting proxies that are even more broken than the WCF one, e.g. returning random non-marshalbyref types
3874 // from Object.GetType().
3878 if (VMClsHnd == TypeHandle(g_pCanonMethodTableClass))
3880 // We can't do this optimization in shared generics code because of we do not know what the actual type is going to be.
3881 // (It can be array, marshalbyref, etc.)
3886 // It is safe to perform this optimization
3890 EE_TO_JIT_TRANSITION_LEAF();
3895 /*********************************************************************/
3896 DWORD CEEInfo::getClassAttribs (CORINFO_CLASS_HANDLE clsHnd)
3905 // <REVISIT_TODO>@todo FIX need to really fetch the class atributes. at present
3906 // we don't need to because the JIT only cares in the case of COM classes</REVISIT_TODO>
3909 JIT_TO_EE_TRANSITION();
3911 ret = getClassAttribsInternal(clsHnd);
3913 EE_TO_JIT_TRANSITION();
3919 /*********************************************************************/
3920 BOOL CEEInfo::isStructRequiringStackAllocRetBuf(CORINFO_CLASS_HANDLE clsHnd)
3931 JIT_TO_EE_TRANSITION_LEAF();
3933 TypeHandle VMClsHnd(clsHnd);
3934 MethodTable * pMT = VMClsHnd.GetMethodTable();
3935 ret = (pMT != NULL && pMT->IsStructRequiringStackAllocRetBuf());
3937 EE_TO_JIT_TRANSITION_LEAF();
3942 /*********************************************************************/
3943 DWORD CEEInfo::getClassAttribsInternal (CORINFO_CLASS_HANDLE clsHnd)
3945 STANDARD_VM_CONTRACT;
3951 TypeHandle VMClsHnd(clsHnd);
3953 // Byrefs should only occur in method and local signatures, which are accessed
3954 // using ICorClassInfo and ICorClassInfo.getChildType.
3955 // So getClassAttribs() should not be called for byrefs
3957 if (VMClsHnd.IsByRef())
3959 _ASSERTE(!"Did findClass() return a Byref?");
3960 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3962 else if (VMClsHnd.IsGenericVariable())
3964 //@GENERICSVER: for now, type variables simply report "variable".
3965 ret |= CORINFO_FLG_GENERIC_TYPE_VARIABLE;
3969 MethodTable *pMT = VMClsHnd.GetMethodTable();
3973 _ASSERTE(!"Did findClass() return a Byref?");
3974 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3977 EEClass * pClass = pMT->GetClass();
3979 // The array flag is used to identify the faked-up methods on
3980 // array types, i.e. .ctor, Get, Set and Address
3982 ret |= CORINFO_FLG_ARRAY;
3984 if (pMT->IsInterface())
3985 ret |= CORINFO_FLG_INTERFACE;
3987 if (pMT->HasComponentSize())
3988 ret |= CORINFO_FLG_VAROBJSIZE;
3990 if (pMT->IsValueType())
3992 ret |= CORINFO_FLG_VALUECLASS;
3994 if (pMT->IsByRefLike())
3995 ret |= CORINFO_FLG_CONTAINS_STACK_PTR;
3997 if ((pClass->IsNotTightlyPacked() && (!pClass->IsManagedSequential() || pClass->HasExplicitSize())) ||
3998 pMT == g_TypedReferenceMT ||
3999 VMClsHnd.IsNativeValueType())
4001 ret |= CORINFO_FLG_CUSTOMLAYOUT;
4004 if (pClass->IsUnsafeValueClass())
4005 ret |= CORINFO_FLG_UNSAFE_VALUECLASS;
4007 if (pClass->HasExplicitFieldOffsetLayout() && pClass->HasOverLayedField())
4008 ret |= CORINFO_FLG_OVERLAPPING_FIELDS;
4009 if (VMClsHnd.IsCanonicalSubtype())
4010 ret |= CORINFO_FLG_SHAREDINST;
4012 if (pMT->HasVariance())
4013 ret |= CORINFO_FLG_VARIANCE;
4015 if (pMT->IsContextful())
4016 ret |= CORINFO_FLG_CONTEXTFUL;
4018 if (pMT->IsMarshaledByRef())
4019 ret |= CORINFO_FLG_MARSHAL_BYREF;
4021 if (pMT->ContainsPointers() || pMT == g_TypedReferenceMT)
4022 ret |= CORINFO_FLG_CONTAINS_GC_PTR;
4024 if (pMT->IsDelegate())
4025 ret |= CORINFO_FLG_DELEGATE;
4027 if (pClass->IsBeforeFieldInit())
4029 if (IsReadyToRunCompilation() && !pMT->GetModule()->IsInCurrentVersionBubble())
4031 // For version resiliency do not allow hoisting static constructors out of loops
4035 ret |= CORINFO_FLG_BEFOREFIELDINIT;
4039 if (pClass->IsAbstract())
4040 ret |= CORINFO_FLG_ABSTRACT;
4042 if (pClass->IsSealed())
4043 ret |= CORINFO_FLG_FINAL;
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 if (!pMD->IsCtor() && !pTypeToInitMT->IsValueType())
4147 // For instance methods of types with precise-initialization
4148 // semantics, we can assume that the .ctor triggerred the
4149 // type initialization.
4150 // This does not hold for NULL "this" object. However, the spec does
4151 // not require that case to work.
4152 result = CORINFO_INITCLASS_NOT_REQUIRED;
4157 if (pTypeToInitMT->IsSharedByGenericInstantiations())
4159 // Shared generic code has to use helper. Moreover, tell JIT not to inline since
4160 // inlining of generic dictionary lookups is not supported.
4161 result = CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE;
4166 // Try to prove that the initialization is not necessary because of nesting
4172 _ASSERTE(fIgnoreBeforeFieldInit || !pTypeToInitMT->GetClass()->IsBeforeFieldInit());
4174 // Note that jit has both methods the same if asking whether to emit cctor
4175 // for a given method's code (as opposed to inlining codegen).
4176 if (context != MAKE_METHODCONTEXT(methodBeingCompiled) && pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4178 // If we're inling a call to a method in our own type, then we should already
4179 // have triggered the .cctor when caller was itself called.
4180 result = CORINFO_INITCLASS_NOT_REQUIRED;
4186 // This optimization may cause static fields in reference types to be accessed without cctor being triggered
4187 // for NULL "this" object. It does not conform with what the spec says. However, we have been historically
4188 // doing it for perf reasons.
4189 if (!pTypeToInitMT->IsValueType() && !pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4191 if (pTypeToInitMT == GetTypeFromContext(context).AsMethodTable() || pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4193 // The class will be initialized by the time we access the field.
4194 result = CORINFO_INITCLASS_NOT_REQUIRED;
4199 // If we are currently compiling the class constructor for this static field access then we can skip the initClass
4200 if (methodBeingCompiled->GetMethodTable() == pTypeToInitMT && methodBeingCompiled->IsStatic() && methodBeingCompiled->IsClassConstructor())
4202 // The class will be initialized by the time we access the field.
4203 result = CORINFO_INITCLASS_NOT_REQUIRED;
4208 if (fMethodDomainNeutral)
4210 // Well, because of code sharing we can't do anything at coge generation time.
4211 // We have to do it at runtime.
4212 result = CORINFO_INITCLASS_USE_HELPER;
4216 #ifndef CROSSGEN_COMPILE
4218 // Optimizations for domain specific code
4221 // Allocate space for the local class if necessary, but don't trigger
4222 // class construction.
4223 DomainLocalModule *pModule = pTypeToInitMT->GetDomainLocalModule();
4224 pModule->PopulateClass(pTypeToInitMT);
4226 if (pTypeToInitMT->IsClassInited())
4228 result = CORINFO_INITCLASS_INITIALIZED;
4232 #ifdef FEATURE_MULTICOREJIT
4233 // Once multicore JIT is enabled in an AppDomain by calling SetProfileRoot, always use helper function to call class init, for consistency
4234 if (! GetAppDomain()->GetMulticoreJitManager().AllowCCtorsToRunDuringJITing())
4236 result = CORINFO_INITCLASS_USE_HELPER;
4242 // To preserve consistent behavior between ngen and not-ngenned states, do not eagerly
4243 // run class constructors for autongennable code.
4244 if (pTypeToInitMT->RunCCTorAsIfNGenImageExists())
4246 result = CORINFO_INITCLASS_USE_HELPER;
4250 if (!pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4252 // Do not inline the access if we cannot initialize the class. Chances are that the class will get
4253 // initialized by the time the access is jitted.
4254 result = CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE;
4260 // Tell the JIT that we may be able to initialize the class when asked to.
4261 result = CORINFO_INITCLASS_SPECULATIVE;
4266 // We cannot run the class constructor without first activating the
4267 // module containing the class. However, since the current module
4268 // we are compiling inside is not active, we don't want to do this.
4270 // This should be an unusal case since normally the method's module should
4271 // be active during jitting.
4273 // @TODO: We should check IsActivating() instead of IsActive() since we may
4274 // be running the Module::.cctor(). The assembly is not marked as active
4276 if (!methodBeingCompiled->GetLoaderModule()->GetDomainFile()->IsActive())
4278 result = CORINFO_INITCLASS_USE_HELPER;
4288 pTypeToInitMT->CheckRunClassInitThrowing();
4292 } EX_END_CATCH(SwallowAllExceptions);
4294 if (pTypeToInitMT->IsClassInited())
4296 result = CORINFO_INITCLASS_INITIALIZED;
4299 #endif // CROSSGEN_COMPILE
4301 // Do not inline the access if we were unable to initialize the class. Chances are that the class will get
4302 // initialized by the time the access is jitted.
4303 result = (CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE);
4307 EE_TO_JIT_TRANSITION();
4309 return (CorInfoInitClassResult)result;
4314 void CEEInfo::classMustBeLoadedBeforeCodeIsRun (CORINFO_CLASS_HANDLE typeToLoadHnd)
4323 JIT_TO_EE_TRANSITION_LEAF();
4325 TypeHandle th = TypeHandle(typeToLoadHnd);
4327 // Type handles returned to JIT at runtime are always fully loaded. Verify that it is the case.
4328 _ASSERTE(th.IsFullyLoaded());
4330 EE_TO_JIT_TRANSITION_LEAF();
4333 /*********************************************************************/
4334 void CEEInfo::methodMustBeLoadedBeforeCodeIsRun (CORINFO_METHOD_HANDLE methHnd)
4343 JIT_TO_EE_TRANSITION_LEAF();
4345 MethodDesc *pMD = (MethodDesc*) methHnd;
4347 // MethodDescs returned to JIT at runtime are always fully loaded. Verify that it is the case.
4348 _ASSERTE(pMD->IsRestored() && pMD->GetMethodTable()->IsFullyLoaded());
4350 EE_TO_JIT_TRANSITION_LEAF();
4353 /*********************************************************************/
4354 CORINFO_METHOD_HANDLE CEEInfo::mapMethodDeclToMethodImpl(CORINFO_METHOD_HANDLE methHnd)
4363 CORINFO_METHOD_HANDLE result = NULL;
4365 JIT_TO_EE_TRANSITION();
4367 MethodDesc *pMD = GetMethod(methHnd);
4368 pMD = MethodTable::MapMethodDeclToMethodImpl(pMD);
4369 result = (CORINFO_METHOD_HANDLE) pMD;
4371 EE_TO_JIT_TRANSITION();
4376 /*********************************************************************/
4377 CORINFO_CLASS_HANDLE CEEInfo::getBuiltinClass(CorInfoClassId classId)
4386 CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE) 0;
4388 JIT_TO_EE_TRANSITION();
4392 case CLASSID_SYSTEM_OBJECT:
4393 result = CORINFO_CLASS_HANDLE(g_pObjectClass);
4395 case CLASSID_TYPED_BYREF:
4396 result = CORINFO_CLASS_HANDLE(g_TypedReferenceMT);
4398 case CLASSID_TYPE_HANDLE:
4399 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__TYPE_HANDLE));
4401 case CLASSID_FIELD_HANDLE:
4402 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__FIELD_HANDLE));
4404 case CLASSID_METHOD_HANDLE:
4405 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__METHOD_HANDLE));
4407 case CLASSID_ARGUMENT_HANDLE:
4408 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__ARGUMENT_HANDLE));
4410 case CLASSID_STRING:
4411 result = CORINFO_CLASS_HANDLE(g_pStringClass);
4413 case CLASSID_RUNTIME_TYPE:
4414 result = CORINFO_CLASS_HANDLE(g_pRuntimeTypeClass);
4417 _ASSERTE(!"NYI: unknown classId");
4421 EE_TO_JIT_TRANSITION();
4428 /*********************************************************************/
4429 CorInfoType CEEInfo::getTypeForPrimitiveValueClass(
4430 CORINFO_CLASS_HANDLE clsHnd)
4439 CorInfoType result = CORINFO_TYPE_UNDEF;
4441 JIT_TO_EE_TRANSITION();
4443 TypeHandle th(clsHnd);
4444 _ASSERTE (!th.IsGenericVariable());
4446 MethodTable *pMT = th.GetMethodTable();
4447 PREFIX_ASSUME(pMT != NULL);
4449 // Is it a non primitive struct such as
4450 // RuntimeTypeHandle, RuntimeMethodHandle, RuntimeArgHandle?
4451 if (pMT->IsValueType() &&
4452 !pMT->IsTruePrimitive() &&
4455 // default value CORINFO_TYPE_UNDEF is what we want
4459 switch (th.GetInternalCorElementType())
4461 case ELEMENT_TYPE_I1:
4462 case ELEMENT_TYPE_U1:
4463 case ELEMENT_TYPE_BOOLEAN:
4464 result = asCorInfoType(ELEMENT_TYPE_I1);
4467 case ELEMENT_TYPE_I2:
4468 case ELEMENT_TYPE_U2:
4469 case ELEMENT_TYPE_CHAR:
4470 result = asCorInfoType(ELEMENT_TYPE_I2);
4473 case ELEMENT_TYPE_I4:
4474 case ELEMENT_TYPE_U4:
4475 result = asCorInfoType(ELEMENT_TYPE_I4);
4478 case ELEMENT_TYPE_I8:
4479 case ELEMENT_TYPE_U8:
4480 result = asCorInfoType(ELEMENT_TYPE_I8);
4483 case ELEMENT_TYPE_I:
4484 case ELEMENT_TYPE_U:
4485 result = asCorInfoType(ELEMENT_TYPE_I);
4488 case ELEMENT_TYPE_R4:
4489 result = asCorInfoType(ELEMENT_TYPE_R4);
4492 case ELEMENT_TYPE_R8:
4493 result = asCorInfoType(ELEMENT_TYPE_R8);
4496 case ELEMENT_TYPE_VOID:
4497 result = asCorInfoType(ELEMENT_TYPE_VOID);
4500 case ELEMENT_TYPE_PTR:
4501 case ELEMENT_TYPE_FNPTR:
4502 result = asCorInfoType(ELEMENT_TYPE_PTR);
4510 EE_TO_JIT_TRANSITION();
4516 void CEEInfo::getGSCookie(GSCookie * pCookieVal, GSCookie ** ppCookieVal)
4525 JIT_TO_EE_TRANSITION();
4529 *pCookieVal = GetProcessGSCookie();
4530 *ppCookieVal = NULL;
4534 *ppCookieVal = GetProcessGSCookiePtr();
4537 EE_TO_JIT_TRANSITION();
4541 /*********************************************************************/
4542 // TRUE if child is a subtype of parent
4543 // if parent is an interface, then does child implement / extend parent
4544 BOOL CEEInfo::canCast(
4545 CORINFO_CLASS_HANDLE child,
4546 CORINFO_CLASS_HANDLE parent)
4555 BOOL result = FALSE;
4557 JIT_TO_EE_TRANSITION();
4559 result = ((TypeHandle)child).CanCastTo((TypeHandle)parent);
4561 EE_TO_JIT_TRANSITION();
4566 /*********************************************************************/
4567 // TRUE if cls1 and cls2 are considered equivalent types.
4568 BOOL CEEInfo::areTypesEquivalent(
4569 CORINFO_CLASS_HANDLE cls1,
4570 CORINFO_CLASS_HANDLE cls2)
4579 BOOL result = FALSE;
4581 JIT_TO_EE_TRANSITION();
4583 result = ((TypeHandle)cls1).IsEquivalentTo((TypeHandle)cls2);
4585 EE_TO_JIT_TRANSITION();
4590 /*********************************************************************/
4591 // returns is the intersection of cls1 and cls2.
4592 CORINFO_CLASS_HANDLE CEEInfo::mergeClasses(
4593 CORINFO_CLASS_HANDLE cls1,
4594 CORINFO_CLASS_HANDLE cls2)
4603 CORINFO_CLASS_HANDLE result = NULL;
4605 JIT_TO_EE_TRANSITION();
4607 TypeHandle merged = TypeHandle::MergeTypeHandlesToCommonParent(TypeHandle(cls1), TypeHandle(cls2));
4610 //Make sure the merge is reflexive in the cases we "support".
4611 TypeHandle hnd1 = TypeHandle(cls1);
4612 TypeHandle hnd2 = TypeHandle(cls2);
4613 TypeHandle reflexive = TypeHandle::MergeTypeHandlesToCommonParent(hnd2, hnd1);
4615 //If both sides are classes than either they have a common non-interface parent (in which case it is
4617 //OR they share a common interface, and it can be order dependent (if they share multiple interfaces
4619 if (!hnd1.IsInterface() && !hnd2.IsInterface())
4621 if (merged.IsInterface())
4623 _ASSERTE(reflexive.IsInterface());
4627 _ASSERTE(merged == reflexive);
4630 //Both results must either be interfaces or classes. They cannot be mixed.
4631 _ASSERTE((!!merged.IsInterface()) == (!!reflexive.IsInterface()));
4633 //If the result of the merge was a class, then the result of the reflexive merge was the same class.
4634 if (!merged.IsInterface())
4636 _ASSERTE(merged == reflexive);
4639 //If both sides are arrays, then the result is either an array or g_pArrayClass. The above is
4640 //actually true about the element type for references types, but I think that that is a little
4641 //excessive for sanity.
4642 if (hnd1.IsArray() && hnd2.IsArray())
4644 _ASSERTE((merged.IsArray() && reflexive.IsArray())
4645 || ((merged == g_pArrayClass) && (reflexive == g_pArrayClass)));
4648 //Can I assert anything about generic variables?
4650 //The results must always be assignable
4651 _ASSERTE(hnd1.CanCastTo(merged) && hnd2.CanCastTo(merged) && hnd1.CanCastTo(reflexive)
4652 && hnd2.CanCastTo(reflexive));
4655 result = CORINFO_CLASS_HANDLE(merged.AsPtr());
4657 EE_TO_JIT_TRANSITION();
4661 /*********************************************************************/
4662 // Given a class handle, returns the Parent type.
4663 // For COMObjectType, it returns Class Handle of System.Object.
4664 // Returns 0 if System.Object is passed in.
4665 CORINFO_CLASS_HANDLE CEEInfo::getParentType(
4666 CORINFO_CLASS_HANDLE cls)
4675 CORINFO_CLASS_HANDLE result = NULL;
4677 JIT_TO_EE_TRANSITION();
4681 _ASSERTE(!th.IsNull());
4682 _ASSERTE(!th.IsGenericVariable());
4684 TypeHandle thParent = th.GetParent();
4686 #ifdef FEATURE_COMINTEROP
4687 // If we encounter __ComObject in the hierarchy, we need to skip it
4688 // since this hierarchy is introduced by the EE, but won't be present
4690 if (!thParent.IsNull() && IsComObjectClass(thParent))
4692 result = (CORINFO_CLASS_HANDLE) g_pObjectClass;
4695 #endif // FEATURE_COMINTEROP
4697 result = CORINFO_CLASS_HANDLE(thParent.AsPtr());
4700 EE_TO_JIT_TRANSITION();
4706 /*********************************************************************/
4707 // Returns the CorInfoType of the "child type". If the child type is
4708 // not a primitive type, *clsRet will be set.
4709 // Given an Array of Type Foo, returns Foo.
4710 // Given BYREF Foo, returns Foo
4711 CorInfoType CEEInfo::getChildType (
4712 CORINFO_CLASS_HANDLE clsHnd,
4713 CORINFO_CLASS_HANDLE *clsRet
4723 CorInfoType ret = CORINFO_TYPE_UNDEF;
4725 TypeHandle retType = TypeHandle();
4727 JIT_TO_EE_TRANSITION();
4729 TypeHandle th(clsHnd);
4731 _ASSERTE(!th.IsNull());
4733 // BYREF, ARRAY types
4734 if (th.IsTypeDesc())
4736 retType = th.AsTypeDesc()->GetTypeParam();
4740 // <REVISIT_TODO> we really should not have this case. arrays type handles
4741 // used in the JIT interface should never be ordinary method tables,
4742 // indeed array type handles should really never be ordinary MTs
4743 // at all. Perhaps we should assert !th.IsTypeDesc() && th.AsMethodTable().IsArray()? </REVISIT_TODO>
4744 MethodTable* pMT= th.AsMethodTable();
4746 retType = pMT->GetApproxArrayElementTypeHandle();
4749 if (!retType.IsNull()) {
4750 CorElementType type = retType.GetInternalCorElementType();
4751 ret = CEEInfo::asCorInfoType(type,retType, clsRet);
4753 // <REVISIT_TODO>What if this one is a value array ?</REVISIT_TODO>
4756 EE_TO_JIT_TRANSITION();
4761 /*********************************************************************/
4762 // Check any constraints on class type arguments
4763 BOOL CEEInfo::satisfiesClassConstraints(CORINFO_CLASS_HANDLE cls)
4772 BOOL result = FALSE;
4774 JIT_TO_EE_TRANSITION();
4776 _ASSERTE(cls != NULL);
4777 result = TypeHandle(cls).SatisfiesClassConstraints();
4779 EE_TO_JIT_TRANSITION();
4784 /*********************************************************************/
4785 // Check if this is a single dimensional array type
4786 BOOL CEEInfo::isSDArray(CORINFO_CLASS_HANDLE cls)
4795 BOOL result = FALSE;
4797 JIT_TO_EE_TRANSITION();
4801 _ASSERTE(!th.IsNull());
4803 if (th.IsArrayType())
4805 // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4806 _ASSERTE(th != TypeHandle(g_pArrayClass));
4808 result = (th.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
4811 EE_TO_JIT_TRANSITION();
4816 /*********************************************************************/
4817 // Get the number of dimensions in an array
4818 unsigned CEEInfo::getArrayRank(CORINFO_CLASS_HANDLE cls)
4827 unsigned result = 0;
4829 JIT_TO_EE_TRANSITION();
4833 _ASSERTE(!th.IsNull());
4835 if (th.IsArrayType())
4837 // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4838 _ASSERTE(th != TypeHandle(g_pArrayClass));
4840 result = th.GetPossiblySharedArrayMethodTable()->GetRank();
4843 EE_TO_JIT_TRANSITION();
4848 /*********************************************************************/
4849 // Get static field data for an array
4850 // Note that it's OK to return NULL from this method. This will cause
4851 // the JIT to make a runtime call to InitializeArray instead of doing
4852 // the inline optimization (thus preserving the original behavior).
4853 void * CEEInfo::getArrayInitializationData(
4854 CORINFO_FIELD_HANDLE field,
4865 void * result = NULL;
4867 JIT_TO_EE_TRANSITION();
4869 FieldDesc* pField = (FieldDesc*) field;
4873 (pField->LoadSize() < size)
4874 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
4875 // This will make sure that when IBC logging is on, the array initialization happens thru
4876 // COMArrayInfo::InitializeArray. This gives a place to put the IBC probe that can help
4877 // separate hold and cold RVA blobs.
4878 || (IsCompilingForNGen() &&
4879 GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
4880 #endif // FEATURE_NATIVE_IMAGE_GENERATION
4887 result = pField->GetStaticAddressHandle(NULL);
4890 EE_TO_JIT_TRANSITION();
4895 CorInfoIsAccessAllowedResult CEEInfo::canAccessClass(
4896 CORINFO_RESOLVED_TOKEN * pResolvedToken,
4897 CORINFO_METHOD_HANDLE callerHandle,
4898 CORINFO_HELPER_DESC *pAccessHelper
4908 CorInfoIsAccessAllowedResult isAccessAllowed = CORINFO_ACCESS_ALLOWED;
4910 JIT_TO_EE_TRANSITION();
4912 INDEBUG(memset(pAccessHelper, 0xCC, sizeof(*pAccessHelper)));
4914 BOOL doAccessCheck = TRUE;
4915 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
4916 DynamicResolver * pAccessContext = NULL;
4918 //All access checks must be done on the open instantiation.
4919 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
4920 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
4922 TypeHandle pCalleeForSecurity = TypeHandle(pResolvedToken->hClass);
4923 if (pResolvedToken->pTypeSpec != NULL)
4925 SigTypeContext typeContext;
4926 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
4928 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
4929 pCalleeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
4932 while (pCalleeForSecurity.HasTypeParam())
4934 pCalleeForSecurity = pCalleeForSecurity.GetTypeParam();
4937 if (IsDynamicScope(pResolvedToken->tokenScope))
4939 doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope),
4940 &callerTypeForSecurity, &accessCheckType,
4944 //Since this is a check against a TypeHandle, there are some things we can stick in a TypeHandle that
4945 //don't require access checks.
4946 if (pCalleeForSecurity.IsGenericVariable())
4948 //I don't need to check for access against !!0.
4949 doAccessCheck = FALSE;
4952 //Now do the visibility checks
4955 AccessCheckOptions accessCheckOptions(accessCheckType,
4957 FALSE /*throw on error*/,
4958 pCalleeForSecurity.GetMethodTable());
4960 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
4961 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
4963 BOOL canAccessType = ClassLoader::CanAccessClass(&accessContext,
4964 pCalleeForSecurity.GetMethodTable(),
4965 pCalleeForSecurity.GetAssembly(),
4966 accessCheckOptions);
4968 isAccessAllowed = canAccessType ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
4972 if (isAccessAllowed != CORINFO_ACCESS_ALLOWED)
4974 //These all get the throw helper
4975 pAccessHelper->helperNum = CORINFO_HELP_CLASS_ACCESS_EXCEPTION;
4976 pAccessHelper->numArgs = 2;
4978 pAccessHelper->args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
4979 pAccessHelper->args[1].Set(CORINFO_CLASS_HANDLE(pCalleeForSecurity.AsPtr()));
4981 if (IsCompilingForNGen())
4983 //see code:CEEInfo::getCallInfo for more information.
4984 if (pCallerForSecurity->ContainsGenericVariables() || pCalleeForSecurity.ContainsGenericVariables())
4985 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic TypeHandle"));
4989 if (isAccessAllowed == CORINFO_ACCESS_ALLOWED)
4991 //Finally let's get me some transparency checks.
4992 CorInfoSecurityRuntimeChecks runtimeChecks = CORINFO_ACCESS_SECURITY_NONE;
4995 DebugSecurityCalloutStress(getMethodBeingCompiled(), isAccessAllowed,
4998 if (isAccessAllowed != CORINFO_ACCESS_ALLOWED)
5000 _ASSERTE(isAccessAllowed == CORINFO_ACCESS_RUNTIME_CHECK);
5001 //Well, time for the runtime helper
5002 pAccessHelper->helperNum = CORINFO_HELP_CLASS_ACCESS_CHECK;
5003 pAccessHelper->numArgs = 3;
5005 pAccessHelper->args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5006 pAccessHelper->args[1].Set(CORINFO_CLASS_HANDLE(pCalleeForSecurity.AsPtr()));
5007 pAccessHelper->args[2].Set(runtimeChecks);
5009 if (IsCompilingForNGen())
5011 //see code:CEEInfo::getCallInfo for more information.
5012 if (pCallerForSecurity->ContainsGenericVariables() || pCalleeForSecurity.ContainsGenericVariables())
5013 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic TypeHandle"));
5018 EE_TO_JIT_TRANSITION();
5019 return isAccessAllowed;
5022 /***********************************************************************/
5023 // return the address of a pointer to a callable stub that will do the
5024 // virtual or interface call
5025 void CEEInfo::getCallInfo(
5026 CORINFO_RESOLVED_TOKEN * pResolvedToken,
5027 CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
5028 CORINFO_METHOD_HANDLE callerHandle,
5029 CORINFO_CALLINFO_FLAGS flags,
5030 CORINFO_CALL_INFO *pResult /*out */)
5039 JIT_TO_EE_TRANSITION();
5041 _ASSERTE(CheckPointer(pResult));
5043 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
5045 MethodDesc* pMD = (MethodDesc *)pResolvedToken->hMethod;
5046 TypeHandle th(pResolvedToken->hClass);
5049 _ASSERTE((size_t(pMD) & 0x1) == 0);
5051 // Spec says that a callvirt lookup ignores static methods. Since static methods
5052 // can't have the exact same signature as instance methods, a lookup that found
5053 // a static method would have never found an instance method.
5054 if (pMD->IsStatic() && (flags & CORINFO_CALLINFO_CALLVIRT))
5056 EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, W("?")));
5061 TypeHandle exactType = TypeHandle(pResolvedToken->hClass);
5063 TypeHandle constrainedType;
5064 if ((flags & CORINFO_CALLINFO_CALLVIRT) && (pConstrainedResolvedToken != NULL))
5066 constrainedType = TypeHandle(pConstrainedResolvedToken->hClass);
5069 BOOL fResolvedConstraint = FALSE;
5070 BOOL fForceUseRuntimeLookup = FALSE;
5072 MethodDesc * pMDAfterConstraintResolution = pMD;
5073 if (constrainedType.IsNull())
5075 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5077 // <NICE> Things go wrong when this code path is used when verifying generic code.
5078 // It would be nice if we didn't go down this sort of code path when verifying but
5079 // not generating code. </NICE>
5080 else if (constrainedType.ContainsGenericVariables() || exactType.ContainsGenericVariables())
5082 // <NICE> It shouldn't really matter what we do here - but the x86 JIT is annoyingly sensitive
5083 // about what we do, since it pretend generic variables are reference types and generates
5084 // an internal JIT tree even when just verifying generic code. </NICE>
5085 if (constrainedType.IsGenericVariable())
5087 pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &T --> T
5089 else if (constrainedType.IsValueType())
5091 pResult->thisTransform = CORINFO_BOX_THIS; // convert 'this' of type &VC<T> --> boxed(VC<T>)
5095 pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &C<T> --> C<T>
5100 // We have a "constrained." call. Try a partial resolve of the constraint call. Note that this
5101 // will not necessarily resolve the call exactly, since we might be compiling
5102 // shared generic code - it may just resolve it to a candidate suitable for
5103 // JIT compilation, and require a runtime lookup for the actual code pointer
5105 if (constrainedType.IsEnum())
5107 // Optimize constrained calls to enum's GetHashCode method. TryResolveConstraintMethodApprox would return
5108 // null since the virtual method resolves to System.Enum's implementation and that's a reference type.
5109 // We can't do this for any other method since ToString and Equals have different semantics for enums
5110 // and their underlying type.
5111 if (pMD->GetSlot() == MscorlibBinder::GetMethod(METHOD__OBJECT__GET_HASH_CODE)->GetSlot())
5113 // Pretend this was a "constrained. UnderlyingType" instruction prefix
5114 constrainedType = TypeHandle(MscorlibBinder::GetElementType(constrainedType.GetVerifierCorElementType()));
5116 // Native image signature encoder will use this field. It needs to match that pretended type, a bogus signature
5117 // would be produced otherwise.
5118 pConstrainedResolvedToken->hClass = (CORINFO_CLASS_HANDLE)constrainedType.AsPtr();
5120 // Clear the token and typespec because of they do not match hClass anymore.
5121 pConstrainedResolvedToken->token = mdTokenNil;
5122 pConstrainedResolvedToken->pTypeSpec = NULL;
5126 MethodDesc * directMethod = constrainedType.GetMethodTable()->TryResolveConstraintMethodApprox(
5129 &fForceUseRuntimeLookup);
5133 // 1. no constraint resolution at compile time (!directMethod)
5134 // OR 2. no code sharing lookup in call
5135 // OR 3. we have have resolved to an instantiating stub
5137 pMDAfterConstraintResolution = directMethod;
5138 _ASSERTE(!pMDAfterConstraintResolution->IsInterface());
5139 fResolvedConstraint = TRUE;
5140 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5142 exactType = constrainedType;
5144 else if (constrainedType.IsValueType())
5146 pResult->thisTransform = CORINFO_BOX_THIS;
5150 pResult->thisTransform = CORINFO_DEREF_THIS;
5155 // Initialize callee context used for inlining and instantiation arguments
5158 MethodDesc * pTargetMD = pMDAfterConstraintResolution;
5160 if (pTargetMD->HasMethodInstantiation())
5162 pResult->contextHandle = MAKE_METHODCONTEXT(pTargetMD);
5163 pResult->exactContextNeedsRuntimeLookup = pTargetMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(pTargetMD->GetMethodInstantiation());
5167 if (!exactType.IsTypeDesc())
5169 // Because of .NET's notion of base calls, exactType may point to a sub-class
5170 // of the actual class that defines pTargetMD. If the JIT decides to inline, it is
5171 // important that they 'match', so we fix exactType here.
5172 #ifdef FEATURE_READYTORUN_COMPILER
5173 if (IsReadyToRunCompilation() &&
5175 !IsInSameVersionBubble((MethodDesc*)callerHandle, pTargetMD))
5177 // For version resilient code we can only inline within the same version bubble;
5178 // we "repair" the precise types only for those callees.
5179 // The above condition needs to stay in sync with CEEInfo::canInline
5185 exactType = pTargetMD->GetExactDeclaringType(exactType.AsMethodTable());
5186 _ASSERTE(!exactType.IsNull());
5190 pResult->contextHandle = MAKE_CLASSCONTEXT(exactType.AsPtr());
5191 pResult->exactContextNeedsRuntimeLookup = exactType.IsSharedByGenericInstantiations();
5195 // Determine whether to perform direct call
5198 bool directCall = false;
5199 bool resolvedCallVirt = false;
5200 bool callVirtCrossingVersionBubble = false;
5202 // Delegate targets are always treated as direct calls here. (It would be nice to clean it up...).
5203 if (flags & CORINFO_CALLINFO_LDFTN)
5205 if (m_pOverride != NULL)
5206 TypeEquivalenceFixupSpecificationHelper(m_pOverride, pTargetMD);
5210 // Static methods are always direct calls
5211 if (pTargetMD->IsStatic())
5216 // Force all interface calls to be interpreted as if they are virtual.
5217 if (pTargetMD->GetMethodTable()->IsInterface())
5222 if (!(flags & CORINFO_CALLINFO_CALLVIRT) || fResolvedConstraint)
5230 #ifdef FEATURE_READYTORUN_COMPILER
5232 // if we are generating version resilient code
5234 // caller/callee are in different version bubbles
5235 // we have to apply more restrictive rules
5236 // These rules are related to the "inlining rules" as far as the
5237 // boundaries of a version bubble are concerned.
5239 if (IsReadyToRunCompilation() &&
5241 !IsInSameVersionBubble((MethodDesc*)callerHandle, pTargetMD)
5244 // For version resiliency we won't de-virtualize all final/sealed method calls. Because during a
5245 // servicing event it is legal to unseal a method or type.
5247 // Note that it is safe to devirtualize in the following cases, since a servicing event cannot later modify it
5248 // 1) Callvirt on a virtual final method of a value type - since value types are sealed types as per ECMA spec
5249 // 2) Delegate.Invoke() - since a Delegate is a sealed class as per ECMA spec
5250 // 3) JIT intrinsics - since they have pre-defined behavior
5251 devirt = pTargetMD->GetMethodTable()->IsValueType() ||
5252 (pTargetMD->GetMethodTable()->IsDelegate() && ((DelegateEEClass*)(pTargetMD->GetMethodTable()->GetClass()))->GetInvokeMethod() == pMD) ||
5253 (pTargetMD->IsFCall() && ECall::GetIntrinsicID(pTargetMD) != CORINFO_INTRINSIC_Illegal);
5255 callVirtCrossingVersionBubble = true;
5260 DWORD dwMethodAttrs = pTargetMD->GetAttrs();
5261 devirt = !IsMdVirtual(dwMethodAttrs) || IsMdFinal(dwMethodAttrs) || pTargetMD->GetMethodTable()->IsSealed();
5266 // We can't allow generic remotable methods to be considered resolved, it leads to a non-instantiating method desc being
5267 // passed to the remoting stub. The easiest way to deal with these is to force them through the virtual code path.
5268 // It is actually good to do this deoptimization for all remotable methods since remoting interception via vtable dispatch
5269 // is faster then remoting interception via thunk
5270 if (!pTargetMD->IsRemotingInterceptedViaVirtualDispatch() /* || !pTargetMD->HasMethodInstantiation() */)
5272 resolvedCallVirt = true;
5280 bool allowInstParam = (flags & CORINFO_CALLINFO_ALLOWINSTPARAM)
5281 // See code:IsRemotingInterceptedViaPrestub on why we need need to disallow inst param for remoting.
5282 && !( pTargetMD->MayBeRemotingIntercepted() && !pTargetMD->IsVtableMethod() );
5284 // Create instantiating stub if necesary
5285 if (!allowInstParam && pTargetMD->RequiresInstArg())
5287 pTargetMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pTargetMD,
5288 exactType.AsMethodTable(),
5289 FALSE /* forceBoxedEntryPoint */,
5290 pTargetMD->GetMethodInstantiation(),
5291 FALSE /* allowInstParam */);
5294 // We don't allow a JIT to call the code directly if a runtime lookup is
5295 // needed. This is the case if
5296 // 1. the scan of the call token indicated that it involves code sharing
5297 // AND 2. the method is an instantiating stub
5299 // In these cases the correct instantiating stub is only found via a runtime lookup.
5301 // Note that most JITs don't call instantiating stubs directly if they can help it -
5302 // they call the underlying shared code and provide the type context parameter
5303 // explicitly. However
5304 // (a) some JITs may call instantiating stubs (it makes the JIT simpler) and
5305 // (b) if the method is a remote stub then the EE will force the
5306 // call through an instantiating stub and
5307 // (c) constraint calls that require runtime context lookup are never resolved
5308 // to underlying shared generic code
5310 if (((pResult->exactContextNeedsRuntimeLookup && pTargetMD->IsInstantiatingStub() && (!allowInstParam || fResolvedConstraint)) || fForceUseRuntimeLookup)
5311 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
5312 && ContextIsShared(pResolvedToken->tokenContext))
5314 _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5315 pResult->kind = CORINFO_CALL_CODE_POINTER;
5317 // For reference types, the constrained type does not affect method resolution
5318 DictionaryEntryKind entryKind = (!constrainedType.IsNull() && constrainedType.IsValueType()) ? ConstrainedMethodEntrySlot : MethodEntrySlot;
5320 ComputeRuntimeLookupForSharedGenericToken(entryKind,
5322 pConstrainedResolvedToken,
5324 &pResult->codePointerLookup);
5328 if (allowInstParam && pTargetMD->IsInstantiatingStub())
5330 pTargetMD = pTargetMD->GetWrappedMethodDesc();
5333 pResult->kind = CORINFO_CALL;
5335 if (IsReadyToRunCompilation())
5337 // Compensate for always treating delegates as direct calls above
5338 if ((flags & CORINFO_CALLINFO_LDFTN) && (flags & CORINFO_CALLINFO_CALLVIRT) && !resolvedCallVirt)
5340 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5344 pResult->nullInstanceCheck = resolvedCallVirt;
5346 // All virtual calls which take method instantiations must
5347 // currently be implemented by an indirect call via a runtime-lookup
5349 else if (pTargetMD->HasMethodInstantiation())
5351 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN; // stub dispatch can't handle generic method calls yet
5352 pResult->nullInstanceCheck = TRUE;
5354 // Non-interface dispatches go through the vtable
5355 else if (!pTargetMD->IsInterface() && !IsReadyToRunCompilation())
5357 pResult->kind = CORINFO_VIRTUALCALL_VTABLE;
5358 pResult->nullInstanceCheck = TRUE;
5362 if (IsReadyToRunCompilation())
5364 // Insert explicit null checks for cross-version bubble non-interface calls.
5365 // It is required to handle null checks properly for non-virtual <-> virtual change between versions
5366 pResult->nullInstanceCheck = !!(callVirtCrossingVersionBubble && !pTargetMD->IsInterface());
5370 // No need to null check - the dispatch code will deal with null this.
5371 pResult->nullInstanceCheck = FALSE;
5373 #ifdef STUB_DISPATCH_PORTABLE
5374 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5375 #else // STUB_DISPATCH_PORTABLE
5376 pResult->kind = CORINFO_VIRTUALCALL_STUB;
5378 // We can't make stub calls when we need exact information
5379 // for interface calls from shared code.
5381 if (// If the token is not shared then we don't need a runtime lookup
5382 pResult->exactContextNeedsRuntimeLookup
5383 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
5384 && ContextIsShared(pResolvedToken->tokenContext))
5386 _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5388 ComputeRuntimeLookupForSharedGenericToken(DispatchStubAddrSlot,
5392 &pResult->stubLookup);
5396 pResult->stubLookup.lookupKind.needsRuntimeLookup = false;
5398 BYTE * indcell = NULL;
5400 if (!(flags & CORINFO_CALLINFO_KINDONLY) && !isVerifyOnly())
5402 #ifndef CROSSGEN_COMPILE
5403 // We shouldn't be using GetLoaderAllocator here because for LCG, we need to get the
5404 // VirtualCallStubManager from where the stub will be used.
5405 // For normal methods there is no difference.
5406 LoaderAllocator *pLoaderAllocator = m_pMethodBeingCompiled->GetLoaderAllocatorForCode();
5407 VirtualCallStubManager *pMgr = pLoaderAllocator->GetVirtualCallStubManager();
5409 PCODE addr = pMgr->GetCallStub(exactType, pTargetMD);
5410 _ASSERTE(pMgr->isStub(addr));
5412 // Now we want to indirect through a cell so that updates can take place atomically.
5413 if (m_pMethodBeingCompiled->IsLCGMethod())
5415 // LCG methods should use recycled indcells to prevent leaks.
5416 indcell = pMgr->GenerateStubIndirection(addr, TRUE);
5418 // Add it to the per DM list so that we can recycle them when the resolver is finalized
5419 LCGMethodResolver *pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetLCGMethodResolver();
5420 pResolver->AddToUsedIndCellList(indcell);
5424 // Normal methods should avoid recycled cells to preserve the locality of all indcells
5425 // used by one method.
5426 indcell = pMgr->GenerateStubIndirection(addr, FALSE);
5428 #else // CROSSGEN_COMPILE
5429 // This path should be unreachable during crossgen
5431 #endif // CROSSGEN_COMPILE
5434 // We use an indirect call
5435 pResult->stubLookup.constLookup.accessType = IAT_PVALUE;
5436 pResult->stubLookup.constLookup.addr = indcell;
5438 #endif // STUB_DISPATCH_PORTABLE
5441 pResult->hMethod = CORINFO_METHOD_HANDLE(pTargetMD);
5443 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5444 if ((flags & CORINFO_CALLINFO_SECURITYCHECKS) &&
5445 !((MethodDesc *)callerHandle)->IsILStub()) // IL stubs can access everything, don't bother doing access checks
5447 //Our type system doesn't always represent the target exactly with the MethodDesc. In all cases,
5448 //carry around the parent MethodTable for both Caller and Callee.
5449 TypeHandle calleeTypeForSecurity = TypeHandle(pResolvedToken->hClass);
5450 MethodDesc * pCalleeForSecurity = pMD;
5452 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle); //Should this be the open MD?
5454 if (pCallerForSecurity->HasClassOrMethodInstantiation())
5456 _ASSERTE(!IsDynamicScope(pResolvedToken->tokenScope));
5458 SigTypeContext typeContext;
5459 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
5460 _ASSERTE(!typeContext.IsEmpty());
5462 //If the caller is generic, load the open type and resolve the token again. Use that for the access
5463 //checks. If we don't do this then we can't tell the difference between:
5465 //BadGeneric<T> containing a methodspec for InaccessibleType::member (illegal)
5467 //BadGeneric<T> containing a methodspec for !!0::member instantiated over InaccessibleType (legal)
5469 if (pResolvedToken->pTypeSpec != NULL)
5471 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
5472 calleeTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5474 // typeHnd can be a variable type
5475 if (calleeTypeForSecurity.GetMethodTable() == NULL)
5477 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
5481 if (pCalleeForSecurity->IsArray())
5483 // FindOrCreateAssociatedMethodDesc won't remap array method desc because of array base type
5484 // is not part of instantiation. We have to special case it.
5485 pCalleeForSecurity = calleeTypeForSecurity.GetMethodTable()->GetParallelMethodDesc(pCalleeForSecurity);
5488 if (pResolvedToken->pMethodSpec != NULL)
5490 DWORD nGenericMethodArgs = 0;
5491 CQuickBytes qbGenericMethodArgs;
5492 TypeHandle *genericMethodArgs = NULL;
5494 SigPointer sp(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
5497 IfFailThrow(sp.GetByte(&etype));
5499 // Load the generic method instantiation
5500 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, (Module *)pResolvedToken->tokenScope);
5502 IfFailThrow(sp.GetData(&nGenericMethodArgs));
5504 DWORD cbAllocSize = 0;
5505 if (!ClrSafeInt<DWORD>::multiply(nGenericMethodArgs, sizeof(TypeHandle), cbAllocSize))
5507 COMPlusThrowHR(COR_E_OVERFLOW);
5510 genericMethodArgs = reinterpret_cast<TypeHandle *>(qbGenericMethodArgs.AllocThrows(cbAllocSize));
5512 for (DWORD i = 0; i < nGenericMethodArgs; i++)
5514 genericMethodArgs[i] = sp.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5515 _ASSERTE (!genericMethodArgs[i].IsNull());
5516 IfFailThrow(sp.SkipExactlyOne());
5519 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(genericMethodArgs, nGenericMethodArgs), FALSE);
5522 if (pResolvedToken->pTypeSpec != NULL)
5524 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(), TRUE);
5528 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5530 //Passed various link-time checks. Now do access checks.
5532 BOOL doAccessCheck = TRUE;
5533 BOOL canAccessMethod = TRUE;
5534 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
5535 DynamicResolver * pAccessContext = NULL;
5537 callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5538 if (pCallerForSecurity->IsDynamicMethod())
5540 doAccessCheck = ModifyCheckForDynamicMethod(pCallerForSecurity->AsDynamicMethodDesc()->GetResolver(),
5541 &callerTypeForSecurity,
5542 &accessCheckType, &pAccessContext);
5545 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5549 AccessCheckOptions accessCheckOptions(accessCheckType,
5552 pCalleeForSecurity);
5554 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5555 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5557 canAccessMethod = ClassLoader::CanAccess(&accessContext,
5558 calleeTypeForSecurity.GetMethodTable(),
5559 calleeTypeForSecurity.GetAssembly(),
5560 pCalleeForSecurity->GetAttrs(),
5566 // If we were allowed access to the exact method, but it is on a type that has a type parameter
5567 // (for instance an array), we need to ensure that we also have access to the type parameter.
5568 if (canAccessMethod && calleeTypeForSecurity.HasTypeParam())
5570 TypeHandle typeParam = calleeTypeForSecurity.GetTypeParam();
5571 while (typeParam.HasTypeParam())
5573 typeParam = typeParam.GetTypeParam();
5576 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5577 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5579 MethodTable* pTypeParamMT = typeParam.GetMethodTable();
5581 // No accees check is need for Var, MVar, or FnPtr.
5582 if (pTypeParamMT != NULL)
5583 canAccessMethod = ClassLoader::CanAccessClass(&accessContext,
5585 typeParam.GetAssembly(),
5586 accessCheckOptions);
5589 pResult->accessAllowed = canAccessMethod ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
5590 if (!canAccessMethod)
5592 //Check failed, fill in the throw exception helper.
5593 pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_METHOD_ACCESS_EXCEPTION;
5594 pResult->callsiteCalloutHelper.numArgs = 2;
5596 pResult->callsiteCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5597 pResult->callsiteCalloutHelper.args[1].Set(CORINFO_METHOD_HANDLE(pCalleeForSecurity));
5599 //We now embed open instantiations in a few places for security callouts (since you can only
5600 //do the security check on the open instantiation). We throw these methods out in
5601 //TriageMethodForZap. In addition, NGen has problems referencing them properly. Just throw out the whole
5602 //method and rejit at runtime.
5603 if (IsCompilingForNGen())
5605 if (pCallerForSecurity->ContainsGenericVariables()
5606 || pCalleeForSecurity->ContainsGenericVariables())
5608 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
5615 //We're pretty much done at this point. Let's grab the rest of the information that the jit is going to
5617 pResult->classFlags = getClassAttribsInternal(pResolvedToken->hClass);
5619 pResult->methodFlags = getMethodAttribsInternal(pResult->hMethod);
5620 getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL);
5622 if (flags & CORINFO_CALLINFO_VERIFICATION)
5624 if (pResult->hMethod != pResolvedToken->hMethod)
5626 pResult->verMethodFlags = getMethodAttribsInternal(pResolvedToken->hMethod);
5627 getMethodSigInternal(pResolvedToken->hMethod, &pResult->verSig, pResolvedToken->hClass);
5631 pResult->verMethodFlags = pResult->methodFlags;
5632 pResult->verSig = pResult->sig;
5636 pResult->secureDelegateInvoke = FALSE;
5638 #ifdef FEATURE_STUBS_AS_IL
5639 if (m_pMethodBeingCompiled->IsDynamicMethod())
5641 auto pMD = m_pMethodBeingCompiled->AsDynamicMethodDesc();
5642 if (pMD->IsILStub() && pMD->IsSecureDelegateStub())
5644 pResult->secureDelegateInvoke = TRUE;
5649 EE_TO_JIT_TRANSITION();
5652 BOOL CEEInfo::canAccessFamily(CORINFO_METHOD_HANDLE hCaller,
5653 CORINFO_CLASS_HANDLE hInstanceType)
5655 WRAPPER_NO_CONTRACT;
5659 //Since this is only for verification, I don't need to do the demand.
5660 JIT_TO_EE_TRANSITION();
5662 TypeHandle targetType = TypeHandle(hInstanceType);
5663 TypeHandle accessingType = TypeHandle(GetMethod(hCaller)->GetMethodTable());
5664 AccessCheckOptions::AccessCheckType accessCheckOptions = AccessCheckOptions::kNormalAccessibilityChecks;
5665 DynamicResolver* pIgnored;
5666 BOOL doCheck = TRUE;
5667 if (GetMethod(hCaller)->IsDynamicMethod())
5669 //If this is a DynamicMethod, perform the check from the type to which the DynamicMethod was
5672 //If this is a dynamic method, don't do this check. If they specified SkipVisibilityChecks
5673 //(ModifyCheckForDynamicMethod returned false), we should obviously skip the check for the C++
5674 //protected rule (since we skipped all the other visibility checks). If they specified
5675 //RestrictedSkipVisibilityChecks, then they're a "free" DynamicMethod. This check is meaningless
5676 //(i.e. it would always fail). We've already done a demand for access to the member. Let that be
5678 doCheck = ModifyCheckForDynamicMethod(GetMethod(hCaller)->AsDynamicMethodDesc()->GetResolver(),
5679 &accessingType, &accessCheckOptions, &pIgnored);
5680 if (accessCheckOptions == AccessCheckOptions::kRestrictedMemberAccess
5681 || accessCheckOptions == AccessCheckOptions::kRestrictedMemberAccessNoTransparency
5688 ret = ClassLoader::CanAccessFamilyVerification(accessingType, targetType);
5695 EE_TO_JIT_TRANSITION();
5698 void CEEInfo::ThrowExceptionForHelper(const CORINFO_HELPER_DESC * throwHelper)
5707 JIT_TO_EE_TRANSITION();
5709 _ASSERTE(throwHelper->args[0].argType == CORINFO_HELPER_ARG_TYPE_Method);
5710 MethodDesc *pCallerMD = GetMethod(throwHelper->args[0].methodHandle);
5712 StaticAccessCheckContext accessContext(pCallerMD);
5714 switch (throwHelper->helperNum)
5716 case CORINFO_HELP_METHOD_ACCESS_EXCEPTION:
5718 _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Method);
5719 ThrowMethodAccessException(&accessContext, GetMethod(throwHelper->args[1].methodHandle));
5722 case CORINFO_HELP_FIELD_ACCESS_EXCEPTION:
5724 _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Field);
5725 ThrowFieldAccessException(&accessContext, reinterpret_cast<FieldDesc *>(throwHelper->args[1].fieldHandle));
5728 case CORINFO_HELP_CLASS_ACCESS_EXCEPTION:
5730 _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Class);
5731 TypeHandle typeHnd(throwHelper->args[1].classHandle);
5732 ThrowTypeAccessException(&accessContext, typeHnd.GetMethodTable());
5737 _ASSERTE(!"Unknown access exception type");
5739 EE_TO_JIT_TRANSITION();
5743 BOOL CEEInfo::isRIDClassDomainID(CORINFO_CLASS_HANDLE cls)
5752 BOOL result = FALSE;
5754 JIT_TO_EE_TRANSITION();
5756 TypeHandle VMClsHnd(cls);
5758 result = !VMClsHnd.AsMethodTable()->IsDynamicStatics();
5760 EE_TO_JIT_TRANSITION();
5766 /***********************************************************************/
5767 unsigned CEEInfo::getClassDomainID (CORINFO_CLASS_HANDLE clsHnd,
5768 void **ppIndirection)
5777 unsigned result = 0;
5779 if (ppIndirection != NULL)
5780 *ppIndirection = NULL;
5782 JIT_TO_EE_TRANSITION();
5784 TypeHandle VMClsHnd(clsHnd);
5786 if (VMClsHnd.AsMethodTable()->IsDynamicStatics())
5788 result = (unsigned)VMClsHnd.AsMethodTable()->GetModuleDynamicEntryID();
5792 result = (unsigned)VMClsHnd.AsMethodTable()->GetClassIndex();
5795 EE_TO_JIT_TRANSITION();
5800 //---------------------------------------------------------------------------------------
5802 // Used by the JIT to determine whether the profiler or IBC is tracking object
5806 // bool indicating whether the profiler or IBC is tracking object allocations
5809 // Normally, a profiler would just directly call the inline helper to determine
5810 // whether the profiler set the relevant event flag (e.g.,
5811 // CORProfilerTrackAllocationsEnabled). However, this wrapper also asks whether we're
5812 // running for IBC instrumentation or enabling the object allocated ETW event. If so,
5813 // we treat that the same as if the profiler requested allocation information, so that
5814 // the JIT will still use the profiling-friendly object allocation jit helper, so the
5815 // allocations can be tracked.
5818 bool __stdcall TrackAllocationsEnabled()
5829 (g_IBCLogger.InstrEnabled() != FALSE)
5830 #ifdef PROFILING_SUPPORTED
5831 || CORProfilerTrackAllocationsEnabled()
5832 #endif // PROFILING_SUPPORTED
5833 #ifdef FEATURE_EVENT_TRACE
5834 || ETW::TypeSystemLog::IsHeapAllocEventEnabled()
5835 #endif // FEATURE_EVENT_TRACE
5839 /***********************************************************************/
5840 CorInfoHelpFunc CEEInfo::getNewHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_METHOD_HANDLE callerHandle)
5849 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5851 JIT_TO_EE_TRANSITION();
5853 TypeHandle VMClsHnd(pResolvedToken->hClass);
5855 if(VMClsHnd.IsTypeDesc())
5857 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateFunctionPointer"));
5860 if(VMClsHnd.IsAbstract())
5862 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateAbstractClass"));
5865 MethodTable* pMT = VMClsHnd.AsMethodTable();
5866 result = getNewHelperStatic(pMT);
5868 _ASSERTE(result != CORINFO_HELP_UNDEF);
5870 EE_TO_JIT_TRANSITION();
5875 /***********************************************************************/
5876 CorInfoHelpFunc CEEInfo::getNewHelperStatic(MethodTable * pMT)
5878 STANDARD_VM_CONTRACT;
5881 // Slow helper is the default
5882 CorInfoHelpFunc helper = CORINFO_HELP_NEWFAST;
5885 if (pMT->IsComObjectType())
5888 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5891 if ((pMT->GetBaseSize() >= LARGE_OBJECT_SIZE) ||
5892 pMT->HasFinalizer())
5895 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5898 // don't call the super-optimized one since that does not check
5900 if (GCStress<cfg_alloc>::IsEnabled())
5903 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5908 // Super fast version doesn't do logging
5909 if (LoggingOn(LF_GCALLOC, LL_INFO10))
5912 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5917 // Don't use the SFAST allocator when tracking object allocations,
5918 // so we don't have to instrument it.
5919 if (TrackAllocationsEnabled())
5922 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5925 #ifdef FEATURE_64BIT_ALIGNMENT
5926 // @ARMTODO: Force all 8-byte alignment requiring allocations down one slow path. As performance
5927 // measurements dictate we can spread these out to faster, more specialized helpers later.
5928 if (pMT->RequiresAlign8())
5931 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5936 // Use the fast helper when all conditions are met
5937 helper = CORINFO_HELP_NEWSFAST;
5940 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
5941 // If we are use the the fast allocator we also may need the
5942 // specialized varion for align8
5943 if (pMT->GetClass()->IsAlign8Candidate() &&
5944 (helper == CORINFO_HELP_NEWSFAST))
5946 helper = CORINFO_HELP_NEWSFAST_ALIGN8;
5948 #endif // FEATURE_DOUBLE_ALIGNMENT_HINT
5953 /***********************************************************************/
5954 // <REVIEW> this only works for shared generic code because all the
5955 // helpers are actually the same. If they were different then things might
5956 // break because the same helper would end up getting used for different but
5957 // representation-compatible arrays (e.g. one with a default constructor
5958 // and one without) </REVIEW>
5959 CorInfoHelpFunc CEEInfo::getNewArrHelper (CORINFO_CLASS_HANDLE arrayClsHnd)
5968 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5970 JIT_TO_EE_TRANSITION();
5972 TypeHandle arrayType(arrayClsHnd);
5974 result = getNewArrHelperStatic(arrayType);
5976 _ASSERTE(result != CORINFO_HELP_UNDEF);
5978 EE_TO_JIT_TRANSITION();
5983 /***********************************************************************/
5984 CorInfoHelpFunc CEEInfo::getNewArrHelperStatic(TypeHandle clsHnd)
5986 STANDARD_VM_CONTRACT;
5988 ArrayTypeDesc* arrayTypeDesc = clsHnd.AsArray();
5989 _ASSERTE(arrayTypeDesc->GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
5991 if (GCStress<cfg_alloc>::IsEnabled())
5993 return CORINFO_HELP_NEWARR_1_DIRECT;
5996 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5998 TypeHandle thElemType = arrayTypeDesc->GetTypeParam();
5999 CorElementType elemType = thElemType.GetInternalCorElementType();
6001 // This is if we're asked for newarr !0 when verifying generic code
6002 // Of course ideally you wouldn't even be generating code when
6003 // simply doing verification (we run the JIT importer in import-only
6004 // mode), but importing does more than one would like so we try to be
6005 // tolerant when asked for non-sensical helpers.
6006 if (CorTypeInfo::IsGenericVariable(elemType))
6008 result = CORINFO_HELP_NEWARR_1_OBJ;
6010 else if (CorTypeInfo::IsObjRef(elemType))
6012 // It is an array of object refs
6013 result = CORINFO_HELP_NEWARR_1_OBJ;
6017 // These cases always must use the slow helper
6019 #ifdef FEATURE_64BIT_ALIGNMENT
6020 thElemType.RequiresAlign8() ||
6022 (elemType == ELEMENT_TYPE_VOID) ||
6023 LoggingOn(LF_GCALLOC, LL_INFO10) ||
6024 TrackAllocationsEnabled())
6026 // Use the slow helper
6027 result = CORINFO_HELP_NEWARR_1_DIRECT;
6029 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
6030 else if (elemType == ELEMENT_TYPE_R8)
6032 // Use the Align8 fast helper
6033 result = CORINFO_HELP_NEWARR_1_ALIGN8;
6038 // Yea, we can do it the fast way!
6039 result = CORINFO_HELP_NEWARR_1_VC;
6046 /***********************************************************************/
6047 CorInfoHelpFunc CEEInfo::getCastingHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fThrowing)
6057 return fThrowing ? CORINFO_HELP_CHKCASTANY : CORINFO_HELP_ISINSTANCEOFANY;
6059 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6061 JIT_TO_EE_TRANSITION();
6063 bool fClassMustBeRestored;
6064 result = getCastingHelperStatic(TypeHandle(pResolvedToken->hClass), fThrowing, &fClassMustBeRestored);
6065 if (fClassMustBeRestored && m_pOverride != NULL)
6066 m_pOverride->classMustBeLoadedBeforeCodeIsRun(pResolvedToken->hClass);
6068 EE_TO_JIT_TRANSITION();
6073 /***********************************************************************/
6074 CorInfoHelpFunc CEEInfo::getCastingHelperStatic(TypeHandle clsHnd, bool fThrowing, bool * pfClassMustBeRestored)
6076 STANDARD_VM_CONTRACT;
6078 // Slow helper is the default
6079 int helper = CORINFO_HELP_ISINSTANCEOFANY;
6081 *pfClassMustBeRestored = false;
6083 if (clsHnd == TypeHandle(g_pCanonMethodTableClass))
6085 // In shared code just use the catch-all helper for type variables, as the same
6086 // code may be used for interface/array/class instantiations
6088 // We may be able to take advantage of constraints to select a specialized helper.
6089 // This optimizations does not seem to be warranted at the moment.
6090 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6093 if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasVariance())
6095 // Casting to variant type requires the type to be fully loaded
6096 *pfClassMustBeRestored = true;
6098 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6101 if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasTypeEquivalence())
6103 // If the type can be equivalent with something, use the slow helper
6104 // Note: if the type of the instance is the one marked as equivalent, it will be
6105 // caught by the fast helpers in the same way as they catch transparent proxies.
6106 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6109 if (clsHnd.IsInterface())
6111 // If it is a non-variant interface, use the fast interface helper
6112 helper = CORINFO_HELP_ISINSTANCEOFINTERFACE;
6115 if (clsHnd.IsArray())
6117 if (clsHnd.AsArray()->GetInternalCorElementType() != ELEMENT_TYPE_SZARRAY)
6119 // Casting to multidimensional array type requires restored pointer to EEClass to fetch rank
6120 *pfClassMustBeRestored = true;
6123 // If it is an array, use the fast array helper
6124 helper = CORINFO_HELP_ISINSTANCEOFARRAY;
6127 if (!clsHnd.IsTypeDesc() && !Nullable::IsNullableType(clsHnd))
6129 // If it is a non-variant class, use the fast class helper
6130 helper = CORINFO_HELP_ISINSTANCEOFCLASS;
6134 // Otherwise, use the slow helper
6135 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6138 #ifdef FEATURE_PREJIT
6139 BOOL t1, t2, forceInstr;
6140 SystemDomain::GetCompilationOverrides(&t1, &t2, &forceInstr);
6143 // If we're compiling for instrumentation, use the slowest but instrumented cast helper
6144 helper = CORINFO_HELP_ISINSTANCEOFANY;
6150 const int delta = CORINFO_HELP_CHKCASTANY - CORINFO_HELP_ISINSTANCEOFANY;
6152 static_assert_no_msg(CORINFO_HELP_CHKCASTINTERFACE
6153 == CORINFO_HELP_ISINSTANCEOFINTERFACE + delta);
6154 static_assert_no_msg(CORINFO_HELP_CHKCASTARRAY
6155 == CORINFO_HELP_ISINSTANCEOFARRAY + delta);
6156 static_assert_no_msg(CORINFO_HELP_CHKCASTCLASS
6157 == CORINFO_HELP_ISINSTANCEOFCLASS + delta);
6162 return (CorInfoHelpFunc)helper;
6165 /***********************************************************************/
6166 CorInfoHelpFunc CEEInfo::getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd)
6175 CorInfoHelpFunc result = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
6177 JIT_TO_EE_TRANSITION_LEAF();
6179 TypeHandle cls(clsHnd);
6180 MethodTable* pMT = cls.AsMethodTable();
6182 if (pMT->IsDynamicStatics())
6184 _ASSERTE(!cls.ContainsGenericVariables());
6185 _ASSERTE(pMT->GetModuleDynamicEntryID() != (unsigned) -1);
6187 result = CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
6190 EE_TO_JIT_TRANSITION_LEAF();
6195 /***********************************************************************/
6196 CorInfoHelpFunc CEEInfo::getUnBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6198 LIMITED_METHOD_CONTRACT;
6200 if (m_pOverride != NULL)
6201 m_pOverride->classMustBeLoadedBeforeCodeIsRun(clsHnd);
6203 TypeHandle VMClsHnd(clsHnd);
6204 if (Nullable::IsNullableType(VMClsHnd))
6205 return CORINFO_HELP_UNBOX_NULLABLE;
6207 return CORINFO_HELP_UNBOX;
6210 /***********************************************************************/
6211 bool CEEInfo::getReadyToRunHelper(
6212 CORINFO_RESOLVED_TOKEN * pResolvedToken,
6213 CORINFO_LOOKUP_KIND * pGenericLookupKind,
6215 CORINFO_CONST_LOOKUP * pLookup
6218 LIMITED_METHOD_CONTRACT;
6219 UNREACHABLE(); // only called during NGen
6222 /***********************************************************************/
6223 void CEEInfo::getReadyToRunDelegateCtorHelper(
6224 CORINFO_RESOLVED_TOKEN * pTargetMethod,
6225 CORINFO_CLASS_HANDLE delegateType,
6226 CORINFO_LOOKUP * pLookup
6229 LIMITED_METHOD_CONTRACT;
6230 UNREACHABLE(); // only called during NGen
6233 /***********************************************************************/
6234 // see code:Nullable#NullableVerification
6236 CORINFO_CLASS_HANDLE CEEInfo::getTypeForBox(CORINFO_CLASS_HANDLE cls)
6238 LIMITED_METHOD_CONTRACT;
6240 TypeHandle VMClsHnd(cls);
6241 if (Nullable::IsNullableType(VMClsHnd)) {
6242 VMClsHnd = VMClsHnd.AsMethodTable()->GetInstantiation()[0];
6244 return static_cast<CORINFO_CLASS_HANDLE>(VMClsHnd.AsPtr());
6247 /***********************************************************************/
6248 // see code:Nullable#NullableVerification
6249 CorInfoHelpFunc CEEInfo::getBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6258 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6260 JIT_TO_EE_TRANSITION();
6262 TypeHandle VMClsHnd(clsHnd);
6263 if (Nullable::IsNullableType(VMClsHnd))
6265 result = CORINFO_HELP_BOX_NULLABLE;
6269 // Dev10 718281 - This has been functionally broken fora very long time (at least 2.0).
6270 // The recent addition of the check for stack pointers has caused it to now AV instead
6271 // of gracefully failing with an InvalidOperationException. Since nobody has noticed
6272 // it being broken, we are choosing not to invest to fix it, and instead explicitly
6273 // breaking it and failing early and consistently.
6274 if(VMClsHnd.IsTypeDesc())
6276 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_TypeCannotBeBoxed"));
6279 // we shouldn't allow boxing of types that contains stack pointers
6280 // csc and vbc already disallow it.
6281 if (VMClsHnd.AsMethodTable()->IsByRefLike())
6282 COMPlusThrow(kInvalidProgramException);
6284 result = CORINFO_HELP_BOX;
6287 EE_TO_JIT_TRANSITION();
6292 /***********************************************************************/
6293 CorInfoHelpFunc CEEInfo::getSecurityPrologHelper(CORINFO_METHOD_HANDLE ftn)
6302 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6304 JIT_TO_EE_TRANSITION();
6306 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6307 // This will make sure that when IBC logging is on, we call the slow helper with IBC probe
6308 if (IsCompilingForNGen() &&
6309 GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
6311 result = CORINFO_HELP_SECURITY_PROLOG_FRAMED;
6313 #endif // FEATURE_NATIVE_IMAGE_GENERATION
6315 if (result == CORINFO_HELP_UNDEF)
6317 result = CORINFO_HELP_SECURITY_PROLOG;
6320 EE_TO_JIT_TRANSITION();
6325 /***********************************************************************/
6326 // registers a vararg sig & returns a class-specific cookie for it.
6328 CORINFO_VARARGS_HANDLE CEEInfo::getVarArgsHandle(CORINFO_SIG_INFO *sig,
6329 void **ppIndirection)
6338 CORINFO_VARARGS_HANDLE result = NULL;
6340 if (ppIndirection != NULL)
6341 *ppIndirection = NULL;
6343 JIT_TO_EE_TRANSITION();
6345 Module* module = GetModule(sig->scope);
6347 result = CORINFO_VARARGS_HANDLE(module->GetVASigCookie(Signature(sig->pSig, sig->cbSig)));
6349 EE_TO_JIT_TRANSITION();
6354 bool CEEInfo::canGetVarArgsHandle(CORINFO_SIG_INFO *sig)
6356 LIMITED_METHOD_CONTRACT;
6360 /***********************************************************************/
6361 unsigned CEEInfo::getMethodHash (CORINFO_METHOD_HANDLE ftnHnd)
6370 unsigned result = 0;
6372 JIT_TO_EE_TRANSITION();
6374 MethodDesc* ftn = GetMethod(ftnHnd);
6376 result = (unsigned) ftn->GetStableHash();
6378 EE_TO_JIT_TRANSITION();
6383 /***********************************************************************/
6384 const char* CEEInfo::getMethodName (CORINFO_METHOD_HANDLE ftnHnd, const char** scopeName)
6393 const char* result = NULL;
6395 JIT_TO_EE_TRANSITION();
6399 ftn = GetMethod(ftnHnd);
6403 if (ftn->IsLCGMethod())
6405 *scopeName = "DynamicClass";
6407 else if (ftn->IsILStub())
6409 *scopeName = ILStubResolver::GetStubClassName(ftn);
6413 MethodTable * pMT = ftn->GetMethodTable();
6415 #ifdef FEATURE_SYMDIFF
6416 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SymDiffDump))
6420 ssClsNameBuff.Clear();
6421 ssClsNameBuff.SetUTF8(pMT->GetDebugClassName());
6424 pMT->_GetFullyQualifiedNameForClassNestedAware(ssClsNameBuff);
6429 // Calling _GetFullyQualifiedNameForClass in chk build is very expensive
6430 // since it construct the class name everytime we call this method. In chk
6431 // builds we already have a cheaper way to get the class name -
6432 // GetDebugClassName - which doesn't calculate the class name everytime.
6433 // This results in huge saving in Ngen time for checked builds.
6434 ssClsNameBuff.Clear();
6435 ssClsNameBuff.SetUTF8(pMT->GetDebugClassName());
6437 #ifdef FEATURE_SYMDIFF
6440 // Append generic instantiation at the end
6441 Instantiation inst = pMT->GetInstantiation();
6442 if (!inst.IsEmpty())
6443 TypeString::AppendInst(ssClsNameBuff, inst);
6445 *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
6447 // since this is for diagnostic purposes only,
6448 // give up on the namespace, as we don't have a buffer to concat it
6449 // also note this won't show array class names.
6451 *scopeName= pMT->GetFullyQualifiedNameInfo(&nameSpace);
6456 result = ftn->GetName();
6458 EE_TO_JIT_TRANSITION();
6463 /*********************************************************************/
6464 DWORD CEEInfo::getMethodAttribs (CORINFO_METHOD_HANDLE ftn)
6475 JIT_TO_EE_TRANSITION();
6477 result = getMethodAttribsInternal(ftn);
6479 EE_TO_JIT_TRANSITION();
6484 /*********************************************************************/
6485 DWORD CEEInfo::getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftn)
6487 STANDARD_VM_CONTRACT;
6490 returns method attribute flags (defined in corhdr.h)
6492 NOTE: This doesn't return certain method flags
6493 (mdAssem, mdFamANDAssem, mdFamORAssem, mdPrivateScope)
6496 MethodDesc* pMD = GetMethod(ftn);
6498 if (pMD->IsLCGMethod())
6500 return CORINFO_FLG_STATIC | CORINFO_FLG_DONT_INLINE | CORINFO_FLG_NOSECURITYWRAP;
6503 DWORD result = CORINFO_FLG_NOSECURITYWRAP;
6505 // <REVISIT_TODO>@todo: can we git rid of CORINFO_FLG_ stuff and just include cor.h?</REVISIT_TODO>
6507 DWORD attribs = pMD->GetAttrs();
6509 if (IsMdFamily(attribs))
6510 result |= CORINFO_FLG_PROTECTED;
6511 if (IsMdStatic(attribs))
6512 result |= CORINFO_FLG_STATIC;
6513 if (pMD->IsSynchronized())
6514 result |= CORINFO_FLG_SYNCH;
6515 if (pMD->IsFCallOrIntrinsic())
6516 result |= CORINFO_FLG_NOGCCHECK | CORINFO_FLG_INTRINSIC;
6517 if (IsMdVirtual(attribs))
6518 result |= CORINFO_FLG_VIRTUAL;
6519 if (IsMdAbstract(attribs))
6520 result |= CORINFO_FLG_ABSTRACT;
6521 if (IsMdRTSpecialName(attribs))
6523 LPCUTF8 pName = pMD->GetName();
6524 if (IsMdInstanceInitializer(attribs, pName) ||
6525 IsMdClassConstructor(attribs, pName))
6526 result |= CORINFO_FLG_CONSTRUCTOR;
6530 // See if we need to embed a .cctor call at the head of the
6534 MethodTable* pMT = pMD->GetMethodTable();
6536 // method or class might have the final bit
6537 if (IsMdFinal(attribs) || pMT->IsSealed())
6539 result |= CORINFO_FLG_FINAL;
6542 if (pMD->IsEnCAddedMethod())
6544 result |= CORINFO_FLG_EnC;
6547 if (pMD->IsSharedByGenericInstantiations())
6549 result |= CORINFO_FLG_SHAREDINST;
6552 if (pMD->IsNDirect())
6554 result |= CORINFO_FLG_PINVOKE;
6557 if (IsMdRequireSecObject(attribs))
6559 // Assume all methods marked as DynamicSecurity are
6560 // marked that way because they use StackCrawlMark to identify
6562 // See comments in canInline or canTailCall
6563 result |= CORINFO_FLG_DONT_INLINE_CALLER;
6566 // Check for an inlining directive.
6567 if (pMD->IsNotInline())
6569 /* Function marked as not inlineable */
6570 result |= CORINFO_FLG_DONT_INLINE;
6572 // AggressiveInlining only makes sense for IL methods.
6573 else if (pMD->IsIL() && IsMiAggressiveInlining(pMD->GetImplAttrs()))
6575 result |= CORINFO_FLG_FORCEINLINE;
6578 if (pMT->IsDelegate() && ((DelegateEEClass*)(pMT->GetClass()))->GetInvokeMethod() == pMD)
6580 // This is now used to emit efficient invoke code for any delegate invoke,
6581 // including multicast.
6582 result |= CORINFO_FLG_DELEGATE_INVOKE;
6588 /*********************************************************************/
6589 void CEEInfo::setMethodAttribs (
6590 CORINFO_METHOD_HANDLE ftnHnd,
6591 CorInfoMethodRuntimeFlags attribs)
6600 JIT_TO_EE_TRANSITION();
6602 MethodDesc* ftn = GetMethod(ftnHnd);
6604 if (attribs & CORINFO_FLG_BAD_INLINEE)
6606 BOOL fCacheInliningHint = TRUE;
6608 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6609 if (IsCompilationProcess())
6611 // Since we are running managed code during NGen the inlining hint may be
6612 // changing underneeth us as the code is JITed. We need to prevent the inlining
6613 // hints from changing once we start to use them to place IL in the image.
6614 if (!g_pCEECompileInfo->IsCachingOfInliningHintsEnabled())
6616 fCacheInliningHint = FALSE;
6620 // Don't cache inlining hints inside mscorlib during NGen of other assemblies,
6621 // since mscorlib is loaded domain neutral and will survive worker process recycling,
6622 // causing determinism problems.
6623 Module * pModule = ftn->GetModule();
6624 if (pModule->IsSystem() && pModule->HasNativeImage())
6626 fCacheInliningHint = FALSE;
6632 if (fCacheInliningHint)
6634 ftn->SetNotInline(true);
6638 EE_TO_JIT_TRANSITION();
6641 /*********************************************************************/
6643 void getMethodInfoILMethodHeaderHelper(
6644 COR_ILMETHOD_DECODER* header,
6645 CORINFO_METHOD_INFO* methInfo
6648 LIMITED_METHOD_CONTRACT;
6650 methInfo->ILCode = const_cast<BYTE*>(header->Code);
6651 methInfo->ILCodeSize = header->GetCodeSize();
6652 methInfo->maxStack = static_cast<unsigned short>(header->GetMaxStack());
6653 methInfo->EHcount = static_cast<unsigned short>(header->EHCount());
6656 (CorInfoOptions)((header->GetFlags() & CorILMethod_InitLocals) ? CORINFO_OPT_INIT_LOCALS : 0) ;
6659 mdToken FindGenericMethodArgTypeSpec(IMDInternalImport* pInternalImport)
6661 STANDARD_VM_CONTRACT;
6663 HENUMInternalHolder hEnumTypeSpecs(pInternalImport);
6666 static const BYTE signature[] = { ELEMENT_TYPE_MVAR, 0 };
6668 hEnumTypeSpecs.EnumAllInit(mdtTypeSpec);
6669 while (hEnumTypeSpecs.EnumNext(&token))
6671 PCCOR_SIGNATURE pSig;
6673 IfFailThrow(pInternalImport->GetTypeSpecFromToken(token, &pSig, &cbSig));
6674 if (cbSig == sizeof(signature) && memcmp(pSig, signature, cbSig) == 0)
6678 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6681 /*********************************************************************
6683 IL is the most efficient and portable way to implement certain low level methods
6684 in mscorlib.dll. Unfortunately, there is no good way to link IL into mscorlib.dll today.
6685 Until we find a good way to link IL into mscorlib.dll, we will provide the IL implementation here.
6687 - All IL intrinsincs are members of System.Runtime.CompilerServices.JitHelpers class
6688 - All IL intrinsincs should be kept very simple. Implement the minimal reusable version of
6689 unsafe construct and depend on inlining to do the rest.
6690 - The C# implementation of the IL intrinsic should be good enough for functionalily. Everything should work
6691 correctly (but slower) if the IL intrinsics are removed.
6693 *********************************************************************/
6695 bool getILIntrinsicImplementation(MethodDesc * ftn,
6696 CORINFO_METHOD_INFO * methInfo)
6698 STANDARD_VM_CONTRACT;
6700 // Precondition: ftn is a method in mscorlib
6701 _ASSERTE(ftn->GetModule()->IsSystem());
6703 mdMethodDef tk = ftn->GetMemberDef();
6705 // Compare tokens to cover all generic instantiations
6706 // The body of the first method is simply ret Arg0. The second one first casts the arg to I4.
6708 if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_CAST)->GetMemberDef())
6710 // Return the argument that was passed in.
6711 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
6712 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6713 methInfo->ILCodeSize = sizeof(ilcode);
6714 methInfo->maxStack = 1;
6715 methInfo->EHcount = 0;
6716 methInfo->options = (CorInfoOptions)0;
6719 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_CAST_TO_STACKPTR)->GetMemberDef())
6721 // Return the argument that was passed in converted to IntPtr
6722 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I, CEE_RET };
6723 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6724 methInfo->ILCodeSize = sizeof(ilcode);
6725 methInfo->maxStack = 1;
6726 methInfo->EHcount = 0;
6727 methInfo->options = (CorInfoOptions)0;
6730 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST)->GetMemberDef())
6732 // Normally we would follow the above pattern and unconditionally replace the IL,
6733 // relying on generic type constraints to guarantee that it will only ever be instantiated
6734 // on the type/size of argument we expect.
6736 // However C#/CLR does not support restricting a generic type to be an Enum, so the best
6737 // we can do is constrain it to be a value type. This is fine for run time, since we only
6738 // ever create instantiations on 4 byte or less Enums. But during NGen we may compile instantiations
6739 // on other value types (to be specific, every value type instatiation of EqualityComparer
6740 // because of its TypeDependencyAttribute; here again we would like to restrict this to
6741 // 4 byte or less Enums but cannot).
6743 // This IL is invalid for those instantiations, and replacing it would lead to all sorts of
6744 // errors at NGen time. So we only replace it for instantiations where it would be valid,
6745 // leaving the others, which we should never execute, with the C# implementation of throwing.
6747 _ASSERTE(ftn->HasMethodInstantiation());
6748 Instantiation inst = ftn->GetMethodInstantiation();
6750 _ASSERTE(inst.GetNumArgs() == 1);
6751 CorElementType et = inst[0].GetVerifierCorElementType();
6752 if (et == ELEMENT_TYPE_I4 ||
6753 et == ELEMENT_TYPE_U4 ||
6754 et == ELEMENT_TYPE_I2 ||
6755 et == ELEMENT_TYPE_U2 ||
6756 et == ELEMENT_TYPE_I1 ||
6757 et == ELEMENT_TYPE_U1)
6759 // Cast to I4 and return the argument that was passed in.
6760 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I4, CEE_RET };
6761 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6762 methInfo->ILCodeSize = sizeof(ilcode);
6763 methInfo->maxStack = 1;
6764 methInfo->EHcount = 0;
6765 methInfo->options = (CorInfoOptions)0;
6769 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG)->GetMemberDef())
6771 // The the comment above on why this is is not an unconditional replacement. This case handles
6772 // Enums backed by 8 byte values.
6774 _ASSERTE(ftn->HasMethodInstantiation());
6775 Instantiation inst = ftn->GetMethodInstantiation();
6777 _ASSERTE(inst.GetNumArgs() == 1);
6778 CorElementType et = inst[0].GetVerifierCorElementType();
6779 if (et == ELEMENT_TYPE_I8 ||
6780 et == ELEMENT_TYPE_U8)
6782 // Cast to I8 and return the argument that was passed in.
6783 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I8, CEE_RET };
6784 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6785 methInfo->ILCodeSize = sizeof(ilcode);
6786 methInfo->maxStack = 1;
6787 methInfo->EHcount = 0;
6788 methInfo->options = (CorInfoOptions)0;
6792 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__GET_RAW_SZ_ARRAY_DATA)->GetMemberDef())
6794 mdToken tokArrayPinningHelper = MscorlibBinder::GetField(FIELD__ARRAY_PINNING_HELPER__M_ARRAY_DATA)->GetMemberDef();
6796 static BYTE ilcode[] = { CEE_LDARG_0,
6800 ilcode[2] = (BYTE)(tokArrayPinningHelper);
6801 ilcode[3] = (BYTE)(tokArrayPinningHelper >> 8);
6802 ilcode[4] = (BYTE)(tokArrayPinningHelper >> 16);
6803 ilcode[5] = (BYTE)(tokArrayPinningHelper >> 24);
6805 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6806 methInfo->ILCodeSize = sizeof(ilcode);
6807 methInfo->maxStack = 1;
6808 methInfo->EHcount = 0;
6809 methInfo->options = (CorInfoOptions)0;
6816 bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
6817 CORINFO_METHOD_INFO * methInfo)
6819 STANDARD_VM_CONTRACT;
6821 // Precondition: ftn is a method in mscorlib
6822 _ASSERTE(ftn->GetModule()->IsSystem());
6824 mdMethodDef tk = ftn->GetMemberDef();
6826 if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_POINTER)->GetMemberDef())
6828 // Return the argument that was passed in.
6829 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_U, CEE_RET };
6830 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6831 methInfo->ILCodeSize = sizeof(ilcode);
6832 methInfo->maxStack = 1;
6833 methInfo->EHcount = 0;
6834 methInfo->options = (CorInfoOptions)0;
6837 if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__SIZEOF)->GetMemberDef())
6839 _ASSERTE(ftn->HasMethodInstantiation());
6840 Instantiation inst = ftn->GetMethodInstantiation();
6842 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
6843 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6845 static BYTE ilcode[] = { CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0, CEE_RET };
6847 ilcode[2] = (BYTE)(tokGenericArg);
6848 ilcode[3] = (BYTE)(tokGenericArg >> 8);
6849 ilcode[4] = (BYTE)(tokGenericArg >> 16);
6850 ilcode[5] = (BYTE)(tokGenericArg >> 24);
6852 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6853 methInfo->ILCodeSize = sizeof(ilcode);
6854 methInfo->maxStack = 1;
6855 methInfo->EHcount = 0;
6856 methInfo->options = (CorInfoOptions)0;
6859 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef() ||
6860 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__OBJECT_AS)->GetMemberDef())
6862 // Return the argument that was passed in.
6863 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
6864 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6865 methInfo->ILCodeSize = sizeof(ilcode);
6866 methInfo->maxStack = 1;
6867 methInfo->EHcount = 0;
6868 methInfo->options = (CorInfoOptions)0;
6871 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD)->GetMemberDef() ||
6872 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_ADD)->GetMemberDef())
6874 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6876 static BYTE ilcode[] = { CEE_LDARG_1,
6877 CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0,
6884 ilcode[3] = (BYTE)(tokGenericArg);
6885 ilcode[4] = (BYTE)(tokGenericArg >> 8);
6886 ilcode[5] = (BYTE)(tokGenericArg >> 16);
6887 ilcode[6] = (BYTE)(tokGenericArg >> 24);
6889 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6890 methInfo->ILCodeSize = sizeof(ilcode);
6891 methInfo->maxStack = 2;
6892 methInfo->EHcount = 0;
6893 methInfo->options = (CorInfoOptions)0;
6896 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD_BYTE_OFFSET)->GetMemberDef())
6898 static BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_ADD, CEE_RET };
6900 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6901 methInfo->ILCodeSize = sizeof(ilcode);
6902 methInfo->maxStack = 2;
6903 methInfo->EHcount = 0;
6904 methInfo->options = (CorInfoOptions)0;
6907 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ARE_SAME)->GetMemberDef())
6909 // Compare the two arguments
6910 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CEQ & 0xFF), CEE_RET };
6911 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6912 methInfo->ILCodeSize = sizeof(ilcode);
6913 methInfo->maxStack = 2;
6914 methInfo->EHcount = 0;
6915 methInfo->options = (CorInfoOptions)0;
6918 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_INIT_BLOCK_UNALIGNED)->GetMemberDef())
6920 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 };
6921 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6922 methInfo->ILCodeSize = sizeof(ilcode);
6923 methInfo->maxStack = 3;
6924 methInfo->EHcount = 0;
6925 methInfo->options = (CorInfoOptions)0;
6928 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_READ_UNALIGNED)->GetMemberDef() ||
6929 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_READ_UNALIGNED)->GetMemberDef())
6931 _ASSERTE(ftn->HasMethodInstantiation());
6932 Instantiation inst = ftn->GetMethodInstantiation();
6933 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
6934 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6936 static const BYTE ilcode[]
6939 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
6940 CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6944 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6945 methInfo->ILCodeSize = sizeof(ilcode);
6946 methInfo->maxStack = 2;
6947 methInfo->EHcount = 0;
6948 methInfo->options = (CorInfoOptions)0;
6951 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_WRITE_UNALIGNED)->GetMemberDef() ||
6952 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_WRITE_UNALIGNED)->GetMemberDef())
6954 _ASSERTE(ftn->HasMethodInstantiation());
6955 Instantiation inst = ftn->GetMethodInstantiation();
6956 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
6957 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6959 static const BYTE ilcode[]
6963 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
6964 CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6968 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6969 methInfo->ILCodeSize = sizeof(ilcode);
6970 methInfo->maxStack = 2;
6971 methInfo->EHcount = 0;
6972 methInfo->options = (CorInfoOptions)0;
6979 bool getILIntrinsicImplementationForVolatile(MethodDesc * ftn,
6980 CORINFO_METHOD_INFO * methInfo)
6982 STANDARD_VM_CONTRACT;
6985 // This replaces the implementations of Volatile.* in mscorlib with more efficient ones.
6986 // We do this because we cannot otherwise express these in C#. What we *want* to do is
6987 // to treat the byref args to these methods as "volatile." In pseudo-C#, this would look
6990 // int Read(ref volatile int location)
6995 // However, C# does not yet provide a way to declare a byref as "volatile." So instead,
6996 // we substitute raw IL bodies for these methods that use the correct volatile instructions.
6999 // Precondition: ftn is a method in mscorlib in the System.Threading.Volatile class
7000 _ASSERTE(ftn->GetModule()->IsSystem());
7001 _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__VOLATILE));
7002 _ASSERTE(strcmp(ftn->GetMethodTable()->GetClass()->GetDebugClassName(), "System.Threading.Volatile") == 0);
7004 const size_t VolatileMethodBodySize = 6;
7006 struct VolatileMethodImpl
7008 BinderMethodID methodId;
7009 BYTE body[VolatileMethodBodySize];
7012 #define VOLATILE_IMPL(type, loadinst, storeinst) \
7014 METHOD__VOLATILE__READ_##type, \
7017 CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7019 CEE_NOP, /*pad to VolatileMethodBodySize bytes*/ \
7024 METHOD__VOLATILE__WRITE_##type, \
7028 CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7034 static const VolatileMethodImpl volatileImpls[] =
7036 VOLATILE_IMPL(T, CEE_LDIND_REF, CEE_STIND_REF)
7037 VOLATILE_IMPL(Bool, CEE_LDIND_I1, CEE_STIND_I1)
7038 VOLATILE_IMPL(Int, CEE_LDIND_I4, CEE_STIND_I4)
7039 VOLATILE_IMPL(IntPtr, CEE_LDIND_I, CEE_STIND_I)
7040 VOLATILE_IMPL(UInt, CEE_LDIND_U4, CEE_STIND_I4)
7041 VOLATILE_IMPL(UIntPtr, CEE_LDIND_I, CEE_STIND_I)
7042 VOLATILE_IMPL(SByt, CEE_LDIND_I1, CEE_STIND_I1)
7043 VOLATILE_IMPL(Byte, CEE_LDIND_U1, CEE_STIND_I1)
7044 VOLATILE_IMPL(Shrt, CEE_LDIND_I2, CEE_STIND_I2)
7045 VOLATILE_IMPL(UShrt, CEE_LDIND_U2, CEE_STIND_I2)
7046 VOLATILE_IMPL(Flt, CEE_LDIND_R4, CEE_STIND_R4)
7049 // Ordinary volatile loads and stores only guarantee atomicity for pointer-sized (or smaller) data.
7050 // So, on 32-bit platforms we must use Interlocked operations instead for the 64-bit types.
7051 // The implementation in mscorlib already does this, so we will only substitute a new
7052 // IL body if we're running on a 64-bit platform.
7054 IN_WIN64(VOLATILE_IMPL(Long, CEE_LDIND_I8, CEE_STIND_I8))
7055 IN_WIN64(VOLATILE_IMPL(ULong, CEE_LDIND_I8, CEE_STIND_I8))
7056 IN_WIN64(VOLATILE_IMPL(Dbl, CEE_LDIND_R8, CEE_STIND_R8))
7059 mdMethodDef md = ftn->GetMemberDef();
7060 for (unsigned i = 0; i < NumItems(volatileImpls); i++)
7062 if (md == MscorlibBinder::GetMethod(volatileImpls[i].methodId)->GetMemberDef())
7064 methInfo->ILCode = const_cast<BYTE*>(volatileImpls[i].body);
7065 methInfo->ILCodeSize = VolatileMethodBodySize;
7066 methInfo->maxStack = 2;
7067 methInfo->EHcount = 0;
7068 methInfo->options = (CorInfoOptions)0;
7076 bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn,
7077 CORINFO_METHOD_INFO * methInfo)
7079 STANDARD_VM_CONTRACT;
7081 // Precondition: ftn is a method in mscorlib in the System.Threading.Interlocked class
7082 _ASSERTE(ftn->GetModule()->IsSystem());
7083 _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__INTERLOCKED));
7085 // We are only interested if ftn's token and CompareExchange<T> token match
7086 if (ftn->GetMemberDef() != MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_T)->GetMemberDef())
7089 // Get MethodDesc for System.Threading.Interlocked.CompareExchangeFast()
7090 MethodDesc* cmpxchgFast = MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_OBJECT);
7092 // The MethodDesc lookup must not fail, and it should have the name "CompareExchangeFast"
7093 _ASSERTE(cmpxchgFast != NULL);
7094 _ASSERTE(strcmp(cmpxchgFast->GetName(), "CompareExchange") == 0);
7096 // Setup up the body of the method
7097 static BYTE il[] = {
7105 // Get the token for System.Threading.Interlocked.CompareExchangeFast(), and patch [target]
7106 mdMethodDef cmpxchgFastToken = cmpxchgFast->GetMemberDef();
7107 il[4] = (BYTE)((int)cmpxchgFastToken >> 0);
7108 il[5] = (BYTE)((int)cmpxchgFastToken >> 8);
7109 il[6] = (BYTE)((int)cmpxchgFastToken >> 16);
7110 il[7] = (BYTE)((int)cmpxchgFastToken >> 24);
7112 // Initialize methInfo
7113 methInfo->ILCode = const_cast<BYTE*>(il);
7114 methInfo->ILCodeSize = sizeof(il);
7115 methInfo->maxStack = 3;
7116 methInfo->EHcount = 0;
7117 methInfo->options = (CorInfoOptions)0;
7122 bool getILIntrinsicImplementationForRuntimeHelpers(MethodDesc * ftn,
7123 CORINFO_METHOD_INFO * methInfo)
7125 STANDARD_VM_CONTRACT;
7127 // Precondition: ftn is a method in mscorlib
7128 _ASSERTE(ftn->GetModule()->IsSystem());
7130 mdMethodDef tk = ftn->GetMemberDef();
7132 if (tk == MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_REFERENCE_OR_CONTAINS_REFERENCES)->GetMemberDef())
7134 _ASSERTE(ftn->HasMethodInstantiation());
7135 Instantiation inst = ftn->GetMethodInstantiation();
7137 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7138 TypeHandle typeHandle = inst[0];
7139 MethodTable * methodTable = typeHandle.GetMethodTable();
7141 static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
7142 static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };
7144 if (!methodTable->IsValueType() || methodTable->ContainsPointers())
7146 methInfo->ILCode = const_cast<BYTE*>(returnTrue);
7150 methInfo->ILCode = const_cast<BYTE*>(returnFalse);
7153 methInfo->ILCodeSize = sizeof(returnTrue);
7154 methInfo->maxStack = 1;
7155 methInfo->EHcount = 0;
7156 methInfo->options = (CorInfoOptions)0;
7163 //---------------------------------------------------------------------------------------
7167 getMethodInfoHelper(
7169 CORINFO_METHOD_HANDLE ftnHnd,
7170 COR_ILMETHOD_DECODER * header,
7171 CORINFO_METHOD_INFO * methInfo)
7173 STANDARD_VM_CONTRACT;
7175 _ASSERTE(ftn == GetMethod(ftnHnd));
7177 methInfo->ftn = ftnHnd;
7178 methInfo->scope = GetScopeHandle(ftn);
7179 methInfo->regionKind = CORINFO_REGION_JIT;
7181 // For Jitted code the regionKind is JIT;
7182 // For Ngen-ed code the zapper will set this to HOT or COLD, if we
7183 // are using IBC data to partition methods into Hot/Cold regions
7185 /* Grab information from the IL header */
7187 PCCOR_SIGNATURE pLocalSig = NULL;
7188 DWORD cbLocalSig = 0;
7192 bool fILIntrinsic = false;
7194 MethodTable * pMT = ftn->GetMethodTable();
7196 if (pMT->GetModule()->IsSystem())
7198 if (MscorlibBinder::IsClass(pMT, CLASS__JIT_HELPERS))
7200 fILIntrinsic = getILIntrinsicImplementation(ftn, methInfo);
7202 else if (MscorlibBinder::IsClass(pMT, CLASS__UNSAFE))
7204 fILIntrinsic = getILIntrinsicImplementationForUnsafe(ftn, methInfo);
7206 else if (MscorlibBinder::IsClass(pMT, CLASS__INTERLOCKED))
7208 fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo);
7210 else if (MscorlibBinder::IsClass(pMT, CLASS__VOLATILE))
7212 fILIntrinsic = getILIntrinsicImplementationForVolatile(ftn, methInfo);
7214 else if (MscorlibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS))
7216 fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo);
7222 getMethodInfoILMethodHeaderHelper(header, methInfo);
7224 // Workaround for https://github.com/dotnet/coreclr/issues/1279
7225 // Set init locals bit to zero for system module unless profiler may have overrided it. Remove once we have
7226 // better solution for this issue.
7227 if (pMT->GetModule()->IsSystem() && !(CORProfilerDisableAllNGenImages() || CORProfilerUseProfileImages()))
7228 methInfo->options = (CorInfoOptions)0;
7230 pLocalSig = header->LocalVarSig;
7231 cbLocalSig = header->cbLocalVarSig;
7236 _ASSERTE(ftn->IsDynamicMethod());
7238 DynamicResolver * pResolver = ftn->AsDynamicMethodDesc()->GetResolver();
7239 unsigned int EHCount;
7240 methInfo->ILCode = pResolver->GetCodeInfo(&methInfo->ILCodeSize,
7241 &methInfo->maxStack,
7244 methInfo->EHcount = (unsigned short)EHCount;
7245 SigPointer localSig = pResolver->GetLocalSig();
7246 localSig.GetSignature(&pLocalSig, &cbLocalSig);
7249 methInfo->options = (CorInfoOptions)(((UINT32)methInfo->options) |
7250 ((ftn->AcquiresInstMethodTableFromThis() ? CORINFO_GENERICS_CTXT_FROM_THIS : 0) |
7251 (ftn->RequiresInstMethodTableArg() ? CORINFO_GENERICS_CTXT_FROM_METHODTABLE : 0) |
7252 (ftn->RequiresInstMethodDescArg() ? CORINFO_GENERICS_CTXT_FROM_METHODDESC : 0)));
7254 // EEJitManager::ResolveEHClause and CrawlFrame::GetExactGenericInstantiations
7255 // need to be able to get to CORINFO_GENERICS_CTXT_MASK if there are any
7256 // catch clauses like "try {} catch(MyException<T> e) {}".
7257 // Such constructs are rare, and having to extend the lifetime of variable
7258 // for such cases is reasonable
7260 if (methInfo->options & CORINFO_GENERICS_CTXT_MASK)
7262 #if defined(PROFILING_SUPPORTED)
7263 BOOL fProfilerRequiresGenericsContextForEnterLeave = FALSE;
7265 BEGIN_PIN_PROFILER(CORProfilerPresent());
7266 if (g_profControlBlock.pProfInterface->RequiresGenericsContextForEnterLeave())
7268 fProfilerRequiresGenericsContextForEnterLeave = TRUE;
7272 if (fProfilerRequiresGenericsContextForEnterLeave)
7274 methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7277 #endif // defined(PROFILING_SUPPORTED)
7279 // Check all the exception clauses
7281 if (ftn->IsDynamicMethod())
7283 // @TODO: how do we detect the need to mark this flag?
7287 COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
7289 for (unsigned i = 0; i < methInfo->EHcount; i++)
7291 const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo =
7292 (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)header->EH->EHClause(i, &ehClause);
7294 // Is it a typed catch clause?
7295 if (ehInfo->GetFlags() != COR_ILEXCEPTION_CLAUSE_NONE)
7298 // Check if we catch "C<T>" ?
7300 DWORD catchTypeToken = ehInfo->GetClassToken();
7301 if (TypeFromToken(catchTypeToken) != mdtTypeSpec)
7304 PCCOR_SIGNATURE pSig;
7306 IfFailThrow(ftn->GetMDImport()->GetTypeSpecFromToken(catchTypeToken, &pSig, &cSig));
7308 SigPointer psig(pSig, cSig);
7310 SigTypeContext sigTypeContext(ftn);
7311 if (psig.IsPolyType(&sigTypeContext) & hasSharableVarsMask)
7313 methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7321 PCCOR_SIGNATURE pSig = NULL;
7323 ftn->GetSig(&pSig, &cbSig);
7325 /* Fetch the method signature */
7326 // Type parameters in the signature should be instantiated according to the
7327 // class/method/array instantiation of ftnHnd
7328 CEEInfo::ConvToJitSig(
7331 GetScopeHandle(ftn),
7337 // Shared generic or static per-inst methods and shared methods on generic structs
7338 // take an extra argument representing their instantiation
7339 if (ftn->RequiresInstArg())
7340 methInfo->args.callConv = (CorInfoCallConv)(methInfo->args.callConv | CORINFO_CALLCONV_PARAMTYPE);
7342 _ASSERTE((IsMdStatic(ftn->GetAttrs()) == 0) == ((methInfo->args.callConv & CORINFO_CALLCONV_HASTHIS) != 0));
7344 /* And its local variables */
7345 // Type parameters in the signature should be instantiated according to the
7346 // class/method/array instantiation of ftnHnd
7347 CEEInfo::ConvToJitSig(
7350 GetScopeHandle(ftn),
7355 } // getMethodInfoHelper
7357 //---------------------------------------------------------------------------------------
7360 CEEInfo::getMethodInfo(
7361 CORINFO_METHOD_HANDLE ftnHnd,
7362 CORINFO_METHOD_INFO * methInfo)
7371 bool result = false;
7373 JIT_TO_EE_TRANSITION();
7375 MethodDesc * ftn = GetMethod(ftnHnd);
7377 if (!ftn->IsDynamicMethod() && (!ftn->IsIL() || !ftn->GetRVA() || ftn->IsWrapperStub()))
7379 /* Return false if not IL or has no code */
7384 /* Get the IL header */
7386 if (ftn->IsDynamicMethod())
7388 getMethodInfoHelper(ftn, ftnHnd, NULL, methInfo);
7392 COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
7394 getMethodInfoHelper(ftn, ftnHnd, &header, methInfo);
7397 LOG((LF_JIT, LL_INFO100000, "Getting method info (possible inline) %s::%s%s\n",
7398 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
7403 EE_TO_JIT_TRANSITION();
7410 /************************************************************************
7411 Return true when ftn contains a local of type CLASS__STACKCRAWMARK
7414 bool containsStackCrawlMarkLocal(MethodDesc* ftn)
7416 STANDARD_VM_CONTRACT;
7418 COR_ILMETHOD* ilHeader = ftn->GetILHeader();
7421 COR_ILMETHOD_DECODER header(ilHeader, ftn->GetMDImport(), NULL);
7423 if (header.LocalVarSig == NULL)
7426 SigPointer ptr(header.LocalVarSig, header.cbLocalVarSig);
7428 IfFailThrow(ptr.GetData(NULL)); // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
7431 IfFailThrow(ptr.GetData(&numLocals));
7433 for(ULONG i = 0; i < numLocals; i++)
7435 CorElementType eType;
7436 IfFailThrow(ptr.PeekElemType(&eType));
7437 if (eType != ELEMENT_TYPE_VALUETYPE)
7439 IfFailThrow(ptr.SkipExactlyOne());
7443 IfFailThrow(ptr.GetElemType(NULL));
7446 IfFailThrow(ptr.GetToken(&token));
7448 // We are inside mscorlib - simple token match is sufficient
7449 if (token == MscorlibBinder::GetClass(CLASS__STACKCRAWMARK)->GetCl())
7458 /*************************************************************
7459 * Check if the caller and calle are in the same assembly
7460 * i.e. do not inline across assemblies
7461 *************************************************************/
7463 CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller,
7464 CORINFO_METHOD_HANDLE hCallee,
7465 DWORD* pRestrictions)
7474 CorInfoInline result = INLINE_PASS; // By default we pass.
7475 // Do not set pass in the rest of the method.
7476 DWORD dwRestrictions = 0; // By default, no restrictions
7477 const char * szFailReason = NULL; // for reportInlineDecision
7479 JIT_TO_EE_TRANSITION();
7481 // This does not work in the multi-threaded case
7483 // Caller should check this condition first
7484 _ASSERTE(!(CORINFO_FLG_DONT_INLINE & getMethodAttribsInternal(hCallee)));
7487 MethodDesc* pCaller = GetMethod(hCaller);
7488 MethodDesc* pCallee = GetMethod(hCallee);
7490 if (pCallee->IsNoMetadata())
7492 result = INLINE_FAIL;
7493 szFailReason = "Inlinee is NoMetadata";
7497 #ifdef DEBUGGING_SUPPORTED
7499 // If the callee wants debuggable code, don't allow it to be inlined
7502 // Combining the next two lines, and eliminating jitDebuggerFlags, leads to bad codegen in x86 Release builds using Visual C++ 19.00.24215.1.
7503 CORJIT_FLAGS jitDebuggerFlags = GetDebuggerCompileFlags(pCallee->GetModule(), CORJIT_FLAGS());
7504 if (jitDebuggerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE))
7506 result = INLINE_NEVER;
7507 szFailReason = "Inlinee is debuggable";
7513 // The orginal caller is the current method
7514 MethodDesc * pOrigCaller;
7515 pOrigCaller = m_pMethodBeingCompiled;
7516 Module * pOrigCallerModule;
7517 pOrigCallerModule = pOrigCaller->GetLoaderModule();
7519 if (pCallee->IsNotInline())
7521 result = INLINE_NEVER;
7522 szFailReason = "Inlinee is marked as no inline";
7526 // Also check to see if the method requires a security object. This means they call demand and
7527 // shouldn't be inlined.
7528 if (IsMdRequireSecObject(pCallee->GetAttrs()))
7530 result = INLINE_NEVER;
7531 szFailReason = "Inlinee requires a security object (or contains StackCrawlMark)";
7535 // If the method is MethodImpl'd by another method within the same type, then we have
7536 // an issue that the importer will import the wrong body. In this case, we'll just
7537 // disallow inlining because getFunctionEntryPoint will do the right thing.
7539 MethodDesc *pMDDecl = pCallee;
7540 MethodTable *pMT = pMDDecl->GetMethodTable();
7541 MethodDesc *pMDImpl = pMT->MapMethodDeclToMethodImpl(pMDDecl);
7543 if (pMDDecl != pMDImpl)
7545 result = INLINE_NEVER;
7546 szFailReason = "Inlinee is MethodImpl'd by another method within the same type";
7552 // Perform the Cross-Assembly inlining checks
7555 Module * pCalleeModule = pCallee->GetModule();
7557 #ifdef FEATURE_PREJIT
7558 Assembly * pCalleeAssembly = pCalleeModule->GetAssembly();
7562 // Make sure that all methods with StackCrawlMark are marked as IsMdRequireSecObject
7564 if (pCalleeAssembly->IsSystem())
7566 _ASSERTE(!containsStackCrawlMarkLocal(pCallee));
7570 // To allow for servicing of Ngen images we want to disable most
7571 // Cross-Assembly inlining except for the cases that we explicitly allow.
7573 if (IsCompilingForNGen())
7575 // This is an canInline call at Ngen time
7578 Assembly * pOrigCallerAssembly = pOrigCallerModule->GetAssembly();
7580 if (pCalleeAssembly == pOrigCallerAssembly)
7582 // Within the same assembly
7583 // we can freely inline with no restrictions
7587 #ifdef FEATURE_READYTORUN_COMPILER
7588 // No inlinining for version resilient code except if in the same version bubble
7589 // If this condition changes, please make the corresponding change
7590 // in getCallInfo, too.
7591 if (IsReadyToRunCompilation() &&
7593 !IsInSameVersionBubble(pCaller, pCallee)
7596 result = INLINE_NEVER;
7597 szFailReason = "Cross-module inlining in version resilient code";
7603 #endif // FEATURE_PREJIT
7605 // TODO: We can probably be smarter here if the caller is jitted, as we will
7606 // know for sure if the inlinee has really no string interning active (currently
7607 // it's only on in the ngen case (besides requiring the attribute)), but this is getting
7608 // too subtle. Will only do if somebody screams about it, as bugs here are going to
7610 if ((pOrigCallerModule != pCalleeModule) && pCalleeModule->IsNoStringInterning())
7612 dwRestrictions |= INLINE_NO_CALLEE_LDSTR;
7615 // The remoting interception can be skipped only if the call is on same this pointer
7616 if (pCallee->MayBeRemotingIntercepted())
7618 dwRestrictions |= INLINE_SAME_THIS;
7622 #ifdef PROFILING_SUPPORTED
7623 if (CORProfilerPresent())
7627 // Currently the rejit path is the only path which sets this.
7628 // If we get more reasons to set this then we may need to change
7629 // the failure reason message or disambiguate them.
7630 if (!m_allowInlining)
7632 result = INLINE_FAIL;
7633 szFailReason = "ReJIT request disabled inlining from caller";
7637 // If the profiler has set a mask preventing inlining, always return
7638 // false to the jit.
7639 if (CORProfilerDisableInlining())
7641 result = INLINE_FAIL;
7642 szFailReason = "Profiler disabled inlining globally";
7646 // If the profiler wishes to be notified of JIT events and the result from
7647 // the above tests will cause a function to be inlined, we need to tell the
7648 // profiler that this inlining is going to take place, and give them a
7649 // chance to prevent it.
7651 BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo());
7652 if (pCaller->IsILStub() || pCallee->IsILStub())
7660 HRESULT hr = g_profControlBlock.pProfInterface->JITInlining(
7661 (FunctionID)pCaller,
7662 (FunctionID)pCallee,
7665 if (SUCCEEDED(hr) && !fShouldInline)
7667 result = INLINE_FAIL;
7668 szFailReason = "Profiler disabled inlining locally";
7675 #endif // PROFILING_SUPPORTED
7679 EE_TO_JIT_TRANSITION();
7681 if (result == INLINE_PASS && dwRestrictions)
7685 *pRestrictions = dwRestrictions;
7689 // If the jitter didn't want to know about restrictions, it shouldn't be inlining
7690 result = INLINE_FAIL;
7691 szFailReason = "Inlinee has restrictions the JIT doesn't want";
7698 // Denied inlining, makes no sense to pass out restrictions,
7703 if (dontInline(result))
7705 // If you hit this assert, it means you added a new way to prevent inlining
7706 // without documenting it for ETW!
7707 _ASSERTE(szFailReason != NULL);
7708 reportInliningDecision(hCaller, hCallee, result, szFailReason);
7714 void CEEInfo::reportInliningDecision (CORINFO_METHOD_HANDLE inlinerHnd,
7715 CORINFO_METHOD_HANDLE inlineeHnd,
7716 CorInfoInline inlineResult,
7717 const char * reason)
7719 STATIC_CONTRACT_THROWS;
7720 STATIC_CONTRACT_GC_TRIGGERS;
7721 STATIC_CONTRACT_SO_TOLERANT;
7723 JIT_TO_EE_TRANSITION();
7726 if (LoggingOn(LF_JIT, LL_INFO100000))
7728 SString currentMethodName;
7729 currentMethodName.AppendUTF8(m_pMethodBeingCompiled->GetModule_NoLogging()->GetFile()->GetSimpleName());
7730 currentMethodName.Append(L'/');
7731 TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled, TypeString::FormatBasic);
7733 SString inlineeMethodName;
7734 if (GetMethod(inlineeHnd))
7736 inlineeMethodName.AppendUTF8(GetMethod(inlineeHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
7737 inlineeMethodName.Append(L'/');
7738 TypeString::AppendMethodInternal(inlineeMethodName, GetMethod(inlineeHnd), TypeString::FormatBasic);
7742 inlineeMethodName.AppendASCII( "<null>" );
7745 SString inlinerMethodName;
7746 if (GetMethod(inlinerHnd))
7748 inlinerMethodName.AppendUTF8(GetMethod(inlinerHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
7749 inlinerMethodName.Append(L'/');
7750 TypeString::AppendMethodInternal(inlinerMethodName, GetMethod(inlinerHnd), TypeString::FormatBasic);
7754 inlinerMethodName.AppendASCII("<null>");
7757 if (dontInline(inlineResult))
7759 LOG((LF_JIT, LL_INFO100000,
7760 "While compiling '%S', inline of '%S' into '%S' failed because: '%s'.\n",
7761 currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
7762 inlinerMethodName.GetUnicode(), reason));
7766 LOG((LF_JIT, LL_INFO100000, "While compiling '%S', inline of '%S' into '%S' succeeded.\n",
7767 currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
7768 inlinerMethodName.GetUnicode()));
7774 //I'm gonna duplicate this code because the format is slightly different. And LoggingOn is debug only.
7775 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
7776 TRACE_LEVEL_VERBOSE,
7777 CLR_JITTRACING_KEYWORD))
7779 SString methodBeingCompiledNames[3];
7780 SString inlinerNames[3];
7781 SString inlineeNames[3];
7782 MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
7783 #define GMI(pMD, strArray) \
7786 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
7788 (strArray)[0].Set(W("<null>")); \
7789 (strArray)[1].Set(W("<null>")); \
7790 (strArray)[2].Set(W("<null>")); \
7793 GMI(methodBeingCompiled, methodBeingCompiledNames);
7794 GMI(GetMethod(inlinerHnd), inlinerNames);
7795 GMI(GetMethod(inlineeHnd), inlineeNames);
7797 if (dontInline(inlineResult))
7799 const char * str = (reason ? reason : "");
7801 FireEtwMethodJitInliningFailed(methodBeingCompiledNames[0].GetUnicode(),
7802 methodBeingCompiledNames[1].GetUnicode(),
7803 methodBeingCompiledNames[2].GetUnicode(),
7804 inlinerNames[0].GetUnicode(),
7805 inlinerNames[1].GetUnicode(),
7806 inlinerNames[2].GetUnicode(),
7807 inlineeNames[0].GetUnicode(),
7808 inlineeNames[1].GetUnicode(),
7809 inlineeNames[2].GetUnicode(),
7810 inlineResult == INLINE_NEVER,
7812 GetClrInstanceId());
7816 FireEtwMethodJitInliningSucceeded(methodBeingCompiledNames[0].GetUnicode(),
7817 methodBeingCompiledNames[1].GetUnicode(),
7818 methodBeingCompiledNames[2].GetUnicode(),
7819 inlinerNames[0].GetUnicode(),
7820 inlinerNames[1].GetUnicode(),
7821 inlinerNames[2].GetUnicode(),
7822 inlineeNames[0].GetUnicode(),
7823 inlineeNames[1].GetUnicode(),
7824 inlineeNames[2].GetUnicode(),
7825 GetClrInstanceId());
7830 EE_TO_JIT_TRANSITION();
7834 /*************************************************************
7835 This loads the (formal) declared constraints on the class and method type parameters,
7836 and detects (but does not itself reject) circularities among the class type parameters
7837 and (separately) method type parameters.
7839 It must be called whenever we verify a typical method, ie any method (generic or
7840 nongeneric) in a typical class. It must be called for non-generic methods too,
7841 because their bodies may still mention class type parameters which will need to
7842 have their formal constraints loaded in order to perform type compatibility tests.
7844 We have to rule out cycles like "C<U,T> where T:U, U:T" only to avoid looping
7845 in the verifier (ie the T.CanCast(A) would loop calling U.CanCast(A) then
7846 T.CanCastTo(A) etc.). Since the JIT only tries to walk the hierarchy from a type
7847 a parameter when verifying, it should be safe to JIT unverified, but trusted,
7848 instantiations even in the presence of cycle constraints.
7849 @TODO: It should be possible (and easy) to detect cycles much earlier on by
7850 directly inspecting the metadata. All you have to do is check that, for each
7851 of the n type parameters to a class or method there is no path of length n
7852 obtained by following naked type parameter constraints of the same kind.
7853 This can be detected by looking directly at metadata, without actually loading
7854 the typehandles for the naked type parameters.
7855 *************************************************************/
7857 void CEEInfo::initConstraintsForVerification(CORINFO_METHOD_HANDLE hMethod,
7858 BOOL *pfHasCircularClassConstraints,
7859 BOOL *pfHasCircularMethodConstraints)
7866 PRECONDITION(CheckPointer(pfHasCircularClassConstraints));
7867 PRECONDITION(CheckPointer(pfHasCircularMethodConstraints));
7870 *pfHasCircularClassConstraints = FALSE;
7871 *pfHasCircularMethodConstraints = FALSE;
7873 JIT_TO_EE_TRANSITION();
7875 MethodDesc* pMethod = GetMethod(hMethod);
7876 if (pMethod->IsTypicalMethodDefinition())
7878 // Force a load of the constraints on the type parameters, detecting cyclic bounds
7879 pMethod->LoadConstraintsForTypicalMethodDefinition(pfHasCircularClassConstraints,pfHasCircularMethodConstraints);
7882 EE_TO_JIT_TRANSITION();
7885 /*************************************************************
7886 * Check if a method to be compiled is an instantiation
7887 * of generic code that has already been verified.
7888 * Three possible return values (see corinfo.h)
7889 *************************************************************/
7891 CorInfoInstantiationVerification
7892 CEEInfo::isInstantiationOfVerifiedGeneric(CORINFO_METHOD_HANDLE hMethod)
7901 CorInfoInstantiationVerification result = INSTVER_NOT_INSTANTIATION;
7903 JIT_TO_EE_TRANSITION();
7905 MethodDesc * pMethod = GetMethod(hMethod);
7907 if (!(pMethod->HasClassOrMethodInstantiation()))
7909 result = INSTVER_NOT_INSTANTIATION;
7913 if (pMethod->IsTypicalMethodDefinition())
7915 result = INSTVER_NOT_INSTANTIATION;
7919 result = INSTVER_GENERIC_PASSED_VERIFICATION;
7923 EE_TO_JIT_TRANSITION();
7928 /*************************************************************
7929 * Similar to above, but perform check for tail call
7930 * eligibility. The callee can be passed as NULL if not known
7931 * (calli and callvirt).
7932 *************************************************************/
7934 bool CEEInfo::canTailCall (CORINFO_METHOD_HANDLE hCaller,
7935 CORINFO_METHOD_HANDLE hDeclaredCallee,
7936 CORINFO_METHOD_HANDLE hExactCallee,
7946 bool result = false;
7947 const char * szFailReason = NULL;
7949 JIT_TO_EE_TRANSITION();
7951 // See comments in canInline above.
7953 MethodDesc* pCaller = GetMethod(hCaller);
7954 MethodDesc* pDeclaredCallee = GetMethod(hDeclaredCallee);
7955 MethodDesc* pExactCallee = GetMethod(hExactCallee);
7957 _ASSERTE(pCaller->GetModule());
7958 _ASSERTE(pCaller->GetModule()->GetClassLoader());
7960 _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule());
7961 _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule()->GetClassLoader());
7963 // If the caller is the static constructor (.cctor) of a class which has a ComImport base class
7964 // somewhere up the class hierarchy, then we cannot make the call into a tailcall. See
7965 // RegisterObjectCreationCallback() in ExtensibleClassFactory.cpp for more information.
7966 if (pCaller->IsClassConstructor() &&
7967 pCaller->GetMethodTable()->IsComObjectType())
7970 szFailReason = "Caller is ComImport .cctor";
7976 mdMethodDef callerToken = pCaller->GetMemberDef();
7978 // We don't want to tailcall the entrypoint for an application; JIT64 will sometimes
7979 // do this for simple entrypoints and it results in a rather confusing debugging
7981 if (callerToken == pCaller->GetModule()->GetEntryPointToken())
7984 szFailReason = "Caller is the entry point";
7988 if (!pCaller->IsNoMetadata())
7990 // Do not tailcall from methods that are marked as noinline (people often use no-inline
7991 // to mean "I want to always see this method in stacktrace")
7992 DWORD dwImplFlags = 0;
7993 IfFailThrow(pCaller->GetMDImport()->GetMethodImplProps(callerToken, NULL, &dwImplFlags));
7995 if (IsMiNoInlining(dwImplFlags))
7998 szFailReason = "Caller is marked as no inline";
8003 // Methods with StackCrawlMark depend on finding their caller on the stack.
8004 // If we tail call one of these guys, they get confused. For lack of
8005 // a better way of identifying them, we use DynamicSecurity attribute to identify
8006 // them. We have an assert in canInline that ensures all StackCrawlMark
8007 // methods are appropriately marked.
8009 if ((pExactCallee != NULL) && IsMdRequireSecObject(pExactCallee->GetAttrs()))
8012 szFailReason = "Callee might have a StackCrawlMark.LookForMyCaller";
8022 EE_TO_JIT_TRANSITION();
8026 // If you hit this assert, it means you added a new way to prevent tail calls
8027 // without documenting it for ETW!
8028 _ASSERTE(szFailReason != NULL);
8029 reportTailCallDecision(hCaller, hExactCallee, fIsTailPrefix, TAILCALL_FAIL, szFailReason);
8035 void CEEInfo::reportTailCallDecision (CORINFO_METHOD_HANDLE callerHnd,
8036 CORINFO_METHOD_HANDLE calleeHnd,
8038 CorInfoTailCall tailCallResult,
8039 const char * reason)
8041 STATIC_CONTRACT_THROWS;
8042 STATIC_CONTRACT_GC_TRIGGERS;
8043 STATIC_CONTRACT_SO_TOLERANT;
8045 JIT_TO_EE_TRANSITION();
8047 //put code here. Make sure to report the method being compiled in addition to inliner and inlinee.
8049 if (LoggingOn(LF_JIT, LL_INFO100000))
8051 SString currentMethodName;
8052 TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled,
8053 TypeString::FormatBasic);
8055 SString calleeMethodName;
8056 if (GetMethod(calleeHnd))
8058 TypeString::AppendMethodInternal(calleeMethodName, GetMethod(calleeHnd),
8059 TypeString::FormatBasic);
8063 calleeMethodName.AppendASCII( "<null>" );
8066 SString callerMethodName;
8067 if (GetMethod(callerHnd))
8069 TypeString::AppendMethodInternal(callerMethodName, GetMethod(callerHnd),
8070 TypeString::FormatBasic);
8074 callerMethodName.AppendASCII( "<null>" );
8076 if (tailCallResult == TAILCALL_FAIL)
8078 LOG((LF_JIT, LL_INFO100000,
8079 "While compiling '%S', %Splicit tail call from '%S' to '%S' failed because: '%s'.\n",
8080 currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8081 callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), reason));
8085 static const char * const tailCallType[] = {
8086 "optimized tail call", "recursive loop", "helper assisted tailcall"
8088 _ASSERTE(tailCallResult >= 0 && (size_t)tailCallResult < sizeof(tailCallType) / sizeof(tailCallType[0]));
8089 LOG((LF_JIT, LL_INFO100000,
8090 "While compiling '%S', %Splicit tail call from '%S' to '%S' generated as a %s.\n",
8091 currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8092 callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), tailCallType[tailCallResult]));
8098 // I'm gonna duplicate this code because the format is slightly different. And LoggingOn is debug only.
8099 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
8100 TRACE_LEVEL_VERBOSE,
8101 CLR_JITTRACING_KEYWORD))
8103 SString methodBeingCompiledNames[3];
8104 SString callerNames[3];
8105 SString calleeNames[3];
8106 MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8107 #define GMI(pMD, strArray) \
8110 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8112 (strArray)[0].Set(W("<null>")); \
8113 (strArray)[1].Set(W("<null>")); \
8114 (strArray)[2].Set(W("<null>")); \
8117 GMI(methodBeingCompiled, methodBeingCompiledNames);
8118 GMI(GetMethod(callerHnd), callerNames);
8119 GMI(GetMethod(calleeHnd), calleeNames);
8121 if (tailCallResult == TAILCALL_FAIL)
8123 const char * str = (reason ? reason : "");
8125 FireEtwMethodJitTailCallFailed(methodBeingCompiledNames[0].GetUnicode(),
8126 methodBeingCompiledNames[1].GetUnicode(),
8127 methodBeingCompiledNames[2].GetUnicode(),
8128 callerNames[0].GetUnicode(),
8129 callerNames[1].GetUnicode(),
8130 callerNames[2].GetUnicode(),
8131 calleeNames[0].GetUnicode(),
8132 calleeNames[1].GetUnicode(),
8133 calleeNames[2].GetUnicode(),
8136 GetClrInstanceId());
8140 FireEtwMethodJitTailCallSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8141 methodBeingCompiledNames[1].GetUnicode(),
8142 methodBeingCompiledNames[2].GetUnicode(),
8143 callerNames[0].GetUnicode(),
8144 callerNames[1].GetUnicode(),
8145 callerNames[2].GetUnicode(),
8146 calleeNames[0].GetUnicode(),
8147 calleeNames[1].GetUnicode(),
8148 calleeNames[2].GetUnicode(),
8151 GetClrInstanceId());
8157 EE_TO_JIT_TRANSITION();
8160 void CEEInfo::getEHinfoHelper(
8161 CORINFO_METHOD_HANDLE ftnHnd,
8163 CORINFO_EH_CLAUSE* clause,
8164 COR_ILMETHOD_DECODER* pILHeader)
8166 STANDARD_VM_CONTRACT;
8168 _ASSERTE(CheckPointer(pILHeader->EH));
8169 _ASSERTE(EHnumber < pILHeader->EH->EHCount());
8171 COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
8172 const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo;
8173 ehInfo = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)pILHeader->EH->EHClause(EHnumber, &ehClause);
8175 clause->Flags = (CORINFO_EH_CLAUSE_FLAGS)ehInfo->GetFlags();
8176 clause->TryOffset = ehInfo->GetTryOffset();
8177 clause->TryLength = ehInfo->GetTryLength();
8178 clause->HandlerOffset = ehInfo->GetHandlerOffset();
8179 clause->HandlerLength = ehInfo->GetHandlerLength();
8180 if ((clause->Flags & CORINFO_EH_CLAUSE_FILTER) == 0)
8181 clause->ClassToken = ehInfo->GetClassToken();
8183 clause->FilterOffset = ehInfo->GetFilterOffset();
8186 /*********************************************************************/
8187 // get individual exception handler
8188 void CEEInfo::getEHinfo(
8189 CORINFO_METHOD_HANDLE ftnHnd,
8191 CORINFO_EH_CLAUSE* clause)
8200 JIT_TO_EE_TRANSITION();
8202 MethodDesc * ftn = GetMethod(ftnHnd);
8204 if (IsDynamicMethodHandle(ftnHnd))
8206 GetMethod(ftnHnd)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
8210 COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
8211 getEHinfoHelper(ftnHnd, EHnumber, clause, &header);
8214 EE_TO_JIT_TRANSITION();
8217 //---------------------------------------------------------------------------------------
8220 CEEInfo::getMethodSig(
8221 CORINFO_METHOD_HANDLE ftnHnd,
8222 CORINFO_SIG_INFO * sigRet,
8223 CORINFO_CLASS_HANDLE owner)
8232 JIT_TO_EE_TRANSITION();
8234 getMethodSigInternal(ftnHnd, sigRet, owner);
8236 EE_TO_JIT_TRANSITION();
8239 //---------------------------------------------------------------------------------------
8242 CEEInfo::getMethodSigInternal(
8243 CORINFO_METHOD_HANDLE ftnHnd,
8244 CORINFO_SIG_INFO * sigRet,
8245 CORINFO_CLASS_HANDLE owner)
8247 STANDARD_VM_CONTRACT;
8249 MethodDesc * ftn = GetMethod(ftnHnd);
8251 PCCOR_SIGNATURE pSig = NULL;
8253 ftn->GetSig(&pSig, &cbSig);
8255 // Type parameters in the signature are instantiated
8256 // according to the class/method/array instantiation of ftnHnd and owner
8257 CEEInfo::ConvToJitSig(
8260 GetScopeHandle(ftn),
8268 // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation
8269 if (ftn->RequiresInstArg())
8271 sigRet->callConv = (CorInfoCallConv) (sigRet->callConv | CORINFO_CALLCONV_PARAMTYPE);
8274 // We want the calling convention bit to be consistant with the method attribute bit
8275 _ASSERTE( (IsMdStatic(ftn->GetAttrs()) == 0) == ((sigRet->callConv & CORINFO_CALLCONV_HASTHIS) != 0) );
8278 //---------------------------------------------------------------------------------------
8280 //@GENERICSVER: for a method desc in a typical instantiation of a generic class,
8281 // this will return the typical instantiation of the generic class,
8282 // but only provided type variables are never shared.
8283 // The JIT verifier relies on this behaviour to extract the typical class from an instantiated method's typical method handle.
8285 CORINFO_CLASS_HANDLE
8286 CEEInfo::getMethodClass(
8287 CORINFO_METHOD_HANDLE methodHnd)
8296 CORINFO_CLASS_HANDLE result = NULL;
8298 JIT_TO_EE_TRANSITION();
8300 MethodDesc* method = GetMethod(methodHnd);
8302 if (method->IsDynamicMethod())
8304 DynamicResolver::SecurityControlFlags securityControlFlags = DynamicResolver::Default;
8305 TypeHandle typeOwner;
8307 DynamicResolver* pResolver = method->AsDynamicMethodDesc()->GetResolver();
8308 pResolver->GetJitContext(&securityControlFlags, &typeOwner);
8310 if (!typeOwner.IsNull() && (method == pResolver->GetDynamicMethod()))
8312 result = CORINFO_CLASS_HANDLE(typeOwner.AsPtr());
8318 TypeHandle th = TypeHandle(method->GetMethodTable());
8320 result = CORINFO_CLASS_HANDLE(th.AsPtr());
8323 EE_TO_JIT_TRANSITION();
8328 /***********************************************************************/
8329 CORINFO_MODULE_HANDLE CEEInfo::getMethodModule (CORINFO_METHOD_HANDLE methodHnd)
8338 CORINFO_MODULE_HANDLE result = NULL;
8340 JIT_TO_EE_TRANSITION_LEAF();
8342 MethodDesc* method = GetMethod(methodHnd);
8344 if (method->IsDynamicMethod())
8346 // this should never be called, thus the assert, I don't know if the (non existent) caller
8347 // expects the Module or the scope
8352 result = (CORINFO_MODULE_HANDLE) method->GetModule();
8355 EE_TO_JIT_TRANSITION_LEAF();
8360 /*********************************************************************/
8361 CorInfoIntrinsics CEEInfo::getIntrinsicID(CORINFO_METHOD_HANDLE methodHnd,
8371 CorInfoIntrinsics result = CORINFO_INTRINSIC_Illegal;
8373 JIT_TO_EE_TRANSITION();
8375 if (pMustExpand != NULL)
8377 *pMustExpand = false;
8380 MethodDesc* method = GetMethod(methodHnd);
8382 if (method->IsArray())
8384 ArrayMethodDesc * arrMethod = (ArrayMethodDesc *)method;
8385 result = arrMethod->GetIntrinsicID();
8388 if (method->IsFCall())
8390 result = ECall::GetIntrinsicID(method);
8394 MethodTable * pMT = method->GetMethodTable();
8395 if (pMT->GetModule()->IsSystem() && pMT->IsByRefLike())
8397 if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
8399 // ByReference<T> has just two methods: constructor and Value property
8400 if (method->IsCtor())
8402 result = CORINFO_INTRINSIC_ByReference_Ctor;
8406 _ASSERTE(strcmp(method->GetName(), "get_Value") == 0);
8407 result = CORINFO_INTRINSIC_ByReference_Value;
8409 if (pMustExpand != nullptr)
8411 *pMustExpand = true;
8414 else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__SPAN)))
8416 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__SPAN__GET_ITEM)))
8418 result = CORINFO_INTRINSIC_Span_GetItem;
8421 else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__READONLY_SPAN)))
8423 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__READONLY_SPAN__GET_ITEM)))
8425 result = CORINFO_INTRINSIC_ReadOnlySpan_GetItem;
8431 EE_TO_JIT_TRANSITION();
8436 /*********************************************************************/
8437 bool CEEInfo::isInSIMDModule(CORINFO_CLASS_HANDLE classHnd)
8446 bool result = false;
8447 JIT_TO_EE_TRANSITION_LEAF();
8449 TypeHandle VMClsHnd(classHnd);
8450 if (VMClsHnd.GetMethodTable()->GetAssembly()->IsSIMDVectorAssembly())
8454 EE_TO_JIT_TRANSITION_LEAF();
8459 /*********************************************************************/
8460 void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd,
8461 unsigned * pOffsetOfIndirection,
8462 unsigned * pOffsetAfterIndirection,
8472 JIT_TO_EE_TRANSITION_LEAF();
8474 MethodDesc* method = GetMethod(methodHnd);
8476 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8477 _ASSERTE(!method->HasMethodInstantiation());
8479 _ASSERTE(MethodTable::GetVtableOffset() < 256); // a rough sanity check
8481 // better be in the vtable
8482 _ASSERTE(method->GetSlot() < method->GetMethodTable()->GetNumVirtuals());
8484 *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * sizeof(MethodTable::VTableIndir_t);
8485 *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * sizeof(PCODE);
8486 *isRelative = MethodTable::VTableIndir_t::isRelative ? 1 : 0;
8488 EE_TO_JIT_TRANSITION_LEAF();
8491 /*********************************************************************/
8492 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethodHelper(CORINFO_METHOD_HANDLE baseMethod,
8493 CORINFO_CLASS_HANDLE derivedClass,
8494 CORINFO_CONTEXT_HANDLE ownerType)
8502 MethodDesc* pBaseMD = GetMethod(baseMethod);
8503 MethodTable* pBaseMT = pBaseMD->GetMethodTable();
8505 // Method better be from a fully loaded class
8506 _ASSERTE(pBaseMD->IsRestored() && pBaseMT->IsFullyLoaded());
8508 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8509 _ASSERTE(!pBaseMD->HasMethodInstantiation());
8511 // Method better be virtual
8512 _ASSERTE(pBaseMD->IsVirtual());
8514 MethodDesc* pDevirtMD = nullptr;
8516 TypeHandle DerivedClsHnd(derivedClass);
8517 MethodTable* pDerivedMT = DerivedClsHnd.GetMethodTable();
8518 _ASSERTE(pDerivedMT->IsRestored() && pDerivedMT->IsFullyLoaded());
8520 // Can't devirtualize from __Canon.
8521 if (DerivedClsHnd == TypeHandle(g_pCanonMethodTableClass))
8526 if (pBaseMT->IsInterface())
8529 #ifdef FEATURE_COMINTEROP
8530 // Don't try and devirtualize com interface calls.
8531 if (pDerivedMT->IsComObjectType())
8535 #endif // FEATURE_COMINTEROP
8537 // Interface call devirtualization.
8539 // We must ensure that pDerivedMT actually implements the
8540 // interface corresponding to pBaseMD.
8541 if (!pDerivedMT->CanCastToInterface(pBaseMT))
8546 // For generic interface methods we must have an ownerType to
8547 // safely devirtualize.
8548 if (ownerType != nullptr)
8550 TypeHandle OwnerClsHnd = GetTypeFromContext(ownerType);
8551 MethodTable* pOwnerMT = OwnerClsHnd.GetMethodTable();
8553 // If the derived class is a shared class, make sure the
8554 // owner class is too.
8555 if (pDerivedMT->IsSharedByGenericInstantiations())
8557 pOwnerMT = pOwnerMT->GetCanonicalMethodTable();
8560 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(TypeHandle(pOwnerMT), pBaseMD);
8562 else if (!pBaseMD->HasClassOrMethodInstantiation())
8564 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(pBaseMD);
8573 // Virtual call devirtualization.
8575 // The derived class should be a subclass of the the base class.
8576 MethodTable* pCheckMT = pDerivedMT;
8578 while (pCheckMT != nullptr)
8580 if (pCheckMT->HasSameTypeDefAs(pBaseMT))
8585 pCheckMT = pCheckMT->GetParentMethodTable();
8588 if (pCheckMT == nullptr)
8593 // The base method should be in the base vtable
8594 WORD slot = pBaseMD->GetSlot();
8595 _ASSERTE(slot < pBaseMT->GetNumVirtuals());
8597 // Fetch the method that would be invoked if the class were
8598 // exactly derived class. It is up to the jit to determine whether
8599 // directly calling this method is correct.
8600 pDevirtMD = pDerivedMT->GetMethodDescForSlot(slot);
8603 _ASSERTE(pDevirtMD->IsRestored());
8605 #ifdef FEATURE_READYTORUN_COMPILER
8606 // Check if devirtualization is dependent upon cross-version
8607 // bubble information and if so, disallow it.
8608 if (IsReadyToRunCompilation())
8610 MethodDesc* callerMethod = m_pMethodBeingCompiled;
8611 Assembly* pCallerAssembly = callerMethod->GetModule()->GetAssembly();
8613 IsInSameVersionBubble(pCallerAssembly , pDevirtMD->GetModule()->GetAssembly())
8614 && IsInSameVersionBubble(pCallerAssembly , pDerivedMT->GetAssembly());
8623 return (CORINFO_METHOD_HANDLE) pDevirtMD;
8626 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethod(CORINFO_METHOD_HANDLE methodHnd,
8627 CORINFO_CLASS_HANDLE derivedClass,
8628 CORINFO_CONTEXT_HANDLE ownerType)
8637 CORINFO_METHOD_HANDLE result = nullptr;
8639 JIT_TO_EE_TRANSITION();
8641 result = resolveVirtualMethodHelper(methodHnd, derivedClass, ownerType);
8643 EE_TO_JIT_TRANSITION();
8648 void CEEInfo::expandRawHandleIntrinsic(
8649 CORINFO_RESOLVED_TOKEN * pResolvedToken,
8650 CORINFO_GENERICHANDLE_RESULT * pResult)
8652 LIMITED_METHOD_CONTRACT;
8653 UNREACHABLE(); // only called with CoreRT.
8656 /*********************************************************************/
8657 void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd,
8658 CORINFO_CONST_LOOKUP * pResult,
8659 CORINFO_ACCESS_FLAGS accessFlags)
8669 InfoAccessType accessType = IAT_VALUE;
8671 JIT_TO_EE_TRANSITION();
8673 MethodDesc * ftn = GetMethod(ftnHnd);
8674 #if defined(FEATURE_GDBJIT)
8675 MethodDesc * orig_ftn = ftn;
8678 // Resolve methodImpl.
8679 ftn = ftn->GetMethodTable()->MapMethodDeclToMethodImpl(ftn);
8681 ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags);
8683 // TryGetMultiCallableAddrOfCode returns NULL if indirect access is desired
8686 // should never get here for EnC methods or if interception via remoting stub is required
8687 _ASSERTE(!ftn->IsEnCMethod());
8689 _ASSERTE((accessFlags & CORINFO_ACCESS_THIS) || !ftn->IsRemotingInterceptedViaVirtualDispatch());
8691 ret = ftn->GetAddrOfSlot();
8692 accessType = IAT_PVALUE;
8696 #if defined(FEATURE_GDBJIT)
8697 CalledMethod * pCM = new CalledMethod(orig_ftn, ret, m_pCalledMethods);
8698 m_pCalledMethods = pCM;
8701 EE_TO_JIT_TRANSITION();
8703 _ASSERTE(ret != NULL);
8705 pResult->accessType = accessType;
8706 pResult->addr = ret;
8709 /*********************************************************************/
8710 void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn,
8711 CORINFO_CONST_LOOKUP * pResult)
8720 JIT_TO_EE_TRANSITION();
8722 MethodDesc * pMD = GetMethod(ftn);
8724 pResult->accessType = IAT_VALUE;
8727 #ifndef CROSSGEN_COMPILE
8728 // If LDFTN target has [NativeCallable] attribute , then create a UMEntryThunk.
8729 if (pMD->HasNativeCallableAttribute())
8731 pResult->addr = (void*)COMDelegate::ConvertToCallback(pMD);
8734 #endif //CROSSGEN_COMPILE
8736 pResult->addr = (void *)pMD->GetMultiCallableAddrOfCode();
8738 EE_TO_JIT_TRANSITION();
8741 /*********************************************************************/
8742 const char* CEEInfo::getFieldName (CORINFO_FIELD_HANDLE fieldHnd, const char** scopeName)
8751 const char* result = NULL;
8753 JIT_TO_EE_TRANSITION();
8755 FieldDesc* field = (FieldDesc*) fieldHnd;
8758 TypeHandle t = TypeHandle(field->GetApproxEnclosingMethodTable());
8763 t.GetName(ssClsNameBuff);
8764 *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
8766 // since this is for diagnostic purposes only,
8767 // give up on the namespace, as we don't have a buffer to concat it
8768 // also note this won't show array class names.
8770 *scopeName= t.GetMethodTable()->GetFullyQualifiedNameInfo(&nameSpace);
8775 result = field->GetName();
8777 EE_TO_JIT_TRANSITION();
8782 /*********************************************************************/
8783 // Get the type that declares the field
8784 CORINFO_CLASS_HANDLE CEEInfo::getFieldClass (CORINFO_FIELD_HANDLE fieldHnd)
8793 CORINFO_CLASS_HANDLE result = NULL;
8795 JIT_TO_EE_TRANSITION_LEAF();
8797 FieldDesc* field = (FieldDesc*) fieldHnd;
8798 result = CORINFO_CLASS_HANDLE(field->GetApproxEnclosingMethodTable());
8800 EE_TO_JIT_TRANSITION_LEAF();
8805 /*********************************************************************/
8806 // Returns the basic type of the field (not the the type that declares the field)
8808 // pTypeHnd - On return, for reference and value types, *pTypeHnd will contain
8809 // the normalized type of the field.
8810 // owner - Optional. For resolving in a generic context
8812 CorInfoType CEEInfo::getFieldType (CORINFO_FIELD_HANDLE fieldHnd,
8813 CORINFO_CLASS_HANDLE* pTypeHnd,
8814 CORINFO_CLASS_HANDLE owner)
8823 CorInfoType result = CORINFO_TYPE_UNDEF;
8825 JIT_TO_EE_TRANSITION();
8827 result = getFieldTypeInternal(fieldHnd, pTypeHnd, owner);
8829 EE_TO_JIT_TRANSITION();
8834 /*********************************************************************/
8835 CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd,
8836 CORINFO_CLASS_HANDLE* pTypeHnd,
8837 CORINFO_CLASS_HANDLE owner)
8839 STANDARD_VM_CONTRACT;
8843 TypeHandle clsHnd = TypeHandle();
8844 FieldDesc* field = (FieldDesc*) fieldHnd;
8845 CorElementType type = field->GetFieldType();
8847 // <REVISIT_TODO>TODO should not burn the time to do this for anything but Value Classes</REVISIT_TODO>
8848 _ASSERTE(type != ELEMENT_TYPE_BYREF);
8850 if (type == ELEMENT_TYPE_I)
8852 PTR_MethodTable enclosingMethodTable = field->GetApproxEnclosingMethodTable();
8853 if (enclosingMethodTable->IsByRefLike() && enclosingMethodTable->HasSameTypeDefAs(g_pByReferenceClass))
8855 _ASSERTE(field->GetOffset() == 0);
8856 return CORINFO_TYPE_BYREF;
8860 if (!CorTypeInfo::IsPrimitiveType(type))
8862 PCCOR_SIGNATURE sig;
8864 CorCallingConvention conv;
8866 field->GetSig(&sig, &sigCount);
8868 conv = (CorCallingConvention)CorSigUncompressCallingConv(sig);
8869 _ASSERTE(isCallConv(conv, IMAGE_CEE_CS_CALLCONV_FIELD));
8871 SigPointer ptr(sig, sigCount);
8873 // For verifying code involving generics, use the class instantiation
8874 // of the optional owner (to provide exact, not representative,
8875 // type information)
8876 SigTypeContext typeContext(field, (TypeHandle)owner);
8878 clsHnd = ptr.GetTypeHandleThrowing(field->GetModule(), &typeContext);
8879 _ASSERTE(!clsHnd.IsNull());
8881 // I believe it doesn't make any diff. if this is GetInternalCorElementType
8882 // or GetSignatureCorElementType.
8883 type = clsHnd.GetSignatureCorElementType();
8886 return CEEInfo::asCorInfoType(type, clsHnd, pTypeHnd);
8889 /*********************************************************************/
8890 unsigned CEEInfo::getFieldOffset (CORINFO_FIELD_HANDLE fieldHnd)
8899 unsigned result = (unsigned) -1;
8901 JIT_TO_EE_TRANSITION();
8903 FieldDesc* field = (FieldDesc*) fieldHnd;
8905 // GetOffset() does not include the size of Object
8906 result = field->GetOffset();
8908 // So if it is not a value class, add the Object into it
8909 if (field->IsStatic())
8911 Module* pModule = field->GetModule();
8912 if (field->IsRVA() && pModule->IsRvaFieldTls(field->GetOffset()))
8914 result = pModule->GetFieldTlsOffset(field->GetOffset());
8917 else if (!field->GetApproxEnclosingMethodTable()->IsValueType())
8919 result += sizeof(Object);
8922 EE_TO_JIT_TRANSITION();
8927 /*********************************************************************/
8928 bool CEEInfo::isWriteBarrierHelperRequired(CORINFO_FIELD_HANDLE field)
8937 bool fHelperRequired = false;
8939 JIT_TO_EE_TRANSITION();
8941 FieldDesc * pField = (FieldDesc *)field;
8943 // TODO: jit64 should be switched to the same plan as the i386 jits - use
8944 // getClassGClayout to figure out the need for writebarrier helper, and inline the copying.
8945 // Once this happens, USE_WRITE_BARRIER_HELPERS and CORINFO_FLG_WRITE_BARRIER_HELPER can be removed.
8946 CorElementType type = pField->GetFieldType();
8948 if(CorTypeInfo::IsObjRef(type))
8949 fHelperRequired = true;
8950 else if (type == ELEMENT_TYPE_VALUETYPE)
8952 TypeHandle th = pField->GetFieldTypeHandleThrowing();
8953 _ASSERTE(!th.IsNull());
8954 if(th.GetMethodTable()->ContainsPointers())
8955 fHelperRequired = true;
8958 EE_TO_JIT_TRANSITION();
8960 return fHelperRequired;
8963 /*********************************************************************/
8964 DWORD CEEInfo::getFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE fieldHnd, void **ppIndirection)
8975 if (ppIndirection != NULL)
8976 *ppIndirection = NULL;
8978 JIT_TO_EE_TRANSITION();
8980 FieldDesc* field = (FieldDesc*) fieldHnd;
8981 Module* module = field->GetModule();
8983 _ASSERTE(field->IsRVA()); // Only RVA statics can be thread local
8984 _ASSERTE(module->IsRvaFieldTls(field->GetOffset()));
8986 result = module->GetTlsIndex();
8988 EE_TO_JIT_TRANSITION();
8993 void *CEEInfo::allocateArray(ULONG cBytes)
9002 void * result = NULL;
9004 JIT_TO_EE_TRANSITION();
9006 result = new BYTE [cBytes];
9008 EE_TO_JIT_TRANSITION();
9013 void CEEInfo::freeArray(void *array)
9022 JIT_TO_EE_TRANSITION();
9024 delete [] ((BYTE*) array);
9026 EE_TO_JIT_TRANSITION();
9029 void CEEInfo::getBoundaries(CORINFO_METHOD_HANDLE ftn,
9030 unsigned int *cILOffsets, DWORD **pILOffsets,
9031 ICorDebugInfo::BoundaryTypes *implicitBoundaries)
9040 JIT_TO_EE_TRANSITION();
9042 #ifdef DEBUGGING_SUPPORTED
9043 if (g_pDebugInterface && !IsCompilationProcess())
9045 g_pDebugInterface->getBoundaries(GetMethod(ftn), cILOffsets, pILOffsets,
9046 implicitBoundaries);
9052 *implicitBoundaries = ICorDebugInfo::DEFAULT_BOUNDARIES;
9054 #endif // DEBUGGING_SUPPORTED
9056 EE_TO_JIT_TRANSITION();
9059 void CEEInfo::getVars(CORINFO_METHOD_HANDLE ftn, ULONG32 *cVars, ICorDebugInfo::ILVarInfo **vars,
9069 JIT_TO_EE_TRANSITION();
9071 #ifdef DEBUGGING_SUPPORTED
9072 if (g_pDebugInterface && !IsCompilationProcess())
9074 g_pDebugInterface->getVars(GetMethod(ftn), cVars, vars, extendOthers);
9081 // Just tell the JIT to extend everything.
9082 *extendOthers = true;
9084 #endif // DEBUGGING_SUPPORTED
9086 EE_TO_JIT_TRANSITION();
9089 /*********************************************************************/
9090 CORINFO_ARG_LIST_HANDLE CEEInfo::getArgNext(CORINFO_ARG_LIST_HANDLE args)
9099 CORINFO_ARG_LIST_HANDLE result = NULL;
9101 JIT_TO_EE_TRANSITION();
9103 SigPointer ptr((unsigned __int8*) args);
9104 IfFailThrow(ptr.SkipExactlyOne());
9106 result = (CORINFO_ARG_LIST_HANDLE) ptr.GetPtr();
9108 EE_TO_JIT_TRANSITION();
9114 /*********************************************************************/
9116 CorInfoTypeWithMod CEEInfo::getArgType (
9117 CORINFO_SIG_INFO* sig,
9118 CORINFO_ARG_LIST_HANDLE args,
9119 CORINFO_CLASS_HANDLE* vcTypeRet
9129 CorInfoTypeWithMod result = CorInfoTypeWithMod(CORINFO_TYPE_UNDEF);
9131 JIT_TO_EE_TRANSITION();
9133 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args && (BYTE*) args < (BYTE*) sig->pSig + sig->cbSig);
9134 _ASSERTE((BYTE*) sig->args <= (BYTE*) args);
9135 INDEBUG(*vcTypeRet = CORINFO_CLASS_HANDLE((size_t)INVALID_POINTER_CC));
9137 SigPointer ptr((unsigned __int8*) args);
9138 CorElementType eType;
9139 IfFailThrow(ptr.PeekElemType(&eType));
9140 while (eType == ELEMENT_TYPE_PINNED)
9142 result = CORINFO_TYPE_MOD_PINNED;
9143 IfFailThrow(ptr.GetElemType(NULL));
9144 IfFailThrow(ptr.PeekElemType(&eType));
9147 // Now read off the "real" element type after taking any instantiations into consideration
9148 SigTypeContext typeContext;
9149 GetTypeContext(&sig->sigInst,&typeContext);
9151 Module* pModule = GetModule(sig->scope);
9153 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9155 TypeHandle typeHnd = TypeHandle();
9157 case ELEMENT_TYPE_VAR :
9158 case ELEMENT_TYPE_MVAR :
9159 case ELEMENT_TYPE_VALUETYPE :
9160 case ELEMENT_TYPE_TYPEDBYREF :
9161 case ELEMENT_TYPE_INTERNAL :
9163 typeHnd = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9164 _ASSERTE(!typeHnd.IsNull());
9166 CorElementType normType = typeHnd.GetInternalCorElementType();
9168 // if we are looking up a value class, don't morph it to a refernece type
9169 // (This can only happen in illegal IL)
9170 if (!CorTypeInfo::IsObjRef(normType) || type != ELEMENT_TYPE_VALUETYPE)
9177 case ELEMENT_TYPE_PTR:
9178 // Load the type eagerly under debugger to make the eval work
9179 if (!isVerifyOnly() && CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
9181 // NOTE: in some IJW cases, when the type pointed at is unmanaged,
9182 // the GetTypeHandle may fail, because there is no TypeDef for such type.
9183 // Usage of GetTypeHandleThrowing would lead to class load exception
9184 TypeHandle thPtr = ptr.GetTypeHandleNT(pModule, &typeContext);
9187 m_pOverride->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(thPtr.AsPtr()));
9192 case ELEMENT_TYPE_VOID:
9193 // void is not valid in local sigs
9194 if (sig->flags & CORINFO_SIGFLAG_IS_LOCAL_SIG)
9195 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
9198 case ELEMENT_TYPE_END:
9199 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9206 result = CorInfoTypeWithMod(result | CEEInfo::asCorInfoType(type, typeHnd, vcTypeRet));
9207 EE_TO_JIT_TRANSITION();
9212 /*********************************************************************/
9214 CORINFO_CLASS_HANDLE CEEInfo::getArgClass (
9215 CORINFO_SIG_INFO* sig,
9216 CORINFO_ARG_LIST_HANDLE args
9226 CORINFO_CLASS_HANDLE result = NULL;
9228 JIT_TO_EE_TRANSITION();
9230 // make certain we dont have a completely wacked out sig pointer
9231 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args);
9232 _ASSERTE((BYTE*) sig->args <= (BYTE*) args && (BYTE*) args < &((BYTE*) sig->args)[0x10000*5]);
9234 Module* pModule = GetModule(sig->scope);
9236 SigPointer ptr((unsigned __int8*) args);
9238 CorElementType eType;
9239 IfFailThrow(ptr.PeekElemType(&eType));
9241 while (eType == ELEMENT_TYPE_PINNED)
9243 IfFailThrow(ptr.GetElemType(NULL));
9244 IfFailThrow(ptr.PeekElemType(&eType));
9246 // Now read off the "real" element type after taking any instantiations into consideration
9247 SigTypeContext typeContext;
9248 GetTypeContext(&sig->sigInst, &typeContext);
9249 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9251 if (!CorTypeInfo::IsPrimitiveType(type)) {
9252 TypeHandle th = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9253 result = CORINFO_CLASS_HANDLE(th.AsPtr());
9256 EE_TO_JIT_TRANSITION();
9261 /*********************************************************************/
9263 CorInfoType CEEInfo::getHFAType(CORINFO_CLASS_HANDLE hClass)
9272 CorInfoType result = CORINFO_TYPE_UNDEF;
9274 JIT_TO_EE_TRANSITION();
9276 TypeHandle VMClsHnd(hClass);
9278 result = asCorInfoType(VMClsHnd.GetHFAType());
9280 EE_TO_JIT_TRANSITION();
9285 /*********************************************************************/
9287 // return the unmanaged calling convention for a PInvoke
9288 CorInfoUnmanagedCallConv CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method)
9297 CorInfoUnmanagedCallConv result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9299 JIT_TO_EE_TRANSITION();
9301 MethodDesc* pMD = NULL;
9302 pMD = GetMethod(method);
9303 _ASSERTE(pMD->IsNDirect());
9308 PInvokeStaticSigInfo sigInfo(pMD, PInvokeStaticSigInfo::NO_THROW_ON_ERROR);
9310 switch (sigInfo.GetCallConv()) {
9311 case pmCallConvCdecl:
9312 result = CORINFO_UNMANAGED_CALLCONV_C;
9314 case pmCallConvStdcall:
9315 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9317 case pmCallConvThiscall:
9318 result = CORINFO_UNMANAGED_CALLCONV_THISCALL;
9321 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9326 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9328 EX_END_CATCH(SwallowAllExceptions)
9329 #else // !_TARGET_X86_
9331 // we have only one calling convention
9333 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9334 #endif // !_TARGET_X86_
9336 EE_TO_JIT_TRANSITION();
9341 /*********************************************************************/
9342 BOOL NDirectMethodDesc::ComputeMarshalingRequired()
9344 WRAPPER_NO_CONTRACT;
9346 return NDirect::MarshalingRequired(this);
9349 /*********************************************************************/
9350 BOOL CEEInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig)
9359 BOOL result = FALSE;
9361 JIT_TO_EE_TRANSITION();
9365 MethodDesc* ftn = GetMethod(method);
9366 _ASSERTE(ftn->IsNDirect());
9367 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9369 #if defined(HAS_NDIRECT_IMPORT_PRECODE)
9370 if (pMD->IsVarArg())
9372 // Varag P/Invoke must not be inlined because its NDirectMethodDesc
9373 // does not contain a meaningful stack size (it is call site specific).
9374 // See code:InlinedCallFrame.UpdateRegDisplay where this is needed.
9377 else if (pMD->MarshalingRequired())
9379 // This is not a no-marshal signature.
9384 // This is a no-marshal non-vararg signature.
9388 // Marshalling is required to lazy initialize the indirection cell
9389 // without NDirectImportPrecode.
9395 // check the call site signature
9396 result = NDirect::MarshalingRequired(
9399 GetModule(callSiteSig->scope));
9402 EE_TO_JIT_TRANSITION();
9407 /*********************************************************************/
9408 // Generate a cookie based on the signature that would needs to be passed
9409 // to CORINFO_HELP_PINVOKE_CALLI
9410 LPVOID CEEInfo::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig,
9411 void **ppIndirection)
9413 WRAPPER_NO_CONTRACT;
9415 return getVarArgsHandle(szMetaSig, ppIndirection);
9418 bool CEEInfo::canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig)
9420 LIMITED_METHOD_CONTRACT;
9425 // Check any constraints on method type arguments
9426 BOOL CEEInfo::satisfiesMethodConstraints(
9427 CORINFO_CLASS_HANDLE parent,
9428 CORINFO_METHOD_HANDLE method)
9437 BOOL result = FALSE;
9439 JIT_TO_EE_TRANSITION();
9441 _ASSERTE(parent != NULL);
9442 _ASSERTE(method != NULL);
9443 result = GetMethod(method)->SatisfiesMethodConstraints(TypeHandle(parent));
9445 EE_TO_JIT_TRANSITION();
9452 /*********************************************************************/
9453 // Given a delegate target class, a target method parent class, a target method,
9454 // a delegate class, check if the method signature is compatible with the Invoke method of the delegate
9455 // (under the typical instantiation of any free type variables in the memberref signatures).
9457 // objCls should be NULL if the target object is NULL
9458 //@GENERICSVER: new (suitable for generics)
9459 BOOL CEEInfo::isCompatibleDelegate(
9460 CORINFO_CLASS_HANDLE objCls,
9461 CORINFO_CLASS_HANDLE methodParentCls,
9462 CORINFO_METHOD_HANDLE method,
9463 CORINFO_CLASS_HANDLE delegateCls,
9464 BOOL* pfIsOpenDelegate)
9473 BOOL result = FALSE;
9475 JIT_TO_EE_TRANSITION();
9477 _ASSERTE(method != NULL);
9478 _ASSERTE(delegateCls != NULL);
9480 TypeHandle delegateClsHnd = (TypeHandle) delegateCls;
9482 _ASSERTE(delegateClsHnd.GetMethodTable()->IsDelegate());
9484 TypeHandle methodParentHnd = (TypeHandle) (methodParentCls);
9485 MethodDesc* pMDFtn = GetMethod(method);
9486 TypeHandle objClsHnd(objCls);
9490 result = COMDelegate::ValidateCtor(objClsHnd, methodParentHnd, pMDFtn, delegateClsHnd, pfIsOpenDelegate);
9495 EX_END_CATCH(SwallowAllExceptions)
9497 EE_TO_JIT_TRANSITION();
9502 /*********************************************************************/
9503 // return the unmanaged target *if method has already been prelinked.*
9504 void* CEEInfo::getPInvokeUnmanagedTarget(CORINFO_METHOD_HANDLE method,
9505 void **ppIndirection)
9514 void* result = NULL;
9516 if (ppIndirection != NULL)
9517 *ppIndirection = NULL;
9519 #ifndef CROSSGEN_COMPILE
9520 JIT_TO_EE_TRANSITION();
9522 MethodDesc* ftn = GetMethod(method);
9523 _ASSERTE(ftn->IsNDirect());
9524 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9526 if (pMD->NDirectTargetIsImportThunk())
9531 result = pMD->GetNDirectTarget();
9534 EE_TO_JIT_TRANSITION();
9535 #endif // CROSSGEN_COMPILE
9540 /*********************************************************************/
9541 // return address of fixup area for late-bound N/Direct calls.
9542 void* CEEInfo::getAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE method,
9543 void **ppIndirection)
9552 void * result = NULL;
9554 if (ppIndirection != NULL)
9555 *ppIndirection = NULL;
9557 JIT_TO_EE_TRANSITION_LEAF();
9559 MethodDesc* ftn = GetMethod(method);
9560 _ASSERTE(ftn->IsNDirect());
9561 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9563 result = (LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
9565 EE_TO_JIT_TRANSITION_LEAF();
9570 /*********************************************************************/
9571 // return address of fixup area for late-bound N/Direct calls.
9572 void CEEInfo::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method,
9573 CORINFO_CONST_LOOKUP *pLookup)
9575 WRAPPER_NO_CONTRACT;
9578 pLookup->accessType = IAT_PVALUE;
9579 pLookup->addr = getAddressOfPInvokeFixup(method, &pIndirection);
9580 _ASSERTE(pIndirection == NULL);
9583 /*********************************************************************/
9584 CORINFO_JUST_MY_CODE_HANDLE CEEInfo::getJustMyCodeHandle(
9585 CORINFO_METHOD_HANDLE method,
9586 CORINFO_JUST_MY_CODE_HANDLE**ppIndirection)
9595 CORINFO_JUST_MY_CODE_HANDLE result = NULL;
9598 *ppIndirection = NULL;
9600 JIT_TO_EE_TRANSITION_LEAF();
9602 // Get the flag from the debugger.
9603 MethodDesc* ftn = GetMethod(method);
9604 DWORD * pFlagAddr = NULL;
9606 if (g_pDebugInterface)
9608 pFlagAddr = g_pDebugInterface->GetJMCFlagAddr(ftn->GetModule());
9611 result = (CORINFO_JUST_MY_CODE_HANDLE) pFlagAddr;
9613 EE_TO_JIT_TRANSITION_LEAF();
9618 /*********************************************************************/
9619 void InlinedCallFrame::GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo *pInfo)
9621 LIMITED_METHOD_CONTRACT;
9623 pInfo->size = sizeof(GSCookie) + sizeof(InlinedCallFrame);
9625 pInfo->offsetOfGSCookie = 0;
9626 pInfo->offsetOfFrameVptr = sizeof(GSCookie);
9627 pInfo->offsetOfFrameLink = sizeof(GSCookie) + Frame::GetOffsetOfNextLink();
9628 pInfo->offsetOfCallSiteSP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallSiteSP);
9629 pInfo->offsetOfCalleeSavedFP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCalleeSavedFP);
9630 pInfo->offsetOfCallTarget = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_Datum);
9631 pInfo->offsetOfReturnAddress = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallerReturnAddress);
9634 /*********************************************************************/
9635 // Return details about EE internal data structures
9636 void CEEInfo::getEEInfo(CORINFO_EE_INFO *pEEInfoOut)
9645 INDEBUG(memset(pEEInfoOut, 0xCC, sizeof(*pEEInfoOut)));
9647 JIT_TO_EE_TRANSITION();
9649 InlinedCallFrame::GetEEInfo(&pEEInfoOut->inlinedCallFrameInfo);
9651 // Offsets into the Thread structure
9652 pEEInfoOut->offsetOfThreadFrame = Thread::GetOffsetOfCurrentFrame();
9653 pEEInfoOut->offsetOfGCState = Thread::GetOffsetOfGCFlag();
9656 pEEInfoOut->offsetOfDelegateInstance = DelegateObject::GetOffsetOfTarget();
9657 pEEInfoOut->offsetOfDelegateFirstTarget = DelegateObject::GetOffsetOfMethodPtr();
9659 // Secure delegate offsets
9660 pEEInfoOut->offsetOfSecureDelegateIndirectCell = DelegateObject::GetOffsetOfMethodPtrAux();
9663 pEEInfoOut->offsetOfTransparentProxyRP = TransparentProxyObject::GetOffsetOfRP();
9664 pEEInfoOut->offsetOfRealProxyServer = RealProxyObject::GetOffsetOfServerObject();
9666 pEEInfoOut->offsetOfObjArrayData = (DWORD)PtrArray::GetDataOffset();
9668 pEEInfoOut->sizeOfReversePInvokeFrame = (DWORD)-1;
9670 pEEInfoOut->osPageSize = GetOsPageSize();
9671 pEEInfoOut->maxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
9672 pEEInfoOut->targetAbi = CORINFO_CORECLR_ABI;
9674 pEEInfoOut->osType = CORINFO_WINNT;
9676 // hardcode OS version to 0.0.0. These fields can be removed from JITEE interface
9677 pEEInfoOut->osMajor = 0;
9678 pEEInfoOut->osMinor = 0;
9679 pEEInfoOut->osBuild = 0;
9681 EE_TO_JIT_TRANSITION();
9684 LPCWSTR CEEInfo::getJitTimeLogFilename()
9693 LPCWSTR result = NULL;
9695 JIT_TO_EE_TRANSITION();
9696 result = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitTimeLogFile);
9697 EE_TO_JIT_TRANSITION();
9704 // Return details about EE internal data structures
9705 DWORD CEEInfo::getThreadTLSIndex(void **ppIndirection)
9714 DWORD result = (DWORD)-1;
9716 if (ppIndirection != NULL)
9717 *ppIndirection = NULL;
9719 JIT_TO_EE_TRANSITION();
9721 #if !defined(CROSSGEN_COMPILE) && !defined(FEATURE_IMPLICIT_TLS)
9722 result = GetThreadTLSIndex();
9724 // The JIT can use the optimized TLS access only if the runtime is using it as well.
9725 // (This is necessaryto make managed code work well under appverifier.)
9726 if (GetTLSAccessMode(result) == TLSACCESS_GENERIC)
9730 EE_TO_JIT_TRANSITION();
9735 const void * CEEInfo::getInlinedCallFrameVptr(void **ppIndirection)
9744 void * result = NULL;
9746 if (ppIndirection != NULL)
9747 *ppIndirection = NULL;
9749 JIT_TO_EE_TRANSITION_LEAF();
9751 #ifndef CROSSGEN_COMPILE
9752 result = (void*)InlinedCallFrame::GetMethodFrameVPtr();
9754 result = (void*)0x43210;
9757 EE_TO_JIT_TRANSITION_LEAF();
9762 LONG * CEEInfo::getAddrOfCaptureThreadGlobal(void **ppIndirection)
9771 LONG * result = NULL;
9773 if (ppIndirection != NULL)
9774 *ppIndirection = NULL;
9776 JIT_TO_EE_TRANSITION_LEAF();
9778 result = (LONG *)&g_TrapReturningThreads;
9780 EE_TO_JIT_TRANSITION_LEAF();
9787 HRESULT CEEInfo::GetErrorHRESULT(struct _EXCEPTION_POINTERS *pExceptionPointers)
9798 //This function is called from the JIT64 exception filter during PEVerify. Because it is a filter, it
9799 //can be "called" from a NOTHROW region in the case of StackOverflow. Security::MapToHR throws
9800 //internally, but it catches all exceptions. Therefore, none of the children can cause an exception to
9801 //percolate out of this function (except for Stack Overflow). Obviously I can't explain most of this to
9802 //the Contracts system, and I can't add this CONTRACT_VIOLATION to the filter in Jit64.
9803 CONTRACT_VIOLATION(ThrowsViolation);
9805 JIT_TO_EE_TRANSITION();
9809 OBJECTREF throwable = GetThread()->LastThrownObject();
9810 hr = GetExceptionHResult(throwable);
9812 EE_TO_JIT_TRANSITION();
9818 ULONG CEEInfo::GetErrorMessage(__inout_ecount(bufferLength) LPWSTR buffer, ULONG bufferLength)
9829 #ifndef CROSSGEN_COMPILE
9830 JIT_TO_EE_TRANSITION();
9834 OBJECTREF throwable = GetThread()->LastThrownObject();
9836 if (throwable != NULL)
9840 result = GetExceptionMessage(throwable, buffer, bufferLength);
9845 EX_END_CATCH(SwallowAllExceptions)
9848 EE_TO_JIT_TRANSITION();
9854 // This method is called from CEEInfo::FilterException which
9855 // is run as part of the SEH filter clause for the JIT.
9856 // It is fatal to throw an exception while running a SEH filter clause
9857 // so our contract is NOTHROW, NOTRIGGER.
9859 LONG EEFilterException(struct _EXCEPTION_POINTERS *pExceptionPointers, void *unused)
9869 JIT_TO_EE_TRANSITION_LEAF();
9871 VALIDATE_BACKOUT_STACK_CONSUMPTION;
9873 unsigned code = pExceptionPointers->ExceptionRecord->ExceptionCode;
9876 if (code == EXCEPTION_ACCESS_VIOLATION)
9881 _ASSERTE(!"Access violation while Jitting!");
9882 // If you set the debugger to catch access violations and 'go'
9883 // you will get back to the point at which the access violation occurred
9884 result = EXCEPTION_CONTINUE_EXECUTION;
9888 result = EXCEPTION_CONTINUE_SEARCH;
9893 // No one should be catching breakpoint
9894 // Similarly the JIT doesn't know how to reset the guard page, so it shouldn't
9895 // be catching a hard stack overflow
9896 if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP || code == EXCEPTION_STACK_OVERFLOW)
9898 result = EXCEPTION_CONTINUE_SEARCH;
9900 #ifdef CROSSGEN_COMPILE
9903 result = EXCEPTION_EXECUTE_HANDLER;
9906 else if (!IsComPlusException(pExceptionPointers->ExceptionRecord))
9908 result = EXCEPTION_EXECUTE_HANDLER;
9914 // This is actually the LastThrown exception object.
9915 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
9917 if (throwable != NULL)
9921 OBJECTREF oLastThrownObject;
9924 ZeroMemory(&_gc, sizeof(_gc));
9926 // Setup the throwables
9927 _gc.oLastThrownObject = throwable;
9929 GCPROTECT_BEGIN(_gc);
9931 // Don't catch ThreadAbort and other uncatchable exceptions
9932 if (IsUncatchable(&_gc.oLastThrownObject))
9933 result = EXCEPTION_CONTINUE_SEARCH;
9935 result = EXCEPTION_EXECUTE_HANDLER;
9942 EE_TO_JIT_TRANSITION_LEAF();
9947 int CEEInfo::FilterException(struct _EXCEPTION_POINTERS *pExceptionPointers)
9949 WRAPPER_NO_CONTRACT;
9950 return EEFilterException(pExceptionPointers, nullptr);
9953 // This code is called if FilterException chose to handle the exception.
9954 void CEEInfo::HandleException(struct _EXCEPTION_POINTERS *pExceptionPointers)
9962 JIT_TO_EE_TRANSITION_LEAF();
9964 #ifndef CROSSGEN_COMPILE
9965 if (IsComPlusException(pExceptionPointers->ExceptionRecord))
9969 // This is actually the LastThrown exception object.
9970 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
9972 if (throwable != NULL)
9976 OBJECTREF oLastThrownObject;
9977 OBJECTREF oCurrentThrowable;
9980 ZeroMemory(&_gc, sizeof(_gc));
9982 PTR_Thread pCurThread = GetThread();
9984 // Setup the throwables
9985 _gc.oLastThrownObject = throwable;
9987 // This will be NULL if no managed exception is active. Otherwise,
9988 // it will reference the active throwable.
9989 _gc.oCurrentThrowable = pCurThread->GetThrowable();
9991 GCPROTECT_BEGIN(_gc);
9993 // JIT does not use or reference managed exceptions at all and simply swallows them,
9994 // or lets them fly through so that they will either get caught in managed code, the VM
9995 // or will go unhandled.
9997 // Blind swallowing of managed exceptions can break the semantic of "which exception handler"
9998 // gets to process the managed exception first. The expected handler is managed code exception
9999 // handler (e.g. COMPlusFrameHandler on x86 and ProcessCLRException on 64bit) which will setup
10000 // the exception tracker for the exception that will enable the expected sync between the
10001 // LastThrownObject (LTO), setup in RaiseTheExceptionInternalOnly, and the exception tracker.
10003 // However, JIT can break this by swallowing the managed exception before managed code exception
10004 // handler gets a chance to setup an exception tracker for it. Since there is no cleanup
10005 // done for the swallowed exception as part of the unwind (because no exception tracker may have been setup),
10006 // we need to reset the LTO, if it is out of sync from the active throwable.
10008 // Hence, check if the LastThrownObject and active-exception throwable are in sync or not.
10009 // If not, bring them in sync.
10013 // It is possible that an exception was already in progress and while processing it (e.g.
10014 // invoking finally block), we invoked JIT that had another managed exception @ JIT-EE transition boundary
10015 // that is swallowed by the JIT before managed code exception handler sees it. This breaks the sync between
10016 // LTO and the active exception in the exception tracker.
10017 if (_gc.oCurrentThrowable != _gc.oLastThrownObject)
10021 // Note: Incase of OOM, this will get set to OOM instance.
10022 pCurThread->SafeSetLastThrownObject(_gc.oCurrentThrowable);
10030 EE_TO_JIT_TRANSITION_LEAF();
10033 void ThrowExceptionForJit(HRESULT res);
10035 void CEEInfo::ThrowExceptionForJitResult(
10045 JIT_TO_EE_TRANSITION();
10047 if (!SUCCEEDED(result))
10048 ThrowExceptionForJit(result);
10050 EE_TO_JIT_TRANSITION();
10054 CORINFO_MODULE_HANDLE CEEInfo::embedModuleHandle(CORINFO_MODULE_HANDLE handle,
10055 void **ppIndirection)
10062 PRECONDITION(!IsDynamicScope(handle));
10066 if (ppIndirection != NULL)
10067 *ppIndirection = NULL;
10069 JIT_TO_EE_TRANSITION_LEAF();
10071 EE_TO_JIT_TRANSITION_LEAF();
10076 CORINFO_CLASS_HANDLE CEEInfo::embedClassHandle(CORINFO_CLASS_HANDLE handle,
10077 void **ppIndirection)
10087 if (ppIndirection != NULL)
10088 *ppIndirection = NULL;
10090 JIT_TO_EE_TRANSITION_LEAF();
10092 EE_TO_JIT_TRANSITION_LEAF();
10097 CORINFO_FIELD_HANDLE CEEInfo::embedFieldHandle(CORINFO_FIELD_HANDLE handle,
10098 void **ppIndirection)
10108 if (ppIndirection != NULL)
10109 *ppIndirection = NULL;
10111 JIT_TO_EE_TRANSITION_LEAF();
10113 EE_TO_JIT_TRANSITION_LEAF();
10118 CORINFO_METHOD_HANDLE CEEInfo::embedMethodHandle(CORINFO_METHOD_HANDLE handle,
10119 void **ppIndirection)
10129 if (ppIndirection != NULL)
10130 *ppIndirection = NULL;
10132 JIT_TO_EE_TRANSITION_LEAF();
10134 EE_TO_JIT_TRANSITION_LEAF();
10139 /*********************************************************************/
10140 void CEEInfo::setJitFlags(const CORJIT_FLAGS& jitFlags)
10142 LIMITED_METHOD_CONTRACT;
10144 m_jitFlags = jitFlags;
10147 /*********************************************************************/
10148 DWORD CEEInfo::getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes)
10157 JIT_TO_EE_TRANSITION_LEAF();
10159 _ASSERTE(sizeInBytes >= sizeof(m_jitFlags));
10160 *jitFlags = m_jitFlags;
10162 EE_TO_JIT_TRANSITION_LEAF();
10164 return sizeof(m_jitFlags);
10167 /*********************************************************************/
10168 #if !defined(PLATFORM_UNIX)
10170 struct RunWithErrorTrapFilterParam
10172 ICorDynamicInfo* m_corInfo;
10173 void (*m_function)(void*);
10175 EXCEPTION_POINTERS m_exceptionPointers;
10178 static LONG RunWithErrorTrapFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
10180 WRAPPER_NO_CONTRACT;
10182 auto* param = reinterpret_cast<RunWithErrorTrapFilterParam*>(theParam);
10183 param->m_exceptionPointers = *exceptionPointers;
10184 return param->m_corInfo->FilterException(exceptionPointers);
10187 #endif // !defined(PLATFORM_UNIX)
10189 bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param)
10191 // No dynamic contract here because SEH is used
10192 STATIC_CONTRACT_THROWS;
10193 STATIC_CONTRACT_GC_TRIGGERS;
10194 STATIC_CONTRACT_SO_TOLERANT;
10195 STATIC_CONTRACT_MODE_PREEMPTIVE;
10197 // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
10198 // transitions into the EE proper should occur either via the call to
10199 // `EEFilterException` (which is appropraitely marked) or via JIT/EE
10200 // interface calls made by `function`.
10202 bool success = true;
10204 #if !defined(PLATFORM_UNIX)
10206 RunWithErrorTrapFilterParam trapParam;
10207 trapParam.m_corInfo = m_pOverride == nullptr ? this : m_pOverride;
10208 trapParam.m_function = function;
10209 trapParam.m_param = param;
10211 PAL_TRY(RunWithErrorTrapFilterParam*, pTrapParam, &trapParam)
10213 pTrapParam->m_function(pTrapParam->m_param);
10215 PAL_EXCEPT_FILTER(RunWithErrorTrapFilter)
10217 HandleException(&trapParam.m_exceptionPointers);
10222 #else // !defined(PLATFORM_UNIX)
10224 // We shouldn't need PAL_TRY on *nix: any exceptions that we are able to catch
10225 // ought to originate from the runtime itself and should be catchable inside of
10226 // EX_TRY/EX_CATCH, including emulated SEH exceptions.
10235 EX_END_CATCH(RethrowTerminalExceptions);
10242 /*********************************************************************/
10243 IEEMemoryManager* CEEInfo::getMemoryManager()
10252 IEEMemoryManager* result = NULL;
10254 JIT_TO_EE_TRANSITION_LEAF();
10256 result = GetEEMemoryManager();
10258 EE_TO_JIT_TRANSITION_LEAF();
10263 /*********************************************************************/
10264 int CEEInfo::doAssert(const char* szFile, int iLine, const char* szExpr)
10266 STATIC_CONTRACT_SO_TOLERANT;
10267 STATIC_CONTRACT_THROWS;
10268 STATIC_CONTRACT_GC_TRIGGERS;
10269 STATIC_CONTRACT_MODE_PREEMPTIVE;
10270 STATIC_CONTRACT_DEBUG_ONLY;
10274 JIT_TO_EE_TRANSITION();
10276 #ifdef CROSSGEN_COMPILE
10277 ThrowHR(COR_E_INVALIDPROGRAM);
10281 BEGIN_DEBUG_ONLY_CODE;
10282 result = _DbgBreakCheck(szFile, iLine, szExpr);
10283 END_DEBUG_ONLY_CODE;
10285 result = 1; // break into debugger
10290 EE_TO_JIT_TRANSITION();
10295 void CEEInfo::reportFatalError(CorJitResult result)
10297 STATIC_CONTRACT_SO_TOLERANT;
10298 STATIC_CONTRACT_THROWS;
10299 STATIC_CONTRACT_GC_TRIGGERS;
10300 STATIC_CONTRACT_MODE_PREEMPTIVE;
10302 JIT_TO_EE_TRANSITION_LEAF();
10304 STRESS_LOG2(LF_JIT,LL_ERROR, "Jit reported error 0x%x while compiling 0x%p\n",
10305 (int)result, (INT_PTR)getMethodBeingCompiled());
10307 EE_TO_JIT_TRANSITION_LEAF();
10310 BOOL CEEInfo::logMsg(unsigned level, const char* fmt, va_list args)
10312 STATIC_CONTRACT_SO_TOLERANT;
10313 STATIC_CONTRACT_THROWS;
10314 STATIC_CONTRACT_GC_TRIGGERS;
10315 STATIC_CONTRACT_MODE_PREEMPTIVE;
10316 STATIC_CONTRACT_DEBUG_ONLY;
10318 BOOL result = FALSE;
10320 JIT_TO_EE_TRANSITION_LEAF();
10323 if (LoggingOn(LF_JIT, level))
10325 LogSpewValist(LF_JIT, level, (char*) fmt, args);
10330 EE_TO_JIT_TRANSITION_LEAF();
10335 void CEEInfo::yieldExecution()
10337 WRAPPER_NO_CONTRACT;
10341 #ifndef CROSSGEN_COMPILE
10343 /*********************************************************************/
10345 void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
10346 void ** ppIndirection) /* OUT */
10355 void* result = NULL;
10357 if (ppIndirection != NULL)
10358 *ppIndirection = NULL;
10360 JIT_TO_EE_TRANSITION_LEAF();
10362 _ASSERTE(ftnNum < CORINFO_HELP_COUNT);
10364 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10366 size_t dynamicFtnNum = ((size_t)pfnHelper - 1);
10367 if (dynamicFtnNum < DYNAMIC_CORINFO_HELP_COUNT)
10370 #pragma warning(push)
10371 #pragma warning(disable:26001) // "Bounds checked above using the underflow trick"
10372 #endif /*_PREFAST_ */
10374 #if defined(_TARGET_AMD64_)
10375 // To avoid using a jump stub we always call certain helpers using an indirect call.
10376 // Because when using a direct call and the target is father away than 2^31 bytes,
10377 // the direct call instead goes to a jump stub which jumps to the jit helper.
10378 // However in this process the jump stub will corrupt RAX.
10380 // The set of helpers for which RAX must be preserved are the profiler probes
10381 // and the STOP_FOR_GC helper which maps to JIT_RareDisableHelper.
10382 // In the case of the STOP_FOR_GC helper RAX can be holding a function return value.
10384 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_STOP_FOR_GC ||
10385 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER ||
10386 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE ||
10387 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL)
10389 _ASSERTE(ppIndirection != NULL);
10390 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10395 #if defined(ENABLE_FAST_GCPOLL_HELPER)
10396 //always call this indirectly so that we can swap GC Poll helpers.
10397 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_POLL_GC)
10399 _ASSERTE(ppIndirection != NULL);
10400 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10405 pfnHelper = hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10408 #pragma warning(pop)
10409 #endif /*_PREFAST_*/
10412 _ASSERTE(pfnHelper);
10414 result = (LPVOID)GetEEFuncEntryPoint(pfnHelper);
10416 EE_TO_JIT_TRANSITION_LEAF();
10421 PCODE CEEJitInfo::getHelperFtnStatic(CorInfoHelpFunc ftnNum)
10423 LIMITED_METHOD_CONTRACT;
10425 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10427 // If pfnHelper is an index into the dynamic helper table, it should be less
10428 // than DYNAMIC_CORINFO_HELP_COUNT. In this case we need to find the actual pfnHelper
10429 // using an extra indirection. Note the special case
10430 // where pfnHelper==0 where pfnHelper-1 will underflow and we will avoid the indirection.
10431 if (((size_t)pfnHelper - 1) < DYNAMIC_CORINFO_HELP_COUNT)
10433 pfnHelper = hlpDynamicFuncTable[((size_t)pfnHelper - 1)].pfnHelper;
10436 _ASSERTE(pfnHelper != NULL);
10438 return GetEEFuncEntryPoint(pfnHelper);
10441 void CEEJitInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
10446 PRECONDITION(CheckPointer(moduleFrom));
10447 PRECONDITION(!IsDynamicScope(moduleFrom));
10448 PRECONDITION(CheckPointer(moduleTo));
10449 PRECONDITION(!IsDynamicScope(moduleTo));
10450 PRECONDITION(moduleFrom != moduleTo);
10454 // This is only called internaly. JIT-EE transition is not needed.
10455 // JIT_TO_EE_TRANSITION();
10457 Module *dependency = (Module *)moduleTo;
10458 _ASSERTE(!dependency->IsSystem());
10460 if (m_pMethodBeingCompiled->IsLCGMethod())
10462 // The context module of the m_pMethodBeingCompiled is irrelevant. Rather than tracking
10463 // the dependency, we just do immediate activation.
10464 dependency->EnsureActive();
10468 #ifdef FEATURE_LOADER_OPTIMIZATION
10469 Module *context = (Module *)moduleFrom;
10471 // Record active dependency for loader.
10472 context->AddActiveDependency(dependency, FALSE);
10474 dependency->EnsureActive();
10478 // EE_TO_JIT_TRANSITION();
10482 // Wrapper around CEEInfo::GetProfilingHandle. The first time this is called for a
10483 // method desc, it calls through to EEToProfInterfaceImpl::EEFunctionIDMappe and caches the
10484 // result in CEEJitInfo::GetProfilingHandleCache. Thereafter, this wrapper regurgitates the cached values
10485 // rather than calling into CEEInfo::GetProfilingHandle each time. This avoids
10486 // making duplicate calls into the profiler's FunctionIDMapper callback.
10487 void CEEJitInfo::GetProfilingHandle(BOOL *pbHookFunction,
10488 void **pProfilerHandle,
10489 BOOL *pbIndirectedHandles)
10498 _ASSERTE(pbHookFunction != NULL);
10499 _ASSERTE(pProfilerHandle != NULL);
10500 _ASSERTE(pbIndirectedHandles != NULL);
10502 if (!m_gphCache.m_bGphIsCacheValid)
10504 #ifdef PROFILING_SUPPORTED
10505 JIT_TO_EE_TRANSITION();
10507 // Cache not filled in, so make our first and only call to CEEInfo::GetProfilingHandle here
10509 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
10510 // they shouldnever come here as they are called out in GetCompileFlag
10511 _ASSERTE(!m_pMethodBeingCompiled->IsNoMetadata());
10513 // We pass in the typical method definition to the function mapper because in
10514 // Whidbey all the profiling API transactions are done in terms of typical
10515 // method definitions not instantiations.
10516 BOOL bHookFunction = TRUE;
10517 void * profilerHandle = m_pMethodBeingCompiled;
10520 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
10521 profilerHandle = (void *)g_profControlBlock.pProfInterface->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction);
10522 END_PIN_PROFILER();
10525 m_gphCache.m_pvGphProfilerHandle = profilerHandle;
10526 m_gphCache.m_bGphHookFunction = (bHookFunction != FALSE);
10527 m_gphCache.m_bGphIsCacheValid = true;
10529 EE_TO_JIT_TRANSITION();
10530 #endif //PROFILING_SUPPORTED
10533 // Our cache of these values are bitfield bools, but the interface requires
10534 // BOOL. So to avoid setting aside a staging area on the stack for these
10535 // values, we filled them in directly in the if (not cached yet) case.
10536 *pbHookFunction = (m_gphCache.m_bGphHookFunction != false);
10538 // At this point, the remaining values must be in the cache by now, so use them
10539 *pProfilerHandle = m_gphCache.m_pvGphProfilerHandle;
10542 // This is the JIT case, which is never indirected.
10544 *pbIndirectedHandles = FALSE;
10547 /*********************************************************************/
10548 void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr)
10555 CodeHeader* pCodeHeader = GetCodeHeader();
10557 jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len);
10560 /*********************************************************************/
10561 // Route jit information to the Jit Debug store.
10562 void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
10563 ICorDebugInfo::OffsetMapping *pMap)
10572 JIT_TO_EE_TRANSITION();
10574 // We receive ownership of the array
10575 _ASSERTE(m_pOffsetMapping == NULL && m_iOffsetMapping == 0);
10576 m_iOffsetMapping = cMap;
10577 m_pOffsetMapping = pMap;
10579 EE_TO_JIT_TRANSITION();
10582 void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
10591 JIT_TO_EE_TRANSITION();
10593 // We receive ownership of the array
10594 _ASSERTE(m_pNativeVarInfo == NULL && m_iNativeVarInfo == 0);
10595 m_iNativeVarInfo = cVars;
10596 m_pNativeVarInfo = vars;
10598 EE_TO_JIT_TRANSITION();
10601 void CEEJitInfo::CompressDebugInfo()
10610 // Don't track JIT info for DynamicMethods.
10611 if (m_pMethodBeingCompiled->IsDynamicMethod())
10614 if (m_iOffsetMapping == 0 && m_iNativeVarInfo == 0)
10617 JIT_TO_EE_TRANSITION();
10621 PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars(
10622 m_pOffsetMapping, m_iOffsetMapping,
10623 m_pNativeVarInfo, m_iNativeVarInfo,
10625 m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap());
10627 GetCodeHeader()->SetDebugInfo(pDebugInfo);
10631 // Just ignore exceptions here. The debugger's structures will still be in a consistent state.
10633 EX_END_CATCH(SwallowAllExceptions)
10635 EE_TO_JIT_TRANSITION();
10638 void reservePersonalityRoutineSpace(ULONG &unwindSize)
10640 #if defined(_TARGET_X86_)
10642 #elif defined(_TARGET_AMD64_)
10643 // Add space for personality routine, it must be 4-byte aligned.
10644 // Everything in the UNWIND_INFO up to the variable-sized UnwindCodes
10645 // array has already had its size included in unwindSize by the caller.
10646 unwindSize += sizeof(ULONG);
10648 // Note that the count of unwind codes (2 bytes each) is stored as a UBYTE
10649 // So the largest size could be 510 bytes, plus the header and language
10650 // specific stuff. This can't overflow.
10652 _ASSERTE(FitsInU4(unwindSize + sizeof(ULONG)));
10653 unwindSize = (ULONG)(ALIGN_UP(unwindSize, sizeof(ULONG)));
10654 #elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
10655 // The JIT passes in a 4-byte aligned block of unwind data.
10656 _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
10658 // Add space for personality routine, it must be 4-byte aligned.
10659 unwindSize += sizeof(ULONG);
10661 PORTABILITY_ASSERT("reservePersonalityRoutineSpace");
10662 #endif // !defined(_TARGET_AMD64_)
10665 // Reserve memory for the method/funclet's unwind information.
10666 // Note that this must be called before allocMem. It should be
10667 // called once for the main method, once for every funclet, and
10668 // once for every block of cold code for which allocUnwindInfo
10671 // This is necessary because jitted code must allocate all the
10672 // memory needed for the unwindInfo at the allocMem call.
10673 // For prejitted code we split up the unwinding information into
10674 // separate sections .rdata and .pdata.
10676 void CEEJitInfo::reserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize)
10678 #ifdef WIN64EXCEPTIONS
10687 JIT_TO_EE_TRANSITION_LEAF();
10689 CONSISTENCY_CHECK_MSG(!isColdCode, "Hot/Cold splitting is not supported in jitted code");
10690 _ASSERTE_MSG(m_theUnwindBlock == NULL,
10691 "reserveUnwindInfo() can only be called before allocMem(), but allocMem() has already been called. "
10692 "This may indicate the JIT has hit a NO_WAY assert after calling allocMem(), and is re-JITting. "
10693 "Set COMPlus_JitBreakOnBadCode=1 and rerun to get the real error.");
10695 ULONG currentSize = unwindSize;
10697 reservePersonalityRoutineSpace(currentSize);
10699 m_totalUnwindSize += currentSize;
10701 m_totalUnwindInfos++;
10703 EE_TO_JIT_TRANSITION_LEAF();
10704 #else // WIN64EXCEPTIONS
10705 LIMITED_METHOD_CONTRACT;
10706 // Dummy implementation to make cross-platform altjit work
10707 #endif // WIN64EXCEPTIONS
10710 // Allocate and initialize the .rdata and .pdata for this method or
10711 // funclet and get the block of memory needed for the machine specific
10712 // unwind information (the info for crawling the stack frame).
10713 // Note that allocMem must be called first.
10715 // The pHotCode parameter points at the first byte of the code of the method
10716 // The startOffset and endOffset are the region (main or funclet) that
10717 // we are to allocate and create .rdata and .pdata for.
10718 // The pUnwindBlock is copied and contains the .pdata unwind area
10722 // pHotCode main method code buffer, always filled in
10723 // pColdCode always NULL for jitted code
10724 // startOffset start of code block, relative to pHotCode
10725 // endOffset end of code block, relative to pHotCode
10726 // unwindSize size of unwind info pointed to by pUnwindBlock
10727 // pUnwindBlock pointer to unwind info
10728 // funcKind type of funclet (main method code, handler, filter)
10730 void CEEJitInfo::allocUnwindInfo (
10731 BYTE * pHotCode, /* IN */
10732 BYTE * pColdCode, /* IN */
10733 ULONG startOffset, /* IN */
10734 ULONG endOffset, /* IN */
10735 ULONG unwindSize, /* IN */
10736 BYTE * pUnwindBlock, /* IN */
10737 CorJitFuncKind funcKind /* IN */
10740 #ifdef WIN64EXCEPTIONS
10746 PRECONDITION(m_theUnwindBlock != NULL);
10747 PRECONDITION(m_usedUnwindSize < m_totalUnwindSize);
10748 PRECONDITION(m_usedUnwindInfos < m_totalUnwindInfos);
10749 PRECONDITION(endOffset <= m_codeSize);
10752 CONSISTENCY_CHECK_MSG(pColdCode == NULL, "Hot/Cold code splitting not supported for jitted code");
10754 JIT_TO_EE_TRANSITION();
10757 // We add one callback-type dynamic function table per range section.
10758 // Therefore, the RUNTIME_FUNCTION info is always relative to the
10759 // image base contained in the dynamic function table, which happens
10760 // to be the LowAddress of the range section. The JIT has no
10761 // knowledge of the range section, so it gives us offsets that are
10762 // relative to the beginning of the method (pHotCode) and we allocate
10763 // and initialize the RUNTIME_FUNCTION data and record its location
10764 // in this function.
10767 if (funcKind != CORJIT_FUNC_ROOT)
10769 // The main method should be emitted before funclets
10770 _ASSERTE(m_usedUnwindInfos > 0);
10773 PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeader->GetUnwindInfo(m_usedUnwindInfos);
10774 m_usedUnwindInfos++;
10776 // Make sure that the RUNTIME_FUNCTION is aligned on a DWORD sized boundary
10777 _ASSERTE(IS_ALIGNED(pRuntimeFunction, sizeof(DWORD)));
10779 UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *) &(m_theUnwindBlock[m_usedUnwindSize]);
10780 m_usedUnwindSize += unwindSize;
10782 reservePersonalityRoutineSpace(m_usedUnwindSize);
10784 _ASSERTE(m_usedUnwindSize <= m_totalUnwindSize);
10786 // Make sure that the UnwindInfo is aligned
10787 _ASSERTE(IS_ALIGNED(pUnwindInfo, sizeof(ULONG)));
10789 /* Calculate Image Relative offset to add to the jit generated unwind offsets */
10791 TADDR baseAddress = m_moduleBase;
10793 size_t currentCodeSizeT = (size_t)pHotCode - baseAddress;
10795 /* Check if currentCodeSizeT offset fits in 32-bits */
10796 if (!FitsInU4(currentCodeSizeT))
10798 _ASSERTE(!"Bad currentCodeSizeT");
10799 COMPlusThrowHR(E_FAIL);
10802 /* Check if EndAddress offset fits in 32-bit */
10803 if (!FitsInU4(currentCodeSizeT + endOffset))
10805 _ASSERTE(!"Bad currentCodeSizeT");
10806 COMPlusThrowHR(E_FAIL);
10809 unsigned currentCodeOffset = (unsigned) currentCodeSizeT;
10811 /* Calculate Unwind Info delta */
10812 size_t unwindInfoDeltaT = (size_t) pUnwindInfo - baseAddress;
10814 /* Check if unwindDeltaT offset fits in 32-bits */
10815 if (!FitsInU4(unwindInfoDeltaT))
10817 _ASSERTE(!"Bad unwindInfoDeltaT");
10818 COMPlusThrowHR(E_FAIL);
10821 unsigned unwindInfoDelta = (unsigned) unwindInfoDeltaT;
10823 RUNTIME_FUNCTION__SetBeginAddress(pRuntimeFunction, currentCodeOffset + startOffset);
10825 #ifdef _TARGET_AMD64_
10826 pRuntimeFunction->EndAddress = currentCodeOffset + endOffset;
10829 RUNTIME_FUNCTION__SetUnwindInfoAddress(pRuntimeFunction, unwindInfoDelta);
10832 if (funcKind != CORJIT_FUNC_ROOT)
10834 // Check the the new funclet doesn't overlap any existing funclet.
10836 for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++)
10838 PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeader->GetUnwindInfo(iUnwindInfo);
10839 _ASSERTE(( RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress)
10840 || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction)));
10845 /* Copy the UnwindBlock */
10846 memcpy(pUnwindInfo, pUnwindBlock, unwindSize);
10848 #if defined(_TARGET_X86_)
10852 #elif defined(_TARGET_AMD64_)
10854 pUnwindInfo->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
10856 ULONG * pPersonalityRoutine = (ULONG*)ALIGN_UP(&(pUnwindInfo->UnwindCode[pUnwindInfo->CountOfUnwindCodes]), sizeof(ULONG));
10857 *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
10859 #elif defined(_TARGET_ARM64_)
10861 *(LONG *)pUnwindInfo |= (1 << 20); // X bit
10863 ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
10864 *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
10866 #elif defined(_TARGET_ARM_)
10868 *(LONG *)pUnwindInfo |= (1 << 20); // X bit
10870 ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
10871 *pPersonalityRoutine = (TADDR)ProcessCLRException - baseAddress;
10875 #if defined(_TARGET_AMD64_)
10876 // Publish the new unwind information in a way that the ETW stack crawler can find
10877 if (m_usedUnwindInfos == m_totalUnwindInfos)
10878 UnwindInfoTable::PublishUnwindInfoForMethod(baseAddress, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos);
10879 #endif // defined(_TARGET_AMD64_)
10881 EE_TO_JIT_TRANSITION();
10882 #else // WIN64EXCEPTIONS
10883 LIMITED_METHOD_CONTRACT;
10884 // Dummy implementation to make cross-platform altjit work
10885 #endif // WIN64EXCEPTIONS
10888 void CEEJitInfo::recordCallSite(ULONG instrOffset,
10889 CORINFO_SIG_INFO * callSig,
10890 CORINFO_METHOD_HANDLE methodHandle)
10892 // Currently, only testing tools use this method. The EE itself doesn't need record this information.
10893 // N.B. The memory that callSig points to is managed by the JIT and isn't guaranteed to be around after
10894 // this function returns, so future implementations should copy the sig info if they want it to persist.
10895 LIMITED_METHOD_CONTRACT;
10898 // This is a variant for AMD64 or other machines that
10899 // cannot always hold the destination address in a 32-bit location
10900 // A relocation is recorded if we are pre-jitting.
10901 // A jump thunk may be inserted if we are jitting
10903 void CEEJitInfo::recordRelocation(void * location,
10917 JIT_TO_EE_TRANSITION();
10921 switch (fRelocType)
10923 case IMAGE_REL_BASED_DIR64:
10924 // Write 64-bits into location
10925 *((UINT64 *) ((BYTE *) location + slot)) = (UINT64) target;
10928 #ifdef _TARGET_AMD64_
10929 case IMAGE_REL_BASED_REL32:
10931 target = (BYTE *)target + addlDelta;
10933 INT32 * fixupLocation = (INT32 *) ((BYTE *) location + slot);
10934 BYTE * baseAddr = (BYTE *)fixupLocation + sizeof(INT32);
10936 delta = (INT64)((BYTE *)target - baseAddr);
10939 // Do we need to insert a jump stub to make the source reach the target?
10941 // Note that we cannot stress insertion of jump stub by inserting it unconditionally. JIT records the relocations
10942 // for intra-module jumps and calls. It does not expect the register used by the jump stub to be trashed.
10944 if (!FitsInI4(delta))
10949 // When m_fAllowRel32 == TRUE, the JIT will use REL32s for both data addresses and direct code targets.
10950 // Since we cannot tell what the relocation is for, we have to defensively retry.
10952 m_fRel32Overflow = TRUE;
10958 // When m_fAllowRel32 == FALSE, the JIT will use a REL32s for direct code targets only.
10961 delta = rel32UsingJumpStub(fixupLocation, (PCODE)target, m_pMethodBeingCompiled);
10965 LOG((LF_JIT, LL_INFO100000, "Encoded a PCREL32 at" FMT_ADDR "to" FMT_ADDR "+%d, delta is 0x%04x\n",
10966 DBG_ADDR(fixupLocation), DBG_ADDR(target), addlDelta, delta));
10968 // Write the 32-bits pc-relative delta into location
10969 *fixupLocation = (INT32) delta;
10972 #endif // _TARGET_AMD64_
10974 #ifdef _TARGET_ARM64_
10975 case IMAGE_REL_ARM64_BRANCH26: // 26 bit offset << 2 & sign ext, for B and BL
10977 _ASSERTE(slot == 0);
10978 _ASSERTE(addlDelta == 0);
10980 PCODE branchTarget = (PCODE) target;
10981 _ASSERTE((branchTarget & 0x3) == 0); // the low two bits must be zero
10983 PCODE fixupLocation = (PCODE) location;
10984 _ASSERTE((fixupLocation & 0x3) == 0); // the low two bits must be zero
10986 delta = (INT64)(branchTarget - fixupLocation);
10987 _ASSERTE((delta & 0x3) == 0); // the low two bits must be zero
10989 UINT32 branchInstr = *((UINT32*) fixupLocation);
10990 branchInstr &= 0xFC000000; // keep bits 31-26
10991 _ASSERTE((branchInstr & 0x7FFFFFFF) == 0x14000000); // Must be B or BL
10994 // Do we need to insert a jump stub to make the source reach the target?
10997 if (!FitsInRel28(delta))
11001 TADDR baseAddr = (TADDR)fixupLocation;
11002 TADDR loAddr = baseAddr - 0x08000000; // -2^27
11003 TADDR hiAddr = baseAddr + 0x07FFFFFF; // +2^27-1
11005 // Check for the wrap around cases
11006 if (loAddr > baseAddr)
11007 loAddr = UINT64_MIN; // overflow
11008 if (hiAddr < baseAddr)
11009 hiAddr = UINT64_MAX; // overflow
11011 PCODE jumpStubAddr = ExecutionManager::jumpStub(m_pMethodBeingCompiled,
11016 delta = (INT64)(jumpStubAddr - fixupLocation);
11018 if (!FitsInRel28(delta))
11020 _ASSERTE(!"jump stub was not in expected range");
11021 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
11024 LOG((LF_JIT, LL_INFO100000, "Using JumpStub at" FMT_ADDR "that jumps to" FMT_ADDR "\n",
11025 DBG_ADDR(jumpStubAddr), DBG_ADDR(target)));
11028 LOG((LF_JIT, LL_INFO100000, "Encoded a BRANCH26 at" FMT_ADDR "to" FMT_ADDR ", delta is 0x%04x\n",
11029 DBG_ADDR(fixupLocation), DBG_ADDR(target), delta));
11031 _ASSERTE(FitsInRel28(delta));
11033 PutArm64Rel28((UINT32*) fixupLocation, (INT32)delta);
11037 case IMAGE_REL_ARM64_PAGEBASE_REL21:
11039 _ASSERTE(slot == 0);
11040 _ASSERTE(addlDelta == 0);
11042 // Write the 21 bits pc-relative page address into location.
11043 INT64 targetPage = (INT64)target & 0xFFFFFFFFFFFFF000LL;
11044 INT64 lcoationPage = (INT64)location & 0xFFFFFFFFFFFFF000LL;
11045 INT64 relPage = (INT64)(targetPage - lcoationPage);
11046 INT32 imm21 = (INT32)(relPage >> 12) & 0x1FFFFF;
11047 PutArm64Rel21((UINT32 *)location, imm21);
11051 case IMAGE_REL_ARM64_PAGEOFFSET_12A:
11053 _ASSERTE(slot == 0);
11054 _ASSERTE(addlDelta == 0);
11056 // Write the 12 bits page offset into location.
11057 INT32 imm12 = (INT32)target & 0xFFFLL;
11058 PutArm64Rel12((UINT32 *)location, imm12);
11062 #endif // _TARGET_ARM64_
11065 _ASSERTE(!"Unknown reloc type");
11069 EE_TO_JIT_TRANSITION();
11071 JIT_TO_EE_TRANSITION_LEAF();
11073 // Nothing to do on 32-bit
11075 EE_TO_JIT_TRANSITION_LEAF();
11079 WORD CEEJitInfo::getRelocTypeHint(void * target)
11088 #ifdef _TARGET_AMD64_
11091 // The JIT calls this method for data addresses only. It always uses REL32s for direct code targets.
11092 if (IsPreferredExecutableRange(target))
11093 return IMAGE_REL_BASED_REL32;
11095 #endif // _TARGET_AMD64_
11101 void CEEJitInfo::getModuleNativeEntryPointRange(void** pStart, void** pEnd)
11111 JIT_TO_EE_TRANSITION_LEAF();
11113 *pStart = *pEnd = 0;
11115 EE_TO_JIT_TRANSITION_LEAF();
11118 DWORD CEEJitInfo::getExpectedTargetArchitecture()
11120 LIMITED_METHOD_CONTRACT;
11122 return IMAGE_FILE_MACHINE_NATIVE;
11125 void CEEInfo::JitProcessShutdownWork()
11127 LIMITED_METHOD_CONTRACT;
11129 EEJitManager* jitMgr = ExecutionManager::GetEEJitManager();
11131 // If we didn't load the JIT, there is no work to do.
11132 if (jitMgr->m_jit != NULL)
11134 // Do the shutdown work.
11135 jitMgr->m_jit->ProcessShutdownWork(this);
11138 #ifdef ALLOW_SXS_JIT
11139 if (jitMgr->m_alternateJit != NULL)
11141 jitMgr->m_alternateJit->ProcessShutdownWork(this);
11143 #endif // ALLOW_SXS_JIT
11146 /*********************************************************************/
11147 InfoAccessType CEEJitInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
11158 InfoAccessType result = IAT_PVALUE;
11160 JIT_TO_EE_TRANSITION();
11162 _ASSERTE(ppValue != NULL);
11164 if (IsDynamicScope(scopeHnd))
11166 *ppValue = (LPVOID)GetDynamicResolver(scopeHnd)->ConstructStringLiteral(metaTok);
11170 *ppValue = (LPVOID)ConstructStringLiteral(scopeHnd, metaTok); // throws
11173 EE_TO_JIT_TRANSITION();
11178 /*********************************************************************/
11179 InfoAccessType CEEJitInfo::emptyStringLiteral(void ** ppValue)
11188 InfoAccessType result = IAT_PVALUE;
11190 if(NingenEnabled())
11196 JIT_TO_EE_TRANSITION();
11197 *ppValue = StringObject::GetEmptyStringRefPtr();
11198 EE_TO_JIT_TRANSITION();
11203 /*********************************************************************/
11204 void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
11205 void **ppIndirection)
11214 void *result = NULL;
11216 if (ppIndirection != NULL)
11217 *ppIndirection = NULL;
11219 // Do not bother with initialization if we are only verifying the method.
11220 if (isVerifyOnly())
11222 return (void *)0x10;
11225 JIT_TO_EE_TRANSITION();
11227 FieldDesc* field = (FieldDesc*) fieldHnd;
11229 MethodTable* pMT = field->GetEnclosingMethodTable();
11231 _ASSERTE(!pMT->ContainsGenericVariables());
11233 // We must not call here for statics of collectible types.
11234 _ASSERTE(!pMT->Collectible());
11238 if (!field->IsRVA())
11240 // <REVISIT_TODO>@todo: assert that the current method being compiled is unshared</REVISIT_TODO>
11242 // Allocate space for the local class if necessary, but don't trigger
11243 // class construction.
11244 DomainLocalModule *pLocalModule = pMT->GetDomainLocalModule();
11245 pLocalModule->PopulateClass(pMT);
11249 base = (void *) field->GetBase();
11252 result = field->GetStaticAddressHandle(base);
11254 EE_TO_JIT_TRANSITION();
11259 static void *GetClassSync(MethodTable *pMT)
11261 STANDARD_VM_CONTRACT;
11265 OBJECTREF ref = pMT->GetManagedClassObject();
11266 return (void*)ref->GetSyncBlock()->GetMonitor();
11269 /*********************************************************************/
11270 void* CEEJitInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
11271 void **ppIndirection)
11280 void * result = NULL;
11282 if (ppIndirection != NULL)
11283 *ppIndirection = NULL;
11285 JIT_TO_EE_TRANSITION();
11287 result = GetClassSync((GetMethod(ftnHnd))->GetMethodTable());
11289 EE_TO_JIT_TRANSITION();
11294 /*********************************************************************/
11295 HRESULT CEEJitInfo::allocBBProfileBuffer (
11297 ICorJitInfo::ProfileBuffer ** profileBuffer
11307 HRESULT hr = E_FAIL;
11309 JIT_TO_EE_TRANSITION();
11311 #ifdef FEATURE_PREJIT
11313 // We need to know the code size. Typically we can get the code size
11314 // from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so
11315 // for that case we need to use DynamicResolver to get the code size.
11317 unsigned codeSize = 0;
11318 if (m_pMethodBeingCompiled->IsDynamicMethod())
11320 unsigned stackSize, ehSize;
11321 CorInfoOptions options;
11322 DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver();
11323 pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize);
11327 codeSize = m_ILHeader->GetCodeSize();
11330 *profileBuffer = m_pMethodBeingCompiled->GetLoaderModule()->AllocateProfileBuffer(m_pMethodBeingCompiled->GetMemberDef(), count, codeSize);
11331 hr = (*profileBuffer ? S_OK : E_OUTOFMEMORY);
11332 #else // FEATURE_PREJIT
11333 _ASSERTE(!"allocBBProfileBuffer not implemented on CEEJitInfo!");
11335 #endif // !FEATURE_PREJIT
11337 EE_TO_JIT_TRANSITION();
11342 // Consider implementing getBBProfileData on CEEJitInfo. This will allow us
11343 // to use profile info in codegen for non zapped images.
11344 HRESULT CEEJitInfo::getBBProfileData (
11345 CORINFO_METHOD_HANDLE ftnHnd,
11347 ICorJitInfo::ProfileBuffer ** profileBuffer,
11351 LIMITED_METHOD_CONTRACT;
11352 _ASSERTE(!"getBBProfileData not implemented on CEEJitInfo!");
11356 void CEEJitInfo::allocMem (
11357 ULONG hotCodeSize, /* IN */
11358 ULONG coldCodeSize, /* IN */
11359 ULONG roDataSize, /* IN */
11360 ULONG xcptnsCount, /* IN */
11361 CorJitAllocMemFlag flag, /* IN */
11362 void ** hotCodeBlock, /* OUT */
11363 void ** coldCodeBlock, /* OUT */
11364 void ** roDataBlock /* OUT */
11374 JIT_TO_EE_TRANSITION();
11376 _ASSERTE(coldCodeSize == 0);
11379 *coldCodeBlock = NULL;
11382 ULONG codeSize = hotCodeSize;
11383 void **codeBlock = hotCodeBlock;
11385 S_SIZE_T totalSize = S_SIZE_T(codeSize);
11387 size_t roDataAlignment = sizeof(void*);
11388 if ((flag & CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN)!= 0)
11390 roDataAlignment = 16;
11392 else if (roDataSize >= 8)
11394 roDataAlignment = 8;
11396 if (roDataSize > 0)
11398 size_t codeAlignment = ((flag & CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN)!= 0)
11399 ? 16 : sizeof(void*);
11400 totalSize.AlignUp(codeAlignment);
11401 if (roDataAlignment > codeAlignment) {
11402 // Add padding to align read-only data.
11403 totalSize += (roDataAlignment - codeAlignment);
11405 totalSize += roDataSize;
11408 #ifdef WIN64EXCEPTIONS
11409 totalSize.AlignUp(sizeof(DWORD));
11410 totalSize += m_totalUnwindSize;
11413 _ASSERTE(m_CodeHeader == 0 &&
11414 // The jit-compiler sometimes tries to compile a method a second time
11415 // if it failed the first time. In such a situation, m_CodeHeader may
11416 // have already been assigned. Its OK to ignore this assert in such a
11417 // situation - we will leak some memory, but that is acceptable
11418 // since this should happen very rarely.
11419 "Note that this may fire if the JITCompiler tries to recompile a method");
11421 if( totalSize.IsOverflow() )
11423 COMPlusThrowHR(CORJIT_OUTOFMEM);
11426 m_CodeHeader = m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), flag
11427 #ifdef WIN64EXCEPTIONS
11428 , m_totalUnwindInfos
11433 BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress();
11435 *codeBlock = current;
11436 current += codeSize;
11438 if (roDataSize > 0)
11440 current = (BYTE *)ALIGN_UP(current, roDataAlignment);
11441 *roDataBlock = current;
11442 current += roDataSize;
11446 *roDataBlock = NULL;
11449 #ifdef WIN64EXCEPTIONS
11450 current = (BYTE *)ALIGN_UP(current, sizeof(DWORD));
11452 m_theUnwindBlock = current;
11453 current += m_totalUnwindSize;
11456 _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value());
11459 m_codeSize = codeSize;
11462 EE_TO_JIT_TRANSITION();
11465 /*********************************************************************/
11466 void * CEEJitInfo::allocGCInfo (size_t size)
11475 void * block = NULL;
11477 JIT_TO_EE_TRANSITION();
11479 _ASSERTE(m_CodeHeader != 0);
11480 _ASSERTE(m_CodeHeader->GetGCInfo() == 0);
11483 if (size & 0xFFFFFFFF80000000LL)
11485 COMPlusThrowHR(CORJIT_OUTOFMEM);
11489 block = m_jitManager->allocGCInfo(m_CodeHeader,(DWORD)size, &m_GCinfo_len);
11492 COMPlusThrowHR(CORJIT_OUTOFMEM);
11495 _ASSERTE(m_CodeHeader->GetGCInfo() != 0 && block == m_CodeHeader->GetGCInfo());
11497 EE_TO_JIT_TRANSITION();
11502 /*********************************************************************/
11503 void CEEJitInfo::setEHcount (
11513 JIT_TO_EE_TRANSITION();
11515 _ASSERTE(cEH != 0);
11516 _ASSERTE(m_CodeHeader != 0);
11517 _ASSERTE(m_CodeHeader->GetEHInfo() == 0);
11519 EE_ILEXCEPTION* ret;
11520 ret = m_jitManager->allocEHInfo(m_CodeHeader,cEH, &m_EHinfo_len);
11521 _ASSERTE(ret); // allocEHInfo throws if there's not enough memory
11523 _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && m_CodeHeader->GetEHInfo()->EHCount() == cEH);
11525 EE_TO_JIT_TRANSITION();
11528 /*********************************************************************/
11529 void CEEJitInfo::setEHinfo (
11531 const CORINFO_EH_CLAUSE* clause)
11540 JIT_TO_EE_TRANSITION();
11542 // <REVISIT_TODO> Fix make the Code Manager EH clauses EH_INFO+</REVISIT_TODO>
11543 _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && EHnumber < m_CodeHeader->GetEHInfo()->EHCount());
11545 EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeader->GetEHInfo()->EHClause(EHnumber);
11547 pEHClause->TryStartPC = clause->TryOffset;
11548 pEHClause->TryEndPC = clause->TryLength;
11549 pEHClause->HandlerStartPC = clause->HandlerOffset;
11550 pEHClause->HandlerEndPC = clause->HandlerLength;
11551 pEHClause->ClassToken = clause->ClassToken;
11552 pEHClause->Flags = (CorExceptionFlag)clause->Flags;
11554 LOG((LF_EH, LL_INFO1000000, "Setting EH clause #%d for %s::%s\n", EHnumber, m_pMethodBeingCompiled->m_pszDebugClassName, m_pMethodBeingCompiled->m_pszDebugMethodName));
11555 LOG((LF_EH, LL_INFO1000000, " Flags : 0x%08lx -> 0x%08lx\n", clause->Flags, pEHClause->Flags));
11556 LOG((LF_EH, LL_INFO1000000, " TryOffset : 0x%08lx -> 0x%08lx (startpc)\n", clause->TryOffset, pEHClause->TryStartPC));
11557 LOG((LF_EH, LL_INFO1000000, " TryLength : 0x%08lx -> 0x%08lx (endpc)\n", clause->TryLength, pEHClause->TryEndPC));
11558 LOG((LF_EH, LL_INFO1000000, " HandlerOffset : 0x%08lx -> 0x%08lx\n", clause->HandlerOffset, pEHClause->HandlerStartPC));
11559 LOG((LF_EH, LL_INFO1000000, " HandlerLength : 0x%08lx -> 0x%08lx\n", clause->HandlerLength, pEHClause->HandlerEndPC));
11560 LOG((LF_EH, LL_INFO1000000, " ClassToken : 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->ClassToken));
11561 LOG((LF_EH, LL_INFO1000000, " FilterOffset : 0x%08lx -> 0x%08lx\n", clause->FilterOffset, pEHClause->FilterOffset));
11563 if (m_pMethodBeingCompiled->IsDynamicMethod() &&
11564 ((pEHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) == 0) &&
11565 (clause->ClassToken != NULL))
11567 MethodDesc * pMD; FieldDesc * pFD;
11568 m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver()->ResolveToken(clause->ClassToken, (TypeHandle *)&pEHClause->TypeHandle, &pMD, &pFD);
11569 SetHasCachedTypeHandle(pEHClause);
11570 LOG((LF_EH, LL_INFO1000000, " CachedTypeHandle: 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->TypeHandle));
11573 EE_TO_JIT_TRANSITION();
11576 /*********************************************************************/
11577 // get individual exception handler
11578 void CEEJitInfo::getEHinfo(
11579 CORINFO_METHOD_HANDLE ftn, /* IN */
11580 unsigned EHnumber, /* IN */
11581 CORINFO_EH_CLAUSE* clause) /* OUT */
11590 JIT_TO_EE_TRANSITION();
11592 if (IsDynamicMethodHandle(ftn))
11594 GetMethod(ftn)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
11598 _ASSERTE(ftn == CORINFO_METHOD_HANDLE(m_pMethodBeingCompiled)); // For now only support if the method being jitted
11599 getEHinfoHelper(ftn, EHnumber, clause, m_ILHeader);
11602 EE_TO_JIT_TRANSITION();
11604 #endif // CROSSGEN_COMPILE
11606 #if defined(CROSSGEN_COMPILE)
11607 EXTERN_C ICorJitCompiler* __stdcall getJit();
11608 #endif // defined(CROSSGEN_COMPILE)
11610 #ifdef FEATURE_INTERPRETER
11611 static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr,
11613 struct CORINFO_METHOD_INFO *info,
11615 BYTE **nativeEntry,
11616 ULONG *nativeSizeOfCode)
11618 STATIC_CONTRACT_THROWS;
11619 STATIC_CONTRACT_GC_TRIGGERS;
11620 STATIC_CONTRACT_MODE_PREEMPTIVE;
11621 STATIC_CONTRACT_SO_INTOLERANT;
11623 SString namespaceOrClassName, methodName, methodSignature;
11624 // Fire an ETW event to mark the beginning of JIT'ing
11625 ETW::MethodLog::MethodJitting(reinterpret_cast<MethodDesc*>(info->ftn), &namespaceOrClassName, &methodName, &methodSignature);
11627 CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode);
11629 // Logically, it would seem that the end-of-JITting ETW even should go here, but it must come after the native code has been
11630 // set for the given method desc, which happens in a caller.
11634 #endif // FEATURE_INTERPRETER
11637 // Helper function because can't have dtors in BEGIN_SO_TOLERANT_CODE.
11639 CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr,
11641 struct CORINFO_METHOD_INFO *info,
11642 CORJIT_FLAGS jitFlags,
11643 BYTE **nativeEntry,
11644 ULONG *nativeSizeOfCode)
11646 STATIC_CONTRACT_THROWS;
11647 STATIC_CONTRACT_GC_TRIGGERS;
11648 STATIC_CONTRACT_MODE_PREEMPTIVE;
11649 STATIC_CONTRACT_SO_INTOLERANT;
11651 CorJitResult ret = CORJIT_SKIPPED; // Note that CORJIT_SKIPPED is an error exit status code
11654 comp->setJitFlags(jitFlags);
11656 #ifdef FEATURE_STACK_SAMPLING
11657 // SO_INTOLERANT due to init affecting global state.
11658 static ConfigDWORD s_stackSamplingEnabled;
11659 bool samplingEnabled = (s_stackSamplingEnabled.val(CLRConfig::UNSUPPORTED_StackSamplingEnabled) != 0);
11662 BEGIN_SO_TOLERANT_CODE(GetThread());
11665 #if defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
11666 if (FAILED(ret) && jitMgr->m_alternateJit
11667 #ifdef FEATURE_STACK_SAMPLING
11668 && (!samplingEnabled || (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)))
11672 ret = jitMgr->m_alternateJit->compileMethod( comp,
11674 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11676 nativeSizeOfCode );
11678 #ifdef FEATURE_STACK_SAMPLING
11679 if (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND))
11681 // Don't bother with failures if we couldn't collect a trace.
11684 #endif // FEATURE_STACK_SAMPLING
11686 // If we failed to jit, then fall back to the primary Jit.
11689 // Consider adding this call:
11690 // ((CEEJitInfo*)comp)->BackoutJitData(jitMgr);
11691 ((CEEJitInfo*)comp)->ResetForJitRetry();
11692 ret = CORJIT_SKIPPED;
11695 #endif // defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
11697 #ifdef FEATURE_INTERPRETER
11698 static ConfigDWORD s_InterpreterFallback;
11700 bool isInterpreterStub = false;
11701 bool interpreterFallback = (s_InterpreterFallback.val(CLRConfig::INTERNAL_InterpreterFallback) != 0);
11703 if (interpreterFallback == false)
11705 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
11706 // (We assume that importation is completely architecture-independent, or at least nearly so.)
11707 if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
11709 if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
11711 isInterpreterStub = true;
11716 if (FAILED(ret) && jitMgr->m_jit)
11718 ret = CompileMethodWithEtwWrapper(jitMgr,
11721 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11726 if (interpreterFallback == true)
11728 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
11729 // (We assume that importation is completely architecture-independent, or at least nearly so.)
11730 if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
11732 if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
11734 isInterpreterStub = true;
11741 ret = jitMgr->m_jit->compileMethod( comp,
11743 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11747 #endif // FEATURE_INTERPRETER
11749 #if !defined(CROSSGEN_COMPILE)
11750 // Cleanup any internal data structures allocated
11751 // such as IL code after a successfull JIT compile
11752 // If the JIT fails we keep the IL around and will
11753 // try reJIT the same IL. VSW 525059
11755 if (SUCCEEDED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !((CEEJitInfo*)comp)->JitAgain())
11757 ((CEEJitInfo*)comp)->CompressDebugInfo();
11759 #ifdef FEATURE_INTERPRETER
11760 // We do this cleanup in the prestub, where we know whether the method
11761 // has been interpreted.
11763 comp->MethodCompileComplete(info->ftn);
11764 #endif // FEATURE_INTERPRETER
11766 #endif // !defined(CROSSGEN_COMPILE)
11769 #if defined(FEATURE_GDBJIT)
11770 bool isJittedEntry = SUCCEEDED(ret) && *nativeEntry != NULL;
11772 #ifdef FEATURE_INTERPRETER
11773 isJittedEntry &= !isInterpreterStub;
11774 #endif // FEATURE_INTERPRETER
11778 CodeHeader* pCH = ((CodeHeader*)((PCODE)*nativeEntry & ~1)) - 1;
11779 pCH->SetCalledMethods((PTR_VOID)comp->GetCalledMethods());
11783 END_SO_TOLERANT_CODE;
11789 /*********************************************************************/
11790 CorJitResult invokeCompileMethod(EEJitManager *jitMgr,
11792 struct CORINFO_METHOD_INFO *info,
11793 CORJIT_FLAGS jitFlags,
11794 BYTE **nativeEntry,
11795 ULONG *nativeSizeOfCode)
11803 // The JIT runs in preemptive mode
11808 CorJitResult ret = invokeCompileMethodHelper(jitMgr, comp, info, jitFlags, nativeEntry, nativeSizeOfCode);
11811 // Verify that we are still in preemptive mode when we return
11815 _ASSERTE(GetThread()->PreemptiveGCDisabled() == FALSE);
11820 CorJitResult CallCompileMethodWithSEHWrapper(EEJitManager *jitMgr,
11822 struct CORINFO_METHOD_INFO *info,
11823 CORJIT_FLAGS flags,
11824 BYTE **nativeEntry,
11825 ULONG *nativeSizeOfCode,
11828 // no dynamic contract here because SEH is used, with a finally clause
11829 STATIC_CONTRACT_NOTHROW;
11830 STATIC_CONTRACT_GC_TRIGGERS;
11832 LOG((LF_CORDB, LL_EVERYTHING, "CallCompileMethodWithSEHWrapper called...\n"));
11836 EEJitManager *jitMgr;
11838 struct CORINFO_METHOD_INFO *info;
11839 CORJIT_FLAGS flags;
11840 BYTE **nativeEntry;
11841 ULONG *nativeSizeOfCode;
11845 param.jitMgr = jitMgr;
11848 param.flags = flags;
11849 param.nativeEntry = nativeEntry;
11850 param.nativeSizeOfCode = nativeSizeOfCode;
11852 param.res = CORJIT_INTERNALERROR;
11854 PAL_TRY(Param *, pParam, ¶m)
11857 // Call out to the JIT-compiler
11860 pParam->res = invokeCompileMethod( pParam->jitMgr,
11864 pParam->nativeEntry,
11865 pParam->nativeSizeOfCode);
11869 #if defined(DEBUGGING_SUPPORTED) && !defined(CROSSGEN_COMPILE)
11870 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) &&
11871 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MCJIT_BACKGROUND)
11872 #ifdef FEATURE_STACK_SAMPLING
11873 && !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)
11874 #endif // FEATURE_STACK_SAMPLING
11878 // Notify the debugger that we have successfully jitted the function
11880 if (ftn->HasNativeCode())
11883 // Nothing to do here (don't need to notify the debugger
11884 // because the function has already been successfully jitted)
11886 // This is the case where we aborted the jit because of a deadlock cycle
11892 if (g_pDebugInterface)
11894 if (param.res == CORJIT_OK && !((CEEJitInfo*)param.comp)->JitAgain())
11896 g_pDebugInterface->JITComplete(ftn, (TADDR) *nativeEntry);
11901 #endif // DEBUGGING_SUPPORTED && !CROSSGEN_COMPILE
11908 /*********************************************************************/
11909 // Figures out the compile flags that are used by both JIT and NGen
11911 /* static */ CORJIT_FLAGS CEEInfo::GetBaseCompileFlags(MethodDesc * ftn)
11919 // Figure out the code quality flags
11922 CORJIT_FLAGS flags;
11923 if (g_pConfig->JitFramed())
11924 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
11925 if (g_pConfig->JitAlignLoops())
11926 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_ALIGN_LOOPS);
11927 if (ReJitManager::IsReJITEnabled() || g_pConfig->AddRejitNops())
11928 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_REJIT_NOPS);
11929 #ifdef _TARGET_X86_
11930 if (g_pConfig->PInvokeRestoreEsp(ftn->GetModule()->IsPreV4Assembly()))
11931 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PINVOKE_RESTORE_ESP);
11932 #endif // _TARGET_X86_
11934 //See if we should instruct the JIT to emit calls to JIT_PollGC for thread suspension. If we have a
11935 //non-default value in the EE Config, then use that. Otherwise select the platform specific default.
11936 #ifdef FEATURE_ENABLE_GCPOLL
11937 EEConfig::GCPollType pollType = g_pConfig->GetGCPollType();
11938 if (EEConfig::GCPOLL_TYPE_POLL == pollType)
11939 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_CALLS);
11940 else if (EEConfig::GCPOLL_TYPE_INLINE == pollType)
11941 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_INLINE);
11942 #endif //FEATURE_ENABLE_GCPOLL
11944 // Set flags based on method's ImplFlags.
11945 if (!ftn->IsNoMetadata())
11947 DWORD dwImplFlags = 0;
11948 IfFailThrow(ftn->GetMDImport()->GetMethodImplProps(ftn->GetMemberDef(), NULL, &dwImplFlags));
11950 if (IsMiNoOptimization(dwImplFlags))
11952 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
11955 // Always emit frames for methods marked no-inline (see #define ETW_EBP_FRAMED in the JIT)
11956 if (IsMiNoInlining(dwImplFlags))
11958 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
11965 /*********************************************************************/
11966 // Figures out (some of) the flags to use to compile the method
11967 // Returns the new set to use
11969 CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags)
11971 STANDARD_VM_CONTRACT;
11973 //Right now if we don't have a debug interface on CoreCLR, we can't generate debug info. So, in those
11974 //cases don't attempt it.
11975 if (!g_pDebugInterface)
11978 #ifdef DEBUGGING_SUPPORTED
11981 if (g_pConfig->GenDebuggableCode())
11982 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
11985 #ifdef EnC_SUPPORTED
11986 if (pModule->IsEditAndContinueEnabled())
11988 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_EnC);
11990 #endif // EnC_SUPPORTED
11992 // Debug info is always tracked
11993 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
11994 #endif // DEBUGGING_SUPPORTED
11996 if (CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
11998 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12001 if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12003 // If we are only verifying the method, dont need any debug info and this
12004 // prevents getVars()/getBoundaries() from being called unnecessarily.
12005 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12006 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12012 CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHOD_INFO * methodInfo)
12014 STANDARD_VM_CONTRACT;
12016 _ASSERTE(methodInfo->regionKind == CORINFO_REGION_JIT);
12019 // Get the compile flags that are shared between JIT and NGen
12021 flags.Add(CEEInfo::GetBaseCompileFlags(ftn));
12024 // Get CPU specific flags
12026 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12028 flags.Add(ExecutionManager::GetEEJitManager()->GetCPUCompileFlags());
12032 // Find the debugger and profiler related flags
12035 #ifdef DEBUGGING_SUPPORTED
12036 flags.Add(GetDebuggerCompileFlags(ftn->GetModule(), flags));
12039 #ifdef PROFILING_SUPPORTED
12040 if (CORProfilerTrackEnterLeave() && !ftn->IsNoMetadata())
12041 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE);
12043 if (CORProfilerTrackTransitions())
12044 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_NO_PINVOKE_INLINE);
12045 #endif // PROFILING_SUPPORTED
12047 // Set optimization flags
12048 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT))
12050 unsigned optType = g_pConfig->GenOptimizeType();
12051 _ASSERTE(optType <= OPT_RANDOM);
12053 if (optType == OPT_RANDOM)
12054 optType = methodInfo->ILCodeSize % OPT_RANDOM;
12056 if (g_pConfig->JitMinOpts())
12057 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12059 if (optType == OPT_SIZE)
12061 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SIZE_OPT);
12063 else if (optType == OPT_SPEED)
12065 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SPEED_OPT);
12069 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12071 if (ftn->IsILStub())
12073 // no debug info available for IL stubs
12074 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12080 // ********************************************************************
12082 // Throw the right type of exception for the given JIT result
12084 void ThrowExceptionForJit(HRESULT res)
12096 case CORJIT_OUTOFMEM:
12100 #ifdef _TARGET_X86_
12101 // Currently, only x86 JIT returns adequate error codes. The x86 JIT is also the
12102 // JIT that has more limitations and given that to get this message for 64 bit
12103 // is going to require some code churn (either changing their EH handlers or
12104 // fixing the 3 or 4 code sites they have that return CORJIT_INTERNALERROR independently
12105 // of the error, the least risk fix is making this x86 only.
12106 case CORJIT_INTERNALERROR:
12107 COMPlusThrow(kInvalidProgramException, (UINT) IDS_EE_JIT_COMPILER_ERROR);
12111 case CORJIT_BADCODE:
12113 COMPlusThrow(kInvalidProgramException);
12118 // ********************************************************************
12120 LONG g_JitCount = 0;
12123 //#define PERF_TRACK_METHOD_JITTIMES
12124 #ifdef _TARGET_AMD64_
12125 BOOL g_fAllowRel32 = TRUE;
12129 // ********************************************************************
12131 // ********************************************************************
12133 // The reason that this is named UnsafeJitFunction is that this helper
12134 // method is not thread safe! When multiple threads get in here for
12135 // the same pMD, ALL of them MUST return the SAME value.
12136 // To insure that this happens you must call MakeJitWorker.
12137 // It creates a DeadlockAware list of methods being jitted and prevents us
12138 // from trying to jit the same method more that once.
12140 // Calls to this method that occur to check if inlining can occur on x86,
12141 // are OK since they discard the return value of this method.
12143 PCODE UnsafeJitFunction(MethodDesc* ftn, COR_ILMETHOD_DECODER* ILHeader, CORJIT_FLAGS flags,
12144 ULONG * pSizeOfCode)
12146 STANDARD_VM_CONTRACT;
12150 COOPERATIVE_TRANSITION_BEGIN();
12152 #ifdef FEATURE_PREJIT
12154 if (g_pConfig->RequireZaps() == EEConfig::REQUIRE_ZAPS_ALL &&
12155 ftn->GetModule()->GetDomainFile()->IsZapRequired() &&
12156 PartialNGenStressPercentage() == 0 &&
12157 #ifdef FEATURE_STACK_SAMPLING
12158 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND) &&
12160 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12162 StackSString ss(SString::Ascii, "ZapRequire: JIT compiler invoked for ");
12163 TypeString::AppendMethodInternal(ss, ftn);
12166 // Assert as some test may not check their error codes well. So throwing an
12167 // exception may not cause a test failure (as it should).
12168 StackScratchBuffer scratch;
12169 DbgAssertDialog(__FILE__, __LINE__, (char*)ss.GetUTF8(scratch));
12172 COMPlusThrowNonLocalized(kFileNotFoundException, ss.GetUnicode());
12175 #endif // FEATURE_PREJIT
12177 #ifndef CROSSGEN_COMPILE
12178 EEJitManager *jitMgr = ExecutionManager::GetEEJitManager();
12179 if (!jitMgr->LoadJIT())
12181 #ifdef ALLOW_SXS_JIT
12182 if (!jitMgr->IsMainJitLoaded())
12184 // Don't want to throw InvalidProgram from here.
12185 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12187 if (!jitMgr->IsAltJitLoaded())
12189 // Don't want to throw InvalidProgram from here.
12190 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load alternative JIT compiler"));
12192 #else // ALLOW_SXS_JIT
12193 // Don't want to throw InvalidProgram from here.
12194 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12195 #endif // ALLOW_SXS_JIT
12197 #endif // CROSSGEN_COMPILE
12200 // This is here so we can see the name and class easily in the debugger
12202 LPCUTF8 cls = ftn->GetMethodTable()->GetDebugClassName();
12203 LPCUTF8 name = ftn->GetName();
12205 if (ftn->IsNoMetadata())
12207 if (ftn->IsILStub())
12209 LOG((LF_JIT, LL_INFO10000, "{ Jitting IL Stub }\n"));
12213 LOG((LF_JIT, LL_INFO10000, "{ Jitting dynamic method }\n"));
12218 SString methodString;
12219 if (LoggingOn(LF_JIT, LL_INFO10000))
12220 TypeString::AppendMethodDebug(methodString, ftn);
12222 LOG((LF_JIT, LL_INFO10000, "{ Jitting method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12226 if (!SString::_stricmp(cls,"ENC") &&
12227 (!SString::_stricmp(name,"G")))
12237 CORINFO_METHOD_HANDLE ftnHnd = (CORINFO_METHOD_HANDLE)ftn;
12238 CORINFO_METHOD_INFO methodInfo;
12240 getMethodInfoHelper(ftn, ftnHnd, ILHeader, &methodInfo);
12242 // If it's generic then we can only enter through an instantiated md (unless we're just verifying it)
12243 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || !ftn->IsGenericMethodDefinition());
12245 // If it's an instance method then it must not be entered from a generic class
12246 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || ftn->IsStatic() ||
12247 ftn->GetNumGenericClassArgs() == 0 || ftn->HasClassInstantiation());
12249 // method attributes and signature are consistant
12250 _ASSERTE(!!ftn->IsStatic() == ((methodInfo.args.callConv & CORINFO_CALLCONV_HASTHIS) == 0));
12252 flags = GetCompileFlags(ftn, flags, &methodInfo);
12255 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION))
12257 SString methodString;
12258 if (LoggingOn(LF_VERIFIER, LL_INFO100))
12259 TypeString::AppendMethodDebug(methodString, ftn);
12261 LOG((LF_VERIFIER, LL_INFO100, "{ Will verify method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12265 #ifdef _TARGET_AMD64_
12266 BOOL fForceRel32Overflow = FALSE;
12269 // Always exercise the overflow codepath with force relocs
12270 if (PEDecoder::GetForceRelocs())
12271 fForceRel32Overflow = TRUE;
12274 BOOL fAllowRel32 = g_fAllowRel32 | fForceRel32Overflow;
12276 // For determinism, never try to use the REL32 in compilation process
12277 if (IsCompilationProcess())
12279 fForceRel32Overflow = FALSE;
12280 fAllowRel32 = FALSE;
12282 #endif // _TARGET_AMD64_
12286 #ifndef CROSSGEN_COMPILE
12287 CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY),
12288 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING));
12290 // This path should be only ever used for verification in crossgen and so we should not need EEJitManager
12291 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY));
12292 CEEInfo jitInfo(ftn, true);
12293 EEJitManager *jitMgr = NULL;
12296 #if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE)
12297 if (fForceRel32Overflow)
12298 jitInfo.SetRel32Overflow(fAllowRel32);
12299 jitInfo.SetAllowRel32(fAllowRel32);
12302 MethodDesc * pMethodForSecurity = jitInfo.GetMethodForSecurity(ftnHnd);
12304 //Since the check could trigger a demand, we have to do this every time.
12305 //This is actually an overly complicated way to make sure that a method can access all its arguments
12306 //and its return type.
12307 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
12308 TypeHandle ownerTypeForSecurity = TypeHandle(pMethodForSecurity->GetMethodTable());
12309 DynamicResolver *pAccessContext = NULL;
12310 BOOL doAccessCheck = TRUE;
12311 if (pMethodForSecurity->IsDynamicMethod())
12313 doAccessCheck = ModifyCheckForDynamicMethod(pMethodForSecurity->AsDynamicMethodDesc()->GetResolver(),
12314 &ownerTypeForSecurity,
12315 &accessCheckType, &pAccessContext);
12319 AccessCheckOptions accessCheckOptions(accessCheckType,
12321 TRUE /*Throw on error*/,
12322 pMethodForSecurity);
12324 StaticAccessCheckContext accessContext(pMethodForSecurity, ownerTypeForSecurity.GetMethodTable());
12326 // We now do an access check from pMethodForSecurity to pMethodForSecurity, its sole purpose is to
12327 // verify that pMethodForSecurity/ownerTypeForSecurity has access to all its parameters.
12329 // ownerTypeForSecurity.GetMethodTable() can be null if the pMethodForSecurity is a DynamicMethod
12330 // associated with a TypeDesc (Array, Ptr, Ref, or FnPtr). That doesn't make any sense, but we will
12331 // just do an access check from a NULL context which means only public types are accessible.
12332 if (!ClassLoader::CanAccess(&accessContext,
12333 ownerTypeForSecurity.GetMethodTable(),
12334 ownerTypeForSecurity.GetAssembly(),
12335 pMethodForSecurity->GetAttrs(),
12336 pMethodForSecurity,
12338 accessCheckOptions))
12340 EX_THROW(EEMethodException, (pMethodForSecurity));
12351 /* There is a double indirection to call compileMethod - can we
12352 improve this with the new structure? */
12354 #ifdef PERF_TRACK_METHOD_JITTIMES
12355 //Because we're not calling QPC enough. I'm not going to track times if we're just importing.
12356 LARGE_INTEGER methodJitTimeStart = {0};
12357 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12358 QueryPerformanceCounter (&methodJitTimeStart);
12361 #if defined(ENABLE_PERF_COUNTERS)
12365 #if defined(ENABLE_PERF_COUNTERS)
12366 LARGE_INTEGER CycleStart;
12367 QueryPerformanceCounter (&CycleStart);
12368 #endif // defined(ENABLE_PERF_COUNTERS)
12370 // Note on debuggerTrackInfo arg: if we're only importing (ie, verifying/
12371 // checking to make sure we could JIT, but not actually generating code (
12372 // eg, for inlining), then DON'T TELL THE DEBUGGER about this.
12373 res = CallCompileMethodWithSEHWrapper(jitMgr,
12380 LOG((LF_CORDB, LL_EVERYTHING, "Got through CallCompile MethodWithSEHWrapper\n"));
12382 #if FEATURE_PERFMAP
12383 // Save the code size so that it can be reported to the perfmap.
12384 if (pSizeOfCode != NULL)
12386 *pSizeOfCode = sizeOfCode;
12390 #if defined(ENABLE_PERF_COUNTERS)
12391 LARGE_INTEGER CycleStop;
12392 QueryPerformanceCounter(&CycleStop);
12393 GetPerfCounters().m_Jit.timeInJitBase = GetPerfCounters().m_Jit.timeInJit;
12394 GetPerfCounters().m_Jit.timeInJit += static_cast<DWORD>(CycleStop.QuadPart - CycleStart.QuadPart);
12395 GetPerfCounters().m_Jit.cMethodsJitted++;
12396 GetPerfCounters().m_Jit.cbILJitted+=methodInfo.ILCodeSize;
12398 #endif // defined(ENABLE_PERF_COUNTERS)
12400 #if defined(ENABLE_PERF_COUNTERS)
12404 #ifdef PERF_TRACK_METHOD_JITTIMES
12405 //store the time in the string buffer. Module name and token are unique enough. Also, do not
12406 //capture importing time, just actual compilation time.
12407 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12409 LARGE_INTEGER methodJitTimeStop;
12410 QueryPerformanceCounter(&methodJitTimeStop);
12412 ftn->GetModule()->GetDomainFile()->GetFile()->GetCodeBaseOrName(codeBase);
12413 codeBase.AppendPrintf(W(",0x%x,%d,%d\n"),
12414 //(const WCHAR *)codeBase, //module name
12415 ftn->GetMemberDef(), //method token
12416 (unsigned)(methodJitTimeStop.QuadPart - methodJitTimeStart.QuadPart), //cycle count
12417 methodInfo.ILCodeSize //il size
12419 WszOutputDebugString((const WCHAR*)codeBase);
12421 #endif // PERF_TRACK_METHOD_JITTIMES
12425 LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s %s }\n",cls,name, ftn->m_pszDebugMethodSignature));
12427 if (!SUCCEEDED(res))
12429 COUNTER_ONLY(GetPerfCounters().m_Jit.cJitFailures++);
12431 #ifndef CROSSGEN_COMPILE
12432 jitInfo.BackoutJitData(jitMgr);
12435 ThrowExceptionForJit(res);
12438 if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12445 COMPlusThrow(kInvalidProgramException);
12447 #if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE)
12448 if (jitInfo.IsRel32Overflow())
12450 // Backout and try again with fAllowRel32 == FALSE.
12451 jitInfo.BackoutJitData(jitMgr);
12453 // Disallow rel32 relocs in future.
12454 g_fAllowRel32 = FALSE;
12456 _ASSERTE(fAllowRel32 != FALSE);
12457 fAllowRel32 = FALSE;
12460 #endif // _TARGET_AMD64_ && !CROSSGEN_COMPILE
12462 LOG((LF_JIT, LL_INFO10000,
12463 "Jitted Entry at" FMT_ADDR "method %s::%s %s\n", DBG_ADDR(nativeEntry),
12464 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
12466 #if defined(FEATURE_CORESYSTEM)
12469 LPCUTF8 pszDebugClassName = ftn->m_pszDebugClassName;
12470 LPCUTF8 pszDebugMethodName = ftn->m_pszDebugMethodName;
12471 LPCUTF8 pszDebugMethodSignature = ftn->m_pszDebugMethodSignature;
12473 LPCUTF8 pszNamespace;
12474 LPCUTF8 pszDebugClassName = ftn->GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace);
12475 LPCUTF8 pszDebugMethodName = ftn->GetName();
12476 LPCUTF8 pszDebugMethodSignature = "";
12479 //DbgPrintf("Jitted Entry at" FMT_ADDR "method %s::%s %s size %08x\n", DBG_ADDR(nativeEntry),
12480 // pszDebugClassName, pszDebugMethodName, pszDebugMethodSignature, sizeOfCode);
12483 ClrFlushInstructionCache(nativeEntry, sizeOfCode);
12484 ret = (PCODE)nativeEntry;
12486 #ifdef _TARGET_ARM_
12495 FastInterlockIncrement(&g_JitCount);
12496 static BOOL fHeartbeat = -1;
12498 if (fHeartbeat == -1)
12499 fHeartbeat = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitHeartbeat);
12505 COOPERATIVE_TRANSITION_END();
12509 extern "C" unsigned __stdcall PartialNGenStressPercentage()
12511 LIMITED_METHOD_CONTRACT;
12515 static ConfigDWORD partialNGenStress;
12516 DWORD partialNGenStressVal = partialNGenStress.val(CLRConfig::INTERNAL_partialNGenStress);
12517 _ASSERTE(partialNGenStressVal <= 100);
12518 return partialNGenStressVal;
12522 #ifdef FEATURE_PREJIT
12523 /*********************************************************************/
12526 // Table loading functions
12528 void Module::LoadHelperTable()
12530 STANDARD_VM_CONTRACT;
12532 #ifndef CROSSGEN_COMPILE
12534 BYTE * table = (BYTE *) GetNativeImage()->GetNativeHelperTable(&tableSize);
12536 if (tableSize == 0)
12539 EnsureWritableExecutablePages(table, tableSize);
12541 BYTE * curEntry = table;
12542 BYTE * tableEnd = table + tableSize;
12544 #ifdef FEATURE_PERFMAP
12545 PerfMap::LogStubs(__FUNCTION__, GetSimpleName(), (PCODE)table, tableSize);
12549 int iEntryNumber = 0;
12556 while (curEntry < tableEnd)
12558 DWORD dwHelper = *(DWORD *)curEntry;
12560 int iHelper = (USHORT)dwHelper;
12561 _ASSERTE(iHelper < CORINFO_HELP_COUNT);
12563 LOG((LF_JIT, LL_INFO1000000, "JIT helper %3d (%-40s: table @ %p, size 0x%x, entry %3d @ %p, pfnHelper %p)\n",
12564 iHelper, hlpFuncTable[iHelper].name, table, tableSize, iEntryNumber, curEntry, hlpFuncTable[iHelper].pfnHelper));
12566 #if defined(ENABLE_FAST_GCPOLL_HELPER)
12567 // The fast GC poll helper works by calling indirect through a pointer that points to either
12568 // JIT_PollGC or JIT_PollGC_Nop, based on whether we need to poll or not. The JIT_PollGC_Nop
12569 // version is just a "ret". The pointer is stored in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
12570 // See EnableJitGCPoll() and DisableJitGCPoll().
12571 // In NGEN images, we generate a direct call to the helper table. Here, we replace that with
12572 // an indirect jump through the pointer in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
12573 if (iHelper == CORINFO_HELP_POLL_GC)
12575 LOG((LF_JIT, LL_INFO1000000, "JIT helper CORINFO_HELP_POLL_GC (%d); emitting indirect jump to 0x%x\n",
12576 CORINFO_HELP_POLL_GC, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper));
12578 emitJumpInd(curEntry, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper);
12579 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
12582 #endif // ENABLE_FAST_GCPOLL_HELPER
12584 PCODE pfnHelper = CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)iHelper);
12586 if (dwHelper & CORCOMPILE_HELPER_PTR)
12589 // Indirection cell
12592 *(TADDR *)curEntry = pfnHelper;
12594 curEntry = curEntry + sizeof(TADDR);
12602 #if defined(_TARGET_AMD64_)
12603 *curEntry = X86_INSTR_JMP_REL32;
12604 *(INT32 *)(curEntry + 1) = rel32UsingJumpStub((INT32 *)(curEntry + 1), pfnHelper, NULL, GetLoaderAllocator());
12605 #else // all other platforms
12606 emitJump(curEntry, (LPVOID)pfnHelper);
12607 _ASSERTE(HELPER_TABLE_ENTRY_LEN >= JUMP_ALLOCATE_SIZE);
12610 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
12614 // Note that some table entries are sizeof(TADDR) in length, and some are HELPER_TABLE_ENTRY_LEN in length
12619 ClrFlushInstructionCache(table, tableSize);
12620 #endif // CROSSGEN_COMPILE
12623 #ifdef FEATURE_READYTORUN
12624 CorInfoHelpFunc MapReadyToRunHelper(ReadyToRunHelper helperNum)
12626 LIMITED_METHOD_CONTRACT;
12630 #define HELPER(readyToRunHelper, corInfoHelpFunc, flags) \
12631 case readyToRunHelper: return corInfoHelpFunc;
12632 #include "readytorunhelpers.h"
12634 case READYTORUN_HELPER_GetString: return CORINFO_HELP_STRCNS;
12636 default: return CORINFO_HELP_UNDEF;
12640 void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap)
12642 STANDARD_VM_CONTRACT;
12644 ZeroMemory(pGCRefMap, cbGCRefMap);
12646 if (!pMT->ContainsPointers())
12649 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
12650 CGCDescSeries* cur = map->GetHighestSeries();
12651 CGCDescSeries* last = map->GetLowestSeries();
12652 DWORD size = pMT->GetBaseSize();
12653 _ASSERTE(cur >= last);
12657 // offset to embedded references in this series must be
12658 // adjusted by the VTable pointer, when in the unboxed state.
12659 size_t offset = cur->GetSeriesOffset() - sizeof(void*);
12660 size_t offsetStop = offset + cur->GetSeriesSize() + size;
12661 while (offset < offsetStop)
12663 size_t bit = offset / sizeof(void *);
12665 size_t index = bit / 8;
12666 _ASSERTE(index < cbGCRefMap);
12667 pGCRefMap[index] |= (1 << (bit & 7));
12669 offset += sizeof(void *);
12672 } while (cur >= last);
12676 // Type layout check verifies that there was no incompatible change in the value type layout.
12677 // If there was one, we will fall back to JIT instead of using the pre-generated code from the ready to run image.
12678 // This should be rare situation. Changes in value type layout not common.
12680 // The following properties of the value type layout are checked:
12682 // - HFA-ness (on platform that support HFAs)
12684 // - Position of GC references
12686 BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob)
12688 STANDARD_VM_CONTRACT;
12690 SigPointer p(pBlob);
12691 IfFailThrow(p.SkipExactlyOne());
12694 IfFailThrow(p.GetData(&dwFlags));
12696 // Size is checked unconditionally
12697 DWORD dwExpectedSize;
12698 IfFailThrow(p.GetData(&dwExpectedSize));
12700 DWORD dwActualSize = pMT->GetNumInstanceFieldBytes();
12701 if (dwExpectedSize != dwActualSize)
12705 if (dwFlags & READYTORUN_LAYOUT_HFA)
12707 DWORD dwExpectedHFAType;
12708 IfFailThrow(p.GetData(&dwExpectedHFAType));
12710 DWORD dwActualHFAType = pMT->GetHFAType();
12711 if (dwExpectedHFAType != dwActualHFAType)
12720 _ASSERTE(!(dwFlags & READYTORUN_LAYOUT_HFA));
12723 if (dwFlags & READYTORUN_LAYOUT_Alignment)
12725 DWORD dwExpectedAlignment = sizeof(void *);
12726 if (!(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
12728 IfFailThrow(p.GetData(&dwExpectedAlignment));
12731 DWORD dwActualAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
12732 if (dwExpectedAlignment != dwActualAlignment)
12737 if (dwFlags & READYTORUN_LAYOUT_GCLayout)
12739 if (dwFlags & READYTORUN_LAYOUT_GCLayout_Empty)
12741 if (pMT->ContainsPointers())
12746 size_t cbGCRefMap = (dwActualSize / sizeof(TADDR) + 7) / 8;
12747 _ASSERTE(cbGCRefMap > 0);
12749 BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
12751 ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
12753 if (memcmp(pGCRefMap, p.GetPtr(), cbGCRefMap) != 0)
12761 #endif // FEATURE_READYTORUN
12763 BOOL LoadDynamicInfoEntry(Module *currentModule,
12767 STANDARD_VM_CONTRACT;
12769 PCCOR_SIGNATURE pBlob = currentModule->GetNativeFixupBlobData(fixupRva);
12771 BYTE kind = *pBlob++;
12773 Module * pInfoModule = currentModule;
12775 if (kind & ENCODE_MODULE_OVERRIDE)
12777 pInfoModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
12778 kind &= ~ENCODE_MODULE_OVERRIDE;
12781 MethodDesc * pMD = NULL;
12783 PCCOR_SIGNATURE pSig;
12792 case ENCODE_MODULE_HANDLE:
12793 result = (size_t)pInfoModule;
12796 case ENCODE_TYPE_HANDLE:
12797 case ENCODE_TYPE_DICTIONARY:
12799 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
12801 if (!th.IsTypeDesc())
12803 if (currentModule->IsReadyToRun())
12805 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12806 th.AsMethodTable()->EnsureInstanceActive();
12810 #ifdef FEATURE_WINMD_RESILIENT
12811 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12812 th.AsMethodTable()->EnsureInstanceActive();
12817 result = (size_t)th.AsPtr();
12821 case ENCODE_METHOD_HANDLE:
12822 case ENCODE_METHOD_DICTIONARY:
12824 MethodDesc * pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
12826 if (currentModule->IsReadyToRun())
12828 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12829 pMD->EnsureActive();
12832 result = (size_t)pMD;
12836 case ENCODE_FIELD_HANDLE:
12837 result = (size_t) ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
12840 #ifndef CROSSGEN_COMPILE
12841 case ENCODE_STRING_HANDLE:
12843 // We need to update strings atomically (due to NoStringInterning attribute). Note
12844 // that modules with string interning dont really need this, as the hash tables have
12845 // their own locking, but dont add more complexity for what will be the non common
12848 // We will have to lock and update the entry. (this is really a double check, where
12849 // the first check is done in the caller of this function)
12850 DWORD rid = CorSigUncompressData(pBlob);
12854 result = (size_t)StringObject::GetEmptyStringRefPtr();
12858 CrstHolder ch(pInfoModule->GetFixupCrst());
12860 if (!CORCOMPILE_IS_POINTER_TAGGED(*entry) && (*entry != NULL))
12862 // We lost the race, just return
12866 // For generic instantiations compiled into the ngen image of some other
12867 // client assembly, we need to ensure that we intern the string
12868 // in the defining assembly.
12869 bool mayNeedToSyncWithFixups = pInfoModule != currentModule;
12871 result = (size_t) pInfoModule->ResolveStringRef(TokenFromRid(rid, mdtString), currentModule->GetDomain(), mayNeedToSyncWithFixups);
12876 case ENCODE_VARARGS_SIG:
12878 mdSignature token = TokenFromRid(
12879 CorSigUncompressData(pBlob),
12882 IfFailThrow(pInfoModule->GetMDImport()->GetSigFromToken(token, &cSig, &pSig));
12888 case ENCODE_VARARGS_METHODREF:
12890 mdSignature token = TokenFromRid(
12891 CorSigUncompressData(pBlob),
12894 LPCSTR szName_Ignore;
12895 IfFailThrow(pInfoModule->GetMDImport()->GetNameAndSigOfMemberRef(token, &pSig, &cSig, &szName_Ignore));
12901 case ENCODE_VARARGS_METHODDEF:
12903 token = TokenFromRid(
12904 CorSigUncompressData(pBlob),
12907 IfFailThrow(pInfoModule->GetMDImport()->GetSigOfMethodDef(token, &cSig, &pSig));
12910 result = (size_t) CORINFO_VARARGS_HANDLE(currentModule->GetVASigCookie(Signature(pSig, cSig)));
12914 // ENCODE_METHOD_NATIVECALLABLE_HANDLE is same as ENCODE_METHOD_ENTRY_DEF_TOKEN
12915 // except for AddrOfCode
12916 case ENCODE_METHOD_NATIVE_ENTRY:
12917 case ENCODE_METHOD_ENTRY_DEF_TOKEN:
12919 mdToken MethodDef = TokenFromRid(CorSigUncompressData(pBlob), mdtMethodDef);
12920 pMD = MemberLoader::GetMethodDescFromMethodDef(pInfoModule, MethodDef, FALSE);
12922 pMD->PrepareForUseAsADependencyOfANativeImage();
12924 if (currentModule->IsReadyToRun())
12926 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12927 pMD->EnsureActive();
12933 case ENCODE_METHOD_ENTRY_REF_TOKEN:
12935 SigTypeContext typeContext;
12936 mdToken MemberRef = TokenFromRid(CorSigUncompressData(pBlob), mdtMemberRef);
12937 FieldDesc * pFD = NULL;
12940 MemberLoader::GetDescFromMemberRef(pInfoModule, MemberRef, &pMD, &pFD, &typeContext, FALSE /* strict metadata checks */, &th);
12941 _ASSERTE(pMD != NULL);
12943 pMD->PrepareForUseAsADependencyOfANativeImage();
12945 if (currentModule->IsReadyToRun())
12947 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12948 pMD->EnsureActive();
12952 #ifdef FEATURE_WINMD_RESILIENT
12953 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12954 pMD->EnsureActive();
12961 case ENCODE_METHOD_ENTRY:
12963 pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
12965 if (currentModule->IsReadyToRun())
12967 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12968 pMD->EnsureActive();
12972 if (kind == ENCODE_METHOD_NATIVE_ENTRY)
12974 result = COMDelegate::ConvertToCallback(pMD);
12978 result = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY);
12981 #ifndef _TARGET_ARM_
12982 if (CORCOMPILE_IS_PCODE_TAGGED(result))
12984 // There is a rare case where the function entrypoint may not be aligned. This could happen only for FCalls,
12985 // only on x86 and only if we failed to hardbind the fcall (e.g. ngen image for mscorlib.dll does not exist
12986 // and /nodependencies flag for ngen was used). The function entrypoints should be aligned in all other cases.
12988 // We will wrap the unaligned method entrypoint by funcptr stub with aligned entrypoint.
12989 _ASSERTE(pMD->IsFCall());
12990 result = pMD->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pMD);
12996 case ENCODE_SYNC_LOCK:
12998 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13000 result = (size_t) GetClassSync(th.AsMethodTable());
13004 case ENCODE_INDIRECT_PINVOKE_TARGET:
13006 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13008 _ASSERTE(pMethod->IsNDirect());
13009 NDirectMethodDesc *pMD = (NDirectMethodDesc*)pMethod;
13010 result = (size_t)(LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
13014 #if defined(PROFILING_SUPPORTED)
13015 case ENCODE_PROFILING_HANDLE:
13017 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13019 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
13020 // they shouldnever come here as they are called out in GetCompileFlag
13021 _ASSERTE(!pMethod->IsNoMetadata());
13023 FunctionID funId = (FunctionID)pMethod;
13025 BOOL bHookFunction = TRUE;
13026 CORINFO_PROFILING_HANDLE profilerHandle = (CORINFO_PROFILING_HANDLE)funId;
13029 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
13030 profilerHandle = (CORINFO_PROFILING_HANDLE) g_profControlBlock.pProfInterface->EEFunctionIDMapper(funId, &bHookFunction);
13031 END_PIN_PROFILER();
13034 // Profiling handle is opaque token. It does not have to be aligned thus we can not store it in the same location as token.
13035 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexClientData) = (SIZE_T)profilerHandle;
13039 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER].pfnHelper;
13040 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE].pfnHelper;
13041 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL].pfnHelper;
13045 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13046 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13047 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13051 #endif // PROFILING_SUPPORTED
13053 case ENCODE_STATIC_FIELD_ADDRESS:
13055 FieldDesc *pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13057 pField->GetEnclosingMethodTable()->CheckRestore();
13059 // We can take address of RVA field only since ngened code is domain neutral
13060 _ASSERTE(pField->IsRVA());
13062 // Field address is not aligned thus we can not store it in the same location as token.
13063 *EnsureWritablePages(entry+1) = (size_t)pField->GetStaticAddressHandle(NULL);
13067 case ENCODE_VIRTUAL_ENTRY_SLOT:
13069 DWORD slot = CorSigUncompressData(pBlob);
13071 TypeHandle ownerType = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13073 LOG((LF_ZAP, LL_INFO100000, " Fixup stub dispatch\n"));
13075 VirtualCallStubManager * pMgr = currentModule->GetLoaderAllocator()->GetVirtualCallStubManager();
13078 // We should be generating a stub indirection here, but the zapper already uses one level
13079 // of indirection, i.e. we would have to return IAT_PPVALUE to the JIT, and on the whole the JITs
13080 // aren't quite set up to accept that. Furthermore the call sequences would be different - at
13081 // the moment an indirection cell uses "call [cell-addr]" on x86, and instead we would want the
13082 // euqivalent of "call [[call-addr]]". This could perhaps be implemented as "call [eax]" </REVISIT_TODO>
13083 result = pMgr->GetCallStub(ownerType, slot);
13087 case ENCODE_CLASS_ID_FOR_STATICS:
13089 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13091 MethodTable * pMT = th.AsMethodTable();
13092 if (pMT->IsDynamicStatics())
13094 result = pMT->GetModuleDynamicEntryID();
13098 result = pMT->GetClassIndex();
13103 case ENCODE_MODULE_ID_FOR_STATICS:
13105 result = pInfoModule->GetModuleID();
13109 case ENCODE_MODULE_ID_FOR_GENERIC_STATICS:
13111 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13113 MethodTable * pMT = th.AsMethodTable();
13115 result = pMT->GetModuleForStatics()->GetModuleID();
13119 case ENCODE_ACTIVE_DEPENDENCY:
13121 Module* pModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13123 STRESS_LOG3(LF_ZAP,LL_INFO10000,"Modules are: %08x,%08x,%08x",currentModule,pInfoModule,pModule);
13124 pInfoModule->AddActiveDependency(pModule, FALSE);
13128 #ifdef FEATURE_READYTORUN
13129 case ENCODE_READYTORUN_HELPER:
13131 DWORD helperNum = CorSigUncompressData(pBlob);
13133 CorInfoHelpFunc corInfoHelpFunc = MapReadyToRunHelper((ReadyToRunHelper)helperNum);
13134 if (corInfoHelpFunc != CORINFO_HELP_UNDEF)
13136 result = (size_t)CEEJitInfo::getHelperFtnStatic(corInfoHelpFunc);
13142 case READYTORUN_HELPER_Module:
13144 Module * pPrevious = InterlockedCompareExchangeT(EnsureWritablePages((Module **)entry), pInfoModule, NULL);
13145 if (pPrevious != pInfoModule && pPrevious != NULL)
13146 COMPlusThrowHR(COR_E_FILELOAD, IDS_NATIVE_IMAGE_CANNOT_BE_LOADED_MULTIPLE_TIMES, pInfoModule->GetPath());
13151 case READYTORUN_HELPER_GSCookie:
13152 result = (size_t)GetProcessGSCookie();
13155 case READYTORUN_HELPER_DelayLoad_MethodCall:
13156 result = (size_t)GetEEFuncEntryPoint(DelayLoad_MethodCall);
13159 case READYTORUN_HELPER_DelayLoad_Helper:
13160 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper);
13163 case READYTORUN_HELPER_DelayLoad_Helper_Obj:
13164 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_Obj);
13167 case READYTORUN_HELPER_DelayLoad_Helper_ObjObj:
13168 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_ObjObj);
13172 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown READYTORUN_HELPER %d\n", helperNum);
13173 _ASSERTE(!"Unknown READYTORUN_HELPER");
13180 case ENCODE_FIELD_OFFSET:
13182 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13183 _ASSERTE(!pFD->IsStatic());
13184 _ASSERTE(!pFD->IsFieldOfValueType());
13186 DWORD dwOffset = (DWORD)sizeof(Object) + pFD->GetOffset();
13188 if (dwOffset > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13194 case ENCODE_FIELD_BASE_OFFSET:
13196 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13198 MethodTable * pMT = th.AsMethodTable();
13199 _ASSERTE(!pMT->IsValueType());
13201 DWORD dwOffsetBase = ReadyToRunInfo::GetFieldBaseOffset(pMT);
13202 if (dwOffsetBase > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13204 result = dwOffsetBase;
13208 case ENCODE_CHECK_TYPE_LAYOUT:
13210 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13211 MethodTable * pMT = th.AsMethodTable();
13212 _ASSERTE(pMT->IsValueType());
13214 if (!TypeLayoutCheck(pMT, pBlob))
13221 case ENCODE_CHECK_FIELD_OFFSET:
13223 DWORD dwExpectedOffset = CorSigUncompressData(pBlob);
13225 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13226 _ASSERTE(!pFD->IsStatic());
13228 DWORD dwOffset = pFD->GetOffset();
13229 if (!pFD->IsFieldOfValueType())
13230 dwOffset += sizeof(Object);
13232 if (dwExpectedOffset != dwOffset)
13238 #endif // FEATURE_READYTORUN
13240 #endif // CROSSGEN_COMPILE
13243 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown FIXUP_BLOB_KIND %d\n", kind);
13244 _ASSERTE(!"Unknown FIXUP_BLOB_KIND");
13249 *EnsureWritablePages(entry) = result;
13253 #endif // FEATURE_PREJIT
13255 void* CEEInfo::getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig,
13256 CorInfoHelperTailCallSpecialHandling flags)
13267 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)
13269 JIT_TO_EE_TRANSITION();
13271 Stub* pStub = CPUSTUBLINKER::CreateTailCallCopyArgsThunk(pSig, flags);
13273 ftn = (void*)pStub->GetEntryPoint();
13275 EE_TO_JIT_TRANSITION();
13277 #endif // _TARGET_AMD64_ || _TARGET_ARM_
13282 void CEEInfo::allocMem (
13283 ULONG hotCodeSize, /* IN */
13284 ULONG coldCodeSize, /* IN */
13285 ULONG roDataSize, /* IN */
13286 ULONG xcptnsCount, /* IN */
13287 CorJitAllocMemFlag flag, /* IN */
13288 void ** hotCodeBlock, /* OUT */
13289 void ** coldCodeBlock, /* OUT */
13290 void ** roDataBlock /* OUT */
13293 LIMITED_METHOD_CONTRACT;
13294 UNREACHABLE(); // only called on derived class.
13297 void CEEInfo::reserveUnwindInfo (
13298 BOOL isFunclet, /* IN */
13299 BOOL isColdCode, /* IN */
13300 ULONG unwindSize /* IN */
13303 LIMITED_METHOD_CONTRACT;
13304 UNREACHABLE(); // only called on derived class.
13307 void CEEInfo::allocUnwindInfo (
13308 BYTE * pHotCode, /* IN */
13309 BYTE * pColdCode, /* IN */
13310 ULONG startOffset, /* IN */
13311 ULONG endOffset, /* IN */
13312 ULONG unwindSize, /* IN */
13313 BYTE * pUnwindBlock, /* IN */
13314 CorJitFuncKind funcKind /* IN */
13317 LIMITED_METHOD_CONTRACT;
13318 UNREACHABLE(); // only called on derived class.
13321 void * CEEInfo::allocGCInfo (
13322 size_t size /* IN */
13325 LIMITED_METHOD_CONTRACT;
13326 UNREACHABLE_RET(); // only called on derived class.
13329 void CEEInfo::setEHcount (
13330 unsigned cEH /* IN */
13333 LIMITED_METHOD_CONTRACT;
13334 UNREACHABLE(); // only called on derived class.
13337 void CEEInfo::setEHinfo (
13338 unsigned EHnumber, /* IN */
13339 const CORINFO_EH_CLAUSE *clause /* IN */
13342 LIMITED_METHOD_CONTRACT;
13343 UNREACHABLE(); // only called on derived class.
13346 InfoAccessType CEEInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
13350 LIMITED_METHOD_CONTRACT;
13351 UNREACHABLE(); // only called on derived class.
13354 InfoAccessType CEEInfo::emptyStringLiteral(void ** ppValue)
13356 LIMITED_METHOD_CONTRACT;
13357 _ASSERTE(isVerifyOnly());
13358 *ppValue = (void *)0x10;
13362 void* CEEInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
13363 void **ppIndirection)
13365 LIMITED_METHOD_CONTRACT;
13366 _ASSERTE(isVerifyOnly());
13367 if (ppIndirection != NULL)
13368 *ppIndirection = NULL;
13369 return (void *)0x10;
13372 void* CEEInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
13373 void **ppIndirection)
13375 LIMITED_METHOD_CONTRACT;
13376 UNREACHABLE(); // only called on derived class.
13379 HRESULT CEEInfo::allocBBProfileBuffer (
13380 ULONG count, // The number of basic blocks that we have
13381 ProfileBuffer ** profileBuffer
13384 LIMITED_METHOD_CONTRACT;
13385 UNREACHABLE_RET(); // only called on derived class.
13388 HRESULT CEEInfo::getBBProfileData(
13389 CORINFO_METHOD_HANDLE ftnHnd,
13390 ULONG * count, // The number of basic blocks that we have
13391 ProfileBuffer ** profileBuffer,
13395 LIMITED_METHOD_CONTRACT;
13396 UNREACHABLE_RET(); // only called on derived class.
13400 void CEEInfo::recordCallSite(
13401 ULONG instrOffset, /* IN */
13402 CORINFO_SIG_INFO * callSig, /* IN */
13403 CORINFO_METHOD_HANDLE methodHandle /* IN */
13406 LIMITED_METHOD_CONTRACT;
13407 UNREACHABLE(); // only called on derived class.
13410 void CEEInfo::recordRelocation(
13411 void * location, /* IN */
13412 void * target, /* IN */
13413 WORD fRelocType, /* IN */
13414 WORD slotNum, /* IN */
13415 INT32 addlDelta /* IN */
13418 LIMITED_METHOD_CONTRACT;
13419 UNREACHABLE(); // only called on derived class.
13422 WORD CEEInfo::getRelocTypeHint(void * target)
13424 LIMITED_METHOD_CONTRACT;
13425 UNREACHABLE_RET(); // only called on derived class.
13428 void CEEInfo::getModuleNativeEntryPointRange(
13429 void ** pStart, /* OUT */
13430 void ** pEnd /* OUT */
13433 LIMITED_METHOD_CONTRACT;
13434 UNREACHABLE(); // only called on derived class.
13437 DWORD CEEInfo::getExpectedTargetArchitecture()
13439 LIMITED_METHOD_CONTRACT;
13441 return IMAGE_FILE_MACHINE_NATIVE;
13444 void CEEInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
13445 ICorDebugInfo::OffsetMapping *pMap)
13447 LIMITED_METHOD_CONTRACT;
13448 UNREACHABLE(); // only called on derived class.
13451 void CEEInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
13453 LIMITED_METHOD_CONTRACT;
13454 UNREACHABLE(); // only called on derived class.
13457 void* CEEInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
13458 void ** ppIndirection) /* OUT */
13460 LIMITED_METHOD_CONTRACT;
13461 UNREACHABLE(); // only called on derived class.
13464 // Active dependency helpers
13465 void CEEInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
13467 LIMITED_METHOD_CONTRACT;
13468 UNREACHABLE(); // only called on derived class.
13471 void CEEInfo::GetProfilingHandle(BOOL *pbHookFunction,
13472 void **pProfilerHandle,
13473 BOOL *pbIndirectedHandles)
13475 LIMITED_METHOD_CONTRACT;
13476 UNREACHABLE(); // only called on derived class.
13479 #endif // !DACCESS_COMPILE
13481 EECodeInfo::EECodeInfo()
13483 WRAPPER_NO_CONTRACT;
13485 m_codeAddress = NULL;
13491 #ifdef WIN64EXCEPTIONS
13492 m_pFunctionEntry = NULL;
13496 void EECodeInfo::Init(PCODE codeAddress)
13504 Init(codeAddress, ExecutionManager::GetScanFlags());
13507 void EECodeInfo::Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag)
13515 m_codeAddress = codeAddress;
13517 RangeSection * pRS = ExecutionManager::FindCodeRange(codeAddress, scanFlag);
13521 if (!pRS->pjit->JitCodeToMethodInfo(pRS, codeAddress, &m_pMD, this))
13532 #ifdef WIN64EXCEPTIONS
13533 m_pFunctionEntry = NULL;
13537 TADDR EECodeInfo::GetSavedMethodCode()
13540 // All EECodeInfo methods must be NOTHROW/GC_NOTRIGGER since they can
13541 // be used during GC.
13548 #if defined(HAVE_GCCOVER)
13549 _ASSERTE (!m_pMD->m_GcCover || GCStress<cfg_instr>::IsEnabled());
13550 if (GCStress<cfg_instr>::IsEnabled()
13551 && m_pMD->m_GcCover)
13553 _ASSERTE(m_pMD->m_GcCover->savedCode);
13555 // Make sure we return the TADDR of savedCode here. The byte array is not marshaled automatically.
13556 // The caller is responsible for any necessary marshaling.
13557 return PTR_TO_MEMBER_TADDR(GCCoverageInfo, m_pMD->m_GcCover, savedCode);
13559 #endif //defined(HAVE_GCCOVER)
13562 return GetStartAddress();
13565 TADDR EECodeInfo::GetStartAddress()
13574 return m_pJM->JitTokenToStartAddress(m_methodToken);
13577 #if defined(WIN64EXCEPTIONS)
13579 // ----------------------------------------------------------------------------
13580 // EECodeInfo::GetMainFunctionInfo
13583 // Simple helper to transform a funclet's EECodeInfo into a parent function EECodeInfo.
13586 // An EECodeInfo for the start of the main function body (offset 0).
13589 EECodeInfo EECodeInfo::GetMainFunctionInfo()
13591 LIMITED_METHOD_CONTRACT;
13594 EECodeInfo result = *this;
13595 result.m_relOffset = 0;
13596 result.m_codeAddress = this->GetStartAddress();
13597 result.m_pFunctionEntry = NULL;
13602 PTR_RUNTIME_FUNCTION EECodeInfo::GetFunctionEntry()
13604 LIMITED_METHOD_CONTRACT;
13607 if (m_pFunctionEntry == NULL)
13608 m_pFunctionEntry = m_pJM->LazyGetFunctionEntry(this);
13609 return m_pFunctionEntry;
13612 #if defined(_TARGET_AMD64_)
13614 BOOL EECodeInfo::HasFrameRegister()
13616 LIMITED_METHOD_CONTRACT;
13618 PTR_RUNTIME_FUNCTION pFuncEntry = GetFunctionEntry();
13619 _ASSERTE(pFuncEntry != NULL);
13621 BOOL fHasFrameRegister = FALSE;
13622 PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(GetModuleBase() + pFuncEntry->UnwindData);
13623 if (pUnwindInfo->FrameRegister != 0)
13625 fHasFrameRegister = TRUE;
13626 _ASSERTE(pUnwindInfo->FrameRegister == kRBP);
13629 return fHasFrameRegister;
13631 #endif // defined(_TARGET_AMD64_)
13633 #endif // defined(WIN64EXCEPTIONS)
13636 #if defined(_TARGET_AMD64_)
13637 // ----------------------------------------------------------------------------
13638 // EECodeInfo::GetUnwindInfoHelper
13641 // Simple helper to return a pointer to the UNWIND_INFO given the offset to the unwind info.
13642 // On DAC builds, this function will read the memory from the target process and create a host copy.
13645 // * unwindInfoOffset - This is the offset to the unwind info, relative to the beginning of the code heap
13646 // for jitted code or to the module base for ngned code. this->GetModuleBase() will return the correct
13650 // Return a pointer to the UNWIND_INFO. On DAC builds, this function will create a host copy of the
13651 // UNWIND_INFO and return a host pointer. It will correctly read all of the memory for the variable-sized
13655 UNWIND_INFO * EECodeInfo::GetUnwindInfoHelper(ULONG unwindInfoOffset)
13657 #if defined(DACCESS_COMPILE)
13658 return DacGetUnwindInfo(static_cast<TADDR>(this->GetModuleBase() + unwindInfoOffset));
13659 #else // !DACCESS_COMPILE
13660 return reinterpret_cast<UNWIND_INFO *>(this->GetModuleBase() + unwindInfoOffset);
13661 #endif // !DACCESS_COMPILE
13664 // ----------------------------------------------------------------------------
13665 // EECodeInfo::GetFixedStackSize
13668 // Return the fixed stack size of a specified managed method. This function DOES NOT take current control
13669 // PC into account. So the fixed stack size returned by this function is not valid in the prolog or
13673 // Return the fixed stack size.
13676 // * For method with dynamic stack allocations, this function will return the fixed stack size on X64 (the
13677 // stack size immediately after the prolog), and it will return 0 on IA64. This difference is due to
13678 // the different unwind info encoding.
13681 ULONG EECodeInfo::GetFixedStackSize()
13683 WRAPPER_NO_CONTRACT;
13686 ULONG uFixedStackSize = 0;
13689 GetOffsetsFromUnwindInfo(&uFixedStackSize, &uDummy);
13691 return uFixedStackSize;
13695 // The information returned by this method is only valid if we are not in a prolog or an epilog.
13696 // Since this method is only used for the security stackwalk cache, this assumption is valid, since
13697 // we cannot make a call in a prolog or an epilog.
13699 // The next assumption is that only rbp is used as a frame register in jitted code. There is an
13700 // assert below to guard this assumption.
13701 void EECodeInfo::GetOffsetsFromUnwindInfo(ULONG* pRSPOffset, ULONG* pRBPOffset)
13703 LIMITED_METHOD_CONTRACT;
13706 _ASSERTE((pRSPOffset != NULL) && (pRBPOffset != NULL));
13708 // moduleBase is a target address.
13709 TADDR moduleBase = GetModuleBase();
13711 DWORD unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(GetFunctionEntry());
13713 if ((unwindInfo & RUNTIME_FUNCTION_INDIRECT) != 0)
13715 unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(PTR_RUNTIME_FUNCTION(moduleBase + (unwindInfo & ~RUNTIME_FUNCTION_INDIRECT)));
13718 UNWIND_INFO * pInfo = GetUnwindInfoHelper(unwindInfo);
13719 if (pInfo->Flags & UNW_FLAG_CHAININFO)
13721 _ASSERTE(!"GetRbpOffset() - chained unwind info used, violating assumptions of the security stackwalk cache");
13725 // Either we are not using a frame pointer, or we are using rbp as the frame pointer.
13726 if ( (pInfo->FrameRegister != 0) && (pInfo->FrameRegister != kRBP) )
13728 _ASSERTE(!"GetRbpOffset() - non-RBP frame pointer used, violating assumptions of the security stackwalk cache");
13732 // Walk the unwind info.
13733 ULONG StackOffset = 0;
13734 ULONG StackSize = 0;
13735 for (int i = 0; i < pInfo->CountOfUnwindCodes; i++)
13737 ULONG UnwindOp = pInfo->UnwindCode[i].UnwindOp;
13738 ULONG OpInfo = pInfo->UnwindCode[i].OpInfo;
13740 if (UnwindOp == UWOP_SAVE_NONVOL)
13742 if (OpInfo == kRBP)
13744 StackOffset = pInfo->UnwindCode[i+1].FrameOffset * 8;
13747 else if (UnwindOp == UWOP_SAVE_NONVOL_FAR)
13749 if (OpInfo == kRBP)
13751 StackOffset = pInfo->UnwindCode[i + 1].FrameOffset;
13752 StackOffset += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
13755 else if (UnwindOp == UWOP_ALLOC_SMALL)
13757 StackSize += (OpInfo * 8) + 8;
13759 else if (UnwindOp == UWOP_ALLOC_LARGE)
13761 ULONG IncrementalStackSize = pInfo->UnwindCode[i + 1].FrameOffset;
13764 IncrementalStackSize *= 8;
13768 IncrementalStackSize += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
13770 // This is a special opcode. We need to increment the index by 1 in addition to the normal adjustments.
13773 StackSize += IncrementalStackSize;
13775 else if (UnwindOp == UWOP_PUSH_NONVOL)
13777 // Because of constraints on epilogs, this unwind opcode is always last in the unwind code array.
13778 // This means that StackSize has been initialized already when we first see this unwind opcode.
13779 // Note that the intial value of StackSize does not include the stack space used for pushes.
13780 // Thus, here we only need to increment StackSize 8 bytes at a time until we see the unwind code for "push rbp".
13781 if (OpInfo == kRBP)
13783 StackOffset = StackSize;
13789 // Adjust the index into the unwind code array.
13790 i += UnwindOpExtraSlotTable[UnwindOp];
13793 *pRSPOffset = StackSize + 8; // add 8 for the return address
13794 *pRBPOffset = StackOffset;
13799 #if defined(_DEBUG) && defined(HAVE_GCCOVER)
13801 LPVOID EECodeInfo::findNextFunclet (LPVOID pvFuncletStart, SIZE_T cbCode, LPVOID *ppvFuncletEnd)
13810 PT_RUNTIME_FUNCTION pFunctionEntry;
13811 ULONGLONG uImageBase;
13813 EECodeInfo codeInfo;
13814 codeInfo.Init((PCODE)pvFuncletStart);
13815 pFunctionEntry = codeInfo.GetFunctionEntry();
13816 uImageBase = (ULONGLONG)codeInfo.GetModuleBase();
13817 #else // !FEATURE_PAL
13819 // This is GCStress debug only - use the slow OS APIs to enumerate funclets
13822 pFunctionEntry = (PT_RUNTIME_FUNCTION) RtlLookupFunctionEntry((ULONGLONG)pvFuncletStart,
13828 if (pFunctionEntry != NULL)
13830 #ifdef FEATURE_PREJIT
13831 // workaround: Check for indirect entry that is generated for cold part of main method body.
13832 if ((TADDR)pvFuncletStart < (TADDR)uImageBase + pFunctionEntry->BeginAddress ||
13833 (TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart)
13835 Module * pZapModule = ExecutionManager::FindZapModule((TADDR)pvFuncletStart);
13836 NGenLayoutInfo * pLayoutInfo = pZapModule->GetNGenLayoutInfo();
13838 int ColdFunctionIndex = NativeUnwindInfoLookupTable::LookupUnwindInfoForMethod((DWORD)((TADDR)pvFuncletStart - uImageBase),
13839 pLayoutInfo->m_pRuntimeFunctions[2],
13840 0, pLayoutInfo->m_nRuntimeFunctions[2] - 1);
13842 pFunctionEntry = pLayoutInfo->m_pRuntimeFunctions[2] + ColdFunctionIndex;
13846 _ASSERTE((TADDR)pvFuncletStart == (TADDR)uImageBase + pFunctionEntry->BeginAddress);
13847 _ASSERTE((TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart + cbCode);
13848 *ppvFuncletEnd = (LPVOID)(uImageBase + pFunctionEntry->EndAddress);
13849 return (LPVOID)(uImageBase + pFunctionEntry->BeginAddress);
13852 pvFuncletStart = (LPVOID)((TADDR)pvFuncletStart + 1);
13858 #endif // defined(_DEBUG) && !defined(HAVE_GCCOVER)
13859 #endif // defined(_TARGET_AMD64_)