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 const char* CEEInfo::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftnHnd, const char** className, const char** namespaceName)
6472 const char* result = NULL;
6473 const char* classResult = NULL;
6474 const char* namespaceResult = NULL;
6476 JIT_TO_EE_TRANSITION();
6478 MethodDesc *ftn = GetMethod(ftnHnd);
6479 mdMethodDef token = ftn->GetMemberDef();
6481 if (!IsNilToken(token))
6483 if (!FAILED(ftn->GetMDImport()->GetNameOfMethodDef(token, &result)))
6485 MethodTable* pMT = ftn->GetMethodTable();
6486 classResult = pMT->GetFullyQualifiedNameInfo(&namespaceResult);
6490 if (className != NULL)
6492 *className = classResult;
6495 if (namespaceName != NULL)
6497 *namespaceName = namespaceResult;
6500 EE_TO_JIT_TRANSITION();
6505 /*********************************************************************/
6506 DWORD CEEInfo::getMethodAttribs (CORINFO_METHOD_HANDLE ftn)
6517 JIT_TO_EE_TRANSITION();
6519 result = getMethodAttribsInternal(ftn);
6521 EE_TO_JIT_TRANSITION();
6526 /*********************************************************************/
6527 DWORD CEEInfo::getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftn)
6529 STANDARD_VM_CONTRACT;
6532 returns method attribute flags (defined in corhdr.h)
6534 NOTE: This doesn't return certain method flags
6535 (mdAssem, mdFamANDAssem, mdFamORAssem, mdPrivateScope)
6538 MethodDesc* pMD = GetMethod(ftn);
6540 if (pMD->IsLCGMethod())
6542 return CORINFO_FLG_STATIC | CORINFO_FLG_DONT_INLINE | CORINFO_FLG_NOSECURITYWRAP;
6545 DWORD result = CORINFO_FLG_NOSECURITYWRAP;
6547 // <REVISIT_TODO>@todo: can we git rid of CORINFO_FLG_ stuff and just include cor.h?</REVISIT_TODO>
6549 DWORD attribs = pMD->GetAttrs();
6551 if (IsMdFamily(attribs))
6552 result |= CORINFO_FLG_PROTECTED;
6553 if (IsMdStatic(attribs))
6554 result |= CORINFO_FLG_STATIC;
6555 if (pMD->IsSynchronized())
6556 result |= CORINFO_FLG_SYNCH;
6557 if (pMD->IsFCallOrIntrinsic())
6558 result |= CORINFO_FLG_NOGCCHECK | CORINFO_FLG_INTRINSIC;
6559 if (pMD->IsJitIntrinsic())
6560 result |= CORINFO_FLG_JIT_INTRINSIC;
6561 if (IsMdVirtual(attribs))
6562 result |= CORINFO_FLG_VIRTUAL;
6563 if (IsMdAbstract(attribs))
6564 result |= CORINFO_FLG_ABSTRACT;
6565 if (IsMdRTSpecialName(attribs))
6567 LPCUTF8 pName = pMD->GetName();
6568 if (IsMdInstanceInitializer(attribs, pName) ||
6569 IsMdClassConstructor(attribs, pName))
6570 result |= CORINFO_FLG_CONSTRUCTOR;
6574 // See if we need to embed a .cctor call at the head of the
6578 MethodTable* pMT = pMD->GetMethodTable();
6580 // method or class might have the final bit
6581 if (IsMdFinal(attribs) || pMT->IsSealed())
6583 result |= CORINFO_FLG_FINAL;
6586 if (pMD->IsEnCAddedMethod())
6588 result |= CORINFO_FLG_EnC;
6591 if (pMD->IsSharedByGenericInstantiations())
6593 result |= CORINFO_FLG_SHAREDINST;
6596 if (pMD->IsNDirect())
6598 result |= CORINFO_FLG_PINVOKE;
6601 if (IsMdRequireSecObject(attribs))
6603 // Assume all methods marked as DynamicSecurity are
6604 // marked that way because they use StackCrawlMark to identify
6606 // See comments in canInline or canTailCall
6607 result |= CORINFO_FLG_DONT_INLINE_CALLER;
6610 // Check for an inlining directive.
6611 if (pMD->IsNotInline())
6613 /* Function marked as not inlineable */
6614 result |= CORINFO_FLG_DONT_INLINE;
6616 // AggressiveInlining only makes sense for IL methods.
6617 else if (pMD->IsIL() && IsMiAggressiveInlining(pMD->GetImplAttrs()))
6619 result |= CORINFO_FLG_FORCEINLINE;
6622 if (pMT->IsDelegate() && ((DelegateEEClass*)(pMT->GetClass()))->GetInvokeMethod() == pMD)
6624 // This is now used to emit efficient invoke code for any delegate invoke,
6625 // including multicast.
6626 result |= CORINFO_FLG_DELEGATE_INVOKE;
6632 /*********************************************************************/
6633 void CEEInfo::setMethodAttribs (
6634 CORINFO_METHOD_HANDLE ftnHnd,
6635 CorInfoMethodRuntimeFlags attribs)
6644 JIT_TO_EE_TRANSITION();
6646 MethodDesc* ftn = GetMethod(ftnHnd);
6648 if (attribs & CORINFO_FLG_BAD_INLINEE)
6650 BOOL fCacheInliningHint = TRUE;
6652 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6653 if (IsCompilationProcess())
6655 // Since we are running managed code during NGen the inlining hint may be
6656 // changing underneeth us as the code is JITed. We need to prevent the inlining
6657 // hints from changing once we start to use them to place IL in the image.
6658 if (!g_pCEECompileInfo->IsCachingOfInliningHintsEnabled())
6660 fCacheInliningHint = FALSE;
6664 // Don't cache inlining hints inside mscorlib during NGen of other assemblies,
6665 // since mscorlib is loaded domain neutral and will survive worker process recycling,
6666 // causing determinism problems.
6667 Module * pModule = ftn->GetModule();
6668 if (pModule->IsSystem() && pModule->HasNativeImage())
6670 fCacheInliningHint = FALSE;
6676 if (fCacheInliningHint)
6678 ftn->SetNotInline(true);
6682 EE_TO_JIT_TRANSITION();
6685 /*********************************************************************/
6687 void getMethodInfoILMethodHeaderHelper(
6688 COR_ILMETHOD_DECODER* header,
6689 CORINFO_METHOD_INFO* methInfo
6692 LIMITED_METHOD_CONTRACT;
6694 methInfo->ILCode = const_cast<BYTE*>(header->Code);
6695 methInfo->ILCodeSize = header->GetCodeSize();
6696 methInfo->maxStack = static_cast<unsigned short>(header->GetMaxStack());
6697 methInfo->EHcount = static_cast<unsigned short>(header->EHCount());
6700 (CorInfoOptions)((header->GetFlags() & CorILMethod_InitLocals) ? CORINFO_OPT_INIT_LOCALS : 0) ;
6703 mdToken FindGenericMethodArgTypeSpec(IMDInternalImport* pInternalImport)
6705 STANDARD_VM_CONTRACT;
6707 HENUMInternalHolder hEnumTypeSpecs(pInternalImport);
6710 static const BYTE signature[] = { ELEMENT_TYPE_MVAR, 0 };
6712 hEnumTypeSpecs.EnumAllInit(mdtTypeSpec);
6713 while (hEnumTypeSpecs.EnumNext(&token))
6715 PCCOR_SIGNATURE pSig;
6717 IfFailThrow(pInternalImport->GetTypeSpecFromToken(token, &pSig, &cbSig));
6718 if (cbSig == sizeof(signature) && memcmp(pSig, signature, cbSig) == 0)
6722 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6725 /*********************************************************************
6727 IL is the most efficient and portable way to implement certain low level methods
6728 in mscorlib.dll. Unfortunately, there is no good way to link IL into mscorlib.dll today.
6729 Until we find a good way to link IL into mscorlib.dll, we will provide the IL implementation here.
6731 - All IL intrinsincs are members of System.Runtime.CompilerServices.JitHelpers class
6732 - All IL intrinsincs should be kept very simple. Implement the minimal reusable version of
6733 unsafe construct and depend on inlining to do the rest.
6734 - The C# implementation of the IL intrinsic should be good enough for functionalily. Everything should work
6735 correctly (but slower) if the IL intrinsics are removed.
6737 *********************************************************************/
6739 bool getILIntrinsicImplementation(MethodDesc * ftn,
6740 CORINFO_METHOD_INFO * methInfo)
6742 STANDARD_VM_CONTRACT;
6744 // Precondition: ftn is a method in mscorlib
6745 _ASSERTE(ftn->GetModule()->IsSystem());
6747 mdMethodDef tk = ftn->GetMemberDef();
6749 // Compare tokens to cover all generic instantiations
6750 // The body of the first method is simply ret Arg0. The second one first casts the arg to I4.
6752 if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_CAST)->GetMemberDef())
6754 // Return the argument that was passed in.
6755 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
6756 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6757 methInfo->ILCodeSize = sizeof(ilcode);
6758 methInfo->maxStack = 1;
6759 methInfo->EHcount = 0;
6760 methInfo->options = (CorInfoOptions)0;
6763 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_CAST_TO_STACKPTR)->GetMemberDef())
6765 // Return the argument that was passed in converted to IntPtr
6766 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I, CEE_RET };
6767 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6768 methInfo->ILCodeSize = sizeof(ilcode);
6769 methInfo->maxStack = 1;
6770 methInfo->EHcount = 0;
6771 methInfo->options = (CorInfoOptions)0;
6774 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST)->GetMemberDef())
6776 // Normally we would follow the above pattern and unconditionally replace the IL,
6777 // relying on generic type constraints to guarantee that it will only ever be instantiated
6778 // on the type/size of argument we expect.
6780 // However C#/CLR does not support restricting a generic type to be an Enum, so the best
6781 // we can do is constrain it to be a value type. This is fine for run time, since we only
6782 // ever create instantiations on 4 byte or less Enums. But during NGen we may compile instantiations
6783 // on other value types (to be specific, every value type instatiation of EqualityComparer
6784 // because of its TypeDependencyAttribute; here again we would like to restrict this to
6785 // 4 byte or less Enums but cannot).
6787 // This IL is invalid for those instantiations, and replacing it would lead to all sorts of
6788 // errors at NGen time. So we only replace it for instantiations where it would be valid,
6789 // leaving the others, which we should never execute, with the C# implementation of throwing.
6791 _ASSERTE(ftn->HasMethodInstantiation());
6792 Instantiation inst = ftn->GetMethodInstantiation();
6794 _ASSERTE(inst.GetNumArgs() == 1);
6795 CorElementType et = inst[0].GetVerifierCorElementType();
6796 if (et == ELEMENT_TYPE_I4 ||
6797 et == ELEMENT_TYPE_U4 ||
6798 et == ELEMENT_TYPE_I2 ||
6799 et == ELEMENT_TYPE_U2 ||
6800 et == ELEMENT_TYPE_I1 ||
6801 et == ELEMENT_TYPE_U1)
6803 // Cast to I4 and return the argument that was passed in.
6804 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I4, CEE_RET };
6805 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6806 methInfo->ILCodeSize = sizeof(ilcode);
6807 methInfo->maxStack = 1;
6808 methInfo->EHcount = 0;
6809 methInfo->options = (CorInfoOptions)0;
6813 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG)->GetMemberDef())
6815 // The the comment above on why this is is not an unconditional replacement. This case handles
6816 // Enums backed by 8 byte values.
6818 _ASSERTE(ftn->HasMethodInstantiation());
6819 Instantiation inst = ftn->GetMethodInstantiation();
6821 _ASSERTE(inst.GetNumArgs() == 1);
6822 CorElementType et = inst[0].GetVerifierCorElementType();
6823 if (et == ELEMENT_TYPE_I8 ||
6824 et == ELEMENT_TYPE_U8)
6826 // Cast to I8 and return the argument that was passed in.
6827 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I8, CEE_RET };
6828 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6829 methInfo->ILCodeSize = sizeof(ilcode);
6830 methInfo->maxStack = 1;
6831 methInfo->EHcount = 0;
6832 methInfo->options = (CorInfoOptions)0;
6836 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__GET_RAW_SZ_ARRAY_DATA)->GetMemberDef())
6838 mdToken tokArrayPinningHelper = MscorlibBinder::GetField(FIELD__ARRAY_PINNING_HELPER__M_ARRAY_DATA)->GetMemberDef();
6840 static BYTE ilcode[] = { CEE_LDARG_0,
6844 ilcode[2] = (BYTE)(tokArrayPinningHelper);
6845 ilcode[3] = (BYTE)(tokArrayPinningHelper >> 8);
6846 ilcode[4] = (BYTE)(tokArrayPinningHelper >> 16);
6847 ilcode[5] = (BYTE)(tokArrayPinningHelper >> 24);
6849 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6850 methInfo->ILCodeSize = sizeof(ilcode);
6851 methInfo->maxStack = 1;
6852 methInfo->EHcount = 0;
6853 methInfo->options = (CorInfoOptions)0;
6860 bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
6861 CORINFO_METHOD_INFO * methInfo)
6863 STANDARD_VM_CONTRACT;
6865 // Precondition: ftn is a method in mscorlib
6866 _ASSERTE(ftn->GetModule()->IsSystem());
6868 mdMethodDef tk = ftn->GetMemberDef();
6870 if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_POINTER)->GetMemberDef())
6872 // Return the argument that was passed in.
6873 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_U, CEE_RET };
6874 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6875 methInfo->ILCodeSize = sizeof(ilcode);
6876 methInfo->maxStack = 1;
6877 methInfo->EHcount = 0;
6878 methInfo->options = (CorInfoOptions)0;
6881 if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__SIZEOF)->GetMemberDef())
6883 _ASSERTE(ftn->HasMethodInstantiation());
6884 Instantiation inst = ftn->GetMethodInstantiation();
6886 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
6887 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6889 static BYTE ilcode[] = { CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0, CEE_RET };
6891 ilcode[2] = (BYTE)(tokGenericArg);
6892 ilcode[3] = (BYTE)(tokGenericArg >> 8);
6893 ilcode[4] = (BYTE)(tokGenericArg >> 16);
6894 ilcode[5] = (BYTE)(tokGenericArg >> 24);
6896 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6897 methInfo->ILCodeSize = sizeof(ilcode);
6898 methInfo->maxStack = 1;
6899 methInfo->EHcount = 0;
6900 methInfo->options = (CorInfoOptions)0;
6903 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef() ||
6904 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__OBJECT_AS)->GetMemberDef())
6906 // Return the argument that was passed in.
6907 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
6908 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6909 methInfo->ILCodeSize = sizeof(ilcode);
6910 methInfo->maxStack = 1;
6911 methInfo->EHcount = 0;
6912 methInfo->options = (CorInfoOptions)0;
6915 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD)->GetMemberDef() ||
6916 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_ADD)->GetMemberDef())
6918 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6920 static BYTE ilcode[] = { CEE_LDARG_1,
6921 CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0,
6928 ilcode[3] = (BYTE)(tokGenericArg);
6929 ilcode[4] = (BYTE)(tokGenericArg >> 8);
6930 ilcode[5] = (BYTE)(tokGenericArg >> 16);
6931 ilcode[6] = (BYTE)(tokGenericArg >> 24);
6933 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6934 methInfo->ILCodeSize = sizeof(ilcode);
6935 methInfo->maxStack = 2;
6936 methInfo->EHcount = 0;
6937 methInfo->options = (CorInfoOptions)0;
6940 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD_BYTE_OFFSET)->GetMemberDef())
6942 static BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_ADD, CEE_RET };
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_ARE_SAME)->GetMemberDef())
6953 // Compare the two arguments
6954 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CEQ & 0xFF), CEE_RET };
6955 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6956 methInfo->ILCodeSize = sizeof(ilcode);
6957 methInfo->maxStack = 2;
6958 methInfo->EHcount = 0;
6959 methInfo->options = (CorInfoOptions)0;
6962 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_INIT_BLOCK_UNALIGNED)->GetMemberDef())
6964 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_LDARG_2, CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 0x01, CEE_PREFIX1, (CEE_INITBLK & 0xFF), CEE_RET };
6965 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6966 methInfo->ILCodeSize = sizeof(ilcode);
6967 methInfo->maxStack = 3;
6968 methInfo->EHcount = 0;
6969 methInfo->options = (CorInfoOptions)0;
6972 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_READ_UNALIGNED)->GetMemberDef() ||
6973 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_READ_UNALIGNED)->GetMemberDef())
6975 _ASSERTE(ftn->HasMethodInstantiation());
6976 Instantiation inst = ftn->GetMethodInstantiation();
6977 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
6978 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6980 static const BYTE ilcode[]
6983 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
6984 CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6988 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6989 methInfo->ILCodeSize = sizeof(ilcode);
6990 methInfo->maxStack = 2;
6991 methInfo->EHcount = 0;
6992 methInfo->options = (CorInfoOptions)0;
6995 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_WRITE_UNALIGNED)->GetMemberDef() ||
6996 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_WRITE_UNALIGNED)->GetMemberDef())
6998 _ASSERTE(ftn->HasMethodInstantiation());
6999 Instantiation inst = ftn->GetMethodInstantiation();
7000 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7001 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
7003 static const BYTE ilcode[]
7007 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
7008 CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7012 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7013 methInfo->ILCodeSize = sizeof(ilcode);
7014 methInfo->maxStack = 2;
7015 methInfo->EHcount = 0;
7016 methInfo->options = (CorInfoOptions)0;
7023 bool getILIntrinsicImplementationForVolatile(MethodDesc * ftn,
7024 CORINFO_METHOD_INFO * methInfo)
7026 STANDARD_VM_CONTRACT;
7029 // This replaces the implementations of Volatile.* in mscorlib with more efficient ones.
7030 // We do this because we cannot otherwise express these in C#. What we *want* to do is
7031 // to treat the byref args to these methods as "volatile." In pseudo-C#, this would look
7034 // int Read(ref volatile int location)
7039 // However, C# does not yet provide a way to declare a byref as "volatile." So instead,
7040 // we substitute raw IL bodies for these methods that use the correct volatile instructions.
7043 // Precondition: ftn is a method in mscorlib in the System.Threading.Volatile class
7044 _ASSERTE(ftn->GetModule()->IsSystem());
7045 _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__VOLATILE));
7046 _ASSERTE(strcmp(ftn->GetMethodTable()->GetClass()->GetDebugClassName(), "System.Threading.Volatile") == 0);
7048 const size_t VolatileMethodBodySize = 6;
7050 struct VolatileMethodImpl
7052 BinderMethodID methodId;
7053 BYTE body[VolatileMethodBodySize];
7056 #define VOLATILE_IMPL(type, loadinst, storeinst) \
7058 METHOD__VOLATILE__READ_##type, \
7061 CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7063 CEE_NOP, /*pad to VolatileMethodBodySize bytes*/ \
7068 METHOD__VOLATILE__WRITE_##type, \
7072 CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7078 static const VolatileMethodImpl volatileImpls[] =
7080 VOLATILE_IMPL(T, CEE_LDIND_REF, CEE_STIND_REF)
7081 VOLATILE_IMPL(Bool, CEE_LDIND_I1, CEE_STIND_I1)
7082 VOLATILE_IMPL(Int, CEE_LDIND_I4, CEE_STIND_I4)
7083 VOLATILE_IMPL(IntPtr, CEE_LDIND_I, CEE_STIND_I)
7084 VOLATILE_IMPL(UInt, CEE_LDIND_U4, CEE_STIND_I4)
7085 VOLATILE_IMPL(UIntPtr, CEE_LDIND_I, CEE_STIND_I)
7086 VOLATILE_IMPL(SByt, CEE_LDIND_I1, CEE_STIND_I1)
7087 VOLATILE_IMPL(Byte, CEE_LDIND_U1, CEE_STIND_I1)
7088 VOLATILE_IMPL(Shrt, CEE_LDIND_I2, CEE_STIND_I2)
7089 VOLATILE_IMPL(UShrt, CEE_LDIND_U2, CEE_STIND_I2)
7090 VOLATILE_IMPL(Flt, CEE_LDIND_R4, CEE_STIND_R4)
7093 // Ordinary volatile loads and stores only guarantee atomicity for pointer-sized (or smaller) data.
7094 // So, on 32-bit platforms we must use Interlocked operations instead for the 64-bit types.
7095 // The implementation in mscorlib already does this, so we will only substitute a new
7096 // IL body if we're running on a 64-bit platform.
7098 IN_WIN64(VOLATILE_IMPL(Long, CEE_LDIND_I8, CEE_STIND_I8))
7099 IN_WIN64(VOLATILE_IMPL(ULong, CEE_LDIND_I8, CEE_STIND_I8))
7100 IN_WIN64(VOLATILE_IMPL(Dbl, CEE_LDIND_R8, CEE_STIND_R8))
7103 mdMethodDef md = ftn->GetMemberDef();
7104 for (unsigned i = 0; i < NumItems(volatileImpls); i++)
7106 if (md == MscorlibBinder::GetMethod(volatileImpls[i].methodId)->GetMemberDef())
7108 methInfo->ILCode = const_cast<BYTE*>(volatileImpls[i].body);
7109 methInfo->ILCodeSize = VolatileMethodBodySize;
7110 methInfo->maxStack = 2;
7111 methInfo->EHcount = 0;
7112 methInfo->options = (CorInfoOptions)0;
7120 bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn,
7121 CORINFO_METHOD_INFO * methInfo)
7123 STANDARD_VM_CONTRACT;
7125 // Precondition: ftn is a method in mscorlib in the System.Threading.Interlocked class
7126 _ASSERTE(ftn->GetModule()->IsSystem());
7127 _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__INTERLOCKED));
7129 // We are only interested if ftn's token and CompareExchange<T> token match
7130 if (ftn->GetMemberDef() != MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_T)->GetMemberDef())
7133 // Get MethodDesc for System.Threading.Interlocked.CompareExchangeFast()
7134 MethodDesc* cmpxchgFast = MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_OBJECT);
7136 // The MethodDesc lookup must not fail, and it should have the name "CompareExchangeFast"
7137 _ASSERTE(cmpxchgFast != NULL);
7138 _ASSERTE(strcmp(cmpxchgFast->GetName(), "CompareExchange") == 0);
7140 // Setup up the body of the method
7141 static BYTE il[] = {
7149 // Get the token for System.Threading.Interlocked.CompareExchangeFast(), and patch [target]
7150 mdMethodDef cmpxchgFastToken = cmpxchgFast->GetMemberDef();
7151 il[4] = (BYTE)((int)cmpxchgFastToken >> 0);
7152 il[5] = (BYTE)((int)cmpxchgFastToken >> 8);
7153 il[6] = (BYTE)((int)cmpxchgFastToken >> 16);
7154 il[7] = (BYTE)((int)cmpxchgFastToken >> 24);
7156 // Initialize methInfo
7157 methInfo->ILCode = const_cast<BYTE*>(il);
7158 methInfo->ILCodeSize = sizeof(il);
7159 methInfo->maxStack = 3;
7160 methInfo->EHcount = 0;
7161 methInfo->options = (CorInfoOptions)0;
7166 bool getILIntrinsicImplementationForRuntimeHelpers(MethodDesc * ftn,
7167 CORINFO_METHOD_INFO * methInfo)
7169 STANDARD_VM_CONTRACT;
7171 // Precondition: ftn is a method in mscorlib
7172 _ASSERTE(ftn->GetModule()->IsSystem());
7174 mdMethodDef tk = ftn->GetMemberDef();
7176 if (tk == MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_REFERENCE_OR_CONTAINS_REFERENCES)->GetMemberDef())
7178 _ASSERTE(ftn->HasMethodInstantiation());
7179 Instantiation inst = ftn->GetMethodInstantiation();
7181 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7182 TypeHandle typeHandle = inst[0];
7183 MethodTable * methodTable = typeHandle.GetMethodTable();
7185 static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
7186 static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };
7188 if (!methodTable->IsValueType() || methodTable->ContainsPointers())
7190 methInfo->ILCode = const_cast<BYTE*>(returnTrue);
7194 methInfo->ILCode = const_cast<BYTE*>(returnFalse);
7197 methInfo->ILCodeSize = sizeof(returnTrue);
7198 methInfo->maxStack = 1;
7199 methInfo->EHcount = 0;
7200 methInfo->options = (CorInfoOptions)0;
7207 //---------------------------------------------------------------------------------------
7211 getMethodInfoHelper(
7213 CORINFO_METHOD_HANDLE ftnHnd,
7214 COR_ILMETHOD_DECODER * header,
7215 CORINFO_METHOD_INFO * methInfo)
7217 STANDARD_VM_CONTRACT;
7219 _ASSERTE(ftn == GetMethod(ftnHnd));
7221 methInfo->ftn = ftnHnd;
7222 methInfo->scope = GetScopeHandle(ftn);
7223 methInfo->regionKind = CORINFO_REGION_JIT;
7225 // For Jitted code the regionKind is JIT;
7226 // For Ngen-ed code the zapper will set this to HOT or COLD, if we
7227 // are using IBC data to partition methods into Hot/Cold regions
7229 /* Grab information from the IL header */
7231 PCCOR_SIGNATURE pLocalSig = NULL;
7232 DWORD cbLocalSig = 0;
7236 bool fILIntrinsic = false;
7238 MethodTable * pMT = ftn->GetMethodTable();
7240 if (pMT->GetModule()->IsSystem())
7242 if (MscorlibBinder::IsClass(pMT, CLASS__JIT_HELPERS))
7244 fILIntrinsic = getILIntrinsicImplementation(ftn, methInfo);
7246 else if (MscorlibBinder::IsClass(pMT, CLASS__UNSAFE))
7248 fILIntrinsic = getILIntrinsicImplementationForUnsafe(ftn, methInfo);
7250 else if (MscorlibBinder::IsClass(pMT, CLASS__INTERLOCKED))
7252 fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo);
7254 else if (MscorlibBinder::IsClass(pMT, CLASS__VOLATILE))
7256 fILIntrinsic = getILIntrinsicImplementationForVolatile(ftn, methInfo);
7258 else if (MscorlibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS))
7260 fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo);
7266 getMethodInfoILMethodHeaderHelper(header, methInfo);
7268 // Workaround for https://github.com/dotnet/coreclr/issues/1279
7269 // Set init locals bit to zero for system module unless profiler may have overrided it. Remove once we have
7270 // better solution for this issue.
7271 if (pMT->GetModule()->IsSystem() && !(CORProfilerDisableAllNGenImages() || CORProfilerUseProfileImages()))
7272 methInfo->options = (CorInfoOptions)0;
7274 pLocalSig = header->LocalVarSig;
7275 cbLocalSig = header->cbLocalVarSig;
7280 _ASSERTE(ftn->IsDynamicMethod());
7282 DynamicResolver * pResolver = ftn->AsDynamicMethodDesc()->GetResolver();
7283 unsigned int EHCount;
7284 methInfo->ILCode = pResolver->GetCodeInfo(&methInfo->ILCodeSize,
7285 &methInfo->maxStack,
7288 methInfo->EHcount = (unsigned short)EHCount;
7289 SigPointer localSig = pResolver->GetLocalSig();
7290 localSig.GetSignature(&pLocalSig, &cbLocalSig);
7293 methInfo->options = (CorInfoOptions)(((UINT32)methInfo->options) |
7294 ((ftn->AcquiresInstMethodTableFromThis() ? CORINFO_GENERICS_CTXT_FROM_THIS : 0) |
7295 (ftn->RequiresInstMethodTableArg() ? CORINFO_GENERICS_CTXT_FROM_METHODTABLE : 0) |
7296 (ftn->RequiresInstMethodDescArg() ? CORINFO_GENERICS_CTXT_FROM_METHODDESC : 0)));
7298 // EEJitManager::ResolveEHClause and CrawlFrame::GetExactGenericInstantiations
7299 // need to be able to get to CORINFO_GENERICS_CTXT_MASK if there are any
7300 // catch clauses like "try {} catch(MyException<T> e) {}".
7301 // Such constructs are rare, and having to extend the lifetime of variable
7302 // for such cases is reasonable
7304 if (methInfo->options & CORINFO_GENERICS_CTXT_MASK)
7306 #if defined(PROFILING_SUPPORTED)
7307 BOOL fProfilerRequiresGenericsContextForEnterLeave = FALSE;
7309 BEGIN_PIN_PROFILER(CORProfilerPresent());
7310 if (g_profControlBlock.pProfInterface->RequiresGenericsContextForEnterLeave())
7312 fProfilerRequiresGenericsContextForEnterLeave = TRUE;
7316 if (fProfilerRequiresGenericsContextForEnterLeave)
7318 methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7321 #endif // defined(PROFILING_SUPPORTED)
7323 // Check all the exception clauses
7325 if (ftn->IsDynamicMethod())
7327 // @TODO: how do we detect the need to mark this flag?
7331 COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
7333 for (unsigned i = 0; i < methInfo->EHcount; i++)
7335 const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo =
7336 (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)header->EH->EHClause(i, &ehClause);
7338 // Is it a typed catch clause?
7339 if (ehInfo->GetFlags() != COR_ILEXCEPTION_CLAUSE_NONE)
7342 // Check if we catch "C<T>" ?
7344 DWORD catchTypeToken = ehInfo->GetClassToken();
7345 if (TypeFromToken(catchTypeToken) != mdtTypeSpec)
7348 PCCOR_SIGNATURE pSig;
7350 IfFailThrow(ftn->GetMDImport()->GetTypeSpecFromToken(catchTypeToken, &pSig, &cSig));
7352 SigPointer psig(pSig, cSig);
7354 SigTypeContext sigTypeContext(ftn);
7355 if (psig.IsPolyType(&sigTypeContext) & hasSharableVarsMask)
7357 methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7365 PCCOR_SIGNATURE pSig = NULL;
7367 ftn->GetSig(&pSig, &cbSig);
7369 /* Fetch the method signature */
7370 // Type parameters in the signature should be instantiated according to the
7371 // class/method/array instantiation of ftnHnd
7372 CEEInfo::ConvToJitSig(
7375 GetScopeHandle(ftn),
7381 // Shared generic or static per-inst methods and shared methods on generic structs
7382 // take an extra argument representing their instantiation
7383 if (ftn->RequiresInstArg())
7384 methInfo->args.callConv = (CorInfoCallConv)(methInfo->args.callConv | CORINFO_CALLCONV_PARAMTYPE);
7386 _ASSERTE((IsMdStatic(ftn->GetAttrs()) == 0) == ((methInfo->args.callConv & CORINFO_CALLCONV_HASTHIS) != 0));
7388 /* And its local variables */
7389 // Type parameters in the signature should be instantiated according to the
7390 // class/method/array instantiation of ftnHnd
7391 CEEInfo::ConvToJitSig(
7394 GetScopeHandle(ftn),
7399 } // getMethodInfoHelper
7401 //---------------------------------------------------------------------------------------
7404 CEEInfo::getMethodInfo(
7405 CORINFO_METHOD_HANDLE ftnHnd,
7406 CORINFO_METHOD_INFO * methInfo)
7415 bool result = false;
7417 JIT_TO_EE_TRANSITION();
7419 MethodDesc * ftn = GetMethod(ftnHnd);
7421 if (!ftn->IsDynamicMethod() && (!ftn->IsIL() || !ftn->GetRVA() || ftn->IsWrapperStub()))
7423 /* Return false if not IL or has no code */
7428 /* Get the IL header */
7430 if (ftn->IsDynamicMethod())
7432 getMethodInfoHelper(ftn, ftnHnd, NULL, methInfo);
7436 COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
7438 getMethodInfoHelper(ftn, ftnHnd, &header, methInfo);
7441 LOG((LF_JIT, LL_INFO100000, "Getting method info (possible inline) %s::%s%s\n",
7442 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
7447 EE_TO_JIT_TRANSITION();
7454 /************************************************************************
7455 Return true when ftn contains a local of type CLASS__STACKCRAWMARK
7458 bool containsStackCrawlMarkLocal(MethodDesc* ftn)
7460 STANDARD_VM_CONTRACT;
7462 COR_ILMETHOD* ilHeader = ftn->GetILHeader();
7465 COR_ILMETHOD_DECODER header(ilHeader, ftn->GetMDImport(), NULL);
7467 if (header.LocalVarSig == NULL)
7470 SigPointer ptr(header.LocalVarSig, header.cbLocalVarSig);
7472 IfFailThrow(ptr.GetData(NULL)); // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
7475 IfFailThrow(ptr.GetData(&numLocals));
7477 for(ULONG i = 0; i < numLocals; i++)
7479 CorElementType eType;
7480 IfFailThrow(ptr.PeekElemType(&eType));
7481 if (eType != ELEMENT_TYPE_VALUETYPE)
7483 IfFailThrow(ptr.SkipExactlyOne());
7487 IfFailThrow(ptr.GetElemType(NULL));
7490 IfFailThrow(ptr.GetToken(&token));
7492 // We are inside mscorlib - simple token match is sufficient
7493 if (token == MscorlibBinder::GetClass(CLASS__STACKCRAWMARK)->GetCl())
7502 /*************************************************************
7503 * Check if the caller and calle are in the same assembly
7504 * i.e. do not inline across assemblies
7505 *************************************************************/
7507 CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller,
7508 CORINFO_METHOD_HANDLE hCallee,
7509 DWORD* pRestrictions)
7518 CorInfoInline result = INLINE_PASS; // By default we pass.
7519 // Do not set pass in the rest of the method.
7520 DWORD dwRestrictions = 0; // By default, no restrictions
7521 const char * szFailReason = NULL; // for reportInlineDecision
7523 JIT_TO_EE_TRANSITION();
7525 // This does not work in the multi-threaded case
7527 // Caller should check this condition first
7528 _ASSERTE(!(CORINFO_FLG_DONT_INLINE & getMethodAttribsInternal(hCallee)));
7531 MethodDesc* pCaller = GetMethod(hCaller);
7532 MethodDesc* pCallee = GetMethod(hCallee);
7534 if (pCallee->IsNoMetadata())
7536 result = INLINE_FAIL;
7537 szFailReason = "Inlinee is NoMetadata";
7541 #ifdef DEBUGGING_SUPPORTED
7543 // If the callee wants debuggable code, don't allow it to be inlined
7546 // Combining the next two lines, and eliminating jitDebuggerFlags, leads to bad codegen in x86 Release builds using Visual C++ 19.00.24215.1.
7547 CORJIT_FLAGS jitDebuggerFlags = GetDebuggerCompileFlags(pCallee->GetModule(), CORJIT_FLAGS());
7548 if (jitDebuggerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE))
7550 result = INLINE_NEVER;
7551 szFailReason = "Inlinee is debuggable";
7557 // The orginal caller is the current method
7558 MethodDesc * pOrigCaller;
7559 pOrigCaller = m_pMethodBeingCompiled;
7560 Module * pOrigCallerModule;
7561 pOrigCallerModule = pOrigCaller->GetLoaderModule();
7563 if (pCallee->IsNotInline())
7565 result = INLINE_NEVER;
7566 szFailReason = "Inlinee is marked as no inline";
7570 // Also check to see if the method requires a security object. This means they call demand and
7571 // shouldn't be inlined.
7572 if (IsMdRequireSecObject(pCallee->GetAttrs()))
7574 result = INLINE_NEVER;
7575 szFailReason = "Inlinee requires a security object (or contains StackCrawlMark)";
7579 // If the method is MethodImpl'd by another method within the same type, then we have
7580 // an issue that the importer will import the wrong body. In this case, we'll just
7581 // disallow inlining because getFunctionEntryPoint will do the right thing.
7583 MethodDesc *pMDDecl = pCallee;
7584 MethodTable *pMT = pMDDecl->GetMethodTable();
7585 MethodDesc *pMDImpl = pMT->MapMethodDeclToMethodImpl(pMDDecl);
7587 if (pMDDecl != pMDImpl)
7589 result = INLINE_NEVER;
7590 szFailReason = "Inlinee is MethodImpl'd by another method within the same type";
7596 // Perform the Cross-Assembly inlining checks
7599 Module * pCalleeModule = pCallee->GetModule();
7601 #ifdef FEATURE_PREJIT
7602 Assembly * pCalleeAssembly = pCalleeModule->GetAssembly();
7606 // Make sure that all methods with StackCrawlMark are marked as IsMdRequireSecObject
7608 if (pCalleeAssembly->IsSystem())
7610 _ASSERTE(!containsStackCrawlMarkLocal(pCallee));
7614 // To allow for servicing of Ngen images we want to disable most
7615 // Cross-Assembly inlining except for the cases that we explicitly allow.
7617 if (IsCompilingForNGen())
7619 // This is an canInline call at Ngen time
7622 Assembly * pOrigCallerAssembly = pOrigCallerModule->GetAssembly();
7624 if (pCalleeAssembly == pOrigCallerAssembly)
7626 // Within the same assembly
7627 // we can freely inline with no restrictions
7631 #ifdef FEATURE_READYTORUN_COMPILER
7632 // No inlinining for version resilient code except if in the same version bubble
7633 // If this condition changes, please make the corresponding change
7634 // in getCallInfo, too.
7635 if (IsReadyToRunCompilation() &&
7637 !IsInSameVersionBubble(pCaller, pCallee)
7640 result = INLINE_NEVER;
7641 szFailReason = "Cross-module inlining in version resilient code";
7647 #endif // FEATURE_PREJIT
7649 // TODO: We can probably be smarter here if the caller is jitted, as we will
7650 // know for sure if the inlinee has really no string interning active (currently
7651 // it's only on in the ngen case (besides requiring the attribute)), but this is getting
7652 // too subtle. Will only do if somebody screams about it, as bugs here are going to
7654 if ((pOrigCallerModule != pCalleeModule) && pCalleeModule->IsNoStringInterning())
7656 dwRestrictions |= INLINE_NO_CALLEE_LDSTR;
7659 // The remoting interception can be skipped only if the call is on same this pointer
7660 if (pCallee->MayBeRemotingIntercepted())
7662 dwRestrictions |= INLINE_SAME_THIS;
7666 #ifdef PROFILING_SUPPORTED
7667 if (CORProfilerPresent())
7671 // Currently the rejit path is the only path which sets this.
7672 // If we get more reasons to set this then we may need to change
7673 // the failure reason message or disambiguate them.
7674 if (!m_allowInlining)
7676 result = INLINE_FAIL;
7677 szFailReason = "ReJIT request disabled inlining from caller";
7681 // If the profiler has set a mask preventing inlining, always return
7682 // false to the jit.
7683 if (CORProfilerDisableInlining())
7685 result = INLINE_FAIL;
7686 szFailReason = "Profiler disabled inlining globally";
7690 // If the profiler wishes to be notified of JIT events and the result from
7691 // the above tests will cause a function to be inlined, we need to tell the
7692 // profiler that this inlining is going to take place, and give them a
7693 // chance to prevent it.
7695 BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo());
7696 if (pCaller->IsILStub() || pCallee->IsILStub())
7704 HRESULT hr = g_profControlBlock.pProfInterface->JITInlining(
7705 (FunctionID)pCaller,
7706 (FunctionID)pCallee,
7709 if (SUCCEEDED(hr) && !fShouldInline)
7711 result = INLINE_FAIL;
7712 szFailReason = "Profiler disabled inlining locally";
7719 #endif // PROFILING_SUPPORTED
7723 EE_TO_JIT_TRANSITION();
7725 if (result == INLINE_PASS && dwRestrictions)
7729 *pRestrictions = dwRestrictions;
7733 // If the jitter didn't want to know about restrictions, it shouldn't be inlining
7734 result = INLINE_FAIL;
7735 szFailReason = "Inlinee has restrictions the JIT doesn't want";
7742 // Denied inlining, makes no sense to pass out restrictions,
7747 if (dontInline(result))
7749 // If you hit this assert, it means you added a new way to prevent inlining
7750 // without documenting it for ETW!
7751 _ASSERTE(szFailReason != NULL);
7752 reportInliningDecision(hCaller, hCallee, result, szFailReason);
7758 void CEEInfo::reportInliningDecision (CORINFO_METHOD_HANDLE inlinerHnd,
7759 CORINFO_METHOD_HANDLE inlineeHnd,
7760 CorInfoInline inlineResult,
7761 const char * reason)
7763 STATIC_CONTRACT_THROWS;
7764 STATIC_CONTRACT_GC_TRIGGERS;
7765 STATIC_CONTRACT_SO_TOLERANT;
7767 JIT_TO_EE_TRANSITION();
7770 if (LoggingOn(LF_JIT, LL_INFO100000))
7772 SString currentMethodName;
7773 currentMethodName.AppendUTF8(m_pMethodBeingCompiled->GetModule_NoLogging()->GetFile()->GetSimpleName());
7774 currentMethodName.Append(L'/');
7775 TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled, TypeString::FormatBasic);
7777 SString inlineeMethodName;
7778 if (GetMethod(inlineeHnd))
7780 inlineeMethodName.AppendUTF8(GetMethod(inlineeHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
7781 inlineeMethodName.Append(L'/');
7782 TypeString::AppendMethodInternal(inlineeMethodName, GetMethod(inlineeHnd), TypeString::FormatBasic);
7786 inlineeMethodName.AppendASCII( "<null>" );
7789 SString inlinerMethodName;
7790 if (GetMethod(inlinerHnd))
7792 inlinerMethodName.AppendUTF8(GetMethod(inlinerHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
7793 inlinerMethodName.Append(L'/');
7794 TypeString::AppendMethodInternal(inlinerMethodName, GetMethod(inlinerHnd), TypeString::FormatBasic);
7798 inlinerMethodName.AppendASCII("<null>");
7801 if (dontInline(inlineResult))
7803 LOG((LF_JIT, LL_INFO100000,
7804 "While compiling '%S', inline of '%S' into '%S' failed because: '%s'.\n",
7805 currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
7806 inlinerMethodName.GetUnicode(), reason));
7810 LOG((LF_JIT, LL_INFO100000, "While compiling '%S', inline of '%S' into '%S' succeeded.\n",
7811 currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
7812 inlinerMethodName.GetUnicode()));
7818 //I'm gonna duplicate this code because the format is slightly different. And LoggingOn is debug only.
7819 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
7820 TRACE_LEVEL_VERBOSE,
7821 CLR_JITTRACING_KEYWORD))
7823 SString methodBeingCompiledNames[3];
7824 SString inlinerNames[3];
7825 SString inlineeNames[3];
7826 MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
7827 #define GMI(pMD, strArray) \
7830 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
7832 (strArray)[0].Set(W("<null>")); \
7833 (strArray)[1].Set(W("<null>")); \
7834 (strArray)[2].Set(W("<null>")); \
7837 GMI(methodBeingCompiled, methodBeingCompiledNames);
7838 GMI(GetMethod(inlinerHnd), inlinerNames);
7839 GMI(GetMethod(inlineeHnd), inlineeNames);
7841 if (dontInline(inlineResult))
7843 const char * str = (reason ? reason : "");
7845 FireEtwMethodJitInliningFailed(methodBeingCompiledNames[0].GetUnicode(),
7846 methodBeingCompiledNames[1].GetUnicode(),
7847 methodBeingCompiledNames[2].GetUnicode(),
7848 inlinerNames[0].GetUnicode(),
7849 inlinerNames[1].GetUnicode(),
7850 inlinerNames[2].GetUnicode(),
7851 inlineeNames[0].GetUnicode(),
7852 inlineeNames[1].GetUnicode(),
7853 inlineeNames[2].GetUnicode(),
7854 inlineResult == INLINE_NEVER,
7856 GetClrInstanceId());
7860 FireEtwMethodJitInliningSucceeded(methodBeingCompiledNames[0].GetUnicode(),
7861 methodBeingCompiledNames[1].GetUnicode(),
7862 methodBeingCompiledNames[2].GetUnicode(),
7863 inlinerNames[0].GetUnicode(),
7864 inlinerNames[1].GetUnicode(),
7865 inlinerNames[2].GetUnicode(),
7866 inlineeNames[0].GetUnicode(),
7867 inlineeNames[1].GetUnicode(),
7868 inlineeNames[2].GetUnicode(),
7869 GetClrInstanceId());
7874 EE_TO_JIT_TRANSITION();
7878 /*************************************************************
7879 This loads the (formal) declared constraints on the class and method type parameters,
7880 and detects (but does not itself reject) circularities among the class type parameters
7881 and (separately) method type parameters.
7883 It must be called whenever we verify a typical method, ie any method (generic or
7884 nongeneric) in a typical class. It must be called for non-generic methods too,
7885 because their bodies may still mention class type parameters which will need to
7886 have their formal constraints loaded in order to perform type compatibility tests.
7888 We have to rule out cycles like "C<U,T> where T:U, U:T" only to avoid looping
7889 in the verifier (ie the T.CanCast(A) would loop calling U.CanCast(A) then
7890 T.CanCastTo(A) etc.). Since the JIT only tries to walk the hierarchy from a type
7891 a parameter when verifying, it should be safe to JIT unverified, but trusted,
7892 instantiations even in the presence of cycle constraints.
7893 @TODO: It should be possible (and easy) to detect cycles much earlier on by
7894 directly inspecting the metadata. All you have to do is check that, for each
7895 of the n type parameters to a class or method there is no path of length n
7896 obtained by following naked type parameter constraints of the same kind.
7897 This can be detected by looking directly at metadata, without actually loading
7898 the typehandles for the naked type parameters.
7899 *************************************************************/
7901 void CEEInfo::initConstraintsForVerification(CORINFO_METHOD_HANDLE hMethod,
7902 BOOL *pfHasCircularClassConstraints,
7903 BOOL *pfHasCircularMethodConstraints)
7910 PRECONDITION(CheckPointer(pfHasCircularClassConstraints));
7911 PRECONDITION(CheckPointer(pfHasCircularMethodConstraints));
7914 *pfHasCircularClassConstraints = FALSE;
7915 *pfHasCircularMethodConstraints = FALSE;
7917 JIT_TO_EE_TRANSITION();
7919 MethodDesc* pMethod = GetMethod(hMethod);
7920 if (pMethod->IsTypicalMethodDefinition())
7922 // Force a load of the constraints on the type parameters, detecting cyclic bounds
7923 pMethod->LoadConstraintsForTypicalMethodDefinition(pfHasCircularClassConstraints,pfHasCircularMethodConstraints);
7926 EE_TO_JIT_TRANSITION();
7929 /*************************************************************
7930 * Check if a method to be compiled is an instantiation
7931 * of generic code that has already been verified.
7932 * Three possible return values (see corinfo.h)
7933 *************************************************************/
7935 CorInfoInstantiationVerification
7936 CEEInfo::isInstantiationOfVerifiedGeneric(CORINFO_METHOD_HANDLE hMethod)
7945 CorInfoInstantiationVerification result = INSTVER_NOT_INSTANTIATION;
7947 JIT_TO_EE_TRANSITION();
7949 MethodDesc * pMethod = GetMethod(hMethod);
7951 if (!(pMethod->HasClassOrMethodInstantiation()))
7953 result = INSTVER_NOT_INSTANTIATION;
7957 if (pMethod->IsTypicalMethodDefinition())
7959 result = INSTVER_NOT_INSTANTIATION;
7963 result = INSTVER_GENERIC_PASSED_VERIFICATION;
7967 EE_TO_JIT_TRANSITION();
7972 /*************************************************************
7973 * Similar to above, but perform check for tail call
7974 * eligibility. The callee can be passed as NULL if not known
7975 * (calli and callvirt).
7976 *************************************************************/
7978 bool CEEInfo::canTailCall (CORINFO_METHOD_HANDLE hCaller,
7979 CORINFO_METHOD_HANDLE hDeclaredCallee,
7980 CORINFO_METHOD_HANDLE hExactCallee,
7990 bool result = false;
7991 const char * szFailReason = NULL;
7993 JIT_TO_EE_TRANSITION();
7995 // See comments in canInline above.
7997 MethodDesc* pCaller = GetMethod(hCaller);
7998 MethodDesc* pDeclaredCallee = GetMethod(hDeclaredCallee);
7999 MethodDesc* pExactCallee = GetMethod(hExactCallee);
8001 _ASSERTE(pCaller->GetModule());
8002 _ASSERTE(pCaller->GetModule()->GetClassLoader());
8004 _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule());
8005 _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule()->GetClassLoader());
8007 // If the caller is the static constructor (.cctor) of a class which has a ComImport base class
8008 // somewhere up the class hierarchy, then we cannot make the call into a tailcall. See
8009 // RegisterObjectCreationCallback() in ExtensibleClassFactory.cpp for more information.
8010 if (pCaller->IsClassConstructor() &&
8011 pCaller->GetMethodTable()->IsComObjectType())
8014 szFailReason = "Caller is ComImport .cctor";
8020 mdMethodDef callerToken = pCaller->GetMemberDef();
8022 // We don't want to tailcall the entrypoint for an application; JIT64 will sometimes
8023 // do this for simple entrypoints and it results in a rather confusing debugging
8025 if (callerToken == pCaller->GetModule()->GetEntryPointToken())
8028 szFailReason = "Caller is the entry point";
8032 if (!pCaller->IsNoMetadata())
8034 // Do not tailcall from methods that are marked as noinline (people often use no-inline
8035 // to mean "I want to always see this method in stacktrace")
8036 DWORD dwImplFlags = 0;
8037 IfFailThrow(pCaller->GetMDImport()->GetMethodImplProps(callerToken, NULL, &dwImplFlags));
8039 if (IsMiNoInlining(dwImplFlags))
8042 szFailReason = "Caller is marked as no inline";
8047 // Methods with StackCrawlMark depend on finding their caller on the stack.
8048 // If we tail call one of these guys, they get confused. For lack of
8049 // a better way of identifying them, we use DynamicSecurity attribute to identify
8050 // them. We have an assert in canInline that ensures all StackCrawlMark
8051 // methods are appropriately marked.
8053 if ((pExactCallee != NULL) && IsMdRequireSecObject(pExactCallee->GetAttrs()))
8056 szFailReason = "Callee might have a StackCrawlMark.LookForMyCaller";
8066 EE_TO_JIT_TRANSITION();
8070 // If you hit this assert, it means you added a new way to prevent tail calls
8071 // without documenting it for ETW!
8072 _ASSERTE(szFailReason != NULL);
8073 reportTailCallDecision(hCaller, hExactCallee, fIsTailPrefix, TAILCALL_FAIL, szFailReason);
8079 void CEEInfo::reportTailCallDecision (CORINFO_METHOD_HANDLE callerHnd,
8080 CORINFO_METHOD_HANDLE calleeHnd,
8082 CorInfoTailCall tailCallResult,
8083 const char * reason)
8085 STATIC_CONTRACT_THROWS;
8086 STATIC_CONTRACT_GC_TRIGGERS;
8087 STATIC_CONTRACT_SO_TOLERANT;
8089 JIT_TO_EE_TRANSITION();
8091 //put code here. Make sure to report the method being compiled in addition to inliner and inlinee.
8093 if (LoggingOn(LF_JIT, LL_INFO100000))
8095 SString currentMethodName;
8096 TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled,
8097 TypeString::FormatBasic);
8099 SString calleeMethodName;
8100 if (GetMethod(calleeHnd))
8102 TypeString::AppendMethodInternal(calleeMethodName, GetMethod(calleeHnd),
8103 TypeString::FormatBasic);
8107 calleeMethodName.AppendASCII( "<null>" );
8110 SString callerMethodName;
8111 if (GetMethod(callerHnd))
8113 TypeString::AppendMethodInternal(callerMethodName, GetMethod(callerHnd),
8114 TypeString::FormatBasic);
8118 callerMethodName.AppendASCII( "<null>" );
8120 if (tailCallResult == TAILCALL_FAIL)
8122 LOG((LF_JIT, LL_INFO100000,
8123 "While compiling '%S', %Splicit tail call from '%S' to '%S' failed because: '%s'.\n",
8124 currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8125 callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), reason));
8129 static const char * const tailCallType[] = {
8130 "optimized tail call", "recursive loop", "helper assisted tailcall"
8132 _ASSERTE(tailCallResult >= 0 && (size_t)tailCallResult < sizeof(tailCallType) / sizeof(tailCallType[0]));
8133 LOG((LF_JIT, LL_INFO100000,
8134 "While compiling '%S', %Splicit tail call from '%S' to '%S' generated as a %s.\n",
8135 currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8136 callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), tailCallType[tailCallResult]));
8142 // I'm gonna duplicate this code because the format is slightly different. And LoggingOn is debug only.
8143 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
8144 TRACE_LEVEL_VERBOSE,
8145 CLR_JITTRACING_KEYWORD))
8147 SString methodBeingCompiledNames[3];
8148 SString callerNames[3];
8149 SString calleeNames[3];
8150 MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8151 #define GMI(pMD, strArray) \
8154 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8156 (strArray)[0].Set(W("<null>")); \
8157 (strArray)[1].Set(W("<null>")); \
8158 (strArray)[2].Set(W("<null>")); \
8161 GMI(methodBeingCompiled, methodBeingCompiledNames);
8162 GMI(GetMethod(callerHnd), callerNames);
8163 GMI(GetMethod(calleeHnd), calleeNames);
8165 if (tailCallResult == TAILCALL_FAIL)
8167 const char * str = (reason ? reason : "");
8169 FireEtwMethodJitTailCallFailed(methodBeingCompiledNames[0].GetUnicode(),
8170 methodBeingCompiledNames[1].GetUnicode(),
8171 methodBeingCompiledNames[2].GetUnicode(),
8172 callerNames[0].GetUnicode(),
8173 callerNames[1].GetUnicode(),
8174 callerNames[2].GetUnicode(),
8175 calleeNames[0].GetUnicode(),
8176 calleeNames[1].GetUnicode(),
8177 calleeNames[2].GetUnicode(),
8180 GetClrInstanceId());
8184 FireEtwMethodJitTailCallSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8185 methodBeingCompiledNames[1].GetUnicode(),
8186 methodBeingCompiledNames[2].GetUnicode(),
8187 callerNames[0].GetUnicode(),
8188 callerNames[1].GetUnicode(),
8189 callerNames[2].GetUnicode(),
8190 calleeNames[0].GetUnicode(),
8191 calleeNames[1].GetUnicode(),
8192 calleeNames[2].GetUnicode(),
8195 GetClrInstanceId());
8201 EE_TO_JIT_TRANSITION();
8204 void CEEInfo::getEHinfoHelper(
8205 CORINFO_METHOD_HANDLE ftnHnd,
8207 CORINFO_EH_CLAUSE* clause,
8208 COR_ILMETHOD_DECODER* pILHeader)
8210 STANDARD_VM_CONTRACT;
8212 _ASSERTE(CheckPointer(pILHeader->EH));
8213 _ASSERTE(EHnumber < pILHeader->EH->EHCount());
8215 COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
8216 const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo;
8217 ehInfo = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)pILHeader->EH->EHClause(EHnumber, &ehClause);
8219 clause->Flags = (CORINFO_EH_CLAUSE_FLAGS)ehInfo->GetFlags();
8220 clause->TryOffset = ehInfo->GetTryOffset();
8221 clause->TryLength = ehInfo->GetTryLength();
8222 clause->HandlerOffset = ehInfo->GetHandlerOffset();
8223 clause->HandlerLength = ehInfo->GetHandlerLength();
8224 if ((clause->Flags & CORINFO_EH_CLAUSE_FILTER) == 0)
8225 clause->ClassToken = ehInfo->GetClassToken();
8227 clause->FilterOffset = ehInfo->GetFilterOffset();
8230 /*********************************************************************/
8231 // get individual exception handler
8232 void CEEInfo::getEHinfo(
8233 CORINFO_METHOD_HANDLE ftnHnd,
8235 CORINFO_EH_CLAUSE* clause)
8244 JIT_TO_EE_TRANSITION();
8246 MethodDesc * ftn = GetMethod(ftnHnd);
8248 if (IsDynamicMethodHandle(ftnHnd))
8250 GetMethod(ftnHnd)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
8254 COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
8255 getEHinfoHelper(ftnHnd, EHnumber, clause, &header);
8258 EE_TO_JIT_TRANSITION();
8261 //---------------------------------------------------------------------------------------
8264 CEEInfo::getMethodSig(
8265 CORINFO_METHOD_HANDLE ftnHnd,
8266 CORINFO_SIG_INFO * sigRet,
8267 CORINFO_CLASS_HANDLE owner)
8276 JIT_TO_EE_TRANSITION();
8278 getMethodSigInternal(ftnHnd, sigRet, owner);
8280 EE_TO_JIT_TRANSITION();
8283 //---------------------------------------------------------------------------------------
8286 CEEInfo::getMethodSigInternal(
8287 CORINFO_METHOD_HANDLE ftnHnd,
8288 CORINFO_SIG_INFO * sigRet,
8289 CORINFO_CLASS_HANDLE owner)
8291 STANDARD_VM_CONTRACT;
8293 MethodDesc * ftn = GetMethod(ftnHnd);
8295 PCCOR_SIGNATURE pSig = NULL;
8297 ftn->GetSig(&pSig, &cbSig);
8299 // Type parameters in the signature are instantiated
8300 // according to the class/method/array instantiation of ftnHnd and owner
8301 CEEInfo::ConvToJitSig(
8304 GetScopeHandle(ftn),
8312 // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation
8313 if (ftn->RequiresInstArg())
8315 sigRet->callConv = (CorInfoCallConv) (sigRet->callConv | CORINFO_CALLCONV_PARAMTYPE);
8318 // We want the calling convention bit to be consistant with the method attribute bit
8319 _ASSERTE( (IsMdStatic(ftn->GetAttrs()) == 0) == ((sigRet->callConv & CORINFO_CALLCONV_HASTHIS) != 0) );
8322 //---------------------------------------------------------------------------------------
8324 //@GENERICSVER: for a method desc in a typical instantiation of a generic class,
8325 // this will return the typical instantiation of the generic class,
8326 // but only provided type variables are never shared.
8327 // The JIT verifier relies on this behaviour to extract the typical class from an instantiated method's typical method handle.
8329 CORINFO_CLASS_HANDLE
8330 CEEInfo::getMethodClass(
8331 CORINFO_METHOD_HANDLE methodHnd)
8340 CORINFO_CLASS_HANDLE result = NULL;
8342 JIT_TO_EE_TRANSITION();
8344 MethodDesc* method = GetMethod(methodHnd);
8346 if (method->IsDynamicMethod())
8348 DynamicResolver::SecurityControlFlags securityControlFlags = DynamicResolver::Default;
8349 TypeHandle typeOwner;
8351 DynamicResolver* pResolver = method->AsDynamicMethodDesc()->GetResolver();
8352 pResolver->GetJitContext(&securityControlFlags, &typeOwner);
8354 if (!typeOwner.IsNull() && (method == pResolver->GetDynamicMethod()))
8356 result = CORINFO_CLASS_HANDLE(typeOwner.AsPtr());
8362 TypeHandle th = TypeHandle(method->GetMethodTable());
8364 result = CORINFO_CLASS_HANDLE(th.AsPtr());
8367 EE_TO_JIT_TRANSITION();
8372 /***********************************************************************/
8373 CORINFO_MODULE_HANDLE CEEInfo::getMethodModule (CORINFO_METHOD_HANDLE methodHnd)
8382 CORINFO_MODULE_HANDLE result = NULL;
8384 JIT_TO_EE_TRANSITION_LEAF();
8386 MethodDesc* method = GetMethod(methodHnd);
8388 if (method->IsDynamicMethod())
8390 // this should never be called, thus the assert, I don't know if the (non existent) caller
8391 // expects the Module or the scope
8396 result = (CORINFO_MODULE_HANDLE) method->GetModule();
8399 EE_TO_JIT_TRANSITION_LEAF();
8404 /*********************************************************************/
8405 CorInfoIntrinsics CEEInfo::getIntrinsicID(CORINFO_METHOD_HANDLE methodHnd,
8415 CorInfoIntrinsics result = CORINFO_INTRINSIC_Illegal;
8417 JIT_TO_EE_TRANSITION();
8419 if (pMustExpand != NULL)
8421 *pMustExpand = false;
8424 MethodDesc* method = GetMethod(methodHnd);
8426 if (method->IsArray())
8428 ArrayMethodDesc * arrMethod = (ArrayMethodDesc *)method;
8429 result = arrMethod->GetIntrinsicID();
8432 if (method->IsFCall())
8434 result = ECall::GetIntrinsicID(method);
8438 MethodTable * pMT = method->GetMethodTable();
8439 if (pMT->GetModule()->IsSystem() && pMT->IsByRefLike())
8441 if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
8443 // ByReference<T> has just two methods: constructor and Value property
8444 if (method->IsCtor())
8446 result = CORINFO_INTRINSIC_ByReference_Ctor;
8450 _ASSERTE(strcmp(method->GetName(), "get_Value") == 0);
8451 result = CORINFO_INTRINSIC_ByReference_Value;
8453 if (pMustExpand != nullptr)
8455 *pMustExpand = true;
8458 else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__SPAN)))
8460 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__SPAN__GET_ITEM)))
8462 result = CORINFO_INTRINSIC_Span_GetItem;
8465 else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__READONLY_SPAN)))
8467 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__READONLY_SPAN__GET_ITEM)))
8469 result = CORINFO_INTRINSIC_ReadOnlySpan_GetItem;
8475 EE_TO_JIT_TRANSITION();
8480 /*********************************************************************/
8481 bool CEEInfo::isInSIMDModule(CORINFO_CLASS_HANDLE classHnd)
8490 bool result = false;
8491 JIT_TO_EE_TRANSITION_LEAF();
8493 TypeHandle VMClsHnd(classHnd);
8494 if (VMClsHnd.GetMethodTable()->GetAssembly()->IsSIMDVectorAssembly())
8498 EE_TO_JIT_TRANSITION_LEAF();
8503 /*********************************************************************/
8504 void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd,
8505 unsigned * pOffsetOfIndirection,
8506 unsigned * pOffsetAfterIndirection,
8516 JIT_TO_EE_TRANSITION_LEAF();
8518 MethodDesc* method = GetMethod(methodHnd);
8520 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8521 _ASSERTE(!method->HasMethodInstantiation());
8523 _ASSERTE(MethodTable::GetVtableOffset() < 256); // a rough sanity check
8525 // better be in the vtable
8526 _ASSERTE(method->GetSlot() < method->GetMethodTable()->GetNumVirtuals());
8528 *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * sizeof(MethodTable::VTableIndir_t);
8529 *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * sizeof(PCODE);
8530 *isRelative = MethodTable::VTableIndir_t::isRelative ? 1 : 0;
8532 EE_TO_JIT_TRANSITION_LEAF();
8535 /*********************************************************************/
8536 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethodHelper(CORINFO_METHOD_HANDLE baseMethod,
8537 CORINFO_CLASS_HANDLE derivedClass,
8538 CORINFO_CONTEXT_HANDLE ownerType)
8546 MethodDesc* pBaseMD = GetMethod(baseMethod);
8547 MethodTable* pBaseMT = pBaseMD->GetMethodTable();
8549 // Method better be from a fully loaded class
8550 _ASSERTE(pBaseMD->IsRestored() && pBaseMT->IsFullyLoaded());
8552 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8553 _ASSERTE(!pBaseMD->HasMethodInstantiation());
8555 // Method better be virtual
8556 _ASSERTE(pBaseMD->IsVirtual());
8558 MethodDesc* pDevirtMD = nullptr;
8560 TypeHandle DerivedClsHnd(derivedClass);
8561 MethodTable* pDerivedMT = DerivedClsHnd.GetMethodTable();
8562 _ASSERTE(pDerivedMT->IsRestored() && pDerivedMT->IsFullyLoaded());
8564 // Can't devirtualize from __Canon.
8565 if (DerivedClsHnd == TypeHandle(g_pCanonMethodTableClass))
8570 if (pBaseMT->IsInterface())
8573 #ifdef FEATURE_COMINTEROP
8574 // Don't try and devirtualize com interface calls.
8575 if (pDerivedMT->IsComObjectType())
8579 #endif // FEATURE_COMINTEROP
8581 // Interface call devirtualization.
8583 // We must ensure that pDerivedMT actually implements the
8584 // interface corresponding to pBaseMD.
8585 if (!pDerivedMT->CanCastToInterface(pBaseMT))
8590 // For generic interface methods we must have an ownerType to
8591 // safely devirtualize.
8592 if (ownerType != nullptr)
8594 TypeHandle OwnerClsHnd = GetTypeFromContext(ownerType);
8595 MethodTable* pOwnerMT = OwnerClsHnd.GetMethodTable();
8597 // If the derived class is a shared class, make sure the
8598 // owner class is too.
8599 if (pDerivedMT->IsSharedByGenericInstantiations())
8601 pOwnerMT = pOwnerMT->GetCanonicalMethodTable();
8604 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(TypeHandle(pOwnerMT), pBaseMD);
8606 else if (!pBaseMD->HasClassOrMethodInstantiation())
8608 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(pBaseMD);
8617 // Virtual call devirtualization.
8619 // The derived class should be a subclass of the the base class.
8620 MethodTable* pCheckMT = pDerivedMT;
8622 while (pCheckMT != nullptr)
8624 if (pCheckMT->HasSameTypeDefAs(pBaseMT))
8629 pCheckMT = pCheckMT->GetParentMethodTable();
8632 if (pCheckMT == nullptr)
8637 // The base method should be in the base vtable
8638 WORD slot = pBaseMD->GetSlot();
8639 _ASSERTE(slot < pBaseMT->GetNumVirtuals());
8641 // Fetch the method that would be invoked if the class were
8642 // exactly derived class. It is up to the jit to determine whether
8643 // directly calling this method is correct.
8644 pDevirtMD = pDerivedMT->GetMethodDescForSlot(slot);
8647 _ASSERTE(pDevirtMD->IsRestored());
8649 #ifdef FEATURE_READYTORUN_COMPILER
8650 // Check if devirtualization is dependent upon cross-version
8651 // bubble information and if so, disallow it.
8652 if (IsReadyToRunCompilation())
8654 MethodDesc* callerMethod = m_pMethodBeingCompiled;
8655 Assembly* pCallerAssembly = callerMethod->GetModule()->GetAssembly();
8657 IsInSameVersionBubble(pCallerAssembly , pDevirtMD->GetModule()->GetAssembly())
8658 && IsInSameVersionBubble(pCallerAssembly , pDerivedMT->GetAssembly());
8667 return (CORINFO_METHOD_HANDLE) pDevirtMD;
8670 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethod(CORINFO_METHOD_HANDLE methodHnd,
8671 CORINFO_CLASS_HANDLE derivedClass,
8672 CORINFO_CONTEXT_HANDLE ownerType)
8681 CORINFO_METHOD_HANDLE result = nullptr;
8683 JIT_TO_EE_TRANSITION();
8685 result = resolveVirtualMethodHelper(methodHnd, derivedClass, ownerType);
8687 EE_TO_JIT_TRANSITION();
8692 void CEEInfo::expandRawHandleIntrinsic(
8693 CORINFO_RESOLVED_TOKEN * pResolvedToken,
8694 CORINFO_GENERICHANDLE_RESULT * pResult)
8696 LIMITED_METHOD_CONTRACT;
8697 UNREACHABLE(); // only called with CoreRT.
8700 /*********************************************************************/
8701 void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd,
8702 CORINFO_CONST_LOOKUP * pResult,
8703 CORINFO_ACCESS_FLAGS accessFlags)
8713 InfoAccessType accessType = IAT_VALUE;
8715 JIT_TO_EE_TRANSITION();
8717 MethodDesc * ftn = GetMethod(ftnHnd);
8718 #if defined(FEATURE_GDBJIT)
8719 MethodDesc * orig_ftn = ftn;
8722 // Resolve methodImpl.
8723 ftn = ftn->GetMethodTable()->MapMethodDeclToMethodImpl(ftn);
8725 ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags);
8727 // TryGetMultiCallableAddrOfCode returns NULL if indirect access is desired
8730 // should never get here for EnC methods or if interception via remoting stub is required
8731 _ASSERTE(!ftn->IsEnCMethod());
8733 _ASSERTE((accessFlags & CORINFO_ACCESS_THIS) || !ftn->IsRemotingInterceptedViaVirtualDispatch());
8735 ret = ftn->GetAddrOfSlot();
8736 accessType = IAT_PVALUE;
8740 #if defined(FEATURE_GDBJIT)
8741 CalledMethod * pCM = new CalledMethod(orig_ftn, ret, m_pCalledMethods);
8742 m_pCalledMethods = pCM;
8745 EE_TO_JIT_TRANSITION();
8747 _ASSERTE(ret != NULL);
8749 pResult->accessType = accessType;
8750 pResult->addr = ret;
8753 /*********************************************************************/
8754 void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn,
8755 CORINFO_CONST_LOOKUP * pResult)
8764 JIT_TO_EE_TRANSITION();
8766 MethodDesc * pMD = GetMethod(ftn);
8768 pResult->accessType = IAT_VALUE;
8771 #ifndef CROSSGEN_COMPILE
8772 // If LDFTN target has [NativeCallable] attribute , then create a UMEntryThunk.
8773 if (pMD->HasNativeCallableAttribute())
8775 pResult->addr = (void*)COMDelegate::ConvertToCallback(pMD);
8778 #endif //CROSSGEN_COMPILE
8780 pResult->addr = (void *)pMD->GetMultiCallableAddrOfCode();
8782 EE_TO_JIT_TRANSITION();
8785 /*********************************************************************/
8786 const char* CEEInfo::getFieldName (CORINFO_FIELD_HANDLE fieldHnd, const char** scopeName)
8795 const char* result = NULL;
8797 JIT_TO_EE_TRANSITION();
8799 FieldDesc* field = (FieldDesc*) fieldHnd;
8802 TypeHandle t = TypeHandle(field->GetApproxEnclosingMethodTable());
8807 t.GetName(ssClsNameBuff);
8808 *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
8810 // since this is for diagnostic purposes only,
8811 // give up on the namespace, as we don't have a buffer to concat it
8812 // also note this won't show array class names.
8814 *scopeName= t.GetMethodTable()->GetFullyQualifiedNameInfo(&nameSpace);
8819 result = field->GetName();
8821 EE_TO_JIT_TRANSITION();
8826 /*********************************************************************/
8827 // Get the type that declares the field
8828 CORINFO_CLASS_HANDLE CEEInfo::getFieldClass (CORINFO_FIELD_HANDLE fieldHnd)
8837 CORINFO_CLASS_HANDLE result = NULL;
8839 JIT_TO_EE_TRANSITION_LEAF();
8841 FieldDesc* field = (FieldDesc*) fieldHnd;
8842 result = CORINFO_CLASS_HANDLE(field->GetApproxEnclosingMethodTable());
8844 EE_TO_JIT_TRANSITION_LEAF();
8849 /*********************************************************************/
8850 // Returns the basic type of the field (not the the type that declares the field)
8852 // pTypeHnd - On return, for reference and value types, *pTypeHnd will contain
8853 // the normalized type of the field.
8854 // owner - Optional. For resolving in a generic context
8856 CorInfoType CEEInfo::getFieldType (CORINFO_FIELD_HANDLE fieldHnd,
8857 CORINFO_CLASS_HANDLE* pTypeHnd,
8858 CORINFO_CLASS_HANDLE owner)
8867 CorInfoType result = CORINFO_TYPE_UNDEF;
8869 JIT_TO_EE_TRANSITION();
8871 result = getFieldTypeInternal(fieldHnd, pTypeHnd, owner);
8873 EE_TO_JIT_TRANSITION();
8878 /*********************************************************************/
8879 CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd,
8880 CORINFO_CLASS_HANDLE* pTypeHnd,
8881 CORINFO_CLASS_HANDLE owner)
8883 STANDARD_VM_CONTRACT;
8887 TypeHandle clsHnd = TypeHandle();
8888 FieldDesc* field = (FieldDesc*) fieldHnd;
8889 CorElementType type = field->GetFieldType();
8891 // <REVISIT_TODO>TODO should not burn the time to do this for anything but Value Classes</REVISIT_TODO>
8892 _ASSERTE(type != ELEMENT_TYPE_BYREF);
8894 if (type == ELEMENT_TYPE_I)
8896 PTR_MethodTable enclosingMethodTable = field->GetApproxEnclosingMethodTable();
8897 if (enclosingMethodTable->IsByRefLike() && enclosingMethodTable->HasSameTypeDefAs(g_pByReferenceClass))
8899 _ASSERTE(field->GetOffset() == 0);
8900 return CORINFO_TYPE_BYREF;
8904 if (!CorTypeInfo::IsPrimitiveType(type))
8906 PCCOR_SIGNATURE sig;
8908 CorCallingConvention conv;
8910 field->GetSig(&sig, &sigCount);
8912 conv = (CorCallingConvention)CorSigUncompressCallingConv(sig);
8913 _ASSERTE(isCallConv(conv, IMAGE_CEE_CS_CALLCONV_FIELD));
8915 SigPointer ptr(sig, sigCount);
8917 // For verifying code involving generics, use the class instantiation
8918 // of the optional owner (to provide exact, not representative,
8919 // type information)
8920 SigTypeContext typeContext(field, (TypeHandle)owner);
8922 clsHnd = ptr.GetTypeHandleThrowing(field->GetModule(), &typeContext);
8923 _ASSERTE(!clsHnd.IsNull());
8925 // I believe it doesn't make any diff. if this is GetInternalCorElementType
8926 // or GetSignatureCorElementType.
8927 type = clsHnd.GetSignatureCorElementType();
8930 return CEEInfo::asCorInfoType(type, clsHnd, pTypeHnd);
8933 /*********************************************************************/
8934 unsigned CEEInfo::getFieldOffset (CORINFO_FIELD_HANDLE fieldHnd)
8943 unsigned result = (unsigned) -1;
8945 JIT_TO_EE_TRANSITION();
8947 FieldDesc* field = (FieldDesc*) fieldHnd;
8949 // GetOffset() does not include the size of Object
8950 result = field->GetOffset();
8952 // So if it is not a value class, add the Object into it
8953 if (field->IsStatic())
8955 Module* pModule = field->GetModule();
8956 if (field->IsRVA() && pModule->IsRvaFieldTls(field->GetOffset()))
8958 result = pModule->GetFieldTlsOffset(field->GetOffset());
8961 else if (!field->GetApproxEnclosingMethodTable()->IsValueType())
8963 result += sizeof(Object);
8966 EE_TO_JIT_TRANSITION();
8971 /*********************************************************************/
8972 bool CEEInfo::isWriteBarrierHelperRequired(CORINFO_FIELD_HANDLE field)
8981 bool fHelperRequired = false;
8983 JIT_TO_EE_TRANSITION();
8985 FieldDesc * pField = (FieldDesc *)field;
8987 // TODO: jit64 should be switched to the same plan as the i386 jits - use
8988 // getClassGClayout to figure out the need for writebarrier helper, and inline the copying.
8989 // Once this happens, USE_WRITE_BARRIER_HELPERS and CORINFO_FLG_WRITE_BARRIER_HELPER can be removed.
8990 CorElementType type = pField->GetFieldType();
8992 if(CorTypeInfo::IsObjRef(type))
8993 fHelperRequired = true;
8994 else if (type == ELEMENT_TYPE_VALUETYPE)
8996 TypeHandle th = pField->GetFieldTypeHandleThrowing();
8997 _ASSERTE(!th.IsNull());
8998 if(th.GetMethodTable()->ContainsPointers())
8999 fHelperRequired = true;
9002 EE_TO_JIT_TRANSITION();
9004 return fHelperRequired;
9007 /*********************************************************************/
9008 DWORD CEEInfo::getFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE fieldHnd, void **ppIndirection)
9019 if (ppIndirection != NULL)
9020 *ppIndirection = NULL;
9022 JIT_TO_EE_TRANSITION();
9024 FieldDesc* field = (FieldDesc*) fieldHnd;
9025 Module* module = field->GetModule();
9027 _ASSERTE(field->IsRVA()); // Only RVA statics can be thread local
9028 _ASSERTE(module->IsRvaFieldTls(field->GetOffset()));
9030 result = module->GetTlsIndex();
9032 EE_TO_JIT_TRANSITION();
9037 void *CEEInfo::allocateArray(ULONG cBytes)
9046 void * result = NULL;
9048 JIT_TO_EE_TRANSITION();
9050 result = new BYTE [cBytes];
9052 EE_TO_JIT_TRANSITION();
9057 void CEEInfo::freeArray(void *array)
9066 JIT_TO_EE_TRANSITION();
9068 delete [] ((BYTE*) array);
9070 EE_TO_JIT_TRANSITION();
9073 void CEEInfo::getBoundaries(CORINFO_METHOD_HANDLE ftn,
9074 unsigned int *cILOffsets, DWORD **pILOffsets,
9075 ICorDebugInfo::BoundaryTypes *implicitBoundaries)
9084 JIT_TO_EE_TRANSITION();
9086 #ifdef DEBUGGING_SUPPORTED
9087 if (g_pDebugInterface && !IsCompilationProcess())
9089 g_pDebugInterface->getBoundaries(GetMethod(ftn), cILOffsets, pILOffsets,
9090 implicitBoundaries);
9096 *implicitBoundaries = ICorDebugInfo::DEFAULT_BOUNDARIES;
9098 #endif // DEBUGGING_SUPPORTED
9100 EE_TO_JIT_TRANSITION();
9103 void CEEInfo::getVars(CORINFO_METHOD_HANDLE ftn, ULONG32 *cVars, ICorDebugInfo::ILVarInfo **vars,
9113 JIT_TO_EE_TRANSITION();
9115 #ifdef DEBUGGING_SUPPORTED
9116 if (g_pDebugInterface && !IsCompilationProcess())
9118 g_pDebugInterface->getVars(GetMethod(ftn), cVars, vars, extendOthers);
9125 // Just tell the JIT to extend everything.
9126 *extendOthers = true;
9128 #endif // DEBUGGING_SUPPORTED
9130 EE_TO_JIT_TRANSITION();
9133 /*********************************************************************/
9134 CORINFO_ARG_LIST_HANDLE CEEInfo::getArgNext(CORINFO_ARG_LIST_HANDLE args)
9143 CORINFO_ARG_LIST_HANDLE result = NULL;
9145 JIT_TO_EE_TRANSITION();
9147 SigPointer ptr((unsigned __int8*) args);
9148 IfFailThrow(ptr.SkipExactlyOne());
9150 result = (CORINFO_ARG_LIST_HANDLE) ptr.GetPtr();
9152 EE_TO_JIT_TRANSITION();
9158 /*********************************************************************/
9160 CorInfoTypeWithMod CEEInfo::getArgType (
9161 CORINFO_SIG_INFO* sig,
9162 CORINFO_ARG_LIST_HANDLE args,
9163 CORINFO_CLASS_HANDLE* vcTypeRet
9173 CorInfoTypeWithMod result = CorInfoTypeWithMod(CORINFO_TYPE_UNDEF);
9175 JIT_TO_EE_TRANSITION();
9177 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args && (BYTE*) args < (BYTE*) sig->pSig + sig->cbSig);
9178 _ASSERTE((BYTE*) sig->args <= (BYTE*) args);
9179 INDEBUG(*vcTypeRet = CORINFO_CLASS_HANDLE((size_t)INVALID_POINTER_CC));
9181 SigPointer ptr((unsigned __int8*) args);
9182 CorElementType eType;
9183 IfFailThrow(ptr.PeekElemType(&eType));
9184 while (eType == ELEMENT_TYPE_PINNED)
9186 result = CORINFO_TYPE_MOD_PINNED;
9187 IfFailThrow(ptr.GetElemType(NULL));
9188 IfFailThrow(ptr.PeekElemType(&eType));
9191 // Now read off the "real" element type after taking any instantiations into consideration
9192 SigTypeContext typeContext;
9193 GetTypeContext(&sig->sigInst,&typeContext);
9195 Module* pModule = GetModule(sig->scope);
9197 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9199 TypeHandle typeHnd = TypeHandle();
9201 case ELEMENT_TYPE_VAR :
9202 case ELEMENT_TYPE_MVAR :
9203 case ELEMENT_TYPE_VALUETYPE :
9204 case ELEMENT_TYPE_TYPEDBYREF :
9205 case ELEMENT_TYPE_INTERNAL :
9207 typeHnd = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9208 _ASSERTE(!typeHnd.IsNull());
9210 CorElementType normType = typeHnd.GetInternalCorElementType();
9212 // if we are looking up a value class, don't morph it to a refernece type
9213 // (This can only happen in illegal IL)
9214 if (!CorTypeInfo::IsObjRef(normType) || type != ELEMENT_TYPE_VALUETYPE)
9221 case ELEMENT_TYPE_PTR:
9222 // Load the type eagerly under debugger to make the eval work
9223 if (!isVerifyOnly() && CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
9225 // NOTE: in some IJW cases, when the type pointed at is unmanaged,
9226 // the GetTypeHandle may fail, because there is no TypeDef for such type.
9227 // Usage of GetTypeHandleThrowing would lead to class load exception
9228 TypeHandle thPtr = ptr.GetTypeHandleNT(pModule, &typeContext);
9231 m_pOverride->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(thPtr.AsPtr()));
9236 case ELEMENT_TYPE_VOID:
9237 // void is not valid in local sigs
9238 if (sig->flags & CORINFO_SIGFLAG_IS_LOCAL_SIG)
9239 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
9242 case ELEMENT_TYPE_END:
9243 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9250 result = CorInfoTypeWithMod(result | CEEInfo::asCorInfoType(type, typeHnd, vcTypeRet));
9251 EE_TO_JIT_TRANSITION();
9256 /*********************************************************************/
9258 CORINFO_CLASS_HANDLE CEEInfo::getArgClass (
9259 CORINFO_SIG_INFO* sig,
9260 CORINFO_ARG_LIST_HANDLE args
9270 CORINFO_CLASS_HANDLE result = NULL;
9272 JIT_TO_EE_TRANSITION();
9274 // make certain we dont have a completely wacked out sig pointer
9275 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args);
9276 _ASSERTE((BYTE*) sig->args <= (BYTE*) args && (BYTE*) args < &((BYTE*) sig->args)[0x10000*5]);
9278 Module* pModule = GetModule(sig->scope);
9280 SigPointer ptr((unsigned __int8*) args);
9282 CorElementType eType;
9283 IfFailThrow(ptr.PeekElemType(&eType));
9285 while (eType == ELEMENT_TYPE_PINNED)
9287 IfFailThrow(ptr.GetElemType(NULL));
9288 IfFailThrow(ptr.PeekElemType(&eType));
9290 // Now read off the "real" element type after taking any instantiations into consideration
9291 SigTypeContext typeContext;
9292 GetTypeContext(&sig->sigInst, &typeContext);
9293 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9295 if (!CorTypeInfo::IsPrimitiveType(type)) {
9296 TypeHandle th = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9297 result = CORINFO_CLASS_HANDLE(th.AsPtr());
9300 EE_TO_JIT_TRANSITION();
9305 /*********************************************************************/
9307 CorInfoType CEEInfo::getHFAType(CORINFO_CLASS_HANDLE hClass)
9316 CorInfoType result = CORINFO_TYPE_UNDEF;
9318 JIT_TO_EE_TRANSITION();
9320 TypeHandle VMClsHnd(hClass);
9322 result = asCorInfoType(VMClsHnd.GetHFAType());
9324 EE_TO_JIT_TRANSITION();
9329 /*********************************************************************/
9331 // return the unmanaged calling convention for a PInvoke
9332 CorInfoUnmanagedCallConv CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method)
9341 CorInfoUnmanagedCallConv result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9343 JIT_TO_EE_TRANSITION();
9345 MethodDesc* pMD = NULL;
9346 pMD = GetMethod(method);
9347 _ASSERTE(pMD->IsNDirect());
9352 PInvokeStaticSigInfo sigInfo(pMD, PInvokeStaticSigInfo::NO_THROW_ON_ERROR);
9354 switch (sigInfo.GetCallConv()) {
9355 case pmCallConvCdecl:
9356 result = CORINFO_UNMANAGED_CALLCONV_C;
9358 case pmCallConvStdcall:
9359 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9361 case pmCallConvThiscall:
9362 result = CORINFO_UNMANAGED_CALLCONV_THISCALL;
9365 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9370 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9372 EX_END_CATCH(SwallowAllExceptions)
9373 #else // !_TARGET_X86_
9375 // we have only one calling convention
9377 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9378 #endif // !_TARGET_X86_
9380 EE_TO_JIT_TRANSITION();
9385 /*********************************************************************/
9386 BOOL NDirectMethodDesc::ComputeMarshalingRequired()
9388 WRAPPER_NO_CONTRACT;
9390 return NDirect::MarshalingRequired(this);
9393 /*********************************************************************/
9394 BOOL CEEInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig)
9403 BOOL result = FALSE;
9405 JIT_TO_EE_TRANSITION();
9409 MethodDesc* ftn = GetMethod(method);
9410 _ASSERTE(ftn->IsNDirect());
9411 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9413 #if defined(HAS_NDIRECT_IMPORT_PRECODE)
9414 if (pMD->IsVarArg())
9416 // Varag P/Invoke must not be inlined because its NDirectMethodDesc
9417 // does not contain a meaningful stack size (it is call site specific).
9418 // See code:InlinedCallFrame.UpdateRegDisplay where this is needed.
9421 else if (pMD->MarshalingRequired())
9423 // This is not a no-marshal signature.
9428 // This is a no-marshal non-vararg signature.
9432 // Marshalling is required to lazy initialize the indirection cell
9433 // without NDirectImportPrecode.
9439 // check the call site signature
9440 result = NDirect::MarshalingRequired(
9443 GetModule(callSiteSig->scope));
9446 EE_TO_JIT_TRANSITION();
9451 /*********************************************************************/
9452 // Generate a cookie based on the signature that would needs to be passed
9453 // to CORINFO_HELP_PINVOKE_CALLI
9454 LPVOID CEEInfo::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig,
9455 void **ppIndirection)
9457 WRAPPER_NO_CONTRACT;
9459 return getVarArgsHandle(szMetaSig, ppIndirection);
9462 bool CEEInfo::canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig)
9464 LIMITED_METHOD_CONTRACT;
9469 // Check any constraints on method type arguments
9470 BOOL CEEInfo::satisfiesMethodConstraints(
9471 CORINFO_CLASS_HANDLE parent,
9472 CORINFO_METHOD_HANDLE method)
9481 BOOL result = FALSE;
9483 JIT_TO_EE_TRANSITION();
9485 _ASSERTE(parent != NULL);
9486 _ASSERTE(method != NULL);
9487 result = GetMethod(method)->SatisfiesMethodConstraints(TypeHandle(parent));
9489 EE_TO_JIT_TRANSITION();
9496 /*********************************************************************/
9497 // Given a delegate target class, a target method parent class, a target method,
9498 // a delegate class, check if the method signature is compatible with the Invoke method of the delegate
9499 // (under the typical instantiation of any free type variables in the memberref signatures).
9501 // objCls should be NULL if the target object is NULL
9502 //@GENERICSVER: new (suitable for generics)
9503 BOOL CEEInfo::isCompatibleDelegate(
9504 CORINFO_CLASS_HANDLE objCls,
9505 CORINFO_CLASS_HANDLE methodParentCls,
9506 CORINFO_METHOD_HANDLE method,
9507 CORINFO_CLASS_HANDLE delegateCls,
9508 BOOL* pfIsOpenDelegate)
9517 BOOL result = FALSE;
9519 JIT_TO_EE_TRANSITION();
9521 _ASSERTE(method != NULL);
9522 _ASSERTE(delegateCls != NULL);
9524 TypeHandle delegateClsHnd = (TypeHandle) delegateCls;
9526 _ASSERTE(delegateClsHnd.GetMethodTable()->IsDelegate());
9528 TypeHandle methodParentHnd = (TypeHandle) (methodParentCls);
9529 MethodDesc* pMDFtn = GetMethod(method);
9530 TypeHandle objClsHnd(objCls);
9534 result = COMDelegate::ValidateCtor(objClsHnd, methodParentHnd, pMDFtn, delegateClsHnd, pfIsOpenDelegate);
9539 EX_END_CATCH(SwallowAllExceptions)
9541 EE_TO_JIT_TRANSITION();
9546 /*********************************************************************/
9547 // return the unmanaged target *if method has already been prelinked.*
9548 void* CEEInfo::getPInvokeUnmanagedTarget(CORINFO_METHOD_HANDLE method,
9549 void **ppIndirection)
9558 void* result = NULL;
9560 if (ppIndirection != NULL)
9561 *ppIndirection = NULL;
9563 #ifndef CROSSGEN_COMPILE
9564 JIT_TO_EE_TRANSITION();
9566 MethodDesc* ftn = GetMethod(method);
9567 _ASSERTE(ftn->IsNDirect());
9568 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9570 if (pMD->NDirectTargetIsImportThunk())
9575 result = pMD->GetNDirectTarget();
9578 EE_TO_JIT_TRANSITION();
9579 #endif // CROSSGEN_COMPILE
9584 /*********************************************************************/
9585 // return address of fixup area for late-bound N/Direct calls.
9586 void* CEEInfo::getAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE method,
9587 void **ppIndirection)
9596 void * result = NULL;
9598 if (ppIndirection != NULL)
9599 *ppIndirection = NULL;
9601 JIT_TO_EE_TRANSITION_LEAF();
9603 MethodDesc* ftn = GetMethod(method);
9604 _ASSERTE(ftn->IsNDirect());
9605 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9607 result = (LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
9609 EE_TO_JIT_TRANSITION_LEAF();
9614 /*********************************************************************/
9615 // return address of fixup area for late-bound N/Direct calls.
9616 void CEEInfo::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method,
9617 CORINFO_CONST_LOOKUP *pLookup)
9619 WRAPPER_NO_CONTRACT;
9622 pLookup->accessType = IAT_PVALUE;
9623 pLookup->addr = getAddressOfPInvokeFixup(method, &pIndirection);
9624 _ASSERTE(pIndirection == NULL);
9627 /*********************************************************************/
9628 CORINFO_JUST_MY_CODE_HANDLE CEEInfo::getJustMyCodeHandle(
9629 CORINFO_METHOD_HANDLE method,
9630 CORINFO_JUST_MY_CODE_HANDLE**ppIndirection)
9639 CORINFO_JUST_MY_CODE_HANDLE result = NULL;
9642 *ppIndirection = NULL;
9644 JIT_TO_EE_TRANSITION_LEAF();
9646 // Get the flag from the debugger.
9647 MethodDesc* ftn = GetMethod(method);
9648 DWORD * pFlagAddr = NULL;
9650 if (g_pDebugInterface)
9652 pFlagAddr = g_pDebugInterface->GetJMCFlagAddr(ftn->GetModule());
9655 result = (CORINFO_JUST_MY_CODE_HANDLE) pFlagAddr;
9657 EE_TO_JIT_TRANSITION_LEAF();
9662 /*********************************************************************/
9663 void InlinedCallFrame::GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo *pInfo)
9665 LIMITED_METHOD_CONTRACT;
9667 pInfo->size = sizeof(GSCookie) + sizeof(InlinedCallFrame);
9669 pInfo->offsetOfGSCookie = 0;
9670 pInfo->offsetOfFrameVptr = sizeof(GSCookie);
9671 pInfo->offsetOfFrameLink = sizeof(GSCookie) + Frame::GetOffsetOfNextLink();
9672 pInfo->offsetOfCallSiteSP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallSiteSP);
9673 pInfo->offsetOfCalleeSavedFP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCalleeSavedFP);
9674 pInfo->offsetOfCallTarget = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_Datum);
9675 pInfo->offsetOfReturnAddress = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallerReturnAddress);
9678 /*********************************************************************/
9679 // Return details about EE internal data structures
9680 void CEEInfo::getEEInfo(CORINFO_EE_INFO *pEEInfoOut)
9689 INDEBUG(memset(pEEInfoOut, 0xCC, sizeof(*pEEInfoOut)));
9691 JIT_TO_EE_TRANSITION();
9693 InlinedCallFrame::GetEEInfo(&pEEInfoOut->inlinedCallFrameInfo);
9695 // Offsets into the Thread structure
9696 pEEInfoOut->offsetOfThreadFrame = Thread::GetOffsetOfCurrentFrame();
9697 pEEInfoOut->offsetOfGCState = Thread::GetOffsetOfGCFlag();
9700 pEEInfoOut->offsetOfDelegateInstance = DelegateObject::GetOffsetOfTarget();
9701 pEEInfoOut->offsetOfDelegateFirstTarget = DelegateObject::GetOffsetOfMethodPtr();
9703 // Secure delegate offsets
9704 pEEInfoOut->offsetOfSecureDelegateIndirectCell = DelegateObject::GetOffsetOfMethodPtrAux();
9707 pEEInfoOut->offsetOfTransparentProxyRP = TransparentProxyObject::GetOffsetOfRP();
9708 pEEInfoOut->offsetOfRealProxyServer = RealProxyObject::GetOffsetOfServerObject();
9710 pEEInfoOut->offsetOfObjArrayData = (DWORD)PtrArray::GetDataOffset();
9712 pEEInfoOut->sizeOfReversePInvokeFrame = (DWORD)-1;
9714 pEEInfoOut->osPageSize = GetOsPageSize();
9715 pEEInfoOut->maxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
9716 pEEInfoOut->targetAbi = CORINFO_CORECLR_ABI;
9718 pEEInfoOut->osType = CORINFO_WINNT;
9720 // hardcode OS version to 0.0.0. These fields can be removed from JITEE interface
9721 pEEInfoOut->osMajor = 0;
9722 pEEInfoOut->osMinor = 0;
9723 pEEInfoOut->osBuild = 0;
9725 EE_TO_JIT_TRANSITION();
9728 LPCWSTR CEEInfo::getJitTimeLogFilename()
9737 LPCWSTR result = NULL;
9739 JIT_TO_EE_TRANSITION();
9740 result = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitTimeLogFile);
9741 EE_TO_JIT_TRANSITION();
9748 // Return details about EE internal data structures
9749 DWORD CEEInfo::getThreadTLSIndex(void **ppIndirection)
9758 DWORD result = (DWORD)-1;
9760 if (ppIndirection != NULL)
9761 *ppIndirection = NULL;
9763 JIT_TO_EE_TRANSITION();
9765 #if !defined(CROSSGEN_COMPILE) && !defined(FEATURE_IMPLICIT_TLS)
9766 result = GetThreadTLSIndex();
9768 // The JIT can use the optimized TLS access only if the runtime is using it as well.
9769 // (This is necessaryto make managed code work well under appverifier.)
9770 if (GetTLSAccessMode(result) == TLSACCESS_GENERIC)
9774 EE_TO_JIT_TRANSITION();
9779 const void * CEEInfo::getInlinedCallFrameVptr(void **ppIndirection)
9788 void * result = NULL;
9790 if (ppIndirection != NULL)
9791 *ppIndirection = NULL;
9793 JIT_TO_EE_TRANSITION_LEAF();
9795 #ifndef CROSSGEN_COMPILE
9796 result = (void*)InlinedCallFrame::GetMethodFrameVPtr();
9798 result = (void*)0x43210;
9801 EE_TO_JIT_TRANSITION_LEAF();
9806 LONG * CEEInfo::getAddrOfCaptureThreadGlobal(void **ppIndirection)
9815 LONG * result = NULL;
9817 if (ppIndirection != NULL)
9818 *ppIndirection = NULL;
9820 JIT_TO_EE_TRANSITION_LEAF();
9822 result = (LONG *)&g_TrapReturningThreads;
9824 EE_TO_JIT_TRANSITION_LEAF();
9831 HRESULT CEEInfo::GetErrorHRESULT(struct _EXCEPTION_POINTERS *pExceptionPointers)
9842 //This function is called from the JIT64 exception filter during PEVerify. Because it is a filter, it
9843 //can be "called" from a NOTHROW region in the case of StackOverflow. Security::MapToHR throws
9844 //internally, but it catches all exceptions. Therefore, none of the children can cause an exception to
9845 //percolate out of this function (except for Stack Overflow). Obviously I can't explain most of this to
9846 //the Contracts system, and I can't add this CONTRACT_VIOLATION to the filter in Jit64.
9847 CONTRACT_VIOLATION(ThrowsViolation);
9849 JIT_TO_EE_TRANSITION();
9853 OBJECTREF throwable = GetThread()->LastThrownObject();
9854 hr = GetExceptionHResult(throwable);
9856 EE_TO_JIT_TRANSITION();
9862 ULONG CEEInfo::GetErrorMessage(__inout_ecount(bufferLength) LPWSTR buffer, ULONG bufferLength)
9873 #ifndef CROSSGEN_COMPILE
9874 JIT_TO_EE_TRANSITION();
9878 OBJECTREF throwable = GetThread()->LastThrownObject();
9880 if (throwable != NULL)
9884 result = GetExceptionMessage(throwable, buffer, bufferLength);
9889 EX_END_CATCH(SwallowAllExceptions)
9892 EE_TO_JIT_TRANSITION();
9898 // This method is called from CEEInfo::FilterException which
9899 // is run as part of the SEH filter clause for the JIT.
9900 // It is fatal to throw an exception while running a SEH filter clause
9901 // so our contract is NOTHROW, NOTRIGGER.
9903 LONG EEFilterException(struct _EXCEPTION_POINTERS *pExceptionPointers, void *unused)
9913 JIT_TO_EE_TRANSITION_LEAF();
9915 VALIDATE_BACKOUT_STACK_CONSUMPTION;
9917 unsigned code = pExceptionPointers->ExceptionRecord->ExceptionCode;
9920 if (code == EXCEPTION_ACCESS_VIOLATION)
9925 _ASSERTE(!"Access violation while Jitting!");
9926 // If you set the debugger to catch access violations and 'go'
9927 // you will get back to the point at which the access violation occurred
9928 result = EXCEPTION_CONTINUE_EXECUTION;
9932 result = EXCEPTION_CONTINUE_SEARCH;
9937 // No one should be catching breakpoint
9938 // Similarly the JIT doesn't know how to reset the guard page, so it shouldn't
9939 // be catching a hard stack overflow
9940 if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP || code == EXCEPTION_STACK_OVERFLOW)
9942 result = EXCEPTION_CONTINUE_SEARCH;
9944 #ifdef CROSSGEN_COMPILE
9947 result = EXCEPTION_EXECUTE_HANDLER;
9950 else if (!IsComPlusException(pExceptionPointers->ExceptionRecord))
9952 result = EXCEPTION_EXECUTE_HANDLER;
9958 // This is actually the LastThrown exception object.
9959 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
9961 if (throwable != NULL)
9965 OBJECTREF oLastThrownObject;
9968 ZeroMemory(&_gc, sizeof(_gc));
9970 // Setup the throwables
9971 _gc.oLastThrownObject = throwable;
9973 GCPROTECT_BEGIN(_gc);
9975 // Don't catch ThreadAbort and other uncatchable exceptions
9976 if (IsUncatchable(&_gc.oLastThrownObject))
9977 result = EXCEPTION_CONTINUE_SEARCH;
9979 result = EXCEPTION_EXECUTE_HANDLER;
9986 EE_TO_JIT_TRANSITION_LEAF();
9991 int CEEInfo::FilterException(struct _EXCEPTION_POINTERS *pExceptionPointers)
9993 WRAPPER_NO_CONTRACT;
9994 return EEFilterException(pExceptionPointers, nullptr);
9997 // This code is called if FilterException chose to handle the exception.
9998 void CEEInfo::HandleException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10006 JIT_TO_EE_TRANSITION_LEAF();
10008 #ifndef CROSSGEN_COMPILE
10009 if (IsComPlusException(pExceptionPointers->ExceptionRecord))
10013 // This is actually the LastThrown exception object.
10014 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10016 if (throwable != NULL)
10020 OBJECTREF oLastThrownObject;
10021 OBJECTREF oCurrentThrowable;
10024 ZeroMemory(&_gc, sizeof(_gc));
10026 PTR_Thread pCurThread = GetThread();
10028 // Setup the throwables
10029 _gc.oLastThrownObject = throwable;
10031 // This will be NULL if no managed exception is active. Otherwise,
10032 // it will reference the active throwable.
10033 _gc.oCurrentThrowable = pCurThread->GetThrowable();
10035 GCPROTECT_BEGIN(_gc);
10037 // JIT does not use or reference managed exceptions at all and simply swallows them,
10038 // or lets them fly through so that they will either get caught in managed code, the VM
10039 // or will go unhandled.
10041 // Blind swallowing of managed exceptions can break the semantic of "which exception handler"
10042 // gets to process the managed exception first. The expected handler is managed code exception
10043 // handler (e.g. COMPlusFrameHandler on x86 and ProcessCLRException on 64bit) which will setup
10044 // the exception tracker for the exception that will enable the expected sync between the
10045 // LastThrownObject (LTO), setup in RaiseTheExceptionInternalOnly, and the exception tracker.
10047 // However, JIT can break this by swallowing the managed exception before managed code exception
10048 // handler gets a chance to setup an exception tracker for it. Since there is no cleanup
10049 // done for the swallowed exception as part of the unwind (because no exception tracker may have been setup),
10050 // we need to reset the LTO, if it is out of sync from the active throwable.
10052 // Hence, check if the LastThrownObject and active-exception throwable are in sync or not.
10053 // If not, bring them in sync.
10057 // It is possible that an exception was already in progress and while processing it (e.g.
10058 // invoking finally block), we invoked JIT that had another managed exception @ JIT-EE transition boundary
10059 // that is swallowed by the JIT before managed code exception handler sees it. This breaks the sync between
10060 // LTO and the active exception in the exception tracker.
10061 if (_gc.oCurrentThrowable != _gc.oLastThrownObject)
10065 // Note: Incase of OOM, this will get set to OOM instance.
10066 pCurThread->SafeSetLastThrownObject(_gc.oCurrentThrowable);
10074 EE_TO_JIT_TRANSITION_LEAF();
10077 void ThrowExceptionForJit(HRESULT res);
10079 void CEEInfo::ThrowExceptionForJitResult(
10089 JIT_TO_EE_TRANSITION();
10091 if (!SUCCEEDED(result))
10092 ThrowExceptionForJit(result);
10094 EE_TO_JIT_TRANSITION();
10098 CORINFO_MODULE_HANDLE CEEInfo::embedModuleHandle(CORINFO_MODULE_HANDLE handle,
10099 void **ppIndirection)
10106 PRECONDITION(!IsDynamicScope(handle));
10110 if (ppIndirection != NULL)
10111 *ppIndirection = NULL;
10113 JIT_TO_EE_TRANSITION_LEAF();
10115 EE_TO_JIT_TRANSITION_LEAF();
10120 CORINFO_CLASS_HANDLE CEEInfo::embedClassHandle(CORINFO_CLASS_HANDLE handle,
10121 void **ppIndirection)
10131 if (ppIndirection != NULL)
10132 *ppIndirection = NULL;
10134 JIT_TO_EE_TRANSITION_LEAF();
10136 EE_TO_JIT_TRANSITION_LEAF();
10141 CORINFO_FIELD_HANDLE CEEInfo::embedFieldHandle(CORINFO_FIELD_HANDLE handle,
10142 void **ppIndirection)
10152 if (ppIndirection != NULL)
10153 *ppIndirection = NULL;
10155 JIT_TO_EE_TRANSITION_LEAF();
10157 EE_TO_JIT_TRANSITION_LEAF();
10162 CORINFO_METHOD_HANDLE CEEInfo::embedMethodHandle(CORINFO_METHOD_HANDLE handle,
10163 void **ppIndirection)
10173 if (ppIndirection != NULL)
10174 *ppIndirection = NULL;
10176 JIT_TO_EE_TRANSITION_LEAF();
10178 EE_TO_JIT_TRANSITION_LEAF();
10183 /*********************************************************************/
10184 void CEEInfo::setJitFlags(const CORJIT_FLAGS& jitFlags)
10186 LIMITED_METHOD_CONTRACT;
10188 m_jitFlags = jitFlags;
10191 /*********************************************************************/
10192 DWORD CEEInfo::getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes)
10201 JIT_TO_EE_TRANSITION_LEAF();
10203 _ASSERTE(sizeInBytes >= sizeof(m_jitFlags));
10204 *jitFlags = m_jitFlags;
10206 EE_TO_JIT_TRANSITION_LEAF();
10208 return sizeof(m_jitFlags);
10211 /*********************************************************************/
10212 #if !defined(PLATFORM_UNIX)
10214 struct RunWithErrorTrapFilterParam
10216 ICorDynamicInfo* m_corInfo;
10217 void (*m_function)(void*);
10219 EXCEPTION_POINTERS m_exceptionPointers;
10222 static LONG RunWithErrorTrapFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
10224 WRAPPER_NO_CONTRACT;
10226 auto* param = reinterpret_cast<RunWithErrorTrapFilterParam*>(theParam);
10227 param->m_exceptionPointers = *exceptionPointers;
10228 return param->m_corInfo->FilterException(exceptionPointers);
10231 #endif // !defined(PLATFORM_UNIX)
10233 bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param)
10235 // No dynamic contract here because SEH is used
10236 STATIC_CONTRACT_THROWS;
10237 STATIC_CONTRACT_GC_TRIGGERS;
10238 STATIC_CONTRACT_SO_TOLERANT;
10239 STATIC_CONTRACT_MODE_PREEMPTIVE;
10241 // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
10242 // transitions into the EE proper should occur either via the call to
10243 // `EEFilterException` (which is appropraitely marked) or via JIT/EE
10244 // interface calls made by `function`.
10246 bool success = true;
10248 #if !defined(PLATFORM_UNIX)
10250 RunWithErrorTrapFilterParam trapParam;
10251 trapParam.m_corInfo = m_pOverride == nullptr ? this : m_pOverride;
10252 trapParam.m_function = function;
10253 trapParam.m_param = param;
10255 PAL_TRY(RunWithErrorTrapFilterParam*, pTrapParam, &trapParam)
10257 pTrapParam->m_function(pTrapParam->m_param);
10259 PAL_EXCEPT_FILTER(RunWithErrorTrapFilter)
10261 HandleException(&trapParam.m_exceptionPointers);
10266 #else // !defined(PLATFORM_UNIX)
10268 // We shouldn't need PAL_TRY on *nix: any exceptions that we are able to catch
10269 // ought to originate from the runtime itself and should be catchable inside of
10270 // EX_TRY/EX_CATCH, including emulated SEH exceptions.
10279 EX_END_CATCH(RethrowTerminalExceptions);
10286 /*********************************************************************/
10287 IEEMemoryManager* CEEInfo::getMemoryManager()
10296 IEEMemoryManager* result = NULL;
10298 JIT_TO_EE_TRANSITION_LEAF();
10300 result = GetEEMemoryManager();
10302 EE_TO_JIT_TRANSITION_LEAF();
10307 /*********************************************************************/
10308 int CEEInfo::doAssert(const char* szFile, int iLine, const char* szExpr)
10310 STATIC_CONTRACT_SO_TOLERANT;
10311 STATIC_CONTRACT_THROWS;
10312 STATIC_CONTRACT_GC_TRIGGERS;
10313 STATIC_CONTRACT_MODE_PREEMPTIVE;
10314 STATIC_CONTRACT_DEBUG_ONLY;
10318 JIT_TO_EE_TRANSITION();
10320 #ifdef CROSSGEN_COMPILE
10321 ThrowHR(COR_E_INVALIDPROGRAM);
10325 BEGIN_DEBUG_ONLY_CODE;
10326 result = _DbgBreakCheck(szFile, iLine, szExpr);
10327 END_DEBUG_ONLY_CODE;
10329 result = 1; // break into debugger
10334 EE_TO_JIT_TRANSITION();
10339 void CEEInfo::reportFatalError(CorJitResult result)
10341 STATIC_CONTRACT_SO_TOLERANT;
10342 STATIC_CONTRACT_THROWS;
10343 STATIC_CONTRACT_GC_TRIGGERS;
10344 STATIC_CONTRACT_MODE_PREEMPTIVE;
10346 JIT_TO_EE_TRANSITION_LEAF();
10348 STRESS_LOG2(LF_JIT,LL_ERROR, "Jit reported error 0x%x while compiling 0x%p\n",
10349 (int)result, (INT_PTR)getMethodBeingCompiled());
10351 EE_TO_JIT_TRANSITION_LEAF();
10354 BOOL CEEInfo::logMsg(unsigned level, const char* fmt, va_list args)
10356 STATIC_CONTRACT_SO_TOLERANT;
10357 STATIC_CONTRACT_THROWS;
10358 STATIC_CONTRACT_GC_TRIGGERS;
10359 STATIC_CONTRACT_MODE_PREEMPTIVE;
10360 STATIC_CONTRACT_DEBUG_ONLY;
10362 BOOL result = FALSE;
10364 JIT_TO_EE_TRANSITION_LEAF();
10367 if (LoggingOn(LF_JIT, level))
10369 LogSpewValist(LF_JIT, level, (char*) fmt, args);
10374 EE_TO_JIT_TRANSITION_LEAF();
10379 void CEEInfo::yieldExecution()
10381 WRAPPER_NO_CONTRACT;
10385 #ifndef CROSSGEN_COMPILE
10387 /*********************************************************************/
10389 void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
10390 void ** ppIndirection) /* OUT */
10399 void* result = NULL;
10401 if (ppIndirection != NULL)
10402 *ppIndirection = NULL;
10404 JIT_TO_EE_TRANSITION_LEAF();
10406 _ASSERTE(ftnNum < CORINFO_HELP_COUNT);
10408 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10410 size_t dynamicFtnNum = ((size_t)pfnHelper - 1);
10411 if (dynamicFtnNum < DYNAMIC_CORINFO_HELP_COUNT)
10414 #pragma warning(push)
10415 #pragma warning(disable:26001) // "Bounds checked above using the underflow trick"
10416 #endif /*_PREFAST_ */
10418 #if defined(_TARGET_AMD64_)
10419 // To avoid using a jump stub we always call certain helpers using an indirect call.
10420 // Because when using a direct call and the target is father away than 2^31 bytes,
10421 // the direct call instead goes to a jump stub which jumps to the jit helper.
10422 // However in this process the jump stub will corrupt RAX.
10424 // The set of helpers for which RAX must be preserved are the profiler probes
10425 // and the STOP_FOR_GC helper which maps to JIT_RareDisableHelper.
10426 // In the case of the STOP_FOR_GC helper RAX can be holding a function return value.
10428 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_STOP_FOR_GC ||
10429 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER ||
10430 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE ||
10431 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL)
10433 _ASSERTE(ppIndirection != NULL);
10434 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10439 #if defined(ENABLE_FAST_GCPOLL_HELPER)
10440 //always call this indirectly so that we can swap GC Poll helpers.
10441 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_POLL_GC)
10443 _ASSERTE(ppIndirection != NULL);
10444 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10449 pfnHelper = hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10452 #pragma warning(pop)
10453 #endif /*_PREFAST_*/
10456 _ASSERTE(pfnHelper);
10458 result = (LPVOID)GetEEFuncEntryPoint(pfnHelper);
10460 EE_TO_JIT_TRANSITION_LEAF();
10465 PCODE CEEJitInfo::getHelperFtnStatic(CorInfoHelpFunc ftnNum)
10467 LIMITED_METHOD_CONTRACT;
10469 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10471 // If pfnHelper is an index into the dynamic helper table, it should be less
10472 // than DYNAMIC_CORINFO_HELP_COUNT. In this case we need to find the actual pfnHelper
10473 // using an extra indirection. Note the special case
10474 // where pfnHelper==0 where pfnHelper-1 will underflow and we will avoid the indirection.
10475 if (((size_t)pfnHelper - 1) < DYNAMIC_CORINFO_HELP_COUNT)
10477 pfnHelper = hlpDynamicFuncTable[((size_t)pfnHelper - 1)].pfnHelper;
10480 _ASSERTE(pfnHelper != NULL);
10482 return GetEEFuncEntryPoint(pfnHelper);
10485 void CEEJitInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
10490 PRECONDITION(CheckPointer(moduleFrom));
10491 PRECONDITION(!IsDynamicScope(moduleFrom));
10492 PRECONDITION(CheckPointer(moduleTo));
10493 PRECONDITION(!IsDynamicScope(moduleTo));
10494 PRECONDITION(moduleFrom != moduleTo);
10498 // This is only called internaly. JIT-EE transition is not needed.
10499 // JIT_TO_EE_TRANSITION();
10501 Module *dependency = (Module *)moduleTo;
10502 _ASSERTE(!dependency->IsSystem());
10504 if (m_pMethodBeingCompiled->IsLCGMethod())
10506 // The context module of the m_pMethodBeingCompiled is irrelevant. Rather than tracking
10507 // the dependency, we just do immediate activation.
10508 dependency->EnsureActive();
10512 #ifdef FEATURE_LOADER_OPTIMIZATION
10513 Module *context = (Module *)moduleFrom;
10515 // Record active dependency for loader.
10516 context->AddActiveDependency(dependency, FALSE);
10518 dependency->EnsureActive();
10522 // EE_TO_JIT_TRANSITION();
10526 // Wrapper around CEEInfo::GetProfilingHandle. The first time this is called for a
10527 // method desc, it calls through to EEToProfInterfaceImpl::EEFunctionIDMappe and caches the
10528 // result in CEEJitInfo::GetProfilingHandleCache. Thereafter, this wrapper regurgitates the cached values
10529 // rather than calling into CEEInfo::GetProfilingHandle each time. This avoids
10530 // making duplicate calls into the profiler's FunctionIDMapper callback.
10531 void CEEJitInfo::GetProfilingHandle(BOOL *pbHookFunction,
10532 void **pProfilerHandle,
10533 BOOL *pbIndirectedHandles)
10542 _ASSERTE(pbHookFunction != NULL);
10543 _ASSERTE(pProfilerHandle != NULL);
10544 _ASSERTE(pbIndirectedHandles != NULL);
10546 if (!m_gphCache.m_bGphIsCacheValid)
10548 #ifdef PROFILING_SUPPORTED
10549 JIT_TO_EE_TRANSITION();
10551 // Cache not filled in, so make our first and only call to CEEInfo::GetProfilingHandle here
10553 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
10554 // they shouldnever come here as they are called out in GetCompileFlag
10555 _ASSERTE(!m_pMethodBeingCompiled->IsNoMetadata());
10557 // We pass in the typical method definition to the function mapper because in
10558 // Whidbey all the profiling API transactions are done in terms of typical
10559 // method definitions not instantiations.
10560 BOOL bHookFunction = TRUE;
10561 void * profilerHandle = m_pMethodBeingCompiled;
10564 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
10565 profilerHandle = (void *)g_profControlBlock.pProfInterface->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction);
10566 END_PIN_PROFILER();
10569 m_gphCache.m_pvGphProfilerHandle = profilerHandle;
10570 m_gphCache.m_bGphHookFunction = (bHookFunction != FALSE);
10571 m_gphCache.m_bGphIsCacheValid = true;
10573 EE_TO_JIT_TRANSITION();
10574 #endif //PROFILING_SUPPORTED
10577 // Our cache of these values are bitfield bools, but the interface requires
10578 // BOOL. So to avoid setting aside a staging area on the stack for these
10579 // values, we filled them in directly in the if (not cached yet) case.
10580 *pbHookFunction = (m_gphCache.m_bGphHookFunction != false);
10582 // At this point, the remaining values must be in the cache by now, so use them
10583 *pProfilerHandle = m_gphCache.m_pvGphProfilerHandle;
10586 // This is the JIT case, which is never indirected.
10588 *pbIndirectedHandles = FALSE;
10591 /*********************************************************************/
10592 void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr)
10599 CodeHeader* pCodeHeader = GetCodeHeader();
10601 jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len);
10604 /*********************************************************************/
10605 // Route jit information to the Jit Debug store.
10606 void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
10607 ICorDebugInfo::OffsetMapping *pMap)
10616 JIT_TO_EE_TRANSITION();
10618 // We receive ownership of the array
10619 _ASSERTE(m_pOffsetMapping == NULL && m_iOffsetMapping == 0);
10620 m_iOffsetMapping = cMap;
10621 m_pOffsetMapping = pMap;
10623 EE_TO_JIT_TRANSITION();
10626 void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
10635 JIT_TO_EE_TRANSITION();
10637 // We receive ownership of the array
10638 _ASSERTE(m_pNativeVarInfo == NULL && m_iNativeVarInfo == 0);
10639 m_iNativeVarInfo = cVars;
10640 m_pNativeVarInfo = vars;
10642 EE_TO_JIT_TRANSITION();
10645 void CEEJitInfo::CompressDebugInfo()
10654 // Don't track JIT info for DynamicMethods.
10655 if (m_pMethodBeingCompiled->IsDynamicMethod())
10658 if (m_iOffsetMapping == 0 && m_iNativeVarInfo == 0)
10661 JIT_TO_EE_TRANSITION();
10665 PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars(
10666 m_pOffsetMapping, m_iOffsetMapping,
10667 m_pNativeVarInfo, m_iNativeVarInfo,
10669 m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap());
10671 GetCodeHeader()->SetDebugInfo(pDebugInfo);
10675 // Just ignore exceptions here. The debugger's structures will still be in a consistent state.
10677 EX_END_CATCH(SwallowAllExceptions)
10679 EE_TO_JIT_TRANSITION();
10682 void reservePersonalityRoutineSpace(ULONG &unwindSize)
10684 #if defined(_TARGET_X86_)
10686 #elif defined(_TARGET_AMD64_)
10687 // Add space for personality routine, it must be 4-byte aligned.
10688 // Everything in the UNWIND_INFO up to the variable-sized UnwindCodes
10689 // array has already had its size included in unwindSize by the caller.
10690 unwindSize += sizeof(ULONG);
10692 // Note that the count of unwind codes (2 bytes each) is stored as a UBYTE
10693 // So the largest size could be 510 bytes, plus the header and language
10694 // specific stuff. This can't overflow.
10696 _ASSERTE(FitsInU4(unwindSize + sizeof(ULONG)));
10697 unwindSize = (ULONG)(ALIGN_UP(unwindSize, sizeof(ULONG)));
10698 #elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
10699 // The JIT passes in a 4-byte aligned block of unwind data.
10700 _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
10702 // Add space for personality routine, it must be 4-byte aligned.
10703 unwindSize += sizeof(ULONG);
10705 PORTABILITY_ASSERT("reservePersonalityRoutineSpace");
10706 #endif // !defined(_TARGET_AMD64_)
10709 // Reserve memory for the method/funclet's unwind information.
10710 // Note that this must be called before allocMem. It should be
10711 // called once for the main method, once for every funclet, and
10712 // once for every block of cold code for which allocUnwindInfo
10715 // This is necessary because jitted code must allocate all the
10716 // memory needed for the unwindInfo at the allocMem call.
10717 // For prejitted code we split up the unwinding information into
10718 // separate sections .rdata and .pdata.
10720 void CEEJitInfo::reserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize)
10722 #ifdef WIN64EXCEPTIONS
10731 JIT_TO_EE_TRANSITION_LEAF();
10733 CONSISTENCY_CHECK_MSG(!isColdCode, "Hot/Cold splitting is not supported in jitted code");
10734 _ASSERTE_MSG(m_theUnwindBlock == NULL,
10735 "reserveUnwindInfo() can only be called before allocMem(), but allocMem() has already been called. "
10736 "This may indicate the JIT has hit a NO_WAY assert after calling allocMem(), and is re-JITting. "
10737 "Set COMPlus_JitBreakOnBadCode=1 and rerun to get the real error.");
10739 ULONG currentSize = unwindSize;
10741 reservePersonalityRoutineSpace(currentSize);
10743 m_totalUnwindSize += currentSize;
10745 m_totalUnwindInfos++;
10747 EE_TO_JIT_TRANSITION_LEAF();
10748 #else // WIN64EXCEPTIONS
10749 LIMITED_METHOD_CONTRACT;
10750 // Dummy implementation to make cross-platform altjit work
10751 #endif // WIN64EXCEPTIONS
10754 // Allocate and initialize the .rdata and .pdata for this method or
10755 // funclet and get the block of memory needed for the machine specific
10756 // unwind information (the info for crawling the stack frame).
10757 // Note that allocMem must be called first.
10759 // The pHotCode parameter points at the first byte of the code of the method
10760 // The startOffset and endOffset are the region (main or funclet) that
10761 // we are to allocate and create .rdata and .pdata for.
10762 // The pUnwindBlock is copied and contains the .pdata unwind area
10766 // pHotCode main method code buffer, always filled in
10767 // pColdCode always NULL for jitted code
10768 // startOffset start of code block, relative to pHotCode
10769 // endOffset end of code block, relative to pHotCode
10770 // unwindSize size of unwind info pointed to by pUnwindBlock
10771 // pUnwindBlock pointer to unwind info
10772 // funcKind type of funclet (main method code, handler, filter)
10774 void CEEJitInfo::allocUnwindInfo (
10775 BYTE * pHotCode, /* IN */
10776 BYTE * pColdCode, /* IN */
10777 ULONG startOffset, /* IN */
10778 ULONG endOffset, /* IN */
10779 ULONG unwindSize, /* IN */
10780 BYTE * pUnwindBlock, /* IN */
10781 CorJitFuncKind funcKind /* IN */
10784 #ifdef WIN64EXCEPTIONS
10790 PRECONDITION(m_theUnwindBlock != NULL);
10791 PRECONDITION(m_usedUnwindSize < m_totalUnwindSize);
10792 PRECONDITION(m_usedUnwindInfos < m_totalUnwindInfos);
10793 PRECONDITION(endOffset <= m_codeSize);
10796 CONSISTENCY_CHECK_MSG(pColdCode == NULL, "Hot/Cold code splitting not supported for jitted code");
10798 JIT_TO_EE_TRANSITION();
10801 // We add one callback-type dynamic function table per range section.
10802 // Therefore, the RUNTIME_FUNCTION info is always relative to the
10803 // image base contained in the dynamic function table, which happens
10804 // to be the LowAddress of the range section. The JIT has no
10805 // knowledge of the range section, so it gives us offsets that are
10806 // relative to the beginning of the method (pHotCode) and we allocate
10807 // and initialize the RUNTIME_FUNCTION data and record its location
10808 // in this function.
10811 if (funcKind != CORJIT_FUNC_ROOT)
10813 // The main method should be emitted before funclets
10814 _ASSERTE(m_usedUnwindInfos > 0);
10817 PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeader->GetUnwindInfo(m_usedUnwindInfos);
10818 m_usedUnwindInfos++;
10820 // Make sure that the RUNTIME_FUNCTION is aligned on a DWORD sized boundary
10821 _ASSERTE(IS_ALIGNED(pRuntimeFunction, sizeof(DWORD)));
10823 UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *) &(m_theUnwindBlock[m_usedUnwindSize]);
10824 m_usedUnwindSize += unwindSize;
10826 reservePersonalityRoutineSpace(m_usedUnwindSize);
10828 _ASSERTE(m_usedUnwindSize <= m_totalUnwindSize);
10830 // Make sure that the UnwindInfo is aligned
10831 _ASSERTE(IS_ALIGNED(pUnwindInfo, sizeof(ULONG)));
10833 /* Calculate Image Relative offset to add to the jit generated unwind offsets */
10835 TADDR baseAddress = m_moduleBase;
10837 size_t currentCodeSizeT = (size_t)pHotCode - baseAddress;
10839 /* Check if currentCodeSizeT offset fits in 32-bits */
10840 if (!FitsInU4(currentCodeSizeT))
10842 _ASSERTE(!"Bad currentCodeSizeT");
10843 COMPlusThrowHR(E_FAIL);
10846 /* Check if EndAddress offset fits in 32-bit */
10847 if (!FitsInU4(currentCodeSizeT + endOffset))
10849 _ASSERTE(!"Bad currentCodeSizeT");
10850 COMPlusThrowHR(E_FAIL);
10853 unsigned currentCodeOffset = (unsigned) currentCodeSizeT;
10855 /* Calculate Unwind Info delta */
10856 size_t unwindInfoDeltaT = (size_t) pUnwindInfo - baseAddress;
10858 /* Check if unwindDeltaT offset fits in 32-bits */
10859 if (!FitsInU4(unwindInfoDeltaT))
10861 _ASSERTE(!"Bad unwindInfoDeltaT");
10862 COMPlusThrowHR(E_FAIL);
10865 unsigned unwindInfoDelta = (unsigned) unwindInfoDeltaT;
10867 RUNTIME_FUNCTION__SetBeginAddress(pRuntimeFunction, currentCodeOffset + startOffset);
10869 #ifdef _TARGET_AMD64_
10870 pRuntimeFunction->EndAddress = currentCodeOffset + endOffset;
10873 RUNTIME_FUNCTION__SetUnwindInfoAddress(pRuntimeFunction, unwindInfoDelta);
10876 if (funcKind != CORJIT_FUNC_ROOT)
10878 // Check the the new funclet doesn't overlap any existing funclet.
10880 for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++)
10882 PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeader->GetUnwindInfo(iUnwindInfo);
10883 _ASSERTE(( RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress)
10884 || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction)));
10889 /* Copy the UnwindBlock */
10890 memcpy(pUnwindInfo, pUnwindBlock, unwindSize);
10892 #if defined(_TARGET_X86_)
10896 #elif defined(_TARGET_AMD64_)
10898 pUnwindInfo->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
10900 ULONG * pPersonalityRoutine = (ULONG*)ALIGN_UP(&(pUnwindInfo->UnwindCode[pUnwindInfo->CountOfUnwindCodes]), sizeof(ULONG));
10901 *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
10903 #elif defined(_TARGET_ARM64_)
10905 *(LONG *)pUnwindInfo |= (1 << 20); // X bit
10907 ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
10908 *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
10910 #elif defined(_TARGET_ARM_)
10912 *(LONG *)pUnwindInfo |= (1 << 20); // X bit
10914 ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
10915 *pPersonalityRoutine = (TADDR)ProcessCLRException - baseAddress;
10919 #if defined(_TARGET_AMD64_)
10920 // Publish the new unwind information in a way that the ETW stack crawler can find
10921 if (m_usedUnwindInfos == m_totalUnwindInfos)
10922 UnwindInfoTable::PublishUnwindInfoForMethod(baseAddress, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos);
10923 #endif // defined(_TARGET_AMD64_)
10925 EE_TO_JIT_TRANSITION();
10926 #else // WIN64EXCEPTIONS
10927 LIMITED_METHOD_CONTRACT;
10928 // Dummy implementation to make cross-platform altjit work
10929 #endif // WIN64EXCEPTIONS
10932 void CEEJitInfo::recordCallSite(ULONG instrOffset,
10933 CORINFO_SIG_INFO * callSig,
10934 CORINFO_METHOD_HANDLE methodHandle)
10936 // Currently, only testing tools use this method. The EE itself doesn't need record this information.
10937 // N.B. The memory that callSig points to is managed by the JIT and isn't guaranteed to be around after
10938 // this function returns, so future implementations should copy the sig info if they want it to persist.
10939 LIMITED_METHOD_CONTRACT;
10942 // This is a variant for AMD64 or other machines that
10943 // cannot always hold the destination address in a 32-bit location
10944 // A relocation is recorded if we are pre-jitting.
10945 // A jump thunk may be inserted if we are jitting
10947 void CEEJitInfo::recordRelocation(void * location,
10961 JIT_TO_EE_TRANSITION();
10965 switch (fRelocType)
10967 case IMAGE_REL_BASED_DIR64:
10968 // Write 64-bits into location
10969 *((UINT64 *) ((BYTE *) location + slot)) = (UINT64) target;
10972 #ifdef _TARGET_AMD64_
10973 case IMAGE_REL_BASED_REL32:
10975 target = (BYTE *)target + addlDelta;
10977 INT32 * fixupLocation = (INT32 *) ((BYTE *) location + slot);
10978 BYTE * baseAddr = (BYTE *)fixupLocation + sizeof(INT32);
10980 delta = (INT64)((BYTE *)target - baseAddr);
10983 // Do we need to insert a jump stub to make the source reach the target?
10985 // Note that we cannot stress insertion of jump stub by inserting it unconditionally. JIT records the relocations
10986 // for intra-module jumps and calls. It does not expect the register used by the jump stub to be trashed.
10988 if (!FitsInI4(delta))
10993 // When m_fAllowRel32 == TRUE, the JIT will use REL32s for both data addresses and direct code targets.
10994 // Since we cannot tell what the relocation is for, we have to defensively retry.
10996 m_fRel32Overflow = TRUE;
11002 // When m_fAllowRel32 == FALSE, the JIT will use a REL32s for direct code targets only.
11005 delta = rel32UsingJumpStub(fixupLocation, (PCODE)target, m_pMethodBeingCompiled);
11009 LOG((LF_JIT, LL_INFO100000, "Encoded a PCREL32 at" FMT_ADDR "to" FMT_ADDR "+%d, delta is 0x%04x\n",
11010 DBG_ADDR(fixupLocation), DBG_ADDR(target), addlDelta, delta));
11012 // Write the 32-bits pc-relative delta into location
11013 *fixupLocation = (INT32) delta;
11016 #endif // _TARGET_AMD64_
11018 #ifdef _TARGET_ARM64_
11019 case IMAGE_REL_ARM64_BRANCH26: // 26 bit offset << 2 & sign ext, for B and BL
11021 _ASSERTE(slot == 0);
11022 _ASSERTE(addlDelta == 0);
11024 PCODE branchTarget = (PCODE) target;
11025 _ASSERTE((branchTarget & 0x3) == 0); // the low two bits must be zero
11027 PCODE fixupLocation = (PCODE) location;
11028 _ASSERTE((fixupLocation & 0x3) == 0); // the low two bits must be zero
11030 delta = (INT64)(branchTarget - fixupLocation);
11031 _ASSERTE((delta & 0x3) == 0); // the low two bits must be zero
11033 UINT32 branchInstr = *((UINT32*) fixupLocation);
11034 branchInstr &= 0xFC000000; // keep bits 31-26
11035 _ASSERTE((branchInstr & 0x7FFFFFFF) == 0x14000000); // Must be B or BL
11038 // Do we need to insert a jump stub to make the source reach the target?
11041 if (!FitsInRel28(delta))
11045 TADDR baseAddr = (TADDR)fixupLocation;
11046 TADDR loAddr = baseAddr - 0x08000000; // -2^27
11047 TADDR hiAddr = baseAddr + 0x07FFFFFF; // +2^27-1
11049 // Check for the wrap around cases
11050 if (loAddr > baseAddr)
11051 loAddr = UINT64_MIN; // overflow
11052 if (hiAddr < baseAddr)
11053 hiAddr = UINT64_MAX; // overflow
11055 PCODE jumpStubAddr = ExecutionManager::jumpStub(m_pMethodBeingCompiled,
11060 delta = (INT64)(jumpStubAddr - fixupLocation);
11062 if (!FitsInRel28(delta))
11064 _ASSERTE(!"jump stub was not in expected range");
11065 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
11068 LOG((LF_JIT, LL_INFO100000, "Using JumpStub at" FMT_ADDR "that jumps to" FMT_ADDR "\n",
11069 DBG_ADDR(jumpStubAddr), DBG_ADDR(target)));
11072 LOG((LF_JIT, LL_INFO100000, "Encoded a BRANCH26 at" FMT_ADDR "to" FMT_ADDR ", delta is 0x%04x\n",
11073 DBG_ADDR(fixupLocation), DBG_ADDR(target), delta));
11075 _ASSERTE(FitsInRel28(delta));
11077 PutArm64Rel28((UINT32*) fixupLocation, (INT32)delta);
11081 case IMAGE_REL_ARM64_PAGEBASE_REL21:
11083 _ASSERTE(slot == 0);
11084 _ASSERTE(addlDelta == 0);
11086 // Write the 21 bits pc-relative page address into location.
11087 INT64 targetPage = (INT64)target & 0xFFFFFFFFFFFFF000LL;
11088 INT64 lcoationPage = (INT64)location & 0xFFFFFFFFFFFFF000LL;
11089 INT64 relPage = (INT64)(targetPage - lcoationPage);
11090 INT32 imm21 = (INT32)(relPage >> 12) & 0x1FFFFF;
11091 PutArm64Rel21((UINT32 *)location, imm21);
11095 case IMAGE_REL_ARM64_PAGEOFFSET_12A:
11097 _ASSERTE(slot == 0);
11098 _ASSERTE(addlDelta == 0);
11100 // Write the 12 bits page offset into location.
11101 INT32 imm12 = (INT32)target & 0xFFFLL;
11102 PutArm64Rel12((UINT32 *)location, imm12);
11106 #endif // _TARGET_ARM64_
11109 _ASSERTE(!"Unknown reloc type");
11113 EE_TO_JIT_TRANSITION();
11115 JIT_TO_EE_TRANSITION_LEAF();
11117 // Nothing to do on 32-bit
11119 EE_TO_JIT_TRANSITION_LEAF();
11123 WORD CEEJitInfo::getRelocTypeHint(void * target)
11132 #ifdef _TARGET_AMD64_
11135 // The JIT calls this method for data addresses only. It always uses REL32s for direct code targets.
11136 if (IsPreferredExecutableRange(target))
11137 return IMAGE_REL_BASED_REL32;
11139 #endif // _TARGET_AMD64_
11145 void CEEJitInfo::getModuleNativeEntryPointRange(void** pStart, void** pEnd)
11155 JIT_TO_EE_TRANSITION_LEAF();
11157 *pStart = *pEnd = 0;
11159 EE_TO_JIT_TRANSITION_LEAF();
11162 DWORD CEEJitInfo::getExpectedTargetArchitecture()
11164 LIMITED_METHOD_CONTRACT;
11166 return IMAGE_FILE_MACHINE_NATIVE;
11169 void CEEInfo::JitProcessShutdownWork()
11171 LIMITED_METHOD_CONTRACT;
11173 EEJitManager* jitMgr = ExecutionManager::GetEEJitManager();
11175 // If we didn't load the JIT, there is no work to do.
11176 if (jitMgr->m_jit != NULL)
11178 // Do the shutdown work.
11179 jitMgr->m_jit->ProcessShutdownWork(this);
11182 #ifdef ALLOW_SXS_JIT
11183 if (jitMgr->m_alternateJit != NULL)
11185 jitMgr->m_alternateJit->ProcessShutdownWork(this);
11187 #endif // ALLOW_SXS_JIT
11190 /*********************************************************************/
11191 InfoAccessType CEEJitInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
11202 InfoAccessType result = IAT_PVALUE;
11204 JIT_TO_EE_TRANSITION();
11206 _ASSERTE(ppValue != NULL);
11208 if (IsDynamicScope(scopeHnd))
11210 *ppValue = (LPVOID)GetDynamicResolver(scopeHnd)->ConstructStringLiteral(metaTok);
11214 *ppValue = (LPVOID)ConstructStringLiteral(scopeHnd, metaTok); // throws
11217 EE_TO_JIT_TRANSITION();
11222 /*********************************************************************/
11223 InfoAccessType CEEJitInfo::emptyStringLiteral(void ** ppValue)
11232 InfoAccessType result = IAT_PVALUE;
11234 if(NingenEnabled())
11240 JIT_TO_EE_TRANSITION();
11241 *ppValue = StringObject::GetEmptyStringRefPtr();
11242 EE_TO_JIT_TRANSITION();
11247 /*********************************************************************/
11248 void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
11249 void **ppIndirection)
11258 void *result = NULL;
11260 if (ppIndirection != NULL)
11261 *ppIndirection = NULL;
11263 // Do not bother with initialization if we are only verifying the method.
11264 if (isVerifyOnly())
11266 return (void *)0x10;
11269 JIT_TO_EE_TRANSITION();
11271 FieldDesc* field = (FieldDesc*) fieldHnd;
11273 MethodTable* pMT = field->GetEnclosingMethodTable();
11275 _ASSERTE(!pMT->ContainsGenericVariables());
11277 // We must not call here for statics of collectible types.
11278 _ASSERTE(!pMT->Collectible());
11282 if (!field->IsRVA())
11284 // <REVISIT_TODO>@todo: assert that the current method being compiled is unshared</REVISIT_TODO>
11286 // Allocate space for the local class if necessary, but don't trigger
11287 // class construction.
11288 DomainLocalModule *pLocalModule = pMT->GetDomainLocalModule();
11289 pLocalModule->PopulateClass(pMT);
11293 base = (void *) field->GetBase();
11296 result = field->GetStaticAddressHandle(base);
11298 EE_TO_JIT_TRANSITION();
11303 static void *GetClassSync(MethodTable *pMT)
11305 STANDARD_VM_CONTRACT;
11309 OBJECTREF ref = pMT->GetManagedClassObject();
11310 return (void*)ref->GetSyncBlock()->GetMonitor();
11313 /*********************************************************************/
11314 void* CEEJitInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
11315 void **ppIndirection)
11324 void * result = NULL;
11326 if (ppIndirection != NULL)
11327 *ppIndirection = NULL;
11329 JIT_TO_EE_TRANSITION();
11331 result = GetClassSync((GetMethod(ftnHnd))->GetMethodTable());
11333 EE_TO_JIT_TRANSITION();
11338 /*********************************************************************/
11339 HRESULT CEEJitInfo::allocBBProfileBuffer (
11341 ICorJitInfo::ProfileBuffer ** profileBuffer
11351 HRESULT hr = E_FAIL;
11353 JIT_TO_EE_TRANSITION();
11355 #ifdef FEATURE_PREJIT
11357 // We need to know the code size. Typically we can get the code size
11358 // from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so
11359 // for that case we need to use DynamicResolver to get the code size.
11361 unsigned codeSize = 0;
11362 if (m_pMethodBeingCompiled->IsDynamicMethod())
11364 unsigned stackSize, ehSize;
11365 CorInfoOptions options;
11366 DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver();
11367 pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize);
11371 codeSize = m_ILHeader->GetCodeSize();
11374 *profileBuffer = m_pMethodBeingCompiled->GetLoaderModule()->AllocateProfileBuffer(m_pMethodBeingCompiled->GetMemberDef(), count, codeSize);
11375 hr = (*profileBuffer ? S_OK : E_OUTOFMEMORY);
11376 #else // FEATURE_PREJIT
11377 _ASSERTE(!"allocBBProfileBuffer not implemented on CEEJitInfo!");
11379 #endif // !FEATURE_PREJIT
11381 EE_TO_JIT_TRANSITION();
11386 // Consider implementing getBBProfileData on CEEJitInfo. This will allow us
11387 // to use profile info in codegen for non zapped images.
11388 HRESULT CEEJitInfo::getBBProfileData (
11389 CORINFO_METHOD_HANDLE ftnHnd,
11391 ICorJitInfo::ProfileBuffer ** profileBuffer,
11395 LIMITED_METHOD_CONTRACT;
11396 _ASSERTE(!"getBBProfileData not implemented on CEEJitInfo!");
11400 void CEEJitInfo::allocMem (
11401 ULONG hotCodeSize, /* IN */
11402 ULONG coldCodeSize, /* IN */
11403 ULONG roDataSize, /* IN */
11404 ULONG xcptnsCount, /* IN */
11405 CorJitAllocMemFlag flag, /* IN */
11406 void ** hotCodeBlock, /* OUT */
11407 void ** coldCodeBlock, /* OUT */
11408 void ** roDataBlock /* OUT */
11418 JIT_TO_EE_TRANSITION();
11420 _ASSERTE(coldCodeSize == 0);
11423 *coldCodeBlock = NULL;
11426 ULONG codeSize = hotCodeSize;
11427 void **codeBlock = hotCodeBlock;
11429 S_SIZE_T totalSize = S_SIZE_T(codeSize);
11431 size_t roDataAlignment = sizeof(void*);
11432 if ((flag & CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN)!= 0)
11434 roDataAlignment = 16;
11436 else if (roDataSize >= 8)
11438 roDataAlignment = 8;
11440 if (roDataSize > 0)
11442 size_t codeAlignment = ((flag & CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN)!= 0)
11443 ? 16 : sizeof(void*);
11444 totalSize.AlignUp(codeAlignment);
11445 if (roDataAlignment > codeAlignment) {
11446 // Add padding to align read-only data.
11447 totalSize += (roDataAlignment - codeAlignment);
11449 totalSize += roDataSize;
11452 #ifdef WIN64EXCEPTIONS
11453 totalSize.AlignUp(sizeof(DWORD));
11454 totalSize += m_totalUnwindSize;
11457 _ASSERTE(m_CodeHeader == 0 &&
11458 // The jit-compiler sometimes tries to compile a method a second time
11459 // if it failed the first time. In such a situation, m_CodeHeader may
11460 // have already been assigned. Its OK to ignore this assert in such a
11461 // situation - we will leak some memory, but that is acceptable
11462 // since this should happen very rarely.
11463 "Note that this may fire if the JITCompiler tries to recompile a method");
11465 if( totalSize.IsOverflow() )
11467 COMPlusThrowHR(CORJIT_OUTOFMEM);
11470 m_CodeHeader = m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), flag
11471 #ifdef WIN64EXCEPTIONS
11472 , m_totalUnwindInfos
11477 BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress();
11479 *codeBlock = current;
11480 current += codeSize;
11482 if (roDataSize > 0)
11484 current = (BYTE *)ALIGN_UP(current, roDataAlignment);
11485 *roDataBlock = current;
11486 current += roDataSize;
11490 *roDataBlock = NULL;
11493 #ifdef WIN64EXCEPTIONS
11494 current = (BYTE *)ALIGN_UP(current, sizeof(DWORD));
11496 m_theUnwindBlock = current;
11497 current += m_totalUnwindSize;
11500 _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value());
11503 m_codeSize = codeSize;
11506 EE_TO_JIT_TRANSITION();
11509 /*********************************************************************/
11510 void * CEEJitInfo::allocGCInfo (size_t size)
11519 void * block = NULL;
11521 JIT_TO_EE_TRANSITION();
11523 _ASSERTE(m_CodeHeader != 0);
11524 _ASSERTE(m_CodeHeader->GetGCInfo() == 0);
11527 if (size & 0xFFFFFFFF80000000LL)
11529 COMPlusThrowHR(CORJIT_OUTOFMEM);
11533 block = m_jitManager->allocGCInfo(m_CodeHeader,(DWORD)size, &m_GCinfo_len);
11536 COMPlusThrowHR(CORJIT_OUTOFMEM);
11539 _ASSERTE(m_CodeHeader->GetGCInfo() != 0 && block == m_CodeHeader->GetGCInfo());
11541 EE_TO_JIT_TRANSITION();
11546 /*********************************************************************/
11547 void CEEJitInfo::setEHcount (
11557 JIT_TO_EE_TRANSITION();
11559 _ASSERTE(cEH != 0);
11560 _ASSERTE(m_CodeHeader != 0);
11561 _ASSERTE(m_CodeHeader->GetEHInfo() == 0);
11563 EE_ILEXCEPTION* ret;
11564 ret = m_jitManager->allocEHInfo(m_CodeHeader,cEH, &m_EHinfo_len);
11565 _ASSERTE(ret); // allocEHInfo throws if there's not enough memory
11567 _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && m_CodeHeader->GetEHInfo()->EHCount() == cEH);
11569 EE_TO_JIT_TRANSITION();
11572 /*********************************************************************/
11573 void CEEJitInfo::setEHinfo (
11575 const CORINFO_EH_CLAUSE* clause)
11584 JIT_TO_EE_TRANSITION();
11586 // <REVISIT_TODO> Fix make the Code Manager EH clauses EH_INFO+</REVISIT_TODO>
11587 _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && EHnumber < m_CodeHeader->GetEHInfo()->EHCount());
11589 EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeader->GetEHInfo()->EHClause(EHnumber);
11591 pEHClause->TryStartPC = clause->TryOffset;
11592 pEHClause->TryEndPC = clause->TryLength;
11593 pEHClause->HandlerStartPC = clause->HandlerOffset;
11594 pEHClause->HandlerEndPC = clause->HandlerLength;
11595 pEHClause->ClassToken = clause->ClassToken;
11596 pEHClause->Flags = (CorExceptionFlag)clause->Flags;
11598 LOG((LF_EH, LL_INFO1000000, "Setting EH clause #%d for %s::%s\n", EHnumber, m_pMethodBeingCompiled->m_pszDebugClassName, m_pMethodBeingCompiled->m_pszDebugMethodName));
11599 LOG((LF_EH, LL_INFO1000000, " Flags : 0x%08lx -> 0x%08lx\n", clause->Flags, pEHClause->Flags));
11600 LOG((LF_EH, LL_INFO1000000, " TryOffset : 0x%08lx -> 0x%08lx (startpc)\n", clause->TryOffset, pEHClause->TryStartPC));
11601 LOG((LF_EH, LL_INFO1000000, " TryLength : 0x%08lx -> 0x%08lx (endpc)\n", clause->TryLength, pEHClause->TryEndPC));
11602 LOG((LF_EH, LL_INFO1000000, " HandlerOffset : 0x%08lx -> 0x%08lx\n", clause->HandlerOffset, pEHClause->HandlerStartPC));
11603 LOG((LF_EH, LL_INFO1000000, " HandlerLength : 0x%08lx -> 0x%08lx\n", clause->HandlerLength, pEHClause->HandlerEndPC));
11604 LOG((LF_EH, LL_INFO1000000, " ClassToken : 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->ClassToken));
11605 LOG((LF_EH, LL_INFO1000000, " FilterOffset : 0x%08lx -> 0x%08lx\n", clause->FilterOffset, pEHClause->FilterOffset));
11607 if (m_pMethodBeingCompiled->IsDynamicMethod() &&
11608 ((pEHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) == 0) &&
11609 (clause->ClassToken != NULL))
11611 MethodDesc * pMD; FieldDesc * pFD;
11612 m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver()->ResolveToken(clause->ClassToken, (TypeHandle *)&pEHClause->TypeHandle, &pMD, &pFD);
11613 SetHasCachedTypeHandle(pEHClause);
11614 LOG((LF_EH, LL_INFO1000000, " CachedTypeHandle: 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->TypeHandle));
11617 EE_TO_JIT_TRANSITION();
11620 /*********************************************************************/
11621 // get individual exception handler
11622 void CEEJitInfo::getEHinfo(
11623 CORINFO_METHOD_HANDLE ftn, /* IN */
11624 unsigned EHnumber, /* IN */
11625 CORINFO_EH_CLAUSE* clause) /* OUT */
11634 JIT_TO_EE_TRANSITION();
11636 if (IsDynamicMethodHandle(ftn))
11638 GetMethod(ftn)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
11642 _ASSERTE(ftn == CORINFO_METHOD_HANDLE(m_pMethodBeingCompiled)); // For now only support if the method being jitted
11643 getEHinfoHelper(ftn, EHnumber, clause, m_ILHeader);
11646 EE_TO_JIT_TRANSITION();
11648 #endif // CROSSGEN_COMPILE
11650 #if defined(CROSSGEN_COMPILE)
11651 EXTERN_C ICorJitCompiler* __stdcall getJit();
11652 #endif // defined(CROSSGEN_COMPILE)
11654 #ifdef FEATURE_INTERPRETER
11655 static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr,
11657 struct CORINFO_METHOD_INFO *info,
11659 BYTE **nativeEntry,
11660 ULONG *nativeSizeOfCode)
11662 STATIC_CONTRACT_THROWS;
11663 STATIC_CONTRACT_GC_TRIGGERS;
11664 STATIC_CONTRACT_MODE_PREEMPTIVE;
11665 STATIC_CONTRACT_SO_INTOLERANT;
11667 SString namespaceOrClassName, methodName, methodSignature;
11668 // Fire an ETW event to mark the beginning of JIT'ing
11669 ETW::MethodLog::MethodJitting(reinterpret_cast<MethodDesc*>(info->ftn), &namespaceOrClassName, &methodName, &methodSignature);
11671 CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode);
11673 // Logically, it would seem that the end-of-JITting ETW even should go here, but it must come after the native code has been
11674 // set for the given method desc, which happens in a caller.
11678 #endif // FEATURE_INTERPRETER
11681 // Helper function because can't have dtors in BEGIN_SO_TOLERANT_CODE.
11683 CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr,
11685 struct CORINFO_METHOD_INFO *info,
11686 CORJIT_FLAGS jitFlags,
11687 BYTE **nativeEntry,
11688 ULONG *nativeSizeOfCode)
11690 STATIC_CONTRACT_THROWS;
11691 STATIC_CONTRACT_GC_TRIGGERS;
11692 STATIC_CONTRACT_MODE_PREEMPTIVE;
11693 STATIC_CONTRACT_SO_INTOLERANT;
11695 CorJitResult ret = CORJIT_SKIPPED; // Note that CORJIT_SKIPPED is an error exit status code
11698 comp->setJitFlags(jitFlags);
11700 #ifdef FEATURE_STACK_SAMPLING
11701 // SO_INTOLERANT due to init affecting global state.
11702 static ConfigDWORD s_stackSamplingEnabled;
11703 bool samplingEnabled = (s_stackSamplingEnabled.val(CLRConfig::UNSUPPORTED_StackSamplingEnabled) != 0);
11706 BEGIN_SO_TOLERANT_CODE(GetThread());
11709 #if defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
11710 if (FAILED(ret) && jitMgr->m_alternateJit
11711 #ifdef FEATURE_STACK_SAMPLING
11712 && (!samplingEnabled || (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)))
11716 ret = jitMgr->m_alternateJit->compileMethod( comp,
11718 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11720 nativeSizeOfCode );
11722 #ifdef FEATURE_STACK_SAMPLING
11723 if (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND))
11725 // Don't bother with failures if we couldn't collect a trace.
11728 #endif // FEATURE_STACK_SAMPLING
11730 // If we failed to jit, then fall back to the primary Jit.
11733 // Consider adding this call:
11734 // ((CEEJitInfo*)comp)->BackoutJitData(jitMgr);
11735 ((CEEJitInfo*)comp)->ResetForJitRetry();
11736 ret = CORJIT_SKIPPED;
11739 #endif // defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
11741 #ifdef FEATURE_INTERPRETER
11742 static ConfigDWORD s_InterpreterFallback;
11744 bool isInterpreterStub = false;
11745 bool interpreterFallback = (s_InterpreterFallback.val(CLRConfig::INTERNAL_InterpreterFallback) != 0);
11747 if (interpreterFallback == false)
11749 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
11750 // (We assume that importation is completely architecture-independent, or at least nearly so.)
11751 if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
11753 if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
11755 isInterpreterStub = true;
11760 if (FAILED(ret) && jitMgr->m_jit)
11762 ret = CompileMethodWithEtwWrapper(jitMgr,
11765 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11770 if (interpreterFallback == true)
11772 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
11773 // (We assume that importation is completely architecture-independent, or at least nearly so.)
11774 if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
11776 if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
11778 isInterpreterStub = true;
11785 ret = jitMgr->m_jit->compileMethod( comp,
11787 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11791 #endif // FEATURE_INTERPRETER
11793 #if !defined(CROSSGEN_COMPILE)
11794 // Cleanup any internal data structures allocated
11795 // such as IL code after a successfull JIT compile
11796 // If the JIT fails we keep the IL around and will
11797 // try reJIT the same IL. VSW 525059
11799 if (SUCCEEDED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !((CEEJitInfo*)comp)->JitAgain())
11801 ((CEEJitInfo*)comp)->CompressDebugInfo();
11803 #ifdef FEATURE_INTERPRETER
11804 // We do this cleanup in the prestub, where we know whether the method
11805 // has been interpreted.
11807 comp->MethodCompileComplete(info->ftn);
11808 #endif // FEATURE_INTERPRETER
11810 #endif // !defined(CROSSGEN_COMPILE)
11813 #if defined(FEATURE_GDBJIT)
11814 bool isJittedEntry = SUCCEEDED(ret) && *nativeEntry != NULL;
11816 #ifdef FEATURE_INTERPRETER
11817 isJittedEntry &= !isInterpreterStub;
11818 #endif // FEATURE_INTERPRETER
11822 CodeHeader* pCH = ((CodeHeader*)((PCODE)*nativeEntry & ~1)) - 1;
11823 pCH->SetCalledMethods((PTR_VOID)comp->GetCalledMethods());
11827 END_SO_TOLERANT_CODE;
11833 /*********************************************************************/
11834 CorJitResult invokeCompileMethod(EEJitManager *jitMgr,
11836 struct CORINFO_METHOD_INFO *info,
11837 CORJIT_FLAGS jitFlags,
11838 BYTE **nativeEntry,
11839 ULONG *nativeSizeOfCode)
11847 // The JIT runs in preemptive mode
11852 CorJitResult ret = invokeCompileMethodHelper(jitMgr, comp, info, jitFlags, nativeEntry, nativeSizeOfCode);
11855 // Verify that we are still in preemptive mode when we return
11859 _ASSERTE(GetThread()->PreemptiveGCDisabled() == FALSE);
11864 CorJitResult CallCompileMethodWithSEHWrapper(EEJitManager *jitMgr,
11866 struct CORINFO_METHOD_INFO *info,
11867 CORJIT_FLAGS flags,
11868 BYTE **nativeEntry,
11869 ULONG *nativeSizeOfCode,
11872 // no dynamic contract here because SEH is used, with a finally clause
11873 STATIC_CONTRACT_NOTHROW;
11874 STATIC_CONTRACT_GC_TRIGGERS;
11876 LOG((LF_CORDB, LL_EVERYTHING, "CallCompileMethodWithSEHWrapper called...\n"));
11880 EEJitManager *jitMgr;
11882 struct CORINFO_METHOD_INFO *info;
11883 CORJIT_FLAGS flags;
11884 BYTE **nativeEntry;
11885 ULONG *nativeSizeOfCode;
11889 param.jitMgr = jitMgr;
11892 param.flags = flags;
11893 param.nativeEntry = nativeEntry;
11894 param.nativeSizeOfCode = nativeSizeOfCode;
11896 param.res = CORJIT_INTERNALERROR;
11898 PAL_TRY(Param *, pParam, ¶m)
11901 // Call out to the JIT-compiler
11904 pParam->res = invokeCompileMethod( pParam->jitMgr,
11908 pParam->nativeEntry,
11909 pParam->nativeSizeOfCode);
11913 #if defined(DEBUGGING_SUPPORTED) && !defined(CROSSGEN_COMPILE)
11914 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) &&
11915 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MCJIT_BACKGROUND)
11916 #ifdef FEATURE_STACK_SAMPLING
11917 && !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)
11918 #endif // FEATURE_STACK_SAMPLING
11922 // Notify the debugger that we have successfully jitted the function
11924 if (ftn->HasNativeCode())
11927 // Nothing to do here (don't need to notify the debugger
11928 // because the function has already been successfully jitted)
11930 // This is the case where we aborted the jit because of a deadlock cycle
11936 if (g_pDebugInterface)
11938 if (param.res == CORJIT_OK && !((CEEJitInfo*)param.comp)->JitAgain())
11940 g_pDebugInterface->JITComplete(ftn, (TADDR) *nativeEntry);
11945 #endif // DEBUGGING_SUPPORTED && !CROSSGEN_COMPILE
11952 /*********************************************************************/
11953 // Figures out the compile flags that are used by both JIT and NGen
11955 /* static */ CORJIT_FLAGS CEEInfo::GetBaseCompileFlags(MethodDesc * ftn)
11963 // Figure out the code quality flags
11966 CORJIT_FLAGS flags;
11967 if (g_pConfig->JitFramed())
11968 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
11969 if (g_pConfig->JitAlignLoops())
11970 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_ALIGN_LOOPS);
11971 if (ReJitManager::IsReJITEnabled() || g_pConfig->AddRejitNops())
11972 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_REJIT_NOPS);
11973 #ifdef _TARGET_X86_
11974 if (g_pConfig->PInvokeRestoreEsp(ftn->GetModule()->IsPreV4Assembly()))
11975 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PINVOKE_RESTORE_ESP);
11976 #endif // _TARGET_X86_
11978 //See if we should instruct the JIT to emit calls to JIT_PollGC for thread suspension. If we have a
11979 //non-default value in the EE Config, then use that. Otherwise select the platform specific default.
11980 #ifdef FEATURE_ENABLE_GCPOLL
11981 EEConfig::GCPollType pollType = g_pConfig->GetGCPollType();
11982 if (EEConfig::GCPOLL_TYPE_POLL == pollType)
11983 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_CALLS);
11984 else if (EEConfig::GCPOLL_TYPE_INLINE == pollType)
11985 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_INLINE);
11986 #endif //FEATURE_ENABLE_GCPOLL
11988 // Set flags based on method's ImplFlags.
11989 if (!ftn->IsNoMetadata())
11991 DWORD dwImplFlags = 0;
11992 IfFailThrow(ftn->GetMDImport()->GetMethodImplProps(ftn->GetMemberDef(), NULL, &dwImplFlags));
11994 if (IsMiNoOptimization(dwImplFlags))
11996 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
11999 // Always emit frames for methods marked no-inline (see #define ETW_EBP_FRAMED in the JIT)
12000 if (IsMiNoInlining(dwImplFlags))
12002 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12009 /*********************************************************************/
12010 // Figures out (some of) the flags to use to compile the method
12011 // Returns the new set to use
12013 CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags)
12015 STANDARD_VM_CONTRACT;
12017 //Right now if we don't have a debug interface on CoreCLR, we can't generate debug info. So, in those
12018 //cases don't attempt it.
12019 if (!g_pDebugInterface)
12022 #ifdef DEBUGGING_SUPPORTED
12025 if (g_pConfig->GenDebuggableCode())
12026 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12029 #ifdef EnC_SUPPORTED
12030 if (pModule->IsEditAndContinueEnabled())
12032 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_EnC);
12034 #endif // EnC_SUPPORTED
12036 // Debug info is always tracked
12037 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12038 #endif // DEBUGGING_SUPPORTED
12040 if (CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
12042 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12045 if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12047 // If we are only verifying the method, dont need any debug info and this
12048 // prevents getVars()/getBoundaries() from being called unnecessarily.
12049 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12050 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12056 CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHOD_INFO * methodInfo)
12058 STANDARD_VM_CONTRACT;
12060 _ASSERTE(methodInfo->regionKind == CORINFO_REGION_JIT);
12063 // Get the compile flags that are shared between JIT and NGen
12065 flags.Add(CEEInfo::GetBaseCompileFlags(ftn));
12068 // Get CPU specific flags
12070 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12072 flags.Add(ExecutionManager::GetEEJitManager()->GetCPUCompileFlags());
12076 // Find the debugger and profiler related flags
12079 #ifdef DEBUGGING_SUPPORTED
12080 flags.Add(GetDebuggerCompileFlags(ftn->GetModule(), flags));
12083 #ifdef PROFILING_SUPPORTED
12084 if (CORProfilerTrackEnterLeave() && !ftn->IsNoMetadata())
12085 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE);
12087 if (CORProfilerTrackTransitions())
12088 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_NO_PINVOKE_INLINE);
12089 #endif // PROFILING_SUPPORTED
12091 // Set optimization flags
12092 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT))
12094 unsigned optType = g_pConfig->GenOptimizeType();
12095 _ASSERTE(optType <= OPT_RANDOM);
12097 if (optType == OPT_RANDOM)
12098 optType = methodInfo->ILCodeSize % OPT_RANDOM;
12100 if (g_pConfig->JitMinOpts())
12101 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12103 if (optType == OPT_SIZE)
12105 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SIZE_OPT);
12107 else if (optType == OPT_SPEED)
12109 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SPEED_OPT);
12113 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12115 if (ftn->IsILStub())
12117 // no debug info available for IL stubs
12118 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12124 // ********************************************************************
12126 // Throw the right type of exception for the given JIT result
12128 void ThrowExceptionForJit(HRESULT res)
12140 case CORJIT_OUTOFMEM:
12144 #ifdef _TARGET_X86_
12145 // Currently, only x86 JIT returns adequate error codes. The x86 JIT is also the
12146 // JIT that has more limitations and given that to get this message for 64 bit
12147 // is going to require some code churn (either changing their EH handlers or
12148 // fixing the 3 or 4 code sites they have that return CORJIT_INTERNALERROR independently
12149 // of the error, the least risk fix is making this x86 only.
12150 case CORJIT_INTERNALERROR:
12151 COMPlusThrow(kInvalidProgramException, (UINT) IDS_EE_JIT_COMPILER_ERROR);
12155 case CORJIT_BADCODE:
12157 COMPlusThrow(kInvalidProgramException);
12162 // ********************************************************************
12164 LONG g_JitCount = 0;
12167 //#define PERF_TRACK_METHOD_JITTIMES
12168 #ifdef _TARGET_AMD64_
12169 BOOL g_fAllowRel32 = TRUE;
12173 // ********************************************************************
12175 // ********************************************************************
12177 // The reason that this is named UnsafeJitFunction is that this helper
12178 // method is not thread safe! When multiple threads get in here for
12179 // the same pMD, ALL of them MUST return the SAME value.
12180 // To insure that this happens you must call MakeJitWorker.
12181 // It creates a DeadlockAware list of methods being jitted and prevents us
12182 // from trying to jit the same method more that once.
12184 // Calls to this method that occur to check if inlining can occur on x86,
12185 // are OK since they discard the return value of this method.
12187 PCODE UnsafeJitFunction(MethodDesc* ftn, COR_ILMETHOD_DECODER* ILHeader, CORJIT_FLAGS flags,
12188 ULONG * pSizeOfCode)
12190 STANDARD_VM_CONTRACT;
12194 COOPERATIVE_TRANSITION_BEGIN();
12196 #ifdef FEATURE_PREJIT
12198 if (g_pConfig->RequireZaps() == EEConfig::REQUIRE_ZAPS_ALL &&
12199 ftn->GetModule()->GetDomainFile()->IsZapRequired() &&
12200 PartialNGenStressPercentage() == 0 &&
12201 #ifdef FEATURE_STACK_SAMPLING
12202 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND) &&
12204 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12206 StackSString ss(SString::Ascii, "ZapRequire: JIT compiler invoked for ");
12207 TypeString::AppendMethodInternal(ss, ftn);
12210 // Assert as some test may not check their error codes well. So throwing an
12211 // exception may not cause a test failure (as it should).
12212 StackScratchBuffer scratch;
12213 DbgAssertDialog(__FILE__, __LINE__, (char*)ss.GetUTF8(scratch));
12216 COMPlusThrowNonLocalized(kFileNotFoundException, ss.GetUnicode());
12219 #endif // FEATURE_PREJIT
12221 #ifndef CROSSGEN_COMPILE
12222 EEJitManager *jitMgr = ExecutionManager::GetEEJitManager();
12223 if (!jitMgr->LoadJIT())
12225 #ifdef ALLOW_SXS_JIT
12226 if (!jitMgr->IsMainJitLoaded())
12228 // Don't want to throw InvalidProgram from here.
12229 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12231 if (!jitMgr->IsAltJitLoaded())
12233 // Don't want to throw InvalidProgram from here.
12234 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load alternative JIT compiler"));
12236 #else // ALLOW_SXS_JIT
12237 // Don't want to throw InvalidProgram from here.
12238 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12239 #endif // ALLOW_SXS_JIT
12241 #endif // CROSSGEN_COMPILE
12244 // This is here so we can see the name and class easily in the debugger
12246 LPCUTF8 cls = ftn->GetMethodTable()->GetDebugClassName();
12247 LPCUTF8 name = ftn->GetName();
12249 if (ftn->IsNoMetadata())
12251 if (ftn->IsILStub())
12253 LOG((LF_JIT, LL_INFO10000, "{ Jitting IL Stub }\n"));
12257 LOG((LF_JIT, LL_INFO10000, "{ Jitting dynamic method }\n"));
12262 SString methodString;
12263 if (LoggingOn(LF_JIT, LL_INFO10000))
12264 TypeString::AppendMethodDebug(methodString, ftn);
12266 LOG((LF_JIT, LL_INFO10000, "{ Jitting method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12270 if (!SString::_stricmp(cls,"ENC") &&
12271 (!SString::_stricmp(name,"G")))
12281 CORINFO_METHOD_HANDLE ftnHnd = (CORINFO_METHOD_HANDLE)ftn;
12282 CORINFO_METHOD_INFO methodInfo;
12284 getMethodInfoHelper(ftn, ftnHnd, ILHeader, &methodInfo);
12286 // If it's generic then we can only enter through an instantiated md (unless we're just verifying it)
12287 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || !ftn->IsGenericMethodDefinition());
12289 // If it's an instance method then it must not be entered from a generic class
12290 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || ftn->IsStatic() ||
12291 ftn->GetNumGenericClassArgs() == 0 || ftn->HasClassInstantiation());
12293 // method attributes and signature are consistant
12294 _ASSERTE(!!ftn->IsStatic() == ((methodInfo.args.callConv & CORINFO_CALLCONV_HASTHIS) == 0));
12296 flags = GetCompileFlags(ftn, flags, &methodInfo);
12299 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION))
12301 SString methodString;
12302 if (LoggingOn(LF_VERIFIER, LL_INFO100))
12303 TypeString::AppendMethodDebug(methodString, ftn);
12305 LOG((LF_VERIFIER, LL_INFO100, "{ Will verify method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12309 #ifdef _TARGET_AMD64_
12310 BOOL fForceRel32Overflow = FALSE;
12313 // Always exercise the overflow codepath with force relocs
12314 if (PEDecoder::GetForceRelocs())
12315 fForceRel32Overflow = TRUE;
12318 BOOL fAllowRel32 = g_fAllowRel32 | fForceRel32Overflow;
12320 // For determinism, never try to use the REL32 in compilation process
12321 if (IsCompilationProcess())
12323 fForceRel32Overflow = FALSE;
12324 fAllowRel32 = FALSE;
12326 #endif // _TARGET_AMD64_
12330 #ifndef CROSSGEN_COMPILE
12331 CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY),
12332 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING));
12334 // This path should be only ever used for verification in crossgen and so we should not need EEJitManager
12335 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY));
12336 CEEInfo jitInfo(ftn, true);
12337 EEJitManager *jitMgr = NULL;
12340 #if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE)
12341 if (fForceRel32Overflow)
12342 jitInfo.SetRel32Overflow(fAllowRel32);
12343 jitInfo.SetAllowRel32(fAllowRel32);
12346 MethodDesc * pMethodForSecurity = jitInfo.GetMethodForSecurity(ftnHnd);
12348 //Since the check could trigger a demand, we have to do this every time.
12349 //This is actually an overly complicated way to make sure that a method can access all its arguments
12350 //and its return type.
12351 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
12352 TypeHandle ownerTypeForSecurity = TypeHandle(pMethodForSecurity->GetMethodTable());
12353 DynamicResolver *pAccessContext = NULL;
12354 BOOL doAccessCheck = TRUE;
12355 if (pMethodForSecurity->IsDynamicMethod())
12357 doAccessCheck = ModifyCheckForDynamicMethod(pMethodForSecurity->AsDynamicMethodDesc()->GetResolver(),
12358 &ownerTypeForSecurity,
12359 &accessCheckType, &pAccessContext);
12363 AccessCheckOptions accessCheckOptions(accessCheckType,
12365 TRUE /*Throw on error*/,
12366 pMethodForSecurity);
12368 StaticAccessCheckContext accessContext(pMethodForSecurity, ownerTypeForSecurity.GetMethodTable());
12370 // We now do an access check from pMethodForSecurity to pMethodForSecurity, its sole purpose is to
12371 // verify that pMethodForSecurity/ownerTypeForSecurity has access to all its parameters.
12373 // ownerTypeForSecurity.GetMethodTable() can be null if the pMethodForSecurity is a DynamicMethod
12374 // associated with a TypeDesc (Array, Ptr, Ref, or FnPtr). That doesn't make any sense, but we will
12375 // just do an access check from a NULL context which means only public types are accessible.
12376 if (!ClassLoader::CanAccess(&accessContext,
12377 ownerTypeForSecurity.GetMethodTable(),
12378 ownerTypeForSecurity.GetAssembly(),
12379 pMethodForSecurity->GetAttrs(),
12380 pMethodForSecurity,
12382 accessCheckOptions))
12384 EX_THROW(EEMethodException, (pMethodForSecurity));
12395 /* There is a double indirection to call compileMethod - can we
12396 improve this with the new structure? */
12398 #ifdef PERF_TRACK_METHOD_JITTIMES
12399 //Because we're not calling QPC enough. I'm not going to track times if we're just importing.
12400 LARGE_INTEGER methodJitTimeStart = {0};
12401 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12402 QueryPerformanceCounter (&methodJitTimeStart);
12405 #if defined(ENABLE_PERF_COUNTERS)
12409 #if defined(ENABLE_PERF_COUNTERS)
12410 LARGE_INTEGER CycleStart;
12411 QueryPerformanceCounter (&CycleStart);
12412 #endif // defined(ENABLE_PERF_COUNTERS)
12414 // Note on debuggerTrackInfo arg: if we're only importing (ie, verifying/
12415 // checking to make sure we could JIT, but not actually generating code (
12416 // eg, for inlining), then DON'T TELL THE DEBUGGER about this.
12417 res = CallCompileMethodWithSEHWrapper(jitMgr,
12424 LOG((LF_CORDB, LL_EVERYTHING, "Got through CallCompile MethodWithSEHWrapper\n"));
12426 #if FEATURE_PERFMAP
12427 // Save the code size so that it can be reported to the perfmap.
12428 if (pSizeOfCode != NULL)
12430 *pSizeOfCode = sizeOfCode;
12434 #if defined(ENABLE_PERF_COUNTERS)
12435 LARGE_INTEGER CycleStop;
12436 QueryPerformanceCounter(&CycleStop);
12437 GetPerfCounters().m_Jit.timeInJitBase = GetPerfCounters().m_Jit.timeInJit;
12438 GetPerfCounters().m_Jit.timeInJit += static_cast<DWORD>(CycleStop.QuadPart - CycleStart.QuadPart);
12439 GetPerfCounters().m_Jit.cMethodsJitted++;
12440 GetPerfCounters().m_Jit.cbILJitted+=methodInfo.ILCodeSize;
12442 #endif // defined(ENABLE_PERF_COUNTERS)
12444 #if defined(ENABLE_PERF_COUNTERS)
12448 #ifdef PERF_TRACK_METHOD_JITTIMES
12449 //store the time in the string buffer. Module name and token are unique enough. Also, do not
12450 //capture importing time, just actual compilation time.
12451 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12453 LARGE_INTEGER methodJitTimeStop;
12454 QueryPerformanceCounter(&methodJitTimeStop);
12456 ftn->GetModule()->GetDomainFile()->GetFile()->GetCodeBaseOrName(codeBase);
12457 codeBase.AppendPrintf(W(",0x%x,%d,%d\n"),
12458 //(const WCHAR *)codeBase, //module name
12459 ftn->GetMemberDef(), //method token
12460 (unsigned)(methodJitTimeStop.QuadPart - methodJitTimeStart.QuadPart), //cycle count
12461 methodInfo.ILCodeSize //il size
12463 WszOutputDebugString((const WCHAR*)codeBase);
12465 #endif // PERF_TRACK_METHOD_JITTIMES
12469 LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s %s }\n",cls,name, ftn->m_pszDebugMethodSignature));
12471 if (!SUCCEEDED(res))
12473 COUNTER_ONLY(GetPerfCounters().m_Jit.cJitFailures++);
12475 #ifndef CROSSGEN_COMPILE
12476 jitInfo.BackoutJitData(jitMgr);
12479 ThrowExceptionForJit(res);
12482 if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12489 COMPlusThrow(kInvalidProgramException);
12491 #if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE)
12492 if (jitInfo.IsRel32Overflow())
12494 // Backout and try again with fAllowRel32 == FALSE.
12495 jitInfo.BackoutJitData(jitMgr);
12497 // Disallow rel32 relocs in future.
12498 g_fAllowRel32 = FALSE;
12500 _ASSERTE(fAllowRel32 != FALSE);
12501 fAllowRel32 = FALSE;
12504 #endif // _TARGET_AMD64_ && !CROSSGEN_COMPILE
12506 LOG((LF_JIT, LL_INFO10000,
12507 "Jitted Entry at" FMT_ADDR "method %s::%s %s\n", DBG_ADDR(nativeEntry),
12508 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
12510 #if defined(FEATURE_CORESYSTEM)
12513 LPCUTF8 pszDebugClassName = ftn->m_pszDebugClassName;
12514 LPCUTF8 pszDebugMethodName = ftn->m_pszDebugMethodName;
12515 LPCUTF8 pszDebugMethodSignature = ftn->m_pszDebugMethodSignature;
12517 LPCUTF8 pszNamespace;
12518 LPCUTF8 pszDebugClassName = ftn->GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace);
12519 LPCUTF8 pszDebugMethodName = ftn->GetName();
12520 LPCUTF8 pszDebugMethodSignature = "";
12523 //DbgPrintf("Jitted Entry at" FMT_ADDR "method %s::%s %s size %08x\n", DBG_ADDR(nativeEntry),
12524 // pszDebugClassName, pszDebugMethodName, pszDebugMethodSignature, sizeOfCode);
12527 ClrFlushInstructionCache(nativeEntry, sizeOfCode);
12528 ret = (PCODE)nativeEntry;
12530 #ifdef _TARGET_ARM_
12539 FastInterlockIncrement(&g_JitCount);
12540 static BOOL fHeartbeat = -1;
12542 if (fHeartbeat == -1)
12543 fHeartbeat = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitHeartbeat);
12549 COOPERATIVE_TRANSITION_END();
12553 extern "C" unsigned __stdcall PartialNGenStressPercentage()
12555 LIMITED_METHOD_CONTRACT;
12559 static ConfigDWORD partialNGenStress;
12560 DWORD partialNGenStressVal = partialNGenStress.val(CLRConfig::INTERNAL_partialNGenStress);
12561 _ASSERTE(partialNGenStressVal <= 100);
12562 return partialNGenStressVal;
12566 #ifdef FEATURE_PREJIT
12567 /*********************************************************************/
12570 // Table loading functions
12572 void Module::LoadHelperTable()
12574 STANDARD_VM_CONTRACT;
12576 #ifndef CROSSGEN_COMPILE
12578 BYTE * table = (BYTE *) GetNativeImage()->GetNativeHelperTable(&tableSize);
12580 if (tableSize == 0)
12583 EnsureWritableExecutablePages(table, tableSize);
12585 BYTE * curEntry = table;
12586 BYTE * tableEnd = table + tableSize;
12588 #ifdef FEATURE_PERFMAP
12589 PerfMap::LogStubs(__FUNCTION__, GetSimpleName(), (PCODE)table, tableSize);
12593 int iEntryNumber = 0;
12600 while (curEntry < tableEnd)
12602 DWORD dwHelper = *(DWORD *)curEntry;
12604 int iHelper = (USHORT)dwHelper;
12605 _ASSERTE(iHelper < CORINFO_HELP_COUNT);
12607 LOG((LF_JIT, LL_INFO1000000, "JIT helper %3d (%-40s: table @ %p, size 0x%x, entry %3d @ %p, pfnHelper %p)\n",
12608 iHelper, hlpFuncTable[iHelper].name, table, tableSize, iEntryNumber, curEntry, hlpFuncTable[iHelper].pfnHelper));
12610 #if defined(ENABLE_FAST_GCPOLL_HELPER)
12611 // The fast GC poll helper works by calling indirect through a pointer that points to either
12612 // JIT_PollGC or JIT_PollGC_Nop, based on whether we need to poll or not. The JIT_PollGC_Nop
12613 // version is just a "ret". The pointer is stored in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
12614 // See EnableJitGCPoll() and DisableJitGCPoll().
12615 // In NGEN images, we generate a direct call to the helper table. Here, we replace that with
12616 // an indirect jump through the pointer in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
12617 if (iHelper == CORINFO_HELP_POLL_GC)
12619 LOG((LF_JIT, LL_INFO1000000, "JIT helper CORINFO_HELP_POLL_GC (%d); emitting indirect jump to 0x%x\n",
12620 CORINFO_HELP_POLL_GC, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper));
12622 emitJumpInd(curEntry, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper);
12623 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
12626 #endif // ENABLE_FAST_GCPOLL_HELPER
12628 PCODE pfnHelper = CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)iHelper);
12630 if (dwHelper & CORCOMPILE_HELPER_PTR)
12633 // Indirection cell
12636 *(TADDR *)curEntry = pfnHelper;
12638 curEntry = curEntry + sizeof(TADDR);
12646 #if defined(_TARGET_AMD64_)
12647 *curEntry = X86_INSTR_JMP_REL32;
12648 *(INT32 *)(curEntry + 1) = rel32UsingJumpStub((INT32 *)(curEntry + 1), pfnHelper, NULL, GetLoaderAllocator());
12649 #else // all other platforms
12650 emitJump(curEntry, (LPVOID)pfnHelper);
12651 _ASSERTE(HELPER_TABLE_ENTRY_LEN >= JUMP_ALLOCATE_SIZE);
12654 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
12658 // Note that some table entries are sizeof(TADDR) in length, and some are HELPER_TABLE_ENTRY_LEN in length
12663 ClrFlushInstructionCache(table, tableSize);
12664 #endif // CROSSGEN_COMPILE
12667 #ifdef FEATURE_READYTORUN
12668 CorInfoHelpFunc MapReadyToRunHelper(ReadyToRunHelper helperNum)
12670 LIMITED_METHOD_CONTRACT;
12674 #define HELPER(readyToRunHelper, corInfoHelpFunc, flags) \
12675 case readyToRunHelper: return corInfoHelpFunc;
12676 #include "readytorunhelpers.h"
12678 case READYTORUN_HELPER_GetString: return CORINFO_HELP_STRCNS;
12680 default: return CORINFO_HELP_UNDEF;
12684 void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap)
12686 STANDARD_VM_CONTRACT;
12688 ZeroMemory(pGCRefMap, cbGCRefMap);
12690 if (!pMT->ContainsPointers())
12693 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
12694 CGCDescSeries* cur = map->GetHighestSeries();
12695 CGCDescSeries* last = map->GetLowestSeries();
12696 DWORD size = pMT->GetBaseSize();
12697 _ASSERTE(cur >= last);
12701 // offset to embedded references in this series must be
12702 // adjusted by the VTable pointer, when in the unboxed state.
12703 size_t offset = cur->GetSeriesOffset() - sizeof(void*);
12704 size_t offsetStop = offset + cur->GetSeriesSize() + size;
12705 while (offset < offsetStop)
12707 size_t bit = offset / sizeof(void *);
12709 size_t index = bit / 8;
12710 _ASSERTE(index < cbGCRefMap);
12711 pGCRefMap[index] |= (1 << (bit & 7));
12713 offset += sizeof(void *);
12716 } while (cur >= last);
12720 // Type layout check verifies that there was no incompatible change in the value type layout.
12721 // If there was one, we will fall back to JIT instead of using the pre-generated code from the ready to run image.
12722 // This should be rare situation. Changes in value type layout not common.
12724 // The following properties of the value type layout are checked:
12726 // - HFA-ness (on platform that support HFAs)
12728 // - Position of GC references
12730 BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob)
12732 STANDARD_VM_CONTRACT;
12734 SigPointer p(pBlob);
12735 IfFailThrow(p.SkipExactlyOne());
12738 IfFailThrow(p.GetData(&dwFlags));
12740 // Size is checked unconditionally
12741 DWORD dwExpectedSize;
12742 IfFailThrow(p.GetData(&dwExpectedSize));
12744 DWORD dwActualSize = pMT->GetNumInstanceFieldBytes();
12745 if (dwExpectedSize != dwActualSize)
12749 if (dwFlags & READYTORUN_LAYOUT_HFA)
12751 DWORD dwExpectedHFAType;
12752 IfFailThrow(p.GetData(&dwExpectedHFAType));
12754 DWORD dwActualHFAType = pMT->GetHFAType();
12755 if (dwExpectedHFAType != dwActualHFAType)
12764 _ASSERTE(!(dwFlags & READYTORUN_LAYOUT_HFA));
12767 if (dwFlags & READYTORUN_LAYOUT_Alignment)
12769 DWORD dwExpectedAlignment = sizeof(void *);
12770 if (!(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
12772 IfFailThrow(p.GetData(&dwExpectedAlignment));
12775 DWORD dwActualAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
12776 if (dwExpectedAlignment != dwActualAlignment)
12781 if (dwFlags & READYTORUN_LAYOUT_GCLayout)
12783 if (dwFlags & READYTORUN_LAYOUT_GCLayout_Empty)
12785 if (pMT->ContainsPointers())
12790 size_t cbGCRefMap = (dwActualSize / sizeof(TADDR) + 7) / 8;
12791 _ASSERTE(cbGCRefMap > 0);
12793 BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
12795 ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
12797 if (memcmp(pGCRefMap, p.GetPtr(), cbGCRefMap) != 0)
12805 #endif // FEATURE_READYTORUN
12807 BOOL LoadDynamicInfoEntry(Module *currentModule,
12811 STANDARD_VM_CONTRACT;
12813 PCCOR_SIGNATURE pBlob = currentModule->GetNativeFixupBlobData(fixupRva);
12815 BYTE kind = *pBlob++;
12817 Module * pInfoModule = currentModule;
12819 if (kind & ENCODE_MODULE_OVERRIDE)
12821 pInfoModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
12822 kind &= ~ENCODE_MODULE_OVERRIDE;
12825 MethodDesc * pMD = NULL;
12827 PCCOR_SIGNATURE pSig;
12836 case ENCODE_MODULE_HANDLE:
12837 result = (size_t)pInfoModule;
12840 case ENCODE_TYPE_HANDLE:
12841 case ENCODE_TYPE_DICTIONARY:
12843 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
12845 if (!th.IsTypeDesc())
12847 if (currentModule->IsReadyToRun())
12849 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12850 th.AsMethodTable()->EnsureInstanceActive();
12854 #ifdef FEATURE_WINMD_RESILIENT
12855 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12856 th.AsMethodTable()->EnsureInstanceActive();
12861 result = (size_t)th.AsPtr();
12865 case ENCODE_METHOD_HANDLE:
12866 case ENCODE_METHOD_DICTIONARY:
12868 MethodDesc * pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
12870 if (currentModule->IsReadyToRun())
12872 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12873 pMD->EnsureActive();
12876 result = (size_t)pMD;
12880 case ENCODE_FIELD_HANDLE:
12881 result = (size_t) ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
12884 #ifndef CROSSGEN_COMPILE
12885 case ENCODE_STRING_HANDLE:
12887 // We need to update strings atomically (due to NoStringInterning attribute). Note
12888 // that modules with string interning dont really need this, as the hash tables have
12889 // their own locking, but dont add more complexity for what will be the non common
12892 // We will have to lock and update the entry. (this is really a double check, where
12893 // the first check is done in the caller of this function)
12894 DWORD rid = CorSigUncompressData(pBlob);
12898 result = (size_t)StringObject::GetEmptyStringRefPtr();
12902 CrstHolder ch(pInfoModule->GetFixupCrst());
12904 if (!CORCOMPILE_IS_POINTER_TAGGED(*entry) && (*entry != NULL))
12906 // We lost the race, just return
12910 // For generic instantiations compiled into the ngen image of some other
12911 // client assembly, we need to ensure that we intern the string
12912 // in the defining assembly.
12913 bool mayNeedToSyncWithFixups = pInfoModule != currentModule;
12915 result = (size_t) pInfoModule->ResolveStringRef(TokenFromRid(rid, mdtString), currentModule->GetDomain(), mayNeedToSyncWithFixups);
12920 case ENCODE_VARARGS_SIG:
12922 mdSignature token = TokenFromRid(
12923 CorSigUncompressData(pBlob),
12926 IfFailThrow(pInfoModule->GetMDImport()->GetSigFromToken(token, &cSig, &pSig));
12932 case ENCODE_VARARGS_METHODREF:
12934 mdSignature token = TokenFromRid(
12935 CorSigUncompressData(pBlob),
12938 LPCSTR szName_Ignore;
12939 IfFailThrow(pInfoModule->GetMDImport()->GetNameAndSigOfMemberRef(token, &pSig, &cSig, &szName_Ignore));
12945 case ENCODE_VARARGS_METHODDEF:
12947 token = TokenFromRid(
12948 CorSigUncompressData(pBlob),
12951 IfFailThrow(pInfoModule->GetMDImport()->GetSigOfMethodDef(token, &cSig, &pSig));
12954 result = (size_t) CORINFO_VARARGS_HANDLE(currentModule->GetVASigCookie(Signature(pSig, cSig)));
12958 // ENCODE_METHOD_NATIVECALLABLE_HANDLE is same as ENCODE_METHOD_ENTRY_DEF_TOKEN
12959 // except for AddrOfCode
12960 case ENCODE_METHOD_NATIVE_ENTRY:
12961 case ENCODE_METHOD_ENTRY_DEF_TOKEN:
12963 mdToken MethodDef = TokenFromRid(CorSigUncompressData(pBlob), mdtMethodDef);
12964 pMD = MemberLoader::GetMethodDescFromMethodDef(pInfoModule, MethodDef, FALSE);
12966 pMD->PrepareForUseAsADependencyOfANativeImage();
12968 if (currentModule->IsReadyToRun())
12970 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12971 pMD->EnsureActive();
12977 case ENCODE_METHOD_ENTRY_REF_TOKEN:
12979 SigTypeContext typeContext;
12980 mdToken MemberRef = TokenFromRid(CorSigUncompressData(pBlob), mdtMemberRef);
12981 FieldDesc * pFD = NULL;
12984 MemberLoader::GetDescFromMemberRef(pInfoModule, MemberRef, &pMD, &pFD, &typeContext, FALSE /* strict metadata checks */, &th);
12985 _ASSERTE(pMD != NULL);
12987 pMD->PrepareForUseAsADependencyOfANativeImage();
12989 if (currentModule->IsReadyToRun())
12991 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12992 pMD->EnsureActive();
12996 #ifdef FEATURE_WINMD_RESILIENT
12997 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
12998 pMD->EnsureActive();
13005 case ENCODE_METHOD_ENTRY:
13007 pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13009 if (currentModule->IsReadyToRun())
13011 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13012 pMD->EnsureActive();
13016 if (kind == ENCODE_METHOD_NATIVE_ENTRY)
13018 result = COMDelegate::ConvertToCallback(pMD);
13022 result = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY);
13025 #ifndef _TARGET_ARM_
13026 if (CORCOMPILE_IS_PCODE_TAGGED(result))
13028 // There is a rare case where the function entrypoint may not be aligned. This could happen only for FCalls,
13029 // only on x86 and only if we failed to hardbind the fcall (e.g. ngen image for mscorlib.dll does not exist
13030 // and /nodependencies flag for ngen was used). The function entrypoints should be aligned in all other cases.
13032 // We will wrap the unaligned method entrypoint by funcptr stub with aligned entrypoint.
13033 _ASSERTE(pMD->IsFCall());
13034 result = pMD->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pMD);
13040 case ENCODE_SYNC_LOCK:
13042 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13044 result = (size_t) GetClassSync(th.AsMethodTable());
13048 case ENCODE_INDIRECT_PINVOKE_TARGET:
13050 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13052 _ASSERTE(pMethod->IsNDirect());
13053 NDirectMethodDesc *pMD = (NDirectMethodDesc*)pMethod;
13054 result = (size_t)(LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
13058 #if defined(PROFILING_SUPPORTED)
13059 case ENCODE_PROFILING_HANDLE:
13061 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13063 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
13064 // they shouldnever come here as they are called out in GetCompileFlag
13065 _ASSERTE(!pMethod->IsNoMetadata());
13067 FunctionID funId = (FunctionID)pMethod;
13069 BOOL bHookFunction = TRUE;
13070 CORINFO_PROFILING_HANDLE profilerHandle = (CORINFO_PROFILING_HANDLE)funId;
13073 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
13074 profilerHandle = (CORINFO_PROFILING_HANDLE) g_profControlBlock.pProfInterface->EEFunctionIDMapper(funId, &bHookFunction);
13075 END_PIN_PROFILER();
13078 // Profiling handle is opaque token. It does not have to be aligned thus we can not store it in the same location as token.
13079 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexClientData) = (SIZE_T)profilerHandle;
13083 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER].pfnHelper;
13084 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE].pfnHelper;
13085 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL].pfnHelper;
13089 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13090 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13091 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13095 #endif // PROFILING_SUPPORTED
13097 case ENCODE_STATIC_FIELD_ADDRESS:
13099 FieldDesc *pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13101 pField->GetEnclosingMethodTable()->CheckRestore();
13103 // We can take address of RVA field only since ngened code is domain neutral
13104 _ASSERTE(pField->IsRVA());
13106 // Field address is not aligned thus we can not store it in the same location as token.
13107 *EnsureWritablePages(entry+1) = (size_t)pField->GetStaticAddressHandle(NULL);
13111 case ENCODE_VIRTUAL_ENTRY_SLOT:
13113 DWORD slot = CorSigUncompressData(pBlob);
13115 TypeHandle ownerType = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13117 LOG((LF_ZAP, LL_INFO100000, " Fixup stub dispatch\n"));
13119 VirtualCallStubManager * pMgr = currentModule->GetLoaderAllocator()->GetVirtualCallStubManager();
13122 // We should be generating a stub indirection here, but the zapper already uses one level
13123 // of indirection, i.e. we would have to return IAT_PPVALUE to the JIT, and on the whole the JITs
13124 // aren't quite set up to accept that. Furthermore the call sequences would be different - at
13125 // the moment an indirection cell uses "call [cell-addr]" on x86, and instead we would want the
13126 // euqivalent of "call [[call-addr]]". This could perhaps be implemented as "call [eax]" </REVISIT_TODO>
13127 result = pMgr->GetCallStub(ownerType, slot);
13131 case ENCODE_CLASS_ID_FOR_STATICS:
13133 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13135 MethodTable * pMT = th.AsMethodTable();
13136 if (pMT->IsDynamicStatics())
13138 result = pMT->GetModuleDynamicEntryID();
13142 result = pMT->GetClassIndex();
13147 case ENCODE_MODULE_ID_FOR_STATICS:
13149 result = pInfoModule->GetModuleID();
13153 case ENCODE_MODULE_ID_FOR_GENERIC_STATICS:
13155 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13157 MethodTable * pMT = th.AsMethodTable();
13159 result = pMT->GetModuleForStatics()->GetModuleID();
13163 case ENCODE_ACTIVE_DEPENDENCY:
13165 Module* pModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13167 STRESS_LOG3(LF_ZAP,LL_INFO10000,"Modules are: %08x,%08x,%08x",currentModule,pInfoModule,pModule);
13168 pInfoModule->AddActiveDependency(pModule, FALSE);
13172 #ifdef FEATURE_READYTORUN
13173 case ENCODE_READYTORUN_HELPER:
13175 DWORD helperNum = CorSigUncompressData(pBlob);
13177 CorInfoHelpFunc corInfoHelpFunc = MapReadyToRunHelper((ReadyToRunHelper)helperNum);
13178 if (corInfoHelpFunc != CORINFO_HELP_UNDEF)
13180 result = (size_t)CEEJitInfo::getHelperFtnStatic(corInfoHelpFunc);
13186 case READYTORUN_HELPER_Module:
13188 Module * pPrevious = InterlockedCompareExchangeT(EnsureWritablePages((Module **)entry), pInfoModule, NULL);
13189 if (pPrevious != pInfoModule && pPrevious != NULL)
13190 COMPlusThrowHR(COR_E_FILELOAD, IDS_NATIVE_IMAGE_CANNOT_BE_LOADED_MULTIPLE_TIMES, pInfoModule->GetPath());
13195 case READYTORUN_HELPER_GSCookie:
13196 result = (size_t)GetProcessGSCookie();
13199 case READYTORUN_HELPER_DelayLoad_MethodCall:
13200 result = (size_t)GetEEFuncEntryPoint(DelayLoad_MethodCall);
13203 case READYTORUN_HELPER_DelayLoad_Helper:
13204 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper);
13207 case READYTORUN_HELPER_DelayLoad_Helper_Obj:
13208 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_Obj);
13211 case READYTORUN_HELPER_DelayLoad_Helper_ObjObj:
13212 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_ObjObj);
13216 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown READYTORUN_HELPER %d\n", helperNum);
13217 _ASSERTE(!"Unknown READYTORUN_HELPER");
13224 case ENCODE_FIELD_OFFSET:
13226 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13227 _ASSERTE(!pFD->IsStatic());
13228 _ASSERTE(!pFD->IsFieldOfValueType());
13230 DWORD dwOffset = (DWORD)sizeof(Object) + pFD->GetOffset();
13232 if (dwOffset > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13238 case ENCODE_FIELD_BASE_OFFSET:
13240 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13242 MethodTable * pMT = th.AsMethodTable();
13243 _ASSERTE(!pMT->IsValueType());
13245 DWORD dwOffsetBase = ReadyToRunInfo::GetFieldBaseOffset(pMT);
13246 if (dwOffsetBase > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13248 result = dwOffsetBase;
13252 case ENCODE_CHECK_TYPE_LAYOUT:
13254 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13255 MethodTable * pMT = th.AsMethodTable();
13256 _ASSERTE(pMT->IsValueType());
13258 if (!TypeLayoutCheck(pMT, pBlob))
13265 case ENCODE_CHECK_FIELD_OFFSET:
13267 DWORD dwExpectedOffset = CorSigUncompressData(pBlob);
13269 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13270 _ASSERTE(!pFD->IsStatic());
13272 DWORD dwOffset = pFD->GetOffset();
13273 if (!pFD->IsFieldOfValueType())
13274 dwOffset += sizeof(Object);
13276 if (dwExpectedOffset != dwOffset)
13282 #endif // FEATURE_READYTORUN
13284 #endif // CROSSGEN_COMPILE
13287 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown FIXUP_BLOB_KIND %d\n", kind);
13288 _ASSERTE(!"Unknown FIXUP_BLOB_KIND");
13293 *EnsureWritablePages(entry) = result;
13297 #endif // FEATURE_PREJIT
13299 void* CEEInfo::getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig,
13300 CorInfoHelperTailCallSpecialHandling flags)
13311 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)
13313 JIT_TO_EE_TRANSITION();
13315 Stub* pStub = CPUSTUBLINKER::CreateTailCallCopyArgsThunk(pSig, flags);
13317 ftn = (void*)pStub->GetEntryPoint();
13319 EE_TO_JIT_TRANSITION();
13321 #endif // _TARGET_AMD64_ || _TARGET_ARM_
13326 void CEEInfo::allocMem (
13327 ULONG hotCodeSize, /* IN */
13328 ULONG coldCodeSize, /* IN */
13329 ULONG roDataSize, /* IN */
13330 ULONG xcptnsCount, /* IN */
13331 CorJitAllocMemFlag flag, /* IN */
13332 void ** hotCodeBlock, /* OUT */
13333 void ** coldCodeBlock, /* OUT */
13334 void ** roDataBlock /* OUT */
13337 LIMITED_METHOD_CONTRACT;
13338 UNREACHABLE(); // only called on derived class.
13341 void CEEInfo::reserveUnwindInfo (
13342 BOOL isFunclet, /* IN */
13343 BOOL isColdCode, /* IN */
13344 ULONG unwindSize /* IN */
13347 LIMITED_METHOD_CONTRACT;
13348 UNREACHABLE(); // only called on derived class.
13351 void CEEInfo::allocUnwindInfo (
13352 BYTE * pHotCode, /* IN */
13353 BYTE * pColdCode, /* IN */
13354 ULONG startOffset, /* IN */
13355 ULONG endOffset, /* IN */
13356 ULONG unwindSize, /* IN */
13357 BYTE * pUnwindBlock, /* IN */
13358 CorJitFuncKind funcKind /* IN */
13361 LIMITED_METHOD_CONTRACT;
13362 UNREACHABLE(); // only called on derived class.
13365 void * CEEInfo::allocGCInfo (
13366 size_t size /* IN */
13369 LIMITED_METHOD_CONTRACT;
13370 UNREACHABLE_RET(); // only called on derived class.
13373 void CEEInfo::setEHcount (
13374 unsigned cEH /* IN */
13377 LIMITED_METHOD_CONTRACT;
13378 UNREACHABLE(); // only called on derived class.
13381 void CEEInfo::setEHinfo (
13382 unsigned EHnumber, /* IN */
13383 const CORINFO_EH_CLAUSE *clause /* IN */
13386 LIMITED_METHOD_CONTRACT;
13387 UNREACHABLE(); // only called on derived class.
13390 InfoAccessType CEEInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
13394 LIMITED_METHOD_CONTRACT;
13395 UNREACHABLE(); // only called on derived class.
13398 InfoAccessType CEEInfo::emptyStringLiteral(void ** ppValue)
13400 LIMITED_METHOD_CONTRACT;
13401 _ASSERTE(isVerifyOnly());
13402 *ppValue = (void *)0x10;
13406 void* CEEInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
13407 void **ppIndirection)
13409 LIMITED_METHOD_CONTRACT;
13410 _ASSERTE(isVerifyOnly());
13411 if (ppIndirection != NULL)
13412 *ppIndirection = NULL;
13413 return (void *)0x10;
13416 void* CEEInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
13417 void **ppIndirection)
13419 LIMITED_METHOD_CONTRACT;
13420 UNREACHABLE(); // only called on derived class.
13423 HRESULT CEEInfo::allocBBProfileBuffer (
13424 ULONG count, // The number of basic blocks that we have
13425 ProfileBuffer ** profileBuffer
13428 LIMITED_METHOD_CONTRACT;
13429 UNREACHABLE_RET(); // only called on derived class.
13432 HRESULT CEEInfo::getBBProfileData(
13433 CORINFO_METHOD_HANDLE ftnHnd,
13434 ULONG * count, // The number of basic blocks that we have
13435 ProfileBuffer ** profileBuffer,
13439 LIMITED_METHOD_CONTRACT;
13440 UNREACHABLE_RET(); // only called on derived class.
13444 void CEEInfo::recordCallSite(
13445 ULONG instrOffset, /* IN */
13446 CORINFO_SIG_INFO * callSig, /* IN */
13447 CORINFO_METHOD_HANDLE methodHandle /* IN */
13450 LIMITED_METHOD_CONTRACT;
13451 UNREACHABLE(); // only called on derived class.
13454 void CEEInfo::recordRelocation(
13455 void * location, /* IN */
13456 void * target, /* IN */
13457 WORD fRelocType, /* IN */
13458 WORD slotNum, /* IN */
13459 INT32 addlDelta /* IN */
13462 LIMITED_METHOD_CONTRACT;
13463 UNREACHABLE(); // only called on derived class.
13466 WORD CEEInfo::getRelocTypeHint(void * target)
13468 LIMITED_METHOD_CONTRACT;
13469 UNREACHABLE_RET(); // only called on derived class.
13472 void CEEInfo::getModuleNativeEntryPointRange(
13473 void ** pStart, /* OUT */
13474 void ** pEnd /* OUT */
13477 LIMITED_METHOD_CONTRACT;
13478 UNREACHABLE(); // only called on derived class.
13481 DWORD CEEInfo::getExpectedTargetArchitecture()
13483 LIMITED_METHOD_CONTRACT;
13485 return IMAGE_FILE_MACHINE_NATIVE;
13488 void CEEInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
13489 ICorDebugInfo::OffsetMapping *pMap)
13491 LIMITED_METHOD_CONTRACT;
13492 UNREACHABLE(); // only called on derived class.
13495 void CEEInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
13497 LIMITED_METHOD_CONTRACT;
13498 UNREACHABLE(); // only called on derived class.
13501 void* CEEInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
13502 void ** ppIndirection) /* OUT */
13504 LIMITED_METHOD_CONTRACT;
13505 UNREACHABLE(); // only called on derived class.
13508 // Active dependency helpers
13509 void CEEInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
13511 LIMITED_METHOD_CONTRACT;
13512 UNREACHABLE(); // only called on derived class.
13515 void CEEInfo::GetProfilingHandle(BOOL *pbHookFunction,
13516 void **pProfilerHandle,
13517 BOOL *pbIndirectedHandles)
13519 LIMITED_METHOD_CONTRACT;
13520 UNREACHABLE(); // only called on derived class.
13523 #endif // !DACCESS_COMPILE
13525 EECodeInfo::EECodeInfo()
13527 WRAPPER_NO_CONTRACT;
13529 m_codeAddress = NULL;
13535 #ifdef WIN64EXCEPTIONS
13536 m_pFunctionEntry = NULL;
13540 void EECodeInfo::Init(PCODE codeAddress)
13548 Init(codeAddress, ExecutionManager::GetScanFlags());
13551 void EECodeInfo::Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag)
13559 m_codeAddress = codeAddress;
13561 RangeSection * pRS = ExecutionManager::FindCodeRange(codeAddress, scanFlag);
13565 if (!pRS->pjit->JitCodeToMethodInfo(pRS, codeAddress, &m_pMD, this))
13576 #ifdef WIN64EXCEPTIONS
13577 m_pFunctionEntry = NULL;
13581 TADDR EECodeInfo::GetSavedMethodCode()
13584 // All EECodeInfo methods must be NOTHROW/GC_NOTRIGGER since they can
13585 // be used during GC.
13592 #if defined(HAVE_GCCOVER)
13593 _ASSERTE (!m_pMD->m_GcCover || GCStress<cfg_instr>::IsEnabled());
13594 if (GCStress<cfg_instr>::IsEnabled()
13595 && m_pMD->m_GcCover)
13597 _ASSERTE(m_pMD->m_GcCover->savedCode);
13599 // Make sure we return the TADDR of savedCode here. The byte array is not marshaled automatically.
13600 // The caller is responsible for any necessary marshaling.
13601 return PTR_TO_MEMBER_TADDR(GCCoverageInfo, m_pMD->m_GcCover, savedCode);
13603 #endif //defined(HAVE_GCCOVER)
13606 return GetStartAddress();
13609 TADDR EECodeInfo::GetStartAddress()
13618 return m_pJM->JitTokenToStartAddress(m_methodToken);
13621 #if defined(WIN64EXCEPTIONS)
13623 // ----------------------------------------------------------------------------
13624 // EECodeInfo::GetMainFunctionInfo
13627 // Simple helper to transform a funclet's EECodeInfo into a parent function EECodeInfo.
13630 // An EECodeInfo for the start of the main function body (offset 0).
13633 EECodeInfo EECodeInfo::GetMainFunctionInfo()
13635 LIMITED_METHOD_CONTRACT;
13638 EECodeInfo result = *this;
13639 result.m_relOffset = 0;
13640 result.m_codeAddress = this->GetStartAddress();
13641 result.m_pFunctionEntry = NULL;
13646 PTR_RUNTIME_FUNCTION EECodeInfo::GetFunctionEntry()
13648 LIMITED_METHOD_CONTRACT;
13651 if (m_pFunctionEntry == NULL)
13652 m_pFunctionEntry = m_pJM->LazyGetFunctionEntry(this);
13653 return m_pFunctionEntry;
13656 #if defined(_TARGET_AMD64_)
13658 BOOL EECodeInfo::HasFrameRegister()
13660 LIMITED_METHOD_CONTRACT;
13662 PTR_RUNTIME_FUNCTION pFuncEntry = GetFunctionEntry();
13663 _ASSERTE(pFuncEntry != NULL);
13665 BOOL fHasFrameRegister = FALSE;
13666 PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(GetModuleBase() + pFuncEntry->UnwindData);
13667 if (pUnwindInfo->FrameRegister != 0)
13669 fHasFrameRegister = TRUE;
13670 _ASSERTE(pUnwindInfo->FrameRegister == kRBP);
13673 return fHasFrameRegister;
13675 #endif // defined(_TARGET_AMD64_)
13677 #endif // defined(WIN64EXCEPTIONS)
13680 #if defined(_TARGET_AMD64_)
13681 // ----------------------------------------------------------------------------
13682 // EECodeInfo::GetUnwindInfoHelper
13685 // Simple helper to return a pointer to the UNWIND_INFO given the offset to the unwind info.
13686 // On DAC builds, this function will read the memory from the target process and create a host copy.
13689 // * unwindInfoOffset - This is the offset to the unwind info, relative to the beginning of the code heap
13690 // for jitted code or to the module base for ngned code. this->GetModuleBase() will return the correct
13694 // Return a pointer to the UNWIND_INFO. On DAC builds, this function will create a host copy of the
13695 // UNWIND_INFO and return a host pointer. It will correctly read all of the memory for the variable-sized
13699 UNWIND_INFO * EECodeInfo::GetUnwindInfoHelper(ULONG unwindInfoOffset)
13701 #if defined(DACCESS_COMPILE)
13702 return DacGetUnwindInfo(static_cast<TADDR>(this->GetModuleBase() + unwindInfoOffset));
13703 #else // !DACCESS_COMPILE
13704 return reinterpret_cast<UNWIND_INFO *>(this->GetModuleBase() + unwindInfoOffset);
13705 #endif // !DACCESS_COMPILE
13708 // ----------------------------------------------------------------------------
13709 // EECodeInfo::GetFixedStackSize
13712 // Return the fixed stack size of a specified managed method. This function DOES NOT take current control
13713 // PC into account. So the fixed stack size returned by this function is not valid in the prolog or
13717 // Return the fixed stack size.
13720 // * For method with dynamic stack allocations, this function will return the fixed stack size on X64 (the
13721 // stack size immediately after the prolog), and it will return 0 on IA64. This difference is due to
13722 // the different unwind info encoding.
13725 ULONG EECodeInfo::GetFixedStackSize()
13727 WRAPPER_NO_CONTRACT;
13730 ULONG uFixedStackSize = 0;
13733 GetOffsetsFromUnwindInfo(&uFixedStackSize, &uDummy);
13735 return uFixedStackSize;
13739 // The information returned by this method is only valid if we are not in a prolog or an epilog.
13740 // Since this method is only used for the security stackwalk cache, this assumption is valid, since
13741 // we cannot make a call in a prolog or an epilog.
13743 // The next assumption is that only rbp is used as a frame register in jitted code. There is an
13744 // assert below to guard this assumption.
13745 void EECodeInfo::GetOffsetsFromUnwindInfo(ULONG* pRSPOffset, ULONG* pRBPOffset)
13747 LIMITED_METHOD_CONTRACT;
13750 _ASSERTE((pRSPOffset != NULL) && (pRBPOffset != NULL));
13752 // moduleBase is a target address.
13753 TADDR moduleBase = GetModuleBase();
13755 DWORD unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(GetFunctionEntry());
13757 if ((unwindInfo & RUNTIME_FUNCTION_INDIRECT) != 0)
13759 unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(PTR_RUNTIME_FUNCTION(moduleBase + (unwindInfo & ~RUNTIME_FUNCTION_INDIRECT)));
13762 UNWIND_INFO * pInfo = GetUnwindInfoHelper(unwindInfo);
13763 if (pInfo->Flags & UNW_FLAG_CHAININFO)
13765 _ASSERTE(!"GetRbpOffset() - chained unwind info used, violating assumptions of the security stackwalk cache");
13769 // Either we are not using a frame pointer, or we are using rbp as the frame pointer.
13770 if ( (pInfo->FrameRegister != 0) && (pInfo->FrameRegister != kRBP) )
13772 _ASSERTE(!"GetRbpOffset() - non-RBP frame pointer used, violating assumptions of the security stackwalk cache");
13776 // Walk the unwind info.
13777 ULONG StackOffset = 0;
13778 ULONG StackSize = 0;
13779 for (int i = 0; i < pInfo->CountOfUnwindCodes; i++)
13781 ULONG UnwindOp = pInfo->UnwindCode[i].UnwindOp;
13782 ULONG OpInfo = pInfo->UnwindCode[i].OpInfo;
13784 if (UnwindOp == UWOP_SAVE_NONVOL)
13786 if (OpInfo == kRBP)
13788 StackOffset = pInfo->UnwindCode[i+1].FrameOffset * 8;
13791 else if (UnwindOp == UWOP_SAVE_NONVOL_FAR)
13793 if (OpInfo == kRBP)
13795 StackOffset = pInfo->UnwindCode[i + 1].FrameOffset;
13796 StackOffset += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
13799 else if (UnwindOp == UWOP_ALLOC_SMALL)
13801 StackSize += (OpInfo * 8) + 8;
13803 else if (UnwindOp == UWOP_ALLOC_LARGE)
13805 ULONG IncrementalStackSize = pInfo->UnwindCode[i + 1].FrameOffset;
13808 IncrementalStackSize *= 8;
13812 IncrementalStackSize += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
13814 // This is a special opcode. We need to increment the index by 1 in addition to the normal adjustments.
13817 StackSize += IncrementalStackSize;
13819 else if (UnwindOp == UWOP_PUSH_NONVOL)
13821 // Because of constraints on epilogs, this unwind opcode is always last in the unwind code array.
13822 // This means that StackSize has been initialized already when we first see this unwind opcode.
13823 // Note that the intial value of StackSize does not include the stack space used for pushes.
13824 // Thus, here we only need to increment StackSize 8 bytes at a time until we see the unwind code for "push rbp".
13825 if (OpInfo == kRBP)
13827 StackOffset = StackSize;
13833 // Adjust the index into the unwind code array.
13834 i += UnwindOpExtraSlotTable[UnwindOp];
13837 *pRSPOffset = StackSize + 8; // add 8 for the return address
13838 *pRBPOffset = StackOffset;
13843 #if defined(_DEBUG) && defined(HAVE_GCCOVER)
13845 LPVOID EECodeInfo::findNextFunclet (LPVOID pvFuncletStart, SIZE_T cbCode, LPVOID *ppvFuncletEnd)
13854 PT_RUNTIME_FUNCTION pFunctionEntry;
13855 ULONGLONG uImageBase;
13857 EECodeInfo codeInfo;
13858 codeInfo.Init((PCODE)pvFuncletStart);
13859 pFunctionEntry = codeInfo.GetFunctionEntry();
13860 uImageBase = (ULONGLONG)codeInfo.GetModuleBase();
13861 #else // !FEATURE_PAL
13863 // This is GCStress debug only - use the slow OS APIs to enumerate funclets
13866 pFunctionEntry = (PT_RUNTIME_FUNCTION) RtlLookupFunctionEntry((ULONGLONG)pvFuncletStart,
13872 if (pFunctionEntry != NULL)
13874 #ifdef FEATURE_PREJIT
13875 // workaround: Check for indirect entry that is generated for cold part of main method body.
13876 if ((TADDR)pvFuncletStart < (TADDR)uImageBase + pFunctionEntry->BeginAddress ||
13877 (TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart)
13879 Module * pZapModule = ExecutionManager::FindZapModule((TADDR)pvFuncletStart);
13880 NGenLayoutInfo * pLayoutInfo = pZapModule->GetNGenLayoutInfo();
13882 int ColdFunctionIndex = NativeUnwindInfoLookupTable::LookupUnwindInfoForMethod((DWORD)((TADDR)pvFuncletStart - uImageBase),
13883 pLayoutInfo->m_pRuntimeFunctions[2],
13884 0, pLayoutInfo->m_nRuntimeFunctions[2] - 1);
13886 pFunctionEntry = pLayoutInfo->m_pRuntimeFunctions[2] + ColdFunctionIndex;
13890 _ASSERTE((TADDR)pvFuncletStart == (TADDR)uImageBase + pFunctionEntry->BeginAddress);
13891 _ASSERTE((TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart + cbCode);
13892 *ppvFuncletEnd = (LPVOID)(uImageBase + pFunctionEntry->EndAddress);
13893 return (LPVOID)(uImageBase + pFunctionEntry->BeginAddress);
13896 pvFuncletStart = (LPVOID)((TADDR)pvFuncletStart + 1);
13902 #endif // defined(_DEBUG) && !defined(HAVE_GCCOVER)
13903 #endif // defined(_TARGET_AMD64_)