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"
28 #include "dllimport.h"
29 #include "gcheaputilities.h"
30 #include "comdelegate.h"
31 #include "jitperf.h" // to track jit perf
33 #include "eeprofinterfaces.h"
34 #include "perfcounters.h"
35 #ifdef PROFILING_SUPPORTED
36 #include "proftoeeinterfaceimpl.h"
37 #include "eetoprofinterfaceimpl.h"
38 #include "eetoprofinterfaceimpl.inl"
39 #include "profilepriv.h"
44 #include "typestring.h"
45 #include "stackprobe.h"
47 #include "genericdict.h"
49 #include "debuginfostore.h"
52 #include "runtimehandles.h"
53 #include "sigbuilder.h"
57 #endif // HAVE_GCCOVER
59 #include "mdaassistants.h"
63 #include "corcompile.h"
64 #endif // FEATURE_PREJIT
67 #ifdef FEATURE_INTERPRETER
68 #include "interpreter.h"
69 #endif // FEATURE_INTERPRETER
71 // The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro
74 #define JIT_TO_EE_TRANSITION() MAKE_CURRENT_THREAD_AVAILABLE_EX(m_pThread); \
75 _ASSERTE(CURRENT_THREAD == GetThread()); \
76 INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE; \
77 COOPERATIVE_TRANSITION_BEGIN(); \
80 #define EE_TO_JIT_TRANSITION() STOP_NON_JIT_PERF(); \
81 COOPERATIVE_TRANSITION_END(); \
82 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE;
84 #define JIT_TO_EE_TRANSITION_LEAF()
85 #define EE_TO_JIT_TRANSITION_LEAF()
88 #if defined(CROSSGEN_COMPILE)
89 static const char *const hlpNameTable[CORINFO_HELP_COUNT] = {
90 #define JITHELPER(code, pfnHelper, sig) #code,
91 #include "jithelpers.h"
95 #ifdef DACCESS_COMPILE
97 // The real definitions are in jithelpers.cpp. However, those files are not included in the DAC build.
98 // Hence, we add them here.
99 GARY_IMPL(VMHELPDEF, hlpFuncTable, CORINFO_HELP_COUNT);
100 GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);
102 #else // DACCESS_COMPILE
104 /*********************************************************************/
106 #if defined(ENABLE_PERF_COUNTERS)
107 LARGE_INTEGER g_lastTimeInJitCompilation;
110 /*********************************************************************/
112 inline CORINFO_MODULE_HANDLE GetScopeHandle(MethodDesc* method)
114 LIMITED_METHOD_CONTRACT;
115 if (method->IsDynamicMethod())
117 return MakeDynamicScope(method->AsDynamicMethodDesc()->GetResolver());
121 return GetScopeHandle(method->GetModule());
125 //This is common refactored code from within several of the access check functions.
126 BOOL ModifyCheckForDynamicMethod(DynamicResolver *pResolver,
127 TypeHandle *pOwnerTypeForSecurity,
128 AccessCheckOptions::AccessCheckType *pAccessCheckType,
129 DynamicResolver** ppAccessContext)
133 PRECONDITION(CheckPointer(pResolver));
134 PRECONDITION(CheckPointer(pOwnerTypeForSecurity));
135 PRECONDITION(CheckPointer(pAccessCheckType));
136 PRECONDITION(CheckPointer(ppAccessContext));
137 PRECONDITION(*pAccessCheckType == AccessCheckOptions::kNormalAccessibilityChecks);
140 BOOL doAccessCheck = TRUE;
142 //Do not blindly initialize fields, since they've already got important values.
143 DynamicResolver::SecurityControlFlags dwSecurityFlags = DynamicResolver::Default;
145 TypeHandle dynamicOwner;
146 pResolver->GetJitContext(&dwSecurityFlags, &dynamicOwner);
147 if (!dynamicOwner.IsNull())
148 *pOwnerTypeForSecurity = dynamicOwner;
150 if (dwSecurityFlags & DynamicResolver::SkipVisibilityChecks)
152 doAccessCheck = FALSE;
154 else if (dwSecurityFlags & DynamicResolver::RestrictedSkipVisibilityChecks)
156 *pAccessCheckType = AccessCheckOptions::kRestrictedMemberAccessNoTransparency;
160 *pAccessCheckType = AccessCheckOptions::kNormalAccessNoTransparency;
163 return doAccessCheck;
166 /*****************************************************************************/
168 // Initialize from data we passed across to the JIT
169 inline static void GetTypeContext(const CORINFO_SIG_INST *info, SigTypeContext *pTypeContext)
171 LIMITED_METHOD_CONTRACT;
172 SigTypeContext::InitTypeContext(
173 Instantiation((TypeHandle *) info->classInst, info->classInstCount),
174 Instantiation((TypeHandle *) info->methInst, info->methInstCount),
178 static MethodDesc* GetMethodFromContext(CORINFO_CONTEXT_HANDLE context)
180 LIMITED_METHOD_CONTRACT;
181 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
187 return GetMethod((CORINFO_METHOD_HANDLE)((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
191 static TypeHandle GetTypeFromContext(CORINFO_CONTEXT_HANDLE context)
193 LIMITED_METHOD_CONTRACT;
194 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
196 return TypeHandle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
200 MethodTable * pMT = GetMethodFromContext(context)->GetMethodTable();
201 return TypeHandle(pMT);
205 // Initialize from a context parameter passed to the JIT and back. This is a parameter
206 // that indicates which method is being jitted.
208 inline static void GetTypeContext(CORINFO_CONTEXT_HANDLE context, SigTypeContext *pTypeContext)
216 PRECONDITION(context != NULL);
219 if (GetMethodFromContext(context))
221 SigTypeContext::InitTypeContext(GetMethodFromContext(context), pTypeContext);
225 SigTypeContext::InitTypeContext(GetTypeFromContext(context), pTypeContext);
229 static BOOL ContextIsShared(CORINFO_CONTEXT_HANDLE context)
231 LIMITED_METHOD_CONTRACT;
232 MethodDesc *pContextMD = GetMethodFromContext(context);
233 if (pContextMD != NULL)
235 return pContextMD->IsSharedByGenericInstantiations();
239 // Type handle contexts are non-shared and are used for inlining of
240 // non-generic methods in generic classes
245 // Returns true if context is providing any generic variables
246 static BOOL ContextIsInstantiated(CORINFO_CONTEXT_HANDLE context)
248 LIMITED_METHOD_CONTRACT;
249 if (GetMethodFromContext(context))
251 return GetMethodFromContext(context)->HasClassOrMethodInstantiation();
255 return GetTypeFromContext(context).HasInstantiation();
259 /*********************************************************************/
260 // This normalizes EE type information into the form expected by the JIT.
262 // If typeHnd contains exact type information, then *clsRet will contain
263 // the normalized CORINFO_CLASS_HANDLE information on return.
266 CorInfoType CEEInfo::asCorInfoType(CorElementType eeType,
267 TypeHandle typeHnd, /* optional in */
268 CORINFO_CLASS_HANDLE *clsRet/* optional out */ ) {
269 CONTRACT(CorInfoType) {
272 PRECONDITION((CorTypeInfo::IsGenericVariable(eeType)) ==
273 (!typeHnd.IsNull() && typeHnd.IsGenericVariable()));
274 PRECONDITION(eeType != ELEMENT_TYPE_GENERICINST);
277 TypeHandle typeHndUpdated = typeHnd;
279 if (!typeHnd.IsNull())
281 CorElementType normType = typeHnd.GetInternalCorElementType();
282 // If we have a type handle, then it has the better type
284 if (eeType == ELEMENT_TYPE_VALUETYPE && !CorTypeInfo::IsObjRef(normType))
287 // Zap the typeHnd when the type _really_ is a primitive
288 // as far as verification is concerned. Returning a null class
289 // handle means it is is a primitive.
291 // Enums are exactly like primitives, even from a verification standpoint,
292 // so we zap the type handle in this case.
294 // However RuntimeTypeHandle etc. are reported as E_T_INT (or something like that)
295 // but don't count as primitives as far as verification is concerned...
297 // To make things stranger, TypedReference returns true for "IsTruePrimitive".
298 // However the JIT likes us to report the type handle in that case.
299 if (!typeHnd.IsTypeDesc() && (
300 (typeHnd.AsMethodTable()->IsTruePrimitive() && typeHnd != TypeHandle(g_TypedReferenceMT))
301 || typeHnd.AsMethodTable()->IsEnum()) )
303 typeHndUpdated = TypeHandle();
308 static const BYTE map[] = {
324 CORINFO_TYPE_PTR, // PTR
326 CORINFO_TYPE_VALUECLASS,
328 CORINFO_TYPE_VAR, // VAR (type variable)
329 CORINFO_TYPE_CLASS, // ARRAY
330 CORINFO_TYPE_CLASS, // WITH
332 CORINFO_TYPE_UNDEF, // VALUEARRAY_UNSUPPORTED
333 CORINFO_TYPE_NATIVEINT, // I
334 CORINFO_TYPE_NATIVEUINT, // U
335 CORINFO_TYPE_UNDEF, // R_UNSUPPORTED
337 // put the correct type when we know our implementation
338 CORINFO_TYPE_PTR, // FNPTR
339 CORINFO_TYPE_CLASS, // OBJECT
340 CORINFO_TYPE_CLASS, // SZARRAY
341 CORINFO_TYPE_VAR, // MVAR
343 CORINFO_TYPE_UNDEF, // CMOD_REQD
344 CORINFO_TYPE_UNDEF, // CMOD_OPT
345 CORINFO_TYPE_UNDEF, // INTERNAL
348 _ASSERTE(sizeof(map) == ELEMENT_TYPE_MAX);
349 _ASSERTE(eeType < (CorElementType) sizeof(map));
350 // spot check of the map
351 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_I4] == CORINFO_TYPE_INT);
352 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_PTR] == CORINFO_TYPE_PTR);
353 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_TYPEDBYREF] == CORINFO_TYPE_REFANY);
355 CorInfoType res = ((unsigned)eeType < ELEMENT_TYPE_MAX) ? ((CorInfoType) map[(unsigned)eeType]) : CORINFO_TYPE_UNDEF;
358 *clsRet = CORINFO_CLASS_HANDLE(typeHndUpdated.AsPtr());
364 inline static CorInfoType toJitType(TypeHandle typeHnd, CORINFO_CLASS_HANDLE *clsRet = NULL)
367 return CEEInfo::asCorInfoType(typeHnd.GetInternalCorElementType(), typeHnd, clsRet);
371 void DebugSecurityCalloutStress(CORINFO_METHOD_HANDLE methodBeingCompiledHnd,
372 CorInfoIsAccessAllowedResult& currentAnswer,
373 CorInfoSecurityRuntimeChecks& currentRuntimeChecks)
376 if (currentAnswer != CORINFO_ACCESS_ALLOWED)
380 static ConfigDWORD AlwaysInsertCallout;
381 switch (AlwaysInsertCallout.val(CLRConfig::INTERNAL_Security_AlwaysInsertCallout))
387 default: //2 (or anything else), do so half the time
388 if (((size_t(methodBeingCompiledHnd) / sizeof(void*)) % 64) < 32)
392 currentAnswer = CORINFO_ACCESS_RUNTIME_CHECK;
393 currentRuntimeChecks = CORINFO_ACCESS_SECURITY_NONE;
396 #define DebugSecurityCalloutStress(a, b, c) do {} while(0)
399 void CheckForEquivalenceAndLoadTypeBeforeCodeIsRun(Module *pModule, mdToken token, Module *pDefModule, mdToken defToken, const SigParser *ptr, SigTypeContext *pTypeContext, void *pData)
409 if (IsTypeDefEquivalent(defToken, pDefModule))
411 SigPointer sigPtr(*ptr);
412 TypeHandle th = sigPtr.GetTypeHandleThrowing(pModule, pTypeContext);
413 ((ICorDynamicInfo *)pData)->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(th.AsPtr()));
417 inline static void TypeEquivalenceFixupSpecificationHelper(ICorDynamicInfo * pCorInfo, MethodDesc *pMD)
419 STANDARD_VM_CONTRACT;
421 // A fixup is necessary to ensure that the parameters to the method are loaded before the method
422 // is called. In these cases we will not perform the appropriate loading when we load parameter
423 // types because with type equivalence, the parameter types at the call site do not necessarily
424 // match that those in the actual function. (They must be equivalent, but not necessarily the same.)
425 // In non-ngen scenarios this code here will force the types to be loaded directly by the call to
426 // HasTypeEquivalentStructParameters.
427 if (!pMD->IsVirtual())
429 if (pMD->HasTypeEquivalentStructParameters())
431 if (IsCompilationProcess())
432 pMD->WalkValueTypeParameters(pMD->GetMethodTable(), CheckForEquivalenceAndLoadTypeBeforeCodeIsRun, pCorInfo);
437 if (pMD->GetMethodTable()->DependsOnEquivalentOrForwardedStructs())
439 if (pMD->HasTypeEquivalentStructParameters())
440 pCorInfo->classMustBeLoadedBeforeCodeIsRun((CORINFO_CLASS_HANDLE)pMD->GetMethodTable());
445 //---------------------------------------------------------------------------------------
448 // The method handle is used to instantiate method and class type parameters
449 // It's also used to determine whether an extra dictionary parameter is required
451 // sig - Input metadata signature
452 // scopeHnd - The signature is to be interpreted in the context of this scope (module)
453 // token - Metadata token used to refer to the signature (may be mdTokenNil for dynamic methods)
454 // sigRet - Resulting output signature in a format that is understood by native compilers
455 // pContextMD - The method with any instantiation information (may be NULL)
456 // localSig - Is it a local variables declaration, or a method signature (with return type, etc).
457 // contextType - The type with any instantiaton information
461 CEEInfo::ConvToJitSig(
462 PCCOR_SIGNATURE pSig,
464 CORINFO_MODULE_HANDLE scopeHnd,
466 CORINFO_SIG_INFO * sigRet,
467 MethodDesc * pContextMD,
469 TypeHandle contextType)
476 SigTypeContext typeContext;
480 SigTypeContext::InitTypeContext(pContextMD, contextType, &typeContext);
484 SigTypeContext::InitTypeContext(contextType, &typeContext);
487 _ASSERTE(CORINFO_CALLCONV_DEFAULT == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_DEFAULT);
488 _ASSERTE(CORINFO_CALLCONV_VARARG == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_VARARG);
489 _ASSERTE(CORINFO_CALLCONV_MASK == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_MASK);
490 _ASSERTE(CORINFO_CALLCONV_HASTHIS == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_HASTHIS);
492 TypeHandle typeHnd = TypeHandle();
495 sigRet->cbSig = cbSig;
496 sigRet->retTypeClass = 0;
497 sigRet->retTypeSigClass = 0;
498 sigRet->scope = scopeHnd;
499 sigRet->token = token;
500 sigRet->sigInst.classInst = (CORINFO_CLASS_HANDLE *) typeContext.m_classInst.GetRawArgs();
501 sigRet->sigInst.classInstCount = (unsigned) typeContext.m_classInst.GetNumArgs();
502 sigRet->sigInst.methInst = (CORINFO_CLASS_HANDLE *) typeContext.m_methodInst.GetRawArgs();
503 sigRet->sigInst.methInstCount = (unsigned) typeContext.m_methodInst.GetNumArgs();
505 SigPointer sig(pSig, cbSig);
509 // This is a method signature which includes calling convention, return type,
512 _ASSERTE(!sig.IsNull());
513 Module * module = GetModule(scopeHnd);
517 IfFailThrow(sig.GetCallingConvInfo(&data));
518 sigRet->callConv = (CorInfoCallConv) data;
520 if ((isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_VARARG)) ||
521 (isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_NATIVEVARARG)))
523 // This signature corresponds to a method that uses varargs, which are not supported.
524 COMPlusThrow(kInvalidProgramException, IDS_EE_VARARG_NOT_SUPPORTED);
527 // Skip number of type arguments
528 if (sigRet->callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
529 IfFailThrow(sig.GetData(NULL));
532 IfFailThrow(sig.GetData(&numArgs));
533 if (numArgs != (unsigned short) numArgs)
534 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
536 sigRet->numArgs = (unsigned short) numArgs;
538 CorElementType type = sig.PeekElemTypeClosed(module, &typeContext);
540 if (!CorTypeInfo::IsPrimitiveType(type))
542 typeHnd = sig.GetTypeHandleThrowing(module, &typeContext);
543 _ASSERTE(!typeHnd.IsNull());
545 // I believe it doesn't make any diff. if this is
546 // GetInternalCorElementType or GetSignatureCorElementType
547 type = typeHnd.GetSignatureCorElementType();
550 sigRet->retType = CEEInfo::asCorInfoType(type, typeHnd, &sigRet->retTypeClass);
551 sigRet->retTypeSigClass = CORINFO_CLASS_HANDLE(typeHnd.AsPtr());
553 IfFailThrow(sig.SkipExactlyOne()); // must to a skip so we skip any class tokens associated with the return type
554 _ASSERTE(sigRet->retType < CORINFO_TYPE_COUNT);
556 sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
560 // This is local variables declaration
562 sigRet->callConv = CORINFO_CALLCONV_DEFAULT;
563 sigRet->retType = CORINFO_TYPE_VOID;
564 sigRet->flags = CORINFO_SIGFLAG_IS_LOCAL_SIG;
569 IfFailThrow(sig.GetCallingConvInfo(&callConv));
570 if (callConv != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG)
572 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_CALLCONV_NOT_LOCAL_SIG);
576 IfFailThrow(sig.GetData(&numArgs));
578 if (numArgs != (unsigned short) numArgs)
579 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
581 sigRet->numArgs = (unsigned short) numArgs;
584 sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
587 _ASSERTE(SigInfoFlagsAreValid(sigRet));
588 } // CEEInfo::ConvToJitSig
590 //---------------------------------------------------------------------------------------
592 CORINFO_CLASS_HANDLE CEEInfo::getTokenTypeAsHandle (CORINFO_RESOLVED_TOKEN * pResolvedToken)
601 CORINFO_CLASS_HANDLE tokenType = NULL;
603 JIT_TO_EE_TRANSITION();
605 _ASSERTE((pResolvedToken->hMethod == NULL) || (pResolvedToken->hField == NULL));
607 BinderClassID classID = CLASS__TYPE_HANDLE;
609 if (pResolvedToken->hMethod != NULL)
611 classID = CLASS__METHOD_HANDLE;
614 if (pResolvedToken->hField != NULL)
616 classID = CLASS__FIELD_HANDLE;
619 tokenType = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(classID));
621 EE_TO_JIT_TRANSITION();
626 /*********************************************************************/
627 size_t CEEInfo::findNameOfToken (
628 CORINFO_MODULE_HANDLE scopeHnd,
630 __out_ecount (FQNameCapacity) char * szFQName,
631 size_t FQNameCapacity)
642 JIT_TO_EE_TRANSITION();
644 if (IsDynamicScope(scopeHnd))
646 strncpy_s (szFQName, FQNameCapacity, "DynamicToken", FQNameCapacity - 1);
647 NameLen = strlen (szFQName);
651 Module* module = (Module *)scopeHnd;
652 NameLen = findNameOfToken(module, metaTOK, szFQName, FQNameCapacity);
655 EE_TO_JIT_TRANSITION();
660 CorInfoCanSkipVerificationResult CEEInfo::canSkipMethodVerification(CORINFO_METHOD_HANDLE ftnHnd)
669 return CORINFO_VERIFICATION_CAN_SKIP;
672 /*********************************************************************/
673 BOOL CEEInfo::shouldEnforceCallvirtRestriction(
674 CORINFO_MODULE_HANDLE scopeHnd)
676 LIMITED_METHOD_CONTRACT;
678 // verification rule added in whidbey requiring virtual methods
679 // to be called via callvirt except if certain other rules are
682 if (g_pConfig->LegacyVirtualMethodCallVerification())
689 #ifdef FEATURE_READYTORUN_COMPILER
691 // Returns true if assemblies are in the same version bubble
692 // Right now each assembly is in its own version bubble.
693 // If the need arises (i.e. performance issues) we will define sets of assemblies (e.g. all app assemblies)
694 // The main point is that all this logic is concentrated in one place.
696 // NOTICE: If you change this logic to allow multi-assembly version bubbles you
697 // need to consider the impact on diagnostic tools. Currently there is an inlining
698 // table which tracks inliner/inlinee relationships in R2R images but it is not
699 // yet capable of encoding cross-assembly inlines. The scenario where this
700 // may show are instrumenting profilers that want to instrument a given method A
701 // using the ReJit APIs. If method A happens to inlined within method B in another
702 // assembly then the profiler needs to know that so it can rejit B too.
703 // The recommended approach is to upgrade the inlining table (vm\inlinetracking.h\.cpp)
704 // now that presumably R2R images have some way to refer to methods in other
705 // assemblies in their version bubble. Chat with the diagnostics team if you need more
708 // There already is a case where cross-assembly inlining occurs in an
709 // unreported fashion for methods marked NonVersionable. There is a specific
710 // exemption called out for this on ICorProfilerInfo6::EnumNgenModuleMethodsInliningThisMethod
711 // and the impact of the cut was vetted with partners. It would not be appropriate
712 // to increase that unreported set without additional review.
715 bool IsInSameVersionBubble(Assembly * current, Assembly * target)
717 LIMITED_METHOD_CONTRACT;
719 // trivial case: current and target are identical
720 // DO NOT change this without reading the notice above
721 if (current == target)
727 // Returns true if the assemblies defining current and target are in the same version bubble
728 static bool IsInSameVersionBubble(MethodDesc* pCurMD, MethodDesc *pTargetMD)
730 LIMITED_METHOD_CONTRACT;
731 // DO NOT change this without reading the notice above
732 if (IsInSameVersionBubble(pCurMD->GetModule()->GetAssembly(),
733 pTargetMD->GetModule()->GetAssembly()))
737 if (IsReadyToRunCompilation())
739 if (pTargetMD->GetModule()->GetMDImport()->GetCustomAttributeByName(pTargetMD->GetMemberDef(),
740 NONVERSIONABLE_TYPE, NULL, NULL) == S_OK)
749 #endif // FEATURE_READYTORUN_COMPILER
752 /*********************************************************************/
753 CorInfoCanSkipVerificationResult CEEInfo::canSkipVerification(
754 CORINFO_MODULE_HANDLE moduleHnd)
763 return CORINFO_VERIFICATION_CAN_SKIP;
766 /*********************************************************************/
767 // Checks if the given metadata token is valid
768 BOOL CEEInfo::isValidToken (
769 CORINFO_MODULE_HANDLE module,
781 JIT_TO_EE_TRANSITION_LEAF();
783 if (IsDynamicScope(module))
785 // No explicit token validation for dynamic code. Validation is
786 // side-effect of token resolution.
791 result = ((Module *)module)->GetMDImport()->IsValidToken(metaTOK);
794 EE_TO_JIT_TRANSITION_LEAF();
799 /*********************************************************************/
800 // Checks if the given metadata token is valid StringRef
801 BOOL CEEInfo::isValidStringRef (
802 CORINFO_MODULE_HANDLE module,
814 JIT_TO_EE_TRANSITION();
816 if (IsDynamicScope(module))
818 result = GetDynamicResolver(module)->IsValidStringRef(metaTOK);
822 result = ((Module *)module)->CheckStringRef(metaTOK);
827 result = (!FAILED(((Module *)module)->GetMDImport()->GetUserString(metaTOK, &dwCharCount, NULL, &pString)) &&
832 EE_TO_JIT_TRANSITION();
838 size_t CEEInfo::findNameOfToken (Module* module,
840 __out_ecount (FQNameCapacity) char * szFQName,
841 size_t FQNameCapacity)
849 PCCOR_SIGNATURE sig = NULL;
851 LPCUTF8 pszNamespace = NULL;
852 LPCUTF8 pszClassName = NULL;
854 mdToken tokType = TypeFromToken(metaTOK);
859 if (FAILED(module->GetMDImport()->GetNameOfTypeRef(metaTOK, &pszNamespace, &pszClassName)))
861 pszNamespace = pszClassName = "Invalid TypeRef record";
863 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
868 if (FAILED(module->GetMDImport()->GetNameOfTypeDef(metaTOK, &pszClassName, &pszNamespace)))
870 pszClassName = pszNamespace = "Invalid TypeDef record";
872 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
878 if (FAILED(module->GetMDImport()->GetNameOfFieldDef(metaTOK, &szFieldName)))
880 szFieldName = "Invalid FieldDef record";
882 strncpy_s(szFQName, FQNameCapacity, (char*)szFieldName, FQNameCapacity - 1);
888 if (FAILED(module->GetMDImport()->GetNameOfMethodDef(metaTOK, &szMethodName)))
890 szMethodName = "Invalid MethodDef record";
892 strncpy_s(szFQName, FQNameCapacity, (char*)szMethodName, FQNameCapacity - 1);
898 if (FAILED(module->GetMDImport()->GetNameAndSigOfMemberRef((mdMemberRef)metaTOK, &sig, &cSig, &szName)))
900 szName = "Invalid MemberRef record";
902 strncpy_s(szFQName, FQNameCapacity, (char *)szName, FQNameCapacity - 1);
906 sprintf_s(szFQName, FQNameCapacity, "!TK_%x", metaTOK);
911 strncpy_s (szFQName, FQNameCapacity, "<UNKNOWN>", FQNameCapacity - 1);
915 return strlen (szFQName);
918 CorInfoHelpFunc CEEInfo::getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle)
927 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
929 JIT_TO_EE_TRANSITION_LEAF();
931 result = IsDynamicScope(handle) ? CORINFO_HELP_UNDEF : CORINFO_HELP_STRCNS;
933 EE_TO_JIT_TRANSITION_LEAF();
939 CHECK CheckContext(CORINFO_MODULE_HANDLE scopeHnd, CORINFO_CONTEXT_HANDLE context)
941 CHECK_MSG(scopeHnd != NULL, "Illegal null scope");
942 CHECK_MSG(((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK) != NULL, "Illegal null context");
943 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
945 TypeHandle handle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
946 CHECK_MSG(handle.GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
950 MethodDesc* handle = (MethodDesc*) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK);
951 CHECK_MSG(handle->GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
958 static DECLSPEC_NORETURN void ThrowBadTokenException(CORINFO_RESOLVED_TOKEN * pResolvedToken)
960 switch (pResolvedToken->tokenType & CORINFO_TOKENKIND_Mask)
962 case CORINFO_TOKENKIND_Class:
963 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_CLASS_TOKEN);
964 case CORINFO_TOKENKIND_Method:
965 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN);
966 case CORINFO_TOKENKIND_Field:
967 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN);
969 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
973 /*********************************************************************/
974 void CEEInfo::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken)
983 JIT_TO_EE_TRANSITION();
985 _ASSERTE(CheckContext(pResolvedToken->tokenScope, pResolvedToken->tokenContext));
987 pResolvedToken->pTypeSpec = NULL;
988 pResolvedToken->cbTypeSpec = NULL;
989 pResolvedToken->pMethodSpec = NULL;
990 pResolvedToken->cbMethodSpec = NULL;
993 MethodDesc * pMD = NULL;
994 FieldDesc * pFD = NULL;
996 CorInfoTokenKind tokenType = pResolvedToken->tokenType;
998 if (IsDynamicScope(pResolvedToken->tokenScope))
1000 GetDynamicResolver(pResolvedToken->tokenScope)->ResolveToken(pResolvedToken->token, &th, &pMD, &pFD);
1003 // Check that we got the expected handles and fill in missing data if necessary
1006 CorTokenType tkType = (CorTokenType)TypeFromToken(pResolvedToken->token);
1010 if ((tkType != mdtMethodDef) && (tkType != mdtMemberRef))
1011 ThrowBadTokenException(pResolvedToken);
1012 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1013 ThrowBadTokenException(pResolvedToken);
1015 th = pMD->GetMethodTable();
1017 // "PermitUninstDefOrRef" check
1018 if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && pMD->ContainsGenericVariables())
1020 COMPlusThrow(kInvalidProgramException);
1023 // if this is a BoxedEntryPointStub get the UnboxedEntryPoint one
1024 if (pMD->IsUnboxingStub())
1026 pMD = pMD->GetMethodTable()->GetUnboxedEntryPointMD(pMD);
1029 // Activate target if required
1030 if (tokenType != CORINFO_TOKENKIND_Ldtoken)
1032 ScanTokenForDynamicScope(pResolvedToken, th, pMD);
1038 if ((tkType != mdtFieldDef) && (tkType != mdtMemberRef))
1039 ThrowBadTokenException(pResolvedToken);
1040 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1041 ThrowBadTokenException(pResolvedToken);
1043 th = pFD->GetApproxEnclosingMethodTable();
1045 if (pFD->IsStatic() && (tokenType != CORINFO_TOKENKIND_Ldtoken))
1047 ScanTokenForDynamicScope(pResolvedToken, th);
1052 if ((tkType != mdtTypeDef) && (tkType != mdtTypeRef))
1053 ThrowBadTokenException(pResolvedToken);
1054 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1055 ThrowBadTokenException(pResolvedToken);
1057 ThrowBadTokenException(pResolvedToken);
1059 if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained)
1061 ScanTokenForDynamicScope(pResolvedToken, th);
1065 _ASSERTE((pMD == NULL) || (pFD == NULL));
1066 _ASSERTE(!th.IsNull());
1068 // "PermitUninstDefOrRef" check
1069 if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && th.ContainsGenericVariables())
1071 COMPlusThrow(kInvalidProgramException);
1074 // The JIT always wants to see normalized typedescs for arrays
1075 if (!th.IsTypeDesc() && th.AsMethodTable()->IsArray())
1077 MethodTable * pMT = th.AsMethodTable();
1079 // Load the TypeDesc for the array type.
1080 DWORD rank = pMT->GetRank();
1081 TypeHandle elemType = pMT->GetApproxArrayElementTypeHandle();
1082 th = ClassLoader::LoadArrayTypeThrowing(elemType, pMT->GetInternalCorElementType(), rank);
1087 unsigned metaTOK = pResolvedToken->token;
1088 Module * pModule = (Module *)pResolvedToken->tokenScope;
1090 switch (TypeFromToken(metaTOK))
1093 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1094 ThrowBadTokenException(pResolvedToken);
1097 DomainFile *pTargetModule = pModule->LoadModule(GetAppDomain(), metaTOK, FALSE /* loadResources */);
1098 if (pTargetModule == NULL)
1099 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1100 th = TypeHandle(pTargetModule->GetModule()->GetGlobalMethodTable());
1102 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
1108 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1109 ThrowBadTokenException(pResolvedToken);
1111 th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, metaTOK,
1112 ClassLoader::ThrowIfNotFound,
1113 (tokenType == CORINFO_TOKENKIND_Ldtoken) ?
1114 ClassLoader::PermitUninstDefOrRef : ClassLoader::FailIfUninstDefOrRef);
1119 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1120 ThrowBadTokenException(pResolvedToken);
1122 IfFailThrow(pModule->GetMDImport()->GetTypeSpecFromToken(metaTOK, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec));
1124 SigTypeContext typeContext;
1125 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1127 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1128 th = sigptr.GetTypeHandleThrowing(pModule, &typeContext);
1133 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1134 ThrowBadTokenException(pResolvedToken);
1136 pMD = MemberLoader::GetMethodDescFromMethodDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1138 th = pMD->GetMethodTable();
1142 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1143 ThrowBadTokenException(pResolvedToken);
1145 pFD = MemberLoader::GetFieldDescFromFieldDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1147 th = pFD->GetEnclosingMethodTable();
1152 SigTypeContext typeContext;
1153 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1155 MemberLoader::GetDescFromMemberRef(pModule, metaTOK, &pMD, &pFD, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken),
1156 &th, TRUE, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec);
1158 _ASSERTE((pMD != NULL) ^ (pFD != NULL));
1159 _ASSERTE(!th.IsNull());
1163 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1164 ThrowBadTokenException(pResolvedToken);
1168 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1169 ThrowBadTokenException(pResolvedToken);
1176 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1177 ThrowBadTokenException(pResolvedToken);
1179 SigTypeContext typeContext;
1180 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1182 // We need the method desc to carry exact instantiation, thus allowInstParam == FALSE.
1183 pMD = MemberLoader::GetMethodDescFromMethodSpec(pModule, metaTOK, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken), FALSE /* allowInstParam */,
1184 &th, TRUE, &pResolvedToken->pTypeSpec, &pResolvedToken->cbTypeSpec, &pResolvedToken->pMethodSpec, &pResolvedToken->cbMethodSpec);
1189 ThrowBadTokenException(pResolvedToken);
1193 // Module dependency tracking
1197 ScanToken(pModule, pResolvedToken, th, pMD);
1202 if (pFD->IsStatic())
1203 ScanToken(pModule, pResolvedToken, th);
1207 // It should not be required to trigger the modules cctors for ldtoken, it is done for backward compatibility only.
1208 if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained || tokenType == CORINFO_TOKENKIND_Ldtoken)
1209 ScanToken(pModule, pResolvedToken, th);
1214 // tokenType specific verification and transformations
1216 CorElementType et = th.GetInternalCorElementType();
1219 case CORINFO_TOKENKIND_Ldtoken:
1220 // Allow everything.
1223 case CORINFO_TOKENKIND_Newarr:
1224 // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1225 if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1226 COMPlusThrow(kInvalidProgramException);
1228 th = ClassLoader::LoadArrayTypeThrowing(th);
1232 // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1233 if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1234 COMPlusThrow(kInvalidProgramException);
1238 // The JIT interface should always return fully loaded types
1239 _ASSERTE(th.IsFullyLoaded());
1241 pResolvedToken->hClass = CORINFO_CLASS_HANDLE(th.AsPtr());
1242 pResolvedToken->hMethod = CORINFO_METHOD_HANDLE(pMD);
1243 pResolvedToken->hField = CORINFO_FIELD_HANDLE(pFD);
1245 EE_TO_JIT_TRANSITION();
1248 /*********************************************************************/
1249 struct TryResolveTokenFilterParam
1252 CORINFO_RESOLVED_TOKEN* m_resolvedToken;
1253 EXCEPTION_POINTERS m_exceptionPointers;
1257 bool isValidTokenForTryResolveToken(CEEInfo* info, CORINFO_RESOLVED_TOKEN* resolvedToken)
1266 if (!info->isValidToken(resolvedToken->tokenScope, resolvedToken->token))
1271 CorInfoTokenKind tokenType = resolvedToken->tokenType;
1272 switch (TypeFromToken(resolvedToken->token))
1278 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1284 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1289 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1294 if ((tokenType & (CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field)) == 0)
1305 LONG EEFilterException(struct _EXCEPTION_POINTERS* exceptionPointers, void* unused);
1307 LONG TryResolveTokenFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
1316 // Backward compatibility: Convert bad image format exceptions thrown while resolving tokens
1317 // to simple true/false successes. This is done for backward compatibility only. Ideally,
1318 // we would always treat bad tokens in the IL stream as fatal errors.
1319 if (exceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1321 auto* param = reinterpret_cast<TryResolveTokenFilterParam*>(theParam);
1322 if (!isValidTokenForTryResolveToken(param->m_this, param->m_resolvedToken))
1324 param->m_exceptionPointers = *exceptionPointers;
1325 return EEFilterException(exceptionPointers, nullptr);
1329 return EXCEPTION_CONTINUE_SEARCH;
1332 bool CEEInfo::tryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken)
1334 // No dynamic contract here because SEH is used
1335 STATIC_CONTRACT_SO_TOLERANT;
1336 STATIC_CONTRACT_THROWS;
1337 STATIC_CONTRACT_GC_TRIGGERS;
1338 STATIC_CONTRACT_MODE_PREEMPTIVE;
1340 TryResolveTokenFilterParam param;
1341 param.m_this = this;
1342 param.m_resolvedToken = resolvedToken;
1343 param.m_success = true;
1345 PAL_TRY(TryResolveTokenFilterParam*, pParam, ¶m)
1347 pParam->m_this->resolveToken(pParam->m_resolvedToken);
1349 PAL_EXCEPT_FILTER(TryResolveTokenFilter)
1351 if (param.m_exceptionPointers.ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS)
1353 HandleException(¶m.m_exceptionPointers);
1356 param.m_success = false;
1360 return param.m_success;
1363 /*********************************************************************/
1364 // We have a few frequently used constants in mscorlib that are defined as
1365 // readonly static fields for historic reasons. Check for them here and
1366 // allow them to be treated as actual constants by the JIT.
1367 static CORINFO_FIELD_ACCESSOR getFieldIntrinsic(FieldDesc * field)
1369 STANDARD_VM_CONTRACT;
1371 if (MscorlibBinder::GetField(FIELD__STRING__EMPTY) == field)
1373 return CORINFO_FIELD_INTRINSIC_EMPTY_STRING;
1376 if ((MscorlibBinder::GetField(FIELD__INTPTR__ZERO) == field) ||
1377 (MscorlibBinder::GetField(FIELD__UINTPTR__ZERO) == field))
1379 return CORINFO_FIELD_INTRINSIC_ZERO;
1382 if (MscorlibBinder::GetField(FIELD__BITCONVERTER__ISLITTLEENDIAN) == field)
1384 return CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN;
1387 return (CORINFO_FIELD_ACCESSOR)-1;
1390 static CorInfoHelpFunc getGenericStaticsHelper(FieldDesc * pField)
1392 STANDARD_VM_CONTRACT;
1394 int helper = CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE;
1396 if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1397 pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1399 helper = CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1402 if (pField->IsThreadStatic())
1404 const int delta = CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1406 static_assert_no_msg(CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE
1407 == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE + delta);
1409 helper += (CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE);
1412 return (CorInfoHelpFunc)helper;
1415 CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable * pFieldMT)
1417 STANDARD_VM_CONTRACT;
1419 int helper = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
1421 if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1422 pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1424 helper = CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1427 if (pFieldMT->IsDynamicStatics())
1429 const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1431 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS
1432 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1437 if (!pFieldMT->HasClassConstructor() && !pFieldMT->HasBoxedRegularStatics())
1439 const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1441 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR
1442 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1447 if (pField->IsThreadStatic())
1449 const int delta = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1451 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE
1452 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1453 static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR
1454 == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR + delta);
1455 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR
1456 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR + delta);
1457 static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS
1458 == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS + delta);
1459 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS
1460 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS + delta);
1465 return (CorInfoHelpFunc)helper;
1468 static CorInfoHelpFunc getInstanceFieldHelper(FieldDesc * pField, CORINFO_ACCESS_FLAGS flags)
1470 STANDARD_VM_CONTRACT;
1474 CorElementType type = pField->GetFieldType();
1476 if (CorTypeInfo::IsObjRef(type))
1477 helper = CORINFO_HELP_GETFIELDOBJ;
1481 case ELEMENT_TYPE_VALUETYPE:
1482 helper = CORINFO_HELP_GETFIELDSTRUCT;
1484 case ELEMENT_TYPE_I1:
1485 case ELEMENT_TYPE_BOOLEAN:
1486 case ELEMENT_TYPE_U1:
1487 helper = CORINFO_HELP_GETFIELD8;
1489 case ELEMENT_TYPE_I2:
1490 case ELEMENT_TYPE_CHAR:
1491 case ELEMENT_TYPE_U2:
1492 helper = CORINFO_HELP_GETFIELD16;
1494 case ELEMENT_TYPE_I4:
1495 case ELEMENT_TYPE_U4:
1497 helper = CORINFO_HELP_GETFIELD32;
1499 case ELEMENT_TYPE_I8:
1500 case ELEMENT_TYPE_U8:
1502 helper = CORINFO_HELP_GETFIELD64;
1504 case ELEMENT_TYPE_R4:
1505 helper = CORINFO_HELP_GETFIELDFLOAT;
1507 case ELEMENT_TYPE_R8:
1508 helper = CORINFO_HELP_GETFIELDDOUBLE;
1512 if (flags & CORINFO_ACCESS_SET)
1514 const int delta = CORINFO_HELP_SETFIELDOBJ - CORINFO_HELP_GETFIELDOBJ;
1516 static_assert_no_msg(CORINFO_HELP_SETFIELD8 == CORINFO_HELP_GETFIELD8 + delta);
1517 static_assert_no_msg(CORINFO_HELP_SETFIELD16 == CORINFO_HELP_GETFIELD16 + delta);
1518 static_assert_no_msg(CORINFO_HELP_SETFIELD32 == CORINFO_HELP_GETFIELD32 + delta);
1519 static_assert_no_msg(CORINFO_HELP_SETFIELD64 == CORINFO_HELP_GETFIELD64 + delta);
1520 static_assert_no_msg(CORINFO_HELP_SETFIELDSTRUCT == CORINFO_HELP_GETFIELDSTRUCT + delta);
1521 static_assert_no_msg(CORINFO_HELP_SETFIELDFLOAT == CORINFO_HELP_GETFIELDFLOAT + delta);
1522 static_assert_no_msg(CORINFO_HELP_SETFIELDDOUBLE == CORINFO_HELP_GETFIELDDOUBLE + delta);
1527 return (CorInfoHelpFunc)helper;
1530 /*********************************************************************/
1531 void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken,
1532 CORINFO_METHOD_HANDLE callerHandle,
1533 CORINFO_ACCESS_FLAGS flags,
1534 CORINFO_FIELD_INFO *pResult
1544 JIT_TO_EE_TRANSITION();
1546 _ASSERTE((flags & (CORINFO_ACCESS_GET | CORINFO_ACCESS_SET | CORINFO_ACCESS_ADDRESS | CORINFO_ACCESS_INIT_ARRAY)) != 0);
1548 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
1550 FieldDesc * pField = (FieldDesc*)pResolvedToken->hField;
1551 MethodTable * pFieldMT = pField->GetApproxEnclosingMethodTable();
1553 // Helper to use if the field access requires it
1554 CORINFO_FIELD_ACCESSOR fieldAccessor = (CORINFO_FIELD_ACCESSOR)-1;
1555 DWORD fieldFlags = 0;
1557 pResult->offset = pField->GetOffset();
1558 if (pField->IsStatic())
1560 fieldFlags |= CORINFO_FLG_FIELD_STATIC;
1562 if (pField->IsRVA())
1564 fieldFlags |= CORINFO_FLG_FIELD_UNMANAGED;
1566 Module* module = pFieldMT->GetModule();
1567 if (module->IsRvaFieldTls(pResult->offset))
1569 fieldAccessor = CORINFO_FIELD_STATIC_TLS;
1571 // Provide helper to use if the JIT is not able to emit the TLS access
1573 pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR_TLS;
1575 pResult->offset = module->GetFieldTlsOffset(pResult->offset);
1579 fieldAccessor = CORINFO_FIELD_STATIC_RVA_ADDRESS;
1582 // We are not going through a helper. The constructor has to be triggered explicitly.
1583 if (!pFieldMT->IsClassPreInited())
1584 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1587 if (pField->IsContextStatic())
1589 fieldAccessor = CORINFO_FIELD_STATIC_ADDR_HELPER;
1591 pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR_CONTEXT;
1595 // Regular or thread static
1596 CORINFO_FIELD_ACCESSOR intrinsicAccessor;
1598 if (pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1599 fieldFlags |= CORINFO_FLG_FIELD_STATIC_IN_HEAP;
1601 if (pFieldMT->IsSharedByGenericInstantiations())
1603 fieldAccessor = CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER;
1605 pResult->helper = getGenericStaticsHelper(pField);
1608 if (pFieldMT->GetModule()->IsSystem() && (flags & CORINFO_ACCESS_GET) &&
1609 (intrinsicAccessor = getFieldIntrinsic(pField)) != (CORINFO_FIELD_ACCESSOR)-1)
1612 fieldAccessor = intrinsicAccessor;
1615 if (// Domain neutral access.
1616 m_pMethodBeingCompiled->IsDomainNeutral() || m_pMethodBeingCompiled->IsZapped() || IsCompilingForNGen() ||
1617 // Static fields are not pinned in collectible types. We will always access
1618 // them using a helper since the address cannot be embeded into the code.
1619 pFieldMT->Collectible() ||
1620 // We always treat accessing thread statics as if we are in domain neutral code.
1621 pField->IsThreadStatic()
1624 fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
1626 pResult->helper = getSharedStaticsHelper(pField, pFieldMT);
1630 fieldAccessor = CORINFO_FIELD_STATIC_ADDRESS;
1632 // We are not going through a helper. The constructor has to be triggered explicitly.
1633 if (!pFieldMT->IsClassPreInited())
1634 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1639 // Currently, we only this optimization for regular statics, but it
1640 // looks like it may be permissible to do this optimization for
1641 // thread statics as well.
1643 if ((flags & CORINFO_ACCESS_ADDRESS) &&
1644 !pField->IsThreadStatic() &&
1645 !pField->IsContextStatic() &&
1646 (fieldAccessor != CORINFO_FIELD_STATIC_TLS))
1648 fieldFlags |= CORINFO_FLG_FIELD_SAFESTATIC_BYREF_RETURN;
1653 BOOL fInstanceHelper = FALSE;
1655 #if CHECK_APP_DOMAIN_LEAKS
1656 if (g_pConfig->EnableFullDebug()
1657 && pField->IsDangerousAppDomainAgileField()
1658 && CorTypeInfo::IsObjRef(pField->GetFieldType()))
1661 // In a checked field with all checks turned on, we use a helper to enforce the app domain
1664 // <REVISIT_TODO>@todo: we'd like to check this for value type fields as well - we
1665 // just need to add some code to iterate through the fields for
1666 // references during the assignment.
1668 fInstanceHelper = TRUE;
1671 #endif // CHECK_APP_DOMAIN_LEAKS
1673 if (fInstanceHelper)
1675 if (flags & CORINFO_ACCESS_ADDRESS)
1677 fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1679 pResult->helper = CORINFO_HELP_GETFIELDADDR;
1683 fieldAccessor = CORINFO_FIELD_INSTANCE_HELPER;
1685 pResult->helper = getInstanceFieldHelper(pField, flags);
1689 if (pField->IsEnCNew())
1691 fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1693 pResult->helper = CORINFO_HELP_GETFIELDADDR;
1697 fieldAccessor = CORINFO_FIELD_INSTANCE;
1700 // FieldDesc::GetOffset() does not include the size of Object
1701 if (!pFieldMT->IsValueType())
1703 pResult->offset += sizeof(Object);
1707 // TODO: This is touching metadata. Can we avoid it?
1708 DWORD fieldAttribs = pField->GetAttributes();
1710 if (IsFdFamily(fieldAttribs))
1711 fieldFlags |= CORINFO_FLG_FIELD_PROTECTED;
1713 if (IsFdInitOnly(fieldAttribs))
1714 fieldFlags |= CORINFO_FLG_FIELD_FINAL;
1716 pResult->fieldAccessor = fieldAccessor;
1717 pResult->fieldFlags = fieldFlags;
1719 if (!(flags & CORINFO_ACCESS_INLINECHECK))
1721 //get the field's type. Grab the class for structs.
1722 pResult->fieldType = getFieldTypeInternal(pResolvedToken->hField, &pResult->structType, pResolvedToken->hClass);
1725 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
1728 //Since we can't get the special verify-only instantiated FD like we can with MDs, go back to the parent
1729 //of the memberRef and load that one. That should give us the open instantiation.
1731 //If the field we found is owned by a generic type, you have to go back to the signature and reload.
1732 //Otherwise we filled in !0.
1733 TypeHandle fieldTypeForSecurity = TypeHandle(pResolvedToken->hClass);
1734 if (pResolvedToken->pTypeSpec != NULL)
1736 SigTypeContext typeContext;
1737 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
1739 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1740 fieldTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
1742 // typeHnd can be a variable type
1743 if (fieldTypeForSecurity.GetMethodTable() == NULL)
1745 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
1749 BOOL doAccessCheck = TRUE;
1750 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
1752 DynamicResolver * pAccessContext = NULL;
1754 //More in code:CEEInfo::getCallInfo, but the short version is that the caller and callee Descs do
1755 //not completely describe the type.
1756 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
1757 if (IsDynamicScope(pResolvedToken->tokenScope))
1759 doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope), &callerTypeForSecurity,
1760 &accessCheckType, &pAccessContext);
1763 //Now for some link time checks.
1764 //Um... where are the field link demands?
1766 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
1770 //Well, let's check some visibility at least.
1771 AccessCheckOptions accessCheckOptions(accessCheckType,
1776 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
1777 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
1779 BOOL canAccess = ClassLoader::CanAccess(
1781 fieldTypeForSecurity.GetMethodTable(),
1782 fieldTypeForSecurity.GetAssembly(),
1785 (flags & CORINFO_ACCESS_INIT_ARRAY) ? NULL : pField, // For InitializeArray, we don't need tocheck the type of the field.
1787 FALSE /*checkTargetMethodTransparency*/,
1788 TRUE /*checkTargetTypeTransparency*/);
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 // Defs have already been checked by the loader for validity
1929 // However refs need to be checked.
1930 if (!Security::CanSkipVerification(module->GetDomainAssembly()))
1932 // Can pass 0 for the flags, since it is only used for defs.
1933 IfFailThrow(validateTokenSig(sigMethTok, pSig, cbSig, 0, module->GetMDImport()));
1936 else if (TypeFromToken(sigMethTok) == mdtMethodDef)
1938 IfFailThrow(module->GetMDImport()->GetSigOfMethodDef(sigMethTok, &cbSig, &pSig));
1942 CEEInfo::ConvToJitSig(
1948 GetMethodFromContext(context),
1950 GetTypeFromContext(context));
1951 EE_TO_JIT_TRANSITION();
1952 } // CEEInfo::findCallSiteSig
1954 //---------------------------------------------------------------------------------------
1958 CORINFO_MODULE_HANDLE scopeHnd,
1960 CORINFO_CONTEXT_HANDLE context,
1961 CORINFO_SIG_INFO * sigRet)
1970 JIT_TO_EE_TRANSITION();
1972 PCCOR_SIGNATURE pSig = NULL;
1975 if (IsDynamicScope(scopeHnd))
1977 SigPointer sig = GetDynamicResolver(scopeHnd)->ResolveSignature(sigTok);
1978 sig.GetSignature(&pSig, &cbSig);
1979 sigTok = mdTokenNil;
1983 Module * module = (Module *)scopeHnd;
1985 // We need to resolve this stand alone sig
1986 IfFailThrow(module->GetMDImport()->GetSigFromToken(
1987 (mdSignature)sigTok,
1992 CEEInfo::ConvToJitSig(
1998 GetMethodFromContext(context),
2000 GetTypeFromContext(context));
2002 EE_TO_JIT_TRANSITION();
2003 } // CEEInfo::findSig
2005 //---------------------------------------------------------------------------------------
2008 CEEInfo::getClassSize(
2009 CORINFO_CLASS_HANDLE clsHnd)
2018 unsigned result = 0;
2020 JIT_TO_EE_TRANSITION_LEAF();
2022 TypeHandle VMClsHnd(clsHnd);
2023 result = VMClsHnd.GetSize();
2025 EE_TO_JIT_TRANSITION_LEAF();
2030 unsigned CEEInfo::getClassAlignmentRequirement(CORINFO_CLASS_HANDLE type, BOOL fDoubleAlignHint)
2039 // Default alignment is sizeof(void*)
2040 unsigned result = sizeof(void*);
2042 JIT_TO_EE_TRANSITION_LEAF();
2044 TypeHandle clsHnd(type);
2046 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
2047 if (fDoubleAlignHint)
2049 MethodTable* pMT = clsHnd.GetMethodTable();
2052 // Return the size of the double align hint. Ignore the actual alignment info account
2053 // so that structs with 64-bit integer fields do not trigger double aligned frames on x86.
2054 if (pMT->GetClass()->IsAlign8Candidate())
2061 result = getClassAlignmentRequirementStatic(clsHnd);
2064 EE_TO_JIT_TRANSITION_LEAF();
2069 unsigned CEEInfo::getClassAlignmentRequirementStatic(TypeHandle clsHnd)
2071 LIMITED_METHOD_CONTRACT;
2073 // Default alignment is sizeof(void*)
2074 unsigned result = sizeof(void*);
2076 MethodTable * pMT = clsHnd.GetMethodTable();
2080 if (pMT->HasLayout())
2082 EEClassLayoutInfo* pInfo = pMT->GetLayoutInfo();
2084 if (clsHnd.IsNativeValueType())
2086 // if it's the unmanaged view of the managed type, we always use the unmanaged alignment requirement
2087 result = pInfo->m_LargestAlignmentRequirementOfAllMembers;
2090 if (pInfo->IsManagedSequential())
2092 _ASSERTE(!pMT->ContainsPointers());
2094 // if it's managed sequential, we use the managed alignment requirement
2095 result = pInfo->m_ManagedLargestAlignmentRequirementOfAllMembers;
2097 else if (pInfo->IsBlittable())
2099 _ASSERTE(!pMT->ContainsPointers());
2101 // if it's blittable, we use the unmanaged alignment requirement
2102 result = pInfo->m_LargestAlignmentRequirementOfAllMembers;
2106 #ifdef FEATURE_64BIT_ALIGNMENT
2107 if (result < 8 && pMT->RequiresAlign8())
2109 // If the structure contains 64-bit primitive fields and the platform requires 8-byte alignment for
2110 // such fields then make sure we return at least 8-byte alignment. Note that it's technically possible
2111 // to create unmanaged APIs that take unaligned structures containing such fields and this
2112 // unconditional alignment bump would cause us to get the calling convention wrong on platforms such
2113 // as ARM. If we see such cases in the future we'd need to add another control (such as an alignment
2114 // property for the StructLayout attribute or a marshaling directive attribute for p/invoke arguments)
2115 // that allows more precise control. For now we'll go with the likely scenario.
2118 #endif // FEATURE_64BIT_ALIGNMENT
2123 CORINFO_FIELD_HANDLE
2124 CEEInfo::getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num)
2133 CORINFO_FIELD_HANDLE result = NULL;
2135 JIT_TO_EE_TRANSITION_LEAF();
2137 TypeHandle VMClsHnd(clsHnd);
2139 MethodTable* pMT= VMClsHnd.AsMethodTable();
2141 result = (CORINFO_FIELD_HANDLE) ((pMT->GetApproxFieldDescListRaw()) + num);
2143 EE_TO_JIT_TRANSITION_LEAF();
2149 CEEInfo::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod)
2158 mdMethodDef result = 0;
2160 JIT_TO_EE_TRANSITION_LEAF();
2162 MethodDesc* pMD = GetMethod(hMethod);
2164 if (pMD->IsDynamicMethod())
2166 // Dynamic methods do not have tokens
2167 result = mdMethodDefNil;
2171 result = pMD->GetMemberDef();
2174 EE_TO_JIT_TRANSITION_LEAF();
2179 BOOL CEEInfo::checkMethodModifier(CORINFO_METHOD_HANDLE hMethod,
2190 BOOL result = FALSE;
2192 JIT_TO_EE_TRANSITION();
2194 MethodDesc* pMD = GetMethod(hMethod);
2195 Module* pModule = pMD->GetModule();
2197 CorElementType eeType = fOptional ? ELEMENT_TYPE_CMOD_OPT : ELEMENT_TYPE_CMOD_REQD;
2199 // modopts/modreqs for the method are by convention stored on the return type
2200 result = sig.GetReturnProps().HasCustomModifier(pModule, modifier, eeType);
2202 EE_TO_JIT_TRANSITION();
2207 /*********************************************************************/
2208 static unsigned ComputeGCLayout(MethodTable * pMT, BYTE* gcPtrs)
2210 STANDARD_VM_CONTRACT;
2212 unsigned result = 0;
2214 _ASSERTE(pMT->IsValueType());
2216 // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in which
2217 // case the check for g_TypedReferenceMT below would not be necessary
2218 if (pMT == g_TypedReferenceMT || pMT->HasSameTypeDefAs(g_pByReferenceClass))
2220 if (gcPtrs[0] == TYPE_GC_NONE)
2222 gcPtrs[0] = TYPE_GC_BYREF;
2225 else if (gcPtrs[0] != TYPE_GC_BYREF)
2227 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2232 ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
2233 for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
2235 int fieldStartIndex = pFD->GetOffset() / sizeof(void*);
2237 if (pFD->GetFieldType() != ELEMENT_TYPE_VALUETYPE)
2239 if (pFD->IsObjRef())
2241 if (gcPtrs[fieldStartIndex] == TYPE_GC_NONE)
2243 gcPtrs[fieldStartIndex] = TYPE_GC_REF;
2246 else if (gcPtrs[fieldStartIndex] != TYPE_GC_REF)
2248 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2254 MethodTable * pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
2255 result += ComputeGCLayout(pFieldMT, gcPtrs + fieldStartIndex);
2261 unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
2270 unsigned result = 0;
2272 JIT_TO_EE_TRANSITION();
2274 TypeHandle VMClsHnd(clsHnd);
2276 MethodTable* pMT = VMClsHnd.GetMethodTable();
2278 if (pMT->IsByRefLike())
2280 // TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in
2281 // which case the check for g_TypedReferenceMT below would not be necessary
2282 if (pMT == g_TypedReferenceMT)
2284 gcPtrs[0] = TYPE_GC_BYREF;
2285 gcPtrs[1] = TYPE_GC_NONE;
2290 memset(gcPtrs, TYPE_GC_NONE,
2291 (VMClsHnd.GetSize() + sizeof(void*) - 1) / sizeof(void*));
2292 // Note: This case is more complicated than the TypedReference case
2293 // due to ByRefLike structs being included as fields in other value
2294 // types (TypedReference can not be.)
2295 result = ComputeGCLayout(VMClsHnd.AsMethodTable(), gcPtrs);
2298 else if (VMClsHnd.IsNativeValueType())
2300 // native value types have no GC pointers
2302 memset(gcPtrs, TYPE_GC_NONE,
2303 (VMClsHnd.GetSize() + sizeof(void*) -1)/ sizeof(void*));
2307 _ASSERTE(pMT->IsValueType());
2308 _ASSERTE(sizeof(BYTE) == 1);
2310 // assume no GC pointers at first
2312 memset(gcPtrs, TYPE_GC_NONE,
2313 (VMClsHnd.GetSize() + sizeof(void*) -1)/ sizeof(void*));
2315 // walk the GC descriptors, turning on the correct bits
2316 if (pMT->ContainsPointers())
2318 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
2319 CGCDescSeries * pByValueSeries = map->GetLowestSeries();
2321 for (SIZE_T i = 0; i < map->GetNumSeries(); i++)
2323 // Get offset into the value class of the first pointer field (includes a +Object)
2324 size_t cbSeriesSize = pByValueSeries->GetSeriesSize() + pMT->GetBaseSize();
2325 size_t cbOffset = pByValueSeries->GetSeriesOffset() - sizeof(Object);
2327 _ASSERTE (cbOffset % sizeof(void*) == 0);
2328 _ASSERTE (cbSeriesSize % sizeof(void*) == 0);
2330 result += (unsigned) (cbSeriesSize / sizeof(void*));
2331 memset(&gcPtrs[cbOffset/sizeof(void*)], TYPE_GC_REF, cbSeriesSize / sizeof(void*));
2338 EE_TO_JIT_TRANSITION();
2343 // returns the enregister info for a struct based on type of fields, alignment, etc.
2344 bool CEEInfo::getSystemVAmd64PassStructInRegisterDescriptor(
2345 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
2346 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
2355 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
2356 JIT_TO_EE_TRANSITION();
2358 _ASSERTE(structPassInRegDescPtr != nullptr);
2359 TypeHandle th(structHnd);
2361 structPassInRegDescPtr->passedInRegisters = false;
2363 // Make sure this is a value type.
2364 if (th.IsValueType())
2366 _ASSERTE((CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeStruct) ||
2367 (CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeTypedReference));
2369 // The useNativeLayout in this case tracks whether the classification
2370 // is for a native layout of the struct or not.
2371 // If the struct has special marshaling it has a native layout.
2372 // In such cases the classifier needs to use the native layout.
2373 // For structs with no native layout, the managed layout should be used
2374 // even if classified for the purposes of marshaling/PInvoke passing.
2375 bool useNativeLayout = false;
2376 MethodTable* methodTablePtr = nullptr;
2377 if (!th.IsTypeDesc())
2379 methodTablePtr = th.AsMethodTable();
2383 _ASSERTE(th.IsNativeValueType());
2385 useNativeLayout = true;
2386 methodTablePtr = th.AsNativeValueType();
2388 _ASSERTE(methodTablePtr != nullptr);
2390 // If we have full support for FEATURE_UNIX_AMD64_STRUCT_PASSING, and not just the interface,
2391 // then we've cached whether this is a reg passed struct in the MethodTable, computed during
2392 // MethodTable construction. Otherwise, we are just building in the interface, and we haven't
2393 // computed or cached anything, so we need to compute it now.
2394 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2395 bool canPassInRegisters = useNativeLayout ? methodTablePtr->GetLayoutInfo()->IsNativeStructPassedInRegisters()
2396 : methodTablePtr->IsRegPassedStruct();
2397 #else // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2398 SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2399 bool canPassInRegisters = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2400 #endif // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2402 if (canPassInRegisters)
2404 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2405 SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2406 bool result = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2408 // The answer must be true at this point.
2410 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
2412 structPassInRegDescPtr->passedInRegisters = true;
2414 structPassInRegDescPtr->eightByteCount = helper.eightByteCount;
2415 _ASSERTE(structPassInRegDescPtr->eightByteCount <= CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS);
2417 for (unsigned int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++)
2419 structPassInRegDescPtr->eightByteClassifications[i] = helper.eightByteClassifications[i];
2420 structPassInRegDescPtr->eightByteSizes[i] = helper.eightByteSizes[i];
2421 structPassInRegDescPtr->eightByteOffsets[i] = helper.eightByteOffsets[i];
2425 _ASSERTE(structPassInRegDescPtr->passedInRegisters == canPassInRegisters);
2428 EE_TO_JIT_TRANSITION();
2431 #else // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
2433 #endif // !defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
2436 /*********************************************************************/
2437 unsigned CEEInfo::getClassNumInstanceFields (CORINFO_CLASS_HANDLE clsHnd)
2446 unsigned result = 0;
2448 JIT_TO_EE_TRANSITION_LEAF();
2450 TypeHandle th(clsHnd);
2452 if (!th.IsTypeDesc())
2454 result = th.AsMethodTable()->GetNumInstanceFields();
2458 // native value types are opaque aggregates with explicit size
2462 EE_TO_JIT_TRANSITION_LEAF();
2468 CorInfoType CEEInfo::asCorInfoType (CORINFO_CLASS_HANDLE clsHnd)
2477 CorInfoType result = CORINFO_TYPE_UNDEF;
2479 JIT_TO_EE_TRANSITION();
2481 TypeHandle VMClsHnd(clsHnd);
2482 result = toJitType(VMClsHnd);
2484 EE_TO_JIT_TRANSITION();
2490 CORINFO_LOOKUP_KIND CEEInfo::getLocationOfThisType(CORINFO_METHOD_HANDLE context)
2499 CORINFO_LOOKUP_KIND result;
2501 /* Initialize fields of result for debug build warning */
2502 result.needsRuntimeLookup = false;
2503 result.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
2505 JIT_TO_EE_TRANSITION();
2507 MethodDesc *pContextMD = GetMethod(context);
2509 // If the method table is not shared, then return CONST
2510 if (!pContextMD->GetMethodTable()->IsSharedByGenericInstantiations())
2512 result.needsRuntimeLookup = false;
2516 result.needsRuntimeLookup = true;
2518 // If we've got a vtable extra argument, go through that
2519 if (pContextMD->RequiresInstMethodTableArg())
2521 result.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
2523 // If we've got an object, go through its vtable
2524 else if (pContextMD->AcquiresInstMethodTableFromThis())
2526 result.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
2528 // Otherwise go through the method-desc argument
2531 _ASSERTE(pContextMD->RequiresInstMethodDescArg());
2532 result.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
2536 EE_TO_JIT_TRANSITION();
2541 CORINFO_METHOD_HANDLE CEEInfo::GetDelegateCtor(
2542 CORINFO_METHOD_HANDLE methHnd,
2543 CORINFO_CLASS_HANDLE clsHnd,
2544 CORINFO_METHOD_HANDLE targetMethodHnd,
2545 DelegateCtorArgs *pCtorData)
2556 // No sense going through the optimized case just for verification and it can cause issues parsing
2557 // uninstantiated generic signatures.
2561 CORINFO_METHOD_HANDLE result = NULL;
2563 JIT_TO_EE_TRANSITION();
2565 MethodDesc *pCurrentCtor = (MethodDesc*)methHnd;
2566 if (!pCurrentCtor->IsFCall())
2572 MethodDesc *pTargetMethod = (MethodDesc*)targetMethodHnd;
2573 TypeHandle delegateType = (TypeHandle)clsHnd;
2575 MethodDesc *pDelegateCtor = COMDelegate::GetDelegateCtor(delegateType, pTargetMethod, pCtorData);
2577 pDelegateCtor = pCurrentCtor;
2578 result = (CORINFO_METHOD_HANDLE)pDelegateCtor;
2581 EE_TO_JIT_TRANSITION();
2586 void CEEInfo::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd)
2595 JIT_TO_EE_TRANSITION();
2597 MethodDesc* pMD = GetMethod(methHnd);
2599 if (pMD->IsDynamicMethod())
2601 pMD->AsDynamicMethodDesc()->GetResolver()->FreeCompileTimeState();
2604 EE_TO_JIT_TRANSITION();
2607 // Given a module scope (scopeHnd), a method handle (context) and an metadata token,
2608 // attempt to load the handle (type, field or method) associated with the token.
2609 // If this is not possible at compile-time (because the method code is shared and the token contains type parameters)
2610 // then indicate how the handle should be looked up at run-time.
2612 // See corinfo.h for more details
2614 void CEEInfo::embedGenericHandle(
2615 CORINFO_RESOLVED_TOKEN * pResolvedToken,
2617 CORINFO_GENERICHANDLE_RESULT *pResult)
2626 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
2628 JIT_TO_EE_TRANSITION();
2630 BOOL fRuntimeLookup;
2631 MethodDesc * pTemplateMD = NULL;
2633 if (!fEmbedParent && pResolvedToken->hMethod != NULL)
2635 MethodDesc * pMD = (MethodDesc *)pResolvedToken->hMethod;
2636 TypeHandle th(pResolvedToken->hClass);
2638 pResult->handleType = CORINFO_HANDLETYPE_METHOD;
2640 Instantiation methodInst = pMD->GetMethodInstantiation();
2642 pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, th.GetMethodTable(), FALSE, methodInst, FALSE);
2644 // Normalize the method handle for reflection
2645 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Ldtoken)
2646 pMD = MethodDesc::FindOrCreateAssociatedMethodDescForReflection(pMD, th, methodInst);
2648 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pMD;
2651 // Runtime lookup is only required for stubs. Regular entrypoints are always the same shared MethodDescs.
2652 fRuntimeLookup = pMD->IsWrapperStub() &&
2653 (pMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(methodInst));
2656 if (!fEmbedParent && pResolvedToken->hField != NULL)
2658 FieldDesc * pFD = (FieldDesc *)pResolvedToken->hField;
2659 TypeHandle th(pResolvedToken->hClass);
2661 pResult->handleType = CORINFO_HANDLETYPE_FIELD;
2663 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pFD;
2665 fRuntimeLookup = th.IsSharedByGenericInstantiations() && pFD->IsStatic();
2669 TypeHandle th(pResolvedToken->hClass);
2671 pResult->handleType = CORINFO_HANDLETYPE_CLASS;
2673 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
2675 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsArray()->GetTemplateMethodTable();
2679 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsPtr();
2682 if (fEmbedParent && pResolvedToken->hMethod != NULL)
2684 MethodDesc * pDeclaringMD = (MethodDesc *)pResolvedToken->hMethod;
2686 if (!pDeclaringMD->GetMethodTable()->HasSameTypeDefAs(th.GetMethodTable()))
2689 // The method type may point to a sub-class of the actual class that declares the method.
2690 // It is important to embed the declaring type in this case.
2693 pTemplateMD = pDeclaringMD;
2695 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pDeclaringMD->GetMethodTable();
2699 // IsSharedByGenericInstantiations would not work here. The runtime lookup is required
2700 // even for standalone generic variables that show up as __Canon here.
2701 fRuntimeLookup = th.IsCanonicalSubtype();
2704 _ASSERTE(pResult->compileTimeHandle);
2707 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
2708 && ContextIsShared(pResolvedToken->tokenContext))
2710 DictionaryEntryKind entryKind = EmptySlot;
2711 switch (pResult->handleType)
2713 case CORINFO_HANDLETYPE_CLASS:
2714 entryKind = (pTemplateMD != NULL) ? DeclaringTypeHandleSlot : TypeHandleSlot;
2716 case CORINFO_HANDLETYPE_METHOD:
2717 entryKind = MethodDescSlot;
2719 case CORINFO_HANDLETYPE_FIELD:
2720 entryKind = FieldDescSlot;
2726 ComputeRuntimeLookupForSharedGenericToken(entryKind,
2734 // If the target is not shared then we've already got our result and
2735 // can simply do a static look up
2736 pResult->lookup.lookupKind.needsRuntimeLookup = false;
2738 pResult->lookup.constLookup.handle = pResult->compileTimeHandle;
2739 pResult->lookup.constLookup.accessType = IAT_VALUE;
2742 EE_TO_JIT_TRANSITION();
2745 void CEEInfo::ScanForModuleDependencies(Module* pModule, SigPointer psig)
2747 STANDARD_VM_CONTRACT;
2749 _ASSERTE(pModule && !pModule->IsSystem());
2751 CorElementType eType;
2752 IfFailThrow(psig.GetElemType(&eType));
2756 case ELEMENT_TYPE_GENERICINST:
2758 ScanForModuleDependencies(pModule,psig);
2759 IfFailThrow(psig.SkipExactlyOne());
2762 IfFailThrow(psig.GetData(&ntypars));
2763 for (ULONG i = 0; i < ntypars; i++)
2765 ScanForModuleDependencies(pModule,psig);
2766 IfFailThrow(psig.SkipExactlyOne());
2771 case ELEMENT_TYPE_VALUETYPE:
2772 case ELEMENT_TYPE_CLASS:
2775 IfFailThrow(psig.GetToken(&tk));
2776 if (TypeFromToken(tk) == mdtTypeRef)
2778 Module * pTypeDefModule;
2781 if (ClassLoader::ResolveTokenToTypeDefThrowing(pModule, tk, &pTypeDefModule, &tkTypeDef))
2784 if (!pTypeDefModule->IsSystem() && (pModule != pTypeDefModule))
2786 m_pOverride->addActiveDependency((CORINFO_MODULE_HANDLE)pModule, (CORINFO_MODULE_HANDLE)pTypeDefModule);
2797 void CEEInfo::ScanMethodSpec(Module * pModule, PCCOR_SIGNATURE pMethodSpec, ULONG cbMethodSpec)
2799 STANDARD_VM_CONTRACT;
2801 SigPointer sp(pMethodSpec, cbMethodSpec);
2804 IfFailThrow(sp.GetByte(&etype));
2806 _ASSERT(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST);
2808 ULONG nGenericMethodArgs;
2809 IfFailThrow(sp.GetData(&nGenericMethodArgs));
2811 for (ULONG i = 0; i < nGenericMethodArgs; i++)
2813 ScanForModuleDependencies(pModule,sp);
2814 IfFailThrow(sp.SkipExactlyOne());
2818 BOOL CEEInfo::ScanTypeSpec(Module * pModule, PCCOR_SIGNATURE pTypeSpec, ULONG cbTypeSpec)
2820 STANDARD_VM_CONTRACT;
2822 SigPointer sp(pTypeSpec, cbTypeSpec);
2824 CorElementType eType;
2825 IfFailThrow(sp.GetElemType(&eType));
2827 // Filter out non-instantiated types and typedescs (typevars, arrays, ...)
2828 if (eType != ELEMENT_TYPE_GENERICINST)
2830 // Scanning of the parent chain is required for reference types only.
2831 // Note that the parent chain MUST NOT be scanned for instantiated
2832 // generic variables because of they are not a real dependencies.
2833 return (eType == ELEMENT_TYPE_CLASS);
2836 IfFailThrow(sp.SkipExactlyOne());
2839 IfFailThrow(sp.GetData(&ntypars));
2841 for (ULONG i = 0; i < ntypars; i++)
2843 ScanForModuleDependencies(pModule,sp);
2844 IfFailThrow(sp.SkipExactlyOne());
2850 void CEEInfo::ScanInstantiation(Module * pModule, Instantiation inst)
2852 STANDARD_VM_CONTRACT;
2854 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
2856 TypeHandle th = inst[i];
2857 if (th.IsTypeDesc())
2860 MethodTable * pMT = th.AsMethodTable();
2862 Module * pDefModule = pMT->GetModule();
2864 if (!pDefModule->IsSystem() && (pModule != pDefModule))
2866 m_pOverride->addActiveDependency((CORINFO_MODULE_HANDLE)pModule, (CORINFO_MODULE_HANDLE)pDefModule);
2869 if (pMT->HasInstantiation())
2871 ScanInstantiation(pModule, pMT->GetInstantiation());
2877 // ScanToken is used to track triggers for creation of per-AppDomain state instead, including allocations required for statics and
2878 // triggering of module cctors.
2880 // The basic rule is: There should be no possibility of a shared module that is "active" to have a direct call into a module that
2881 // is not "active". And we don't want to intercept every call during runtime, so during compile time we track static calls and
2882 // everything that can result in new virtual calls.
2884 // The current algoritm (scan the parent type chain and instantiation variables) is more than enough to maintain this invariant.
2885 // One could come up with a more efficient algorithm that still maintains the invariant, but it may introduce backward compatibility
2888 // For efficiency, the implementation leverages the loaded types as much as possible. Unfortunately, we still have to go back to
2889 // metadata when the generic variables could have been substituted via generic context.
2891 void CEEInfo::ScanToken(Module * pModule, CORINFO_RESOLVED_TOKEN * pResolvedToken, TypeHandle th, MethodDesc * pMD)
2893 STANDARD_VM_CONTRACT;
2895 if (pModule->IsSystem())
2902 // Scan method instantiation
2904 if (pMD != NULL && pResolvedToken->pMethodSpec != NULL)
2906 if (ContextIsInstantiated(pResolvedToken->tokenContext))
2908 ScanMethodSpec(pModule, pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
2912 ScanInstantiation(pModule, pMD->GetMethodInstantiation());
2916 if (th.IsTypeDesc())
2919 MethodTable * pMT = th.AsMethodTable();
2922 // Scan type instantiation
2924 if (pResolvedToken->pTypeSpec != NULL)
2926 if (ContextIsInstantiated(pResolvedToken->tokenContext))
2928 if (!ScanTypeSpec(pModule, pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec))
2933 ScanInstantiation(pModule, pMT->GetInstantiation());
2938 // Scan chain of parent types
2942 Module * pDefModule = pMT->GetModule();
2943 if (pDefModule->IsSystem())
2946 if (pModule != pDefModule)
2948 m_pOverride->addActiveDependency((CORINFO_MODULE_HANDLE)pModule, (CORINFO_MODULE_HANDLE)pDefModule);
2951 MethodTable * pParentMT = pMT->GetParentMethodTable();
2952 if (pParentMT == NULL)
2955 if (pParentMT->HasInstantiation())
2957 IMDInternalImport* pInternalImport = pDefModule->GetMDImport();
2960 IfFailThrow(pInternalImport->GetTypeDefProps(pMT->GetCl(), NULL, &tkParent));
2962 if (TypeFromToken(tkParent) == mdtTypeSpec)
2964 PCCOR_SIGNATURE pTypeSpec;
2966 IfFailThrow(pInternalImport->GetTypeSpecFromToken(tkParent, &pTypeSpec, &cbTypeSpec));
2968 ScanTypeSpec(pDefModule, pTypeSpec, cbTypeSpec);
2976 void CEEInfo::ScanTokenForDynamicScope(CORINFO_RESOLVED_TOKEN * pResolvedToken, TypeHandle th, MethodDesc * pMD)
2978 STANDARD_VM_CONTRACT;
2980 if (m_pMethodBeingCompiled->IsLCGMethod())
2982 // The dependency tracking for LCG is irrelevant. Perform immediate activation.
2983 if (pMD != NULL && pMD->HasMethodInstantiation())
2984 pMD->EnsureActive();
2985 if (!th.IsTypeDesc())
2986 th.AsMethodTable()->EnsureInstanceActive();
2990 // Stubs-as-IL have to do regular dependency tracking because they can be shared cross-domain.
2991 Module * pModule = GetDynamicResolver(pResolvedToken->tokenScope)->GetDynamicMethod()->GetModule();
2992 ScanToken(pModule, pResolvedToken, th, pMD);
2995 MethodDesc * CEEInfo::GetMethodForSecurity(CORINFO_METHOD_HANDLE callerHandle)
2997 STANDARD_VM_CONTRACT;
2999 // Cache the cast lookup
3000 if (callerHandle == m_hMethodForSecurity_Key)
3002 return m_pMethodForSecurity_Value;
3005 MethodDesc * pCallerMethod = (MethodDesc *)callerHandle;
3007 //If the caller is generic, load the open type and then load the field again, This allows us to
3008 //differentiate between BadGeneric<T> containing a memberRef for a field of type InaccessibleClass and
3009 //GoodGeneric<T> containing a memberRef for a field of type T instantiated over InaccessibleClass.
3010 MethodDesc * pMethodForSecurity = pCallerMethod->IsILStub() ?
3011 pCallerMethod : pCallerMethod->LoadTypicalMethodDefinition();
3013 m_hMethodForSecurity_Key = callerHandle;
3014 m_pMethodForSecurity_Value = pMethodForSecurity;
3016 return pMethodForSecurity;
3019 // Check that the instantation is <!/!!0, ..., !/!!(n-1)>
3020 static BOOL IsSignatureForTypicalInstantiation(SigPointer sigptr, CorElementType varType, ULONG ntypars)
3022 STANDARD_VM_CONTRACT;
3024 for (ULONG i = 0; i < ntypars; i++)
3026 CorElementType type;
3027 IfFailThrow(sigptr.GetElemType(&type));
3028 if (type != varType)
3032 IfFailThrow(sigptr.GetData(&data));
3041 // Check that methodSpec instantiation is <!!0, ..., !!(n-1)>
3042 static BOOL IsMethodSpecForTypicalInstantation(SigPointer sigptr)
3044 STANDARD_VM_CONTRACT;
3047 IfFailThrow(sigptr.GetByte(&etype));
3048 _ASSERTE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST);
3051 IfFailThrow(sigptr.GetData(&ntypars));
3053 return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_MVAR, ntypars);
3056 // Check that typeSpec instantiation is <!0, ..., !(n-1)>
3057 static BOOL IsTypeSpecForTypicalInstantiation(SigPointer sigptr)
3059 STANDARD_VM_CONTRACT;
3061 CorElementType type;
3062 IfFailThrow(sigptr.GetElemType(&type));
3063 if (type != ELEMENT_TYPE_GENERICINST)
3066 IfFailThrow(sigptr.SkipExactlyOne());
3069 IfFailThrow(sigptr.GetData(&ntypars));
3071 return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_VAR, ntypars);
3074 void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entryKind,
3075 CORINFO_RESOLVED_TOKEN * pResolvedToken,
3076 CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
3077 MethodDesc * pTemplateMD /* for method-based slots */,
3078 CORINFO_LOOKUP *pResultLookup)
3082 PRECONDITION(CheckPointer(pResultLookup));
3086 // We should never get here when we are only verifying
3087 _ASSERTE(!isVerifyOnly());
3089 pResultLookup->lookupKind.needsRuntimeLookup = true;
3090 pResultLookup->lookupKind.runtimeLookupFlags = 0;
3092 CORINFO_RUNTIME_LOOKUP *pResult = &pResultLookup->runtimeLookup;
3093 pResult->signature = NULL;
3095 pResult->indirectFirstOffset = 0;
3096 pResult->indirectSecondOffset = 0;
3098 // Unless we decide otherwise, just do the lookup via a helper function
3099 pResult->indirections = CORINFO_USEHELPER;
3101 MethodDesc *pContextMD = GetMethodFromContext(pResolvedToken->tokenContext);
3102 MethodTable *pContextMT = pContextMD->GetMethodTable();
3104 // Do not bother computing the runtime lookup if we are inlining. The JIT is going
3105 // to abort the inlining attempt anyway.
3106 if (pContextMD != m_pMethodBeingCompiled)
3111 // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup.
3112 // All callers of ComputeRuntimeLookupForSharedGenericToken have to filter out this case. We can't do much about it here.
3113 _ASSERTE(pContextMD->IsSharedByGenericInstantiations());
3115 BOOL fInstrument = FALSE;
3117 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
3118 // This will make sure that when IBC logging is turned on we will go through a version
3119 // of JIT_GenericHandle which logs the access. Note that we still want the dictionaries
3120 // to be populated to prepopulate the types at NGen time.
3121 if (IsCompilingForNGen() &&
3122 GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
3126 #endif // FEATURE_NATIVE_IMAGE_GENERATION
3128 if (pContextMD->RequiresInstMethodDescArg())
3130 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
3134 if (pContextMD->RequiresInstMethodTableArg())
3135 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
3137 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
3140 #ifdef FEATURE_READYTORUN_COMPILER
3141 if (IsReadyToRunCompilation())
3143 #if defined(_TARGET_ARM_)
3144 ThrowHR(E_NOTIMPL); /* TODO - NYI */
3146 pResultLookup->lookupKind.runtimeLookupArgs = NULL;
3150 case DeclaringTypeHandleSlot:
3151 _ASSERTE(pTemplateMD != NULL);
3152 pResultLookup->lookupKind.runtimeLookupArgs = pTemplateMD->GetMethodTable();
3153 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_DeclaringTypeHandle;
3156 case TypeHandleSlot:
3157 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_TypeHandle;
3160 case MethodDescSlot:
3161 case MethodEntrySlot:
3162 case ConstrainedMethodEntrySlot:
3163 case DispatchStubAddrSlot:
3165 if (pTemplateMD != (MethodDesc*)pResolvedToken->hMethod)
3168 if (entryKind == MethodDescSlot)
3169 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_MethodHandle;
3170 else if (entryKind == MethodEntrySlot || entryKind == ConstrainedMethodEntrySlot)
3171 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_MethodEntry;
3173 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_VirtualEntry;
3175 pResultLookup->lookupKind.runtimeLookupArgs = pConstrainedResolvedToken;
3181 pResultLookup->lookupKind.runtimeLookupFlags = READYTORUN_FIXUP_FieldHandle;
3185 _ASSERTE(!"Unknown dictionary entry kind!");
3186 IfFailThrow(E_FAIL);
3189 // For R2R compilations, we don't generate the dictionary lookup signatures (dictionary lookups are done in a
3190 // different way that is more version resilient... plus we can't have pointers to existing MTs/MDs in the sigs)
3194 // If we've got a method type parameter of any kind then we must look in the method desc arg
3195 if (pContextMD->RequiresInstMethodDescArg())
3197 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG : CORINFO_HELP_RUNTIMEHANDLE_METHOD;
3203 // (1) Naked method type variable: look up directly in instantiation hanging off runtime md
3204 // (2) Reference to method-spec of current method (e.g. a recursive call) i.e. currentmeth<!0,...,!(n-1)>
3205 if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3207 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3208 CorElementType type;
3209 IfFailThrow(sigptr.GetElemType(&type));
3210 if (type == ELEMENT_TYPE_MVAR)
3212 pResult->indirections = 2;
3213 pResult->testForNull = 0;
3214 #ifdef FEATURE_PREJIT
3215 pResult->testForFixup = 1;
3217 pResult->testForFixup = 0;
3219 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3221 if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
3223 pResult->indirectFirstOffset = 1;
3227 IfFailThrow(sigptr.GetData(&data));
3228 pResult->offsets[1] = sizeof(TypeHandle) * data;
3233 else if (entryKind == MethodDescSlot)
3235 // It's the context itself (i.e. a recursive call)
3236 if (!pTemplateMD->HasSameMethodDefAs(pContextMD))
3239 // Now just check that the instantiation is (!!0, ..., !!(n-1))
3240 if (!IsMethodSpecForTypicalInstantation(SigPointer(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)))
3243 // Type instantiation has to match too if there is one
3244 if (pContextMT->HasInstantiation())
3246 TypeHandle thTemplate(pResolvedToken->hClass);
3248 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3251 // This check filters out method instantiation on generic type definition, like G::M<!!0>()
3252 // We may not ever get it here. Filter it out just to be sure...
3253 if (pResolvedToken->pTypeSpec == NULL)
3256 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3260 // Just use the method descriptor that was passed in!
3261 pResult->indirections = 0;
3262 pResult->testForNull = 0;
3263 pResult->testForFixup = 0;
3268 // Otherwise we must just have class type variables
3271 _ASSERTE(pContextMT->GetNumGenericArgs() > 0);
3273 if (pContextMD->RequiresInstMethodTableArg())
3275 // If we've got a vtable extra argument, go through that
3276 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3278 // If we've got an object, go through its vtable
3281 _ASSERTE(pContextMD->AcquiresInstMethodTableFromThis());
3282 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3289 // (1) Naked class type variable: look up directly in instantiation hanging off vtable
3290 // (2) C<!0,...,!(n-1)> where C is the context's class and C is sealed: just return vtable ptr
3291 if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3293 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3294 CorElementType type;
3295 IfFailThrow(sigptr.GetElemType(&type));
3296 if (type == ELEMENT_TYPE_VAR)
3298 pResult->indirections = 3;
3299 pResult->testForNull = 0;
3300 #ifdef FEATURE_PREJIT
3301 pResult->testForFixup = 1;
3303 pResult->testForFixup = 0;
3305 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3306 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3308 IfFailThrow(sigptr.GetData(&data));
3309 pResult->offsets[2] = sizeof(TypeHandle) * data;
3311 if (MethodTable::IsPerInstInfoRelative())
3313 pResult->indirectFirstOffset = 1;
3314 pResult->indirectSecondOffset = 1;
3319 else if (type == ELEMENT_TYPE_GENERICINST &&
3320 (pContextMT->IsSealed() || pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM))
3322 TypeHandle thTemplate(pResolvedToken->hClass);
3324 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3327 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3330 // Just use the vtable pointer itself!
3331 pResult->indirections = 0;
3332 pResult->testForNull = 0;
3333 pResult->testForFixup = 0;
3342 SigBuilder sigBuilder;
3344 sigBuilder.AppendData(entryKind);
3346 if (pResultLookup->lookupKind.runtimeLookupKind != CORINFO_LOOKUP_METHODPARAM)
3348 _ASSERTE(pContextMT->GetNumDicts() > 0);
3349 sigBuilder.AppendData(pContextMT->GetNumDicts() - 1);
3352 Module * pModule = (Module *)pResolvedToken->tokenScope;
3356 case DeclaringTypeHandleSlot:
3357 _ASSERTE(pTemplateMD != NULL);
3358 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3359 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3362 case TypeHandleSlot:
3364 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
3366 if (!IsReadyToRunCompilation())
3368 sigBuilder.AppendElementType((CorElementType)ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
3371 sigBuilder.AppendElementType(ELEMENT_TYPE_SZARRAY);
3374 // Note that we can come here with pResolvedToken->pTypeSpec == NULL for invalid IL that
3375 // directly references __Canon
3376 if (pResolvedToken->pTypeSpec != NULL)
3378 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3379 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3383 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3384 sigBuilder.AppendPointer(pResolvedToken->hClass);
3389 case ConstrainedMethodEntrySlot:
3390 // Encode constrained type token
3391 if (pConstrainedResolvedToken->pTypeSpec != NULL)
3393 SigPointer sigptr(pConstrainedResolvedToken->pTypeSpec, pConstrainedResolvedToken->cbTypeSpec);
3394 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3398 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3399 sigBuilder.AppendPointer(pConstrainedResolvedToken->hClass);
3403 case MethodDescSlot:
3404 case MethodEntrySlot:
3405 case DispatchStubAddrSlot:
3407 // Encode containing type
3408 if (pResolvedToken->pTypeSpec != NULL)
3410 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3411 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3415 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3416 sigBuilder.AppendPointer(pResolvedToken->hClass);
3420 _ASSERTE(pTemplateMD != NULL);
3422 mdMethodDef methodToken = pTemplateMD->GetMemberDef_NoLogging();
3423 DWORD methodFlags = 0;
3425 // Check for non-NULL method spec first. We can encode the method instantiation only if we have one in method spec to start with. Note that there are weird cases
3426 // like instantiating stub for generic method definition that do not have method spec but that won't be caught by the later conditions either.
3427 BOOL fMethodNeedsInstantiation = (pResolvedToken->pMethodSpec != NULL) && pTemplateMD->HasMethodInstantiation() && !pTemplateMD->IsGenericMethodDefinition();
3429 if (pTemplateMD->IsUnboxingStub())
3430 methodFlags |= ENCODE_METHOD_SIG_UnboxingStub;
3431 // Always create instantiating stub for method entry points even if the template does not ask for it. It saves caller
3432 // from creating throw-away instantiating stub.
3433 if (pTemplateMD->IsInstantiatingStub() || (entryKind == MethodEntrySlot))
3434 methodFlags |= ENCODE_METHOD_SIG_InstantiatingStub;
3435 if (fMethodNeedsInstantiation)
3436 methodFlags |= ENCODE_METHOD_SIG_MethodInstantiation;
3437 if (IsNilToken(methodToken))
3439 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3442 if (entryKind == DispatchStubAddrSlot && pTemplateMD->IsVtableMethod())
3444 // Encode the method for dispatch stub using slot to avoid touching the interface method MethodDesc at runtime
3446 // There should be no other flags set if we are encoding the method using slot for virtual stub dispatch
3447 _ASSERTE(methodFlags == 0);
3449 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3452 if (!pTemplateMD->GetModule()->IsInCurrentVersionBubble())
3454 // Using a method defined in another version bubble. We can assume the slot number is stable only for real interface methods.
3455 if (!pTemplateMD->GetMethodTable()->IsInterface() || pTemplateMD->IsStatic() || pTemplateMD->HasMethodInstantiation())
3457 _ASSERTE(!"References to non-interface methods not yet supported in version resilient images");
3458 IfFailThrow(E_FAIL);
3460 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3463 sigBuilder.AppendData(methodFlags);
3465 if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
3467 // Encode method token and its module context (as method's type)
3468 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3469 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3471 sigBuilder.AppendData(RidFromToken(methodToken));
3475 sigBuilder.AppendData(pTemplateMD->GetSlot());
3478 if (fMethodNeedsInstantiation)
3480 SigPointer sigptr(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
3483 IfFailThrow(sigptr.GetByte(&etype));
3485 // Load the generic method instantiation
3486 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, pModule);
3488 DWORD nGenericMethodArgs;
3489 IfFailThrow(sigptr.GetData(&nGenericMethodArgs));
3490 sigBuilder.AppendData(nGenericMethodArgs);
3492 _ASSERTE(nGenericMethodArgs == pTemplateMD->GetNumGenericMethodArgs());
3494 for (DWORD i = 0; i < nGenericMethodArgs; i++)
3496 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3504 if (pResolvedToken->pTypeSpec != NULL)
3506 // Encode containing type
3507 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3508 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3512 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3513 sigBuilder.AppendPointer(pResolvedToken->hClass);
3516 FieldDesc * pField = (FieldDesc *)pResolvedToken->hField;
3517 _ASSERTE(pField != NULL);
3519 DWORD fieldIndex = pField->GetApproxEnclosingMethodTable()->GetIndexForFieldDesc(pField);
3520 sigBuilder.AppendData(fieldIndex);
3528 DictionaryEntrySignatureSource signatureSource = (IsCompilationProcess() ? FromZapImage : FromJIT);
3530 // It's a method dictionary lookup
3531 if (pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM)
3533 _ASSERTE(pContextMD != NULL);
3534 _ASSERTE(pContextMD->HasMethodInstantiation());
3536 if (DictionaryLayout::FindToken(pContextMD->GetLoaderAllocator(), pContextMD->GetNumGenericMethodArgs(), pContextMD->GetDictionaryLayout(), pResult, &sigBuilder, 1, signatureSource))
3538 pResult->testForNull = 1;
3539 pResult->testForFixup = 0;
3541 // Indirect through dictionary table pointer in InstantiatedMethodDesc
3542 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3544 if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
3546 pResult->indirectFirstOffset = 1;
3551 // It's a class dictionary lookup (CORINFO_LOOKUP_CLASSPARAM or CORINFO_LOOKUP_THISOBJ)
3554 if (DictionaryLayout::FindToken(pContextMT->GetLoaderAllocator(), pContextMT->GetNumGenericArgs(), pContextMT->GetClass()->GetDictionaryLayout(), pResult, &sigBuilder, 2, signatureSource))
3556 pResult->testForNull = 1;
3557 pResult->testForFixup = 0;
3559 // Indirect through dictionary table pointer in vtable
3560 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3562 // Next indirect through the dictionary appropriate to this instantiated type
3563 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3565 if (MethodTable::IsPerInstInfoRelative())
3567 pResult->indirectFirstOffset = 1;
3568 pResult->indirectSecondOffset = 1;
3576 /*********************************************************************/
3577 const char* CEEInfo::getClassName (CORINFO_CLASS_HANDLE clsHnd)
3586 const char* result = NULL;
3588 JIT_TO_EE_TRANSITION();
3590 TypeHandle VMClsHnd(clsHnd);
3591 MethodTable* pMT = VMClsHnd.GetMethodTable();
3599 result = pMT->GetDebugClassName();
3601 // since this is for diagnostic purposes only,
3602 // give up on the namespace, as we don't have a buffer to concat it
3603 // also note this won't show array class names.
3605 result = pMT->GetFullyQualifiedNameInfo(&nameSpace);
3609 EE_TO_JIT_TRANSITION();
3614 /***********************************************************************/
3615 const char* CEEInfo::getHelperName (CorInfoHelpFunc ftnNum)
3622 PRECONDITION(ftnNum >= 0 && ftnNum < CORINFO_HELP_COUNT);
3625 const char* result = NULL;
3627 JIT_TO_EE_TRANSITION_LEAF();
3629 #ifdef CROSSGEN_COMPILE
3630 result = hlpNameTable[ftnNum];
3633 result = hlpFuncTable[ftnNum].name;
3635 result = "AnyJITHelper";
3639 EE_TO_JIT_TRANSITION_LEAF();
3645 /*********************************************************************/
3646 int CEEInfo::appendClassName(__deref_inout_ecount(*pnBufLen) WCHAR** ppBuf,
3648 CORINFO_CLASS_HANDLE clsHnd,
3662 JIT_TO_EE_TRANSITION();
3664 TypeHandle th(clsHnd);
3666 TypeString::AppendType(ss,th,
3667 (fNamespace ? TypeString::FormatNamespace : 0) |
3668 (fFullInst ? TypeString::FormatFullInst : 0) |
3669 (fAssembly ? TypeString::FormatAssembly : 0));
3670 const WCHAR* szString = ss.GetUnicode();
3671 nLen = (int)wcslen(szString);
3674 wcscpy_s(*ppBuf, *pnBufLen, szString );
3675 (*ppBuf)[(*pnBufLen) - 1] = W('\0');
3677 (*pnBufLen) -= nLen;
3680 EE_TO_JIT_TRANSITION();
3685 /*********************************************************************/
3686 CORINFO_MODULE_HANDLE CEEInfo::getClassModule(CORINFO_CLASS_HANDLE clsHnd)
3695 CORINFO_MODULE_HANDLE result = NULL;
3697 JIT_TO_EE_TRANSITION_LEAF();
3699 TypeHandle VMClsHnd(clsHnd);
3701 result = CORINFO_MODULE_HANDLE(VMClsHnd.GetModule());
3703 EE_TO_JIT_TRANSITION_LEAF();
3708 /*********************************************************************/
3709 CORINFO_ASSEMBLY_HANDLE CEEInfo::getModuleAssembly(CORINFO_MODULE_HANDLE modHnd)
3718 CORINFO_ASSEMBLY_HANDLE result = NULL;
3720 JIT_TO_EE_TRANSITION_LEAF();
3722 result = CORINFO_ASSEMBLY_HANDLE(GetModule(modHnd)->GetAssembly());
3724 EE_TO_JIT_TRANSITION_LEAF();
3729 /*********************************************************************/
3730 const char* CEEInfo::getAssemblyName(CORINFO_ASSEMBLY_HANDLE asmHnd)
3739 const char* result = NULL;
3741 JIT_TO_EE_TRANSITION();
3742 result = ((Assembly*)asmHnd)->GetSimpleName();
3743 EE_TO_JIT_TRANSITION();
3748 /*********************************************************************/
3749 void* CEEInfo::LongLifetimeMalloc(size_t sz)
3758 void* result = NULL;
3760 JIT_TO_EE_TRANSITION_LEAF();
3761 result = new (nothrow) char[sz];
3762 EE_TO_JIT_TRANSITION_LEAF();
3767 /*********************************************************************/
3768 void CEEInfo::LongLifetimeFree(void* obj)
3777 JIT_TO_EE_TRANSITION_LEAF();
3778 (operator delete)(obj);
3779 EE_TO_JIT_TRANSITION_LEAF();
3782 /*********************************************************************/
3783 size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_MODULE_HANDLE *pModuleHandle, void **ppIndirection)
3794 JIT_TO_EE_TRANSITION_LEAF();
3796 TypeHandle VMClsHnd(clsHnd);
3797 Module *pModule = VMClsHnd.AsMethodTable()->GetModuleForStatics();
3799 if (ppIndirection != NULL)
3800 *ppIndirection = NULL;
3802 // The zapper needs the module handle. The jit should not use it at all.
3804 *pModuleHandle = CORINFO_MODULE_HANDLE(pModule);
3806 result = pModule->GetModuleID();
3810 EE_TO_JIT_TRANSITION_LEAF();
3815 /*********************************************************************/
3816 BOOL CEEInfo::isValueClass(CORINFO_CLASS_HANDLE clsHnd)
3827 JIT_TO_EE_TRANSITION_LEAF();
3831 // Note that clsHnd.IsValueType() would not return what the JIT expects
3832 // for corner cases like ELEMENT_TYPE_FNPTR
3833 TypeHandle VMClsHnd(clsHnd);
3834 MethodTable * pMT = VMClsHnd.GetMethodTable();
3835 ret = (pMT != NULL) ? pMT->IsValueType() : 0;
3837 EE_TO_JIT_TRANSITION_LEAF();
3842 /*********************************************************************/
3843 // If this method returns true, JIT will do optimization to inline the check for
3844 // GetClassFromHandle(handle) == obj.GetType()
3846 // This will enable to use directly the typehandle instead of going through getClassByHandle
3847 BOOL CEEInfo::canInlineTypeCheckWithObjectVTable (CORINFO_CLASS_HANDLE clsHnd)
3858 JIT_TO_EE_TRANSITION_LEAF();
3862 TypeHandle VMClsHnd(clsHnd);
3864 if (VMClsHnd.IsTypeDesc())
3866 // We can't do this optimization for arrays because of the object methodtable is template methodtable
3870 if (VMClsHnd.AsMethodTable()->IsMarshaledByRef())
3872 // We can't do this optimization for marshalbyrefs because of the object methodtable can be transparent proxy
3876 if (VMClsHnd.AsMethodTable()->IsInterface())
3878 // Object.GetType() should not ever return interface. However, WCF custom remoting proxy does it. Disable this
3879 // optimization for interfaces so that (autogenerated) code that compares Object.GetType() with interface type works
3880 // as expected for WCF custom remoting proxy. Note that this optimization is still not going to work well for custom
3881 // remoting proxies that are even more broken than the WCF one, e.g. returning random non-marshalbyref types
3882 // from Object.GetType().
3886 if (VMClsHnd == TypeHandle(g_pCanonMethodTableClass))
3888 // We can't do this optimization in shared generics code because of we do not know what the actual type is going to be.
3889 // (It can be array, marshalbyref, etc.)
3894 // It is safe to perform this optimization
3898 EE_TO_JIT_TRANSITION_LEAF();
3903 /*********************************************************************/
3904 DWORD CEEInfo::getClassAttribs (CORINFO_CLASS_HANDLE clsHnd)
3913 // <REVISIT_TODO>@todo FIX need to really fetch the class atributes. at present
3914 // we don't need to because the JIT only cares in the case of COM classes</REVISIT_TODO>
3917 JIT_TO_EE_TRANSITION();
3919 ret = getClassAttribsInternal(clsHnd);
3921 EE_TO_JIT_TRANSITION();
3927 /*********************************************************************/
3928 BOOL CEEInfo::isStructRequiringStackAllocRetBuf(CORINFO_CLASS_HANDLE clsHnd)
3939 JIT_TO_EE_TRANSITION_LEAF();
3941 TypeHandle VMClsHnd(clsHnd);
3942 MethodTable * pMT = VMClsHnd.GetMethodTable();
3943 ret = (pMT != NULL && pMT->IsStructRequiringStackAllocRetBuf());
3945 EE_TO_JIT_TRANSITION_LEAF();
3950 /*********************************************************************/
3951 DWORD CEEInfo::getClassAttribsInternal (CORINFO_CLASS_HANDLE clsHnd)
3953 STANDARD_VM_CONTRACT;
3959 TypeHandle VMClsHnd(clsHnd);
3961 // Byrefs should only occur in method and local signatures, which are accessed
3962 // using ICorClassInfo and ICorClassInfo.getChildType.
3963 // So getClassAttribs() should not be called for byrefs
3965 if (VMClsHnd.IsByRef())
3967 _ASSERTE(!"Did findClass() return a Byref?");
3968 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3970 else if (VMClsHnd.IsGenericVariable())
3972 //@GENERICSVER: for now, type variables simply report "variable".
3973 ret |= CORINFO_FLG_GENERIC_TYPE_VARIABLE;
3977 MethodTable *pMT = VMClsHnd.GetMethodTable();
3981 _ASSERTE(!"Did findClass() return a Byref?");
3982 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3985 EEClass * pClass = pMT->GetClass();
3987 // The array flag is used to identify the faked-up methods on
3988 // array types, i.e. .ctor, Get, Set and Address
3990 ret |= CORINFO_FLG_ARRAY;
3992 if (pMT->IsInterface())
3993 ret |= CORINFO_FLG_INTERFACE;
3995 if (pMT->HasComponentSize())
3996 ret |= CORINFO_FLG_VAROBJSIZE;
3998 if (pMT->IsValueType())
4000 ret |= CORINFO_FLG_VALUECLASS;
4002 if (pMT->IsByRefLike())
4003 ret |= CORINFO_FLG_CONTAINS_STACK_PTR;
4005 if ((pClass->IsNotTightlyPacked() && (!pClass->IsManagedSequential() || pClass->HasExplicitSize())) ||
4006 pMT == g_TypedReferenceMT ||
4007 VMClsHnd.IsNativeValueType())
4009 ret |= CORINFO_FLG_CUSTOMLAYOUT;
4012 if (pClass->IsUnsafeValueClass())
4013 ret |= CORINFO_FLG_UNSAFE_VALUECLASS;
4015 if (pClass->HasExplicitFieldOffsetLayout() && pClass->HasOverLayedField())
4016 ret |= CORINFO_FLG_OVERLAPPING_FIELDS;
4017 if (VMClsHnd.IsCanonicalSubtype())
4018 ret |= CORINFO_FLG_SHAREDINST;
4020 if (pMT->HasVariance())
4021 ret |= CORINFO_FLG_VARIANCE;
4023 if (pMT->IsContextful())
4024 ret |= CORINFO_FLG_CONTEXTFUL;
4026 if (pMT->IsMarshaledByRef())
4027 ret |= CORINFO_FLG_MARSHAL_BYREF;
4029 if (pMT->ContainsPointers() || pMT == g_TypedReferenceMT)
4030 ret |= CORINFO_FLG_CONTAINS_GC_PTR;
4032 if (pMT->IsDelegate())
4033 ret |= CORINFO_FLG_DELEGATE;
4035 if (pClass->IsBeforeFieldInit())
4037 if (IsReadyToRunCompilation() && !pMT->GetModule()->IsInCurrentVersionBubble())
4039 // For version resiliency do not allow hoisting static constructors out of loops
4043 ret |= CORINFO_FLG_BEFOREFIELDINIT;
4047 if (pClass->IsAbstract())
4048 ret |= CORINFO_FLG_ABSTRACT;
4050 if (pClass->IsSealed())
4051 ret |= CORINFO_FLG_FINAL;
4057 /*********************************************************************/
4059 // See code:CorInfoFlag#ClassConstructionFlags for details.
4061 CorInfoInitClassResult CEEInfo::initClass(
4062 CORINFO_FIELD_HANDLE field,
4063 CORINFO_METHOD_HANDLE method,
4064 CORINFO_CONTEXT_HANDLE context,
4074 DWORD result = CORINFO_INITCLASS_NOT_REQUIRED;
4076 JIT_TO_EE_TRANSITION();
4079 // Do not bother figuring out the initialization if we are only verifying the method.
4082 result = CORINFO_INITCLASS_NOT_REQUIRED;
4086 FieldDesc * pFD = (FieldDesc *)field;
4087 _ASSERTE(pFD == NULL || pFD->IsStatic());
4089 MethodDesc * pMD = (MethodDesc *)method;
4091 TypeHandle typeToInitTH = (pFD != NULL) ? pFD->GetEnclosingMethodTable() : GetTypeFromContext(context);
4093 MethodDesc *methodBeingCompiled = m_pMethodBeingCompiled;
4095 BOOL fMethodDomainNeutral = methodBeingCompiled->IsDomainNeutral() || methodBeingCompiled->IsZapped() || IsCompilingForNGen();
4097 MethodTable *pTypeToInitMT = typeToInitTH.AsMethodTable();
4099 // This should be the most common early-out case.
4100 if (fMethodDomainNeutral)
4102 if (pTypeToInitMT->IsClassPreInited())
4104 result = CORINFO_INITCLASS_NOT_REQUIRED;
4110 #ifdef CROSSGEN_COMPILE
4112 #else // CROSSGEN_COMPILE
4113 if (pTypeToInitMT->IsClassInited())
4115 // If the type is initialized there really is nothing to do.
4116 result = CORINFO_INITCLASS_INITIALIZED;
4119 #endif // CROSSGEN_COMPILE
4122 if (pTypeToInitMT->IsGlobalClass())
4124 // For both jitted and ngen code the global class is always considered initialized
4125 result = CORINFO_INITCLASS_NOT_REQUIRED;
4129 bool fIgnoreBeforeFieldInit = false;
4133 if (!fIgnoreBeforeFieldInit && pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4135 // We can wait for field accesses to run .cctor
4136 result = CORINFO_INITCLASS_NOT_REQUIRED;
4140 // Run .cctor on statics & constructors
4141 if (pMD->IsStatic())
4143 // Except don't class construct on .cctor - it would be circular
4144 if (pMD->IsClassConstructor())
4146 result = CORINFO_INITCLASS_NOT_REQUIRED;
4151 // According to the spec, we should be able to do this optimization for both reference and valuetypes.
4152 // To maintain backward compatibility, we are doing it for reference types only.
4153 if (!pMD->IsCtor() && !pTypeToInitMT->IsValueType())
4155 // For instance methods of types with precise-initialization
4156 // semantics, we can assume that the .ctor triggerred the
4157 // type initialization.
4158 // This does not hold for NULL "this" object. However, the spec does
4159 // not require that case to work.
4160 result = CORINFO_INITCLASS_NOT_REQUIRED;
4165 if (pTypeToInitMT->IsSharedByGenericInstantiations())
4167 // Shared generic code has to use helper. Moreover, tell JIT not to inline since
4168 // inlining of generic dictionary lookups is not supported.
4169 result = CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE;
4174 // Try to prove that the initialization is not necessary because of nesting
4180 _ASSERTE(fIgnoreBeforeFieldInit || !pTypeToInitMT->GetClass()->IsBeforeFieldInit());
4182 // Note that jit has both methods the same if asking whether to emit cctor
4183 // for a given method's code (as opposed to inlining codegen).
4184 if (context != MAKE_METHODCONTEXT(methodBeingCompiled) && pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4186 // If we're inling a call to a method in our own type, then we should already
4187 // have triggered the .cctor when caller was itself called.
4188 result = CORINFO_INITCLASS_NOT_REQUIRED;
4194 // This optimization may cause static fields in reference types to be accessed without cctor being triggered
4195 // for NULL "this" object. It does not conform with what the spec says. However, we have been historically
4196 // doing it for perf reasons.
4197 if (!pTypeToInitMT->IsValueType() && !pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4199 if (pTypeToInitMT == GetTypeFromContext(context).AsMethodTable() || pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4201 // The class will be initialized by the time we access the field.
4202 result = CORINFO_INITCLASS_NOT_REQUIRED;
4207 // If we are currently compiling the class constructor for this static field access then we can skip the initClass
4208 if (methodBeingCompiled->GetMethodTable() == pTypeToInitMT && methodBeingCompiled->IsStatic() && methodBeingCompiled->IsClassConstructor())
4210 // The class will be initialized by the time we access the field.
4211 result = CORINFO_INITCLASS_NOT_REQUIRED;
4216 if (fMethodDomainNeutral)
4218 // Well, because of code sharing we can't do anything at coge generation time.
4219 // We have to do it at runtime.
4220 result = CORINFO_INITCLASS_USE_HELPER;
4224 #ifndef CROSSGEN_COMPILE
4226 // Optimizations for domain specific code
4229 // Allocate space for the local class if necessary, but don't trigger
4230 // class construction.
4231 DomainLocalModule *pModule = pTypeToInitMT->GetDomainLocalModule();
4232 pModule->PopulateClass(pTypeToInitMT);
4234 if (pTypeToInitMT->IsClassInited())
4236 result = CORINFO_INITCLASS_INITIALIZED;
4240 #ifdef FEATURE_MULTICOREJIT
4241 // Once multicore JIT is enabled in an AppDomain by calling SetProfileRoot, always use helper function to call class init, for consistency
4242 if (! GetAppDomain()->GetMulticoreJitManager().AllowCCtorsToRunDuringJITing())
4244 result = CORINFO_INITCLASS_USE_HELPER;
4250 // To preserve consistent behavior between ngen and not-ngenned states, do not eagerly
4251 // run class constructors for autongennable code.
4252 if (pTypeToInitMT->RunCCTorAsIfNGenImageExists())
4254 result = CORINFO_INITCLASS_USE_HELPER;
4258 if (!pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4260 // Do not inline the access if we cannot initialize the class. Chances are that the class will get
4261 // initialized by the time the access is jitted.
4262 result = CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE;
4268 // Tell the JIT that we may be able to initialize the class when asked to.
4269 result = CORINFO_INITCLASS_SPECULATIVE;
4274 // We cannot run the class constructor without first activating the
4275 // module containing the class. However, since the current module
4276 // we are compiling inside is not active, we don't want to do this.
4278 // This should be an unusal case since normally the method's module should
4279 // be active during jitting.
4281 // @TODO: We should check IsActivating() instead of IsActive() since we may
4282 // be running the Module::.cctor(). The assembly is not marked as active
4284 if (!methodBeingCompiled->GetLoaderModule()->GetDomainFile()->IsActive())
4286 result = CORINFO_INITCLASS_USE_HELPER;
4296 pTypeToInitMT->CheckRunClassInitThrowing();
4300 } EX_END_CATCH(SwallowAllExceptions);
4302 if (pTypeToInitMT->IsClassInited())
4304 result = CORINFO_INITCLASS_INITIALIZED;
4307 #endif // CROSSGEN_COMPILE
4309 // Do not inline the access if we were unable to initialize the class. Chances are that the class will get
4310 // initialized by the time the access is jitted.
4311 result = (CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE);
4315 EE_TO_JIT_TRANSITION();
4317 return (CorInfoInitClassResult)result;
4322 void CEEInfo::classMustBeLoadedBeforeCodeIsRun (CORINFO_CLASS_HANDLE typeToLoadHnd)
4331 JIT_TO_EE_TRANSITION_LEAF();
4333 TypeHandle th = TypeHandle(typeToLoadHnd);
4335 // Type handles returned to JIT at runtime are always fully loaded. Verify that it is the case.
4336 _ASSERTE(th.IsFullyLoaded());
4338 EE_TO_JIT_TRANSITION_LEAF();
4341 /*********************************************************************/
4342 void CEEInfo::methodMustBeLoadedBeforeCodeIsRun (CORINFO_METHOD_HANDLE methHnd)
4351 JIT_TO_EE_TRANSITION_LEAF();
4353 MethodDesc *pMD = (MethodDesc*) methHnd;
4355 // MethodDescs returned to JIT at runtime are always fully loaded. Verify that it is the case.
4356 _ASSERTE(pMD->IsRestored() && pMD->GetMethodTable()->IsFullyLoaded());
4358 EE_TO_JIT_TRANSITION_LEAF();
4361 /*********************************************************************/
4362 CORINFO_METHOD_HANDLE CEEInfo::mapMethodDeclToMethodImpl(CORINFO_METHOD_HANDLE methHnd)
4371 CORINFO_METHOD_HANDLE result = NULL;
4373 JIT_TO_EE_TRANSITION();
4375 MethodDesc *pMD = GetMethod(methHnd);
4376 pMD = MethodTable::MapMethodDeclToMethodImpl(pMD);
4377 result = (CORINFO_METHOD_HANDLE) pMD;
4379 EE_TO_JIT_TRANSITION();
4384 /*********************************************************************/
4385 CORINFO_CLASS_HANDLE CEEInfo::getBuiltinClass(CorInfoClassId classId)
4394 CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE) 0;
4396 JIT_TO_EE_TRANSITION();
4400 case CLASSID_SYSTEM_OBJECT:
4401 result = CORINFO_CLASS_HANDLE(g_pObjectClass);
4403 case CLASSID_TYPED_BYREF:
4404 result = CORINFO_CLASS_HANDLE(g_TypedReferenceMT);
4406 case CLASSID_TYPE_HANDLE:
4407 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__TYPE_HANDLE));
4409 case CLASSID_FIELD_HANDLE:
4410 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__FIELD_HANDLE));
4412 case CLASSID_METHOD_HANDLE:
4413 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__METHOD_HANDLE));
4415 case CLASSID_ARGUMENT_HANDLE:
4416 result = CORINFO_CLASS_HANDLE(MscorlibBinder::GetClass(CLASS__ARGUMENT_HANDLE));
4418 case CLASSID_STRING:
4419 result = CORINFO_CLASS_HANDLE(g_pStringClass);
4421 case CLASSID_RUNTIME_TYPE:
4422 result = CORINFO_CLASS_HANDLE(g_pRuntimeTypeClass);
4425 _ASSERTE(!"NYI: unknown classId");
4429 EE_TO_JIT_TRANSITION();
4436 /*********************************************************************/
4437 CorInfoType CEEInfo::getTypeForPrimitiveValueClass(
4438 CORINFO_CLASS_HANDLE clsHnd)
4447 CorInfoType result = CORINFO_TYPE_UNDEF;
4449 JIT_TO_EE_TRANSITION();
4451 TypeHandle th(clsHnd);
4452 _ASSERTE (!th.IsGenericVariable());
4454 MethodTable *pMT = th.GetMethodTable();
4455 PREFIX_ASSUME(pMT != NULL);
4457 // Is it a non primitive struct such as
4458 // RuntimeTypeHandle, RuntimeMethodHandle, RuntimeArgHandle?
4459 if (pMT->IsValueType() &&
4460 !pMT->IsTruePrimitive() &&
4463 // default value CORINFO_TYPE_UNDEF is what we want
4467 switch (th.GetInternalCorElementType())
4469 case ELEMENT_TYPE_I1:
4470 case ELEMENT_TYPE_U1:
4471 case ELEMENT_TYPE_BOOLEAN:
4472 result = asCorInfoType(ELEMENT_TYPE_I1);
4475 case ELEMENT_TYPE_I2:
4476 case ELEMENT_TYPE_U2:
4477 case ELEMENT_TYPE_CHAR:
4478 result = asCorInfoType(ELEMENT_TYPE_I2);
4481 case ELEMENT_TYPE_I4:
4482 case ELEMENT_TYPE_U4:
4483 result = asCorInfoType(ELEMENT_TYPE_I4);
4486 case ELEMENT_TYPE_I8:
4487 case ELEMENT_TYPE_U8:
4488 result = asCorInfoType(ELEMENT_TYPE_I8);
4491 case ELEMENT_TYPE_I:
4492 case ELEMENT_TYPE_U:
4493 result = asCorInfoType(ELEMENT_TYPE_I);
4496 case ELEMENT_TYPE_R4:
4497 result = asCorInfoType(ELEMENT_TYPE_R4);
4500 case ELEMENT_TYPE_R8:
4501 result = asCorInfoType(ELEMENT_TYPE_R8);
4504 case ELEMENT_TYPE_VOID:
4505 result = asCorInfoType(ELEMENT_TYPE_VOID);
4508 case ELEMENT_TYPE_PTR:
4509 case ELEMENT_TYPE_FNPTR:
4510 result = asCorInfoType(ELEMENT_TYPE_PTR);
4518 EE_TO_JIT_TRANSITION();
4524 void CEEInfo::getGSCookie(GSCookie * pCookieVal, GSCookie ** ppCookieVal)
4533 JIT_TO_EE_TRANSITION();
4537 *pCookieVal = GetProcessGSCookie();
4538 *ppCookieVal = NULL;
4542 *ppCookieVal = GetProcessGSCookiePtr();
4545 EE_TO_JIT_TRANSITION();
4549 /*********************************************************************/
4550 // TRUE if child is a subtype of parent
4551 // if parent is an interface, then does child implement / extend parent
4552 BOOL CEEInfo::canCast(
4553 CORINFO_CLASS_HANDLE child,
4554 CORINFO_CLASS_HANDLE parent)
4563 BOOL result = FALSE;
4565 JIT_TO_EE_TRANSITION();
4567 result = ((TypeHandle)child).CanCastTo((TypeHandle)parent);
4569 EE_TO_JIT_TRANSITION();
4574 /*********************************************************************/
4575 // TRUE if cls1 and cls2 are considered equivalent types.
4576 BOOL CEEInfo::areTypesEquivalent(
4577 CORINFO_CLASS_HANDLE cls1,
4578 CORINFO_CLASS_HANDLE cls2)
4587 BOOL result = FALSE;
4589 JIT_TO_EE_TRANSITION();
4591 result = ((TypeHandle)cls1).IsEquivalentTo((TypeHandle)cls2);
4593 EE_TO_JIT_TRANSITION();
4598 /*********************************************************************/
4599 // returns is the intersection of cls1 and cls2.
4600 CORINFO_CLASS_HANDLE CEEInfo::mergeClasses(
4601 CORINFO_CLASS_HANDLE cls1,
4602 CORINFO_CLASS_HANDLE cls2)
4611 CORINFO_CLASS_HANDLE result = NULL;
4613 JIT_TO_EE_TRANSITION();
4615 TypeHandle merged = TypeHandle::MergeTypeHandlesToCommonParent(TypeHandle(cls1), TypeHandle(cls2));
4618 //Make sure the merge is reflexive in the cases we "support".
4619 TypeHandle hnd1 = TypeHandle(cls1);
4620 TypeHandle hnd2 = TypeHandle(cls2);
4621 TypeHandle reflexive = TypeHandle::MergeTypeHandlesToCommonParent(hnd2, hnd1);
4623 //If both sides are classes than either they have a common non-interface parent (in which case it is
4625 //OR they share a common interface, and it can be order dependent (if they share multiple interfaces
4627 if (!hnd1.IsInterface() && !hnd2.IsInterface())
4629 if (merged.IsInterface())
4631 _ASSERTE(reflexive.IsInterface());
4635 _ASSERTE(merged == reflexive);
4638 //Both results must either be interfaces or classes. They cannot be mixed.
4639 _ASSERTE((!!merged.IsInterface()) == (!!reflexive.IsInterface()));
4641 //If the result of the merge was a class, then the result of the reflexive merge was the same class.
4642 if (!merged.IsInterface())
4644 _ASSERTE(merged == reflexive);
4647 //If both sides are arrays, then the result is either an array or g_pArrayClass. The above is
4648 //actually true about the element type for references types, but I think that that is a little
4649 //excessive for sanity.
4650 if (hnd1.IsArray() && hnd2.IsArray())
4652 _ASSERTE((merged.IsArray() && reflexive.IsArray())
4653 || ((merged == g_pArrayClass) && (reflexive == g_pArrayClass)));
4656 //Can I assert anything about generic variables?
4658 //The results must always be assignable
4659 _ASSERTE(hnd1.CanCastTo(merged) && hnd2.CanCastTo(merged) && hnd1.CanCastTo(reflexive)
4660 && hnd2.CanCastTo(reflexive));
4663 result = CORINFO_CLASS_HANDLE(merged.AsPtr());
4665 EE_TO_JIT_TRANSITION();
4669 /*********************************************************************/
4670 // Given a class handle, returns the Parent type.
4671 // For COMObjectType, it returns Class Handle of System.Object.
4672 // Returns 0 if System.Object is passed in.
4673 CORINFO_CLASS_HANDLE CEEInfo::getParentType(
4674 CORINFO_CLASS_HANDLE cls)
4683 CORINFO_CLASS_HANDLE result = NULL;
4685 JIT_TO_EE_TRANSITION();
4689 _ASSERTE(!th.IsNull());
4690 _ASSERTE(!th.IsGenericVariable());
4692 TypeHandle thParent = th.GetParent();
4694 #ifdef FEATURE_COMINTEROP
4695 // If we encounter __ComObject in the hierarchy, we need to skip it
4696 // since this hierarchy is introduced by the EE, but won't be present
4698 if (!thParent.IsNull() && IsComObjectClass(thParent))
4700 result = (CORINFO_CLASS_HANDLE) g_pObjectClass;
4703 #endif // FEATURE_COMINTEROP
4705 result = CORINFO_CLASS_HANDLE(thParent.AsPtr());
4708 EE_TO_JIT_TRANSITION();
4714 /*********************************************************************/
4715 // Returns the CorInfoType of the "child type". If the child type is
4716 // not a primitive type, *clsRet will be set.
4717 // Given an Array of Type Foo, returns Foo.
4718 // Given BYREF Foo, returns Foo
4719 CorInfoType CEEInfo::getChildType (
4720 CORINFO_CLASS_HANDLE clsHnd,
4721 CORINFO_CLASS_HANDLE *clsRet
4731 CorInfoType ret = CORINFO_TYPE_UNDEF;
4733 TypeHandle retType = TypeHandle();
4735 JIT_TO_EE_TRANSITION();
4737 TypeHandle th(clsHnd);
4739 _ASSERTE(!th.IsNull());
4741 // BYREF, ARRAY types
4742 if (th.IsTypeDesc())
4744 retType = th.AsTypeDesc()->GetTypeParam();
4748 // <REVISIT_TODO> we really should not have this case. arrays type handles
4749 // used in the JIT interface should never be ordinary method tables,
4750 // indeed array type handles should really never be ordinary MTs
4751 // at all. Perhaps we should assert !th.IsTypeDesc() && th.AsMethodTable().IsArray()? </REVISIT_TODO>
4752 MethodTable* pMT= th.AsMethodTable();
4754 retType = pMT->GetApproxArrayElementTypeHandle();
4757 if (!retType.IsNull()) {
4758 CorElementType type = retType.GetInternalCorElementType();
4759 ret = CEEInfo::asCorInfoType(type,retType, clsRet);
4761 // <REVISIT_TODO>What if this one is a value array ?</REVISIT_TODO>
4764 EE_TO_JIT_TRANSITION();
4769 /*********************************************************************/
4770 // Check any constraints on class type arguments
4771 BOOL CEEInfo::satisfiesClassConstraints(CORINFO_CLASS_HANDLE cls)
4780 BOOL result = FALSE;
4782 JIT_TO_EE_TRANSITION();
4784 _ASSERTE(cls != NULL);
4785 result = TypeHandle(cls).SatisfiesClassConstraints();
4787 EE_TO_JIT_TRANSITION();
4792 /*********************************************************************/
4793 // Check if this is a single dimensional array type
4794 BOOL CEEInfo::isSDArray(CORINFO_CLASS_HANDLE cls)
4803 BOOL result = FALSE;
4805 JIT_TO_EE_TRANSITION();
4809 _ASSERTE(!th.IsNull());
4811 if (th.IsArrayType())
4813 // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4814 _ASSERTE(th != TypeHandle(g_pArrayClass));
4816 result = (th.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
4819 EE_TO_JIT_TRANSITION();
4824 /*********************************************************************/
4825 // Get the number of dimensions in an array
4826 unsigned CEEInfo::getArrayRank(CORINFO_CLASS_HANDLE cls)
4835 unsigned result = 0;
4837 JIT_TO_EE_TRANSITION();
4841 _ASSERTE(!th.IsNull());
4843 if (th.IsArrayType())
4845 // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4846 _ASSERTE(th != TypeHandle(g_pArrayClass));
4848 result = th.GetPossiblySharedArrayMethodTable()->GetRank();
4851 EE_TO_JIT_TRANSITION();
4856 /*********************************************************************/
4857 // Get static field data for an array
4858 // Note that it's OK to return NULL from this method. This will cause
4859 // the JIT to make a runtime call to InitializeArray instead of doing
4860 // the inline optimization (thus preserving the original behavior).
4861 void * CEEInfo::getArrayInitializationData(
4862 CORINFO_FIELD_HANDLE field,
4873 void * result = NULL;
4875 JIT_TO_EE_TRANSITION();
4877 FieldDesc* pField = (FieldDesc*) field;
4881 (pField->LoadSize() < size)
4882 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
4883 // This will make sure that when IBC logging is on, the array initialization happens thru
4884 // COMArrayInfo::InitializeArray. This gives a place to put the IBC probe that can help
4885 // separate hold and cold RVA blobs.
4886 || (IsCompilingForNGen() &&
4887 GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
4888 #endif // FEATURE_NATIVE_IMAGE_GENERATION
4895 result = pField->GetStaticAddressHandle(NULL);
4898 EE_TO_JIT_TRANSITION();
4903 CorInfoIsAccessAllowedResult CEEInfo::canAccessClass(
4904 CORINFO_RESOLVED_TOKEN * pResolvedToken,
4905 CORINFO_METHOD_HANDLE callerHandle,
4906 CORINFO_HELPER_DESC *pAccessHelper
4916 CorInfoIsAccessAllowedResult isAccessAllowed = CORINFO_ACCESS_ALLOWED;
4918 JIT_TO_EE_TRANSITION();
4920 INDEBUG(memset(pAccessHelper, 0xCC, sizeof(*pAccessHelper)));
4922 BOOL doAccessCheck = TRUE;
4923 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
4924 DynamicResolver * pAccessContext = NULL;
4926 //All access checks must be done on the open instantiation.
4927 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
4928 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
4930 TypeHandle pCalleeForSecurity = TypeHandle(pResolvedToken->hClass);
4931 if (pResolvedToken->pTypeSpec != NULL)
4933 SigTypeContext typeContext;
4934 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
4936 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
4937 pCalleeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
4940 while (pCalleeForSecurity.HasTypeParam())
4942 pCalleeForSecurity = pCalleeForSecurity.GetTypeParam();
4945 if (IsDynamicScope(pResolvedToken->tokenScope))
4947 doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope),
4948 &callerTypeForSecurity, &accessCheckType,
4952 //Since this is a check against a TypeHandle, there are some things we can stick in a TypeHandle that
4953 //don't require access checks.
4954 if (pCalleeForSecurity.IsGenericVariable())
4956 //I don't need to check for access against !!0.
4957 doAccessCheck = FALSE;
4960 //Now do the visibility checks
4963 AccessCheckOptions accessCheckOptions(accessCheckType,
4965 FALSE /*throw on error*/,
4966 pCalleeForSecurity.GetMethodTable());
4968 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
4969 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
4971 BOOL canAccessType = ClassLoader::CanAccessClass(&accessContext,
4972 pCalleeForSecurity.GetMethodTable(),
4973 pCalleeForSecurity.GetAssembly(),
4974 accessCheckOptions);
4976 isAccessAllowed = canAccessType ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
4980 if (isAccessAllowed != CORINFO_ACCESS_ALLOWED)
4982 //These all get the throw helper
4983 pAccessHelper->helperNum = CORINFO_HELP_CLASS_ACCESS_EXCEPTION;
4984 pAccessHelper->numArgs = 2;
4986 pAccessHelper->args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
4987 pAccessHelper->args[1].Set(CORINFO_CLASS_HANDLE(pCalleeForSecurity.AsPtr()));
4989 if (IsCompilingForNGen())
4991 //see code:CEEInfo::getCallInfo for more information.
4992 if (pCallerForSecurity->ContainsGenericVariables() || pCalleeForSecurity.ContainsGenericVariables())
4993 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic TypeHandle"));
4997 if (isAccessAllowed == CORINFO_ACCESS_ALLOWED)
4999 //Finally let's get me some transparency checks.
5000 CorInfoSecurityRuntimeChecks runtimeChecks = CORINFO_ACCESS_SECURITY_NONE;
5003 DebugSecurityCalloutStress(getMethodBeingCompiled(), isAccessAllowed,
5006 if (isAccessAllowed != CORINFO_ACCESS_ALLOWED)
5008 _ASSERTE(isAccessAllowed == CORINFO_ACCESS_RUNTIME_CHECK);
5009 //Well, time for the runtime helper
5010 pAccessHelper->helperNum = CORINFO_HELP_CLASS_ACCESS_CHECK;
5011 pAccessHelper->numArgs = 3;
5013 pAccessHelper->args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5014 pAccessHelper->args[1].Set(CORINFO_CLASS_HANDLE(pCalleeForSecurity.AsPtr()));
5015 pAccessHelper->args[2].Set(runtimeChecks);
5017 if (IsCompilingForNGen())
5019 //see code:CEEInfo::getCallInfo for more information.
5020 if (pCallerForSecurity->ContainsGenericVariables() || pCalleeForSecurity.ContainsGenericVariables())
5021 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic TypeHandle"));
5026 EE_TO_JIT_TRANSITION();
5027 return isAccessAllowed;
5030 /***********************************************************************/
5031 // return the address of a pointer to a callable stub that will do the
5032 // virtual or interface call
5033 void CEEInfo::getCallInfo(
5034 CORINFO_RESOLVED_TOKEN * pResolvedToken,
5035 CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
5036 CORINFO_METHOD_HANDLE callerHandle,
5037 CORINFO_CALLINFO_FLAGS flags,
5038 CORINFO_CALL_INFO *pResult /*out */)
5047 JIT_TO_EE_TRANSITION();
5049 _ASSERTE(CheckPointer(pResult));
5051 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
5053 MethodDesc* pMD = (MethodDesc *)pResolvedToken->hMethod;
5054 TypeHandle th(pResolvedToken->hClass);
5057 _ASSERTE((size_t(pMD) & 0x1) == 0);
5059 // Spec says that a callvirt lookup ignores static methods. Since static methods
5060 // can't have the exact same signature as instance methods, a lookup that found
5061 // a static method would have never found an instance method.
5062 if (pMD->IsStatic() && (flags & CORINFO_CALLINFO_CALLVIRT))
5064 EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, W("?")));
5069 TypeHandle exactType = TypeHandle(pResolvedToken->hClass);
5071 TypeHandle constrainedType;
5072 if ((flags & CORINFO_CALLINFO_CALLVIRT) && (pConstrainedResolvedToken != NULL))
5074 constrainedType = TypeHandle(pConstrainedResolvedToken->hClass);
5077 BOOL fResolvedConstraint = FALSE;
5078 BOOL fForceUseRuntimeLookup = FALSE;
5080 MethodDesc * pMDAfterConstraintResolution = pMD;
5081 if (constrainedType.IsNull())
5083 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5085 // <NICE> Things go wrong when this code path is used when verifying generic code.
5086 // It would be nice if we didn't go down this sort of code path when verifying but
5087 // not generating code. </NICE>
5088 else if (constrainedType.ContainsGenericVariables() || exactType.ContainsGenericVariables())
5090 // <NICE> It shouldn't really matter what we do here - but the x86 JIT is annoyingly sensitive
5091 // about what we do, since it pretend generic variables are reference types and generates
5092 // an internal JIT tree even when just verifying generic code. </NICE>
5093 if (constrainedType.IsGenericVariable())
5095 pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &T --> T
5097 else if (constrainedType.IsValueType())
5099 pResult->thisTransform = CORINFO_BOX_THIS; // convert 'this' of type &VC<T> --> boxed(VC<T>)
5103 pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &C<T> --> C<T>
5108 // We have a "constrained." call. Try a partial resolve of the constraint call. Note that this
5109 // will not necessarily resolve the call exactly, since we might be compiling
5110 // shared generic code - it may just resolve it to a candidate suitable for
5111 // JIT compilation, and require a runtime lookup for the actual code pointer
5113 if (constrainedType.IsEnum())
5115 // Optimize constrained calls to enum's GetHashCode method. TryResolveConstraintMethodApprox would return
5116 // null since the virtual method resolves to System.Enum's implementation and that's a reference type.
5117 // We can't do this for any other method since ToString and Equals have different semantics for enums
5118 // and their underlying type.
5119 if (pMD->GetSlot() == MscorlibBinder::GetMethod(METHOD__OBJECT__GET_HASH_CODE)->GetSlot())
5121 // Pretend this was a "constrained. UnderlyingType" instruction prefix
5122 constrainedType = TypeHandle(MscorlibBinder::GetElementType(constrainedType.GetVerifierCorElementType()));
5124 // Native image signature encoder will use this field. It needs to match that pretended type, a bogus signature
5125 // would be produced otherwise.
5126 pConstrainedResolvedToken->hClass = (CORINFO_CLASS_HANDLE)constrainedType.AsPtr();
5128 // Clear the token and typespec because of they do not match hClass anymore.
5129 pConstrainedResolvedToken->token = mdTokenNil;
5130 pConstrainedResolvedToken->pTypeSpec = NULL;
5134 MethodDesc * directMethod = constrainedType.GetMethodTable()->TryResolveConstraintMethodApprox(
5137 &fForceUseRuntimeLookup);
5141 // 1. no constraint resolution at compile time (!directMethod)
5142 // OR 2. no code sharing lookup in call
5143 // OR 3. we have have resolved to an instantiating stub
5145 pMDAfterConstraintResolution = directMethod;
5146 _ASSERTE(!pMDAfterConstraintResolution->IsInterface());
5147 fResolvedConstraint = TRUE;
5148 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5150 exactType = constrainedType;
5152 else if (constrainedType.IsValueType())
5154 pResult->thisTransform = CORINFO_BOX_THIS;
5158 pResult->thisTransform = CORINFO_DEREF_THIS;
5163 // Initialize callee context used for inlining and instantiation arguments
5166 MethodDesc * pTargetMD = pMDAfterConstraintResolution;
5168 if (pTargetMD->HasMethodInstantiation())
5170 pResult->contextHandle = MAKE_METHODCONTEXT(pTargetMD);
5171 pResult->exactContextNeedsRuntimeLookup = pTargetMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(pTargetMD->GetMethodInstantiation());
5175 if (!exactType.IsTypeDesc())
5177 // Because of .NET's notion of base calls, exactType may point to a sub-class
5178 // of the actual class that defines pTargetMD. If the JIT decides to inline, it is
5179 // important that they 'match', so we fix exactType here.
5180 #ifdef FEATURE_READYTORUN_COMPILER
5181 if (IsReadyToRunCompilation() &&
5183 !IsInSameVersionBubble((MethodDesc*)callerHandle, pTargetMD))
5185 // For version resilient code we can only inline within the same version bubble;
5186 // we "repair" the precise types only for those callees.
5187 // The above condition needs to stay in sync with CEEInfo::canInline
5193 exactType = pTargetMD->GetExactDeclaringType(exactType.AsMethodTable());
5194 _ASSERTE(!exactType.IsNull());
5198 pResult->contextHandle = MAKE_CLASSCONTEXT(exactType.AsPtr());
5199 pResult->exactContextNeedsRuntimeLookup = exactType.IsSharedByGenericInstantiations();
5203 // Determine whether to perform direct call
5206 bool directCall = false;
5207 bool resolvedCallVirt = false;
5208 bool callVirtCrossingVersionBubble = false;
5210 // Delegate targets are always treated as direct calls here. (It would be nice to clean it up...).
5211 if (flags & CORINFO_CALLINFO_LDFTN)
5213 if (m_pOverride != NULL)
5214 TypeEquivalenceFixupSpecificationHelper(m_pOverride, pTargetMD);
5218 // Static methods are always direct calls
5219 if (pTargetMD->IsStatic())
5224 // Force all interface calls to be interpreted as if they are virtual.
5225 if (pTargetMD->GetMethodTable()->IsInterface())
5230 if (!(flags & CORINFO_CALLINFO_CALLVIRT) || fResolvedConstraint)
5238 #ifdef FEATURE_READYTORUN_COMPILER
5240 // if we are generating version resilient code
5242 // caller/callee are in different version bubbles
5243 // we have to apply more restrictive rules
5244 // These rules are related to the "inlining rules" as far as the
5245 // boundaries of a version bubble are concerned.
5247 if (IsReadyToRunCompilation() &&
5249 !IsInSameVersionBubble((MethodDesc*)callerHandle, pTargetMD)
5252 // For version resiliency we won't de-virtualize all final/sealed method calls. Because during a
5253 // servicing event it is legal to unseal a method or type.
5255 // Note that it is safe to devirtualize in the following cases, since a servicing event cannot later modify it
5256 // 1) Callvirt on a virtual final method of a value type - since value types are sealed types as per ECMA spec
5257 // 2) Delegate.Invoke() - since a Delegate is a sealed class as per ECMA spec
5258 // 3) JIT intrinsics - since they have pre-defined behavior
5259 devirt = pTargetMD->GetMethodTable()->IsValueType() ||
5260 (pTargetMD->GetMethodTable()->IsDelegate() && ((DelegateEEClass*)(pTargetMD->GetMethodTable()->GetClass()))->GetInvokeMethod() == pMD) ||
5261 (pTargetMD->IsFCall() && ECall::GetIntrinsicID(pTargetMD) != CORINFO_INTRINSIC_Illegal);
5263 callVirtCrossingVersionBubble = true;
5268 DWORD dwMethodAttrs = pTargetMD->GetAttrs();
5269 devirt = !IsMdVirtual(dwMethodAttrs) || IsMdFinal(dwMethodAttrs) || pTargetMD->GetMethodTable()->IsSealed();
5274 // We can't allow generic remotable methods to be considered resolved, it leads to a non-instantiating method desc being
5275 // passed to the remoting stub. The easiest way to deal with these is to force them through the virtual code path.
5276 // It is actually good to do this deoptimization for all remotable methods since remoting interception via vtable dispatch
5277 // is faster then remoting interception via thunk
5278 if (!pTargetMD->IsRemotingInterceptedViaVirtualDispatch() /* || !pTargetMD->HasMethodInstantiation() */)
5280 resolvedCallVirt = true;
5288 bool allowInstParam = (flags & CORINFO_CALLINFO_ALLOWINSTPARAM)
5289 // See code:IsRemotingInterceptedViaPrestub on why we need need to disallow inst param for remoting.
5290 && !( pTargetMD->MayBeRemotingIntercepted() && !pTargetMD->IsVtableMethod() );
5292 // Create instantiating stub if necesary
5293 if (!allowInstParam && pTargetMD->RequiresInstArg())
5295 pTargetMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pTargetMD,
5296 exactType.AsMethodTable(),
5297 FALSE /* forceBoxedEntryPoint */,
5298 pTargetMD->GetMethodInstantiation(),
5299 FALSE /* allowInstParam */);
5302 // We don't allow a JIT to call the code directly if a runtime lookup is
5303 // needed. This is the case if
5304 // 1. the scan of the call token indicated that it involves code sharing
5305 // AND 2. the method is an instantiating stub
5307 // In these cases the correct instantiating stub is only found via a runtime lookup.
5309 // Note that most JITs don't call instantiating stubs directly if they can help it -
5310 // they call the underlying shared code and provide the type context parameter
5311 // explicitly. However
5312 // (a) some JITs may call instantiating stubs (it makes the JIT simpler) and
5313 // (b) if the method is a remote stub then the EE will force the
5314 // call through an instantiating stub and
5315 // (c) constraint calls that require runtime context lookup are never resolved
5316 // to underlying shared generic code
5318 if (((pResult->exactContextNeedsRuntimeLookup && pTargetMD->IsInstantiatingStub() && (!allowInstParam || fResolvedConstraint)) || fForceUseRuntimeLookup)
5319 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
5320 && ContextIsShared(pResolvedToken->tokenContext))
5322 _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5323 pResult->kind = CORINFO_CALL_CODE_POINTER;
5325 // For reference types, the constrained type does not affect method resolution
5326 DictionaryEntryKind entryKind = (!constrainedType.IsNull() && constrainedType.IsValueType()) ? ConstrainedMethodEntrySlot : MethodEntrySlot;
5328 ComputeRuntimeLookupForSharedGenericToken(entryKind,
5330 pConstrainedResolvedToken,
5332 &pResult->codePointerLookup);
5336 if (allowInstParam && pTargetMD->IsInstantiatingStub())
5338 pTargetMD = pTargetMD->GetWrappedMethodDesc();
5341 pResult->kind = CORINFO_CALL;
5343 if (IsReadyToRunCompilation())
5345 // Compensate for always treating delegates as direct calls above
5346 if ((flags & CORINFO_CALLINFO_LDFTN) && (flags & CORINFO_CALLINFO_CALLVIRT) && !resolvedCallVirt)
5348 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5352 pResult->nullInstanceCheck = resolvedCallVirt;
5354 // All virtual calls which take method instantiations must
5355 // currently be implemented by an indirect call via a runtime-lookup
5357 else if (pTargetMD->HasMethodInstantiation())
5359 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN; // stub dispatch can't handle generic method calls yet
5360 pResult->nullInstanceCheck = TRUE;
5362 // Non-interface dispatches go through the vtable
5363 else if (!pTargetMD->IsInterface() && !IsReadyToRunCompilation())
5365 pResult->kind = CORINFO_VIRTUALCALL_VTABLE;
5366 pResult->nullInstanceCheck = TRUE;
5370 if (IsReadyToRunCompilation())
5372 // Insert explicit null checks for cross-version bubble non-interface calls.
5373 // It is required to handle null checks properly for non-virtual <-> virtual change between versions
5374 pResult->nullInstanceCheck = !!(callVirtCrossingVersionBubble && !pTargetMD->IsInterface());
5378 // No need to null check - the dispatch code will deal with null this.
5379 pResult->nullInstanceCheck = FALSE;
5381 #ifdef STUB_DISPATCH_PORTABLE
5382 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5383 #else // STUB_DISPATCH_PORTABLE
5384 pResult->kind = CORINFO_VIRTUALCALL_STUB;
5386 // We can't make stub calls when we need exact information
5387 // for interface calls from shared code.
5389 if (// If the token is not shared then we don't need a runtime lookup
5390 pResult->exactContextNeedsRuntimeLookup
5391 // Handle invalid IL - see comment in code:CEEInfo::ComputeRuntimeLookupForSharedGenericToken
5392 && ContextIsShared(pResolvedToken->tokenContext))
5394 _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5396 ComputeRuntimeLookupForSharedGenericToken(DispatchStubAddrSlot,
5400 &pResult->stubLookup);
5404 pResult->stubLookup.lookupKind.needsRuntimeLookup = false;
5406 BYTE * indcell = NULL;
5408 if (!(flags & CORINFO_CALLINFO_KINDONLY) && !isVerifyOnly())
5410 #ifndef CROSSGEN_COMPILE
5411 // We shouldn't be using GetLoaderAllocator here because for LCG, we need to get the
5412 // VirtualCallStubManager from where the stub will be used.
5413 // For normal methods there is no difference.
5414 LoaderAllocator *pLoaderAllocator = m_pMethodBeingCompiled->GetLoaderAllocatorForCode();
5415 VirtualCallStubManager *pMgr = pLoaderAllocator->GetVirtualCallStubManager();
5417 PCODE addr = pMgr->GetCallStub(exactType, pTargetMD);
5418 _ASSERTE(pMgr->isStub(addr));
5420 // Now we want to indirect through a cell so that updates can take place atomically.
5421 if (m_pMethodBeingCompiled->IsLCGMethod())
5423 // LCG methods should use recycled indcells to prevent leaks.
5424 indcell = pMgr->GenerateStubIndirection(addr, TRUE);
5426 // Add it to the per DM list so that we can recycle them when the resolver is finalized
5427 LCGMethodResolver *pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetLCGMethodResolver();
5428 pResolver->AddToUsedIndCellList(indcell);
5432 // Normal methods should avoid recycled cells to preserve the locality of all indcells
5433 // used by one method.
5434 indcell = pMgr->GenerateStubIndirection(addr, FALSE);
5436 #else // CROSSGEN_COMPILE
5437 // This path should be unreachable during crossgen
5439 #endif // CROSSGEN_COMPILE
5442 // We use an indirect call
5443 pResult->stubLookup.constLookup.accessType = IAT_PVALUE;
5444 pResult->stubLookup.constLookup.addr = indcell;
5446 #endif // STUB_DISPATCH_PORTABLE
5449 pResult->hMethod = CORINFO_METHOD_HANDLE(pTargetMD);
5451 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5452 if ((flags & CORINFO_CALLINFO_SECURITYCHECKS) &&
5453 !((MethodDesc *)callerHandle)->IsILStub()) // IL stubs can access everything, don't bother doing access checks
5455 //Our type system doesn't always represent the target exactly with the MethodDesc. In all cases,
5456 //carry around the parent MethodTable for both Caller and Callee.
5457 TypeHandle calleeTypeForSecurity = TypeHandle(pResolvedToken->hClass);
5458 MethodDesc * pCalleeForSecurity = pMD;
5460 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle); //Should this be the open MD?
5462 if (pCallerForSecurity->HasClassOrMethodInstantiation())
5464 _ASSERTE(!IsDynamicScope(pResolvedToken->tokenScope));
5466 SigTypeContext typeContext;
5467 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
5468 _ASSERTE(!typeContext.IsEmpty());
5470 //If the caller is generic, load the open type and resolve the token again. Use that for the access
5471 //checks. If we don't do this then we can't tell the difference between:
5473 //BadGeneric<T> containing a methodspec for InaccessibleType::member (illegal)
5475 //BadGeneric<T> containing a methodspec for !!0::member instantiated over InaccessibleType (legal)
5477 if (pResolvedToken->pTypeSpec != NULL)
5479 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
5480 calleeTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5482 // typeHnd can be a variable type
5483 if (calleeTypeForSecurity.GetMethodTable() == NULL)
5485 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
5489 if (pCalleeForSecurity->IsArray())
5491 // FindOrCreateAssociatedMethodDesc won't remap array method desc because of array base type
5492 // is not part of instantiation. We have to special case it.
5493 pCalleeForSecurity = calleeTypeForSecurity.GetMethodTable()->GetParallelMethodDesc(pCalleeForSecurity);
5496 if (pResolvedToken->pMethodSpec != NULL)
5498 DWORD nGenericMethodArgs = 0;
5499 CQuickBytes qbGenericMethodArgs;
5500 TypeHandle *genericMethodArgs = NULL;
5502 SigPointer sp(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
5505 IfFailThrow(sp.GetByte(&etype));
5507 // Load the generic method instantiation
5508 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, (Module *)pResolvedToken->tokenScope);
5510 IfFailThrow(sp.GetData(&nGenericMethodArgs));
5512 DWORD cbAllocSize = 0;
5513 if (!ClrSafeInt<DWORD>::multiply(nGenericMethodArgs, sizeof(TypeHandle), cbAllocSize))
5515 COMPlusThrowHR(COR_E_OVERFLOW);
5518 genericMethodArgs = reinterpret_cast<TypeHandle *>(qbGenericMethodArgs.AllocThrows(cbAllocSize));
5520 for (DWORD i = 0; i < nGenericMethodArgs; i++)
5522 genericMethodArgs[i] = sp.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5523 _ASSERTE (!genericMethodArgs[i].IsNull());
5524 IfFailThrow(sp.SkipExactlyOne());
5527 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(genericMethodArgs, nGenericMethodArgs), FALSE);
5530 if (pResolvedToken->pTypeSpec != NULL)
5532 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(), TRUE);
5536 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5538 //Passed various link-time checks. Now do access checks.
5540 BOOL doAccessCheck = TRUE;
5541 BOOL canAccessMethod = TRUE;
5542 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
5543 DynamicResolver * pAccessContext = NULL;
5545 callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5546 if (pCallerForSecurity->IsDynamicMethod())
5548 doAccessCheck = ModifyCheckForDynamicMethod(pCallerForSecurity->AsDynamicMethodDesc()->GetResolver(),
5549 &callerTypeForSecurity,
5550 &accessCheckType, &pAccessContext);
5553 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5557 AccessCheckOptions accessCheckOptions(accessCheckType,
5560 pCalleeForSecurity);
5562 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5563 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5565 canAccessMethod = ClassLoader::CanAccess(&accessContext,
5566 calleeTypeForSecurity.GetMethodTable(),
5567 calleeTypeForSecurity.GetAssembly(),
5568 pCalleeForSecurity->GetAttrs(),
5576 // If we were allowed access to the exact method, but it is on a type that has a type parameter
5577 // (for instance an array), we need to ensure that we also have access to the type parameter.
5578 if (canAccessMethod && calleeTypeForSecurity.HasTypeParam())
5580 TypeHandle typeParam = calleeTypeForSecurity.GetTypeParam();
5581 while (typeParam.HasTypeParam())
5583 typeParam = typeParam.GetTypeParam();
5586 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5587 StaticAccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5589 MethodTable* pTypeParamMT = typeParam.GetMethodTable();
5591 // No accees check is need for Var, MVar, or FnPtr.
5592 if (pTypeParamMT != NULL)
5593 canAccessMethod = ClassLoader::CanAccessClassForExtraChecks(&accessContext,
5595 typeParam.GetAssembly(),
5600 pResult->accessAllowed = canAccessMethod ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
5601 if (!canAccessMethod)
5603 //Check failed, fill in the throw exception helper.
5604 pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_METHOD_ACCESS_EXCEPTION;
5605 pResult->callsiteCalloutHelper.numArgs = 2;
5607 pResult->callsiteCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5608 pResult->callsiteCalloutHelper.args[1].Set(CORINFO_METHOD_HANDLE(pCalleeForSecurity));
5610 //We now embed open instantiations in a few places for security callouts (since you can only
5611 //do the security check on the open instantiation). We throw these methods out in
5612 //TriageMethodForZap. In addition, NGen has problems referencing them properly. Just throw out the whole
5613 //method and rejit at runtime.
5614 if (IsCompilingForNGen())
5616 if (pCallerForSecurity->ContainsGenericVariables()
5617 || pCalleeForSecurity->ContainsGenericVariables())
5619 COMPlusThrowNonLocalized(kNotSupportedException, W("Cannot embed generic MethodDesc"));
5626 //We're pretty much done at this point. Let's grab the rest of the information that the jit is going to
5628 pResult->classFlags = getClassAttribsInternal(pResolvedToken->hClass);
5630 pResult->methodFlags = getMethodAttribsInternal(pResult->hMethod);
5631 getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL);
5633 if (flags & CORINFO_CALLINFO_VERIFICATION)
5635 if (pResult->hMethod != pResolvedToken->hMethod)
5637 pResult->verMethodFlags = getMethodAttribsInternal(pResolvedToken->hMethod);
5638 getMethodSigInternal(pResolvedToken->hMethod, &pResult->verSig, pResolvedToken->hClass);
5642 pResult->verMethodFlags = pResult->methodFlags;
5643 pResult->verSig = pResult->sig;
5647 pResult->secureDelegateInvoke = FALSE;
5649 #ifdef FEATURE_STUBS_AS_IL
5650 if (m_pMethodBeingCompiled->IsDynamicMethod())
5652 auto pMD = m_pMethodBeingCompiled->AsDynamicMethodDesc();
5653 if (pMD->IsILStub() && pMD->IsSecureDelegateStub())
5655 pResult->secureDelegateInvoke = TRUE;
5660 EE_TO_JIT_TRANSITION();
5663 BOOL CEEInfo::canAccessFamily(CORINFO_METHOD_HANDLE hCaller,
5664 CORINFO_CLASS_HANDLE hInstanceType)
5666 WRAPPER_NO_CONTRACT;
5670 //Since this is only for verification, I don't need to do the demand.
5671 JIT_TO_EE_TRANSITION();
5673 TypeHandle targetType = TypeHandle(hInstanceType);
5674 TypeHandle accessingType = TypeHandle(GetMethod(hCaller)->GetMethodTable());
5675 AccessCheckOptions::AccessCheckType accessCheckOptions = AccessCheckOptions::kNormalAccessibilityChecks;
5676 DynamicResolver* pIgnored;
5677 BOOL doCheck = TRUE;
5678 if (GetMethod(hCaller)->IsDynamicMethod())
5680 //If this is a DynamicMethod, perform the check from the type to which the DynamicMethod was
5683 //If this is a dynamic method, don't do this check. If they specified SkipVisibilityChecks
5684 //(ModifyCheckForDynamicMethod returned false), we should obviously skip the check for the C++
5685 //protected rule (since we skipped all the other visibility checks). If they specified
5686 //RestrictedSkipVisibilityChecks, then they're a "free" DynamicMethod. This check is meaningless
5687 //(i.e. it would always fail). We've already done a demand for access to the member. Let that be
5689 doCheck = ModifyCheckForDynamicMethod(GetMethod(hCaller)->AsDynamicMethodDesc()->GetResolver(),
5690 &accessingType, &accessCheckOptions, &pIgnored);
5691 if (accessCheckOptions == AccessCheckOptions::kRestrictedMemberAccess
5692 || accessCheckOptions == AccessCheckOptions::kRestrictedMemberAccessNoTransparency
5699 ret = ClassLoader::CanAccessFamilyVerification(accessingType, targetType);
5706 EE_TO_JIT_TRANSITION();
5709 void CEEInfo::ThrowExceptionForHelper(const CORINFO_HELPER_DESC * throwHelper)
5718 JIT_TO_EE_TRANSITION();
5720 _ASSERTE(throwHelper->args[0].argType == CORINFO_HELPER_ARG_TYPE_Method);
5721 MethodDesc *pCallerMD = GetMethod(throwHelper->args[0].methodHandle);
5723 StaticAccessCheckContext accessContext(pCallerMD);
5725 switch (throwHelper->helperNum)
5727 case CORINFO_HELP_METHOD_ACCESS_EXCEPTION:
5729 _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Method);
5730 ThrowMethodAccessException(&accessContext, GetMethod(throwHelper->args[1].methodHandle));
5733 case CORINFO_HELP_FIELD_ACCESS_EXCEPTION:
5735 _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Field);
5736 ThrowFieldAccessException(&accessContext, reinterpret_cast<FieldDesc *>(throwHelper->args[1].fieldHandle));
5739 case CORINFO_HELP_CLASS_ACCESS_EXCEPTION:
5741 _ASSERTE(throwHelper->args[1].argType == CORINFO_HELPER_ARG_TYPE_Class);
5742 TypeHandle typeHnd(throwHelper->args[1].classHandle);
5743 ThrowTypeAccessException(&accessContext, typeHnd.GetMethodTable());
5748 _ASSERTE(!"Unknown access exception type");
5750 EE_TO_JIT_TRANSITION();
5754 BOOL CEEInfo::isRIDClassDomainID(CORINFO_CLASS_HANDLE cls)
5763 BOOL result = FALSE;
5765 JIT_TO_EE_TRANSITION();
5767 TypeHandle VMClsHnd(cls);
5769 result = !VMClsHnd.AsMethodTable()->IsDynamicStatics();
5771 EE_TO_JIT_TRANSITION();
5777 /***********************************************************************/
5778 unsigned CEEInfo::getClassDomainID (CORINFO_CLASS_HANDLE clsHnd,
5779 void **ppIndirection)
5788 unsigned result = 0;
5790 if (ppIndirection != NULL)
5791 *ppIndirection = NULL;
5793 JIT_TO_EE_TRANSITION();
5795 TypeHandle VMClsHnd(clsHnd);
5797 if (VMClsHnd.AsMethodTable()->IsDynamicStatics())
5799 result = (unsigned)VMClsHnd.AsMethodTable()->GetModuleDynamicEntryID();
5803 result = (unsigned)VMClsHnd.AsMethodTable()->GetClassIndex();
5806 EE_TO_JIT_TRANSITION();
5811 //---------------------------------------------------------------------------------------
5813 // Used by the JIT to determine whether the profiler or IBC is tracking object
5817 // bool indicating whether the profiler or IBC is tracking object allocations
5820 // Normally, a profiler would just directly call the inline helper to determine
5821 // whether the profiler set the relevant event flag (e.g.,
5822 // CORProfilerTrackAllocationsEnabled). However, this wrapper also asks whether we're
5823 // running for IBC instrumentation or enabling the object allocated ETW event. If so,
5824 // we treat that the same as if the profiler requested allocation information, so that
5825 // the JIT will still use the profiling-friendly object allocation jit helper, so the
5826 // allocations can be tracked.
5829 bool __stdcall TrackAllocationsEnabled()
5840 (g_IBCLogger.InstrEnabled() != FALSE)
5841 #ifdef PROFILING_SUPPORTED
5842 || CORProfilerTrackAllocationsEnabled()
5843 #endif // PROFILING_SUPPORTED
5844 #ifdef FEATURE_EVENT_TRACE
5845 || ETW::TypeSystemLog::IsHeapAllocEventEnabled()
5846 #endif // FEATURE_EVENT_TRACE
5850 /***********************************************************************/
5851 CorInfoHelpFunc CEEInfo::getNewHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_METHOD_HANDLE callerHandle)
5860 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5862 JIT_TO_EE_TRANSITION();
5864 TypeHandle VMClsHnd(pResolvedToken->hClass);
5866 if(VMClsHnd.IsTypeDesc())
5868 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateFunctionPointer"));
5871 if(VMClsHnd.IsAbstract())
5873 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateAbstractClass"));
5876 MethodTable* pMT = VMClsHnd.AsMethodTable();
5877 result = getNewHelperStatic(pMT);
5879 _ASSERTE(result != CORINFO_HELP_UNDEF);
5881 EE_TO_JIT_TRANSITION();
5886 /***********************************************************************/
5887 CorInfoHelpFunc CEEInfo::getNewHelperStatic(MethodTable * pMT)
5889 STANDARD_VM_CONTRACT;
5892 // Slow helper is the default
5893 CorInfoHelpFunc helper = CORINFO_HELP_NEWFAST;
5896 if (pMT->IsComObjectType())
5899 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5902 if ((pMT->GetBaseSize() >= LARGE_OBJECT_SIZE) ||
5903 pMT->HasFinalizer())
5906 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5909 // don't call the super-optimized one since that does not check
5911 if (GCStress<cfg_alloc>::IsEnabled())
5914 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5919 // Super fast version doesn't do logging
5920 if (LoggingOn(LF_GCALLOC, LL_INFO10))
5923 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5928 // Don't use the SFAST allocator when tracking object allocations,
5929 // so we don't have to instrument it.
5930 if (TrackAllocationsEnabled())
5933 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5936 #ifdef FEATURE_64BIT_ALIGNMENT
5937 // @ARMTODO: Force all 8-byte alignment requiring allocations down one slow path. As performance
5938 // measurements dictate we can spread these out to faster, more specialized helpers later.
5939 if (pMT->RequiresAlign8())
5942 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5947 // Use the fast helper when all conditions are met
5948 helper = CORINFO_HELP_NEWSFAST;
5951 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
5952 // If we are use the the fast allocator we also may need the
5953 // specialized varion for align8
5954 if (pMT->GetClass()->IsAlign8Candidate() &&
5955 (helper == CORINFO_HELP_NEWSFAST))
5957 helper = CORINFO_HELP_NEWSFAST_ALIGN8;
5959 #endif // FEATURE_DOUBLE_ALIGNMENT_HINT
5964 /***********************************************************************/
5965 // <REVIEW> this only works for shared generic code because all the
5966 // helpers are actually the same. If they were different then things might
5967 // break because the same helper would end up getting used for different but
5968 // representation-compatible arrays (e.g. one with a default constructor
5969 // and one without) </REVIEW>
5970 CorInfoHelpFunc CEEInfo::getNewArrHelper (CORINFO_CLASS_HANDLE arrayClsHnd)
5979 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5981 JIT_TO_EE_TRANSITION();
5983 TypeHandle arrayType(arrayClsHnd);
5985 result = getNewArrHelperStatic(arrayType);
5987 _ASSERTE(result != CORINFO_HELP_UNDEF);
5989 EE_TO_JIT_TRANSITION();
5994 /***********************************************************************/
5995 CorInfoHelpFunc CEEInfo::getNewArrHelperStatic(TypeHandle clsHnd)
5997 STANDARD_VM_CONTRACT;
5999 ArrayTypeDesc* arrayTypeDesc = clsHnd.AsArray();
6000 _ASSERTE(arrayTypeDesc->GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
6002 if (GCStress<cfg_alloc>::IsEnabled())
6004 return CORINFO_HELP_NEWARR_1_DIRECT;
6007 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6009 TypeHandle thElemType = arrayTypeDesc->GetTypeParam();
6010 CorElementType elemType = thElemType.GetInternalCorElementType();
6012 // This is if we're asked for newarr !0 when verifying generic code
6013 // Of course ideally you wouldn't even be generating code when
6014 // simply doing verification (we run the JIT importer in import-only
6015 // mode), but importing does more than one would like so we try to be
6016 // tolerant when asked for non-sensical helpers.
6017 if (CorTypeInfo::IsGenericVariable(elemType))
6019 result = CORINFO_HELP_NEWARR_1_OBJ;
6021 else if (CorTypeInfo::IsObjRef(elemType))
6023 // It is an array of object refs
6024 result = CORINFO_HELP_NEWARR_1_OBJ;
6028 // These cases always must use the slow helper
6030 #ifdef FEATURE_64BIT_ALIGNMENT
6031 thElemType.RequiresAlign8() ||
6033 (elemType == ELEMENT_TYPE_VOID) ||
6034 LoggingOn(LF_GCALLOC, LL_INFO10) ||
6035 TrackAllocationsEnabled())
6037 // Use the slow helper
6038 result = CORINFO_HELP_NEWARR_1_DIRECT;
6040 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
6041 else if (elemType == ELEMENT_TYPE_R8)
6043 // Use the Align8 fast helper
6044 result = CORINFO_HELP_NEWARR_1_ALIGN8;
6049 // Yea, we can do it the fast way!
6050 result = CORINFO_HELP_NEWARR_1_VC;
6057 /***********************************************************************/
6058 CorInfoHelpFunc CEEInfo::getCastingHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fThrowing)
6068 return fThrowing ? CORINFO_HELP_CHKCASTANY : CORINFO_HELP_ISINSTANCEOFANY;
6070 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6072 JIT_TO_EE_TRANSITION();
6074 bool fClassMustBeRestored;
6075 result = getCastingHelperStatic(TypeHandle(pResolvedToken->hClass), fThrowing, &fClassMustBeRestored);
6076 if (fClassMustBeRestored && m_pOverride != NULL)
6077 m_pOverride->classMustBeLoadedBeforeCodeIsRun(pResolvedToken->hClass);
6079 EE_TO_JIT_TRANSITION();
6084 /***********************************************************************/
6085 CorInfoHelpFunc CEEInfo::getCastingHelperStatic(TypeHandle clsHnd, bool fThrowing, bool * pfClassMustBeRestored)
6087 STANDARD_VM_CONTRACT;
6089 // Slow helper is the default
6090 int helper = CORINFO_HELP_ISINSTANCEOFANY;
6092 *pfClassMustBeRestored = false;
6094 if (clsHnd == TypeHandle(g_pCanonMethodTableClass))
6096 // In shared code just use the catch-all helper for type variables, as the same
6097 // code may be used for interface/array/class instantiations
6099 // We may be able to take advantage of constraints to select a specialized helper.
6100 // This optimizations does not seem to be warranted at the moment.
6101 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6104 if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasVariance())
6106 // Casting to variant type requires the type to be fully loaded
6107 *pfClassMustBeRestored = true;
6109 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6112 if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasTypeEquivalence())
6114 // If the type can be equivalent with something, use the slow helper
6115 // Note: if the type of the instance is the one marked as equivalent, it will be
6116 // caught by the fast helpers in the same way as they catch transparent proxies.
6117 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6120 if (clsHnd.IsInterface())
6122 // If it is a non-variant interface, use the fast interface helper
6123 helper = CORINFO_HELP_ISINSTANCEOFINTERFACE;
6126 if (clsHnd.IsArray())
6128 if (clsHnd.AsArray()->GetInternalCorElementType() != ELEMENT_TYPE_SZARRAY)
6130 // Casting to multidimensional array type requires restored pointer to EEClass to fetch rank
6131 *pfClassMustBeRestored = true;
6134 // If it is an array, use the fast array helper
6135 helper = CORINFO_HELP_ISINSTANCEOFARRAY;
6138 if (!clsHnd.IsTypeDesc() && !Nullable::IsNullableType(clsHnd))
6140 // If it is a non-variant class, use the fast class helper
6141 helper = CORINFO_HELP_ISINSTANCEOFCLASS;
6145 // Otherwise, use the slow helper
6146 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6149 #ifdef FEATURE_PREJIT
6150 BOOL t1, t2, forceInstr;
6151 SystemDomain::GetCompilationOverrides(&t1, &t2, &forceInstr);
6154 // If we're compiling for instrumentation, use the slowest but instrumented cast helper
6155 helper = CORINFO_HELP_ISINSTANCEOFANY;
6161 const int delta = CORINFO_HELP_CHKCASTANY - CORINFO_HELP_ISINSTANCEOFANY;
6163 static_assert_no_msg(CORINFO_HELP_CHKCASTINTERFACE
6164 == CORINFO_HELP_ISINSTANCEOFINTERFACE + delta);
6165 static_assert_no_msg(CORINFO_HELP_CHKCASTARRAY
6166 == CORINFO_HELP_ISINSTANCEOFARRAY + delta);
6167 static_assert_no_msg(CORINFO_HELP_CHKCASTCLASS
6168 == CORINFO_HELP_ISINSTANCEOFCLASS + delta);
6173 return (CorInfoHelpFunc)helper;
6176 /***********************************************************************/
6177 CorInfoHelpFunc CEEInfo::getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd)
6186 CorInfoHelpFunc result = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
6188 JIT_TO_EE_TRANSITION_LEAF();
6190 TypeHandle cls(clsHnd);
6191 MethodTable* pMT = cls.AsMethodTable();
6193 if (pMT->IsDynamicStatics())
6195 _ASSERTE(!cls.ContainsGenericVariables());
6196 _ASSERTE(pMT->GetModuleDynamicEntryID() != (unsigned) -1);
6198 result = CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
6201 EE_TO_JIT_TRANSITION_LEAF();
6206 /***********************************************************************/
6207 CorInfoHelpFunc CEEInfo::getUnBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6209 LIMITED_METHOD_CONTRACT;
6211 if (m_pOverride != NULL)
6212 m_pOverride->classMustBeLoadedBeforeCodeIsRun(clsHnd);
6214 TypeHandle VMClsHnd(clsHnd);
6215 if (Nullable::IsNullableType(VMClsHnd))
6216 return CORINFO_HELP_UNBOX_NULLABLE;
6218 return CORINFO_HELP_UNBOX;
6221 /***********************************************************************/
6222 bool CEEInfo::getReadyToRunHelper(
6223 CORINFO_RESOLVED_TOKEN * pResolvedToken,
6224 CORINFO_LOOKUP_KIND * pGenericLookupKind,
6226 CORINFO_CONST_LOOKUP * pLookup
6229 LIMITED_METHOD_CONTRACT;
6230 UNREACHABLE(); // only called during NGen
6233 /***********************************************************************/
6234 void CEEInfo::getReadyToRunDelegateCtorHelper(
6235 CORINFO_RESOLVED_TOKEN * pTargetMethod,
6236 CORINFO_CLASS_HANDLE delegateType,
6237 CORINFO_LOOKUP * pLookup
6240 LIMITED_METHOD_CONTRACT;
6241 UNREACHABLE(); // only called during NGen
6244 /***********************************************************************/
6245 // see code:Nullable#NullableVerification
6247 CORINFO_CLASS_HANDLE CEEInfo::getTypeForBox(CORINFO_CLASS_HANDLE cls)
6249 LIMITED_METHOD_CONTRACT;
6251 TypeHandle VMClsHnd(cls);
6252 if (Nullable::IsNullableType(VMClsHnd)) {
6253 VMClsHnd = VMClsHnd.AsMethodTable()->GetInstantiation()[0];
6255 return static_cast<CORINFO_CLASS_HANDLE>(VMClsHnd.AsPtr());
6258 /***********************************************************************/
6259 // see code:Nullable#NullableVerification
6260 CorInfoHelpFunc CEEInfo::getBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6269 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6271 JIT_TO_EE_TRANSITION();
6273 TypeHandle VMClsHnd(clsHnd);
6274 if (Nullable::IsNullableType(VMClsHnd))
6276 result = CORINFO_HELP_BOX_NULLABLE;
6280 // Dev10 718281 - This has been functionally broken fora very long time (at least 2.0).
6281 // The recent addition of the check for stack pointers has caused it to now AV instead
6282 // of gracefully failing with an InvalidOperationException. Since nobody has noticed
6283 // it being broken, we are choosing not to invest to fix it, and instead explicitly
6284 // breaking it and failing early and consistently.
6285 if(VMClsHnd.IsTypeDesc())
6287 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_TypeCannotBeBoxed"));
6290 // we shouldn't allow boxing of types that contains stack pointers
6291 // csc and vbc already disallow it.
6292 if (VMClsHnd.AsMethodTable()->IsByRefLike())
6293 COMPlusThrow(kInvalidProgramException);
6295 result = CORINFO_HELP_BOX;
6298 EE_TO_JIT_TRANSITION();
6303 /***********************************************************************/
6304 CorInfoHelpFunc CEEInfo::getSecurityPrologHelper(CORINFO_METHOD_HANDLE ftn)
6313 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6315 JIT_TO_EE_TRANSITION();
6317 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6318 // This will make sure that when IBC logging is on, we call the slow helper with IBC probe
6319 if (IsCompilingForNGen() &&
6320 GetAppDomain()->ToCompilationDomain()->m_fForceInstrument)
6322 result = CORINFO_HELP_SECURITY_PROLOG_FRAMED;
6324 #endif // FEATURE_NATIVE_IMAGE_GENERATION
6326 if (result == CORINFO_HELP_UNDEF)
6328 result = CORINFO_HELP_SECURITY_PROLOG;
6331 EE_TO_JIT_TRANSITION();
6336 /***********************************************************************/
6337 // registers a vararg sig & returns a class-specific cookie for it.
6339 CORINFO_VARARGS_HANDLE CEEInfo::getVarArgsHandle(CORINFO_SIG_INFO *sig,
6340 void **ppIndirection)
6349 CORINFO_VARARGS_HANDLE result = NULL;
6351 if (ppIndirection != NULL)
6352 *ppIndirection = NULL;
6354 JIT_TO_EE_TRANSITION();
6356 Module* module = GetModule(sig->scope);
6358 result = CORINFO_VARARGS_HANDLE(module->GetVASigCookie(Signature(sig->pSig, sig->cbSig)));
6360 EE_TO_JIT_TRANSITION();
6365 bool CEEInfo::canGetVarArgsHandle(CORINFO_SIG_INFO *sig)
6367 LIMITED_METHOD_CONTRACT;
6371 /***********************************************************************/
6372 unsigned CEEInfo::getMethodHash (CORINFO_METHOD_HANDLE ftnHnd)
6381 unsigned result = 0;
6383 JIT_TO_EE_TRANSITION();
6385 MethodDesc* ftn = GetMethod(ftnHnd);
6387 result = (unsigned) ftn->GetStableHash();
6389 EE_TO_JIT_TRANSITION();
6394 /***********************************************************************/
6395 const char* CEEInfo::getMethodName (CORINFO_METHOD_HANDLE ftnHnd, const char** scopeName)
6404 const char* result = NULL;
6406 JIT_TO_EE_TRANSITION();
6410 ftn = GetMethod(ftnHnd);
6414 if (ftn->IsLCGMethod())
6416 *scopeName = "DynamicClass";
6418 else if (ftn->IsILStub())
6420 *scopeName = ILStubResolver::GetStubClassName(ftn);
6424 MethodTable * pMT = ftn->GetMethodTable();
6426 #ifdef FEATURE_SYMDIFF
6427 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SymDiffDump))
6431 ssClsNameBuff.Clear();
6432 ssClsNameBuff.SetUTF8(pMT->GetDebugClassName());
6435 pMT->_GetFullyQualifiedNameForClassNestedAware(ssClsNameBuff);
6440 // Calling _GetFullyQualifiedNameForClass in chk build is very expensive
6441 // since it construct the class name everytime we call this method. In chk
6442 // builds we already have a cheaper way to get the class name -
6443 // GetDebugClassName - which doesn't calculate the class name everytime.
6444 // This results in huge saving in Ngen time for checked builds.
6445 ssClsNameBuff.Clear();
6446 ssClsNameBuff.SetUTF8(pMT->GetDebugClassName());
6448 #ifdef FEATURE_SYMDIFF
6451 // Append generic instantiation at the end
6452 Instantiation inst = pMT->GetInstantiation();
6453 if (!inst.IsEmpty())
6454 TypeString::AppendInst(ssClsNameBuff, inst);
6456 *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
6458 // since this is for diagnostic purposes only,
6459 // give up on the namespace, as we don't have a buffer to concat it
6460 // also note this won't show array class names.
6462 *scopeName= pMT->GetFullyQualifiedNameInfo(&nameSpace);
6467 result = ftn->GetName();
6469 EE_TO_JIT_TRANSITION();
6474 /*********************************************************************/
6475 DWORD CEEInfo::getMethodAttribs (CORINFO_METHOD_HANDLE ftn)
6486 JIT_TO_EE_TRANSITION();
6488 result = getMethodAttribsInternal(ftn);
6490 EE_TO_JIT_TRANSITION();
6495 /*********************************************************************/
6496 DWORD CEEInfo::getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftn)
6498 STANDARD_VM_CONTRACT;
6501 returns method attribute flags (defined in corhdr.h)
6503 NOTE: This doesn't return certain method flags
6504 (mdAssem, mdFamANDAssem, mdFamORAssem, mdPrivateScope)
6507 MethodDesc* pMD = GetMethod(ftn);
6509 if (pMD->IsLCGMethod())
6511 #ifndef CROSSGEN_COMPILE
6512 #endif // !CROSSGEN_COMPILE
6514 return CORINFO_FLG_STATIC | CORINFO_FLG_DONT_INLINE | CORINFO_FLG_NOSECURITYWRAP;
6519 // <REVISIT_TODO>@todo: can we git rid of CORINFO_FLG_ stuff and just include cor.h?</REVISIT_TODO>
6521 DWORD attribs = pMD->GetAttrs();
6523 if (IsMdFamily(attribs))
6524 result |= CORINFO_FLG_PROTECTED;
6525 if (IsMdStatic(attribs))
6526 result |= CORINFO_FLG_STATIC;
6527 if (pMD->IsSynchronized())
6528 result |= CORINFO_FLG_SYNCH;
6529 if (pMD->IsFCallOrIntrinsic())
6530 result |= CORINFO_FLG_NOGCCHECK | CORINFO_FLG_INTRINSIC;
6531 if (IsMdVirtual(attribs))
6532 result |= CORINFO_FLG_VIRTUAL;
6533 if (IsMdAbstract(attribs))
6534 result |= CORINFO_FLG_ABSTRACT;
6535 if (IsMdRTSpecialName(attribs))
6537 LPCUTF8 pName = pMD->GetName();
6538 if (IsMdInstanceInitializer(attribs, pName) ||
6539 IsMdClassConstructor(attribs, pName))
6540 result |= CORINFO_FLG_CONSTRUCTOR;
6544 // See if we need to embed a .cctor call at the head of the
6548 MethodTable* pMT = pMD->GetMethodTable();
6550 // method or class might have the final bit
6551 if (IsMdFinal(attribs) || pMT->IsSealed())
6553 result |= CORINFO_FLG_FINAL;
6556 if (pMD->IsEnCAddedMethod())
6558 result |= CORINFO_FLG_EnC;
6561 if (pMD->IsSharedByGenericInstantiations())
6563 result |= CORINFO_FLG_SHAREDINST;
6566 if (pMD->IsNDirect())
6568 result |= CORINFO_FLG_PINVOKE;
6571 if (!pMD->IsInterceptedForDeclSecurity())
6573 result |= CORINFO_FLG_NOSECURITYWRAP;
6576 if (IsMdRequireSecObject(attribs))
6578 // Assume all methods marked as DynamicSecurity are
6579 // marked that way because they use StackCrawlMark to identify
6581 // See comments in canInline or canTailCall
6582 result |= CORINFO_FLG_DONT_INLINE_CALLER;
6585 // Check for an inlining directive.
6586 if (pMD->IsNotInline())
6588 /* Function marked as not inlineable */
6589 result |= CORINFO_FLG_DONT_INLINE;
6591 // AggressiveInlining only makes sense for IL methods.
6592 else if (pMD->IsIL() && IsMiAggressiveInlining(pMD->GetImplAttrs()))
6594 result |= CORINFO_FLG_FORCEINLINE;
6597 if (pMT->IsDelegate() && ((DelegateEEClass*)(pMT->GetClass()))->GetInvokeMethod() == pMD)
6599 // This is now used to emit efficient invoke code for any delegate invoke,
6600 // including multicast.
6601 result |= CORINFO_FLG_DELEGATE_INVOKE;
6607 /*********************************************************************/
6608 void CEEInfo::setMethodAttribs (
6609 CORINFO_METHOD_HANDLE ftnHnd,
6610 CorInfoMethodRuntimeFlags attribs)
6619 JIT_TO_EE_TRANSITION();
6621 MethodDesc* ftn = GetMethod(ftnHnd);
6623 if (attribs & CORINFO_FLG_BAD_INLINEE)
6625 BOOL fCacheInliningHint = TRUE;
6627 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
6628 if (IsCompilationProcess())
6630 // Since we are running managed code during NGen the inlining hint may be
6631 // changing underneeth us as the code is JITed. We need to prevent the inlining
6632 // hints from changing once we start to use them to place IL in the image.
6633 if (!g_pCEECompileInfo->IsCachingOfInliningHintsEnabled())
6635 fCacheInliningHint = FALSE;
6639 // Don't cache inlining hints inside mscorlib during NGen of other assemblies,
6640 // since mscorlib is loaded domain neutral and will survive worker process recycling,
6641 // causing determinism problems.
6642 Module * pModule = ftn->GetModule();
6643 if (pModule->IsSystem() && pModule->HasNativeImage())
6645 fCacheInliningHint = FALSE;
6651 if (fCacheInliningHint)
6653 ftn->SetNotInline(true);
6657 // Both CORINFO_FLG_UNVERIFIABLE and CORINFO_FLG_VERIFIABLE cannot be set
6658 _ASSERTE(!(attribs & CORINFO_FLG_UNVERIFIABLE) ||
6659 !(attribs & CORINFO_FLG_VERIFIABLE ));
6661 if (attribs & CORINFO_FLG_VERIFIABLE)
6662 ftn->SetIsVerified(TRUE);
6663 else if (attribs & CORINFO_FLG_UNVERIFIABLE)
6664 ftn->SetIsVerified(FALSE);
6666 EE_TO_JIT_TRANSITION();
6669 /*********************************************************************/
6671 void getMethodInfoILMethodHeaderHelper(
6672 COR_ILMETHOD_DECODER* header,
6673 CORINFO_METHOD_INFO* methInfo
6676 LIMITED_METHOD_CONTRACT;
6678 methInfo->ILCode = const_cast<BYTE*>(header->Code);
6679 methInfo->ILCodeSize = header->GetCodeSize();
6680 methInfo->maxStack = static_cast<unsigned short>(header->GetMaxStack());
6681 methInfo->EHcount = static_cast<unsigned short>(header->EHCount());
6684 (CorInfoOptions)((header->GetFlags() & CorILMethod_InitLocals) ? CORINFO_OPT_INIT_LOCALS : 0) ;
6687 mdToken FindGenericMethodArgTypeSpec(IMDInternalImport* pInternalImport)
6689 STANDARD_VM_CONTRACT;
6691 HENUMInternalHolder hEnumTypeSpecs(pInternalImport);
6694 static const BYTE signature[] = { ELEMENT_TYPE_MVAR, 0 };
6696 hEnumTypeSpecs.EnumAllInit(mdtTypeSpec);
6697 while (hEnumTypeSpecs.EnumNext(&token))
6699 PCCOR_SIGNATURE pSig;
6701 IfFailThrow(pInternalImport->GetTypeSpecFromToken(token, &pSig, &cbSig));
6702 if (cbSig == sizeof(signature) && memcmp(pSig, signature, cbSig) == 0)
6706 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6709 /*********************************************************************
6711 IL is the most efficient and portable way to implement certain low level methods
6712 in mscorlib.dll. Unfortunately, there is no good way to link IL into mscorlib.dll today.
6713 Until we find a good way to link IL into mscorlib.dll, we will provide the IL implementation here.
6715 - All IL intrinsincs are members of System.Runtime.CompilerServices.JitHelpers class
6716 - All IL intrinsincs should be kept very simple. Implement the minimal reusable version of
6717 unsafe construct and depend on inlining to do the rest.
6718 - The C# implementation of the IL intrinsic should be good enough for functionalily. Everything should work
6719 correctly (but slower) if the IL intrinsics are removed.
6721 *********************************************************************/
6723 bool getILIntrinsicImplementation(MethodDesc * ftn,
6724 CORINFO_METHOD_INFO * methInfo)
6726 STANDARD_VM_CONTRACT;
6728 // Precondition: ftn is a method in mscorlib
6729 _ASSERTE(ftn->GetModule()->IsSystem());
6731 mdMethodDef tk = ftn->GetMemberDef();
6733 // Compare tokens to cover all generic instantiations
6734 // The body of the first method is simply ret Arg0. The second one first casts the arg to I4.
6736 if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_CAST)->GetMemberDef())
6738 // Return the argument that was passed in.
6739 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
6740 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6741 methInfo->ILCodeSize = sizeof(ilcode);
6742 methInfo->maxStack = 1;
6743 methInfo->EHcount = 0;
6744 methInfo->options = (CorInfoOptions)0;
6747 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_CAST_TO_STACKPTR)->GetMemberDef())
6749 // Return the argument that was passed in converted to IntPtr
6750 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I, CEE_RET };
6751 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6752 methInfo->ILCodeSize = sizeof(ilcode);
6753 methInfo->maxStack = 1;
6754 methInfo->EHcount = 0;
6755 methInfo->options = (CorInfoOptions)0;
6758 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST)->GetMemberDef())
6760 // Normally we would follow the above pattern and unconditionally replace the IL,
6761 // relying on generic type constraints to guarantee that it will only ever be instantiated
6762 // on the type/size of argument we expect.
6764 // However C#/CLR does not support restricting a generic type to be an Enum, so the best
6765 // we can do is constrain it to be a value type. This is fine for run time, since we only
6766 // ever create instantiations on 4 byte or less Enums. But during NGen we may compile instantiations
6767 // on other value types (to be specific, every value type instatiation of EqualityComparer
6768 // because of its TypeDependencyAttribute; here again we would like to restrict this to
6769 // 4 byte or less Enums but cannot).
6771 // This IL is invalid for those instantiations, and replacing it would lead to all sorts of
6772 // errors at NGen time. So we only replace it for instantiations where it would be valid,
6773 // leaving the others, which we should never execute, with the C# implementation of throwing.
6775 _ASSERTE(ftn->HasMethodInstantiation());
6776 Instantiation inst = ftn->GetMethodInstantiation();
6778 _ASSERTE(inst.GetNumArgs() == 1);
6779 CorElementType et = inst[0].GetVerifierCorElementType();
6780 if (et == ELEMENT_TYPE_I4 ||
6781 et == ELEMENT_TYPE_U4 ||
6782 et == ELEMENT_TYPE_I2 ||
6783 et == ELEMENT_TYPE_U2 ||
6784 et == ELEMENT_TYPE_I1 ||
6785 et == ELEMENT_TYPE_U1)
6787 // Cast to I4 and return the argument that was passed in.
6788 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I4, CEE_RET };
6789 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6790 methInfo->ILCodeSize = sizeof(ilcode);
6791 methInfo->maxStack = 1;
6792 methInfo->EHcount = 0;
6793 methInfo->options = (CorInfoOptions)0;
6797 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG)->GetMemberDef())
6799 // The the comment above on why this is is not an unconditional replacement. This case handles
6800 // Enums backed by 8 byte values.
6802 _ASSERTE(ftn->HasMethodInstantiation());
6803 Instantiation inst = ftn->GetMethodInstantiation();
6805 _ASSERTE(inst.GetNumArgs() == 1);
6806 CorElementType et = inst[0].GetVerifierCorElementType();
6807 if (et == ELEMENT_TYPE_I8 ||
6808 et == ELEMENT_TYPE_U8)
6810 // Cast to I8 and return the argument that was passed in.
6811 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_I8, CEE_RET };
6812 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6813 methInfo->ILCodeSize = sizeof(ilcode);
6814 methInfo->maxStack = 1;
6815 methInfo->EHcount = 0;
6816 methInfo->options = (CorInfoOptions)0;
6820 else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__GET_RAW_SZ_ARRAY_DATA)->GetMemberDef())
6822 mdToken tokArrayPinningHelper = MscorlibBinder::GetField(FIELD__ARRAY_PINNING_HELPER__M_ARRAY_DATA)->GetMemberDef();
6824 static BYTE ilcode[] = { CEE_LDARG_0,
6828 ilcode[2] = (BYTE)(tokArrayPinningHelper);
6829 ilcode[3] = (BYTE)(tokArrayPinningHelper >> 8);
6830 ilcode[4] = (BYTE)(tokArrayPinningHelper >> 16);
6831 ilcode[5] = (BYTE)(tokArrayPinningHelper >> 24);
6833 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6834 methInfo->ILCodeSize = sizeof(ilcode);
6835 methInfo->maxStack = 1;
6836 methInfo->EHcount = 0;
6837 methInfo->options = (CorInfoOptions)0;
6844 bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
6845 CORINFO_METHOD_INFO * methInfo)
6847 STANDARD_VM_CONTRACT;
6849 // Precondition: ftn is a method in mscorlib
6850 _ASSERTE(ftn->GetModule()->IsSystem());
6852 mdMethodDef tk = ftn->GetMemberDef();
6854 if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_POINTER)->GetMemberDef())
6856 // Return the argument that was passed in.
6857 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_CONV_U, CEE_RET };
6858 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6859 methInfo->ILCodeSize = sizeof(ilcode);
6860 methInfo->maxStack = 1;
6861 methInfo->EHcount = 0;
6862 methInfo->options = (CorInfoOptions)0;
6865 if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__SIZEOF)->GetMemberDef())
6867 _ASSERTE(ftn->HasMethodInstantiation());
6868 Instantiation inst = ftn->GetMethodInstantiation();
6870 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
6871 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6873 static BYTE ilcode[] = { CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0, CEE_RET };
6875 ilcode[2] = (BYTE)(tokGenericArg);
6876 ilcode[3] = (BYTE)(tokGenericArg >> 8);
6877 ilcode[4] = (BYTE)(tokGenericArg >> 16);
6878 ilcode[5] = (BYTE)(tokGenericArg >> 24);
6880 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6881 methInfo->ILCodeSize = sizeof(ilcode);
6882 methInfo->maxStack = 1;
6883 methInfo->EHcount = 0;
6884 methInfo->options = (CorInfoOptions)0;
6887 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef())
6889 // Return the argument that was passed in.
6890 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
6891 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6892 methInfo->ILCodeSize = sizeof(ilcode);
6893 methInfo->maxStack = 1;
6894 methInfo->EHcount = 0;
6895 methInfo->options = (CorInfoOptions)0;
6898 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD)->GetMemberDef())
6900 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6902 static BYTE ilcode[] = { CEE_LDARG_1,
6903 CEE_PREFIX1, (CEE_SIZEOF & 0xFF), 0,0,0,0,
6910 ilcode[3] = (BYTE)(tokGenericArg);
6911 ilcode[4] = (BYTE)(tokGenericArg >> 8);
6912 ilcode[5] = (BYTE)(tokGenericArg >> 16);
6913 ilcode[6] = (BYTE)(tokGenericArg >> 24);
6915 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6916 methInfo->ILCodeSize = sizeof(ilcode);
6917 methInfo->maxStack = 2;
6918 methInfo->EHcount = 0;
6919 methInfo->options = (CorInfoOptions)0;
6922 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD_BYTE_OFFSET)->GetMemberDef())
6924 static BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_ADD, CEE_RET };
6926 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6927 methInfo->ILCodeSize = sizeof(ilcode);
6928 methInfo->maxStack = 2;
6929 methInfo->EHcount = 0;
6930 methInfo->options = (CorInfoOptions)0;
6933 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ARE_SAME)->GetMemberDef())
6935 // Compare the two arguments
6936 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CEQ & 0xFF), CEE_RET };
6937 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6938 methInfo->ILCodeSize = sizeof(ilcode);
6939 methInfo->maxStack = 2;
6940 methInfo->EHcount = 0;
6941 methInfo->options = (CorInfoOptions)0;
6944 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_INIT_BLOCK_UNALIGNED)->GetMemberDef())
6946 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_LDARG_2, CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 0x01, CEE_PREFIX1, (CEE_INITBLK & 0xFF), CEE_RET };
6947 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6948 methInfo->ILCodeSize = sizeof(ilcode);
6949 methInfo->maxStack = 3;
6950 methInfo->EHcount = 0;
6951 methInfo->options = (CorInfoOptions)0;
6954 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_READ_UNALIGNED)->GetMemberDef() ||
6955 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_READ_UNALIGNED)->GetMemberDef())
6957 _ASSERTE(ftn->HasMethodInstantiation());
6958 Instantiation inst = ftn->GetMethodInstantiation();
6959 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
6960 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6962 static const BYTE ilcode[]
6965 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
6966 CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6970 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6971 methInfo->ILCodeSize = sizeof(ilcode);
6972 methInfo->maxStack = 2;
6973 methInfo->EHcount = 0;
6974 methInfo->options = (CorInfoOptions)0;
6977 else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_WRITE_UNALIGNED)->GetMemberDef() ||
6978 tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__PTR_WRITE_UNALIGNED)->GetMemberDef())
6980 _ASSERTE(ftn->HasMethodInstantiation());
6981 Instantiation inst = ftn->GetMethodInstantiation();
6982 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
6983 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
6985 static const BYTE ilcode[]
6989 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
6990 CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6994 methInfo->ILCode = const_cast<BYTE*>(ilcode);
6995 methInfo->ILCodeSize = sizeof(ilcode);
6996 methInfo->maxStack = 2;
6997 methInfo->EHcount = 0;
6998 methInfo->options = (CorInfoOptions)0;
7005 bool getILIntrinsicImplementationForVolatile(MethodDesc * ftn,
7006 CORINFO_METHOD_INFO * methInfo)
7008 STANDARD_VM_CONTRACT;
7011 // This replaces the implementations of Volatile.* in mscorlib with more efficient ones.
7012 // We do this because we cannot otherwise express these in C#. What we *want* to do is
7013 // to treat the byref args to these methods as "volatile." In pseudo-C#, this would look
7016 // int Read(ref volatile int location)
7021 // However, C# does not yet provide a way to declare a byref as "volatile." So instead,
7022 // we substitute raw IL bodies for these methods that use the correct volatile instructions.
7025 // Precondition: ftn is a method in mscorlib in the System.Threading.Volatile class
7026 _ASSERTE(ftn->GetModule()->IsSystem());
7027 _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__VOLATILE));
7028 _ASSERTE(strcmp(ftn->GetMethodTable()->GetClass()->GetDebugClassName(), "System.Threading.Volatile") == 0);
7030 const size_t VolatileMethodBodySize = 6;
7032 struct VolatileMethodImpl
7034 BinderMethodID methodId;
7035 BYTE body[VolatileMethodBodySize];
7038 #define VOLATILE_IMPL(type, loadinst, storeinst) \
7040 METHOD__VOLATILE__READ_##type, \
7043 CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7045 CEE_NOP, /*pad to VolatileMethodBodySize bytes*/ \
7050 METHOD__VOLATILE__WRITE_##type, \
7054 CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \
7060 static const VolatileMethodImpl volatileImpls[] =
7062 VOLATILE_IMPL(T, CEE_LDIND_REF, CEE_STIND_REF)
7063 VOLATILE_IMPL(Bool, CEE_LDIND_I1, CEE_STIND_I1)
7064 VOLATILE_IMPL(Int, CEE_LDIND_I4, CEE_STIND_I4)
7065 VOLATILE_IMPL(IntPtr, CEE_LDIND_I, CEE_STIND_I)
7066 VOLATILE_IMPL(UInt, CEE_LDIND_U4, CEE_STIND_I4)
7067 VOLATILE_IMPL(UIntPtr, CEE_LDIND_I, CEE_STIND_I)
7068 VOLATILE_IMPL(SByt, CEE_LDIND_I1, CEE_STIND_I1)
7069 VOLATILE_IMPL(Byte, CEE_LDIND_U1, CEE_STIND_I1)
7070 VOLATILE_IMPL(Shrt, CEE_LDIND_I2, CEE_STIND_I2)
7071 VOLATILE_IMPL(UShrt, CEE_LDIND_U2, CEE_STIND_I2)
7072 VOLATILE_IMPL(Flt, CEE_LDIND_R4, CEE_STIND_R4)
7075 // Ordinary volatile loads and stores only guarantee atomicity for pointer-sized (or smaller) data.
7076 // So, on 32-bit platforms we must use Interlocked operations instead for the 64-bit types.
7077 // The implementation in mscorlib already does this, so we will only substitute a new
7078 // IL body if we're running on a 64-bit platform.
7080 IN_WIN64(VOLATILE_IMPL(Long, CEE_LDIND_I8, CEE_STIND_I8))
7081 IN_WIN64(VOLATILE_IMPL(ULong, CEE_LDIND_I8, CEE_STIND_I8))
7082 IN_WIN64(VOLATILE_IMPL(Dbl, CEE_LDIND_R8, CEE_STIND_R8))
7085 mdMethodDef md = ftn->GetMemberDef();
7086 for (unsigned i = 0; i < NumItems(volatileImpls); i++)
7088 if (md == MscorlibBinder::GetMethod(volatileImpls[i].methodId)->GetMemberDef())
7090 methInfo->ILCode = const_cast<BYTE*>(volatileImpls[i].body);
7091 methInfo->ILCodeSize = VolatileMethodBodySize;
7092 methInfo->maxStack = 2;
7093 methInfo->EHcount = 0;
7094 methInfo->options = (CorInfoOptions)0;
7102 bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn,
7103 CORINFO_METHOD_INFO * methInfo)
7105 STANDARD_VM_CONTRACT;
7107 // Precondition: ftn is a method in mscorlib in the System.Threading.Interlocked class
7108 _ASSERTE(ftn->GetModule()->IsSystem());
7109 _ASSERTE(MscorlibBinder::IsClass(ftn->GetMethodTable(), CLASS__INTERLOCKED));
7111 // We are only interested if ftn's token and CompareExchange<T> token match
7112 if (ftn->GetMemberDef() != MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_T)->GetMemberDef())
7115 // Get MethodDesc for System.Threading.Interlocked.CompareExchangeFast()
7116 MethodDesc* cmpxchgFast = MscorlibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_OBJECT);
7118 // The MethodDesc lookup must not fail, and it should have the name "CompareExchangeFast"
7119 _ASSERTE(cmpxchgFast != NULL);
7120 _ASSERTE(strcmp(cmpxchgFast->GetName(), "CompareExchange") == 0);
7122 // Setup up the body of the method
7123 static BYTE il[] = {
7131 // Get the token for System.Threading.Interlocked.CompareExchangeFast(), and patch [target]
7132 mdMethodDef cmpxchgFastToken = cmpxchgFast->GetMemberDef();
7133 il[4] = (BYTE)((int)cmpxchgFastToken >> 0);
7134 il[5] = (BYTE)((int)cmpxchgFastToken >> 8);
7135 il[6] = (BYTE)((int)cmpxchgFastToken >> 16);
7136 il[7] = (BYTE)((int)cmpxchgFastToken >> 24);
7138 // Initialize methInfo
7139 methInfo->ILCode = const_cast<BYTE*>(il);
7140 methInfo->ILCodeSize = sizeof(il);
7141 methInfo->maxStack = 3;
7142 methInfo->EHcount = 0;
7143 methInfo->options = (CorInfoOptions)0;
7148 bool getILIntrinsicImplementationForRuntimeHelpers(MethodDesc * ftn,
7149 CORINFO_METHOD_INFO * methInfo)
7151 STANDARD_VM_CONTRACT;
7153 // Precondition: ftn is a method in mscorlib
7154 _ASSERTE(ftn->GetModule()->IsSystem());
7156 mdMethodDef tk = ftn->GetMemberDef();
7158 if (tk == MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_REFERENCE_OR_CONTAINS_REFERENCES)->GetMemberDef())
7160 _ASSERTE(ftn->HasMethodInstantiation());
7161 Instantiation inst = ftn->GetMethodInstantiation();
7163 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7164 TypeHandle typeHandle = inst[0];
7165 MethodTable * methodTable = typeHandle.GetMethodTable();
7167 static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
7168 static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };
7170 if (!methodTable->IsValueType() || methodTable->ContainsPointers())
7172 methInfo->ILCode = const_cast<BYTE*>(returnTrue);
7176 methInfo->ILCode = const_cast<BYTE*>(returnFalse);
7179 methInfo->ILCodeSize = sizeof(returnTrue);
7180 methInfo->maxStack = 1;
7181 methInfo->EHcount = 0;
7182 methInfo->options = (CorInfoOptions)0;
7189 //---------------------------------------------------------------------------------------
7193 getMethodInfoHelper(
7195 CORINFO_METHOD_HANDLE ftnHnd,
7196 COR_ILMETHOD_DECODER * header,
7197 CORINFO_METHOD_INFO * methInfo)
7199 STANDARD_VM_CONTRACT;
7201 _ASSERTE(ftn == GetMethod(ftnHnd));
7203 methInfo->ftn = ftnHnd;
7204 methInfo->scope = GetScopeHandle(ftn);
7205 methInfo->regionKind = CORINFO_REGION_JIT;
7207 // For Jitted code the regionKind is JIT;
7208 // For Ngen-ed code the zapper will set this to HOT or COLD, if we
7209 // are using IBC data to partition methods into Hot/Cold regions
7211 /* Grab information from the IL header */
7213 PCCOR_SIGNATURE pLocalSig = NULL;
7214 DWORD cbLocalSig = 0;
7218 bool fILIntrinsic = false;
7220 MethodTable * pMT = ftn->GetMethodTable();
7222 if (MscorlibBinder::IsClass(pMT, CLASS__JIT_HELPERS))
7224 fILIntrinsic = getILIntrinsicImplementation(ftn, methInfo);
7226 else if (MscorlibBinder::IsClass(pMT, CLASS__UNSAFE))
7228 fILIntrinsic = getILIntrinsicImplementationForUnsafe(ftn, methInfo);
7230 else if (MscorlibBinder::IsClass(pMT, CLASS__INTERLOCKED))
7232 fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo);
7234 else if (MscorlibBinder::IsClass(pMT, CLASS__VOLATILE))
7236 fILIntrinsic = getILIntrinsicImplementationForVolatile(ftn, methInfo);
7238 else if (MscorlibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS))
7240 fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo);
7245 getMethodInfoILMethodHeaderHelper(header, methInfo);
7246 pLocalSig = header->LocalVarSig;
7247 cbLocalSig = header->cbLocalVarSig;
7252 _ASSERTE(ftn->IsDynamicMethod());
7254 DynamicResolver * pResolver = ftn->AsDynamicMethodDesc()->GetResolver();
7255 unsigned int EHCount;
7256 methInfo->ILCode = pResolver->GetCodeInfo(&methInfo->ILCodeSize,
7257 &methInfo->maxStack,
7260 methInfo->EHcount = (unsigned short)EHCount;
7261 SigPointer localSig = pResolver->GetLocalSig();
7262 localSig.GetSignature(&pLocalSig, &cbLocalSig);
7265 methInfo->options = (CorInfoOptions)(((UINT32)methInfo->options) |
7266 ((ftn->AcquiresInstMethodTableFromThis() ? CORINFO_GENERICS_CTXT_FROM_THIS : 0) |
7267 (ftn->RequiresInstMethodTableArg() ? CORINFO_GENERICS_CTXT_FROM_METHODTABLE : 0) |
7268 (ftn->RequiresInstMethodDescArg() ? CORINFO_GENERICS_CTXT_FROM_METHODDESC : 0)));
7270 // EEJitManager::ResolveEHClause and CrawlFrame::GetExactGenericInstantiations
7271 // need to be able to get to CORINFO_GENERICS_CTXT_MASK if there are any
7272 // catch clauses like "try {} catch(MyException<T> e) {}".
7273 // Such constructs are rare, and having to extend the lifetime of variable
7274 // for such cases is reasonable
7276 if (methInfo->options & CORINFO_GENERICS_CTXT_MASK)
7278 #if defined(PROFILING_SUPPORTED)
7279 BOOL fProfilerRequiresGenericsContextForEnterLeave = FALSE;
7281 BEGIN_PIN_PROFILER(CORProfilerPresent());
7282 if (g_profControlBlock.pProfInterface->RequiresGenericsContextForEnterLeave())
7284 fProfilerRequiresGenericsContextForEnterLeave = TRUE;
7288 if (fProfilerRequiresGenericsContextForEnterLeave)
7290 methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7293 #endif // defined(PROFILING_SUPPORTED)
7295 // Check all the exception clauses
7297 if (ftn->IsDynamicMethod())
7299 // @TODO: how do we detect the need to mark this flag?
7303 COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
7305 for (unsigned i = 0; i < methInfo->EHcount; i++)
7307 const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo =
7308 (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)header->EH->EHClause(i, &ehClause);
7310 // Is it a typed catch clause?
7311 if (ehInfo->GetFlags() != COR_ILEXCEPTION_CLAUSE_NONE)
7314 // Check if we catch "C<T>" ?
7316 DWORD catchTypeToken = ehInfo->GetClassToken();
7317 if (TypeFromToken(catchTypeToken) != mdtTypeSpec)
7320 PCCOR_SIGNATURE pSig;
7322 IfFailThrow(ftn->GetMDImport()->GetTypeSpecFromToken(catchTypeToken, &pSig, &cSig));
7324 SigPointer psig(pSig, cSig);
7326 SigTypeContext sigTypeContext(ftn);
7327 if (psig.IsPolyType(&sigTypeContext) & hasSharableVarsMask)
7329 methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7337 PCCOR_SIGNATURE pSig = NULL;
7339 ftn->GetSig(&pSig, &cbSig);
7341 /* Fetch the method signature */
7342 // Type parameters in the signature should be instantiated according to the
7343 // class/method/array instantiation of ftnHnd
7344 CEEInfo::ConvToJitSig(
7347 GetScopeHandle(ftn),
7353 // Shared generic or static per-inst methods and shared methods on generic structs
7354 // take an extra argument representing their instantiation
7355 if (ftn->RequiresInstArg())
7356 methInfo->args.callConv = (CorInfoCallConv)(methInfo->args.callConv | CORINFO_CALLCONV_PARAMTYPE);
7358 _ASSERTE((IsMdStatic(ftn->GetAttrs()) == 0) == ((methInfo->args.callConv & CORINFO_CALLCONV_HASTHIS) != 0));
7360 /* And its local variables */
7361 // Type parameters in the signature should be instantiated according to the
7362 // class/method/array instantiation of ftnHnd
7363 CEEInfo::ConvToJitSig(
7366 GetScopeHandle(ftn),
7371 } // getMethodInfoHelper
7373 //---------------------------------------------------------------------------------------
7376 CEEInfo::getMethodInfo(
7377 CORINFO_METHOD_HANDLE ftnHnd,
7378 CORINFO_METHOD_INFO * methInfo)
7387 bool result = false;
7389 JIT_TO_EE_TRANSITION();
7391 MethodDesc * ftn = GetMethod(ftnHnd);
7393 if (!ftn->IsDynamicMethod() && (!ftn->IsIL() || !ftn->GetRVA() || ftn->IsWrapperStub()))
7395 /* Return false if not IL or has no code */
7400 /* Get the IL header */
7401 /* <REVISIT_TODO>TODO: canInline already did validation, however, we do it again
7402 here because NGEN uses this function without calling canInline
7403 It would be nice to avoid this redundancy </REVISIT_TODO>*/
7404 Module* pModule = ftn->GetModule();
7406 bool verify = !Security::CanSkipVerification(ftn);
7408 if (ftn->IsDynamicMethod())
7410 getMethodInfoHelper(ftn, ftnHnd, NULL, methInfo);
7414 COR_ILMETHOD_DECODER::DecoderStatus status = COR_ILMETHOD_DECODER::SUCCESS;
7415 COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), verify ? &status : NULL);
7417 // If we get a verification error then we try to demand SkipVerification for the module
7418 if (status == COR_ILMETHOD_DECODER::VERIFICATION_ERROR &&
7419 Security::CanSkipVerification(pModule->GetDomainAssembly()))
7421 status = COR_ILMETHOD_DECODER::SUCCESS;
7424 if (status != COR_ILMETHOD_DECODER::SUCCESS)
7426 if (status == COR_ILMETHOD_DECODER::VERIFICATION_ERROR)
7428 // Throw a verification HR
7429 COMPlusThrowHR(COR_E_VERIFICATION);
7433 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL);
7437 getMethodInfoHelper(ftn, ftnHnd, &header, methInfo);
7440 LOG((LF_JIT, LL_INFO100000, "Getting method info (possible inline) %s::%s%s\n",
7441 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
7446 EE_TO_JIT_TRANSITION();
7453 /************************************************************************
7454 Return true when ftn contains a local of type CLASS__STACKCRAWMARK
7457 bool containsStackCrawlMarkLocal(MethodDesc* ftn)
7459 STANDARD_VM_CONTRACT;
7461 COR_ILMETHOD* ilHeader = ftn->GetILHeader();
7464 COR_ILMETHOD_DECODER header(ilHeader, ftn->GetMDImport(), NULL);
7466 if (header.LocalVarSig == NULL)
7469 SigPointer ptr(header.LocalVarSig, header.cbLocalVarSig);
7471 IfFailThrow(ptr.GetData(NULL)); // IMAGE_CEE_CS_CALLCONV_LOCAL_SIG
7474 IfFailThrow(ptr.GetData(&numLocals));
7476 for(ULONG i = 0; i < numLocals; i++)
7478 CorElementType eType;
7479 IfFailThrow(ptr.PeekElemType(&eType));
7480 if (eType != ELEMENT_TYPE_VALUETYPE)
7482 IfFailThrow(ptr.SkipExactlyOne());
7486 IfFailThrow(ptr.GetElemType(NULL));
7489 IfFailThrow(ptr.GetToken(&token));
7491 // We are inside mscorlib - simple token match is sufficient
7492 if (token == MscorlibBinder::GetClass(CLASS__STACKCRAWMARK)->GetCl())
7501 /*************************************************************
7502 * Check if the caller and calle are in the same assembly
7503 * i.e. do not inline across assemblies
7504 *************************************************************/
7506 CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller,
7507 CORINFO_METHOD_HANDLE hCallee,
7508 DWORD* pRestrictions)
7517 CorInfoInline result = INLINE_PASS; // By default we pass.
7518 // Do not set pass in the rest of the method.
7519 DWORD dwRestrictions = 0; // By default, no restrictions
7520 const char * szFailReason = NULL; // for reportInlineDecision
7522 JIT_TO_EE_TRANSITION();
7524 // This does not work in the multi-threaded case
7526 // Caller should check this condition first
7527 _ASSERTE(!(CORINFO_FLG_DONT_INLINE & getMethodAttribsInternal(hCallee)));
7530 MethodDesc* pCaller = GetMethod(hCaller);
7531 MethodDesc* pCallee = GetMethod(hCallee);
7533 if (pCallee->IsNoMetadata())
7535 result = INLINE_FAIL;
7536 szFailReason = "Inlinee is NoMetadata";
7540 #ifdef DEBUGGING_SUPPORTED
7542 // If the callee wants debuggable code, don't allow it to be inlined
7545 // Combining the next two lines, and eliminating jitDebuggerFlags, leads to bad codegen in x86 Release builds using Visual C++ 19.00.24215.1.
7546 CORJIT_FLAGS jitDebuggerFlags = GetDebuggerCompileFlags(pCallee->GetModule(), CORJIT_FLAGS());
7547 if (jitDebuggerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE))
7549 result = INLINE_NEVER;
7550 szFailReason = "Inlinee is debuggable";
7556 // The orginal caller is the current method
7557 MethodDesc * pOrigCaller;
7558 pOrigCaller = m_pMethodBeingCompiled;
7559 Module * pOrigCallerModule;
7560 pOrigCallerModule = pOrigCaller->GetLoaderModule();
7562 // Prevent recursive compiling/inlining/verifying
7563 if (pOrigCaller != pCallee)
7565 // The Inliner may not do code verification.
7566 // So never inline anything that is unverifiable / bad code.
7567 if (!Security::CanSkipVerification(pCallee))
7569 // Inlinee needs to be verifiable
7570 if (!pCallee->IsVerifiable())
7572 result = INLINE_NEVER;
7573 szFailReason = "Inlinee is not verifiable";
7579 // We check this here as the call to MethodDesc::IsVerifiable()
7580 // may set CORINFO_FLG_DONT_INLINE.
7581 if (pCallee->IsNotInline())
7583 result = INLINE_NEVER;
7584 szFailReason = "Inlinee is marked as no inline";
7588 // Also check to see if the method requires a security object. This means they call demand and
7589 // shouldn't be inlined.
7590 if (IsMdRequireSecObject(pCallee->GetAttrs()))
7592 result = INLINE_NEVER;
7593 szFailReason = "Inlinee requires a security object (or contains StackCrawlMark)";
7597 // If the method is MethodImpl'd by another method within the same type, then we have
7598 // an issue that the importer will import the wrong body. In this case, we'll just
7599 // disallow inlining because getFunctionEntryPoint will do the right thing.
7601 MethodDesc *pMDDecl = pCallee;
7602 MethodTable *pMT = pMDDecl->GetMethodTable();
7603 MethodDesc *pMDImpl = pMT->MapMethodDeclToMethodImpl(pMDDecl);
7605 if (pMDDecl != pMDImpl)
7607 result = INLINE_NEVER;
7608 szFailReason = "Inlinee is MethodImpl'd by another method within the same type";
7614 // Perform the Cross-Assembly inlining checks
7617 Module * pCalleeModule = pCallee->GetModule();
7619 #ifdef FEATURE_PREJIT
7620 Assembly * pCalleeAssembly = pCalleeModule->GetAssembly();
7624 // Make sure that all methods with StackCrawlMark are marked as IsMdRequireSecObject
7626 if (pCalleeAssembly->IsSystem())
7628 _ASSERTE(!containsStackCrawlMarkLocal(pCallee));
7632 // To allow for servicing of Ngen images we want to disable most
7633 // Cross-Assembly inlining except for the cases that we explicitly allow.
7635 if (IsCompilingForNGen())
7637 // This is an canInline call at Ngen time
7640 Assembly * pOrigCallerAssembly = pOrigCallerModule->GetAssembly();
7642 if (pCalleeAssembly == pOrigCallerAssembly)
7644 // Within the same assembly
7645 // we can freely inline with no restrictions
7649 #ifdef FEATURE_READYTORUN_COMPILER
7650 // No inlinining for version resilient code except if in the same version bubble
7651 // If this condition changes, please make the corresponding change
7652 // in getCallInfo, too.
7653 if (IsReadyToRunCompilation() &&
7655 !IsInSameVersionBubble(pCaller, pCallee)
7658 result = INLINE_NEVER;
7659 szFailReason = "Cross-module inlining in version resilient code";
7665 #endif // FEATURE_PREJIT
7667 // TODO: We can probably be smarter here if the caller is jitted, as we will
7668 // know for sure if the inlinee has really no string interning active (currently
7669 // it's only on in the ngen case (besides requiring the attribute)), but this is getting
7670 // too subtle. Will only do if somebody screams about it, as bugs here are going to
7672 if ((pOrigCallerModule != pCalleeModule) && pCalleeModule->IsNoStringInterning())
7674 dwRestrictions |= INLINE_NO_CALLEE_LDSTR;
7677 // The remoting interception can be skipped only if the call is on same this pointer
7678 if (pCallee->MayBeRemotingIntercepted())
7680 dwRestrictions |= INLINE_SAME_THIS;
7684 #ifdef PROFILING_SUPPORTED
7685 if (CORProfilerPresent())
7689 // See if rejit-specific flags for the caller disable inlining
7690 if ((ReJitManager::GetCurrentReJitFlags(pCaller) &
7691 COR_PRF_CODEGEN_DISABLE_INLINING) != 0)
7693 result = INLINE_FAIL;
7694 szFailReason = "ReJIT request disabled inlining from caller";
7698 // If the profiler has set a mask preventing inlining, always return
7699 // false to the jit.
7700 if (CORProfilerDisableInlining())
7702 result = INLINE_FAIL;
7703 szFailReason = "Profiler disabled inlining globally";
7707 // If the profiler wishes to be notified of JIT events and the result from
7708 // the above tests will cause a function to be inlined, we need to tell the
7709 // profiler that this inlining is going to take place, and give them a
7710 // chance to prevent it.
7712 BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo());
7713 if (pCaller->IsILStub() || pCallee->IsILStub())
7721 HRESULT hr = g_profControlBlock.pProfInterface->JITInlining(
7722 (FunctionID)pCaller,
7723 (FunctionID)pCallee,
7726 if (SUCCEEDED(hr) && !fShouldInline)
7728 result = INLINE_FAIL;
7729 szFailReason = "Profiler disabled inlining locally";
7736 #endif // PROFILING_SUPPORTED
7739 #ifdef PROFILING_SUPPORTED
7740 if (CORProfilerPresent())
7744 // See if rejit-specific flags for the caller disable inlining
7745 if ((ReJitManager::GetCurrentReJitFlags(pCaller) &
7746 COR_PRF_CODEGEN_DISABLE_INLINING) != 0)
7748 result = INLINE_FAIL;
7749 szFailReason = "ReJIT request disabled inlining from caller";
7753 // If the profiler has set a mask preventing inlining, always return
7754 // false to the jit.
7755 if (CORProfilerDisableInlining())
7757 result = INLINE_FAIL;
7758 szFailReason = "Profiler disabled inlining globally";
7762 // If the profiler wishes to be notified of JIT events and the result from
7763 // the above tests will cause a function to be inlined, we need to tell the
7764 // profiler that this inlining is going to take place, and give them a
7765 // chance to prevent it.
7767 BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo());
7768 if (pCaller->IsILStub() || pCallee->IsILStub())
7776 HRESULT hr = g_profControlBlock.pProfInterface->JITInlining(
7777 (FunctionID)pCaller,
7778 (FunctionID)pCallee,
7781 if (SUCCEEDED(hr) && !fShouldInline)
7783 result = INLINE_FAIL;
7784 szFailReason = "Profiler disabled inlining locally";
7791 #endif // PROFILING_SUPPORTED
7795 EE_TO_JIT_TRANSITION();
7797 if (result == INLINE_PASS && dwRestrictions)
7801 *pRestrictions = dwRestrictions;
7805 // If the jitter didn't want to know about restrictions, it shouldn't be inlining
7806 result = INLINE_FAIL;
7807 szFailReason = "Inlinee has restrictions the JIT doesn't want";
7814 // Denied inlining, makes no sense to pass out restrictions,
7819 if (dontInline(result))
7821 // If you hit this assert, it means you added a new way to prevent inlining
7822 // without documenting it for ETW!
7823 _ASSERTE(szFailReason != NULL);
7824 reportInliningDecision(hCaller, hCallee, result, szFailReason);
7830 void CEEInfo::reportInliningDecision (CORINFO_METHOD_HANDLE inlinerHnd,
7831 CORINFO_METHOD_HANDLE inlineeHnd,
7832 CorInfoInline inlineResult,
7833 const char * reason)
7835 STATIC_CONTRACT_THROWS;
7836 STATIC_CONTRACT_GC_TRIGGERS;
7837 STATIC_CONTRACT_SO_TOLERANT;
7839 JIT_TO_EE_TRANSITION();
7842 if (LoggingOn(LF_JIT, LL_INFO100000))
7844 SString currentMethodName;
7845 currentMethodName.AppendUTF8(m_pMethodBeingCompiled->GetModule_NoLogging()->GetFile()->GetSimpleName());
7846 currentMethodName.Append(L'/');
7847 TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled, TypeString::FormatBasic);
7849 SString inlineeMethodName;
7850 if (GetMethod(inlineeHnd))
7852 inlineeMethodName.AppendUTF8(GetMethod(inlineeHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
7853 inlineeMethodName.Append(L'/');
7854 TypeString::AppendMethodInternal(inlineeMethodName, GetMethod(inlineeHnd), TypeString::FormatBasic);
7858 inlineeMethodName.AppendASCII( "<null>" );
7861 SString inlinerMethodName;
7862 if (GetMethod(inlinerHnd))
7864 inlinerMethodName.AppendUTF8(GetMethod(inlinerHnd)->GetModule_NoLogging()->GetFile()->GetSimpleName());
7865 inlinerMethodName.Append(L'/');
7866 TypeString::AppendMethodInternal(inlinerMethodName, GetMethod(inlinerHnd), TypeString::FormatBasic);
7870 inlinerMethodName.AppendASCII("<null>");
7873 if (dontInline(inlineResult))
7875 LOG((LF_JIT, LL_INFO100000,
7876 "While compiling '%S', inline of '%S' into '%S' failed because: '%s'.\n",
7877 currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
7878 inlinerMethodName.GetUnicode(), reason));
7882 LOG((LF_JIT, LL_INFO100000, "While compiling '%S', inline of '%S' into '%S' succeeded.\n",
7883 currentMethodName.GetUnicode(), inlineeMethodName.GetUnicode(),
7884 inlinerMethodName.GetUnicode()));
7890 //I'm gonna duplicate this code because the format is slightly different. And LoggingOn is debug only.
7891 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
7892 TRACE_LEVEL_VERBOSE,
7893 CLR_JITTRACING_KEYWORD))
7895 SString methodBeingCompiledNames[3];
7896 SString inlinerNames[3];
7897 SString inlineeNames[3];
7898 MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
7899 #define GMI(pMD, strArray) \
7902 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
7904 (strArray)[0].Set(W("<null>")); \
7905 (strArray)[1].Set(W("<null>")); \
7906 (strArray)[2].Set(W("<null>")); \
7909 GMI(methodBeingCompiled, methodBeingCompiledNames);
7910 GMI(GetMethod(inlinerHnd), inlinerNames);
7911 GMI(GetMethod(inlineeHnd), inlineeNames);
7913 if (dontInline(inlineResult))
7915 const char * str = (reason ? reason : "");
7917 FireEtwMethodJitInliningFailed(methodBeingCompiledNames[0].GetUnicode(),
7918 methodBeingCompiledNames[1].GetUnicode(),
7919 methodBeingCompiledNames[2].GetUnicode(),
7920 inlinerNames[0].GetUnicode(),
7921 inlinerNames[1].GetUnicode(),
7922 inlinerNames[2].GetUnicode(),
7923 inlineeNames[0].GetUnicode(),
7924 inlineeNames[1].GetUnicode(),
7925 inlineeNames[2].GetUnicode(),
7926 inlineResult == INLINE_NEVER,
7928 GetClrInstanceId());
7932 FireEtwMethodJitInliningSucceeded(methodBeingCompiledNames[0].GetUnicode(),
7933 methodBeingCompiledNames[1].GetUnicode(),
7934 methodBeingCompiledNames[2].GetUnicode(),
7935 inlinerNames[0].GetUnicode(),
7936 inlinerNames[1].GetUnicode(),
7937 inlinerNames[2].GetUnicode(),
7938 inlineeNames[0].GetUnicode(),
7939 inlineeNames[1].GetUnicode(),
7940 inlineeNames[2].GetUnicode(),
7941 GetClrInstanceId());
7946 EE_TO_JIT_TRANSITION();
7950 /*************************************************************
7951 This loads the (formal) declared constraints on the class and method type parameters,
7952 and detects (but does not itself reject) circularities among the class type parameters
7953 and (separately) method type parameters.
7955 It must be called whenever we verify a typical method, ie any method (generic or
7956 nongeneric) in a typical class. It must be called for non-generic methods too,
7957 because their bodies may still mention class type parameters which will need to
7958 have their formal constraints loaded in order to perform type compatibility tests.
7960 We have to rule out cycles like "C<U,T> where T:U, U:T" only to avoid looping
7961 in the verifier (ie the T.CanCast(A) would loop calling U.CanCast(A) then
7962 T.CanCastTo(A) etc.). Since the JIT only tries to walk the hierarchy from a type
7963 a parameter when verifying, it should be safe to JIT unverified, but trusted,
7964 instantiations even in the presence of cycle constraints.
7965 @TODO: It should be possible (and easy) to detect cycles much earlier on by
7966 directly inspecting the metadata. All you have to do is check that, for each
7967 of the n type parameters to a class or method there is no path of length n
7968 obtained by following naked type parameter constraints of the same kind.
7969 This can be detected by looking directly at metadata, without actually loading
7970 the typehandles for the naked type parameters.
7971 *************************************************************/
7973 void CEEInfo::initConstraintsForVerification(CORINFO_METHOD_HANDLE hMethod,
7974 BOOL *pfHasCircularClassConstraints,
7975 BOOL *pfHasCircularMethodConstraints)
7982 PRECONDITION(CheckPointer(pfHasCircularClassConstraints));
7983 PRECONDITION(CheckPointer(pfHasCircularMethodConstraints));
7986 *pfHasCircularClassConstraints = FALSE;
7987 *pfHasCircularMethodConstraints = FALSE;
7989 JIT_TO_EE_TRANSITION();
7991 MethodDesc* pMethod = GetMethod(hMethod);
7992 if (pMethod->IsTypicalMethodDefinition())
7994 // Force a load of the constraints on the type parameters, detecting cyclic bounds
7995 pMethod->LoadConstraintsForTypicalMethodDefinition(pfHasCircularClassConstraints,pfHasCircularMethodConstraints);
7998 EE_TO_JIT_TRANSITION();
8001 /*************************************************************
8002 * Check if a method to be compiled is an instantiation
8003 * of generic code that has already been verified.
8004 * Three possible return values (see corinfo.h)
8005 *************************************************************/
8007 CorInfoInstantiationVerification
8008 CEEInfo::isInstantiationOfVerifiedGeneric(CORINFO_METHOD_HANDLE hMethod)
8017 CorInfoInstantiationVerification result = INSTVER_NOT_INSTANTIATION;
8019 JIT_TO_EE_TRANSITION();
8021 MethodDesc * pMethod = GetMethod(hMethod);
8023 if (!(pMethod->HasClassOrMethodInstantiation()))
8025 result = INSTVER_NOT_INSTANTIATION;
8029 if (pMethod->IsTypicalMethodDefinition())
8031 result = INSTVER_NOT_INSTANTIATION;
8035 result = pMethod->IsVerifiable() ? INSTVER_GENERIC_PASSED_VERIFICATION
8036 : INSTVER_GENERIC_FAILED_VERIFICATION;
8040 EE_TO_JIT_TRANSITION();
8045 /*************************************************************
8046 * Similar to above, but perform check for tail call
8047 * eligibility. The callee can be passed as NULL if not known
8048 * (calli and callvirt).
8049 *************************************************************/
8051 bool CEEInfo::canTailCall (CORINFO_METHOD_HANDLE hCaller,
8052 CORINFO_METHOD_HANDLE hDeclaredCallee,
8053 CORINFO_METHOD_HANDLE hExactCallee,
8063 bool result = false;
8064 const char * szFailReason = NULL;
8066 JIT_TO_EE_TRANSITION();
8068 // See comments in canInline above.
8070 MethodDesc* pCaller = GetMethod(hCaller);
8071 MethodDesc* pDeclaredCallee = GetMethod(hDeclaredCallee);
8072 MethodDesc* pExactCallee = GetMethod(hExactCallee);
8074 _ASSERTE(pCaller->GetModule());
8075 _ASSERTE(pCaller->GetModule()->GetClassLoader());
8077 _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule());
8078 _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule()->GetClassLoader());
8080 // If the caller is the static constructor (.cctor) of a class which has a ComImport base class
8081 // somewhere up the class hierarchy, then we cannot make the call into a tailcall. See
8082 // RegisterObjectCreationCallback() in ExtensibleClassFactory.cpp for more information.
8083 if (pCaller->IsClassConstructor() &&
8084 pCaller->GetMethodTable()->IsComObjectType())
8087 szFailReason = "Caller is ComImport .cctor";
8091 // TailCalls will throw off security stackwalking logic when there is a declarative Assert
8092 // Note that this check will also include declarative demands. It's OK to do a tailcall in
8093 // those cases, but we currently don't have a way to check only for declarative Asserts.
8094 if (pCaller->IsInterceptedForDeclSecurity())
8097 szFailReason = "Caller has declarative security";
8103 mdMethodDef callerToken = pCaller->GetMemberDef();
8105 // We don't want to tailcall the entrypoint for an application; JIT64 will sometimes
8106 // do this for simple entrypoints and it results in a rather confusing debugging
8108 if (callerToken == pCaller->GetModule()->GetEntryPointToken())
8111 szFailReason = "Caller is the entry point";
8115 if (!pCaller->IsNoMetadata())
8117 // Do not tailcall from methods that are marked as noinline (people often use no-inline
8118 // to mean "I want to always see this method in stacktrace")
8119 DWORD dwImplFlags = 0;
8120 IfFailThrow(pCaller->GetMDImport()->GetMethodImplProps(callerToken, NULL, &dwImplFlags));
8122 if (IsMiNoInlining(dwImplFlags))
8125 szFailReason = "Caller is marked as no inline";
8130 // Methods with StackCrawlMark depend on finding their caller on the stack.
8131 // If we tail call one of these guys, they get confused. For lack of
8132 // a better way of identifying them, we use DynamicSecurity attribute to identify
8133 // them. We have an assert in canInline that ensures all StackCrawlMark
8134 // methods are appropriately marked.
8136 if ((pExactCallee != NULL) && IsMdRequireSecObject(pExactCallee->GetAttrs()))
8139 szFailReason = "Callee might have a StackCrawlMark.LookForMyCaller";
8149 EE_TO_JIT_TRANSITION();
8153 // If you hit this assert, it means you added a new way to prevent tail calls
8154 // without documenting it for ETW!
8155 _ASSERTE(szFailReason != NULL);
8156 reportTailCallDecision(hCaller, hExactCallee, fIsTailPrefix, TAILCALL_FAIL, szFailReason);
8162 void CEEInfo::reportTailCallDecision (CORINFO_METHOD_HANDLE callerHnd,
8163 CORINFO_METHOD_HANDLE calleeHnd,
8165 CorInfoTailCall tailCallResult,
8166 const char * reason)
8168 STATIC_CONTRACT_THROWS;
8169 STATIC_CONTRACT_GC_TRIGGERS;
8170 STATIC_CONTRACT_SO_TOLERANT;
8172 JIT_TO_EE_TRANSITION();
8174 //put code here. Make sure to report the method being compiled in addition to inliner and inlinee.
8176 if (LoggingOn(LF_JIT, LL_INFO100000))
8178 SString currentMethodName;
8179 TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled,
8180 TypeString::FormatBasic);
8182 SString calleeMethodName;
8183 if (GetMethod(calleeHnd))
8185 TypeString::AppendMethodInternal(calleeMethodName, GetMethod(calleeHnd),
8186 TypeString::FormatBasic);
8190 calleeMethodName.AppendASCII( "<null>" );
8193 SString callerMethodName;
8194 if (GetMethod(callerHnd))
8196 TypeString::AppendMethodInternal(callerMethodName, GetMethod(callerHnd),
8197 TypeString::FormatBasic);
8201 callerMethodName.AppendASCII( "<null>" );
8203 if (tailCallResult == TAILCALL_FAIL)
8205 LOG((LF_JIT, LL_INFO100000,
8206 "While compiling '%S', %Splicit tail call from '%S' to '%S' failed because: '%s'.\n",
8207 currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8208 callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), reason));
8212 static const char * const tailCallType[] = {
8213 "optimized tail call", "recursive loop", "helper assisted tailcall"
8215 _ASSERTE(tailCallResult >= 0 && (size_t)tailCallResult < sizeof(tailCallType) / sizeof(tailCallType[0]));
8216 LOG((LF_JIT, LL_INFO100000,
8217 "While compiling '%S', %Splicit tail call from '%S' to '%S' generated as a %s.\n",
8218 currentMethodName.GetUnicode(), fIsTailPrefix ? W("ex") : W("im"),
8219 callerMethodName.GetUnicode(), calleeMethodName.GetUnicode(), tailCallType[tailCallResult]));
8225 // I'm gonna duplicate this code because the format is slightly different. And LoggingOn is debug only.
8226 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context,
8227 TRACE_LEVEL_VERBOSE,
8228 CLR_JITTRACING_KEYWORD))
8230 SString methodBeingCompiledNames[3];
8231 SString callerNames[3];
8232 SString calleeNames[3];
8233 MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8234 #define GMI(pMD, strArray) \
8237 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8239 (strArray)[0].Set(W("<null>")); \
8240 (strArray)[1].Set(W("<null>")); \
8241 (strArray)[2].Set(W("<null>")); \
8244 GMI(methodBeingCompiled, methodBeingCompiledNames);
8245 GMI(GetMethod(callerHnd), callerNames);
8246 GMI(GetMethod(calleeHnd), calleeNames);
8248 if (tailCallResult == TAILCALL_FAIL)
8250 const char * str = (reason ? reason : "");
8252 FireEtwMethodJitTailCallFailed(methodBeingCompiledNames[0].GetUnicode(),
8253 methodBeingCompiledNames[1].GetUnicode(),
8254 methodBeingCompiledNames[2].GetUnicode(),
8255 callerNames[0].GetUnicode(),
8256 callerNames[1].GetUnicode(),
8257 callerNames[2].GetUnicode(),
8258 calleeNames[0].GetUnicode(),
8259 calleeNames[1].GetUnicode(),
8260 calleeNames[2].GetUnicode(),
8263 GetClrInstanceId());
8267 FireEtwMethodJitTailCallSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8268 methodBeingCompiledNames[1].GetUnicode(),
8269 methodBeingCompiledNames[2].GetUnicode(),
8270 callerNames[0].GetUnicode(),
8271 callerNames[1].GetUnicode(),
8272 callerNames[2].GetUnicode(),
8273 calleeNames[0].GetUnicode(),
8274 calleeNames[1].GetUnicode(),
8275 calleeNames[2].GetUnicode(),
8278 GetClrInstanceId());
8284 EE_TO_JIT_TRANSITION();
8287 void CEEInfo::getEHinfoHelper(
8288 CORINFO_METHOD_HANDLE ftnHnd,
8290 CORINFO_EH_CLAUSE* clause,
8291 COR_ILMETHOD_DECODER* pILHeader)
8293 STANDARD_VM_CONTRACT;
8295 _ASSERTE(CheckPointer(pILHeader->EH));
8296 _ASSERTE(EHnumber < pILHeader->EH->EHCount());
8298 COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
8299 const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo;
8300 ehInfo = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)pILHeader->EH->EHClause(EHnumber, &ehClause);
8302 clause->Flags = (CORINFO_EH_CLAUSE_FLAGS)ehInfo->GetFlags();
8303 clause->TryOffset = ehInfo->GetTryOffset();
8304 clause->TryLength = ehInfo->GetTryLength();
8305 clause->HandlerOffset = ehInfo->GetHandlerOffset();
8306 clause->HandlerLength = ehInfo->GetHandlerLength();
8307 if ((clause->Flags & CORINFO_EH_CLAUSE_FILTER) == 0)
8308 clause->ClassToken = ehInfo->GetClassToken();
8310 clause->FilterOffset = ehInfo->GetFilterOffset();
8313 /*********************************************************************/
8314 // get individual exception handler
8315 void CEEInfo::getEHinfo(
8316 CORINFO_METHOD_HANDLE ftnHnd,
8318 CORINFO_EH_CLAUSE* clause)
8327 JIT_TO_EE_TRANSITION();
8329 MethodDesc * ftn = GetMethod(ftnHnd);
8331 if (IsDynamicMethodHandle(ftnHnd))
8333 GetMethod(ftnHnd)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
8337 COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
8338 getEHinfoHelper(ftnHnd, EHnumber, clause, &header);
8341 EE_TO_JIT_TRANSITION();
8344 //---------------------------------------------------------------------------------------
8347 CEEInfo::getMethodSig(
8348 CORINFO_METHOD_HANDLE ftnHnd,
8349 CORINFO_SIG_INFO * sigRet,
8350 CORINFO_CLASS_HANDLE owner)
8359 JIT_TO_EE_TRANSITION();
8361 getMethodSigInternal(ftnHnd, sigRet, owner);
8363 EE_TO_JIT_TRANSITION();
8366 //---------------------------------------------------------------------------------------
8369 CEEInfo::getMethodSigInternal(
8370 CORINFO_METHOD_HANDLE ftnHnd,
8371 CORINFO_SIG_INFO * sigRet,
8372 CORINFO_CLASS_HANDLE owner)
8374 STANDARD_VM_CONTRACT;
8376 MethodDesc * ftn = GetMethod(ftnHnd);
8378 PCCOR_SIGNATURE pSig = NULL;
8380 ftn->GetSig(&pSig, &cbSig);
8382 // Type parameters in the signature are instantiated
8383 // according to the class/method/array instantiation of ftnHnd and owner
8384 CEEInfo::ConvToJitSig(
8387 GetScopeHandle(ftn),
8395 // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation
8396 if (ftn->RequiresInstArg())
8398 sigRet->callConv = (CorInfoCallConv) (sigRet->callConv | CORINFO_CALLCONV_PARAMTYPE);
8401 // We want the calling convention bit to be consistant with the method attribute bit
8402 _ASSERTE( (IsMdStatic(ftn->GetAttrs()) == 0) == ((sigRet->callConv & CORINFO_CALLCONV_HASTHIS) != 0) );
8405 //---------------------------------------------------------------------------------------
8407 //@GENERICSVER: for a method desc in a typical instantiation of a generic class,
8408 // this will return the typical instantiation of the generic class,
8409 // but only provided type variables are never shared.
8410 // The JIT verifier relies on this behaviour to extract the typical class from an instantiated method's typical method handle.
8412 CORINFO_CLASS_HANDLE
8413 CEEInfo::getMethodClass(
8414 CORINFO_METHOD_HANDLE methodHnd)
8423 CORINFO_CLASS_HANDLE result = NULL;
8425 JIT_TO_EE_TRANSITION();
8427 MethodDesc* method = GetMethod(methodHnd);
8429 if (method->IsDynamicMethod())
8431 DynamicResolver::SecurityControlFlags securityControlFlags = DynamicResolver::Default;
8432 TypeHandle typeOwner;
8434 DynamicResolver* pResolver = method->AsDynamicMethodDesc()->GetResolver();
8435 pResolver->GetJitContext(&securityControlFlags, &typeOwner);
8437 if (!typeOwner.IsNull() && (method == pResolver->GetDynamicMethod()))
8439 result = CORINFO_CLASS_HANDLE(typeOwner.AsPtr());
8445 TypeHandle th = TypeHandle(method->GetMethodTable());
8447 result = CORINFO_CLASS_HANDLE(th.AsPtr());
8450 EE_TO_JIT_TRANSITION();
8455 /***********************************************************************/
8456 CORINFO_MODULE_HANDLE CEEInfo::getMethodModule (CORINFO_METHOD_HANDLE methodHnd)
8465 CORINFO_MODULE_HANDLE result = NULL;
8467 JIT_TO_EE_TRANSITION_LEAF();
8469 MethodDesc* method = GetMethod(methodHnd);
8471 if (method->IsDynamicMethod())
8473 // this should never be called, thus the assert, I don't know if the (non existent) caller
8474 // expects the Module or the scope
8479 result = (CORINFO_MODULE_HANDLE) method->GetModule();
8482 EE_TO_JIT_TRANSITION_LEAF();
8487 /*********************************************************************/
8488 CorInfoIntrinsics CEEInfo::getIntrinsicID(CORINFO_METHOD_HANDLE methodHnd,
8498 CorInfoIntrinsics result = CORINFO_INTRINSIC_Illegal;
8500 JIT_TO_EE_TRANSITION();
8502 if (pMustExpand != NULL)
8504 *pMustExpand = false;
8507 MethodDesc* method = GetMethod(methodHnd);
8509 if (method->IsArray())
8511 ArrayMethodDesc * arrMethod = (ArrayMethodDesc *)method;
8512 result = arrMethod->GetIntrinsicID();
8515 if (method->IsFCall())
8517 result = ECall::GetIntrinsicID(method);
8521 MethodTable * pMT = method->GetMethodTable();
8522 if (pMT->GetModule()->IsSystem() && pMT->IsByRefLike())
8524 if (pMT->HasSameTypeDefAs(g_pByReferenceClass))
8526 // ByReference<T> has just two methods: constructor and Value property
8527 if (method->IsCtor())
8529 result = CORINFO_INTRINSIC_ByReference_Ctor;
8533 _ASSERTE(strcmp(method->GetName(), "get_Value") == 0);
8534 result = CORINFO_INTRINSIC_ByReference_Value;
8536 if (pMustExpand != nullptr)
8538 *pMustExpand = true;
8541 else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__SPAN)))
8543 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__SPAN__GET_ITEM)))
8545 result = CORINFO_INTRINSIC_Span_GetItem;
8548 else if (pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__READONLY_SPAN)))
8550 if (method->HasSameMethodDefAs(MscorlibBinder::GetMethod(METHOD__READONLY_SPAN__GET_ITEM)))
8552 result = CORINFO_INTRINSIC_ReadOnlySpan_GetItem;
8558 EE_TO_JIT_TRANSITION();
8563 /*********************************************************************/
8564 bool CEEInfo::isInSIMDModule(CORINFO_CLASS_HANDLE classHnd)
8573 bool result = false;
8574 JIT_TO_EE_TRANSITION_LEAF();
8576 TypeHandle VMClsHnd(classHnd);
8577 if (VMClsHnd.GetMethodTable()->GetAssembly()->IsSIMDVectorAssembly())
8581 EE_TO_JIT_TRANSITION_LEAF();
8586 /*********************************************************************/
8587 void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd,
8588 unsigned * pOffsetOfIndirection,
8589 unsigned * pOffsetAfterIndirection,
8590 unsigned * isRelative)
8599 JIT_TO_EE_TRANSITION_LEAF();
8601 MethodDesc* method = GetMethod(methodHnd);
8603 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8604 _ASSERTE(!method->HasMethodInstantiation());
8606 _ASSERTE(MethodTable::GetVtableOffset() < 256); // a rough sanity check
8608 // better be in the vtable
8609 _ASSERTE(method->GetSlot() < method->GetMethodTable()->GetNumVirtuals());
8611 *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * sizeof(MethodTable::VTableIndir_t);
8612 *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * sizeof(PCODE);
8613 *isRelative = MethodTable::VTableIndir_t::isRelative ? 1 : 0;
8615 EE_TO_JIT_TRANSITION_LEAF();
8618 /*********************************************************************/
8619 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethodHelper(CORINFO_METHOD_HANDLE baseMethod,
8620 CORINFO_CLASS_HANDLE derivedClass,
8621 CORINFO_CONTEXT_HANDLE ownerType)
8629 MethodDesc* pBaseMD = GetMethod(baseMethod);
8630 MethodTable* pBaseMT = pBaseMD->GetMethodTable();
8632 // Method better be from a fully loaded class
8633 _ASSERTE(pBaseMD->IsRestored() && pBaseMT->IsFullyLoaded());
8635 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8636 _ASSERTE(!pBaseMD->HasMethodInstantiation());
8638 // Method better be virtual
8639 _ASSERTE(pBaseMD->IsVirtual());
8641 MethodDesc* pDevirtMD = nullptr;
8643 TypeHandle DerivedClsHnd(derivedClass);
8644 MethodTable* pDerivedMT = DerivedClsHnd.GetMethodTable();
8645 _ASSERTE(pDerivedMT->IsRestored() && pDerivedMT->IsFullyLoaded());
8647 // Can't devirtualize from __Canon.
8648 if (DerivedClsHnd == TypeHandle(g_pCanonMethodTableClass))
8653 if (pBaseMT->IsInterface())
8656 #ifdef FEATURE_COMINTEROP
8657 // Don't try and devirtualize com interface calls.
8658 if (pDerivedMT->IsComObjectType())
8662 #endif // FEATURE_COMINTEROP
8664 // Interface call devirtualization.
8666 // We must ensure that pDerivedMT actually implements the
8667 // interface corresponding to pBaseMD.
8668 if (!pDerivedMT->CanCastToInterface(pBaseMT))
8673 // For generic interface methods we must have an ownerType to
8674 // safely devirtualize.
8675 if (ownerType != nullptr)
8677 TypeHandle OwnerClsHnd = GetTypeFromContext(ownerType);
8678 MethodTable* pOwnerMT = OwnerClsHnd.GetMethodTable();
8680 // If the derived class is a shared class, make sure the
8681 // owner class is too.
8682 if (pDerivedMT->IsSharedByGenericInstantiations())
8684 pOwnerMT = pOwnerMT->GetCanonicalMethodTable();
8687 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(TypeHandle(pOwnerMT), pBaseMD);
8689 else if (!pBaseMD->HasClassOrMethodInstantiation())
8691 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(pBaseMD);
8700 // Virtual call devirtualization.
8702 // The derived class should be a subclass of the the base class.
8703 MethodTable* pCheckMT = pDerivedMT;
8705 while (pCheckMT != nullptr)
8707 if (pCheckMT->HasSameTypeDefAs(pBaseMT))
8712 pCheckMT = pCheckMT->GetParentMethodTable();
8715 if (pCheckMT == nullptr)
8720 // The base method should be in the base vtable
8721 WORD slot = pBaseMD->GetSlot();
8722 _ASSERTE(slot < pBaseMT->GetNumVirtuals());
8724 // Fetch the method that would be invoked if the class were
8725 // exactly derived class. It is up to the jit to determine whether
8726 // directly calling this method is correct.
8727 pDevirtMD = pDerivedMT->GetMethodDescForSlot(slot);
8730 _ASSERTE(pDevirtMD->IsRestored());
8732 #ifdef FEATURE_READYTORUN_COMPILER
8733 // Check if devirtualization is dependent upon cross-version
8734 // bubble information and if so, disallow it.
8735 if (IsReadyToRunCompilation())
8737 MethodDesc* callerMethod = m_pMethodBeingCompiled;
8738 Assembly* pCallerAssembly = callerMethod->GetModule()->GetAssembly();
8740 IsInSameVersionBubble(pCallerAssembly , pDevirtMD->GetModule()->GetAssembly())
8741 && IsInSameVersionBubble(pCallerAssembly , pDerivedMT->GetAssembly());
8750 return (CORINFO_METHOD_HANDLE) pDevirtMD;
8753 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethod(CORINFO_METHOD_HANDLE methodHnd,
8754 CORINFO_CLASS_HANDLE derivedClass,
8755 CORINFO_CONTEXT_HANDLE ownerType)
8764 CORINFO_METHOD_HANDLE result = nullptr;
8766 JIT_TO_EE_TRANSITION();
8768 result = resolveVirtualMethodHelper(methodHnd, derivedClass, ownerType);
8770 EE_TO_JIT_TRANSITION();
8775 void CEEInfo::expandRawHandleIntrinsic(
8776 CORINFO_RESOLVED_TOKEN * pResolvedToken,
8777 CORINFO_GENERICHANDLE_RESULT * pResult)
8779 LIMITED_METHOD_CONTRACT;
8780 UNREACHABLE(); // only called with CoreRT.
8783 /*********************************************************************/
8784 void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd,
8785 CORINFO_CONST_LOOKUP * pResult,
8786 CORINFO_ACCESS_FLAGS accessFlags)
8796 InfoAccessType accessType = IAT_VALUE;
8798 JIT_TO_EE_TRANSITION();
8800 MethodDesc * ftn = GetMethod(ftnHnd);
8801 #if defined(FEATURE_GDBJIT)
8802 MethodDesc * orig_ftn = ftn;
8805 // Resolve methodImpl.
8806 ftn = ftn->GetMethodTable()->MapMethodDeclToMethodImpl(ftn);
8808 ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags);
8810 // TryGetMultiCallableAddrOfCode returns NULL if indirect access is desired
8813 // should never get here for EnC methods or if interception via remoting stub is required
8814 _ASSERTE(!ftn->IsEnCMethod());
8816 _ASSERTE((accessFlags & CORINFO_ACCESS_THIS) || !ftn->IsRemotingInterceptedViaVirtualDispatch());
8818 ret = ftn->GetAddrOfSlot();
8819 accessType = IAT_PVALUE;
8823 #if defined(FEATURE_GDBJIT)
8824 CalledMethod * pCM = new CalledMethod(orig_ftn, ret, m_pCalledMethods);
8825 m_pCalledMethods = pCM;
8828 EE_TO_JIT_TRANSITION();
8830 _ASSERTE(ret != NULL);
8832 pResult->accessType = accessType;
8833 pResult->addr = ret;
8836 /*********************************************************************/
8837 void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn,
8838 CORINFO_CONST_LOOKUP * pResult)
8847 JIT_TO_EE_TRANSITION();
8849 MethodDesc * pMD = GetMethod(ftn);
8851 pResult->accessType = IAT_VALUE;
8854 #ifndef CROSSGEN_COMPILE
8855 // If LDFTN target has [NativeCallable] attribute , then create a UMEntryThunk.
8856 if (pMD->HasNativeCallableAttribute())
8858 pResult->addr = (void*)COMDelegate::ConvertToCallback(pMD);
8861 #endif //CROSSGEN_COMPILE
8863 pResult->addr = (void *)pMD->GetMultiCallableAddrOfCode();
8865 EE_TO_JIT_TRANSITION();
8868 /*********************************************************************/
8869 const char* CEEInfo::getFieldName (CORINFO_FIELD_HANDLE fieldHnd, const char** scopeName)
8878 const char* result = NULL;
8880 JIT_TO_EE_TRANSITION();
8882 FieldDesc* field = (FieldDesc*) fieldHnd;
8885 TypeHandle t = TypeHandle(field->GetApproxEnclosingMethodTable());
8890 t.GetName(ssClsNameBuff);
8891 *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
8893 // since this is for diagnostic purposes only,
8894 // give up on the namespace, as we don't have a buffer to concat it
8895 // also note this won't show array class names.
8897 *scopeName= t.GetMethodTable()->GetFullyQualifiedNameInfo(&nameSpace);
8902 result = field->GetName();
8904 EE_TO_JIT_TRANSITION();
8909 /*********************************************************************/
8910 // Get the type that declares the field
8911 CORINFO_CLASS_HANDLE CEEInfo::getFieldClass (CORINFO_FIELD_HANDLE fieldHnd)
8920 CORINFO_CLASS_HANDLE result = NULL;
8922 JIT_TO_EE_TRANSITION_LEAF();
8924 FieldDesc* field = (FieldDesc*) fieldHnd;
8925 result = CORINFO_CLASS_HANDLE(field->GetApproxEnclosingMethodTable());
8927 EE_TO_JIT_TRANSITION_LEAF();
8932 /*********************************************************************/
8933 // Returns the basic type of the field (not the the type that declares the field)
8935 // pTypeHnd - On return, for reference and value types, *pTypeHnd will contain
8936 // the normalized type of the field.
8937 // owner - Optional. For resolving in a generic context
8939 CorInfoType CEEInfo::getFieldType (CORINFO_FIELD_HANDLE fieldHnd,
8940 CORINFO_CLASS_HANDLE* pTypeHnd,
8941 CORINFO_CLASS_HANDLE owner)
8950 CorInfoType result = CORINFO_TYPE_UNDEF;
8952 JIT_TO_EE_TRANSITION();
8954 result = getFieldTypeInternal(fieldHnd, pTypeHnd, owner);
8956 EE_TO_JIT_TRANSITION();
8961 /*********************************************************************/
8962 CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd,
8963 CORINFO_CLASS_HANDLE* pTypeHnd,
8964 CORINFO_CLASS_HANDLE owner)
8966 STANDARD_VM_CONTRACT;
8970 TypeHandle clsHnd = TypeHandle();
8971 FieldDesc* field = (FieldDesc*) fieldHnd;
8972 CorElementType type = field->GetFieldType();
8974 // <REVISIT_TODO>TODO should not burn the time to do this for anything but Value Classes</REVISIT_TODO>
8975 _ASSERTE(type != ELEMENT_TYPE_BYREF);
8977 if (type == ELEMENT_TYPE_I)
8979 PTR_MethodTable enclosingMethodTable = field->GetApproxEnclosingMethodTable();
8980 if (enclosingMethodTable->IsByRefLike() && enclosingMethodTable->HasSameTypeDefAs(g_pByReferenceClass))
8982 _ASSERTE(field->GetOffset() == 0);
8983 return CORINFO_TYPE_BYREF;
8987 if (!CorTypeInfo::IsPrimitiveType(type))
8989 PCCOR_SIGNATURE sig;
8991 CorCallingConvention conv;
8993 field->GetSig(&sig, &sigCount);
8995 conv = (CorCallingConvention)CorSigUncompressCallingConv(sig);
8996 _ASSERTE(isCallConv(conv, IMAGE_CEE_CS_CALLCONV_FIELD));
8998 SigPointer ptr(sig, sigCount);
9000 // For verifying code involving generics, use the class instantiation
9001 // of the optional owner (to provide exact, not representative,
9002 // type information)
9003 SigTypeContext typeContext(field, (TypeHandle)owner);
9005 clsHnd = ptr.GetTypeHandleThrowing(field->GetModule(), &typeContext);
9006 _ASSERTE(!clsHnd.IsNull());
9008 // I believe it doesn't make any diff. if this is GetInternalCorElementType
9009 // or GetSignatureCorElementType.
9010 type = clsHnd.GetSignatureCorElementType();
9013 return CEEInfo::asCorInfoType(type, clsHnd, pTypeHnd);
9016 /*********************************************************************/
9017 unsigned CEEInfo::getFieldOffset (CORINFO_FIELD_HANDLE fieldHnd)
9026 unsigned result = (unsigned) -1;
9028 JIT_TO_EE_TRANSITION();
9030 FieldDesc* field = (FieldDesc*) fieldHnd;
9032 // GetOffset() does not include the size of Object
9033 result = field->GetOffset();
9035 // So if it is not a value class, add the Object into it
9036 if (field->IsStatic())
9038 Module* pModule = field->GetModule();
9039 if (field->IsRVA() && pModule->IsRvaFieldTls(field->GetOffset()))
9041 result = pModule->GetFieldTlsOffset(field->GetOffset());
9044 else if (!field->GetApproxEnclosingMethodTable()->IsValueType())
9046 result += sizeof(Object);
9049 EE_TO_JIT_TRANSITION();
9054 /*********************************************************************/
9055 bool CEEInfo::isWriteBarrierHelperRequired(CORINFO_FIELD_HANDLE field)
9064 bool fHelperRequired = false;
9066 JIT_TO_EE_TRANSITION();
9068 FieldDesc * pField = (FieldDesc *)field;
9070 // TODO: jit64 should be switched to the same plan as the i386 jits - use
9071 // getClassGClayout to figure out the need for writebarrier helper, and inline the copying.
9072 // Once this happens, USE_WRITE_BARRIER_HELPERS and CORINFO_FLG_WRITE_BARRIER_HELPER can be removed.
9073 CorElementType type = pField->GetFieldType();
9075 if(CorTypeInfo::IsObjRef(type))
9076 fHelperRequired = true;
9077 else if (type == ELEMENT_TYPE_VALUETYPE)
9079 TypeHandle th = pField->GetFieldTypeHandleThrowing();
9080 _ASSERTE(!th.IsNull());
9081 if(th.GetMethodTable()->ContainsPointers())
9082 fHelperRequired = true;
9085 EE_TO_JIT_TRANSITION();
9087 return fHelperRequired;
9090 /*********************************************************************/
9091 DWORD CEEInfo::getFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE fieldHnd, void **ppIndirection)
9102 if (ppIndirection != NULL)
9103 *ppIndirection = NULL;
9105 JIT_TO_EE_TRANSITION();
9107 FieldDesc* field = (FieldDesc*) fieldHnd;
9108 Module* module = field->GetModule();
9110 _ASSERTE(field->IsRVA()); // Only RVA statics can be thread local
9111 _ASSERTE(module->IsRvaFieldTls(field->GetOffset()));
9113 result = module->GetTlsIndex();
9115 EE_TO_JIT_TRANSITION();
9120 void *CEEInfo::allocateArray(ULONG cBytes)
9129 void * result = NULL;
9131 JIT_TO_EE_TRANSITION();
9133 result = new BYTE [cBytes];
9135 EE_TO_JIT_TRANSITION();
9140 void CEEInfo::freeArray(void *array)
9149 JIT_TO_EE_TRANSITION();
9151 delete [] ((BYTE*) array);
9153 EE_TO_JIT_TRANSITION();
9156 void CEEInfo::getBoundaries(CORINFO_METHOD_HANDLE ftn,
9157 unsigned int *cILOffsets, DWORD **pILOffsets,
9158 ICorDebugInfo::BoundaryTypes *implicitBoundaries)
9167 JIT_TO_EE_TRANSITION();
9169 #ifdef DEBUGGING_SUPPORTED
9170 if (g_pDebugInterface && !IsCompilationProcess())
9172 g_pDebugInterface->getBoundaries(GetMethod(ftn), cILOffsets, pILOffsets,
9173 implicitBoundaries);
9179 *implicitBoundaries = ICorDebugInfo::DEFAULT_BOUNDARIES;
9181 #endif // DEBUGGING_SUPPORTED
9183 EE_TO_JIT_TRANSITION();
9186 void CEEInfo::getVars(CORINFO_METHOD_HANDLE ftn, ULONG32 *cVars, ICorDebugInfo::ILVarInfo **vars,
9196 JIT_TO_EE_TRANSITION();
9198 #ifdef DEBUGGING_SUPPORTED
9199 if (g_pDebugInterface && !IsCompilationProcess())
9201 g_pDebugInterface->getVars(GetMethod(ftn), cVars, vars, extendOthers);
9208 // Just tell the JIT to extend everything.
9209 *extendOthers = true;
9211 #endif // DEBUGGING_SUPPORTED
9213 EE_TO_JIT_TRANSITION();
9216 /*********************************************************************/
9217 CORINFO_ARG_LIST_HANDLE CEEInfo::getArgNext(CORINFO_ARG_LIST_HANDLE args)
9226 CORINFO_ARG_LIST_HANDLE result = NULL;
9228 JIT_TO_EE_TRANSITION();
9230 SigPointer ptr((unsigned __int8*) args);
9231 IfFailThrow(ptr.SkipExactlyOne());
9233 result = (CORINFO_ARG_LIST_HANDLE) ptr.GetPtr();
9235 EE_TO_JIT_TRANSITION();
9241 /*********************************************************************/
9243 CorInfoTypeWithMod CEEInfo::getArgType (
9244 CORINFO_SIG_INFO* sig,
9245 CORINFO_ARG_LIST_HANDLE args,
9246 CORINFO_CLASS_HANDLE* vcTypeRet
9256 CorInfoTypeWithMod result = CorInfoTypeWithMod(CORINFO_TYPE_UNDEF);
9258 JIT_TO_EE_TRANSITION();
9260 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args && (BYTE*) args < (BYTE*) sig->pSig + sig->cbSig);
9261 _ASSERTE((BYTE*) sig->args <= (BYTE*) args);
9262 INDEBUG(*vcTypeRet = CORINFO_CLASS_HANDLE((size_t)INVALID_POINTER_CC));
9264 SigPointer ptr((unsigned __int8*) args);
9265 CorElementType eType;
9266 IfFailThrow(ptr.PeekElemType(&eType));
9267 while (eType == ELEMENT_TYPE_PINNED)
9269 result = CORINFO_TYPE_MOD_PINNED;
9270 IfFailThrow(ptr.GetElemType(NULL));
9271 IfFailThrow(ptr.PeekElemType(&eType));
9274 // Now read off the "real" element type after taking any instantiations into consideration
9275 SigTypeContext typeContext;
9276 GetTypeContext(&sig->sigInst,&typeContext);
9278 Module* pModule = GetModule(sig->scope);
9280 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9282 TypeHandle typeHnd = TypeHandle();
9284 case ELEMENT_TYPE_VAR :
9285 case ELEMENT_TYPE_MVAR :
9286 case ELEMENT_TYPE_VALUETYPE :
9287 case ELEMENT_TYPE_TYPEDBYREF :
9288 case ELEMENT_TYPE_INTERNAL :
9290 typeHnd = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9291 _ASSERTE(!typeHnd.IsNull());
9293 CorElementType normType = typeHnd.GetInternalCorElementType();
9295 // if we are looking up a value class, don't morph it to a refernece type
9296 // (This can only happen in illegal IL)
9297 if (!CorTypeInfo::IsObjRef(normType) || type != ELEMENT_TYPE_VALUETYPE)
9304 case ELEMENT_TYPE_PTR:
9305 // Load the type eagerly under debugger to make the eval work
9306 if (!isVerifyOnly() && CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
9308 // NOTE: in some IJW cases, when the type pointed at is unmanaged,
9309 // the GetTypeHandle may fail, because there is no TypeDef for such type.
9310 // Usage of GetTypeHandleThrowing would lead to class load exception
9311 TypeHandle thPtr = ptr.GetTypeHandleNT(pModule, &typeContext);
9314 m_pOverride->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(thPtr.AsPtr()));
9319 case ELEMENT_TYPE_VOID:
9320 // void is not valid in local sigs
9321 if (sig->flags & CORINFO_SIGFLAG_IS_LOCAL_SIG)
9322 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
9325 case ELEMENT_TYPE_END:
9326 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9333 result = CorInfoTypeWithMod(result | CEEInfo::asCorInfoType(type, typeHnd, vcTypeRet));
9334 EE_TO_JIT_TRANSITION();
9339 /*********************************************************************/
9341 CORINFO_CLASS_HANDLE CEEInfo::getArgClass (
9342 CORINFO_SIG_INFO* sig,
9343 CORINFO_ARG_LIST_HANDLE args
9353 CORINFO_CLASS_HANDLE result = NULL;
9355 JIT_TO_EE_TRANSITION();
9357 // make certain we dont have a completely wacked out sig pointer
9358 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args);
9359 _ASSERTE((BYTE*) sig->args <= (BYTE*) args && (BYTE*) args < &((BYTE*) sig->args)[0x10000*5]);
9361 Module* pModule = GetModule(sig->scope);
9363 SigPointer ptr((unsigned __int8*) args);
9365 CorElementType eType;
9366 IfFailThrow(ptr.PeekElemType(&eType));
9368 while (eType == ELEMENT_TYPE_PINNED)
9370 IfFailThrow(ptr.GetElemType(NULL));
9371 IfFailThrow(ptr.PeekElemType(&eType));
9373 // Now read off the "real" element type after taking any instantiations into consideration
9374 SigTypeContext typeContext;
9375 GetTypeContext(&sig->sigInst, &typeContext);
9376 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9378 if (!CorTypeInfo::IsPrimitiveType(type)) {
9379 TypeHandle th = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9380 result = CORINFO_CLASS_HANDLE(th.AsPtr());
9383 EE_TO_JIT_TRANSITION();
9388 /*********************************************************************/
9390 CorInfoType CEEInfo::getHFAType(CORINFO_CLASS_HANDLE hClass)
9399 CorInfoType result = CORINFO_TYPE_UNDEF;
9402 JIT_TO_EE_TRANSITION();
9404 TypeHandle VMClsHnd(hClass);
9406 result = asCorInfoType(VMClsHnd.GetHFAType());
9408 EE_TO_JIT_TRANSITION();
9414 /*********************************************************************/
9416 // return the unmanaged calling convention for a PInvoke
9417 CorInfoUnmanagedCallConv CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method)
9426 CorInfoUnmanagedCallConv result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9428 JIT_TO_EE_TRANSITION();
9430 MethodDesc* pMD = NULL;
9431 pMD = GetMethod(method);
9432 _ASSERTE(pMD->IsNDirect());
9437 PInvokeStaticSigInfo sigInfo(pMD, PInvokeStaticSigInfo::NO_THROW_ON_ERROR);
9439 switch (sigInfo.GetCallConv()) {
9440 case pmCallConvCdecl:
9441 result = CORINFO_UNMANAGED_CALLCONV_C;
9443 case pmCallConvStdcall:
9444 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9446 case pmCallConvThiscall:
9447 result = CORINFO_UNMANAGED_CALLCONV_THISCALL;
9450 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9455 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9457 EX_END_CATCH(SwallowAllExceptions)
9458 #else // !_TARGET_X86_
9460 // we have only one calling convention
9462 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9463 #endif // !_TARGET_X86_
9465 EE_TO_JIT_TRANSITION();
9470 /*********************************************************************/
9471 BOOL NDirectMethodDesc::ComputeMarshalingRequired()
9473 WRAPPER_NO_CONTRACT;
9475 return NDirect::MarshalingRequired(this);
9478 /*********************************************************************/
9479 BOOL CEEInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig)
9488 BOOL result = FALSE;
9490 JIT_TO_EE_TRANSITION();
9494 MethodDesc* ftn = GetMethod(method);
9495 _ASSERTE(ftn->IsNDirect());
9496 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9498 #if defined(HAS_NDIRECT_IMPORT_PRECODE)
9499 if (pMD->IsVarArg())
9501 // Varag P/Invoke must not be inlined because its NDirectMethodDesc
9502 // does not contain a meaningful stack size (it is call site specific).
9503 // See code:InlinedCallFrame.UpdateRegDisplay where this is needed.
9506 else if (pMD->MarshalingRequired())
9508 // This is not a no-marshal signature.
9513 // This is a no-marshal non-vararg signature.
9517 // Marshalling is required to lazy initialize the indirection cell
9518 // without NDirectImportPrecode.
9524 // check the call site signature
9525 result = NDirect::MarshalingRequired(
9528 GetModule(callSiteSig->scope));
9531 EE_TO_JIT_TRANSITION();
9536 /*********************************************************************/
9537 // Generate a cookie based on the signature that would needs to be passed
9538 // to CORINFO_HELP_PINVOKE_CALLI
9539 LPVOID CEEInfo::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig,
9540 void **ppIndirection)
9542 WRAPPER_NO_CONTRACT;
9544 return getVarArgsHandle(szMetaSig, ppIndirection);
9547 bool CEEInfo::canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig)
9549 LIMITED_METHOD_CONTRACT;
9554 // Check any constraints on method type arguments
9555 BOOL CEEInfo::satisfiesMethodConstraints(
9556 CORINFO_CLASS_HANDLE parent,
9557 CORINFO_METHOD_HANDLE method)
9566 BOOL result = FALSE;
9568 JIT_TO_EE_TRANSITION();
9570 _ASSERTE(parent != NULL);
9571 _ASSERTE(method != NULL);
9572 result = GetMethod(method)->SatisfiesMethodConstraints(TypeHandle(parent));
9574 EE_TO_JIT_TRANSITION();
9581 /*********************************************************************/
9582 // Given a delegate target class, a target method parent class, a target method,
9583 // a delegate class, check if the method signature is compatible with the Invoke method of the delegate
9584 // (under the typical instantiation of any free type variables in the memberref signatures).
9586 // objCls should be NULL if the target object is NULL
9587 //@GENERICSVER: new (suitable for generics)
9588 BOOL CEEInfo::isCompatibleDelegate(
9589 CORINFO_CLASS_HANDLE objCls,
9590 CORINFO_CLASS_HANDLE methodParentCls,
9591 CORINFO_METHOD_HANDLE method,
9592 CORINFO_CLASS_HANDLE delegateCls,
9593 BOOL* pfIsOpenDelegate)
9602 BOOL result = FALSE;
9604 JIT_TO_EE_TRANSITION();
9606 _ASSERTE(method != NULL);
9607 _ASSERTE(delegateCls != NULL);
9609 TypeHandle delegateClsHnd = (TypeHandle) delegateCls;
9611 _ASSERTE(delegateClsHnd.GetMethodTable()->IsDelegate());
9613 TypeHandle methodParentHnd = (TypeHandle) (methodParentCls);
9614 MethodDesc* pMDFtn = GetMethod(method);
9615 TypeHandle objClsHnd(objCls);
9619 result = COMDelegate::ValidateCtor(objClsHnd, methodParentHnd, pMDFtn, delegateClsHnd, pfIsOpenDelegate);
9624 EX_END_CATCH(SwallowAllExceptions)
9626 EE_TO_JIT_TRANSITION();
9631 /*********************************************************************/
9632 // return the unmanaged target *if method has already been prelinked.*
9633 void* CEEInfo::getPInvokeUnmanagedTarget(CORINFO_METHOD_HANDLE method,
9634 void **ppIndirection)
9643 void* result = NULL;
9645 if (ppIndirection != NULL)
9646 *ppIndirection = NULL;
9648 #ifndef CROSSGEN_COMPILE
9649 JIT_TO_EE_TRANSITION();
9651 MethodDesc* ftn = GetMethod(method);
9652 _ASSERTE(ftn->IsNDirect());
9653 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9655 if (pMD->NDirectTargetIsImportThunk())
9660 result = pMD->GetNDirectTarget();
9663 EE_TO_JIT_TRANSITION();
9664 #endif // CROSSGEN_COMPILE
9669 /*********************************************************************/
9670 // return address of fixup area for late-bound N/Direct calls.
9671 void* CEEInfo::getAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE method,
9672 void **ppIndirection)
9681 void * result = NULL;
9683 if (ppIndirection != NULL)
9684 *ppIndirection = NULL;
9686 JIT_TO_EE_TRANSITION_LEAF();
9688 MethodDesc* ftn = GetMethod(method);
9689 _ASSERTE(ftn->IsNDirect());
9690 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9692 result = (LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
9694 EE_TO_JIT_TRANSITION_LEAF();
9699 /*********************************************************************/
9700 // return address of fixup area for late-bound N/Direct calls.
9701 void CEEInfo::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method,
9702 CORINFO_CONST_LOOKUP *pLookup)
9704 WRAPPER_NO_CONTRACT;
9707 pLookup->accessType = IAT_PVALUE;
9708 pLookup->addr = getAddressOfPInvokeFixup(method, &pIndirection);
9709 _ASSERTE(pIndirection == NULL);
9712 /*********************************************************************/
9713 CORINFO_JUST_MY_CODE_HANDLE CEEInfo::getJustMyCodeHandle(
9714 CORINFO_METHOD_HANDLE method,
9715 CORINFO_JUST_MY_CODE_HANDLE**ppIndirection)
9724 CORINFO_JUST_MY_CODE_HANDLE result = NULL;
9727 *ppIndirection = NULL;
9729 JIT_TO_EE_TRANSITION_LEAF();
9731 // Get the flag from the debugger.
9732 MethodDesc* ftn = GetMethod(method);
9733 DWORD * pFlagAddr = NULL;
9735 if (g_pDebugInterface)
9737 pFlagAddr = g_pDebugInterface->GetJMCFlagAddr(ftn->GetModule());
9740 result = (CORINFO_JUST_MY_CODE_HANDLE) pFlagAddr;
9742 EE_TO_JIT_TRANSITION_LEAF();
9747 /*********************************************************************/
9748 void InlinedCallFrame::GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo *pInfo)
9750 LIMITED_METHOD_CONTRACT;
9752 pInfo->size = sizeof(GSCookie) + sizeof(InlinedCallFrame);
9754 pInfo->offsetOfGSCookie = 0;
9755 pInfo->offsetOfFrameVptr = sizeof(GSCookie);
9756 pInfo->offsetOfFrameLink = sizeof(GSCookie) + Frame::GetOffsetOfNextLink();
9757 pInfo->offsetOfCallSiteSP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallSiteSP);
9758 pInfo->offsetOfCalleeSavedFP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCalleeSavedFP);
9759 pInfo->offsetOfCallTarget = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_Datum);
9760 pInfo->offsetOfReturnAddress = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallerReturnAddress);
9763 /*********************************************************************/
9764 // Return details about EE internal data structures
9765 void CEEInfo::getEEInfo(CORINFO_EE_INFO *pEEInfoOut)
9774 INDEBUG(memset(pEEInfoOut, 0xCC, sizeof(*pEEInfoOut)));
9776 JIT_TO_EE_TRANSITION();
9778 InlinedCallFrame::GetEEInfo(&pEEInfoOut->inlinedCallFrameInfo);
9780 // Offsets into the Thread structure
9781 pEEInfoOut->offsetOfThreadFrame = Thread::GetOffsetOfCurrentFrame();
9782 pEEInfoOut->offsetOfGCState = Thread::GetOffsetOfGCFlag();
9785 pEEInfoOut->offsetOfDelegateInstance = DelegateObject::GetOffsetOfTarget();
9786 pEEInfoOut->offsetOfDelegateFirstTarget = DelegateObject::GetOffsetOfMethodPtr();
9788 // Secure delegate offsets
9789 pEEInfoOut->offsetOfSecureDelegateIndirectCell = DelegateObject::GetOffsetOfMethodPtrAux();
9792 pEEInfoOut->offsetOfTransparentProxyRP = TransparentProxyObject::GetOffsetOfRP();
9793 pEEInfoOut->offsetOfRealProxyServer = RealProxyObject::GetOffsetOfServerObject();
9795 pEEInfoOut->offsetOfObjArrayData = (DWORD)PtrArray::GetDataOffset();
9797 pEEInfoOut->sizeOfReversePInvokeFrame = (DWORD)-1;
9799 pEEInfoOut->osPageSize = GetOsPageSize();
9800 pEEInfoOut->maxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
9801 pEEInfoOut->targetAbi = CORINFO_CORECLR_ABI;
9803 pEEInfoOut->osType = CORINFO_WINNT;
9805 // hardcode OS version to 0.0.0. These fields can be removed from JITEE interface
9806 pEEInfoOut->osMajor = 0;
9807 pEEInfoOut->osMinor = 0;
9808 pEEInfoOut->osBuild = 0;
9810 EE_TO_JIT_TRANSITION();
9813 LPCWSTR CEEInfo::getJitTimeLogFilename()
9822 LPCWSTR result = NULL;
9824 JIT_TO_EE_TRANSITION();
9825 result = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitTimeLogFile);
9826 EE_TO_JIT_TRANSITION();
9833 // Return details about EE internal data structures
9834 DWORD CEEInfo::getThreadTLSIndex(void **ppIndirection)
9843 DWORD result = (DWORD)-1;
9845 if (ppIndirection != NULL)
9846 *ppIndirection = NULL;
9848 JIT_TO_EE_TRANSITION();
9850 #if !defined(CROSSGEN_COMPILE) && !defined(FEATURE_IMPLICIT_TLS)
9851 result = GetThreadTLSIndex();
9853 // The JIT can use the optimized TLS access only if the runtime is using it as well.
9854 // (This is necessaryto make managed code work well under appverifier.)
9855 if (GetTLSAccessMode(result) == TLSACCESS_GENERIC)
9859 EE_TO_JIT_TRANSITION();
9864 const void * CEEInfo::getInlinedCallFrameVptr(void **ppIndirection)
9873 void * result = NULL;
9875 if (ppIndirection != NULL)
9876 *ppIndirection = NULL;
9878 JIT_TO_EE_TRANSITION_LEAF();
9880 #ifndef CROSSGEN_COMPILE
9881 result = (void*)InlinedCallFrame::GetMethodFrameVPtr();
9883 result = (void*)0x43210;
9886 EE_TO_JIT_TRANSITION_LEAF();
9891 LONG * CEEInfo::getAddrOfCaptureThreadGlobal(void **ppIndirection)
9900 LONG * result = NULL;
9902 if (ppIndirection != NULL)
9903 *ppIndirection = NULL;
9905 JIT_TO_EE_TRANSITION_LEAF();
9907 result = (LONG *)&g_TrapReturningThreads;
9909 EE_TO_JIT_TRANSITION_LEAF();
9916 HRESULT CEEInfo::GetErrorHRESULT(struct _EXCEPTION_POINTERS *pExceptionPointers)
9927 //This function is called from the JIT64 exception filter during PEVerify. Because it is a filter, it
9928 //can be "called" from a NOTHROW region in the case of StackOverflow. Security::MapToHR throws
9929 //internally, but it catches all exceptions. Therefore, none of the children can cause an exception to
9930 //percolate out of this function (except for Stack Overflow). Obviously I can't explain most of this to
9931 //the Contracts system, and I can't add this CONTRACT_VIOLATION to the filter in Jit64.
9932 CONTRACT_VIOLATION(ThrowsViolation);
9934 JIT_TO_EE_TRANSITION();
9938 OBJECTREF throwable = GetThread()->LastThrownObject();
9939 hr = GetExceptionHResult(throwable);
9941 EE_TO_JIT_TRANSITION();
9947 ULONG CEEInfo::GetErrorMessage(__inout_ecount(bufferLength) LPWSTR buffer, ULONG bufferLength)
9958 #ifndef CROSSGEN_COMPILE
9959 JIT_TO_EE_TRANSITION();
9963 OBJECTREF throwable = GetThread()->LastThrownObject();
9965 if (throwable != NULL)
9969 result = GetExceptionMessage(throwable, buffer, bufferLength);
9974 EX_END_CATCH(SwallowAllExceptions)
9977 EE_TO_JIT_TRANSITION();
9983 // This method is called from CEEInfo::FilterException which
9984 // is run as part of the SEH filter clause for the JIT.
9985 // It is fatal to throw an exception while running a SEH filter clause
9986 // so our contract is NOTHROW, NOTRIGGER.
9988 LONG EEFilterException(struct _EXCEPTION_POINTERS *pExceptionPointers, void *unused)
9998 JIT_TO_EE_TRANSITION_LEAF();
10000 VALIDATE_BACKOUT_STACK_CONSUMPTION;
10002 unsigned code = pExceptionPointers->ExceptionRecord->ExceptionCode;
10005 if (code == EXCEPTION_ACCESS_VIOLATION)
10007 static int hit = 0;
10010 _ASSERTE(!"Access violation while Jitting!");
10011 // If you set the debugger to catch access violations and 'go'
10012 // you will get back to the point at which the access violation occurred
10013 result = EXCEPTION_CONTINUE_EXECUTION;
10017 result = EXCEPTION_CONTINUE_SEARCH;
10022 // No one should be catching breakpoint
10023 // Similarly the JIT doesn't know how to reset the guard page, so it shouldn't
10024 // be catching a hard stack overflow
10025 if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP || code == EXCEPTION_STACK_OVERFLOW)
10027 result = EXCEPTION_CONTINUE_SEARCH;
10029 #ifdef CROSSGEN_COMPILE
10032 result = EXCEPTION_EXECUTE_HANDLER;
10035 else if (!IsComPlusException(pExceptionPointers->ExceptionRecord))
10037 result = EXCEPTION_EXECUTE_HANDLER;
10043 // This is actually the LastThrown exception object.
10044 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10046 if (throwable != NULL)
10050 OBJECTREF oLastThrownObject;
10053 ZeroMemory(&_gc, sizeof(_gc));
10055 // Setup the throwables
10056 _gc.oLastThrownObject = throwable;
10058 GCPROTECT_BEGIN(_gc);
10060 // Don't catch ThreadAbort and other uncatchable exceptions
10061 if (IsUncatchable(&_gc.oLastThrownObject))
10062 result = EXCEPTION_CONTINUE_SEARCH;
10064 result = EXCEPTION_EXECUTE_HANDLER;
10071 EE_TO_JIT_TRANSITION_LEAF();
10076 int CEEInfo::FilterException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10078 WRAPPER_NO_CONTRACT;
10079 return EEFilterException(pExceptionPointers, nullptr);
10082 // This code is called if FilterException chose to handle the exception.
10083 void CEEInfo::HandleException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10091 JIT_TO_EE_TRANSITION_LEAF();
10093 #ifndef CROSSGEN_COMPILE
10094 if (IsComPlusException(pExceptionPointers->ExceptionRecord))
10098 // This is actually the LastThrown exception object.
10099 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10101 if (throwable != NULL)
10105 OBJECTREF oLastThrownObject;
10106 OBJECTREF oCurrentThrowable;
10109 ZeroMemory(&_gc, sizeof(_gc));
10111 PTR_Thread pCurThread = GetThread();
10113 // Setup the throwables
10114 _gc.oLastThrownObject = throwable;
10116 // This will be NULL if no managed exception is active. Otherwise,
10117 // it will reference the active throwable.
10118 _gc.oCurrentThrowable = pCurThread->GetThrowable();
10120 GCPROTECT_BEGIN(_gc);
10122 // JIT does not use or reference managed exceptions at all and simply swallows them,
10123 // or lets them fly through so that they will either get caught in managed code, the VM
10124 // or will go unhandled.
10126 // Blind swallowing of managed exceptions can break the semantic of "which exception handler"
10127 // gets to process the managed exception first. The expected handler is managed code exception
10128 // handler (e.g. COMPlusFrameHandler on x86 and ProcessCLRException on 64bit) which will setup
10129 // the exception tracker for the exception that will enable the expected sync between the
10130 // LastThrownObject (LTO), setup in RaiseTheExceptionInternalOnly, and the exception tracker.
10132 // However, JIT can break this by swallowing the managed exception before managed code exception
10133 // handler gets a chance to setup an exception tracker for it. Since there is no cleanup
10134 // done for the swallowed exception as part of the unwind (because no exception tracker may have been setup),
10135 // we need to reset the LTO, if it is out of sync from the active throwable.
10137 // Hence, check if the LastThrownObject and active-exception throwable are in sync or not.
10138 // If not, bring them in sync.
10142 // It is possible that an exception was already in progress and while processing it (e.g.
10143 // invoking finally block), we invoked JIT that had another managed exception @ JIT-EE transition boundary
10144 // that is swallowed by the JIT before managed code exception handler sees it. This breaks the sync between
10145 // LTO and the active exception in the exception tracker.
10146 if (_gc.oCurrentThrowable != _gc.oLastThrownObject)
10150 // Note: Incase of OOM, this will get set to OOM instance.
10151 pCurThread->SafeSetLastThrownObject(_gc.oCurrentThrowable);
10159 EE_TO_JIT_TRANSITION_LEAF();
10162 void ThrowExceptionForJit(HRESULT res);
10164 void CEEInfo::ThrowExceptionForJitResult(
10174 JIT_TO_EE_TRANSITION();
10176 if (!SUCCEEDED(result))
10177 ThrowExceptionForJit(result);
10179 EE_TO_JIT_TRANSITION();
10183 CORINFO_MODULE_HANDLE CEEInfo::embedModuleHandle(CORINFO_MODULE_HANDLE handle,
10184 void **ppIndirection)
10191 PRECONDITION(!IsDynamicScope(handle));
10195 if (ppIndirection != NULL)
10196 *ppIndirection = NULL;
10198 JIT_TO_EE_TRANSITION_LEAF();
10200 EE_TO_JIT_TRANSITION_LEAF();
10205 CORINFO_CLASS_HANDLE CEEInfo::embedClassHandle(CORINFO_CLASS_HANDLE handle,
10206 void **ppIndirection)
10216 if (ppIndirection != NULL)
10217 *ppIndirection = NULL;
10219 JIT_TO_EE_TRANSITION_LEAF();
10221 EE_TO_JIT_TRANSITION_LEAF();
10226 CORINFO_FIELD_HANDLE CEEInfo::embedFieldHandle(CORINFO_FIELD_HANDLE handle,
10227 void **ppIndirection)
10237 if (ppIndirection != NULL)
10238 *ppIndirection = NULL;
10240 JIT_TO_EE_TRANSITION_LEAF();
10242 EE_TO_JIT_TRANSITION_LEAF();
10247 CORINFO_METHOD_HANDLE CEEInfo::embedMethodHandle(CORINFO_METHOD_HANDLE handle,
10248 void **ppIndirection)
10258 if (ppIndirection != NULL)
10259 *ppIndirection = NULL;
10261 JIT_TO_EE_TRANSITION_LEAF();
10263 EE_TO_JIT_TRANSITION_LEAF();
10268 /*********************************************************************/
10269 void CEEInfo::setJitFlags(const CORJIT_FLAGS& jitFlags)
10271 LIMITED_METHOD_CONTRACT;
10273 m_jitFlags = jitFlags;
10276 /*********************************************************************/
10277 DWORD CEEInfo::getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes)
10286 JIT_TO_EE_TRANSITION_LEAF();
10288 _ASSERTE(sizeInBytes >= sizeof(m_jitFlags));
10289 *jitFlags = m_jitFlags;
10291 EE_TO_JIT_TRANSITION_LEAF();
10293 return sizeof(m_jitFlags);
10296 /*********************************************************************/
10297 #if !defined(PLATFORM_UNIX)
10299 struct RunWithErrorTrapFilterParam
10301 ICorDynamicInfo* m_corInfo;
10302 void (*m_function)(void*);
10304 EXCEPTION_POINTERS m_exceptionPointers;
10307 static LONG RunWithErrorTrapFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
10309 WRAPPER_NO_CONTRACT;
10311 auto* param = reinterpret_cast<RunWithErrorTrapFilterParam*>(theParam);
10312 param->m_exceptionPointers = *exceptionPointers;
10313 return param->m_corInfo->FilterException(exceptionPointers);
10316 #endif // !defined(PLATFORM_UNIX)
10318 bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param)
10320 // No dynamic contract here because SEH is used
10321 STATIC_CONTRACT_THROWS;
10322 STATIC_CONTRACT_GC_TRIGGERS;
10323 STATIC_CONTRACT_SO_TOLERANT;
10324 STATIC_CONTRACT_MODE_PREEMPTIVE;
10326 // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
10327 // transitions into the EE proper should occur either via the call to
10328 // `EEFilterException` (which is appropraitely marked) or via JIT/EE
10329 // interface calls made by `function`.
10331 bool success = true;
10333 #if !defined(PLATFORM_UNIX)
10335 RunWithErrorTrapFilterParam trapParam;
10336 trapParam.m_corInfo = m_pOverride == nullptr ? this : m_pOverride;
10337 trapParam.m_function = function;
10338 trapParam.m_param = param;
10340 PAL_TRY(RunWithErrorTrapFilterParam*, pTrapParam, &trapParam)
10342 pTrapParam->m_function(pTrapParam->m_param);
10344 PAL_EXCEPT_FILTER(RunWithErrorTrapFilter)
10346 HandleException(&trapParam.m_exceptionPointers);
10351 #else // !defined(PLATFORM_UNIX)
10353 // We shouldn't need PAL_TRY on *nix: any exceptions that we are able to catch
10354 // ought to originate from the runtime itself and should be catchable inside of
10355 // EX_TRY/EX_CATCH, including emulated SEH exceptions.
10364 EX_END_CATCH(RethrowTerminalExceptions);
10371 /*********************************************************************/
10372 IEEMemoryManager* CEEInfo::getMemoryManager()
10381 IEEMemoryManager* result = NULL;
10383 JIT_TO_EE_TRANSITION_LEAF();
10385 result = GetEEMemoryManager();
10387 EE_TO_JIT_TRANSITION_LEAF();
10392 /*********************************************************************/
10393 int CEEInfo::doAssert(const char* szFile, int iLine, const char* szExpr)
10395 STATIC_CONTRACT_SO_TOLERANT;
10396 STATIC_CONTRACT_THROWS;
10397 STATIC_CONTRACT_GC_TRIGGERS;
10398 STATIC_CONTRACT_MODE_PREEMPTIVE;
10399 STATIC_CONTRACT_DEBUG_ONLY;
10403 JIT_TO_EE_TRANSITION();
10405 #ifdef CROSSGEN_COMPILE
10406 ThrowHR(COR_E_INVALIDPROGRAM);
10410 BEGIN_DEBUG_ONLY_CODE;
10411 result = _DbgBreakCheck(szFile, iLine, szExpr);
10412 END_DEBUG_ONLY_CODE;
10414 result = 1; // break into debugger
10419 EE_TO_JIT_TRANSITION();
10424 void CEEInfo::reportFatalError(CorJitResult result)
10426 STATIC_CONTRACT_SO_TOLERANT;
10427 STATIC_CONTRACT_THROWS;
10428 STATIC_CONTRACT_GC_TRIGGERS;
10429 STATIC_CONTRACT_MODE_PREEMPTIVE;
10431 JIT_TO_EE_TRANSITION_LEAF();
10433 STRESS_LOG2(LF_JIT,LL_ERROR, "Jit reported error 0x%x while compiling 0x%p\n",
10434 (int)result, (INT_PTR)getMethodBeingCompiled());
10436 EE_TO_JIT_TRANSITION_LEAF();
10439 BOOL CEEInfo::logMsg(unsigned level, const char* fmt, va_list args)
10441 STATIC_CONTRACT_SO_TOLERANT;
10442 STATIC_CONTRACT_THROWS;
10443 STATIC_CONTRACT_GC_TRIGGERS;
10444 STATIC_CONTRACT_MODE_PREEMPTIVE;
10445 STATIC_CONTRACT_DEBUG_ONLY;
10447 BOOL result = FALSE;
10449 JIT_TO_EE_TRANSITION_LEAF();
10452 if (LoggingOn(LF_JIT, level))
10454 LogSpewValist(LF_JIT, level, (char*) fmt, args);
10459 EE_TO_JIT_TRANSITION_LEAF();
10464 void CEEInfo::yieldExecution()
10466 WRAPPER_NO_CONTRACT;
10470 #ifndef CROSSGEN_COMPILE
10472 /*********************************************************************/
10474 void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
10475 void ** ppIndirection) /* OUT */
10484 void* result = NULL;
10486 if (ppIndirection != NULL)
10487 *ppIndirection = NULL;
10489 JIT_TO_EE_TRANSITION_LEAF();
10491 _ASSERTE(ftnNum < CORINFO_HELP_COUNT);
10493 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10495 size_t dynamicFtnNum = ((size_t)pfnHelper - 1);
10496 if (dynamicFtnNum < DYNAMIC_CORINFO_HELP_COUNT)
10499 #pragma warning(push)
10500 #pragma warning(disable:26001) // "Bounds checked above using the underflow trick"
10501 #endif /*_PREFAST_ */
10503 #if defined(_TARGET_AMD64_)
10504 // To avoid using a jump stub we always call certain helpers using an indirect call.
10505 // Because when using a direct call and the target is father away than 2^31 bytes,
10506 // the direct call instead goes to a jump stub which jumps to the jit helper.
10507 // However in this process the jump stub will corrupt RAX.
10509 // The set of helpers for which RAX must be preserved are the profiler probes
10510 // and the STOP_FOR_GC helper which maps to JIT_RareDisableHelper.
10511 // In the case of the STOP_FOR_GC helper RAX can be holding a function return value.
10513 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_STOP_FOR_GC ||
10514 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER ||
10515 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE ||
10516 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL)
10518 _ASSERTE(ppIndirection != NULL);
10519 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10524 #if defined(ENABLE_FAST_GCPOLL_HELPER)
10525 //always call this indirectly so that we can swap GC Poll helpers.
10526 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_POLL_GC)
10528 _ASSERTE(ppIndirection != NULL);
10529 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10534 pfnHelper = hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10537 #pragma warning(pop)
10538 #endif /*_PREFAST_*/
10541 _ASSERTE(pfnHelper);
10543 result = (LPVOID)GetEEFuncEntryPoint(pfnHelper);
10545 EE_TO_JIT_TRANSITION_LEAF();
10550 PCODE CEEJitInfo::getHelperFtnStatic(CorInfoHelpFunc ftnNum)
10552 LIMITED_METHOD_CONTRACT;
10554 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10556 // If pfnHelper is an index into the dynamic helper table, it should be less
10557 // than DYNAMIC_CORINFO_HELP_COUNT. In this case we need to find the actual pfnHelper
10558 // using an extra indirection. Note the special case
10559 // where pfnHelper==0 where pfnHelper-1 will underflow and we will avoid the indirection.
10560 if (((size_t)pfnHelper - 1) < DYNAMIC_CORINFO_HELP_COUNT)
10562 pfnHelper = hlpDynamicFuncTable[((size_t)pfnHelper - 1)].pfnHelper;
10565 _ASSERTE(pfnHelper != NULL);
10567 return GetEEFuncEntryPoint(pfnHelper);
10570 void CEEJitInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
10575 PRECONDITION(CheckPointer(moduleFrom));
10576 PRECONDITION(!IsDynamicScope(moduleFrom));
10577 PRECONDITION(CheckPointer(moduleTo));
10578 PRECONDITION(!IsDynamicScope(moduleTo));
10579 PRECONDITION(moduleFrom != moduleTo);
10583 // This is only called internaly. JIT-EE transition is not needed.
10584 // JIT_TO_EE_TRANSITION();
10586 Module *dependency = (Module *)moduleTo;
10587 _ASSERTE(!dependency->IsSystem());
10589 if (m_pMethodBeingCompiled->IsLCGMethod())
10591 // The context module of the m_pMethodBeingCompiled is irrelevant. Rather than tracking
10592 // the dependency, we just do immediate activation.
10593 dependency->EnsureActive();
10597 #ifdef FEATURE_LOADER_OPTIMIZATION
10598 Module *context = (Module *)moduleFrom;
10600 // Record active dependency for loader.
10601 context->AddActiveDependency(dependency, FALSE);
10603 dependency->EnsureActive();
10607 // EE_TO_JIT_TRANSITION();
10611 // Wrapper around CEEInfo::GetProfilingHandle. The first time this is called for a
10612 // method desc, it calls through to EEToProfInterfaceImpl::EEFunctionIDMappe and caches the
10613 // result in CEEJitInfo::GetProfilingHandleCache. Thereafter, this wrapper regurgitates the cached values
10614 // rather than calling into CEEInfo::GetProfilingHandle each time. This avoids
10615 // making duplicate calls into the profiler's FunctionIDMapper callback.
10616 void CEEJitInfo::GetProfilingHandle(BOOL *pbHookFunction,
10617 void **pProfilerHandle,
10618 BOOL *pbIndirectedHandles)
10627 _ASSERTE(pbHookFunction != NULL);
10628 _ASSERTE(pProfilerHandle != NULL);
10629 _ASSERTE(pbIndirectedHandles != NULL);
10631 if (!m_gphCache.m_bGphIsCacheValid)
10633 #ifdef PROFILING_SUPPORTED
10634 JIT_TO_EE_TRANSITION();
10636 // Cache not filled in, so make our first and only call to CEEInfo::GetProfilingHandle here
10638 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
10639 // they shouldnever come here as they are called out in GetCompileFlag
10640 _ASSERTE(!m_pMethodBeingCompiled->IsNoMetadata());
10642 // We pass in the typical method definition to the function mapper because in
10643 // Whidbey all the profiling API transactions are done in terms of typical
10644 // method definitions not instantiations.
10645 BOOL bHookFunction = TRUE;
10646 void * profilerHandle = m_pMethodBeingCompiled;
10649 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
10650 profilerHandle = (void *)g_profControlBlock.pProfInterface->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction);
10651 END_PIN_PROFILER();
10654 m_gphCache.m_pvGphProfilerHandle = profilerHandle;
10655 m_gphCache.m_bGphHookFunction = (bHookFunction != FALSE);
10656 m_gphCache.m_bGphIsCacheValid = true;
10658 EE_TO_JIT_TRANSITION();
10659 #endif //PROFILING_SUPPORTED
10662 // Our cache of these values are bitfield bools, but the interface requires
10663 // BOOL. So to avoid setting aside a staging area on the stack for these
10664 // values, we filled them in directly in the if (not cached yet) case.
10665 *pbHookFunction = (m_gphCache.m_bGphHookFunction != false);
10667 // At this point, the remaining values must be in the cache by now, so use them
10668 *pProfilerHandle = m_gphCache.m_pvGphProfilerHandle;
10671 // This is the JIT case, which is never indirected.
10673 *pbIndirectedHandles = FALSE;
10676 /*********************************************************************/
10677 void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr)
10684 CodeHeader* pCodeHeader = GetCodeHeader();
10686 jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len);
10689 /*********************************************************************/
10690 // Route jit information to the Jit Debug store.
10691 void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
10692 ICorDebugInfo::OffsetMapping *pMap)
10701 JIT_TO_EE_TRANSITION();
10703 // We receive ownership of the array
10704 _ASSERTE(m_pOffsetMapping == NULL && m_iOffsetMapping == 0);
10705 m_iOffsetMapping = cMap;
10706 m_pOffsetMapping = pMap;
10708 EE_TO_JIT_TRANSITION();
10711 void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
10720 JIT_TO_EE_TRANSITION();
10722 // We receive ownership of the array
10723 _ASSERTE(m_pNativeVarInfo == NULL && m_iNativeVarInfo == 0);
10724 m_iNativeVarInfo = cVars;
10725 m_pNativeVarInfo = vars;
10727 EE_TO_JIT_TRANSITION();
10730 void CEEJitInfo::CompressDebugInfo()
10739 // Don't track JIT info for DynamicMethods.
10740 if (m_pMethodBeingCompiled->IsDynamicMethod())
10743 if (m_iOffsetMapping == 0 && m_iNativeVarInfo == 0)
10746 JIT_TO_EE_TRANSITION();
10750 PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars(
10751 m_pOffsetMapping, m_iOffsetMapping,
10752 m_pNativeVarInfo, m_iNativeVarInfo,
10754 m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap());
10756 GetCodeHeader()->SetDebugInfo(pDebugInfo);
10760 // Just ignore exceptions here. The debugger's structures will still be in a consistent state.
10762 EX_END_CATCH(SwallowAllExceptions)
10764 EE_TO_JIT_TRANSITION();
10767 void reservePersonalityRoutineSpace(ULONG &unwindSize)
10769 #if defined(_TARGET_X86_)
10771 #elif defined(_TARGET_AMD64_)
10772 // Add space for personality routine, it must be 4-byte aligned.
10773 // Everything in the UNWIND_INFO up to the variable-sized UnwindCodes
10774 // array has already had its size included in unwindSize by the caller.
10775 unwindSize += sizeof(ULONG);
10777 // Note that the count of unwind codes (2 bytes each) is stored as a UBYTE
10778 // So the largest size could be 510 bytes, plus the header and language
10779 // specific stuff. This can't overflow.
10781 _ASSERTE(FitsInU4(unwindSize + sizeof(ULONG)));
10782 unwindSize = (ULONG)(ALIGN_UP(unwindSize, sizeof(ULONG)));
10783 #elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
10784 // The JIT passes in a 4-byte aligned block of unwind data.
10785 _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
10787 // Add space for personality routine, it must be 4-byte aligned.
10788 unwindSize += sizeof(ULONG);
10790 PORTABILITY_ASSERT("reservePersonalityRoutineSpace");
10791 #endif // !defined(_TARGET_AMD64_)
10794 // Reserve memory for the method/funclet's unwind information.
10795 // Note that this must be called before allocMem. It should be
10796 // called once for the main method, once for every funclet, and
10797 // once for every block of cold code for which allocUnwindInfo
10800 // This is necessary because jitted code must allocate all the
10801 // memory needed for the unwindInfo at the allocMem call.
10802 // For prejitted code we split up the unwinding information into
10803 // separate sections .rdata and .pdata.
10805 void CEEJitInfo::reserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize)
10807 #ifdef WIN64EXCEPTIONS
10816 JIT_TO_EE_TRANSITION_LEAF();
10818 CONSISTENCY_CHECK_MSG(!isColdCode, "Hot/Cold splitting is not supported in jitted code");
10819 _ASSERTE_MSG(m_theUnwindBlock == NULL,
10820 "reserveUnwindInfo() can only be called before allocMem(), but allocMem() has already been called. "
10821 "This may indicate the JIT has hit a NO_WAY assert after calling allocMem(), and is re-JITting. "
10822 "Set COMPlus_JitBreakOnBadCode=1 and rerun to get the real error.");
10824 ULONG currentSize = unwindSize;
10826 reservePersonalityRoutineSpace(currentSize);
10828 m_totalUnwindSize += currentSize;
10830 m_totalUnwindInfos++;
10832 EE_TO_JIT_TRANSITION_LEAF();
10833 #else // WIN64EXCEPTIONS
10834 LIMITED_METHOD_CONTRACT;
10835 // Dummy implementation to make cross-platform altjit work
10836 #endif // WIN64EXCEPTIONS
10839 // Allocate and initialize the .rdata and .pdata for this method or
10840 // funclet and get the block of memory needed for the machine specific
10841 // unwind information (the info for crawling the stack frame).
10842 // Note that allocMem must be called first.
10844 // The pHotCode parameter points at the first byte of the code of the method
10845 // The startOffset and endOffset are the region (main or funclet) that
10846 // we are to allocate and create .rdata and .pdata for.
10847 // The pUnwindBlock is copied and contains the .pdata unwind area
10851 // pHotCode main method code buffer, always filled in
10852 // pColdCode always NULL for jitted code
10853 // startOffset start of code block, relative to pHotCode
10854 // endOffset end of code block, relative to pHotCode
10855 // unwindSize size of unwind info pointed to by pUnwindBlock
10856 // pUnwindBlock pointer to unwind info
10857 // funcKind type of funclet (main method code, handler, filter)
10859 void CEEJitInfo::allocUnwindInfo (
10860 BYTE * pHotCode, /* IN */
10861 BYTE * pColdCode, /* IN */
10862 ULONG startOffset, /* IN */
10863 ULONG endOffset, /* IN */
10864 ULONG unwindSize, /* IN */
10865 BYTE * pUnwindBlock, /* IN */
10866 CorJitFuncKind funcKind /* IN */
10869 #ifdef WIN64EXCEPTIONS
10875 PRECONDITION(m_theUnwindBlock != NULL);
10876 PRECONDITION(m_usedUnwindSize < m_totalUnwindSize);
10877 PRECONDITION(m_usedUnwindInfos < m_totalUnwindInfos);
10878 PRECONDITION(endOffset <= m_codeSize);
10881 CONSISTENCY_CHECK_MSG(pColdCode == NULL, "Hot/Cold code splitting not supported for jitted code");
10883 JIT_TO_EE_TRANSITION();
10886 // We add one callback-type dynamic function table per range section.
10887 // Therefore, the RUNTIME_FUNCTION info is always relative to the
10888 // image base contained in the dynamic function table, which happens
10889 // to be the LowAddress of the range section. The JIT has no
10890 // knowledge of the range section, so it gives us offsets that are
10891 // relative to the beginning of the method (pHotCode) and we allocate
10892 // and initialize the RUNTIME_FUNCTION data and record its location
10893 // in this function.
10896 if (funcKind != CORJIT_FUNC_ROOT)
10898 // The main method should be emitted before funclets
10899 _ASSERTE(m_usedUnwindInfos > 0);
10902 PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeader->GetUnwindInfo(m_usedUnwindInfos);
10903 m_usedUnwindInfos++;
10905 // Make sure that the RUNTIME_FUNCTION is aligned on a DWORD sized boundary
10906 _ASSERTE(IS_ALIGNED(pRuntimeFunction, sizeof(DWORD)));
10908 UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *) &(m_theUnwindBlock[m_usedUnwindSize]);
10909 m_usedUnwindSize += unwindSize;
10911 reservePersonalityRoutineSpace(m_usedUnwindSize);
10913 _ASSERTE(m_usedUnwindSize <= m_totalUnwindSize);
10915 // Make sure that the UnwindInfo is aligned
10916 _ASSERTE(IS_ALIGNED(pUnwindInfo, sizeof(ULONG)));
10918 /* Calculate Image Relative offset to add to the jit generated unwind offsets */
10920 TADDR baseAddress = m_moduleBase;
10922 size_t currentCodeSizeT = (size_t)pHotCode - baseAddress;
10924 /* Check if currentCodeSizeT offset fits in 32-bits */
10925 if (!FitsInU4(currentCodeSizeT))
10927 _ASSERTE(!"Bad currentCodeSizeT");
10928 COMPlusThrowHR(E_FAIL);
10931 /* Check if EndAddress offset fits in 32-bit */
10932 if (!FitsInU4(currentCodeSizeT + endOffset))
10934 _ASSERTE(!"Bad currentCodeSizeT");
10935 COMPlusThrowHR(E_FAIL);
10938 unsigned currentCodeOffset = (unsigned) currentCodeSizeT;
10940 /* Calculate Unwind Info delta */
10941 size_t unwindInfoDeltaT = (size_t) pUnwindInfo - baseAddress;
10943 /* Check if unwindDeltaT offset fits in 32-bits */
10944 if (!FitsInU4(unwindInfoDeltaT))
10946 _ASSERTE(!"Bad unwindInfoDeltaT");
10947 COMPlusThrowHR(E_FAIL);
10950 unsigned unwindInfoDelta = (unsigned) unwindInfoDeltaT;
10952 RUNTIME_FUNCTION__SetBeginAddress(pRuntimeFunction, currentCodeOffset + startOffset);
10954 #ifdef _TARGET_AMD64_
10955 pRuntimeFunction->EndAddress = currentCodeOffset + endOffset;
10958 RUNTIME_FUNCTION__SetUnwindInfoAddress(pRuntimeFunction, unwindInfoDelta);
10961 if (funcKind != CORJIT_FUNC_ROOT)
10963 // Check the the new funclet doesn't overlap any existing funclet.
10965 for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++)
10967 PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeader->GetUnwindInfo(iUnwindInfo);
10968 _ASSERTE(( RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress)
10969 || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction)));
10974 /* Copy the UnwindBlock */
10975 memcpy(pUnwindInfo, pUnwindBlock, unwindSize);
10977 #if defined(_TARGET_X86_)
10981 #elif defined(_TARGET_AMD64_)
10983 pUnwindInfo->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
10985 ULONG * pPersonalityRoutine = (ULONG*)ALIGN_UP(&(pUnwindInfo->UnwindCode[pUnwindInfo->CountOfUnwindCodes]), sizeof(ULONG));
10986 *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
10988 #elif defined(_TARGET_ARM64_)
10990 *(LONG *)pUnwindInfo |= (1 << 20); // X bit
10992 ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
10993 *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
10995 #elif defined(_TARGET_ARM_)
10997 *(LONG *)pUnwindInfo |= (1 << 20); // X bit
10999 ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
11000 *pPersonalityRoutine = (TADDR)ProcessCLRException - baseAddress;
11004 #if defined(_TARGET_AMD64_)
11005 // Publish the new unwind information in a way that the ETW stack crawler can find
11006 if (m_usedUnwindInfos == m_totalUnwindInfos)
11007 UnwindInfoTable::PublishUnwindInfoForMethod(baseAddress, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos);
11008 #endif // defined(_TARGET_AMD64_)
11010 EE_TO_JIT_TRANSITION();
11011 #else // WIN64EXCEPTIONS
11012 LIMITED_METHOD_CONTRACT;
11013 // Dummy implementation to make cross-platform altjit work
11014 #endif // WIN64EXCEPTIONS
11017 void CEEJitInfo::recordCallSite(ULONG instrOffset,
11018 CORINFO_SIG_INFO * callSig,
11019 CORINFO_METHOD_HANDLE methodHandle)
11021 // Currently, only testing tools use this method. The EE itself doesn't need record this information.
11022 // N.B. The memory that callSig points to is managed by the JIT and isn't guaranteed to be around after
11023 // this function returns, so future implementations should copy the sig info if they want it to persist.
11024 LIMITED_METHOD_CONTRACT;
11027 // This is a variant for AMD64 or other machines that
11028 // cannot always hold the destination address in a 32-bit location
11029 // A relocation is recorded if we are pre-jitting.
11030 // A jump thunk may be inserted if we are jitting
11032 void CEEJitInfo::recordRelocation(void * location,
11046 JIT_TO_EE_TRANSITION();
11050 switch (fRelocType)
11052 case IMAGE_REL_BASED_DIR64:
11053 // Write 64-bits into location
11054 *((UINT64 *) ((BYTE *) location + slot)) = (UINT64) target;
11057 #ifdef _TARGET_AMD64_
11058 case IMAGE_REL_BASED_REL32:
11060 target = (BYTE *)target + addlDelta;
11062 INT32 * fixupLocation = (INT32 *) ((BYTE *) location + slot);
11063 BYTE * baseAddr = (BYTE *)fixupLocation + sizeof(INT32);
11065 delta = (INT64)((BYTE *)target - baseAddr);
11068 // Do we need to insert a jump stub to make the source reach the target?
11070 // Note that we cannot stress insertion of jump stub by inserting it unconditionally. JIT records the relocations
11071 // for intra-module jumps and calls. It does not expect the register used by the jump stub to be trashed.
11073 if (!FitsInI4(delta))
11078 // When m_fAllowRel32 == TRUE, the JIT will use REL32s for both data addresses and direct code targets.
11079 // Since we cannot tell what the relocation is for, we have to defensively retry.
11081 m_fRel32Overflow = TRUE;
11087 // When m_fAllowRel32 == FALSE, the JIT will use a REL32s for direct code targets only.
11090 delta = rel32UsingJumpStub(fixupLocation, (PCODE)target, m_pMethodBeingCompiled);
11094 LOG((LF_JIT, LL_INFO100000, "Encoded a PCREL32 at" FMT_ADDR "to" FMT_ADDR "+%d, delta is 0x%04x\n",
11095 DBG_ADDR(fixupLocation), DBG_ADDR(target), addlDelta, delta));
11097 // Write the 32-bits pc-relative delta into location
11098 *fixupLocation = (INT32) delta;
11101 #endif // _TARGET_AMD64_
11103 #ifdef _TARGET_ARM64_
11104 case IMAGE_REL_ARM64_BRANCH26: // 26 bit offset << 2 & sign ext, for B and BL
11106 _ASSERTE(slot == 0);
11107 _ASSERTE(addlDelta == 0);
11109 PCODE branchTarget = (PCODE) target;
11110 _ASSERTE((branchTarget & 0x3) == 0); // the low two bits must be zero
11112 PCODE fixupLocation = (PCODE) location;
11113 _ASSERTE((fixupLocation & 0x3) == 0); // the low two bits must be zero
11115 delta = (INT64)(branchTarget - fixupLocation);
11116 _ASSERTE((delta & 0x3) == 0); // the low two bits must be zero
11118 UINT32 branchInstr = *((UINT32*) fixupLocation);
11119 branchInstr &= 0xFC000000; // keep bits 31-26
11120 _ASSERTE((branchInstr & 0x7FFFFFFF) == 0x14000000); // Must be B or BL
11123 // Do we need to insert a jump stub to make the source reach the target?
11126 if (!FitsInRel28(delta))
11130 TADDR baseAddr = (TADDR)fixupLocation;
11131 TADDR loAddr = baseAddr - 0x08000000; // -2^27
11132 TADDR hiAddr = baseAddr + 0x07FFFFFF; // +2^27-1
11134 // Check for the wrap around cases
11135 if (loAddr > baseAddr)
11136 loAddr = UINT64_MIN; // overflow
11137 if (hiAddr < baseAddr)
11138 hiAddr = UINT64_MAX; // overflow
11140 PCODE jumpStubAddr = ExecutionManager::jumpStub(m_pMethodBeingCompiled,
11145 delta = (INT64)(jumpStubAddr - fixupLocation);
11147 if (!FitsInRel28(delta))
11149 _ASSERTE(!"jump stub was not in expected range");
11150 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
11153 LOG((LF_JIT, LL_INFO100000, "Using JumpStub at" FMT_ADDR "that jumps to" FMT_ADDR "\n",
11154 DBG_ADDR(jumpStubAddr), DBG_ADDR(target)));
11157 LOG((LF_JIT, LL_INFO100000, "Encoded a BRANCH26 at" FMT_ADDR "to" FMT_ADDR ", delta is 0x%04x\n",
11158 DBG_ADDR(fixupLocation), DBG_ADDR(target), delta));
11160 _ASSERTE(FitsInRel28(delta));
11162 PutArm64Rel28((UINT32*) fixupLocation, (INT32)delta);
11166 case IMAGE_REL_ARM64_PAGEBASE_REL21:
11168 _ASSERTE(slot == 0);
11169 _ASSERTE(addlDelta == 0);
11171 // Write the 21 bits pc-relative page address into location.
11172 INT64 targetPage = (INT64)target & 0xFFFFFFFFFFFFF000LL;
11173 INT64 lcoationPage = (INT64)location & 0xFFFFFFFFFFFFF000LL;
11174 INT64 relPage = (INT64)(targetPage - lcoationPage);
11175 INT32 imm21 = (INT32)(relPage >> 12) & 0x1FFFFF;
11176 PutArm64Rel21((UINT32 *)location, imm21);
11180 case IMAGE_REL_ARM64_PAGEOFFSET_12A:
11182 _ASSERTE(slot == 0);
11183 _ASSERTE(addlDelta == 0);
11185 // Write the 12 bits page offset into location.
11186 INT32 imm12 = (INT32)target & 0xFFFLL;
11187 PutArm64Rel12((UINT32 *)location, imm12);
11191 #endif // _TARGET_ARM64_
11194 _ASSERTE(!"Unknown reloc type");
11198 EE_TO_JIT_TRANSITION();
11200 JIT_TO_EE_TRANSITION_LEAF();
11202 // Nothing to do on 32-bit
11204 EE_TO_JIT_TRANSITION_LEAF();
11208 WORD CEEJitInfo::getRelocTypeHint(void * target)
11217 #ifdef _TARGET_AMD64_
11220 // The JIT calls this method for data addresses only. It always uses REL32s for direct code targets.
11221 if (IsPreferredExecutableRange(target))
11222 return IMAGE_REL_BASED_REL32;
11224 #endif // _TARGET_AMD64_
11230 void CEEJitInfo::getModuleNativeEntryPointRange(void** pStart, void** pEnd)
11240 JIT_TO_EE_TRANSITION_LEAF();
11242 *pStart = *pEnd = 0;
11244 EE_TO_JIT_TRANSITION_LEAF();
11247 DWORD CEEJitInfo::getExpectedTargetArchitecture()
11249 LIMITED_METHOD_CONTRACT;
11251 return IMAGE_FILE_MACHINE_NATIVE;
11254 void CEEInfo::JitProcessShutdownWork()
11256 LIMITED_METHOD_CONTRACT;
11258 EEJitManager* jitMgr = ExecutionManager::GetEEJitManager();
11260 // If we didn't load the JIT, there is no work to do.
11261 if (jitMgr->m_jit != NULL)
11263 // Do the shutdown work.
11264 jitMgr->m_jit->ProcessShutdownWork(this);
11267 #ifdef ALLOW_SXS_JIT
11268 if (jitMgr->m_alternateJit != NULL)
11270 jitMgr->m_alternateJit->ProcessShutdownWork(this);
11272 #endif // ALLOW_SXS_JIT
11275 /*********************************************************************/
11276 InfoAccessType CEEJitInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
11287 InfoAccessType result = IAT_PVALUE;
11289 JIT_TO_EE_TRANSITION();
11291 _ASSERTE(ppValue != NULL);
11293 if (IsDynamicScope(scopeHnd))
11295 *ppValue = (LPVOID)GetDynamicResolver(scopeHnd)->ConstructStringLiteral(metaTok);
11299 *ppValue = (LPVOID)ConstructStringLiteral(scopeHnd, metaTok); // throws
11302 EE_TO_JIT_TRANSITION();
11307 /*********************************************************************/
11308 InfoAccessType CEEJitInfo::emptyStringLiteral(void ** ppValue)
11317 InfoAccessType result = IAT_PVALUE;
11319 if(NingenEnabled())
11325 JIT_TO_EE_TRANSITION();
11326 *ppValue = StringObject::GetEmptyStringRefPtr();
11327 EE_TO_JIT_TRANSITION();
11332 /*********************************************************************/
11333 void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
11334 void **ppIndirection)
11343 void *result = NULL;
11345 if (ppIndirection != NULL)
11346 *ppIndirection = NULL;
11348 // Do not bother with initialization if we are only verifying the method.
11349 if (isVerifyOnly())
11351 return (void *)0x10;
11354 JIT_TO_EE_TRANSITION();
11356 FieldDesc* field = (FieldDesc*) fieldHnd;
11358 MethodTable* pMT = field->GetEnclosingMethodTable();
11360 _ASSERTE(!pMT->ContainsGenericVariables());
11362 // We must not call here for statics of collectible types.
11363 _ASSERTE(!pMT->Collectible());
11367 if (!field->IsRVA())
11369 // <REVISIT_TODO>@todo: assert that the current method being compiled is unshared</REVISIT_TODO>
11371 // Allocate space for the local class if necessary, but don't trigger
11372 // class construction.
11373 DomainLocalModule *pLocalModule = pMT->GetDomainLocalModule();
11374 pLocalModule->PopulateClass(pMT);
11378 base = (void *) field->GetBase();
11381 result = field->GetStaticAddressHandle(base);
11383 EE_TO_JIT_TRANSITION();
11388 static void *GetClassSync(MethodTable *pMT)
11390 STANDARD_VM_CONTRACT;
11394 OBJECTREF ref = pMT->GetManagedClassObject();
11395 return (void*)ref->GetSyncBlock()->GetMonitor();
11398 /*********************************************************************/
11399 void* CEEJitInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
11400 void **ppIndirection)
11409 void * result = NULL;
11411 if (ppIndirection != NULL)
11412 *ppIndirection = NULL;
11414 JIT_TO_EE_TRANSITION();
11416 result = GetClassSync((GetMethod(ftnHnd))->GetMethodTable());
11418 EE_TO_JIT_TRANSITION();
11423 /*********************************************************************/
11424 HRESULT CEEJitInfo::allocBBProfileBuffer (
11426 ICorJitInfo::ProfileBuffer ** profileBuffer
11436 HRESULT hr = E_FAIL;
11438 JIT_TO_EE_TRANSITION();
11440 #ifdef FEATURE_PREJIT
11442 // We need to know the code size. Typically we can get the code size
11443 // from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so
11444 // for that case we need to use DynamicResolver to get the code size.
11446 unsigned codeSize = 0;
11447 if (m_pMethodBeingCompiled->IsDynamicMethod())
11449 unsigned stackSize, ehSize;
11450 CorInfoOptions options;
11451 DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver();
11452 pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize);
11456 codeSize = m_ILHeader->GetCodeSize();
11459 *profileBuffer = m_pMethodBeingCompiled->GetLoaderModule()->AllocateProfileBuffer(m_pMethodBeingCompiled->GetMemberDef(), count, codeSize);
11460 hr = (*profileBuffer ? S_OK : E_OUTOFMEMORY);
11461 #else // FEATURE_PREJIT
11462 _ASSERTE(!"allocBBProfileBuffer not implemented on CEEJitInfo!");
11464 #endif // !FEATURE_PREJIT
11466 EE_TO_JIT_TRANSITION();
11471 // Consider implementing getBBProfileData on CEEJitInfo. This will allow us
11472 // to use profile info in codegen for non zapped images.
11473 HRESULT CEEJitInfo::getBBProfileData (
11474 CORINFO_METHOD_HANDLE ftnHnd,
11476 ICorJitInfo::ProfileBuffer ** profileBuffer,
11480 LIMITED_METHOD_CONTRACT;
11481 _ASSERTE(!"getBBProfileData not implemented on CEEJitInfo!");
11485 void CEEJitInfo::allocMem (
11486 ULONG hotCodeSize, /* IN */
11487 ULONG coldCodeSize, /* IN */
11488 ULONG roDataSize, /* IN */
11489 ULONG xcptnsCount, /* IN */
11490 CorJitAllocMemFlag flag, /* IN */
11491 void ** hotCodeBlock, /* OUT */
11492 void ** coldCodeBlock, /* OUT */
11493 void ** roDataBlock /* OUT */
11503 JIT_TO_EE_TRANSITION();
11505 _ASSERTE(coldCodeSize == 0);
11508 *coldCodeBlock = NULL;
11511 ULONG codeSize = hotCodeSize;
11512 void **codeBlock = hotCodeBlock;
11514 S_SIZE_T totalSize = S_SIZE_T(codeSize);
11516 size_t roDataAlignment = sizeof(void*);
11517 if ((flag & CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN)!= 0)
11519 roDataAlignment = 16;
11521 else if (roDataSize >= 8)
11523 roDataAlignment = 8;
11525 if (roDataSize > 0)
11527 size_t codeAlignment = ((flag & CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN)!= 0)
11528 ? 16 : sizeof(void*);
11529 totalSize.AlignUp(codeAlignment);
11530 if (roDataAlignment > codeAlignment) {
11531 // Add padding to align read-only data.
11532 totalSize += (roDataAlignment - codeAlignment);
11534 totalSize += roDataSize;
11537 #ifdef WIN64EXCEPTIONS
11538 totalSize.AlignUp(sizeof(DWORD));
11539 totalSize += m_totalUnwindSize;
11542 _ASSERTE(m_CodeHeader == 0 &&
11543 // The jit-compiler sometimes tries to compile a method a second time
11544 // if it failed the first time. In such a situation, m_CodeHeader may
11545 // have already been assigned. Its OK to ignore this assert in such a
11546 // situation - we will leak some memory, but that is acceptable
11547 // since this should happen very rarely.
11548 "Note that this may fire if the JITCompiler tries to recompile a method");
11550 if( totalSize.IsOverflow() )
11552 COMPlusThrowHR(CORJIT_OUTOFMEM);
11555 m_CodeHeader = m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), flag
11556 #ifdef WIN64EXCEPTIONS
11557 , m_totalUnwindInfos
11562 BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress();
11564 *codeBlock = current;
11565 current += codeSize;
11567 if (roDataSize > 0)
11569 current = (BYTE *)ALIGN_UP(current, roDataAlignment);
11570 *roDataBlock = current;
11571 current += roDataSize;
11575 *roDataBlock = NULL;
11578 #ifdef WIN64EXCEPTIONS
11579 current = (BYTE *)ALIGN_UP(current, sizeof(DWORD));
11581 m_theUnwindBlock = current;
11582 current += m_totalUnwindSize;
11585 _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value());
11588 m_codeSize = codeSize;
11591 EE_TO_JIT_TRANSITION();
11594 /*********************************************************************/
11595 void * CEEJitInfo::allocGCInfo (size_t size)
11604 void * block = NULL;
11606 JIT_TO_EE_TRANSITION();
11608 _ASSERTE(m_CodeHeader != 0);
11609 _ASSERTE(m_CodeHeader->GetGCInfo() == 0);
11612 if (size & 0xFFFFFFFF80000000LL)
11614 COMPlusThrowHR(CORJIT_OUTOFMEM);
11618 block = m_jitManager->allocGCInfo(m_CodeHeader,(DWORD)size, &m_GCinfo_len);
11621 COMPlusThrowHR(CORJIT_OUTOFMEM);
11624 _ASSERTE(m_CodeHeader->GetGCInfo() != 0 && block == m_CodeHeader->GetGCInfo());
11626 EE_TO_JIT_TRANSITION();
11631 /*********************************************************************/
11632 void CEEJitInfo::setEHcount (
11642 JIT_TO_EE_TRANSITION();
11644 _ASSERTE(cEH != 0);
11645 _ASSERTE(m_CodeHeader != 0);
11646 _ASSERTE(m_CodeHeader->GetEHInfo() == 0);
11648 EE_ILEXCEPTION* ret;
11649 ret = m_jitManager->allocEHInfo(m_CodeHeader,cEH, &m_EHinfo_len);
11650 _ASSERTE(ret); // allocEHInfo throws if there's not enough memory
11652 _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && m_CodeHeader->GetEHInfo()->EHCount() == cEH);
11654 EE_TO_JIT_TRANSITION();
11657 /*********************************************************************/
11658 void CEEJitInfo::setEHinfo (
11660 const CORINFO_EH_CLAUSE* clause)
11669 JIT_TO_EE_TRANSITION();
11671 // <REVISIT_TODO> Fix make the Code Manager EH clauses EH_INFO+</REVISIT_TODO>
11672 _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && EHnumber < m_CodeHeader->GetEHInfo()->EHCount());
11674 EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeader->GetEHInfo()->EHClause(EHnumber);
11676 pEHClause->TryStartPC = clause->TryOffset;
11677 pEHClause->TryEndPC = clause->TryLength;
11678 pEHClause->HandlerStartPC = clause->HandlerOffset;
11679 pEHClause->HandlerEndPC = clause->HandlerLength;
11680 pEHClause->ClassToken = clause->ClassToken;
11681 pEHClause->Flags = (CorExceptionFlag)clause->Flags;
11683 LOG((LF_EH, LL_INFO1000000, "Setting EH clause #%d for %s::%s\n", EHnumber, m_pMethodBeingCompiled->m_pszDebugClassName, m_pMethodBeingCompiled->m_pszDebugMethodName));
11684 LOG((LF_EH, LL_INFO1000000, " Flags : 0x%08lx -> 0x%08lx\n", clause->Flags, pEHClause->Flags));
11685 LOG((LF_EH, LL_INFO1000000, " TryOffset : 0x%08lx -> 0x%08lx (startpc)\n", clause->TryOffset, pEHClause->TryStartPC));
11686 LOG((LF_EH, LL_INFO1000000, " TryLength : 0x%08lx -> 0x%08lx (endpc)\n", clause->TryLength, pEHClause->TryEndPC));
11687 LOG((LF_EH, LL_INFO1000000, " HandlerOffset : 0x%08lx -> 0x%08lx\n", clause->HandlerOffset, pEHClause->HandlerStartPC));
11688 LOG((LF_EH, LL_INFO1000000, " HandlerLength : 0x%08lx -> 0x%08lx\n", clause->HandlerLength, pEHClause->HandlerEndPC));
11689 LOG((LF_EH, LL_INFO1000000, " ClassToken : 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->ClassToken));
11690 LOG((LF_EH, LL_INFO1000000, " FilterOffset : 0x%08lx -> 0x%08lx\n", clause->FilterOffset, pEHClause->FilterOffset));
11692 if (m_pMethodBeingCompiled->IsDynamicMethod() &&
11693 ((pEHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) == 0) &&
11694 (clause->ClassToken != NULL))
11696 MethodDesc * pMD; FieldDesc * pFD;
11697 m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver()->ResolveToken(clause->ClassToken, (TypeHandle *)&pEHClause->TypeHandle, &pMD, &pFD);
11698 SetHasCachedTypeHandle(pEHClause);
11699 LOG((LF_EH, LL_INFO1000000, " CachedTypeHandle: 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->TypeHandle));
11702 EE_TO_JIT_TRANSITION();
11705 /*********************************************************************/
11706 // get individual exception handler
11707 void CEEJitInfo::getEHinfo(
11708 CORINFO_METHOD_HANDLE ftn, /* IN */
11709 unsigned EHnumber, /* IN */
11710 CORINFO_EH_CLAUSE* clause) /* OUT */
11719 JIT_TO_EE_TRANSITION();
11721 if (IsDynamicMethodHandle(ftn))
11723 GetMethod(ftn)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
11727 _ASSERTE(ftn == CORINFO_METHOD_HANDLE(m_pMethodBeingCompiled)); // For now only support if the method being jitted
11728 getEHinfoHelper(ftn, EHnumber, clause, m_ILHeader);
11731 EE_TO_JIT_TRANSITION();
11733 #endif // CROSSGEN_COMPILE
11735 #if defined(CROSSGEN_COMPILE)
11736 EXTERN_C ICorJitCompiler* __stdcall getJit();
11737 #endif // defined(CROSSGEN_COMPILE)
11739 #ifdef FEATURE_INTERPRETER
11740 static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr,
11742 struct CORINFO_METHOD_INFO *info,
11744 BYTE **nativeEntry,
11745 ULONG *nativeSizeOfCode)
11747 STATIC_CONTRACT_THROWS;
11748 STATIC_CONTRACT_GC_TRIGGERS;
11749 STATIC_CONTRACT_MODE_PREEMPTIVE;
11750 STATIC_CONTRACT_SO_INTOLERANT;
11752 SString namespaceOrClassName, methodName, methodSignature;
11753 // Fire an ETW event to mark the beginning of JIT'ing
11754 ETW::MethodLog::MethodJitting(reinterpret_cast<MethodDesc*>(info->ftn), &namespaceOrClassName, &methodName, &methodSignature);
11756 CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode);
11758 // Logically, it would seem that the end-of-JITting ETW even should go here, but it must come after the native code has been
11759 // set for the given method desc, which happens in a caller.
11763 #endif // FEATURE_INTERPRETER
11766 // Helper function because can't have dtors in BEGIN_SO_TOLERANT_CODE.
11768 CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr,
11770 struct CORINFO_METHOD_INFO *info,
11771 CORJIT_FLAGS jitFlags,
11772 BYTE **nativeEntry,
11773 ULONG *nativeSizeOfCode)
11775 STATIC_CONTRACT_THROWS;
11776 STATIC_CONTRACT_GC_TRIGGERS;
11777 STATIC_CONTRACT_MODE_PREEMPTIVE;
11778 STATIC_CONTRACT_SO_INTOLERANT;
11780 CorJitResult ret = CORJIT_SKIPPED; // Note that CORJIT_SKIPPED is an error exit status code
11783 comp->setJitFlags(jitFlags);
11785 #ifdef FEATURE_STACK_SAMPLING
11786 // SO_INTOLERANT due to init affecting global state.
11787 static ConfigDWORD s_stackSamplingEnabled;
11788 bool samplingEnabled = (s_stackSamplingEnabled.val(CLRConfig::UNSUPPORTED_StackSamplingEnabled) != 0);
11791 BEGIN_SO_TOLERANT_CODE(GetThread());
11794 #if defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
11795 if (FAILED(ret) && jitMgr->m_alternateJit
11796 #ifdef FEATURE_STACK_SAMPLING
11797 && (!samplingEnabled || (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)))
11801 ret = jitMgr->m_alternateJit->compileMethod( comp,
11803 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11805 nativeSizeOfCode );
11807 #ifdef FEATURE_STACK_SAMPLING
11808 if (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND))
11810 // Don't bother with failures if we couldn't collect a trace.
11813 #endif // FEATURE_STACK_SAMPLING
11815 // If we failed to jit, then fall back to the primary Jit.
11818 // Consider adding this call:
11819 // ((CEEJitInfo*)comp)->BackoutJitData(jitMgr);
11820 ((CEEJitInfo*)comp)->ResetForJitRetry();
11821 ret = CORJIT_SKIPPED;
11824 #endif // defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
11826 #ifdef FEATURE_INTERPRETER
11827 static ConfigDWORD s_InterpreterFallback;
11829 bool interpreterFallback = (s_InterpreterFallback.val(CLRConfig::INTERNAL_InterpreterFallback) != 0);
11831 if (interpreterFallback == false)
11833 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
11834 // (We assume that importation is completely architecture-independent, or at least nearly so.)
11835 if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
11837 ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode);
11841 if (FAILED(ret) && jitMgr->m_jit)
11843 ret = CompileMethodWithEtwWrapper(jitMgr,
11846 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11851 if (interpreterFallback == true)
11853 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
11854 // (We assume that importation is completely architecture-independent, or at least nearly so.)
11855 if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
11857 ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode);
11863 ret = jitMgr->m_jit->compileMethod( comp,
11865 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11869 #endif // FEATURE_INTERPRETER
11871 #if !defined(CROSSGEN_COMPILE)
11872 // Cleanup any internal data structures allocated
11873 // such as IL code after a successfull JIT compile
11874 // If the JIT fails we keep the IL around and will
11875 // try reJIT the same IL. VSW 525059
11877 if (SUCCEEDED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !((CEEJitInfo*)comp)->JitAgain())
11879 ((CEEJitInfo*)comp)->CompressDebugInfo();
11881 #ifdef FEATURE_INTERPRETER
11882 // We do this cleanup in the prestub, where we know whether the method
11883 // has been interpreted.
11885 comp->MethodCompileComplete(info->ftn);
11886 #endif // FEATURE_INTERPRETER
11888 #endif // !defined(CROSSGEN_COMPILE)
11891 #if defined(FEATURE_GDBJIT)
11892 if (SUCCEEDED(ret) && *nativeEntry != NULL)
11894 CodeHeader* pCH = ((CodeHeader*)((PCODE)*nativeEntry & ~1)) - 1;
11895 pCH->SetCalledMethods((PTR_VOID)comp->GetCalledMethods());
11899 END_SO_TOLERANT_CODE;
11905 /*********************************************************************/
11906 CorJitResult invokeCompileMethod(EEJitManager *jitMgr,
11908 struct CORINFO_METHOD_INFO *info,
11909 CORJIT_FLAGS jitFlags,
11910 BYTE **nativeEntry,
11911 ULONG *nativeSizeOfCode)
11919 // The JIT runs in preemptive mode
11924 CorJitResult ret = invokeCompileMethodHelper(jitMgr, comp, info, jitFlags, nativeEntry, nativeSizeOfCode);
11927 // Verify that we are still in preemptive mode when we return
11931 _ASSERTE(GetThread()->PreemptiveGCDisabled() == FALSE);
11936 CORJIT_FLAGS GetCompileFlagsIfGenericInstantiation(
11937 CORINFO_METHOD_HANDLE method,
11938 CORJIT_FLAGS compileFlags,
11939 ICorJitInfo * pCorJitInfo,
11940 BOOL * raiseVerificationException,
11941 BOOL * unverifiableGenericCode);
11943 CorJitResult CallCompileMethodWithSEHWrapper(EEJitManager *jitMgr,
11945 struct CORINFO_METHOD_INFO *info,
11946 CORJIT_FLAGS flags,
11947 BYTE **nativeEntry,
11948 ULONG *nativeSizeOfCode,
11951 // no dynamic contract here because SEH is used, with a finally clause
11952 STATIC_CONTRACT_NOTHROW;
11953 STATIC_CONTRACT_GC_TRIGGERS;
11955 LOG((LF_CORDB, LL_EVERYTHING, "CallCompileMethodWithSEHWrapper called...\n"));
11959 EEJitManager *jitMgr;
11961 struct CORINFO_METHOD_INFO *info;
11962 CORJIT_FLAGS flags;
11963 BYTE **nativeEntry;
11964 ULONG *nativeSizeOfCode;
11968 param.jitMgr = jitMgr;
11971 param.flags = flags;
11972 param.nativeEntry = nativeEntry;
11973 param.nativeSizeOfCode = nativeSizeOfCode;
11975 param.res = CORJIT_INTERNALERROR;
11977 PAL_TRY(Param *, pParam, ¶m)
11980 // Call out to the JIT-compiler
11983 pParam->res = invokeCompileMethod( pParam->jitMgr,
11987 pParam->nativeEntry,
11988 pParam->nativeSizeOfCode);
11992 #if defined(DEBUGGING_SUPPORTED) && !defined(CROSSGEN_COMPILE)
11993 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) &&
11994 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MCJIT_BACKGROUND)
11995 #ifdef FEATURE_STACK_SAMPLING
11996 && !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)
11997 #endif // FEATURE_STACK_SAMPLING
12001 // Notify the debugger that we have successfully jitted the function
12003 if (ftn->HasNativeCode())
12006 // Nothing to do here (don't need to notify the debugger
12007 // because the function has already been successfully jitted)
12009 // This is the case where we aborted the jit because of a deadlock cycle
12015 if (g_pDebugInterface)
12017 if (param.res == CORJIT_OK && !((CEEJitInfo*)param.comp)->JitAgain())
12019 g_pDebugInterface->JITComplete(ftn, (TADDR) *nativeEntry);
12024 #endif // DEBUGGING_SUPPORTED && !CROSSGEN_COMPILE
12031 /*********************************************************************/
12032 // Figures out the compile flags that are used by both JIT and NGen
12034 /* static */ CORJIT_FLAGS CEEInfo::GetBaseCompileFlags(MethodDesc * ftn)
12042 // Figure out the code quality flags
12045 CORJIT_FLAGS flags;
12046 if (g_pConfig->JitFramed())
12047 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12048 if (g_pConfig->JitAlignLoops())
12049 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_ALIGN_LOOPS);
12050 if (ReJitManager::IsReJITEnabled() || g_pConfig->AddRejitNops())
12051 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_REJIT_NOPS);
12052 #ifdef _TARGET_X86_
12053 if (g_pConfig->PInvokeRestoreEsp(ftn->GetModule()->IsPreV4Assembly()))
12054 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PINVOKE_RESTORE_ESP);
12055 #endif // _TARGET_X86_
12057 //See if we should instruct the JIT to emit calls to JIT_PollGC for thread suspension. If we have a
12058 //non-default value in the EE Config, then use that. Otherwise select the platform specific default.
12059 #ifdef FEATURE_ENABLE_GCPOLL
12060 EEConfig::GCPollType pollType = g_pConfig->GetGCPollType();
12061 if (EEConfig::GCPOLL_TYPE_POLL == pollType)
12062 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_CALLS);
12063 else if (EEConfig::GCPOLL_TYPE_INLINE == pollType)
12064 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_INLINE);
12065 #endif //FEATURE_ENABLE_GCPOLL
12067 // Set flags based on method's ImplFlags.
12068 if (!ftn->IsNoMetadata())
12070 DWORD dwImplFlags = 0;
12071 IfFailThrow(ftn->GetMDImport()->GetMethodImplProps(ftn->GetMemberDef(), NULL, &dwImplFlags));
12073 if (IsMiNoOptimization(dwImplFlags))
12075 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12078 // Always emit frames for methods marked no-inline (see #define ETW_EBP_FRAMED in the JIT)
12079 if (IsMiNoInlining(dwImplFlags))
12081 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12088 /*********************************************************************/
12089 // Figures out (some of) the flags to use to compile the method
12090 // Returns the new set to use
12092 CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags)
12094 STANDARD_VM_CONTRACT;
12096 //Right now if we don't have a debug interface on CoreCLR, we can't generate debug info. So, in those
12097 //cases don't attempt it.
12098 if (!g_pDebugInterface)
12101 #ifdef DEBUGGING_SUPPORTED
12104 if (g_pConfig->GenDebuggableCode())
12105 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12108 #ifdef EnC_SUPPORTED
12109 if (pModule->IsEditAndContinueEnabled())
12111 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_EnC);
12113 #endif // EnC_SUPPORTED
12115 // Debug info is always tracked
12116 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12117 #endif // DEBUGGING_SUPPORTED
12119 if (CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
12121 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12124 if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12126 // If we are only verifying the method, dont need any debug info and this
12127 // prevents getVars()/getBoundaries() from being called unnecessarily.
12128 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12129 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12135 CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHOD_INFO * methodInfo)
12137 STANDARD_VM_CONTRACT;
12139 _ASSERTE(methodInfo->regionKind == CORINFO_REGION_JIT);
12142 // Get the compile flags that are shared between JIT and NGen
12144 flags.Add(CEEInfo::GetBaseCompileFlags(ftn));
12147 // Get CPU specific flags
12149 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12151 flags.Add(ExecutionManager::GetEEJitManager()->GetCPUCompileFlags());
12155 // Find the debugger and profiler related flags
12158 #ifdef DEBUGGING_SUPPORTED
12159 flags.Add(GetDebuggerCompileFlags(ftn->GetModule(), flags));
12162 #ifdef PROFILING_SUPPORTED
12163 if (CORProfilerTrackEnterLeave() && !ftn->IsNoMetadata())
12164 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE);
12166 if (CORProfilerTrackTransitions())
12167 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_NO_PINVOKE_INLINE);
12168 #endif // PROFILING_SUPPORTED
12170 // Set optimization flags
12171 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT))
12173 unsigned optType = g_pConfig->GenOptimizeType();
12174 _ASSERTE(optType <= OPT_RANDOM);
12176 if (optType == OPT_RANDOM)
12177 optType = methodInfo->ILCodeSize % OPT_RANDOM;
12179 if (g_pConfig->JitMinOpts())
12180 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12182 if (optType == OPT_SIZE)
12184 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SIZE_OPT);
12186 else if (optType == OPT_SPEED)
12188 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SPEED_OPT);
12193 // Verification flags
12197 if (g_pConfig->IsJitVerificationDisabled())
12198 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12201 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && Security::CanSkipVerification(ftn))
12202 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12204 if (ftn->IsILStub())
12206 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12208 // no debug info available for IL stubs
12209 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12215 #if defined(_WIN64)
12216 //The implementation of Jit64 prevents it from both inlining and verifying at the same time. This causes a
12217 //perf problem for code that adopts Transparency. This code attempts to enable inlining in spite of that
12218 //limitation in that scenario.
12220 //This only works for real methods. If the method isn't IsIL, then IsVerifiable will AV. That would be a
12222 BOOL IsTransparentMethodSafeToSkipVerification(CORJIT_FLAGS flags, MethodDesc * ftn)
12224 STANDARD_VM_CONTRACT;
12227 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION)
12228 && Security::IsMethodTransparent(ftn) &&
12229 ((ftn->IsIL() && !ftn->IsUnboxingStub()) ||
12230 (ftn->IsDynamicMethod() && !ftn->IsILStub())))
12234 //Verify the method
12235 ret = ftn->IsVerifiable();
12239 //If the jit throws an exception, do not let it leak out of here. For example, we can sometimes
12240 //get an IPE that we could recover from in the Jit (i.e. invalid local in a method with skip
12243 EX_END_CATCH(RethrowTerminalExceptions)
12248 #define IsTransparentMethodSafeToSkipVerification(flags,ftn) (FALSE)
12251 /*********************************************************************/
12252 // We verify generic code once and for all using the typical open type,
12253 // and then no instantiations need to be verified. If verification
12254 // failed, then we need to throw an exception whenever we try
12255 // to compile a real instantiation
12257 CORJIT_FLAGS GetCompileFlagsIfGenericInstantiation(
12258 CORINFO_METHOD_HANDLE method,
12259 CORJIT_FLAGS compileFlags,
12260 ICorJitInfo * pCorJitInfo,
12261 BOOL * raiseVerificationException,
12262 BOOL * unverifiableGenericCode)
12264 STANDARD_VM_CONTRACT;
12266 *raiseVerificationException = FALSE;
12267 *unverifiableGenericCode = FALSE;
12269 // If we have already decided to skip verification, keep on going.
12270 if (compileFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION))
12271 return compileFlags;
12273 CorInfoInstantiationVerification ver = pCorJitInfo->isInstantiationOfVerifiedGeneric(method);
12277 case INSTVER_NOT_INSTANTIATION:
12278 // Non-generic, or open instantiation of a generic type/method
12279 if (IsTransparentMethodSafeToSkipVerification(compileFlags, (MethodDesc*)method))
12280 compileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12281 return compileFlags;
12283 case INSTVER_GENERIC_PASSED_VERIFICATION:
12284 // If the typical instantiation is verifiable, there is no need
12285 // to verify the concrete instantiations
12286 compileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12287 return compileFlags;
12289 case INSTVER_GENERIC_FAILED_VERIFICATION:
12291 *unverifiableGenericCode = TRUE;
12293 // The generic method is not verifiable.
12294 // Check if it has SkipVerification permission
12295 MethodDesc * pGenMethod = GetMethod(method)->LoadTypicalMethodDefinition();
12297 CORINFO_METHOD_HANDLE genMethodHandle = CORINFO_METHOD_HANDLE(pGenMethod);
12299 CorInfoCanSkipVerificationResult canSkipVer;
12300 canSkipVer = pCorJitInfo->canSkipMethodVerification(genMethodHandle);
12305 #ifdef FEATURE_PREJIT
12306 case CORINFO_VERIFICATION_DONT_JIT:
12308 // Transparent code could be partial trust, but we don't know at NGEN time.
12309 // This is the flag that NGEN passes to the JIT to tell it to give-up if it
12310 // hits unverifiable code. Since we've already hit unverifiable code,
12311 // there's no point in starting the JIT, just to have it give up, so we
12313 _ASSERTE(compileFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_PREJIT));
12314 *raiseVerificationException = TRUE;
12315 return CORJIT_FLAGS(); // This value will not be used
12317 #else // FEATURE_PREJIT
12318 // Need to have this case here to keep the MAC build happy
12319 case CORINFO_VERIFICATION_DONT_JIT:
12321 _ASSERTE(!"We should never get here");
12322 return compileFlags;
12324 #endif // FEATURE_PREJIT
12326 case CORINFO_VERIFICATION_CANNOT_SKIP:
12328 // For unverifiable generic code without SkipVerification permission,
12329 // we cannot ask the compiler to emit CORINFO_HELP_VERIFICATION in
12330 // unverifiable branches as the compiler cannot determine the unverifiable
12331 // branches while compiling the concrete instantiation. Instead,
12332 // just throw a VerificationException right away.
12333 *raiseVerificationException = TRUE;
12334 return CORJIT_FLAGS(); // This value will not be used
12337 case CORINFO_VERIFICATION_CAN_SKIP:
12339 compileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12340 return compileFlags;
12343 case CORINFO_VERIFICATION_RUNTIME_CHECK:
12345 // Compile the method without CORJIT_FLAG_SKIP_VERIFICATION.
12346 // The compiler will know to add a call to
12347 // CORINFO_HELP_VERIFICATION_RUNTIME_CHECK, and then to skip verification.
12348 return compileFlags;
12353 _ASSERTE(!"We should never get here");
12354 return compileFlags;
12357 // ********************************************************************
12359 // Throw the right type of exception for the given JIT result
12361 void ThrowExceptionForJit(HRESULT res)
12373 case CORJIT_OUTOFMEM:
12377 #ifdef _TARGET_X86_
12378 // Currently, only x86 JIT returns adequate error codes. The x86 JIT is also the
12379 // JIT that has more limitations and given that to get this message for 64 bit
12380 // is going to require some code churn (either changing their EH handlers or
12381 // fixing the 3 or 4 code sites they have that return CORJIT_INTERNALERROR independently
12382 // of the error, the least risk fix is making this x86 only.
12383 case CORJIT_INTERNALERROR:
12384 COMPlusThrow(kInvalidProgramException, (UINT) IDS_EE_JIT_COMPILER_ERROR);
12388 case CORJIT_BADCODE:
12390 COMPlusThrow(kInvalidProgramException);
12395 // ********************************************************************
12397 LONG g_JitCount = 0;
12400 //#define PERF_TRACK_METHOD_JITTIMES
12401 #ifdef _TARGET_AMD64_
12402 BOOL g_fAllowRel32 = TRUE;
12406 // ********************************************************************
12408 // ********************************************************************
12410 // The reason that this is named UnsafeJitFunction is that this helper
12411 // method is not thread safe! When multiple threads get in here for
12412 // the same pMD, ALL of them MUST return the SAME value.
12413 // To insure that this happens you must call MakeJitWorker.
12414 // It creates a DeadlockAware list of methods being jitted and prevents us
12415 // from trying to jit the same method more that once.
12417 // Calls to this method that occur to check if inlining can occur on x86,
12418 // are OK since they discard the return value of this method.
12420 PCODE UnsafeJitFunction(MethodDesc* ftn, COR_ILMETHOD_DECODER* ILHeader, CORJIT_FLAGS flags,
12421 ULONG * pSizeOfCode)
12423 STANDARD_VM_CONTRACT;
12427 COOPERATIVE_TRANSITION_BEGIN();
12429 #ifdef FEATURE_PREJIT
12431 if (g_pConfig->RequireZaps() == EEConfig::REQUIRE_ZAPS_ALL &&
12432 ftn->GetModule()->GetDomainFile()->IsZapRequired() &&
12433 PartialNGenStressPercentage() == 0 &&
12434 #ifdef FEATURE_STACK_SAMPLING
12435 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND) &&
12437 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12439 StackSString ss(SString::Ascii, "ZapRequire: JIT compiler invoked for ");
12440 TypeString::AppendMethodInternal(ss, ftn);
12443 // Assert as some test may not check their error codes well. So throwing an
12444 // exception may not cause a test failure (as it should).
12445 StackScratchBuffer scratch;
12446 DbgAssertDialog(__FILE__, __LINE__, (char*)ss.GetUTF8(scratch));
12449 COMPlusThrowNonLocalized(kFileNotFoundException, ss.GetUnicode());
12452 #endif // FEATURE_PREJIT
12454 #ifndef CROSSGEN_COMPILE
12455 EEJitManager *jitMgr = ExecutionManager::GetEEJitManager();
12456 if (!jitMgr->LoadJIT())
12458 #ifdef ALLOW_SXS_JIT
12459 if (!jitMgr->IsMainJitLoaded())
12461 // Don't want to throw InvalidProgram from here.
12462 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12464 if (!jitMgr->IsAltJitLoaded())
12466 // Don't want to throw InvalidProgram from here.
12467 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load alternative JIT compiler"));
12469 #else // ALLOW_SXS_JIT
12470 // Don't want to throw InvalidProgram from here.
12471 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12472 #endif // ALLOW_SXS_JIT
12474 #endif // CROSSGEN_COMPILE
12477 // This is here so we can see the name and class easily in the debugger
12479 LPCUTF8 cls = ftn->GetMethodTable()->GetDebugClassName();
12480 LPCUTF8 name = ftn->GetName();
12482 if (ftn->IsNoMetadata())
12484 if (ftn->IsILStub())
12486 LOG((LF_JIT, LL_INFO10000, "{ Jitting IL Stub }\n"));
12490 LOG((LF_JIT, LL_INFO10000, "{ Jitting dynamic method }\n"));
12495 SString methodString;
12496 if (LoggingOn(LF_JIT, LL_INFO10000))
12497 TypeString::AppendMethodDebug(methodString, ftn);
12499 LOG((LF_JIT, LL_INFO10000, "{ Jitting method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12503 if (!SString::_stricmp(cls,"ENC") &&
12504 (!SString::_stricmp(name,"G")))
12514 CORINFO_METHOD_HANDLE ftnHnd = (CORINFO_METHOD_HANDLE)ftn;
12515 CORINFO_METHOD_INFO methodInfo;
12517 getMethodInfoHelper(ftn, ftnHnd, ILHeader, &methodInfo);
12519 // If it's generic then we can only enter through an instantiated md (unless we're just verifying it)
12520 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || !ftn->IsGenericMethodDefinition());
12522 // If it's an instance method then it must not be entered from a generic class
12523 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || ftn->IsStatic() ||
12524 ftn->GetNumGenericClassArgs() == 0 || ftn->HasClassInstantiation());
12526 // method attributes and signature are consistant
12527 _ASSERTE(!!ftn->IsStatic() == ((methodInfo.args.callConv & CORINFO_CALLCONV_HASTHIS) == 0));
12529 flags = GetCompileFlags(ftn, flags, &methodInfo);
12532 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION))
12534 SString methodString;
12535 if (LoggingOn(LF_VERIFIER, LL_INFO100))
12536 TypeString::AppendMethodDebug(methodString, ftn);
12538 LOG((LF_VERIFIER, LL_INFO100, "{ Will verify method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12542 #ifdef _TARGET_AMD64_
12543 BOOL fForceRel32Overflow = FALSE;
12546 // Always exercise the overflow codepath with force relocs
12547 if (PEDecoder::GetForceRelocs())
12548 fForceRel32Overflow = TRUE;
12551 BOOL fAllowRel32 = g_fAllowRel32 | fForceRel32Overflow;
12553 // For determinism, never try to use the REL32 in compilation process
12554 if (IsCompilationProcess())
12556 fForceRel32Overflow = FALSE;
12557 fAllowRel32 = FALSE;
12559 #endif // _TARGET_AMD64_
12563 #ifndef CROSSGEN_COMPILE
12564 CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY));
12566 // This path should be only ever used for verification in crossgen and so we should not need EEJitManager
12567 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY));
12568 CEEInfo jitInfo(ftn, true);
12569 EEJitManager *jitMgr = NULL;
12572 #if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE)
12573 if (fForceRel32Overflow)
12574 jitInfo.SetRel32Overflow(fAllowRel32);
12575 jitInfo.SetAllowRel32(fAllowRel32);
12578 MethodDesc * pMethodForSecurity = jitInfo.GetMethodForSecurity(ftnHnd);
12580 //Since the check could trigger a demand, we have to do this every time.
12581 //This is actually an overly complicated way to make sure that a method can access all its arguments
12582 //and its return type.
12583 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
12584 TypeHandle ownerTypeForSecurity = TypeHandle(pMethodForSecurity->GetMethodTable());
12585 DynamicResolver *pAccessContext = NULL;
12586 BOOL doAccessCheck = TRUE;
12587 if (pMethodForSecurity->IsDynamicMethod())
12589 doAccessCheck = ModifyCheckForDynamicMethod(pMethodForSecurity->AsDynamicMethodDesc()->GetResolver(),
12590 &ownerTypeForSecurity,
12591 &accessCheckType, &pAccessContext);
12595 AccessCheckOptions accessCheckOptions(accessCheckType,
12597 TRUE /*Throw on error*/,
12598 pMethodForSecurity);
12600 StaticAccessCheckContext accessContext(pMethodForSecurity, ownerTypeForSecurity.GetMethodTable());
12602 // We now do an access check from pMethodForSecurity to pMethodForSecurity, its sole purpose is to
12603 // verify that pMethodForSecurity/ownerTypeForSecurity has access to all its parameters.
12605 // ownerTypeForSecurity.GetMethodTable() can be null if the pMethodForSecurity is a DynamicMethod
12606 // associated with a TypeDesc (Array, Ptr, Ref, or FnPtr). That doesn't make any sense, but we will
12607 // just do an access check from a NULL context which means only public types are accessible.
12608 if (!ClassLoader::CanAccess(&accessContext,
12609 ownerTypeForSecurity.GetMethodTable(),
12610 ownerTypeForSecurity.GetAssembly(),
12611 pMethodForSecurity->GetAttrs(),
12612 pMethodForSecurity,
12614 accessCheckOptions,
12615 TRUE /*Check method transparency*/,
12616 TRUE /*Check type transparency*/))
12618 EX_THROW(EEMethodException, (pMethodForSecurity));
12622 BOOL raiseVerificationException, unverifiableGenericCode;
12624 flags = GetCompileFlagsIfGenericInstantiation(
12628 &raiseVerificationException,
12629 &unverifiableGenericCode);
12631 if (raiseVerificationException)
12632 COMPlusThrow(kVerificationException);
12641 /* There is a double indirection to call compileMethod - can we
12642 improve this with the new structure? */
12644 #ifdef PERF_TRACK_METHOD_JITTIMES
12645 //Because we're not calling QPC enough. I'm not going to track times if we're just importing.
12646 LARGE_INTEGER methodJitTimeStart = {0};
12647 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12648 QueryPerformanceCounter (&methodJitTimeStart);
12651 #if defined(ENABLE_PERF_COUNTERS)
12655 #if defined(ENABLE_PERF_COUNTERS)
12656 LARGE_INTEGER CycleStart;
12657 QueryPerformanceCounter (&CycleStart);
12658 #endif // defined(ENABLE_PERF_COUNTERS)
12660 // Note on debuggerTrackInfo arg: if we're only importing (ie, verifying/
12661 // checking to make sure we could JIT, but not actually generating code (
12662 // eg, for inlining), then DON'T TELL THE DEBUGGER about this.
12663 res = CallCompileMethodWithSEHWrapper(jitMgr,
12670 LOG((LF_CORDB, LL_EVERYTHING, "Got through CallCompile MethodWithSEHWrapper\n"));
12672 #if FEATURE_PERFMAP
12673 // Save the code size so that it can be reported to the perfmap.
12674 if (pSizeOfCode != NULL)
12676 *pSizeOfCode = sizeOfCode;
12680 #if defined(ENABLE_PERF_COUNTERS)
12681 LARGE_INTEGER CycleStop;
12682 QueryPerformanceCounter(&CycleStop);
12683 GetPerfCounters().m_Jit.timeInJitBase = GetPerfCounters().m_Jit.timeInJit;
12684 GetPerfCounters().m_Jit.timeInJit += static_cast<DWORD>(CycleStop.QuadPart - CycleStart.QuadPart);
12685 GetPerfCounters().m_Jit.cMethodsJitted++;
12686 GetPerfCounters().m_Jit.cbILJitted+=methodInfo.ILCodeSize;
12688 #endif // defined(ENABLE_PERF_COUNTERS)
12690 #if defined(ENABLE_PERF_COUNTERS)
12694 #ifdef PERF_TRACK_METHOD_JITTIMES
12695 //store the time in the string buffer. Module name and token are unique enough. Also, do not
12696 //capture importing time, just actual compilation time.
12697 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12699 LARGE_INTEGER methodJitTimeStop;
12700 QueryPerformanceCounter(&methodJitTimeStop);
12702 ftn->GetModule()->GetDomainFile()->GetFile()->GetCodeBaseOrName(codeBase);
12703 codeBase.AppendPrintf(W(",0x%x,%d,%d\n"),
12704 //(const WCHAR *)codeBase, //module name
12705 ftn->GetMemberDef(), //method token
12706 (unsigned)(methodJitTimeStop.QuadPart - methodJitTimeStart.QuadPart), //cycle count
12707 methodInfo.ILCodeSize //il size
12709 WszOutputDebugString((const WCHAR*)codeBase);
12711 #endif // PERF_TRACK_METHOD_JITTIMES
12715 LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s %s }\n",cls,name, ftn->m_pszDebugMethodSignature));
12717 if (!SUCCEEDED(res))
12719 COUNTER_ONLY(GetPerfCounters().m_Jit.cJitFailures++);
12721 #ifndef CROSSGEN_COMPILE
12722 jitInfo.BackoutJitData(jitMgr);
12725 ThrowExceptionForJit(res);
12728 if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12730 // The method must been processed by the verifier. Note that it may
12731 // either have been marked as verifiable or unverifiable.
12732 // ie. IsVerified() does not imply IsVerifiable()
12733 _ASSERTE(ftn->IsVerified());
12740 COMPlusThrow(kInvalidProgramException);
12742 #if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE)
12743 if (jitInfo.IsRel32Overflow())
12745 // Backout and try again with fAllowRel32 == FALSE.
12746 jitInfo.BackoutJitData(jitMgr);
12748 // Disallow rel32 relocs in future.
12749 g_fAllowRel32 = FALSE;
12751 _ASSERTE(fAllowRel32 != FALSE);
12752 fAllowRel32 = FALSE;
12755 #endif // _TARGET_AMD64_ && !CROSSGEN_COMPILE
12757 LOG((LF_JIT, LL_INFO10000,
12758 "Jitted Entry at" FMT_ADDR "method %s::%s %s\n", DBG_ADDR(nativeEntry),
12759 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
12761 #if defined(FEATURE_CORESYSTEM)
12764 LPCUTF8 pszDebugClassName = ftn->m_pszDebugClassName;
12765 LPCUTF8 pszDebugMethodName = ftn->m_pszDebugMethodName;
12766 LPCUTF8 pszDebugMethodSignature = ftn->m_pszDebugMethodSignature;
12768 LPCUTF8 pszNamespace;
12769 LPCUTF8 pszDebugClassName = ftn->GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace);
12770 LPCUTF8 pszDebugMethodName = ftn->GetName();
12771 LPCUTF8 pszDebugMethodSignature = "";
12774 //DbgPrintf("Jitted Entry at" FMT_ADDR "method %s::%s %s size %08x\n", DBG_ADDR(nativeEntry),
12775 // pszDebugClassName, pszDebugMethodName, pszDebugMethodSignature, sizeOfCode);
12778 ClrFlushInstructionCache(nativeEntry, sizeOfCode);
12779 ret = (PCODE)nativeEntry;
12781 #ifdef _TARGET_ARM_
12790 FastInterlockIncrement(&g_JitCount);
12791 static BOOL fHeartbeat = -1;
12793 if (fHeartbeat == -1)
12794 fHeartbeat = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitHeartbeat);
12800 COOPERATIVE_TRANSITION_END();
12804 extern "C" unsigned __stdcall PartialNGenStressPercentage()
12806 LIMITED_METHOD_CONTRACT;
12810 static ConfigDWORD partialNGenStress;
12811 DWORD partialNGenStressVal = partialNGenStress.val(CLRConfig::INTERNAL_partialNGenStress);
12812 _ASSERTE(partialNGenStressVal <= 100);
12813 return partialNGenStressVal;
12817 #ifdef FEATURE_PREJIT
12818 /*********************************************************************/
12821 // Table loading functions
12823 void Module::LoadHelperTable()
12825 STANDARD_VM_CONTRACT;
12827 #ifndef CROSSGEN_COMPILE
12829 BYTE * table = (BYTE *) GetNativeImage()->GetNativeHelperTable(&tableSize);
12831 if (tableSize == 0)
12834 EnsureWritableExecutablePages(table, tableSize);
12836 BYTE * curEntry = table;
12837 BYTE * tableEnd = table + tableSize;
12840 int iEntryNumber = 0;
12847 while (curEntry < tableEnd)
12849 DWORD dwHelper = *(DWORD *)curEntry;
12851 int iHelper = (USHORT)dwHelper;
12852 _ASSERTE(iHelper < CORINFO_HELP_COUNT);
12854 LOG((LF_JIT, LL_INFO1000000, "JIT helper %3d (%-40s: table @ %p, size 0x%x, entry %3d @ %p, pfnHelper %p)\n",
12855 iHelper, hlpFuncTable[iHelper].name, table, tableSize, iEntryNumber, curEntry, hlpFuncTable[iHelper].pfnHelper));
12857 #if defined(ENABLE_FAST_GCPOLL_HELPER)
12858 // The fast GC poll helper works by calling indirect through a pointer that points to either
12859 // JIT_PollGC or JIT_PollGC_Nop, based on whether we need to poll or not. The JIT_PollGC_Nop
12860 // version is just a "ret". The pointer is stored in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
12861 // See EnableJitGCPoll() and DisableJitGCPoll().
12862 // In NGEN images, we generate a direct call to the helper table. Here, we replace that with
12863 // an indirect jump through the pointer in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
12864 if (iHelper == CORINFO_HELP_POLL_GC)
12866 LOG((LF_JIT, LL_INFO1000000, "JIT helper CORINFO_HELP_POLL_GC (%d); emitting indirect jump to 0x%x\n",
12867 CORINFO_HELP_POLL_GC, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper));
12869 emitJumpInd(curEntry, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper);
12870 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
12873 #endif // ENABLE_FAST_GCPOLL_HELPER
12875 PCODE pfnHelper = CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)iHelper);
12877 if (dwHelper & CORCOMPILE_HELPER_PTR)
12880 // Indirection cell
12883 *(TADDR *)curEntry = pfnHelper;
12885 curEntry = curEntry + sizeof(TADDR);
12893 #if defined(_TARGET_AMD64_)
12894 *curEntry = X86_INSTR_JMP_REL32;
12895 *(INT32 *)(curEntry + 1) = rel32UsingJumpStub((INT32 *)(curEntry + 1), pfnHelper, NULL, GetLoaderAllocator());
12896 #else // all other platforms
12897 emitJump(curEntry, (LPVOID)pfnHelper);
12898 _ASSERTE(HELPER_TABLE_ENTRY_LEN >= JUMP_ALLOCATE_SIZE);
12901 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
12905 // Note that some table entries are sizeof(TADDR) in length, and some are HELPER_TABLE_ENTRY_LEN in length
12910 ClrFlushInstructionCache(table, tableSize);
12911 #endif // CROSSGEN_COMPILE
12914 #ifdef FEATURE_READYTORUN
12915 CorInfoHelpFunc MapReadyToRunHelper(ReadyToRunHelper helperNum)
12917 LIMITED_METHOD_CONTRACT;
12921 #define HELPER(readyToRunHelper, corInfoHelpFunc, flags) \
12922 case readyToRunHelper: return corInfoHelpFunc;
12923 #include "readytorunhelpers.h"
12925 case READYTORUN_HELPER_GetString: return CORINFO_HELP_STRCNS;
12927 default: return CORINFO_HELP_UNDEF;
12931 void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap)
12933 STANDARD_VM_CONTRACT;
12935 ZeroMemory(pGCRefMap, cbGCRefMap);
12937 if (!pMT->ContainsPointers())
12940 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
12941 CGCDescSeries* cur = map->GetHighestSeries();
12942 CGCDescSeries* last = map->GetLowestSeries();
12943 DWORD size = pMT->GetBaseSize();
12944 _ASSERTE(cur >= last);
12948 // offset to embedded references in this series must be
12949 // adjusted by the VTable pointer, when in the unboxed state.
12950 size_t offset = cur->GetSeriesOffset() - sizeof(void*);
12951 size_t offsetStop = offset + cur->GetSeriesSize() + size;
12952 while (offset < offsetStop)
12954 size_t bit = offset / sizeof(void *);
12956 size_t index = bit / 8;
12957 _ASSERTE(index < cbGCRefMap);
12958 pGCRefMap[index] |= (1 << (bit & 7));
12960 offset += sizeof(void *);
12963 } while (cur >= last);
12967 // Type layout check verifies that there was no incompatible change in the value type layout.
12968 // If there was one, we will fall back to JIT instead of using the pre-generated code from the ready to run image.
12969 // This should be rare situation. Changes in value type layout not common.
12971 // The following properties of the value type layout are checked:
12973 // - HFA-ness (on platform that support HFAs)
12975 // - Position of GC references
12977 BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob)
12979 STANDARD_VM_CONTRACT;
12981 SigPointer p(pBlob);
12982 IfFailThrow(p.SkipExactlyOne());
12985 IfFailThrow(p.GetData(&dwFlags));
12987 // Size is checked unconditionally
12988 DWORD dwExpectedSize;
12989 IfFailThrow(p.GetData(&dwExpectedSize));
12991 DWORD dwActualSize = pMT->GetNumInstanceFieldBytes();
12992 if (dwExpectedSize != dwActualSize)
12996 if (dwFlags & READYTORUN_LAYOUT_HFA)
12998 DWORD dwExpectedHFAType;
12999 IfFailThrow(p.GetData(&dwExpectedHFAType));
13001 DWORD dwActualHFAType = pMT->GetHFAType();
13002 if (dwExpectedHFAType != dwActualHFAType)
13011 _ASSERTE(!(dwFlags & READYTORUN_LAYOUT_HFA));
13014 if (dwFlags & READYTORUN_LAYOUT_Alignment)
13016 DWORD dwExpectedAlignment = sizeof(void *);
13017 if (!(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
13019 IfFailThrow(p.GetData(&dwExpectedAlignment));
13022 DWORD dwActualAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
13023 if (dwExpectedAlignment != dwActualAlignment)
13028 if (dwFlags & READYTORUN_LAYOUT_GCLayout)
13030 if (dwFlags & READYTORUN_LAYOUT_GCLayout_Empty)
13032 if (pMT->ContainsPointers())
13037 size_t cbGCRefMap = (dwActualSize / sizeof(TADDR) + 7) / 8;
13038 _ASSERTE(cbGCRefMap > 0);
13040 BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
13042 ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
13044 if (memcmp(pGCRefMap, p.GetPtr(), cbGCRefMap) != 0)
13052 #endif // FEATURE_READYTORUN
13054 BOOL LoadDynamicInfoEntry(Module *currentModule,
13058 STANDARD_VM_CONTRACT;
13060 PCCOR_SIGNATURE pBlob = currentModule->GetNativeFixupBlobData(fixupRva);
13062 BYTE kind = *pBlob++;
13064 Module * pInfoModule = currentModule;
13066 if (kind & ENCODE_MODULE_OVERRIDE)
13068 pInfoModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13069 kind &= ~ENCODE_MODULE_OVERRIDE;
13072 MethodDesc * pMD = NULL;
13074 PCCOR_SIGNATURE pSig;
13083 case ENCODE_MODULE_HANDLE:
13084 result = (size_t)pInfoModule;
13087 case ENCODE_TYPE_HANDLE:
13088 case ENCODE_TYPE_DICTIONARY:
13090 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13092 if (!th.IsTypeDesc())
13094 if (currentModule->IsReadyToRun())
13096 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13097 th.AsMethodTable()->EnsureInstanceActive();
13101 #ifdef FEATURE_WINMD_RESILIENT
13102 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13103 th.AsMethodTable()->EnsureInstanceActive();
13108 result = (size_t)th.AsPtr();
13112 case ENCODE_METHOD_HANDLE:
13113 case ENCODE_METHOD_DICTIONARY:
13115 MethodDesc * pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13117 if (currentModule->IsReadyToRun())
13119 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13120 pMD->EnsureActive();
13123 result = (size_t)pMD;
13127 case ENCODE_FIELD_HANDLE:
13128 result = (size_t) ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13131 #ifndef CROSSGEN_COMPILE
13132 case ENCODE_STRING_HANDLE:
13134 // We need to update strings atomically (due to NoStringInterning attribute). Note
13135 // that modules with string interning dont really need this, as the hash tables have
13136 // their own locking, but dont add more complexity for what will be the non common
13139 // We will have to lock and update the entry. (this is really a double check, where
13140 // the first check is done in the caller of this function)
13141 DWORD rid = CorSigUncompressData(pBlob);
13145 result = (size_t)StringObject::GetEmptyStringRefPtr();
13149 CrstHolder ch(pInfoModule->GetFixupCrst());
13151 if (!CORCOMPILE_IS_POINTER_TAGGED(*entry) && (*entry != NULL))
13153 // We lost the race, just return
13157 // For generic instantiations compiled into the ngen image of some other
13158 // client assembly, we need to ensure that we intern the string
13159 // in the defining assembly.
13160 bool mayNeedToSyncWithFixups = pInfoModule != currentModule;
13162 result = (size_t) pInfoModule->ResolveStringRef(TokenFromRid(rid, mdtString), currentModule->GetDomain(), mayNeedToSyncWithFixups);
13167 case ENCODE_VARARGS_SIG:
13169 mdSignature token = TokenFromRid(
13170 CorSigUncompressData(pBlob),
13173 IfFailThrow(pInfoModule->GetMDImport()->GetSigFromToken(token, &cSig, &pSig));
13179 case ENCODE_VARARGS_METHODREF:
13181 mdSignature token = TokenFromRid(
13182 CorSigUncompressData(pBlob),
13185 LPCSTR szName_Ignore;
13186 IfFailThrow(pInfoModule->GetMDImport()->GetNameAndSigOfMemberRef(token, &pSig, &cSig, &szName_Ignore));
13192 case ENCODE_VARARGS_METHODDEF:
13194 token = TokenFromRid(
13195 CorSigUncompressData(pBlob),
13198 IfFailThrow(pInfoModule->GetMDImport()->GetSigOfMethodDef(token, &cSig, &pSig));
13201 result = (size_t) CORINFO_VARARGS_HANDLE(currentModule->GetVASigCookie(Signature(pSig, cSig)));
13205 // ENCODE_METHOD_NATIVECALLABLE_HANDLE is same as ENCODE_METHOD_ENTRY_DEF_TOKEN
13206 // except for AddrOfCode
13207 case ENCODE_METHOD_NATIVE_ENTRY:
13208 case ENCODE_METHOD_ENTRY_DEF_TOKEN:
13210 mdToken MethodDef = TokenFromRid(CorSigUncompressData(pBlob), mdtMethodDef);
13211 pMD = MemberLoader::GetMethodDescFromMethodDef(pInfoModule, MethodDef, FALSE);
13213 pMD->PrepareForUseAsADependencyOfANativeImage();
13215 if (currentModule->IsReadyToRun())
13217 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13218 pMD->EnsureActive();
13224 case ENCODE_METHOD_ENTRY_REF_TOKEN:
13226 SigTypeContext typeContext;
13227 mdToken MemberRef = TokenFromRid(CorSigUncompressData(pBlob), mdtMemberRef);
13228 FieldDesc * pFD = NULL;
13231 MemberLoader::GetDescFromMemberRef(pInfoModule, MemberRef, &pMD, &pFD, &typeContext, FALSE /* strict metadata checks */, &th);
13232 _ASSERTE(pMD != NULL);
13234 pMD->PrepareForUseAsADependencyOfANativeImage();
13236 if (currentModule->IsReadyToRun())
13238 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13239 pMD->EnsureActive();
13243 #ifdef FEATURE_WINMD_RESILIENT
13244 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13245 pMD->EnsureActive();
13252 case ENCODE_METHOD_ENTRY:
13254 pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13256 if (currentModule->IsReadyToRun())
13258 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13259 pMD->EnsureActive();
13263 if (kind == ENCODE_METHOD_NATIVE_ENTRY)
13265 result = COMDelegate::ConvertToCallback(pMD);
13269 result = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY);
13272 #ifndef _TARGET_ARM_
13273 if (CORCOMPILE_IS_PCODE_TAGGED(result))
13275 // There is a rare case where the function entrypoint may not be aligned. This could happen only for FCalls,
13276 // only on x86 and only if we failed to hardbind the fcall (e.g. ngen image for mscorlib.dll does not exist
13277 // and /nodependencies flag for ngen was used). The function entrypoints should be aligned in all other cases.
13279 // We will wrap the unaligned method entrypoint by funcptr stub with aligned entrypoint.
13280 _ASSERTE(pMD->IsFCall());
13281 result = pMD->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pMD);
13287 case ENCODE_SYNC_LOCK:
13289 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13291 result = (size_t) GetClassSync(th.AsMethodTable());
13295 case ENCODE_INDIRECT_PINVOKE_TARGET:
13297 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13299 _ASSERTE(pMethod->IsNDirect());
13300 NDirectMethodDesc *pMD = (NDirectMethodDesc*)pMethod;
13301 result = (size_t)(LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
13305 #if defined(PROFILING_SUPPORTED)
13306 case ENCODE_PROFILING_HANDLE:
13308 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13310 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
13311 // they shouldnever come here as they are called out in GetCompileFlag
13312 _ASSERTE(!pMethod->IsNoMetadata());
13314 FunctionID funId = (FunctionID)pMethod;
13316 BOOL bHookFunction = TRUE;
13317 CORINFO_PROFILING_HANDLE profilerHandle = (CORINFO_PROFILING_HANDLE)funId;
13320 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
13321 profilerHandle = (CORINFO_PROFILING_HANDLE) g_profControlBlock.pProfInterface->EEFunctionIDMapper(funId, &bHookFunction);
13322 END_PIN_PROFILER();
13325 // Profiling handle is opaque token. It does not have to be aligned thus we can not store it in the same location as token.
13326 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexClientData) = (SIZE_T)profilerHandle;
13330 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER].pfnHelper;
13331 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE].pfnHelper;
13332 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL].pfnHelper;
13336 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13337 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13338 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13342 #endif // PROFILING_SUPPORTED
13344 case ENCODE_STATIC_FIELD_ADDRESS:
13346 FieldDesc *pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13348 pField->GetEnclosingMethodTable()->CheckRestore();
13350 // We can take address of RVA field only since ngened code is domain neutral
13351 _ASSERTE(pField->IsRVA());
13353 // Field address is not aligned thus we can not store it in the same location as token.
13354 *EnsureWritablePages(entry+1) = (size_t)pField->GetStaticAddressHandle(NULL);
13358 case ENCODE_VIRTUAL_ENTRY_SLOT:
13360 DWORD slot = CorSigUncompressData(pBlob);
13362 TypeHandle ownerType = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13364 LOG((LF_ZAP, LL_INFO100000, " Fixup stub dispatch\n"));
13366 VirtualCallStubManager * pMgr = currentModule->GetLoaderAllocator()->GetVirtualCallStubManager();
13369 // We should be generating a stub indirection here, but the zapper already uses one level
13370 // of indirection, i.e. we would have to return IAT_PPVALUE to the JIT, and on the whole the JITs
13371 // aren't quite set up to accept that. Furthermore the call sequences would be different - at
13372 // the moment an indirection cell uses "call [cell-addr]" on x86, and instead we would want the
13373 // euqivalent of "call [[call-addr]]". This could perhaps be implemented as "call [eax]" </REVISIT_TODO>
13374 result = pMgr->GetCallStub(ownerType, slot);
13378 case ENCODE_CLASS_ID_FOR_STATICS:
13380 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13382 MethodTable * pMT = th.AsMethodTable();
13383 if (pMT->IsDynamicStatics())
13385 result = pMT->GetModuleDynamicEntryID();
13389 result = pMT->GetClassIndex();
13394 case ENCODE_MODULE_ID_FOR_STATICS:
13396 result = pInfoModule->GetModuleID();
13400 case ENCODE_MODULE_ID_FOR_GENERIC_STATICS:
13402 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13404 MethodTable * pMT = th.AsMethodTable();
13406 result = pMT->GetModuleForStatics()->GetModuleID();
13410 case ENCODE_ACTIVE_DEPENDENCY:
13412 Module* pModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13414 STRESS_LOG3(LF_ZAP,LL_INFO10000,"Modules are: %08x,%08x,%08x",currentModule,pInfoModule,pModule);
13415 pInfoModule->AddActiveDependency(pModule, FALSE);
13419 #ifdef FEATURE_READYTORUN
13420 case ENCODE_READYTORUN_HELPER:
13422 DWORD helperNum = CorSigUncompressData(pBlob);
13424 CorInfoHelpFunc corInfoHelpFunc = MapReadyToRunHelper((ReadyToRunHelper)helperNum);
13425 if (corInfoHelpFunc != CORINFO_HELP_UNDEF)
13427 result = (size_t)CEEJitInfo::getHelperFtnStatic(corInfoHelpFunc);
13433 case READYTORUN_HELPER_Module:
13435 Module * pPrevious = InterlockedCompareExchangeT(EnsureWritablePages((Module **)entry), pInfoModule, NULL);
13436 if (pPrevious != pInfoModule && pPrevious != NULL)
13437 COMPlusThrowHR(COR_E_FILELOAD, IDS_NATIVE_IMAGE_CANNOT_BE_LOADED_MULTIPLE_TIMES, pInfoModule->GetPath());
13442 case READYTORUN_HELPER_GSCookie:
13443 result = (size_t)GetProcessGSCookie();
13446 case READYTORUN_HELPER_DelayLoad_MethodCall:
13447 result = (size_t)GetEEFuncEntryPoint(DelayLoad_MethodCall);
13450 case READYTORUN_HELPER_DelayLoad_Helper:
13451 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper);
13454 case READYTORUN_HELPER_DelayLoad_Helper_Obj:
13455 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_Obj);
13458 case READYTORUN_HELPER_DelayLoad_Helper_ObjObj:
13459 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_ObjObj);
13463 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown READYTORUN_HELPER %d\n", helperNum);
13464 _ASSERTE(!"Unknown READYTORUN_HELPER");
13471 case ENCODE_FIELD_OFFSET:
13473 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13474 _ASSERTE(!pFD->IsStatic());
13475 _ASSERTE(!pFD->IsFieldOfValueType());
13477 DWORD dwOffset = (DWORD)sizeof(Object) + pFD->GetOffset();
13479 if (dwOffset > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13485 case ENCODE_FIELD_BASE_OFFSET:
13487 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13489 MethodTable * pMT = th.AsMethodTable();
13490 _ASSERTE(!pMT->IsValueType());
13492 DWORD dwOffsetBase = ReadyToRunInfo::GetFieldBaseOffset(pMT);
13493 if (dwOffsetBase > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13495 result = dwOffsetBase;
13499 case ENCODE_CHECK_TYPE_LAYOUT:
13501 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13502 MethodTable * pMT = th.AsMethodTable();
13503 _ASSERTE(pMT->IsValueType());
13505 if (!TypeLayoutCheck(pMT, pBlob))
13512 case ENCODE_CHECK_FIELD_OFFSET:
13514 DWORD dwExpectedOffset = CorSigUncompressData(pBlob);
13516 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13517 _ASSERTE(!pFD->IsStatic());
13519 DWORD dwOffset = pFD->GetOffset();
13520 if (!pFD->IsFieldOfValueType())
13521 dwOffset += sizeof(Object);
13523 if (dwExpectedOffset != dwOffset)
13529 #endif // FEATURE_READYTORUN
13531 #endif // CROSSGEN_COMPILE
13534 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown FIXUP_BLOB_KIND %d\n", kind);
13535 _ASSERTE(!"Unknown FIXUP_BLOB_KIND");
13540 *EnsureWritablePages(entry) = result;
13544 #endif // FEATURE_PREJIT
13546 void* CEEInfo::getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig,
13547 CorInfoHelperTailCallSpecialHandling flags)
13558 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)
13560 JIT_TO_EE_TRANSITION();
13562 Stub* pStub = CPUSTUBLINKER::CreateTailCallCopyArgsThunk(pSig, flags);
13564 ftn = (void*)pStub->GetEntryPoint();
13566 EE_TO_JIT_TRANSITION();
13568 #endif // _TARGET_AMD64_ || _TARGET_ARM_
13573 void CEEInfo::allocMem (
13574 ULONG hotCodeSize, /* IN */
13575 ULONG coldCodeSize, /* IN */
13576 ULONG roDataSize, /* IN */
13577 ULONG xcptnsCount, /* IN */
13578 CorJitAllocMemFlag flag, /* IN */
13579 void ** hotCodeBlock, /* OUT */
13580 void ** coldCodeBlock, /* OUT */
13581 void ** roDataBlock /* OUT */
13584 LIMITED_METHOD_CONTRACT;
13585 UNREACHABLE(); // only called on derived class.
13588 void CEEInfo::reserveUnwindInfo (
13589 BOOL isFunclet, /* IN */
13590 BOOL isColdCode, /* IN */
13591 ULONG unwindSize /* IN */
13594 LIMITED_METHOD_CONTRACT;
13595 UNREACHABLE(); // only called on derived class.
13598 void CEEInfo::allocUnwindInfo (
13599 BYTE * pHotCode, /* IN */
13600 BYTE * pColdCode, /* IN */
13601 ULONG startOffset, /* IN */
13602 ULONG endOffset, /* IN */
13603 ULONG unwindSize, /* IN */
13604 BYTE * pUnwindBlock, /* IN */
13605 CorJitFuncKind funcKind /* IN */
13608 LIMITED_METHOD_CONTRACT;
13609 UNREACHABLE(); // only called on derived class.
13612 void * CEEInfo::allocGCInfo (
13613 size_t size /* IN */
13616 LIMITED_METHOD_CONTRACT;
13617 UNREACHABLE_RET(); // only called on derived class.
13620 void CEEInfo::setEHcount (
13621 unsigned cEH /* IN */
13624 LIMITED_METHOD_CONTRACT;
13625 UNREACHABLE(); // only called on derived class.
13628 void CEEInfo::setEHinfo (
13629 unsigned EHnumber, /* IN */
13630 const CORINFO_EH_CLAUSE *clause /* IN */
13633 LIMITED_METHOD_CONTRACT;
13634 UNREACHABLE(); // only called on derived class.
13637 InfoAccessType CEEInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
13641 LIMITED_METHOD_CONTRACT;
13642 UNREACHABLE(); // only called on derived class.
13645 InfoAccessType CEEInfo::emptyStringLiteral(void ** ppValue)
13647 LIMITED_METHOD_CONTRACT;
13648 _ASSERTE(isVerifyOnly());
13649 *ppValue = (void *)0x10;
13653 void* CEEInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
13654 void **ppIndirection)
13656 LIMITED_METHOD_CONTRACT;
13657 _ASSERTE(isVerifyOnly());
13658 if (ppIndirection != NULL)
13659 *ppIndirection = NULL;
13660 return (void *)0x10;
13663 void* CEEInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
13664 void **ppIndirection)
13666 LIMITED_METHOD_CONTRACT;
13667 UNREACHABLE(); // only called on derived class.
13670 HRESULT CEEInfo::allocBBProfileBuffer (
13671 ULONG count, // The number of basic blocks that we have
13672 ProfileBuffer ** profileBuffer
13675 LIMITED_METHOD_CONTRACT;
13676 UNREACHABLE_RET(); // only called on derived class.
13679 HRESULT CEEInfo::getBBProfileData(
13680 CORINFO_METHOD_HANDLE ftnHnd,
13681 ULONG * count, // The number of basic blocks that we have
13682 ProfileBuffer ** profileBuffer,
13686 LIMITED_METHOD_CONTRACT;
13687 UNREACHABLE_RET(); // only called on derived class.
13691 void CEEInfo::recordCallSite(
13692 ULONG instrOffset, /* IN */
13693 CORINFO_SIG_INFO * callSig, /* IN */
13694 CORINFO_METHOD_HANDLE methodHandle /* IN */
13697 LIMITED_METHOD_CONTRACT;
13698 UNREACHABLE(); // only called on derived class.
13701 void CEEInfo::recordRelocation(
13702 void * location, /* IN */
13703 void * target, /* IN */
13704 WORD fRelocType, /* IN */
13705 WORD slotNum, /* IN */
13706 INT32 addlDelta /* IN */
13709 LIMITED_METHOD_CONTRACT;
13710 UNREACHABLE(); // only called on derived class.
13713 WORD CEEInfo::getRelocTypeHint(void * target)
13715 LIMITED_METHOD_CONTRACT;
13716 UNREACHABLE_RET(); // only called on derived class.
13719 void CEEInfo::getModuleNativeEntryPointRange(
13720 void ** pStart, /* OUT */
13721 void ** pEnd /* OUT */
13724 LIMITED_METHOD_CONTRACT;
13725 UNREACHABLE(); // only called on derived class.
13728 DWORD CEEInfo::getExpectedTargetArchitecture()
13730 LIMITED_METHOD_CONTRACT;
13732 return IMAGE_FILE_MACHINE_NATIVE;
13735 void CEEInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
13736 ICorDebugInfo::OffsetMapping *pMap)
13738 LIMITED_METHOD_CONTRACT;
13739 UNREACHABLE(); // only called on derived class.
13742 void CEEInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
13744 LIMITED_METHOD_CONTRACT;
13745 UNREACHABLE(); // only called on derived class.
13748 void* CEEInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
13749 void ** ppIndirection) /* OUT */
13751 LIMITED_METHOD_CONTRACT;
13752 UNREACHABLE(); // only called on derived class.
13755 // Active dependency helpers
13756 void CEEInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
13758 LIMITED_METHOD_CONTRACT;
13759 UNREACHABLE(); // only called on derived class.
13762 void CEEInfo::GetProfilingHandle(BOOL *pbHookFunction,
13763 void **pProfilerHandle,
13764 BOOL *pbIndirectedHandles)
13766 LIMITED_METHOD_CONTRACT;
13767 UNREACHABLE(); // only called on derived class.
13770 #endif // !DACCESS_COMPILE
13772 EECodeInfo::EECodeInfo()
13774 WRAPPER_NO_CONTRACT;
13776 m_codeAddress = NULL;
13782 #ifdef WIN64EXCEPTIONS
13783 m_pFunctionEntry = NULL;
13787 void EECodeInfo::Init(PCODE codeAddress)
13795 Init(codeAddress, ExecutionManager::GetScanFlags());
13798 void EECodeInfo::Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag)
13806 m_codeAddress = codeAddress;
13808 RangeSection * pRS = ExecutionManager::FindCodeRange(codeAddress, scanFlag);
13812 if (!pRS->pjit->JitCodeToMethodInfo(pRS, codeAddress, &m_pMD, this))
13823 #ifdef WIN64EXCEPTIONS
13824 m_pFunctionEntry = NULL;
13828 TADDR EECodeInfo::GetSavedMethodCode()
13831 // All EECodeInfo methods must be NOTHROW/GC_NOTRIGGER since they can
13832 // be used during GC.
13839 #if defined(HAVE_GCCOVER)
13840 _ASSERTE (!m_pMD->m_GcCover || GCStress<cfg_instr>::IsEnabled());
13841 if (GCStress<cfg_instr>::IsEnabled()
13842 && m_pMD->m_GcCover)
13844 _ASSERTE(m_pMD->m_GcCover->savedCode);
13846 // Make sure we return the TADDR of savedCode here. The byte array is not marshaled automatically.
13847 // The caller is responsible for any necessary marshaling.
13848 return PTR_TO_MEMBER_TADDR(GCCoverageInfo, m_pMD->m_GcCover, savedCode);
13850 #endif //defined(HAVE_GCCOVER)
13853 return GetStartAddress();
13856 TADDR EECodeInfo::GetStartAddress()
13865 return m_pJM->JitTokenToStartAddress(m_methodToken);
13868 #if defined(WIN64EXCEPTIONS)
13870 // ----------------------------------------------------------------------------
13871 // EECodeInfo::GetMainFunctionInfo
13874 // Simple helper to transform a funclet's EECodeInfo into a parent function EECodeInfo.
13877 // An EECodeInfo for the start of the main function body (offset 0).
13880 EECodeInfo EECodeInfo::GetMainFunctionInfo()
13882 LIMITED_METHOD_CONTRACT;
13885 EECodeInfo result = *this;
13886 result.m_relOffset = 0;
13887 result.m_codeAddress = this->GetStartAddress();
13888 result.m_pFunctionEntry = NULL;
13893 PTR_RUNTIME_FUNCTION EECodeInfo::GetFunctionEntry()
13895 LIMITED_METHOD_CONTRACT;
13898 if (m_pFunctionEntry == NULL)
13899 m_pFunctionEntry = m_pJM->LazyGetFunctionEntry(this);
13900 return m_pFunctionEntry;
13903 #if defined(_TARGET_AMD64_)
13905 BOOL EECodeInfo::HasFrameRegister()
13907 LIMITED_METHOD_CONTRACT;
13909 PTR_RUNTIME_FUNCTION pFuncEntry = GetFunctionEntry();
13910 _ASSERTE(pFuncEntry != NULL);
13912 BOOL fHasFrameRegister = FALSE;
13913 PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(GetModuleBase() + pFuncEntry->UnwindData);
13914 if (pUnwindInfo->FrameRegister != 0)
13916 fHasFrameRegister = TRUE;
13917 _ASSERTE(pUnwindInfo->FrameRegister == kRBP);
13920 return fHasFrameRegister;
13922 #endif // defined(_TARGET_AMD64_)
13924 #endif // defined(WIN64EXCEPTIONS)
13927 #if defined(_TARGET_AMD64_)
13928 // ----------------------------------------------------------------------------
13929 // EECodeInfo::GetUnwindInfoHelper
13932 // Simple helper to return a pointer to the UNWIND_INFO given the offset to the unwind info.
13933 // On DAC builds, this function will read the memory from the target process and create a host copy.
13936 // * unwindInfoOffset - This is the offset to the unwind info, relative to the beginning of the code heap
13937 // for jitted code or to the module base for ngned code. this->GetModuleBase() will return the correct
13941 // Return a pointer to the UNWIND_INFO. On DAC builds, this function will create a host copy of the
13942 // UNWIND_INFO and return a host pointer. It will correctly read all of the memory for the variable-sized
13946 UNWIND_INFO * EECodeInfo::GetUnwindInfoHelper(ULONG unwindInfoOffset)
13948 #if defined(DACCESS_COMPILE)
13949 return DacGetUnwindInfo(static_cast<TADDR>(this->GetModuleBase() + unwindInfoOffset));
13950 #else // !DACCESS_COMPILE
13951 return reinterpret_cast<UNWIND_INFO *>(this->GetModuleBase() + unwindInfoOffset);
13952 #endif // !DACCESS_COMPILE
13955 // ----------------------------------------------------------------------------
13956 // EECodeInfo::GetFixedStackSize
13959 // Return the fixed stack size of a specified managed method. This function DOES NOT take current control
13960 // PC into account. So the fixed stack size returned by this function is not valid in the prolog or
13964 // Return the fixed stack size.
13967 // * For method with dynamic stack allocations, this function will return the fixed stack size on X64 (the
13968 // stack size immediately after the prolog), and it will return 0 on IA64. This difference is due to
13969 // the different unwind info encoding.
13972 ULONG EECodeInfo::GetFixedStackSize()
13974 WRAPPER_NO_CONTRACT;
13977 ULONG uFixedStackSize = 0;
13980 GetOffsetsFromUnwindInfo(&uFixedStackSize, &uDummy);
13982 return uFixedStackSize;
13986 // The information returned by this method is only valid if we are not in a prolog or an epilog.
13987 // Since this method is only used for the security stackwalk cache, this assumption is valid, since
13988 // we cannot make a call in a prolog or an epilog.
13990 // The next assumption is that only rbp is used as a frame register in jitted code. There is an
13991 // assert below to guard this assumption.
13992 void EECodeInfo::GetOffsetsFromUnwindInfo(ULONG* pRSPOffset, ULONG* pRBPOffset)
13994 LIMITED_METHOD_CONTRACT;
13997 _ASSERTE((pRSPOffset != NULL) && (pRBPOffset != NULL));
13999 // moduleBase is a target address.
14000 TADDR moduleBase = GetModuleBase();
14002 DWORD unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(GetFunctionEntry());
14004 if ((unwindInfo & RUNTIME_FUNCTION_INDIRECT) != 0)
14006 unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(PTR_RUNTIME_FUNCTION(moduleBase + (unwindInfo & ~RUNTIME_FUNCTION_INDIRECT)));
14009 UNWIND_INFO * pInfo = GetUnwindInfoHelper(unwindInfo);
14010 if (pInfo->Flags & UNW_FLAG_CHAININFO)
14012 _ASSERTE(!"GetRbpOffset() - chained unwind info used, violating assumptions of the security stackwalk cache");
14016 // Either we are not using a frame pointer, or we are using rbp as the frame pointer.
14017 if ( (pInfo->FrameRegister != 0) && (pInfo->FrameRegister != kRBP) )
14019 _ASSERTE(!"GetRbpOffset() - non-RBP frame pointer used, violating assumptions of the security stackwalk cache");
14023 // Walk the unwind info.
14024 ULONG StackOffset = 0;
14025 ULONG StackSize = 0;
14026 for (int i = 0; i < pInfo->CountOfUnwindCodes; i++)
14028 ULONG UnwindOp = pInfo->UnwindCode[i].UnwindOp;
14029 ULONG OpInfo = pInfo->UnwindCode[i].OpInfo;
14031 if (UnwindOp == UWOP_SAVE_NONVOL)
14033 if (OpInfo == kRBP)
14035 StackOffset = pInfo->UnwindCode[i+1].FrameOffset * 8;
14038 else if (UnwindOp == UWOP_SAVE_NONVOL_FAR)
14040 if (OpInfo == kRBP)
14042 StackOffset = pInfo->UnwindCode[i + 1].FrameOffset;
14043 StackOffset += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14046 else if (UnwindOp == UWOP_ALLOC_SMALL)
14048 StackSize += (OpInfo * 8) + 8;
14050 else if (UnwindOp == UWOP_ALLOC_LARGE)
14052 ULONG IncrementalStackSize = pInfo->UnwindCode[i + 1].FrameOffset;
14055 IncrementalStackSize *= 8;
14059 IncrementalStackSize += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14061 // This is a special opcode. We need to increment the index by 1 in addition to the normal adjustments.
14064 StackSize += IncrementalStackSize;
14066 else if (UnwindOp == UWOP_PUSH_NONVOL)
14068 // Because of constraints on epilogs, this unwind opcode is always last in the unwind code array.
14069 // This means that StackSize has been initialized already when we first see this unwind opcode.
14070 // Note that the intial value of StackSize does not include the stack space used for pushes.
14071 // Thus, here we only need to increment StackSize 8 bytes at a time until we see the unwind code for "push rbp".
14072 if (OpInfo == kRBP)
14074 StackOffset = StackSize;
14080 // Adjust the index into the unwind code array.
14081 i += UnwindOpExtraSlotTable[UnwindOp];
14084 *pRSPOffset = StackSize + 8; // add 8 for the return address
14085 *pRBPOffset = StackOffset;
14090 #if defined(_DEBUG) && defined(HAVE_GCCOVER)
14092 LPVOID EECodeInfo::findNextFunclet (LPVOID pvFuncletStart, SIZE_T cbCode, LPVOID *ppvFuncletEnd)
14101 PT_RUNTIME_FUNCTION pFunctionEntry;
14102 ULONGLONG uImageBase;
14104 EECodeInfo codeInfo;
14105 codeInfo.Init((PCODE)pvFuncletStart);
14106 pFunctionEntry = codeInfo.GetFunctionEntry();
14107 uImageBase = (ULONGLONG)codeInfo.GetModuleBase();
14108 #else // !FEATURE_PAL
14110 // This is GCStress debug only - use the slow OS APIs to enumerate funclets
14113 pFunctionEntry = (PT_RUNTIME_FUNCTION) RtlLookupFunctionEntry((ULONGLONG)pvFuncletStart,
14119 if (pFunctionEntry != NULL)
14121 #ifdef FEATURE_PREJIT
14122 // workaround: Check for indirect entry that is generated for cold part of main method body.
14123 if ((TADDR)pvFuncletStart < (TADDR)uImageBase + pFunctionEntry->BeginAddress ||
14124 (TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart)
14126 Module * pZapModule = ExecutionManager::FindZapModule((TADDR)pvFuncletStart);
14127 NGenLayoutInfo * pLayoutInfo = pZapModule->GetNGenLayoutInfo();
14129 int ColdFunctionIndex = NativeUnwindInfoLookupTable::LookupUnwindInfoForMethod((DWORD)((TADDR)pvFuncletStart - uImageBase),
14130 pLayoutInfo->m_pRuntimeFunctions[2],
14131 0, pLayoutInfo->m_nRuntimeFunctions[2] - 1);
14133 pFunctionEntry = pLayoutInfo->m_pRuntimeFunctions[2] + ColdFunctionIndex;
14137 _ASSERTE((TADDR)pvFuncletStart == (TADDR)uImageBase + pFunctionEntry->BeginAddress);
14138 _ASSERTE((TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart + cbCode);
14139 *ppvFuncletEnd = (LPVOID)(uImageBase + pFunctionEntry->EndAddress);
14140 return (LPVOID)(uImageBase + pFunctionEntry->BeginAddress);
14143 pvFuncletStart = (LPVOID)((TADDR)pvFuncletStart + 1);
14149 #endif // defined(_DEBUG) && !defined(HAVE_GCCOVER)
14150 #endif // defined(_TARGET_AMD64_)