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)
8598 JIT_TO_EE_TRANSITION_LEAF();
8600 MethodDesc* method = GetMethod(methodHnd);
8602 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8603 _ASSERTE(!method->HasMethodInstantiation());
8605 _ASSERTE(MethodTable::GetVtableOffset() < 256); // a rough sanity check
8607 // better be in the vtable
8608 _ASSERTE(method->GetSlot() < method->GetMethodTable()->GetNumVirtuals());
8610 *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * sizeof(PTR_PCODE);
8611 *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * sizeof(PCODE);
8613 EE_TO_JIT_TRANSITION_LEAF();
8616 /*********************************************************************/
8617 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethodHelper(CORINFO_METHOD_HANDLE baseMethod,
8618 CORINFO_CLASS_HANDLE derivedClass,
8619 CORINFO_CONTEXT_HANDLE ownerType)
8627 MethodDesc* pBaseMD = GetMethod(baseMethod);
8628 MethodTable* pBaseMT = pBaseMD->GetMethodTable();
8630 // Method better be from a fully loaded class
8631 _ASSERTE(pBaseMD->IsRestored() && pBaseMT->IsFullyLoaded());
8633 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8634 _ASSERTE(!pBaseMD->HasMethodInstantiation());
8636 // Method better be virtual
8637 _ASSERTE(pBaseMD->IsVirtual());
8639 MethodDesc* pDevirtMD = nullptr;
8641 TypeHandle DerivedClsHnd(derivedClass);
8642 MethodTable* pDerivedMT = DerivedClsHnd.GetMethodTable();
8643 _ASSERTE(pDerivedMT->IsRestored() && pDerivedMT->IsFullyLoaded());
8645 // Can't devirtualize from __Canon.
8646 if (DerivedClsHnd == TypeHandle(g_pCanonMethodTableClass))
8651 if (pBaseMT->IsInterface())
8654 #ifdef FEATURE_COMINTEROP
8655 // Don't try and devirtualize com interface calls.
8656 if (pDerivedMT->IsComObjectType())
8660 #endif // FEATURE_COMINTEROP
8662 // Interface call devirtualization.
8664 // We must ensure that pDerivedMT actually implements the
8665 // interface corresponding to pBaseMD.
8666 if (!pDerivedMT->CanCastToInterface(pBaseMT))
8671 // For generic interface methods we must have an ownerType to
8672 // safely devirtualize.
8673 if (ownerType != nullptr)
8675 TypeHandle OwnerClsHnd = GetTypeFromContext(ownerType);
8676 MethodTable* pOwnerMT = OwnerClsHnd.GetMethodTable();
8678 // If the derived class is a shared class, make sure the
8679 // owner class is too.
8680 if (pDerivedMT->IsSharedByGenericInstantiations())
8682 pOwnerMT = pOwnerMT->GetCanonicalMethodTable();
8685 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(TypeHandle(pOwnerMT), pBaseMD);
8687 else if (!pBaseMD->HasClassOrMethodInstantiation())
8689 pDevirtMD = pDerivedMT->GetMethodDescForInterfaceMethod(pBaseMD);
8698 // Virtual call devirtualization.
8700 // The derived class should be a subclass of the the base class.
8701 MethodTable* pCheckMT = pDerivedMT;
8703 while (pCheckMT != nullptr)
8705 if (pCheckMT->HasSameTypeDefAs(pBaseMT))
8710 pCheckMT = pCheckMT->GetParentMethodTable();
8713 if (pCheckMT == nullptr)
8718 // The base method should be in the base vtable
8719 WORD slot = pBaseMD->GetSlot();
8720 _ASSERTE(slot < pBaseMT->GetNumVirtuals());
8722 // Fetch the method that would be invoked if the class were
8723 // exactly derived class. It is up to the jit to determine whether
8724 // directly calling this method is correct.
8725 pDevirtMD = pDerivedMT->GetMethodDescForSlot(slot);
8728 _ASSERTE(pDevirtMD->IsRestored());
8730 #ifdef FEATURE_READYTORUN_COMPILER
8731 // Check if devirtualization is dependent upon cross-version
8732 // bubble information and if so, disallow it.
8733 if (IsReadyToRunCompilation())
8735 MethodDesc* callerMethod = m_pMethodBeingCompiled;
8736 Assembly* pCallerAssembly = callerMethod->GetModule()->GetAssembly();
8738 IsInSameVersionBubble(pCallerAssembly , pDevirtMD->GetModule()->GetAssembly())
8739 && IsInSameVersionBubble(pCallerAssembly , pDerivedMT->GetAssembly());
8748 return (CORINFO_METHOD_HANDLE) pDevirtMD;
8751 CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethod(CORINFO_METHOD_HANDLE methodHnd,
8752 CORINFO_CLASS_HANDLE derivedClass,
8753 CORINFO_CONTEXT_HANDLE ownerType)
8762 CORINFO_METHOD_HANDLE result = nullptr;
8764 JIT_TO_EE_TRANSITION();
8766 result = resolveVirtualMethodHelper(methodHnd, derivedClass, ownerType);
8768 EE_TO_JIT_TRANSITION();
8773 void CEEInfo::expandRawHandleIntrinsic(
8774 CORINFO_RESOLVED_TOKEN * pResolvedToken,
8775 CORINFO_GENERICHANDLE_RESULT * pResult)
8777 LIMITED_METHOD_CONTRACT;
8778 UNREACHABLE(); // only called with CoreRT.
8781 /*********************************************************************/
8782 void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd,
8783 CORINFO_CONST_LOOKUP * pResult,
8784 CORINFO_ACCESS_FLAGS accessFlags)
8794 InfoAccessType accessType = IAT_VALUE;
8796 JIT_TO_EE_TRANSITION();
8798 MethodDesc * ftn = GetMethod(ftnHnd);
8799 #if defined(FEATURE_GDBJIT)
8800 MethodDesc * orig_ftn = ftn;
8803 // Resolve methodImpl.
8804 ftn = ftn->GetMethodTable()->MapMethodDeclToMethodImpl(ftn);
8806 ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags);
8808 // TryGetMultiCallableAddrOfCode returns NULL if indirect access is desired
8811 // should never get here for EnC methods or if interception via remoting stub is required
8812 _ASSERTE(!ftn->IsEnCMethod());
8814 _ASSERTE((accessFlags & CORINFO_ACCESS_THIS) || !ftn->IsRemotingInterceptedViaVirtualDispatch());
8816 ret = ftn->GetAddrOfSlot();
8817 accessType = IAT_PVALUE;
8821 #if defined(FEATURE_GDBJIT)
8822 CalledMethod * pCM = new CalledMethod(orig_ftn, ret, m_pCalledMethods);
8823 m_pCalledMethods = pCM;
8826 EE_TO_JIT_TRANSITION();
8828 _ASSERTE(ret != NULL);
8830 pResult->accessType = accessType;
8831 pResult->addr = ret;
8834 /*********************************************************************/
8835 void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn,
8836 CORINFO_CONST_LOOKUP * pResult)
8845 JIT_TO_EE_TRANSITION();
8847 MethodDesc * pMD = GetMethod(ftn);
8849 pResult->accessType = IAT_VALUE;
8852 #ifndef CROSSGEN_COMPILE
8853 // If LDFTN target has [NativeCallable] attribute , then create a UMEntryThunk.
8854 if (pMD->HasNativeCallableAttribute())
8856 pResult->addr = (void*)COMDelegate::ConvertToCallback(pMD);
8859 #endif //CROSSGEN_COMPILE
8861 pResult->addr = (void *)pMD->GetMultiCallableAddrOfCode();
8863 EE_TO_JIT_TRANSITION();
8866 /*********************************************************************/
8867 const char* CEEInfo::getFieldName (CORINFO_FIELD_HANDLE fieldHnd, const char** scopeName)
8876 const char* result = NULL;
8878 JIT_TO_EE_TRANSITION();
8880 FieldDesc* field = (FieldDesc*) fieldHnd;
8883 TypeHandle t = TypeHandle(field->GetApproxEnclosingMethodTable());
8888 t.GetName(ssClsNameBuff);
8889 *scopeName = ssClsNameBuff.GetUTF8(ssClsNameBuffScratch);
8891 // since this is for diagnostic purposes only,
8892 // give up on the namespace, as we don't have a buffer to concat it
8893 // also note this won't show array class names.
8895 *scopeName= t.GetMethodTable()->GetFullyQualifiedNameInfo(&nameSpace);
8900 result = field->GetName();
8902 EE_TO_JIT_TRANSITION();
8907 /*********************************************************************/
8908 // Get the type that declares the field
8909 CORINFO_CLASS_HANDLE CEEInfo::getFieldClass (CORINFO_FIELD_HANDLE fieldHnd)
8918 CORINFO_CLASS_HANDLE result = NULL;
8920 JIT_TO_EE_TRANSITION_LEAF();
8922 FieldDesc* field = (FieldDesc*) fieldHnd;
8923 result = CORINFO_CLASS_HANDLE(field->GetApproxEnclosingMethodTable());
8925 EE_TO_JIT_TRANSITION_LEAF();
8930 /*********************************************************************/
8931 // Returns the basic type of the field (not the the type that declares the field)
8933 // pTypeHnd - On return, for reference and value types, *pTypeHnd will contain
8934 // the normalized type of the field.
8935 // owner - Optional. For resolving in a generic context
8937 CorInfoType CEEInfo::getFieldType (CORINFO_FIELD_HANDLE fieldHnd,
8938 CORINFO_CLASS_HANDLE* pTypeHnd,
8939 CORINFO_CLASS_HANDLE owner)
8948 CorInfoType result = CORINFO_TYPE_UNDEF;
8950 JIT_TO_EE_TRANSITION();
8952 result = getFieldTypeInternal(fieldHnd, pTypeHnd, owner);
8954 EE_TO_JIT_TRANSITION();
8959 /*********************************************************************/
8960 CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd,
8961 CORINFO_CLASS_HANDLE* pTypeHnd,
8962 CORINFO_CLASS_HANDLE owner)
8964 STANDARD_VM_CONTRACT;
8968 TypeHandle clsHnd = TypeHandle();
8969 FieldDesc* field = (FieldDesc*) fieldHnd;
8970 CorElementType type = field->GetFieldType();
8972 // <REVISIT_TODO>TODO should not burn the time to do this for anything but Value Classes</REVISIT_TODO>
8973 _ASSERTE(type != ELEMENT_TYPE_BYREF);
8975 if (type == ELEMENT_TYPE_I)
8977 PTR_MethodTable enclosingMethodTable = field->GetApproxEnclosingMethodTable();
8978 if (enclosingMethodTable->IsByRefLike() && enclosingMethodTable->HasSameTypeDefAs(g_pByReferenceClass))
8980 _ASSERTE(field->GetOffset() == 0);
8981 return CORINFO_TYPE_BYREF;
8985 if (!CorTypeInfo::IsPrimitiveType(type))
8987 PCCOR_SIGNATURE sig;
8989 CorCallingConvention conv;
8991 field->GetSig(&sig, &sigCount);
8993 conv = (CorCallingConvention)CorSigUncompressCallingConv(sig);
8994 _ASSERTE(isCallConv(conv, IMAGE_CEE_CS_CALLCONV_FIELD));
8996 SigPointer ptr(sig, sigCount);
8998 // For verifying code involving generics, use the class instantiation
8999 // of the optional owner (to provide exact, not representative,
9000 // type information)
9001 SigTypeContext typeContext(field, (TypeHandle)owner);
9003 clsHnd = ptr.GetTypeHandleThrowing(field->GetModule(), &typeContext);
9004 _ASSERTE(!clsHnd.IsNull());
9006 // I believe it doesn't make any diff. if this is GetInternalCorElementType
9007 // or GetSignatureCorElementType.
9008 type = clsHnd.GetSignatureCorElementType();
9011 return CEEInfo::asCorInfoType(type, clsHnd, pTypeHnd);
9014 /*********************************************************************/
9015 unsigned CEEInfo::getFieldOffset (CORINFO_FIELD_HANDLE fieldHnd)
9024 unsigned result = (unsigned) -1;
9026 JIT_TO_EE_TRANSITION();
9028 FieldDesc* field = (FieldDesc*) fieldHnd;
9030 // GetOffset() does not include the size of Object
9031 result = field->GetOffset();
9033 // So if it is not a value class, add the Object into it
9034 if (field->IsStatic())
9036 Module* pModule = field->GetModule();
9037 if (field->IsRVA() && pModule->IsRvaFieldTls(field->GetOffset()))
9039 result = pModule->GetFieldTlsOffset(field->GetOffset());
9042 else if (!field->GetApproxEnclosingMethodTable()->IsValueType())
9044 result += sizeof(Object);
9047 EE_TO_JIT_TRANSITION();
9052 /*********************************************************************/
9053 bool CEEInfo::isWriteBarrierHelperRequired(CORINFO_FIELD_HANDLE field)
9062 bool fHelperRequired = false;
9064 JIT_TO_EE_TRANSITION();
9066 FieldDesc * pField = (FieldDesc *)field;
9068 // TODO: jit64 should be switched to the same plan as the i386 jits - use
9069 // getClassGClayout to figure out the need for writebarrier helper, and inline the copying.
9070 // Once this happens, USE_WRITE_BARRIER_HELPERS and CORINFO_FLG_WRITE_BARRIER_HELPER can be removed.
9071 CorElementType type = pField->GetFieldType();
9073 if(CorTypeInfo::IsObjRef(type))
9074 fHelperRequired = true;
9075 else if (type == ELEMENT_TYPE_VALUETYPE)
9077 TypeHandle th = pField->GetFieldTypeHandleThrowing();
9078 _ASSERTE(!th.IsNull());
9079 if(th.GetMethodTable()->ContainsPointers())
9080 fHelperRequired = true;
9083 EE_TO_JIT_TRANSITION();
9085 return fHelperRequired;
9088 /*********************************************************************/
9089 DWORD CEEInfo::getFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE fieldHnd, void **ppIndirection)
9100 if (ppIndirection != NULL)
9101 *ppIndirection = NULL;
9103 JIT_TO_EE_TRANSITION();
9105 FieldDesc* field = (FieldDesc*) fieldHnd;
9106 Module* module = field->GetModule();
9108 _ASSERTE(field->IsRVA()); // Only RVA statics can be thread local
9109 _ASSERTE(module->IsRvaFieldTls(field->GetOffset()));
9111 result = module->GetTlsIndex();
9113 EE_TO_JIT_TRANSITION();
9118 void *CEEInfo::allocateArray(ULONG cBytes)
9127 void * result = NULL;
9129 JIT_TO_EE_TRANSITION();
9131 result = new BYTE [cBytes];
9133 EE_TO_JIT_TRANSITION();
9138 void CEEInfo::freeArray(void *array)
9147 JIT_TO_EE_TRANSITION();
9149 delete [] ((BYTE*) array);
9151 EE_TO_JIT_TRANSITION();
9154 void CEEInfo::getBoundaries(CORINFO_METHOD_HANDLE ftn,
9155 unsigned int *cILOffsets, DWORD **pILOffsets,
9156 ICorDebugInfo::BoundaryTypes *implicitBoundaries)
9165 JIT_TO_EE_TRANSITION();
9167 #ifdef DEBUGGING_SUPPORTED
9168 if (g_pDebugInterface && !IsCompilationProcess())
9170 g_pDebugInterface->getBoundaries(GetMethod(ftn), cILOffsets, pILOffsets,
9171 implicitBoundaries);
9177 *implicitBoundaries = ICorDebugInfo::DEFAULT_BOUNDARIES;
9179 #endif // DEBUGGING_SUPPORTED
9181 EE_TO_JIT_TRANSITION();
9184 void CEEInfo::getVars(CORINFO_METHOD_HANDLE ftn, ULONG32 *cVars, ICorDebugInfo::ILVarInfo **vars,
9194 JIT_TO_EE_TRANSITION();
9196 #ifdef DEBUGGING_SUPPORTED
9197 if (g_pDebugInterface && !IsCompilationProcess())
9199 g_pDebugInterface->getVars(GetMethod(ftn), cVars, vars, extendOthers);
9206 // Just tell the JIT to extend everything.
9207 *extendOthers = true;
9209 #endif // DEBUGGING_SUPPORTED
9211 EE_TO_JIT_TRANSITION();
9214 /*********************************************************************/
9215 CORINFO_ARG_LIST_HANDLE CEEInfo::getArgNext(CORINFO_ARG_LIST_HANDLE args)
9224 CORINFO_ARG_LIST_HANDLE result = NULL;
9226 JIT_TO_EE_TRANSITION();
9228 SigPointer ptr((unsigned __int8*) args);
9229 IfFailThrow(ptr.SkipExactlyOne());
9231 result = (CORINFO_ARG_LIST_HANDLE) ptr.GetPtr();
9233 EE_TO_JIT_TRANSITION();
9239 /*********************************************************************/
9241 CorInfoTypeWithMod CEEInfo::getArgType (
9242 CORINFO_SIG_INFO* sig,
9243 CORINFO_ARG_LIST_HANDLE args,
9244 CORINFO_CLASS_HANDLE* vcTypeRet
9254 CorInfoTypeWithMod result = CorInfoTypeWithMod(CORINFO_TYPE_UNDEF);
9256 JIT_TO_EE_TRANSITION();
9258 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args && (BYTE*) args < (BYTE*) sig->pSig + sig->cbSig);
9259 _ASSERTE((BYTE*) sig->args <= (BYTE*) args);
9260 INDEBUG(*vcTypeRet = CORINFO_CLASS_HANDLE((size_t)INVALID_POINTER_CC));
9262 SigPointer ptr((unsigned __int8*) args);
9263 CorElementType eType;
9264 IfFailThrow(ptr.PeekElemType(&eType));
9265 while (eType == ELEMENT_TYPE_PINNED)
9267 result = CORINFO_TYPE_MOD_PINNED;
9268 IfFailThrow(ptr.GetElemType(NULL));
9269 IfFailThrow(ptr.PeekElemType(&eType));
9272 // Now read off the "real" element type after taking any instantiations into consideration
9273 SigTypeContext typeContext;
9274 GetTypeContext(&sig->sigInst,&typeContext);
9276 Module* pModule = GetModule(sig->scope);
9278 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9280 TypeHandle typeHnd = TypeHandle();
9282 case ELEMENT_TYPE_VAR :
9283 case ELEMENT_TYPE_MVAR :
9284 case ELEMENT_TYPE_VALUETYPE :
9285 case ELEMENT_TYPE_TYPEDBYREF :
9286 case ELEMENT_TYPE_INTERNAL :
9288 typeHnd = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9289 _ASSERTE(!typeHnd.IsNull());
9291 CorElementType normType = typeHnd.GetInternalCorElementType();
9293 // if we are looking up a value class, don't morph it to a refernece type
9294 // (This can only happen in illegal IL)
9295 if (!CorTypeInfo::IsObjRef(normType) || type != ELEMENT_TYPE_VALUETYPE)
9302 case ELEMENT_TYPE_PTR:
9303 // Load the type eagerly under debugger to make the eval work
9304 if (!isVerifyOnly() && CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
9306 // NOTE: in some IJW cases, when the type pointed at is unmanaged,
9307 // the GetTypeHandle may fail, because there is no TypeDef for such type.
9308 // Usage of GetTypeHandleThrowing would lead to class load exception
9309 TypeHandle thPtr = ptr.GetTypeHandleNT(pModule, &typeContext);
9312 m_pOverride->classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(thPtr.AsPtr()));
9317 case ELEMENT_TYPE_VOID:
9318 // void is not valid in local sigs
9319 if (sig->flags & CORINFO_SIGFLAG_IS_LOCAL_SIG)
9320 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
9323 case ELEMENT_TYPE_END:
9324 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9331 result = CorInfoTypeWithMod(result | CEEInfo::asCorInfoType(type, typeHnd, vcTypeRet));
9332 EE_TO_JIT_TRANSITION();
9337 /*********************************************************************/
9339 CORINFO_CLASS_HANDLE CEEInfo::getArgClass (
9340 CORINFO_SIG_INFO* sig,
9341 CORINFO_ARG_LIST_HANDLE args
9351 CORINFO_CLASS_HANDLE result = NULL;
9353 JIT_TO_EE_TRANSITION();
9355 // make certain we dont have a completely wacked out sig pointer
9356 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args);
9357 _ASSERTE((BYTE*) sig->args <= (BYTE*) args && (BYTE*) args < &((BYTE*) sig->args)[0x10000*5]);
9359 Module* pModule = GetModule(sig->scope);
9361 SigPointer ptr((unsigned __int8*) args);
9363 CorElementType eType;
9364 IfFailThrow(ptr.PeekElemType(&eType));
9366 while (eType == ELEMENT_TYPE_PINNED)
9368 IfFailThrow(ptr.GetElemType(NULL));
9369 IfFailThrow(ptr.PeekElemType(&eType));
9371 // Now read off the "real" element type after taking any instantiations into consideration
9372 SigTypeContext typeContext;
9373 GetTypeContext(&sig->sigInst, &typeContext);
9374 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9376 if (!CorTypeInfo::IsPrimitiveType(type)) {
9377 TypeHandle th = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9378 result = CORINFO_CLASS_HANDLE(th.AsPtr());
9381 EE_TO_JIT_TRANSITION();
9386 /*********************************************************************/
9388 CorInfoType CEEInfo::getHFAType(CORINFO_CLASS_HANDLE hClass)
9397 CorInfoType result = CORINFO_TYPE_UNDEF;
9400 JIT_TO_EE_TRANSITION();
9402 TypeHandle VMClsHnd(hClass);
9404 result = asCorInfoType(VMClsHnd.GetHFAType());
9406 EE_TO_JIT_TRANSITION();
9412 /*********************************************************************/
9414 // return the unmanaged calling convention for a PInvoke
9415 CorInfoUnmanagedCallConv CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method)
9424 CorInfoUnmanagedCallConv result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9426 JIT_TO_EE_TRANSITION();
9428 MethodDesc* pMD = NULL;
9429 pMD = GetMethod(method);
9430 _ASSERTE(pMD->IsNDirect());
9435 PInvokeStaticSigInfo sigInfo(pMD, PInvokeStaticSigInfo::NO_THROW_ON_ERROR);
9437 switch (sigInfo.GetCallConv()) {
9438 case pmCallConvCdecl:
9439 result = CORINFO_UNMANAGED_CALLCONV_C;
9441 case pmCallConvStdcall:
9442 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9444 case pmCallConvThiscall:
9445 result = CORINFO_UNMANAGED_CALLCONV_THISCALL;
9448 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9453 result = CORINFO_UNMANAGED_CALLCONV_UNKNOWN;
9455 EX_END_CATCH(SwallowAllExceptions)
9456 #else // !_TARGET_X86_
9458 // we have only one calling convention
9460 result = CORINFO_UNMANAGED_CALLCONV_STDCALL;
9461 #endif // !_TARGET_X86_
9463 EE_TO_JIT_TRANSITION();
9468 /*********************************************************************/
9469 BOOL NDirectMethodDesc::ComputeMarshalingRequired()
9471 WRAPPER_NO_CONTRACT;
9473 return NDirect::MarshalingRequired(this);
9476 /*********************************************************************/
9477 BOOL CEEInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig)
9486 BOOL result = FALSE;
9488 JIT_TO_EE_TRANSITION();
9492 MethodDesc* ftn = GetMethod(method);
9493 _ASSERTE(ftn->IsNDirect());
9494 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9496 #if defined(HAS_NDIRECT_IMPORT_PRECODE)
9497 if (pMD->IsVarArg())
9499 // Varag P/Invoke must not be inlined because its NDirectMethodDesc
9500 // does not contain a meaningful stack size (it is call site specific).
9501 // See code:InlinedCallFrame.UpdateRegDisplay where this is needed.
9504 else if (pMD->MarshalingRequired())
9506 // This is not a no-marshal signature.
9511 // This is a no-marshal non-vararg signature.
9515 // Marshalling is required to lazy initialize the indirection cell
9516 // without NDirectImportPrecode.
9522 // check the call site signature
9523 result = NDirect::MarshalingRequired(
9526 GetModule(callSiteSig->scope));
9529 EE_TO_JIT_TRANSITION();
9534 /*********************************************************************/
9535 // Generate a cookie based on the signature that would needs to be passed
9536 // to CORINFO_HELP_PINVOKE_CALLI
9537 LPVOID CEEInfo::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig,
9538 void **ppIndirection)
9540 WRAPPER_NO_CONTRACT;
9542 return getVarArgsHandle(szMetaSig, ppIndirection);
9545 bool CEEInfo::canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig)
9547 LIMITED_METHOD_CONTRACT;
9552 // Check any constraints on method type arguments
9553 BOOL CEEInfo::satisfiesMethodConstraints(
9554 CORINFO_CLASS_HANDLE parent,
9555 CORINFO_METHOD_HANDLE method)
9564 BOOL result = FALSE;
9566 JIT_TO_EE_TRANSITION();
9568 _ASSERTE(parent != NULL);
9569 _ASSERTE(method != NULL);
9570 result = GetMethod(method)->SatisfiesMethodConstraints(TypeHandle(parent));
9572 EE_TO_JIT_TRANSITION();
9579 /*********************************************************************/
9580 // Given a delegate target class, a target method parent class, a target method,
9581 // a delegate class, check if the method signature is compatible with the Invoke method of the delegate
9582 // (under the typical instantiation of any free type variables in the memberref signatures).
9584 // objCls should be NULL if the target object is NULL
9585 //@GENERICSVER: new (suitable for generics)
9586 BOOL CEEInfo::isCompatibleDelegate(
9587 CORINFO_CLASS_HANDLE objCls,
9588 CORINFO_CLASS_HANDLE methodParentCls,
9589 CORINFO_METHOD_HANDLE method,
9590 CORINFO_CLASS_HANDLE delegateCls,
9591 BOOL* pfIsOpenDelegate)
9600 BOOL result = FALSE;
9602 JIT_TO_EE_TRANSITION();
9604 _ASSERTE(method != NULL);
9605 _ASSERTE(delegateCls != NULL);
9607 TypeHandle delegateClsHnd = (TypeHandle) delegateCls;
9609 _ASSERTE(delegateClsHnd.GetMethodTable()->IsDelegate());
9611 TypeHandle methodParentHnd = (TypeHandle) (methodParentCls);
9612 MethodDesc* pMDFtn = GetMethod(method);
9613 TypeHandle objClsHnd(objCls);
9617 result = COMDelegate::ValidateCtor(objClsHnd, methodParentHnd, pMDFtn, delegateClsHnd, pfIsOpenDelegate);
9622 EX_END_CATCH(SwallowAllExceptions)
9624 EE_TO_JIT_TRANSITION();
9629 /*********************************************************************/
9630 // return the unmanaged target *if method has already been prelinked.*
9631 void* CEEInfo::getPInvokeUnmanagedTarget(CORINFO_METHOD_HANDLE method,
9632 void **ppIndirection)
9641 void* result = NULL;
9643 if (ppIndirection != NULL)
9644 *ppIndirection = NULL;
9646 #ifndef CROSSGEN_COMPILE
9647 JIT_TO_EE_TRANSITION();
9649 MethodDesc* ftn = GetMethod(method);
9650 _ASSERTE(ftn->IsNDirect());
9651 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9653 if (pMD->NDirectTargetIsImportThunk())
9658 result = pMD->GetNDirectTarget();
9661 EE_TO_JIT_TRANSITION();
9662 #endif // CROSSGEN_COMPILE
9667 /*********************************************************************/
9668 // return address of fixup area for late-bound N/Direct calls.
9669 void* CEEInfo::getAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE method,
9670 void **ppIndirection)
9679 void * result = NULL;
9681 if (ppIndirection != NULL)
9682 *ppIndirection = NULL;
9684 JIT_TO_EE_TRANSITION_LEAF();
9686 MethodDesc* ftn = GetMethod(method);
9687 _ASSERTE(ftn->IsNDirect());
9688 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9690 result = (LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
9692 EE_TO_JIT_TRANSITION_LEAF();
9697 /*********************************************************************/
9698 // return address of fixup area for late-bound N/Direct calls.
9699 void CEEInfo::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method,
9700 CORINFO_CONST_LOOKUP *pLookup)
9702 WRAPPER_NO_CONTRACT;
9705 pLookup->accessType = IAT_PVALUE;
9706 pLookup->addr = getAddressOfPInvokeFixup(method, &pIndirection);
9707 _ASSERTE(pIndirection == NULL);
9710 /*********************************************************************/
9711 CORINFO_JUST_MY_CODE_HANDLE CEEInfo::getJustMyCodeHandle(
9712 CORINFO_METHOD_HANDLE method,
9713 CORINFO_JUST_MY_CODE_HANDLE**ppIndirection)
9722 CORINFO_JUST_MY_CODE_HANDLE result = NULL;
9725 *ppIndirection = NULL;
9727 JIT_TO_EE_TRANSITION_LEAF();
9729 // Get the flag from the debugger.
9730 MethodDesc* ftn = GetMethod(method);
9731 DWORD * pFlagAddr = NULL;
9733 if (g_pDebugInterface)
9735 pFlagAddr = g_pDebugInterface->GetJMCFlagAddr(ftn->GetModule());
9738 result = (CORINFO_JUST_MY_CODE_HANDLE) pFlagAddr;
9740 EE_TO_JIT_TRANSITION_LEAF();
9745 /*********************************************************************/
9746 void InlinedCallFrame::GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo *pInfo)
9748 LIMITED_METHOD_CONTRACT;
9750 pInfo->size = sizeof(GSCookie) + sizeof(InlinedCallFrame);
9752 pInfo->offsetOfGSCookie = 0;
9753 pInfo->offsetOfFrameVptr = sizeof(GSCookie);
9754 pInfo->offsetOfFrameLink = sizeof(GSCookie) + Frame::GetOffsetOfNextLink();
9755 pInfo->offsetOfCallSiteSP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallSiteSP);
9756 pInfo->offsetOfCalleeSavedFP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCalleeSavedFP);
9757 pInfo->offsetOfCallTarget = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_Datum);
9758 pInfo->offsetOfReturnAddress = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallerReturnAddress);
9761 /*********************************************************************/
9762 // Return details about EE internal data structures
9763 void CEEInfo::getEEInfo(CORINFO_EE_INFO *pEEInfoOut)
9772 INDEBUG(memset(pEEInfoOut, 0xCC, sizeof(*pEEInfoOut)));
9774 JIT_TO_EE_TRANSITION();
9776 InlinedCallFrame::GetEEInfo(&pEEInfoOut->inlinedCallFrameInfo);
9778 // Offsets into the Thread structure
9779 pEEInfoOut->offsetOfThreadFrame = Thread::GetOffsetOfCurrentFrame();
9780 pEEInfoOut->offsetOfGCState = Thread::GetOffsetOfGCFlag();
9783 pEEInfoOut->offsetOfDelegateInstance = DelegateObject::GetOffsetOfTarget();
9784 pEEInfoOut->offsetOfDelegateFirstTarget = DelegateObject::GetOffsetOfMethodPtr();
9786 // Secure delegate offsets
9787 pEEInfoOut->offsetOfSecureDelegateIndirectCell = DelegateObject::GetOffsetOfMethodPtrAux();
9790 pEEInfoOut->offsetOfTransparentProxyRP = TransparentProxyObject::GetOffsetOfRP();
9791 pEEInfoOut->offsetOfRealProxyServer = RealProxyObject::GetOffsetOfServerObject();
9793 pEEInfoOut->offsetOfObjArrayData = (DWORD)PtrArray::GetDataOffset();
9795 pEEInfoOut->sizeOfReversePInvokeFrame = (DWORD)-1;
9797 pEEInfoOut->osPageSize = GetOsPageSize();
9798 pEEInfoOut->maxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
9799 pEEInfoOut->targetAbi = CORINFO_CORECLR_ABI;
9801 pEEInfoOut->osType = CORINFO_WINNT;
9803 // hardcode OS version to 0.0.0. These fields can be removed from JITEE interface
9804 pEEInfoOut->osMajor = 0;
9805 pEEInfoOut->osMinor = 0;
9806 pEEInfoOut->osBuild = 0;
9808 EE_TO_JIT_TRANSITION();
9811 LPCWSTR CEEInfo::getJitTimeLogFilename()
9820 LPCWSTR result = NULL;
9822 JIT_TO_EE_TRANSITION();
9823 result = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitTimeLogFile);
9824 EE_TO_JIT_TRANSITION();
9831 // Return details about EE internal data structures
9832 DWORD CEEInfo::getThreadTLSIndex(void **ppIndirection)
9841 DWORD result = (DWORD)-1;
9843 if (ppIndirection != NULL)
9844 *ppIndirection = NULL;
9846 JIT_TO_EE_TRANSITION();
9848 #if !defined(CROSSGEN_COMPILE) && !defined(FEATURE_IMPLICIT_TLS)
9849 result = GetThreadTLSIndex();
9851 // The JIT can use the optimized TLS access only if the runtime is using it as well.
9852 // (This is necessaryto make managed code work well under appverifier.)
9853 if (GetTLSAccessMode(result) == TLSACCESS_GENERIC)
9857 EE_TO_JIT_TRANSITION();
9862 const void * CEEInfo::getInlinedCallFrameVptr(void **ppIndirection)
9871 void * result = NULL;
9873 if (ppIndirection != NULL)
9874 *ppIndirection = NULL;
9876 JIT_TO_EE_TRANSITION_LEAF();
9878 #ifndef CROSSGEN_COMPILE
9879 result = (void*)InlinedCallFrame::GetMethodFrameVPtr();
9881 result = (void*)0x43210;
9884 EE_TO_JIT_TRANSITION_LEAF();
9889 LONG * CEEInfo::getAddrOfCaptureThreadGlobal(void **ppIndirection)
9898 LONG * result = NULL;
9900 if (ppIndirection != NULL)
9901 *ppIndirection = NULL;
9903 JIT_TO_EE_TRANSITION_LEAF();
9905 result = (LONG *)&g_TrapReturningThreads;
9907 EE_TO_JIT_TRANSITION_LEAF();
9914 HRESULT CEEInfo::GetErrorHRESULT(struct _EXCEPTION_POINTERS *pExceptionPointers)
9925 //This function is called from the JIT64 exception filter during PEVerify. Because it is a filter, it
9926 //can be "called" from a NOTHROW region in the case of StackOverflow. Security::MapToHR throws
9927 //internally, but it catches all exceptions. Therefore, none of the children can cause an exception to
9928 //percolate out of this function (except for Stack Overflow). Obviously I can't explain most of this to
9929 //the Contracts system, and I can't add this CONTRACT_VIOLATION to the filter in Jit64.
9930 CONTRACT_VIOLATION(ThrowsViolation);
9932 JIT_TO_EE_TRANSITION();
9936 OBJECTREF throwable = GetThread()->LastThrownObject();
9937 hr = GetExceptionHResult(throwable);
9939 EE_TO_JIT_TRANSITION();
9945 ULONG CEEInfo::GetErrorMessage(__inout_ecount(bufferLength) LPWSTR buffer, ULONG bufferLength)
9956 #ifndef CROSSGEN_COMPILE
9957 JIT_TO_EE_TRANSITION();
9961 OBJECTREF throwable = GetThread()->LastThrownObject();
9963 if (throwable != NULL)
9967 result = GetExceptionMessage(throwable, buffer, bufferLength);
9972 EX_END_CATCH(SwallowAllExceptions)
9975 EE_TO_JIT_TRANSITION();
9981 // This method is called from CEEInfo::FilterException which
9982 // is run as part of the SEH filter clause for the JIT.
9983 // It is fatal to throw an exception while running a SEH filter clause
9984 // so our contract is NOTHROW, NOTRIGGER.
9986 LONG EEFilterException(struct _EXCEPTION_POINTERS *pExceptionPointers, void *unused)
9996 JIT_TO_EE_TRANSITION_LEAF();
9998 VALIDATE_BACKOUT_STACK_CONSUMPTION;
10000 unsigned code = pExceptionPointers->ExceptionRecord->ExceptionCode;
10003 if (code == EXCEPTION_ACCESS_VIOLATION)
10005 static int hit = 0;
10008 _ASSERTE(!"Access violation while Jitting!");
10009 // If you set the debugger to catch access violations and 'go'
10010 // you will get back to the point at which the access violation occurred
10011 result = EXCEPTION_CONTINUE_EXECUTION;
10015 result = EXCEPTION_CONTINUE_SEARCH;
10020 // No one should be catching breakpoint
10021 // Similarly the JIT doesn't know how to reset the guard page, so it shouldn't
10022 // be catching a hard stack overflow
10023 if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP || code == EXCEPTION_STACK_OVERFLOW)
10025 result = EXCEPTION_CONTINUE_SEARCH;
10027 #ifdef CROSSGEN_COMPILE
10030 result = EXCEPTION_EXECUTE_HANDLER;
10033 else if (!IsComPlusException(pExceptionPointers->ExceptionRecord))
10035 result = EXCEPTION_EXECUTE_HANDLER;
10041 // This is actually the LastThrown exception object.
10042 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10044 if (throwable != NULL)
10048 OBJECTREF oLastThrownObject;
10051 ZeroMemory(&_gc, sizeof(_gc));
10053 // Setup the throwables
10054 _gc.oLastThrownObject = throwable;
10056 GCPROTECT_BEGIN(_gc);
10058 // Don't catch ThreadAbort and other uncatchable exceptions
10059 if (IsUncatchable(&_gc.oLastThrownObject))
10060 result = EXCEPTION_CONTINUE_SEARCH;
10062 result = EXCEPTION_EXECUTE_HANDLER;
10069 EE_TO_JIT_TRANSITION_LEAF();
10074 int CEEInfo::FilterException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10076 WRAPPER_NO_CONTRACT;
10077 return EEFilterException(pExceptionPointers, nullptr);
10080 // This code is called if FilterException chose to handle the exception.
10081 void CEEInfo::HandleException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10089 JIT_TO_EE_TRANSITION_LEAF();
10091 #ifndef CROSSGEN_COMPILE
10092 if (IsComPlusException(pExceptionPointers->ExceptionRecord))
10096 // This is actually the LastThrown exception object.
10097 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10099 if (throwable != NULL)
10103 OBJECTREF oLastThrownObject;
10104 OBJECTREF oCurrentThrowable;
10107 ZeroMemory(&_gc, sizeof(_gc));
10109 PTR_Thread pCurThread = GetThread();
10111 // Setup the throwables
10112 _gc.oLastThrownObject = throwable;
10114 // This will be NULL if no managed exception is active. Otherwise,
10115 // it will reference the active throwable.
10116 _gc.oCurrentThrowable = pCurThread->GetThrowable();
10118 GCPROTECT_BEGIN(_gc);
10120 // JIT does not use or reference managed exceptions at all and simply swallows them,
10121 // or lets them fly through so that they will either get caught in managed code, the VM
10122 // or will go unhandled.
10124 // Blind swallowing of managed exceptions can break the semantic of "which exception handler"
10125 // gets to process the managed exception first. The expected handler is managed code exception
10126 // handler (e.g. COMPlusFrameHandler on x86 and ProcessCLRException on 64bit) which will setup
10127 // the exception tracker for the exception that will enable the expected sync between the
10128 // LastThrownObject (LTO), setup in RaiseTheExceptionInternalOnly, and the exception tracker.
10130 // However, JIT can break this by swallowing the managed exception before managed code exception
10131 // handler gets a chance to setup an exception tracker for it. Since there is no cleanup
10132 // done for the swallowed exception as part of the unwind (because no exception tracker may have been setup),
10133 // we need to reset the LTO, if it is out of sync from the active throwable.
10135 // Hence, check if the LastThrownObject and active-exception throwable are in sync or not.
10136 // If not, bring them in sync.
10140 // It is possible that an exception was already in progress and while processing it (e.g.
10141 // invoking finally block), we invoked JIT that had another managed exception @ JIT-EE transition boundary
10142 // that is swallowed by the JIT before managed code exception handler sees it. This breaks the sync between
10143 // LTO and the active exception in the exception tracker.
10144 if (_gc.oCurrentThrowable != _gc.oLastThrownObject)
10148 // Note: Incase of OOM, this will get set to OOM instance.
10149 pCurThread->SafeSetLastThrownObject(_gc.oCurrentThrowable);
10157 EE_TO_JIT_TRANSITION_LEAF();
10160 void ThrowExceptionForJit(HRESULT res);
10162 void CEEInfo::ThrowExceptionForJitResult(
10172 JIT_TO_EE_TRANSITION();
10174 if (!SUCCEEDED(result))
10175 ThrowExceptionForJit(result);
10177 EE_TO_JIT_TRANSITION();
10181 CORINFO_MODULE_HANDLE CEEInfo::embedModuleHandle(CORINFO_MODULE_HANDLE handle,
10182 void **ppIndirection)
10189 PRECONDITION(!IsDynamicScope(handle));
10193 if (ppIndirection != NULL)
10194 *ppIndirection = NULL;
10196 JIT_TO_EE_TRANSITION_LEAF();
10198 EE_TO_JIT_TRANSITION_LEAF();
10203 CORINFO_CLASS_HANDLE CEEInfo::embedClassHandle(CORINFO_CLASS_HANDLE handle,
10204 void **ppIndirection)
10214 if (ppIndirection != NULL)
10215 *ppIndirection = NULL;
10217 JIT_TO_EE_TRANSITION_LEAF();
10219 EE_TO_JIT_TRANSITION_LEAF();
10224 CORINFO_FIELD_HANDLE CEEInfo::embedFieldHandle(CORINFO_FIELD_HANDLE handle,
10225 void **ppIndirection)
10235 if (ppIndirection != NULL)
10236 *ppIndirection = NULL;
10238 JIT_TO_EE_TRANSITION_LEAF();
10240 EE_TO_JIT_TRANSITION_LEAF();
10245 CORINFO_METHOD_HANDLE CEEInfo::embedMethodHandle(CORINFO_METHOD_HANDLE handle,
10246 void **ppIndirection)
10256 if (ppIndirection != NULL)
10257 *ppIndirection = NULL;
10259 JIT_TO_EE_TRANSITION_LEAF();
10261 EE_TO_JIT_TRANSITION_LEAF();
10266 /*********************************************************************/
10267 void CEEInfo::setJitFlags(const CORJIT_FLAGS& jitFlags)
10269 LIMITED_METHOD_CONTRACT;
10271 m_jitFlags = jitFlags;
10274 /*********************************************************************/
10275 DWORD CEEInfo::getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes)
10284 JIT_TO_EE_TRANSITION_LEAF();
10286 _ASSERTE(sizeInBytes >= sizeof(m_jitFlags));
10287 *jitFlags = m_jitFlags;
10289 EE_TO_JIT_TRANSITION_LEAF();
10291 return sizeof(m_jitFlags);
10294 /*********************************************************************/
10295 #if !defined(PLATFORM_UNIX)
10297 struct RunWithErrorTrapFilterParam
10299 ICorDynamicInfo* m_corInfo;
10300 void (*m_function)(void*);
10302 EXCEPTION_POINTERS m_exceptionPointers;
10305 static LONG RunWithErrorTrapFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
10307 WRAPPER_NO_CONTRACT;
10309 auto* param = reinterpret_cast<RunWithErrorTrapFilterParam*>(theParam);
10310 param->m_exceptionPointers = *exceptionPointers;
10311 return param->m_corInfo->FilterException(exceptionPointers);
10314 #endif // !defined(PLATFORM_UNIX)
10316 bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param)
10318 // No dynamic contract here because SEH is used
10319 STATIC_CONTRACT_THROWS;
10320 STATIC_CONTRACT_GC_TRIGGERS;
10321 STATIC_CONTRACT_SO_TOLERANT;
10322 STATIC_CONTRACT_MODE_PREEMPTIVE;
10324 // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
10325 // transitions into the EE proper should occur either via the call to
10326 // `EEFilterException` (which is appropraitely marked) or via JIT/EE
10327 // interface calls made by `function`.
10329 bool success = true;
10331 #if !defined(PLATFORM_UNIX)
10333 RunWithErrorTrapFilterParam trapParam;
10334 trapParam.m_corInfo = m_pOverride == nullptr ? this : m_pOverride;
10335 trapParam.m_function = function;
10336 trapParam.m_param = param;
10338 PAL_TRY(RunWithErrorTrapFilterParam*, pTrapParam, &trapParam)
10340 pTrapParam->m_function(pTrapParam->m_param);
10342 PAL_EXCEPT_FILTER(RunWithErrorTrapFilter)
10344 HandleException(&trapParam.m_exceptionPointers);
10349 #else // !defined(PLATFORM_UNIX)
10351 // We shouldn't need PAL_TRY on *nix: any exceptions that we are able to catch
10352 // ought to originate from the runtime itself and should be catchable inside of
10353 // EX_TRY/EX_CATCH, including emulated SEH exceptions.
10362 EX_END_CATCH(RethrowTerminalExceptions);
10369 /*********************************************************************/
10370 IEEMemoryManager* CEEInfo::getMemoryManager()
10379 IEEMemoryManager* result = NULL;
10381 JIT_TO_EE_TRANSITION_LEAF();
10383 result = GetEEMemoryManager();
10385 EE_TO_JIT_TRANSITION_LEAF();
10390 /*********************************************************************/
10391 int CEEInfo::doAssert(const char* szFile, int iLine, const char* szExpr)
10393 STATIC_CONTRACT_SO_TOLERANT;
10394 STATIC_CONTRACT_THROWS;
10395 STATIC_CONTRACT_GC_TRIGGERS;
10396 STATIC_CONTRACT_MODE_PREEMPTIVE;
10397 STATIC_CONTRACT_DEBUG_ONLY;
10401 JIT_TO_EE_TRANSITION();
10403 #ifdef CROSSGEN_COMPILE
10404 ThrowHR(COR_E_INVALIDPROGRAM);
10408 BEGIN_DEBUG_ONLY_CODE;
10409 result = _DbgBreakCheck(szFile, iLine, szExpr);
10410 END_DEBUG_ONLY_CODE;
10412 result = 1; // break into debugger
10417 EE_TO_JIT_TRANSITION();
10422 void CEEInfo::reportFatalError(CorJitResult result)
10424 STATIC_CONTRACT_SO_TOLERANT;
10425 STATIC_CONTRACT_THROWS;
10426 STATIC_CONTRACT_GC_TRIGGERS;
10427 STATIC_CONTRACT_MODE_PREEMPTIVE;
10429 JIT_TO_EE_TRANSITION_LEAF();
10431 STRESS_LOG2(LF_JIT,LL_ERROR, "Jit reported error 0x%x while compiling 0x%p\n",
10432 (int)result, (INT_PTR)getMethodBeingCompiled());
10434 EE_TO_JIT_TRANSITION_LEAF();
10437 BOOL CEEInfo::logMsg(unsigned level, const char* fmt, va_list args)
10439 STATIC_CONTRACT_SO_TOLERANT;
10440 STATIC_CONTRACT_THROWS;
10441 STATIC_CONTRACT_GC_TRIGGERS;
10442 STATIC_CONTRACT_MODE_PREEMPTIVE;
10443 STATIC_CONTRACT_DEBUG_ONLY;
10445 BOOL result = FALSE;
10447 JIT_TO_EE_TRANSITION_LEAF();
10450 if (LoggingOn(LF_JIT, level))
10452 LogSpewValist(LF_JIT, level, (char*) fmt, args);
10457 EE_TO_JIT_TRANSITION_LEAF();
10462 void CEEInfo::yieldExecution()
10464 WRAPPER_NO_CONTRACT;
10468 #ifndef CROSSGEN_COMPILE
10470 /*********************************************************************/
10472 void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
10473 void ** ppIndirection) /* OUT */
10482 void* result = NULL;
10484 if (ppIndirection != NULL)
10485 *ppIndirection = NULL;
10487 JIT_TO_EE_TRANSITION_LEAF();
10489 _ASSERTE(ftnNum < CORINFO_HELP_COUNT);
10491 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10493 size_t dynamicFtnNum = ((size_t)pfnHelper - 1);
10494 if (dynamicFtnNum < DYNAMIC_CORINFO_HELP_COUNT)
10497 #pragma warning(push)
10498 #pragma warning(disable:26001) // "Bounds checked above using the underflow trick"
10499 #endif /*_PREFAST_ */
10501 #if defined(_TARGET_AMD64_)
10502 // To avoid using a jump stub we always call certain helpers using an indirect call.
10503 // Because when using a direct call and the target is father away than 2^31 bytes,
10504 // the direct call instead goes to a jump stub which jumps to the jit helper.
10505 // However in this process the jump stub will corrupt RAX.
10507 // The set of helpers for which RAX must be preserved are the profiler probes
10508 // and the STOP_FOR_GC helper which maps to JIT_RareDisableHelper.
10509 // In the case of the STOP_FOR_GC helper RAX can be holding a function return value.
10511 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_STOP_FOR_GC ||
10512 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER ||
10513 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE ||
10514 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL)
10516 _ASSERTE(ppIndirection != NULL);
10517 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10522 #if defined(ENABLE_FAST_GCPOLL_HELPER)
10523 //always call this indirectly so that we can swap GC Poll helpers.
10524 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_POLL_GC)
10526 _ASSERTE(ppIndirection != NULL);
10527 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10532 pfnHelper = hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10535 #pragma warning(pop)
10536 #endif /*_PREFAST_*/
10539 _ASSERTE(pfnHelper);
10541 result = (LPVOID)GetEEFuncEntryPoint(pfnHelper);
10543 EE_TO_JIT_TRANSITION_LEAF();
10548 PCODE CEEJitInfo::getHelperFtnStatic(CorInfoHelpFunc ftnNum)
10550 LIMITED_METHOD_CONTRACT;
10552 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10554 // If pfnHelper is an index into the dynamic helper table, it should be less
10555 // than DYNAMIC_CORINFO_HELP_COUNT. In this case we need to find the actual pfnHelper
10556 // using an extra indirection. Note the special case
10557 // where pfnHelper==0 where pfnHelper-1 will underflow and we will avoid the indirection.
10558 if (((size_t)pfnHelper - 1) < DYNAMIC_CORINFO_HELP_COUNT)
10560 pfnHelper = hlpDynamicFuncTable[((size_t)pfnHelper - 1)].pfnHelper;
10563 _ASSERTE(pfnHelper != NULL);
10565 return GetEEFuncEntryPoint(pfnHelper);
10568 void CEEJitInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
10573 PRECONDITION(CheckPointer(moduleFrom));
10574 PRECONDITION(!IsDynamicScope(moduleFrom));
10575 PRECONDITION(CheckPointer(moduleTo));
10576 PRECONDITION(!IsDynamicScope(moduleTo));
10577 PRECONDITION(moduleFrom != moduleTo);
10581 // This is only called internaly. JIT-EE transition is not needed.
10582 // JIT_TO_EE_TRANSITION();
10584 Module *dependency = (Module *)moduleTo;
10585 _ASSERTE(!dependency->IsSystem());
10587 if (m_pMethodBeingCompiled->IsLCGMethod())
10589 // The context module of the m_pMethodBeingCompiled is irrelevant. Rather than tracking
10590 // the dependency, we just do immediate activation.
10591 dependency->EnsureActive();
10595 #ifdef FEATURE_LOADER_OPTIMIZATION
10596 Module *context = (Module *)moduleFrom;
10598 // Record active dependency for loader.
10599 context->AddActiveDependency(dependency, FALSE);
10601 dependency->EnsureActive();
10605 // EE_TO_JIT_TRANSITION();
10609 // Wrapper around CEEInfo::GetProfilingHandle. The first time this is called for a
10610 // method desc, it calls through to EEToProfInterfaceImpl::EEFunctionIDMappe and caches the
10611 // result in CEEJitInfo::GetProfilingHandleCache. Thereafter, this wrapper regurgitates the cached values
10612 // rather than calling into CEEInfo::GetProfilingHandle each time. This avoids
10613 // making duplicate calls into the profiler's FunctionIDMapper callback.
10614 void CEEJitInfo::GetProfilingHandle(BOOL *pbHookFunction,
10615 void **pProfilerHandle,
10616 BOOL *pbIndirectedHandles)
10625 _ASSERTE(pbHookFunction != NULL);
10626 _ASSERTE(pProfilerHandle != NULL);
10627 _ASSERTE(pbIndirectedHandles != NULL);
10629 if (!m_gphCache.m_bGphIsCacheValid)
10631 #ifdef PROFILING_SUPPORTED
10632 JIT_TO_EE_TRANSITION();
10634 // Cache not filled in, so make our first and only call to CEEInfo::GetProfilingHandle here
10636 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
10637 // they shouldnever come here as they are called out in GetCompileFlag
10638 _ASSERTE(!m_pMethodBeingCompiled->IsNoMetadata());
10640 // We pass in the typical method definition to the function mapper because in
10641 // Whidbey all the profiling API transactions are done in terms of typical
10642 // method definitions not instantiations.
10643 BOOL bHookFunction = TRUE;
10644 void * profilerHandle = m_pMethodBeingCompiled;
10647 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
10648 profilerHandle = (void *)g_profControlBlock.pProfInterface->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction);
10649 END_PIN_PROFILER();
10652 m_gphCache.m_pvGphProfilerHandle = profilerHandle;
10653 m_gphCache.m_bGphHookFunction = (bHookFunction != FALSE);
10654 m_gphCache.m_bGphIsCacheValid = true;
10656 EE_TO_JIT_TRANSITION();
10657 #endif //PROFILING_SUPPORTED
10660 // Our cache of these values are bitfield bools, but the interface requires
10661 // BOOL. So to avoid setting aside a staging area on the stack for these
10662 // values, we filled them in directly in the if (not cached yet) case.
10663 *pbHookFunction = (m_gphCache.m_bGphHookFunction != false);
10665 // At this point, the remaining values must be in the cache by now, so use them
10666 *pProfilerHandle = m_gphCache.m_pvGphProfilerHandle;
10669 // This is the JIT case, which is never indirected.
10671 *pbIndirectedHandles = FALSE;
10674 /*********************************************************************/
10675 void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr)
10682 CodeHeader* pCodeHeader = GetCodeHeader();
10684 jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len);
10687 /*********************************************************************/
10688 // Route jit information to the Jit Debug store.
10689 void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
10690 ICorDebugInfo::OffsetMapping *pMap)
10699 JIT_TO_EE_TRANSITION();
10701 // We receive ownership of the array
10702 _ASSERTE(m_pOffsetMapping == NULL && m_iOffsetMapping == 0);
10703 m_iOffsetMapping = cMap;
10704 m_pOffsetMapping = pMap;
10706 EE_TO_JIT_TRANSITION();
10709 void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
10718 JIT_TO_EE_TRANSITION();
10720 // We receive ownership of the array
10721 _ASSERTE(m_pNativeVarInfo == NULL && m_iNativeVarInfo == 0);
10722 m_iNativeVarInfo = cVars;
10723 m_pNativeVarInfo = vars;
10725 EE_TO_JIT_TRANSITION();
10728 void CEEJitInfo::CompressDebugInfo()
10737 // Don't track JIT info for DynamicMethods.
10738 if (m_pMethodBeingCompiled->IsDynamicMethod())
10741 if (m_iOffsetMapping == 0 && m_iNativeVarInfo == 0)
10744 JIT_TO_EE_TRANSITION();
10748 PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars(
10749 m_pOffsetMapping, m_iOffsetMapping,
10750 m_pNativeVarInfo, m_iNativeVarInfo,
10752 m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap());
10754 GetCodeHeader()->SetDebugInfo(pDebugInfo);
10758 // Just ignore exceptions here. The debugger's structures will still be in a consistent state.
10760 EX_END_CATCH(SwallowAllExceptions)
10762 EE_TO_JIT_TRANSITION();
10765 void reservePersonalityRoutineSpace(ULONG &unwindSize)
10767 #if defined(_TARGET_X86_)
10769 #elif defined(_TARGET_AMD64_)
10770 // Add space for personality routine, it must be 4-byte aligned.
10771 // Everything in the UNWIND_INFO up to the variable-sized UnwindCodes
10772 // array has already had its size included in unwindSize by the caller.
10773 unwindSize += sizeof(ULONG);
10775 // Note that the count of unwind codes (2 bytes each) is stored as a UBYTE
10776 // So the largest size could be 510 bytes, plus the header and language
10777 // specific stuff. This can't overflow.
10779 _ASSERTE(FitsInU4(unwindSize + sizeof(ULONG)));
10780 unwindSize = (ULONG)(ALIGN_UP(unwindSize, sizeof(ULONG)));
10781 #elif defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
10782 // The JIT passes in a 4-byte aligned block of unwind data.
10783 _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
10785 // Add space for personality routine, it must be 4-byte aligned.
10786 unwindSize += sizeof(ULONG);
10788 PORTABILITY_ASSERT("reservePersonalityRoutineSpace");
10789 #endif // !defined(_TARGET_AMD64_)
10792 // Reserve memory for the method/funclet's unwind information.
10793 // Note that this must be called before allocMem. It should be
10794 // called once for the main method, once for every funclet, and
10795 // once for every block of cold code for which allocUnwindInfo
10798 // This is necessary because jitted code must allocate all the
10799 // memory needed for the unwindInfo at the allocMem call.
10800 // For prejitted code we split up the unwinding information into
10801 // separate sections .rdata and .pdata.
10803 void CEEJitInfo::reserveUnwindInfo(BOOL isFunclet, BOOL isColdCode, ULONG unwindSize)
10805 #ifdef WIN64EXCEPTIONS
10814 JIT_TO_EE_TRANSITION_LEAF();
10816 CONSISTENCY_CHECK_MSG(!isColdCode, "Hot/Cold splitting is not supported in jitted code");
10817 _ASSERTE_MSG(m_theUnwindBlock == NULL,
10818 "reserveUnwindInfo() can only be called before allocMem(), but allocMem() has already been called. "
10819 "This may indicate the JIT has hit a NO_WAY assert after calling allocMem(), and is re-JITting. "
10820 "Set COMPlus_JitBreakOnBadCode=1 and rerun to get the real error.");
10822 ULONG currentSize = unwindSize;
10824 reservePersonalityRoutineSpace(currentSize);
10826 m_totalUnwindSize += currentSize;
10828 m_totalUnwindInfos++;
10830 EE_TO_JIT_TRANSITION_LEAF();
10831 #else // WIN64EXCEPTIONS
10832 LIMITED_METHOD_CONTRACT;
10833 // Dummy implementation to make cross-platform altjit work
10834 #endif // WIN64EXCEPTIONS
10837 // Allocate and initialize the .rdata and .pdata for this method or
10838 // funclet and get the block of memory needed for the machine specific
10839 // unwind information (the info for crawling the stack frame).
10840 // Note that allocMem must be called first.
10842 // The pHotCode parameter points at the first byte of the code of the method
10843 // The startOffset and endOffset are the region (main or funclet) that
10844 // we are to allocate and create .rdata and .pdata for.
10845 // The pUnwindBlock is copied and contains the .pdata unwind area
10849 // pHotCode main method code buffer, always filled in
10850 // pColdCode always NULL for jitted code
10851 // startOffset start of code block, relative to pHotCode
10852 // endOffset end of code block, relative to pHotCode
10853 // unwindSize size of unwind info pointed to by pUnwindBlock
10854 // pUnwindBlock pointer to unwind info
10855 // funcKind type of funclet (main method code, handler, filter)
10857 void CEEJitInfo::allocUnwindInfo (
10858 BYTE * pHotCode, /* IN */
10859 BYTE * pColdCode, /* IN */
10860 ULONG startOffset, /* IN */
10861 ULONG endOffset, /* IN */
10862 ULONG unwindSize, /* IN */
10863 BYTE * pUnwindBlock, /* IN */
10864 CorJitFuncKind funcKind /* IN */
10867 #ifdef WIN64EXCEPTIONS
10873 PRECONDITION(m_theUnwindBlock != NULL);
10874 PRECONDITION(m_usedUnwindSize < m_totalUnwindSize);
10875 PRECONDITION(m_usedUnwindInfos < m_totalUnwindInfos);
10876 PRECONDITION(endOffset <= m_codeSize);
10879 CONSISTENCY_CHECK_MSG(pColdCode == NULL, "Hot/Cold code splitting not supported for jitted code");
10881 JIT_TO_EE_TRANSITION();
10884 // We add one callback-type dynamic function table per range section.
10885 // Therefore, the RUNTIME_FUNCTION info is always relative to the
10886 // image base contained in the dynamic function table, which happens
10887 // to be the LowAddress of the range section. The JIT has no
10888 // knowledge of the range section, so it gives us offsets that are
10889 // relative to the beginning of the method (pHotCode) and we allocate
10890 // and initialize the RUNTIME_FUNCTION data and record its location
10891 // in this function.
10894 if (funcKind != CORJIT_FUNC_ROOT)
10896 // The main method should be emitted before funclets
10897 _ASSERTE(m_usedUnwindInfos > 0);
10900 PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeader->GetUnwindInfo(m_usedUnwindInfos);
10901 m_usedUnwindInfos++;
10903 // Make sure that the RUNTIME_FUNCTION is aligned on a DWORD sized boundary
10904 _ASSERTE(IS_ALIGNED(pRuntimeFunction, sizeof(DWORD)));
10906 UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *) &(m_theUnwindBlock[m_usedUnwindSize]);
10907 m_usedUnwindSize += unwindSize;
10909 reservePersonalityRoutineSpace(m_usedUnwindSize);
10911 _ASSERTE(m_usedUnwindSize <= m_totalUnwindSize);
10913 // Make sure that the UnwindInfo is aligned
10914 _ASSERTE(IS_ALIGNED(pUnwindInfo, sizeof(ULONG)));
10916 /* Calculate Image Relative offset to add to the jit generated unwind offsets */
10918 TADDR baseAddress = m_moduleBase;
10920 size_t currentCodeSizeT = (size_t)pHotCode - baseAddress;
10922 /* Check if currentCodeSizeT offset fits in 32-bits */
10923 if (!FitsInU4(currentCodeSizeT))
10925 _ASSERTE(!"Bad currentCodeSizeT");
10926 COMPlusThrowHR(E_FAIL);
10929 /* Check if EndAddress offset fits in 32-bit */
10930 if (!FitsInU4(currentCodeSizeT + endOffset))
10932 _ASSERTE(!"Bad currentCodeSizeT");
10933 COMPlusThrowHR(E_FAIL);
10936 unsigned currentCodeOffset = (unsigned) currentCodeSizeT;
10938 /* Calculate Unwind Info delta */
10939 size_t unwindInfoDeltaT = (size_t) pUnwindInfo - baseAddress;
10941 /* Check if unwindDeltaT offset fits in 32-bits */
10942 if (!FitsInU4(unwindInfoDeltaT))
10944 _ASSERTE(!"Bad unwindInfoDeltaT");
10945 COMPlusThrowHR(E_FAIL);
10948 unsigned unwindInfoDelta = (unsigned) unwindInfoDeltaT;
10950 RUNTIME_FUNCTION__SetBeginAddress(pRuntimeFunction, currentCodeOffset + startOffset);
10952 #ifdef _TARGET_AMD64_
10953 pRuntimeFunction->EndAddress = currentCodeOffset + endOffset;
10956 RUNTIME_FUNCTION__SetUnwindInfoAddress(pRuntimeFunction, unwindInfoDelta);
10959 if (funcKind != CORJIT_FUNC_ROOT)
10961 // Check the the new funclet doesn't overlap any existing funclet.
10963 for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++)
10965 PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeader->GetUnwindInfo(iUnwindInfo);
10966 _ASSERTE(( RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress)
10967 || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction)));
10972 /* Copy the UnwindBlock */
10973 memcpy(pUnwindInfo, pUnwindBlock, unwindSize);
10975 #if defined(_TARGET_X86_)
10979 #elif defined(_TARGET_AMD64_)
10981 pUnwindInfo->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
10983 ULONG * pPersonalityRoutine = (ULONG*)ALIGN_UP(&(pUnwindInfo->UnwindCode[pUnwindInfo->CountOfUnwindCodes]), sizeof(ULONG));
10984 *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
10986 #elif defined(_TARGET_ARM64_)
10988 *(LONG *)pUnwindInfo |= (1 << 20); // X bit
10990 ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
10991 *pPersonalityRoutine = ExecutionManager::GetCLRPersonalityRoutineValue();
10993 #elif defined(_TARGET_ARM_)
10995 *(LONG *)pUnwindInfo |= (1 << 20); // X bit
10997 ULONG * pPersonalityRoutine = (ULONG*)((BYTE *)pUnwindInfo + ALIGN_UP(unwindSize, sizeof(ULONG)));
10998 *pPersonalityRoutine = (TADDR)ProcessCLRException - baseAddress;
11002 #if defined(_TARGET_AMD64_)
11003 // Publish the new unwind information in a way that the ETW stack crawler can find
11004 if (m_usedUnwindInfos == m_totalUnwindInfos)
11005 UnwindInfoTable::PublishUnwindInfoForMethod(baseAddress, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos);
11006 #endif // defined(_TARGET_AMD64_)
11008 EE_TO_JIT_TRANSITION();
11009 #else // WIN64EXCEPTIONS
11010 LIMITED_METHOD_CONTRACT;
11011 // Dummy implementation to make cross-platform altjit work
11012 #endif // WIN64EXCEPTIONS
11015 void CEEJitInfo::recordCallSite(ULONG instrOffset,
11016 CORINFO_SIG_INFO * callSig,
11017 CORINFO_METHOD_HANDLE methodHandle)
11019 // Currently, only testing tools use this method. The EE itself doesn't need record this information.
11020 // N.B. The memory that callSig points to is managed by the JIT and isn't guaranteed to be around after
11021 // this function returns, so future implementations should copy the sig info if they want it to persist.
11022 LIMITED_METHOD_CONTRACT;
11025 // This is a variant for AMD64 or other machines that
11026 // cannot always hold the destination address in a 32-bit location
11027 // A relocation is recorded if we are pre-jitting.
11028 // A jump thunk may be inserted if we are jitting
11030 void CEEJitInfo::recordRelocation(void * location,
11044 JIT_TO_EE_TRANSITION();
11048 switch (fRelocType)
11050 case IMAGE_REL_BASED_DIR64:
11051 // Write 64-bits into location
11052 *((UINT64 *) ((BYTE *) location + slot)) = (UINT64) target;
11055 #ifdef _TARGET_AMD64_
11056 case IMAGE_REL_BASED_REL32:
11058 target = (BYTE *)target + addlDelta;
11060 INT32 * fixupLocation = (INT32 *) ((BYTE *) location + slot);
11061 BYTE * baseAddr = (BYTE *)fixupLocation + sizeof(INT32);
11063 delta = (INT64)((BYTE *)target - baseAddr);
11066 // Do we need to insert a jump stub to make the source reach the target?
11068 // Note that we cannot stress insertion of jump stub by inserting it unconditionally. JIT records the relocations
11069 // for intra-module jumps and calls. It does not expect the register used by the jump stub to be trashed.
11071 if (!FitsInI4(delta))
11076 // When m_fAllowRel32 == TRUE, the JIT will use REL32s for both data addresses and direct code targets.
11077 // Since we cannot tell what the relocation is for, we have to defensively retry.
11079 m_fRel32Overflow = TRUE;
11085 // When m_fAllowRel32 == FALSE, the JIT will use a REL32s for direct code targets only.
11088 delta = rel32UsingJumpStub(fixupLocation, (PCODE)target, m_pMethodBeingCompiled);
11092 LOG((LF_JIT, LL_INFO100000, "Encoded a PCREL32 at" FMT_ADDR "to" FMT_ADDR "+%d, delta is 0x%04x\n",
11093 DBG_ADDR(fixupLocation), DBG_ADDR(target), addlDelta, delta));
11095 // Write the 32-bits pc-relative delta into location
11096 *fixupLocation = (INT32) delta;
11099 #endif // _TARGET_AMD64_
11101 #ifdef _TARGET_ARM64_
11102 case IMAGE_REL_ARM64_BRANCH26: // 26 bit offset << 2 & sign ext, for B and BL
11104 _ASSERTE(slot == 0);
11105 _ASSERTE(addlDelta == 0);
11107 PCODE branchTarget = (PCODE) target;
11108 _ASSERTE((branchTarget & 0x3) == 0); // the low two bits must be zero
11110 PCODE fixupLocation = (PCODE) location;
11111 _ASSERTE((fixupLocation & 0x3) == 0); // the low two bits must be zero
11113 delta = (INT64)(branchTarget - fixupLocation);
11114 _ASSERTE((delta & 0x3) == 0); // the low two bits must be zero
11116 UINT32 branchInstr = *((UINT32*) fixupLocation);
11117 branchInstr &= 0xFC000000; // keep bits 31-26
11118 _ASSERTE((branchInstr & 0x7FFFFFFF) == 0x14000000); // Must be B or BL
11121 // Do we need to insert a jump stub to make the source reach the target?
11124 if (!FitsInRel28(delta))
11128 TADDR baseAddr = (TADDR)fixupLocation;
11129 TADDR loAddr = baseAddr - 0x08000000; // -2^27
11130 TADDR hiAddr = baseAddr + 0x07FFFFFF; // +2^27-1
11132 // Check for the wrap around cases
11133 if (loAddr > baseAddr)
11134 loAddr = UINT64_MIN; // overflow
11135 if (hiAddr < baseAddr)
11136 hiAddr = UINT64_MAX; // overflow
11138 PCODE jumpStubAddr = ExecutionManager::jumpStub(m_pMethodBeingCompiled,
11143 delta = (INT64)(jumpStubAddr - fixupLocation);
11145 if (!FitsInRel28(delta))
11147 _ASSERTE(!"jump stub was not in expected range");
11148 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
11151 LOG((LF_JIT, LL_INFO100000, "Using JumpStub at" FMT_ADDR "that jumps to" FMT_ADDR "\n",
11152 DBG_ADDR(jumpStubAddr), DBG_ADDR(target)));
11155 LOG((LF_JIT, LL_INFO100000, "Encoded a BRANCH26 at" FMT_ADDR "to" FMT_ADDR ", delta is 0x%04x\n",
11156 DBG_ADDR(fixupLocation), DBG_ADDR(target), delta));
11158 _ASSERTE(FitsInRel28(delta));
11160 PutArm64Rel28((UINT32*) fixupLocation, (INT32)delta);
11164 case IMAGE_REL_ARM64_PAGEBASE_REL21:
11166 _ASSERTE(slot == 0);
11167 _ASSERTE(addlDelta == 0);
11169 // Write the 21 bits pc-relative page address into location.
11170 INT64 targetPage = (INT64)target & 0xFFFFFFFFFFFFF000LL;
11171 INT64 lcoationPage = (INT64)location & 0xFFFFFFFFFFFFF000LL;
11172 INT64 relPage = (INT64)(targetPage - lcoationPage);
11173 INT32 imm21 = (INT32)(relPage >> 12) & 0x1FFFFF;
11174 PutArm64Rel21((UINT32 *)location, imm21);
11178 case IMAGE_REL_ARM64_PAGEOFFSET_12A:
11180 _ASSERTE(slot == 0);
11181 _ASSERTE(addlDelta == 0);
11183 // Write the 12 bits page offset into location.
11184 INT32 imm12 = (INT32)target & 0xFFFLL;
11185 PutArm64Rel12((UINT32 *)location, imm12);
11189 #endif // _TARGET_ARM64_
11192 _ASSERTE(!"Unknown reloc type");
11196 EE_TO_JIT_TRANSITION();
11198 JIT_TO_EE_TRANSITION_LEAF();
11200 // Nothing to do on 32-bit
11202 EE_TO_JIT_TRANSITION_LEAF();
11206 WORD CEEJitInfo::getRelocTypeHint(void * target)
11215 #ifdef _TARGET_AMD64_
11218 // The JIT calls this method for data addresses only. It always uses REL32s for direct code targets.
11219 if (IsPreferredExecutableRange(target))
11220 return IMAGE_REL_BASED_REL32;
11222 #endif // _TARGET_AMD64_
11228 void CEEJitInfo::getModuleNativeEntryPointRange(void** pStart, void** pEnd)
11238 JIT_TO_EE_TRANSITION_LEAF();
11240 *pStart = *pEnd = 0;
11242 EE_TO_JIT_TRANSITION_LEAF();
11245 DWORD CEEJitInfo::getExpectedTargetArchitecture()
11247 LIMITED_METHOD_CONTRACT;
11249 return IMAGE_FILE_MACHINE_NATIVE;
11252 void CEEInfo::JitProcessShutdownWork()
11254 LIMITED_METHOD_CONTRACT;
11256 EEJitManager* jitMgr = ExecutionManager::GetEEJitManager();
11258 // If we didn't load the JIT, there is no work to do.
11259 if (jitMgr->m_jit != NULL)
11261 // Do the shutdown work.
11262 jitMgr->m_jit->ProcessShutdownWork(this);
11265 #ifdef ALLOW_SXS_JIT
11266 if (jitMgr->m_alternateJit != NULL)
11268 jitMgr->m_alternateJit->ProcessShutdownWork(this);
11270 #endif // ALLOW_SXS_JIT
11273 /*********************************************************************/
11274 InfoAccessType CEEJitInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
11285 InfoAccessType result = IAT_PVALUE;
11287 JIT_TO_EE_TRANSITION();
11289 _ASSERTE(ppValue != NULL);
11291 if (IsDynamicScope(scopeHnd))
11293 *ppValue = (LPVOID)GetDynamicResolver(scopeHnd)->ConstructStringLiteral(metaTok);
11297 *ppValue = (LPVOID)ConstructStringLiteral(scopeHnd, metaTok); // throws
11300 EE_TO_JIT_TRANSITION();
11305 /*********************************************************************/
11306 InfoAccessType CEEJitInfo::emptyStringLiteral(void ** ppValue)
11315 InfoAccessType result = IAT_PVALUE;
11317 if(NingenEnabled())
11323 JIT_TO_EE_TRANSITION();
11324 *ppValue = StringObject::GetEmptyStringRefPtr();
11325 EE_TO_JIT_TRANSITION();
11330 /*********************************************************************/
11331 void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
11332 void **ppIndirection)
11341 void *result = NULL;
11343 if (ppIndirection != NULL)
11344 *ppIndirection = NULL;
11346 // Do not bother with initialization if we are only verifying the method.
11347 if (isVerifyOnly())
11349 return (void *)0x10;
11352 JIT_TO_EE_TRANSITION();
11354 FieldDesc* field = (FieldDesc*) fieldHnd;
11356 MethodTable* pMT = field->GetEnclosingMethodTable();
11358 _ASSERTE(!pMT->ContainsGenericVariables());
11360 // We must not call here for statics of collectible types.
11361 _ASSERTE(!pMT->Collectible());
11365 if (!field->IsRVA())
11367 // <REVISIT_TODO>@todo: assert that the current method being compiled is unshared</REVISIT_TODO>
11369 // Allocate space for the local class if necessary, but don't trigger
11370 // class construction.
11371 DomainLocalModule *pLocalModule = pMT->GetDomainLocalModule();
11372 pLocalModule->PopulateClass(pMT);
11376 base = (void *) field->GetBase();
11379 result = field->GetStaticAddressHandle(base);
11381 EE_TO_JIT_TRANSITION();
11386 static void *GetClassSync(MethodTable *pMT)
11388 STANDARD_VM_CONTRACT;
11392 OBJECTREF ref = pMT->GetManagedClassObject();
11393 return (void*)ref->GetSyncBlock()->GetMonitor();
11396 /*********************************************************************/
11397 void* CEEJitInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
11398 void **ppIndirection)
11407 void * result = NULL;
11409 if (ppIndirection != NULL)
11410 *ppIndirection = NULL;
11412 JIT_TO_EE_TRANSITION();
11414 result = GetClassSync((GetMethod(ftnHnd))->GetMethodTable());
11416 EE_TO_JIT_TRANSITION();
11421 /*********************************************************************/
11422 HRESULT CEEJitInfo::allocBBProfileBuffer (
11424 ICorJitInfo::ProfileBuffer ** profileBuffer
11434 HRESULT hr = E_FAIL;
11436 JIT_TO_EE_TRANSITION();
11438 #ifdef FEATURE_PREJIT
11440 // We need to know the code size. Typically we can get the code size
11441 // from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so
11442 // for that case we need to use DynamicResolver to get the code size.
11444 unsigned codeSize = 0;
11445 if (m_pMethodBeingCompiled->IsDynamicMethod())
11447 unsigned stackSize, ehSize;
11448 CorInfoOptions options;
11449 DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver();
11450 pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize);
11454 codeSize = m_ILHeader->GetCodeSize();
11457 *profileBuffer = m_pMethodBeingCompiled->GetLoaderModule()->AllocateProfileBuffer(m_pMethodBeingCompiled->GetMemberDef(), count, codeSize);
11458 hr = (*profileBuffer ? S_OK : E_OUTOFMEMORY);
11459 #else // FEATURE_PREJIT
11460 _ASSERTE(!"allocBBProfileBuffer not implemented on CEEJitInfo!");
11462 #endif // !FEATURE_PREJIT
11464 EE_TO_JIT_TRANSITION();
11469 // Consider implementing getBBProfileData on CEEJitInfo. This will allow us
11470 // to use profile info in codegen for non zapped images.
11471 HRESULT CEEJitInfo::getBBProfileData (
11472 CORINFO_METHOD_HANDLE ftnHnd,
11474 ICorJitInfo::ProfileBuffer ** profileBuffer,
11478 LIMITED_METHOD_CONTRACT;
11479 _ASSERTE(!"getBBProfileData not implemented on CEEJitInfo!");
11483 void CEEJitInfo::allocMem (
11484 ULONG hotCodeSize, /* IN */
11485 ULONG coldCodeSize, /* IN */
11486 ULONG roDataSize, /* IN */
11487 ULONG xcptnsCount, /* IN */
11488 CorJitAllocMemFlag flag, /* IN */
11489 void ** hotCodeBlock, /* OUT */
11490 void ** coldCodeBlock, /* OUT */
11491 void ** roDataBlock /* OUT */
11501 JIT_TO_EE_TRANSITION();
11503 _ASSERTE(coldCodeSize == 0);
11506 *coldCodeBlock = NULL;
11509 ULONG codeSize = hotCodeSize;
11510 void **codeBlock = hotCodeBlock;
11512 S_SIZE_T totalSize = S_SIZE_T(codeSize);
11514 size_t roDataAlignment = sizeof(void*);
11515 if ((flag & CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN)!= 0)
11517 roDataAlignment = 16;
11519 else if (roDataSize >= 8)
11521 roDataAlignment = 8;
11523 if (roDataSize > 0)
11525 size_t codeAlignment = ((flag & CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN)!= 0)
11526 ? 16 : sizeof(void*);
11527 totalSize.AlignUp(codeAlignment);
11528 if (roDataAlignment > codeAlignment) {
11529 // Add padding to align read-only data.
11530 totalSize += (roDataAlignment - codeAlignment);
11532 totalSize += roDataSize;
11535 #ifdef WIN64EXCEPTIONS
11536 totalSize.AlignUp(sizeof(DWORD));
11537 totalSize += m_totalUnwindSize;
11540 _ASSERTE(m_CodeHeader == 0 &&
11541 // The jit-compiler sometimes tries to compile a method a second time
11542 // if it failed the first time. In such a situation, m_CodeHeader may
11543 // have already been assigned. Its OK to ignore this assert in such a
11544 // situation - we will leak some memory, but that is acceptable
11545 // since this should happen very rarely.
11546 "Note that this may fire if the JITCompiler tries to recompile a method");
11548 if( totalSize.IsOverflow() )
11550 COMPlusThrowHR(CORJIT_OUTOFMEM);
11553 m_CodeHeader = m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), flag
11554 #ifdef WIN64EXCEPTIONS
11555 , m_totalUnwindInfos
11560 BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress();
11562 *codeBlock = current;
11563 current += codeSize;
11565 if (roDataSize > 0)
11567 current = (BYTE *)ALIGN_UP(current, roDataAlignment);
11568 *roDataBlock = current;
11569 current += roDataSize;
11573 *roDataBlock = NULL;
11576 #ifdef WIN64EXCEPTIONS
11577 current = (BYTE *)ALIGN_UP(current, sizeof(DWORD));
11579 m_theUnwindBlock = current;
11580 current += m_totalUnwindSize;
11583 _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value());
11586 m_codeSize = codeSize;
11589 EE_TO_JIT_TRANSITION();
11592 /*********************************************************************/
11593 void * CEEJitInfo::allocGCInfo (size_t size)
11602 void * block = NULL;
11604 JIT_TO_EE_TRANSITION();
11606 _ASSERTE(m_CodeHeader != 0);
11607 _ASSERTE(m_CodeHeader->GetGCInfo() == 0);
11610 if (size & 0xFFFFFFFF80000000LL)
11612 COMPlusThrowHR(CORJIT_OUTOFMEM);
11616 block = m_jitManager->allocGCInfo(m_CodeHeader,(DWORD)size, &m_GCinfo_len);
11619 COMPlusThrowHR(CORJIT_OUTOFMEM);
11622 _ASSERTE(m_CodeHeader->GetGCInfo() != 0 && block == m_CodeHeader->GetGCInfo());
11624 EE_TO_JIT_TRANSITION();
11629 /*********************************************************************/
11630 void CEEJitInfo::setEHcount (
11640 JIT_TO_EE_TRANSITION();
11642 _ASSERTE(cEH != 0);
11643 _ASSERTE(m_CodeHeader != 0);
11644 _ASSERTE(m_CodeHeader->GetEHInfo() == 0);
11646 EE_ILEXCEPTION* ret;
11647 ret = m_jitManager->allocEHInfo(m_CodeHeader,cEH, &m_EHinfo_len);
11648 _ASSERTE(ret); // allocEHInfo throws if there's not enough memory
11650 _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && m_CodeHeader->GetEHInfo()->EHCount() == cEH);
11652 EE_TO_JIT_TRANSITION();
11655 /*********************************************************************/
11656 void CEEJitInfo::setEHinfo (
11658 const CORINFO_EH_CLAUSE* clause)
11667 JIT_TO_EE_TRANSITION();
11669 // <REVISIT_TODO> Fix make the Code Manager EH clauses EH_INFO+</REVISIT_TODO>
11670 _ASSERTE(m_CodeHeader->GetEHInfo() != 0 && EHnumber < m_CodeHeader->GetEHInfo()->EHCount());
11672 EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeader->GetEHInfo()->EHClause(EHnumber);
11674 pEHClause->TryStartPC = clause->TryOffset;
11675 pEHClause->TryEndPC = clause->TryLength;
11676 pEHClause->HandlerStartPC = clause->HandlerOffset;
11677 pEHClause->HandlerEndPC = clause->HandlerLength;
11678 pEHClause->ClassToken = clause->ClassToken;
11679 pEHClause->Flags = (CorExceptionFlag)clause->Flags;
11681 LOG((LF_EH, LL_INFO1000000, "Setting EH clause #%d for %s::%s\n", EHnumber, m_pMethodBeingCompiled->m_pszDebugClassName, m_pMethodBeingCompiled->m_pszDebugMethodName));
11682 LOG((LF_EH, LL_INFO1000000, " Flags : 0x%08lx -> 0x%08lx\n", clause->Flags, pEHClause->Flags));
11683 LOG((LF_EH, LL_INFO1000000, " TryOffset : 0x%08lx -> 0x%08lx (startpc)\n", clause->TryOffset, pEHClause->TryStartPC));
11684 LOG((LF_EH, LL_INFO1000000, " TryLength : 0x%08lx -> 0x%08lx (endpc)\n", clause->TryLength, pEHClause->TryEndPC));
11685 LOG((LF_EH, LL_INFO1000000, " HandlerOffset : 0x%08lx -> 0x%08lx\n", clause->HandlerOffset, pEHClause->HandlerStartPC));
11686 LOG((LF_EH, LL_INFO1000000, " HandlerLength : 0x%08lx -> 0x%08lx\n", clause->HandlerLength, pEHClause->HandlerEndPC));
11687 LOG((LF_EH, LL_INFO1000000, " ClassToken : 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->ClassToken));
11688 LOG((LF_EH, LL_INFO1000000, " FilterOffset : 0x%08lx -> 0x%08lx\n", clause->FilterOffset, pEHClause->FilterOffset));
11690 if (m_pMethodBeingCompiled->IsDynamicMethod() &&
11691 ((pEHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) == 0) &&
11692 (clause->ClassToken != NULL))
11694 MethodDesc * pMD; FieldDesc * pFD;
11695 m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver()->ResolveToken(clause->ClassToken, (TypeHandle *)&pEHClause->TypeHandle, &pMD, &pFD);
11696 SetHasCachedTypeHandle(pEHClause);
11697 LOG((LF_EH, LL_INFO1000000, " CachedTypeHandle: 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->TypeHandle));
11700 EE_TO_JIT_TRANSITION();
11703 /*********************************************************************/
11704 // get individual exception handler
11705 void CEEJitInfo::getEHinfo(
11706 CORINFO_METHOD_HANDLE ftn, /* IN */
11707 unsigned EHnumber, /* IN */
11708 CORINFO_EH_CLAUSE* clause) /* OUT */
11717 JIT_TO_EE_TRANSITION();
11719 if (IsDynamicMethodHandle(ftn))
11721 GetMethod(ftn)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
11725 _ASSERTE(ftn == CORINFO_METHOD_HANDLE(m_pMethodBeingCompiled)); // For now only support if the method being jitted
11726 getEHinfoHelper(ftn, EHnumber, clause, m_ILHeader);
11729 EE_TO_JIT_TRANSITION();
11731 #endif // CROSSGEN_COMPILE
11733 #if defined(CROSSGEN_COMPILE)
11734 EXTERN_C ICorJitCompiler* __stdcall getJit();
11735 #endif // defined(CROSSGEN_COMPILE)
11737 #ifdef FEATURE_INTERPRETER
11738 static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr,
11740 struct CORINFO_METHOD_INFO *info,
11742 BYTE **nativeEntry,
11743 ULONG *nativeSizeOfCode)
11745 STATIC_CONTRACT_THROWS;
11746 STATIC_CONTRACT_GC_TRIGGERS;
11747 STATIC_CONTRACT_MODE_PREEMPTIVE;
11748 STATIC_CONTRACT_SO_INTOLERANT;
11750 SString namespaceOrClassName, methodName, methodSignature;
11751 // Fire an ETW event to mark the beginning of JIT'ing
11752 ETW::MethodLog::MethodJitting(reinterpret_cast<MethodDesc*>(info->ftn), &namespaceOrClassName, &methodName, &methodSignature);
11754 CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode);
11756 // Logically, it would seem that the end-of-JITting ETW even should go here, but it must come after the native code has been
11757 // set for the given method desc, which happens in a caller.
11761 #endif // FEATURE_INTERPRETER
11764 // Helper function because can't have dtors in BEGIN_SO_TOLERANT_CODE.
11766 CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr,
11768 struct CORINFO_METHOD_INFO *info,
11769 CORJIT_FLAGS jitFlags,
11770 BYTE **nativeEntry,
11771 ULONG *nativeSizeOfCode)
11773 STATIC_CONTRACT_THROWS;
11774 STATIC_CONTRACT_GC_TRIGGERS;
11775 STATIC_CONTRACT_MODE_PREEMPTIVE;
11776 STATIC_CONTRACT_SO_INTOLERANT;
11778 CorJitResult ret = CORJIT_SKIPPED; // Note that CORJIT_SKIPPED is an error exit status code
11781 comp->setJitFlags(jitFlags);
11783 #ifdef FEATURE_STACK_SAMPLING
11784 // SO_INTOLERANT due to init affecting global state.
11785 static ConfigDWORD s_stackSamplingEnabled;
11786 bool samplingEnabled = (s_stackSamplingEnabled.val(CLRConfig::UNSUPPORTED_StackSamplingEnabled) != 0);
11789 BEGIN_SO_TOLERANT_CODE(GetThread());
11792 #if defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
11793 if (FAILED(ret) && jitMgr->m_alternateJit
11794 #ifdef FEATURE_STACK_SAMPLING
11795 && (!samplingEnabled || (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)))
11799 ret = jitMgr->m_alternateJit->compileMethod( comp,
11801 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11803 nativeSizeOfCode );
11805 #ifdef FEATURE_STACK_SAMPLING
11806 if (jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND))
11808 // Don't bother with failures if we couldn't collect a trace.
11811 #endif // FEATURE_STACK_SAMPLING
11813 // If we failed to jit, then fall back to the primary Jit.
11816 // Consider adding this call:
11817 // ((CEEJitInfo*)comp)->BackoutJitData(jitMgr);
11818 ((CEEJitInfo*)comp)->ResetForJitRetry();
11819 ret = CORJIT_SKIPPED;
11822 #endif // defined(ALLOW_SXS_JIT) && !defined(CROSSGEN_COMPILE)
11824 #ifdef FEATURE_INTERPRETER
11825 static ConfigDWORD s_InterpreterFallback;
11827 bool interpreterFallback = (s_InterpreterFallback.val(CLRConfig::INTERNAL_InterpreterFallback) != 0);
11829 if (interpreterFallback == false)
11831 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
11832 // (We assume that importation is completely architecture-independent, or at least nearly so.)
11833 if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
11835 ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode);
11839 if (FAILED(ret) && jitMgr->m_jit)
11841 ret = CompileMethodWithEtwWrapper(jitMgr,
11844 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11849 if (interpreterFallback == true)
11851 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
11852 // (We assume that importation is completely architecture-independent, or at least nearly so.)
11853 if (FAILED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE))
11855 ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode);
11861 ret = jitMgr->m_jit->compileMethod( comp,
11863 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
11867 #endif // FEATURE_INTERPRETER
11869 #if !defined(CROSSGEN_COMPILE)
11870 // Cleanup any internal data structures allocated
11871 // such as IL code after a successfull JIT compile
11872 // If the JIT fails we keep the IL around and will
11873 // try reJIT the same IL. VSW 525059
11875 if (SUCCEEDED(ret) && !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !((CEEJitInfo*)comp)->JitAgain())
11877 ((CEEJitInfo*)comp)->CompressDebugInfo();
11879 #ifdef FEATURE_INTERPRETER
11880 // We do this cleanup in the prestub, where we know whether the method
11881 // has been interpreted.
11883 comp->MethodCompileComplete(info->ftn);
11884 #endif // FEATURE_INTERPRETER
11886 #endif // !defined(CROSSGEN_COMPILE)
11889 #if defined(FEATURE_GDBJIT)
11890 if (SUCCEEDED(ret) && *nativeEntry != NULL)
11892 CodeHeader* pCH = ((CodeHeader*)((PCODE)*nativeEntry & ~1)) - 1;
11893 pCH->SetCalledMethods((PTR_VOID)comp->GetCalledMethods());
11897 END_SO_TOLERANT_CODE;
11903 /*********************************************************************/
11904 CorJitResult invokeCompileMethod(EEJitManager *jitMgr,
11906 struct CORINFO_METHOD_INFO *info,
11907 CORJIT_FLAGS jitFlags,
11908 BYTE **nativeEntry,
11909 ULONG *nativeSizeOfCode)
11917 // The JIT runs in preemptive mode
11922 CorJitResult ret = invokeCompileMethodHelper(jitMgr, comp, info, jitFlags, nativeEntry, nativeSizeOfCode);
11925 // Verify that we are still in preemptive mode when we return
11929 _ASSERTE(GetThread()->PreemptiveGCDisabled() == FALSE);
11934 CORJIT_FLAGS GetCompileFlagsIfGenericInstantiation(
11935 CORINFO_METHOD_HANDLE method,
11936 CORJIT_FLAGS compileFlags,
11937 ICorJitInfo * pCorJitInfo,
11938 BOOL * raiseVerificationException,
11939 BOOL * unverifiableGenericCode);
11941 CorJitResult CallCompileMethodWithSEHWrapper(EEJitManager *jitMgr,
11943 struct CORINFO_METHOD_INFO *info,
11944 CORJIT_FLAGS flags,
11945 BYTE **nativeEntry,
11946 ULONG *nativeSizeOfCode,
11949 // no dynamic contract here because SEH is used, with a finally clause
11950 STATIC_CONTRACT_NOTHROW;
11951 STATIC_CONTRACT_GC_TRIGGERS;
11953 LOG((LF_CORDB, LL_EVERYTHING, "CallCompileMethodWithSEHWrapper called...\n"));
11957 EEJitManager *jitMgr;
11959 struct CORINFO_METHOD_INFO *info;
11960 CORJIT_FLAGS flags;
11961 BYTE **nativeEntry;
11962 ULONG *nativeSizeOfCode;
11966 param.jitMgr = jitMgr;
11969 param.flags = flags;
11970 param.nativeEntry = nativeEntry;
11971 param.nativeSizeOfCode = nativeSizeOfCode;
11973 param.res = CORJIT_INTERNALERROR;
11975 PAL_TRY(Param *, pParam, ¶m)
11978 // Call out to the JIT-compiler
11981 pParam->res = invokeCompileMethod( pParam->jitMgr,
11985 pParam->nativeEntry,
11986 pParam->nativeSizeOfCode);
11990 #if defined(DEBUGGING_SUPPORTED) && !defined(CROSSGEN_COMPILE)
11991 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) &&
11992 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MCJIT_BACKGROUND)
11993 #ifdef FEATURE_STACK_SAMPLING
11994 && !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND)
11995 #endif // FEATURE_STACK_SAMPLING
11999 // Notify the debugger that we have successfully jitted the function
12001 if (ftn->HasNativeCode())
12004 // Nothing to do here (don't need to notify the debugger
12005 // because the function has already been successfully jitted)
12007 // This is the case where we aborted the jit because of a deadlock cycle
12013 if (g_pDebugInterface)
12015 if (param.res == CORJIT_OK && !((CEEJitInfo*)param.comp)->JitAgain())
12017 g_pDebugInterface->JITComplete(ftn, (TADDR) *nativeEntry);
12022 #endif // DEBUGGING_SUPPORTED && !CROSSGEN_COMPILE
12029 /*********************************************************************/
12030 // Figures out the compile flags that are used by both JIT and NGen
12032 /* static */ CORJIT_FLAGS CEEInfo::GetBaseCompileFlags(MethodDesc * ftn)
12040 // Figure out the code quality flags
12043 CORJIT_FLAGS flags;
12044 if (g_pConfig->JitFramed())
12045 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12046 if (g_pConfig->JitAlignLoops())
12047 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_ALIGN_LOOPS);
12048 if (ReJitManager::IsReJITEnabled() || g_pConfig->AddRejitNops())
12049 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_REJIT_NOPS);
12050 #ifdef _TARGET_X86_
12051 if (g_pConfig->PInvokeRestoreEsp(ftn->GetModule()->IsPreV4Assembly()))
12052 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PINVOKE_RESTORE_ESP);
12053 #endif // _TARGET_X86_
12055 //See if we should instruct the JIT to emit calls to JIT_PollGC for thread suspension. If we have a
12056 //non-default value in the EE Config, then use that. Otherwise select the platform specific default.
12057 #ifdef FEATURE_ENABLE_GCPOLL
12058 EEConfig::GCPollType pollType = g_pConfig->GetGCPollType();
12059 if (EEConfig::GCPOLL_TYPE_POLL == pollType)
12060 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_CALLS);
12061 else if (EEConfig::GCPOLL_TYPE_INLINE == pollType)
12062 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_GCPOLL_INLINE);
12063 #endif //FEATURE_ENABLE_GCPOLL
12065 // Set flags based on method's ImplFlags.
12066 if (!ftn->IsNoMetadata())
12068 DWORD dwImplFlags = 0;
12069 IfFailThrow(ftn->GetMDImport()->GetMethodImplProps(ftn->GetMemberDef(), NULL, &dwImplFlags));
12071 if (IsMiNoOptimization(dwImplFlags))
12073 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12076 // Always emit frames for methods marked no-inline (see #define ETW_EBP_FRAMED in the JIT)
12077 if (IsMiNoInlining(dwImplFlags))
12079 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12086 /*********************************************************************/
12087 // Figures out (some of) the flags to use to compile the method
12088 // Returns the new set to use
12090 CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags)
12092 STANDARD_VM_CONTRACT;
12094 //Right now if we don't have a debug interface on CoreCLR, we can't generate debug info. So, in those
12095 //cases don't attempt it.
12096 if (!g_pDebugInterface)
12099 #ifdef DEBUGGING_SUPPORTED
12102 if (g_pConfig->GenDebuggableCode())
12103 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12106 #ifdef EnC_SUPPORTED
12107 if (pModule->IsEditAndContinueEnabled())
12109 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_EnC);
12111 #endif // EnC_SUPPORTED
12113 // Debug info is always tracked
12114 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12115 #endif // DEBUGGING_SUPPORTED
12117 if (CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
12119 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12122 if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12124 // If we are only verifying the method, dont need any debug info and this
12125 // prevents getVars()/getBoundaries() from being called unnecessarily.
12126 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12127 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12133 CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHOD_INFO * methodInfo)
12135 STANDARD_VM_CONTRACT;
12137 _ASSERTE(methodInfo->regionKind == CORINFO_REGION_JIT);
12140 // Get the compile flags that are shared between JIT and NGen
12142 flags.Add(CEEInfo::GetBaseCompileFlags(ftn));
12145 // Get CPU specific flags
12147 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12149 flags.Add(ExecutionManager::GetEEJitManager()->GetCPUCompileFlags());
12153 // Find the debugger and profiler related flags
12156 #ifdef DEBUGGING_SUPPORTED
12157 flags.Add(GetDebuggerCompileFlags(ftn->GetModule(), flags));
12160 #ifdef PROFILING_SUPPORTED
12161 if (CORProfilerTrackEnterLeave() && !ftn->IsNoMetadata())
12162 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE);
12164 if (CORProfilerTrackTransitions())
12165 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_NO_PINVOKE_INLINE);
12166 #endif // PROFILING_SUPPORTED
12168 // Set optimization flags
12169 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT))
12171 unsigned optType = g_pConfig->GenOptimizeType();
12172 _ASSERTE(optType <= OPT_RANDOM);
12174 if (optType == OPT_RANDOM)
12175 optType = methodInfo->ILCodeSize % OPT_RANDOM;
12177 if (g_pConfig->JitMinOpts())
12178 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12180 if (optType == OPT_SIZE)
12182 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SIZE_OPT);
12184 else if (optType == OPT_SPEED)
12186 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SPEED_OPT);
12191 // Verification flags
12195 if (g_pConfig->IsJitVerificationDisabled())
12196 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12199 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && Security::CanSkipVerification(ftn))
12200 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12202 if (ftn->IsILStub())
12204 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12206 // no debug info available for IL stubs
12207 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12213 #if defined(_WIN64)
12214 //The implementation of Jit64 prevents it from both inlining and verifying at the same time. This causes a
12215 //perf problem for code that adopts Transparency. This code attempts to enable inlining in spite of that
12216 //limitation in that scenario.
12218 //This only works for real methods. If the method isn't IsIL, then IsVerifiable will AV. That would be a
12220 BOOL IsTransparentMethodSafeToSkipVerification(CORJIT_FLAGS flags, MethodDesc * ftn)
12222 STANDARD_VM_CONTRACT;
12225 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) && !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION)
12226 && Security::IsMethodTransparent(ftn) &&
12227 ((ftn->IsIL() && !ftn->IsUnboxingStub()) ||
12228 (ftn->IsDynamicMethod() && !ftn->IsILStub())))
12232 //Verify the method
12233 ret = ftn->IsVerifiable();
12237 //If the jit throws an exception, do not let it leak out of here. For example, we can sometimes
12238 //get an IPE that we could recover from in the Jit (i.e. invalid local in a method with skip
12241 EX_END_CATCH(RethrowTerminalExceptions)
12246 #define IsTransparentMethodSafeToSkipVerification(flags,ftn) (FALSE)
12249 /*********************************************************************/
12250 // We verify generic code once and for all using the typical open type,
12251 // and then no instantiations need to be verified. If verification
12252 // failed, then we need to throw an exception whenever we try
12253 // to compile a real instantiation
12255 CORJIT_FLAGS GetCompileFlagsIfGenericInstantiation(
12256 CORINFO_METHOD_HANDLE method,
12257 CORJIT_FLAGS compileFlags,
12258 ICorJitInfo * pCorJitInfo,
12259 BOOL * raiseVerificationException,
12260 BOOL * unverifiableGenericCode)
12262 STANDARD_VM_CONTRACT;
12264 *raiseVerificationException = FALSE;
12265 *unverifiableGenericCode = FALSE;
12267 // If we have already decided to skip verification, keep on going.
12268 if (compileFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION))
12269 return compileFlags;
12271 CorInfoInstantiationVerification ver = pCorJitInfo->isInstantiationOfVerifiedGeneric(method);
12275 case INSTVER_NOT_INSTANTIATION:
12276 // Non-generic, or open instantiation of a generic type/method
12277 if (IsTransparentMethodSafeToSkipVerification(compileFlags, (MethodDesc*)method))
12278 compileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12279 return compileFlags;
12281 case INSTVER_GENERIC_PASSED_VERIFICATION:
12282 // If the typical instantiation is verifiable, there is no need
12283 // to verify the concrete instantiations
12284 compileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12285 return compileFlags;
12287 case INSTVER_GENERIC_FAILED_VERIFICATION:
12289 *unverifiableGenericCode = TRUE;
12291 // The generic method is not verifiable.
12292 // Check if it has SkipVerification permission
12293 MethodDesc * pGenMethod = GetMethod(method)->LoadTypicalMethodDefinition();
12295 CORINFO_METHOD_HANDLE genMethodHandle = CORINFO_METHOD_HANDLE(pGenMethod);
12297 CorInfoCanSkipVerificationResult canSkipVer;
12298 canSkipVer = pCorJitInfo->canSkipMethodVerification(genMethodHandle);
12303 #ifdef FEATURE_PREJIT
12304 case CORINFO_VERIFICATION_DONT_JIT:
12306 // Transparent code could be partial trust, but we don't know at NGEN time.
12307 // This is the flag that NGEN passes to the JIT to tell it to give-up if it
12308 // hits unverifiable code. Since we've already hit unverifiable code,
12309 // there's no point in starting the JIT, just to have it give up, so we
12311 _ASSERTE(compileFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_PREJIT));
12312 *raiseVerificationException = TRUE;
12313 return CORJIT_FLAGS(); // This value will not be used
12315 #else // FEATURE_PREJIT
12316 // Need to have this case here to keep the MAC build happy
12317 case CORINFO_VERIFICATION_DONT_JIT:
12319 _ASSERTE(!"We should never get here");
12320 return compileFlags;
12322 #endif // FEATURE_PREJIT
12324 case CORINFO_VERIFICATION_CANNOT_SKIP:
12326 // For unverifiable generic code without SkipVerification permission,
12327 // we cannot ask the compiler to emit CORINFO_HELP_VERIFICATION in
12328 // unverifiable branches as the compiler cannot determine the unverifiable
12329 // branches while compiling the concrete instantiation. Instead,
12330 // just throw a VerificationException right away.
12331 *raiseVerificationException = TRUE;
12332 return CORJIT_FLAGS(); // This value will not be used
12335 case CORINFO_VERIFICATION_CAN_SKIP:
12337 compileFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION);
12338 return compileFlags;
12341 case CORINFO_VERIFICATION_RUNTIME_CHECK:
12343 // Compile the method without CORJIT_FLAG_SKIP_VERIFICATION.
12344 // The compiler will know to add a call to
12345 // CORINFO_HELP_VERIFICATION_RUNTIME_CHECK, and then to skip verification.
12346 return compileFlags;
12351 _ASSERTE(!"We should never get here");
12352 return compileFlags;
12355 // ********************************************************************
12357 // Throw the right type of exception for the given JIT result
12359 void ThrowExceptionForJit(HRESULT res)
12371 case CORJIT_OUTOFMEM:
12375 #ifdef _TARGET_X86_
12376 // Currently, only x86 JIT returns adequate error codes. The x86 JIT is also the
12377 // JIT that has more limitations and given that to get this message for 64 bit
12378 // is going to require some code churn (either changing their EH handlers or
12379 // fixing the 3 or 4 code sites they have that return CORJIT_INTERNALERROR independently
12380 // of the error, the least risk fix is making this x86 only.
12381 case CORJIT_INTERNALERROR:
12382 COMPlusThrow(kInvalidProgramException, (UINT) IDS_EE_JIT_COMPILER_ERROR);
12386 case CORJIT_BADCODE:
12388 COMPlusThrow(kInvalidProgramException);
12393 // ********************************************************************
12395 LONG g_JitCount = 0;
12398 //#define PERF_TRACK_METHOD_JITTIMES
12399 #ifdef _TARGET_AMD64_
12400 BOOL g_fAllowRel32 = TRUE;
12404 // ********************************************************************
12406 // ********************************************************************
12408 // The reason that this is named UnsafeJitFunction is that this helper
12409 // method is not thread safe! When multiple threads get in here for
12410 // the same pMD, ALL of them MUST return the SAME value.
12411 // To insure that this happens you must call MakeJitWorker.
12412 // It creates a DeadlockAware list of methods being jitted and prevents us
12413 // from trying to jit the same method more that once.
12415 // Calls to this method that occur to check if inlining can occur on x86,
12416 // are OK since they discard the return value of this method.
12418 PCODE UnsafeJitFunction(MethodDesc* ftn, COR_ILMETHOD_DECODER* ILHeader, CORJIT_FLAGS flags,
12419 ULONG * pSizeOfCode)
12421 STANDARD_VM_CONTRACT;
12425 COOPERATIVE_TRANSITION_BEGIN();
12427 #ifdef FEATURE_PREJIT
12429 if (g_pConfig->RequireZaps() == EEConfig::REQUIRE_ZAPS_ALL &&
12430 ftn->GetModule()->GetDomainFile()->IsZapRequired() &&
12431 PartialNGenStressPercentage() == 0 &&
12432 #ifdef FEATURE_STACK_SAMPLING
12433 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SAMPLING_JIT_BACKGROUND) &&
12435 !flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12437 StackSString ss(SString::Ascii, "ZapRequire: JIT compiler invoked for ");
12438 TypeString::AppendMethodInternal(ss, ftn);
12441 // Assert as some test may not check their error codes well. So throwing an
12442 // exception may not cause a test failure (as it should).
12443 StackScratchBuffer scratch;
12444 DbgAssertDialog(__FILE__, __LINE__, (char*)ss.GetUTF8(scratch));
12447 COMPlusThrowNonLocalized(kFileNotFoundException, ss.GetUnicode());
12450 #endif // FEATURE_PREJIT
12452 #ifndef CROSSGEN_COMPILE
12453 EEJitManager *jitMgr = ExecutionManager::GetEEJitManager();
12454 if (!jitMgr->LoadJIT())
12456 #ifdef ALLOW_SXS_JIT
12457 if (!jitMgr->IsMainJitLoaded())
12459 // Don't want to throw InvalidProgram from here.
12460 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12462 if (!jitMgr->IsAltJitLoaded())
12464 // Don't want to throw InvalidProgram from here.
12465 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load alternative JIT compiler"));
12467 #else // ALLOW_SXS_JIT
12468 // Don't want to throw InvalidProgram from here.
12469 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12470 #endif // ALLOW_SXS_JIT
12472 #endif // CROSSGEN_COMPILE
12475 // This is here so we can see the name and class easily in the debugger
12477 LPCUTF8 cls = ftn->GetMethodTable()->GetDebugClassName();
12478 LPCUTF8 name = ftn->GetName();
12480 if (ftn->IsNoMetadata())
12482 if (ftn->IsILStub())
12484 LOG((LF_JIT, LL_INFO10000, "{ Jitting IL Stub }\n"));
12488 LOG((LF_JIT, LL_INFO10000, "{ Jitting dynamic method }\n"));
12493 SString methodString;
12494 if (LoggingOn(LF_JIT, LL_INFO10000))
12495 TypeString::AppendMethodDebug(methodString, ftn);
12497 LOG((LF_JIT, LL_INFO10000, "{ Jitting method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12501 if (!SString::_stricmp(cls,"ENC") &&
12502 (!SString::_stricmp(name,"G")))
12512 CORINFO_METHOD_HANDLE ftnHnd = (CORINFO_METHOD_HANDLE)ftn;
12513 CORINFO_METHOD_INFO methodInfo;
12515 getMethodInfoHelper(ftn, ftnHnd, ILHeader, &methodInfo);
12517 // If it's generic then we can only enter through an instantiated md (unless we're just verifying it)
12518 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || !ftn->IsGenericMethodDefinition());
12520 // If it's an instance method then it must not be entered from a generic class
12521 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY) || ftn->IsStatic() ||
12522 ftn->GetNumGenericClassArgs() == 0 || ftn->HasClassInstantiation());
12524 // method attributes and signature are consistant
12525 _ASSERTE(!!ftn->IsStatic() == ((methodInfo.args.callConv & CORINFO_CALLCONV_HASTHIS) == 0));
12527 flags = GetCompileFlags(ftn, flags, &methodInfo);
12530 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_SKIP_VERIFICATION))
12532 SString methodString;
12533 if (LoggingOn(LF_VERIFIER, LL_INFO100))
12534 TypeString::AppendMethodDebug(methodString, ftn);
12536 LOG((LF_VERIFIER, LL_INFO100, "{ Will verify method (%p) %S %s\n", ftn, methodString.GetUnicode(), ftn->m_pszDebugMethodSignature));
12540 #ifdef _TARGET_AMD64_
12541 BOOL fForceRel32Overflow = FALSE;
12544 // Always exercise the overflow codepath with force relocs
12545 if (PEDecoder::GetForceRelocs())
12546 fForceRel32Overflow = TRUE;
12549 BOOL fAllowRel32 = g_fAllowRel32 | fForceRel32Overflow;
12551 // For determinism, never try to use the REL32 in compilation process
12552 if (IsCompilationProcess())
12554 fForceRel32Overflow = FALSE;
12555 fAllowRel32 = FALSE;
12557 #endif // _TARGET_AMD64_
12561 #ifndef CROSSGEN_COMPILE
12562 CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY));
12564 // This path should be only ever used for verification in crossgen and so we should not need EEJitManager
12565 _ASSERTE(flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY));
12566 CEEInfo jitInfo(ftn, true);
12567 EEJitManager *jitMgr = NULL;
12570 #if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE)
12571 if (fForceRel32Overflow)
12572 jitInfo.SetRel32Overflow(fAllowRel32);
12573 jitInfo.SetAllowRel32(fAllowRel32);
12576 MethodDesc * pMethodForSecurity = jitInfo.GetMethodForSecurity(ftnHnd);
12578 //Since the check could trigger a demand, we have to do this every time.
12579 //This is actually an overly complicated way to make sure that a method can access all its arguments
12580 //and its return type.
12581 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
12582 TypeHandle ownerTypeForSecurity = TypeHandle(pMethodForSecurity->GetMethodTable());
12583 DynamicResolver *pAccessContext = NULL;
12584 BOOL doAccessCheck = TRUE;
12585 if (pMethodForSecurity->IsDynamicMethod())
12587 doAccessCheck = ModifyCheckForDynamicMethod(pMethodForSecurity->AsDynamicMethodDesc()->GetResolver(),
12588 &ownerTypeForSecurity,
12589 &accessCheckType, &pAccessContext);
12593 AccessCheckOptions accessCheckOptions(accessCheckType,
12595 TRUE /*Throw on error*/,
12596 pMethodForSecurity);
12598 StaticAccessCheckContext accessContext(pMethodForSecurity, ownerTypeForSecurity.GetMethodTable());
12600 // We now do an access check from pMethodForSecurity to pMethodForSecurity, its sole purpose is to
12601 // verify that pMethodForSecurity/ownerTypeForSecurity has access to all its parameters.
12603 // ownerTypeForSecurity.GetMethodTable() can be null if the pMethodForSecurity is a DynamicMethod
12604 // associated with a TypeDesc (Array, Ptr, Ref, or FnPtr). That doesn't make any sense, but we will
12605 // just do an access check from a NULL context which means only public types are accessible.
12606 if (!ClassLoader::CanAccess(&accessContext,
12607 ownerTypeForSecurity.GetMethodTable(),
12608 ownerTypeForSecurity.GetAssembly(),
12609 pMethodForSecurity->GetAttrs(),
12610 pMethodForSecurity,
12612 accessCheckOptions,
12613 TRUE /*Check method transparency*/,
12614 TRUE /*Check type transparency*/))
12616 EX_THROW(EEMethodException, (pMethodForSecurity));
12620 BOOL raiseVerificationException, unverifiableGenericCode;
12622 flags = GetCompileFlagsIfGenericInstantiation(
12626 &raiseVerificationException,
12627 &unverifiableGenericCode);
12629 if (raiseVerificationException)
12630 COMPlusThrow(kVerificationException);
12639 /* There is a double indirection to call compileMethod - can we
12640 improve this with the new structure? */
12642 #ifdef PERF_TRACK_METHOD_JITTIMES
12643 //Because we're not calling QPC enough. I'm not going to track times if we're just importing.
12644 LARGE_INTEGER methodJitTimeStart = {0};
12645 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12646 QueryPerformanceCounter (&methodJitTimeStart);
12649 #if defined(ENABLE_PERF_COUNTERS)
12653 #if defined(ENABLE_PERF_COUNTERS)
12654 LARGE_INTEGER CycleStart;
12655 QueryPerformanceCounter (&CycleStart);
12656 #endif // defined(ENABLE_PERF_COUNTERS)
12658 // Note on debuggerTrackInfo arg: if we're only importing (ie, verifying/
12659 // checking to make sure we could JIT, but not actually generating code (
12660 // eg, for inlining), then DON'T TELL THE DEBUGGER about this.
12661 res = CallCompileMethodWithSEHWrapper(jitMgr,
12668 LOG((LF_CORDB, LL_EVERYTHING, "Got through CallCompile MethodWithSEHWrapper\n"));
12670 #if FEATURE_PERFMAP
12671 // Save the code size so that it can be reported to the perfmap.
12672 if (pSizeOfCode != NULL)
12674 *pSizeOfCode = sizeOfCode;
12678 #if defined(ENABLE_PERF_COUNTERS)
12679 LARGE_INTEGER CycleStop;
12680 QueryPerformanceCounter(&CycleStop);
12681 GetPerfCounters().m_Jit.timeInJitBase = GetPerfCounters().m_Jit.timeInJit;
12682 GetPerfCounters().m_Jit.timeInJit += static_cast<DWORD>(CycleStop.QuadPart - CycleStart.QuadPart);
12683 GetPerfCounters().m_Jit.cMethodsJitted++;
12684 GetPerfCounters().m_Jit.cbILJitted+=methodInfo.ILCodeSize;
12686 #endif // defined(ENABLE_PERF_COUNTERS)
12688 #if defined(ENABLE_PERF_COUNTERS)
12692 #ifdef PERF_TRACK_METHOD_JITTIMES
12693 //store the time in the string buffer. Module name and token are unique enough. Also, do not
12694 //capture importing time, just actual compilation time.
12695 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12697 LARGE_INTEGER methodJitTimeStop;
12698 QueryPerformanceCounter(&methodJitTimeStop);
12700 ftn->GetModule()->GetDomainFile()->GetFile()->GetCodeBaseOrName(codeBase);
12701 codeBase.AppendPrintf(W(",0x%x,%d,%d\n"),
12702 //(const WCHAR *)codeBase, //module name
12703 ftn->GetMemberDef(), //method token
12704 (unsigned)(methodJitTimeStop.QuadPart - methodJitTimeStart.QuadPart), //cycle count
12705 methodInfo.ILCodeSize //il size
12707 WszOutputDebugString((const WCHAR*)codeBase);
12709 #endif // PERF_TRACK_METHOD_JITTIMES
12713 LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s %s }\n",cls,name, ftn->m_pszDebugMethodSignature));
12715 if (!SUCCEEDED(res))
12717 COUNTER_ONLY(GetPerfCounters().m_Jit.cJitFailures++);
12719 #ifndef CROSSGEN_COMPILE
12720 jitInfo.BackoutJitData(jitMgr);
12723 ThrowExceptionForJit(res);
12726 if (flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IMPORT_ONLY))
12728 // The method must been processed by the verifier. Note that it may
12729 // either have been marked as verifiable or unverifiable.
12730 // ie. IsVerified() does not imply IsVerifiable()
12731 _ASSERTE(ftn->IsVerified());
12738 COMPlusThrow(kInvalidProgramException);
12740 #if defined(_TARGET_AMD64_) && !defined(CROSSGEN_COMPILE)
12741 if (jitInfo.IsRel32Overflow())
12743 // Backout and try again with fAllowRel32 == FALSE.
12744 jitInfo.BackoutJitData(jitMgr);
12746 // Disallow rel32 relocs in future.
12747 g_fAllowRel32 = FALSE;
12749 _ASSERTE(fAllowRel32 != FALSE);
12750 fAllowRel32 = FALSE;
12753 #endif // _TARGET_AMD64_ && !CROSSGEN_COMPILE
12755 LOG((LF_JIT, LL_INFO10000,
12756 "Jitted Entry at" FMT_ADDR "method %s::%s %s\n", DBG_ADDR(nativeEntry),
12757 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
12759 #if defined(FEATURE_CORESYSTEM)
12762 LPCUTF8 pszDebugClassName = ftn->m_pszDebugClassName;
12763 LPCUTF8 pszDebugMethodName = ftn->m_pszDebugMethodName;
12764 LPCUTF8 pszDebugMethodSignature = ftn->m_pszDebugMethodSignature;
12766 LPCUTF8 pszNamespace;
12767 LPCUTF8 pszDebugClassName = ftn->GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace);
12768 LPCUTF8 pszDebugMethodName = ftn->GetName();
12769 LPCUTF8 pszDebugMethodSignature = "";
12772 //DbgPrintf("Jitted Entry at" FMT_ADDR "method %s::%s %s size %08x\n", DBG_ADDR(nativeEntry),
12773 // pszDebugClassName, pszDebugMethodName, pszDebugMethodSignature, sizeOfCode);
12776 ClrFlushInstructionCache(nativeEntry, sizeOfCode);
12777 ret = (PCODE)nativeEntry;
12779 #ifdef _TARGET_ARM_
12788 FastInterlockIncrement(&g_JitCount);
12789 static BOOL fHeartbeat = -1;
12791 if (fHeartbeat == -1)
12792 fHeartbeat = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitHeartbeat);
12798 COOPERATIVE_TRANSITION_END();
12802 extern "C" unsigned __stdcall PartialNGenStressPercentage()
12804 LIMITED_METHOD_CONTRACT;
12808 static ConfigDWORD partialNGenStress;
12809 DWORD partialNGenStressVal = partialNGenStress.val(CLRConfig::INTERNAL_partialNGenStress);
12810 _ASSERTE(partialNGenStressVal <= 100);
12811 return partialNGenStressVal;
12815 #ifdef FEATURE_PREJIT
12816 /*********************************************************************/
12819 // Table loading functions
12821 void Module::LoadHelperTable()
12823 STANDARD_VM_CONTRACT;
12825 #ifndef CROSSGEN_COMPILE
12827 BYTE * table = (BYTE *) GetNativeImage()->GetNativeHelperTable(&tableSize);
12829 if (tableSize == 0)
12832 EnsureWritableExecutablePages(table, tableSize);
12834 BYTE * curEntry = table;
12835 BYTE * tableEnd = table + tableSize;
12838 int iEntryNumber = 0;
12845 while (curEntry < tableEnd)
12847 DWORD dwHelper = *(DWORD *)curEntry;
12849 int iHelper = (USHORT)dwHelper;
12850 _ASSERTE(iHelper < CORINFO_HELP_COUNT);
12852 LOG((LF_JIT, LL_INFO1000000, "JIT helper %3d (%-40s: table @ %p, size 0x%x, entry %3d @ %p, pfnHelper %p)\n",
12853 iHelper, hlpFuncTable[iHelper].name, table, tableSize, iEntryNumber, curEntry, hlpFuncTable[iHelper].pfnHelper));
12855 #if defined(ENABLE_FAST_GCPOLL_HELPER)
12856 // The fast GC poll helper works by calling indirect through a pointer that points to either
12857 // JIT_PollGC or JIT_PollGC_Nop, based on whether we need to poll or not. The JIT_PollGC_Nop
12858 // version is just a "ret". The pointer is stored in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
12859 // See EnableJitGCPoll() and DisableJitGCPoll().
12860 // In NGEN images, we generate a direct call to the helper table. Here, we replace that with
12861 // an indirect jump through the pointer in hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].
12862 if (iHelper == CORINFO_HELP_POLL_GC)
12864 LOG((LF_JIT, LL_INFO1000000, "JIT helper CORINFO_HELP_POLL_GC (%d); emitting indirect jump to 0x%x\n",
12865 CORINFO_HELP_POLL_GC, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper));
12867 emitJumpInd(curEntry, &hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_POLL_GC].pfnHelper);
12868 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
12871 #endif // ENABLE_FAST_GCPOLL_HELPER
12873 PCODE pfnHelper = CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)iHelper);
12875 if (dwHelper & CORCOMPILE_HELPER_PTR)
12878 // Indirection cell
12881 *(TADDR *)curEntry = pfnHelper;
12883 curEntry = curEntry + sizeof(TADDR);
12891 #if defined(_TARGET_AMD64_)
12892 *curEntry = X86_INSTR_JMP_REL32;
12893 *(INT32 *)(curEntry + 1) = rel32UsingJumpStub((INT32 *)(curEntry + 1), pfnHelper, NULL, GetLoaderAllocator());
12894 #else // all other platforms
12895 emitJump(curEntry, (LPVOID)pfnHelper);
12896 _ASSERTE(HELPER_TABLE_ENTRY_LEN >= JUMP_ALLOCATE_SIZE);
12899 curEntry = curEntry + HELPER_TABLE_ENTRY_LEN;
12903 // Note that some table entries are sizeof(TADDR) in length, and some are HELPER_TABLE_ENTRY_LEN in length
12908 ClrFlushInstructionCache(table, tableSize);
12909 #endif // CROSSGEN_COMPILE
12912 #ifdef FEATURE_READYTORUN
12913 CorInfoHelpFunc MapReadyToRunHelper(ReadyToRunHelper helperNum)
12915 LIMITED_METHOD_CONTRACT;
12919 #define HELPER(readyToRunHelper, corInfoHelpFunc, flags) \
12920 case readyToRunHelper: return corInfoHelpFunc;
12921 #include "readytorunhelpers.h"
12923 case READYTORUN_HELPER_GetString: return CORINFO_HELP_STRCNS;
12925 default: return CORINFO_HELP_UNDEF;
12929 void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap)
12931 STANDARD_VM_CONTRACT;
12933 ZeroMemory(pGCRefMap, cbGCRefMap);
12935 if (!pMT->ContainsPointers())
12938 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
12939 CGCDescSeries* cur = map->GetHighestSeries();
12940 CGCDescSeries* last = map->GetLowestSeries();
12941 DWORD size = pMT->GetBaseSize();
12942 _ASSERTE(cur >= last);
12946 // offset to embedded references in this series must be
12947 // adjusted by the VTable pointer, when in the unboxed state.
12948 size_t offset = cur->GetSeriesOffset() - sizeof(void*);
12949 size_t offsetStop = offset + cur->GetSeriesSize() + size;
12950 while (offset < offsetStop)
12952 size_t bit = offset / sizeof(void *);
12954 size_t index = bit / 8;
12955 _ASSERTE(index < cbGCRefMap);
12956 pGCRefMap[index] |= (1 << (bit & 7));
12958 offset += sizeof(void *);
12961 } while (cur >= last);
12965 // Type layout check verifies that there was no incompatible change in the value type layout.
12966 // If there was one, we will fall back to JIT instead of using the pre-generated code from the ready to run image.
12967 // This should be rare situation. Changes in value type layout not common.
12969 // The following properties of the value type layout are checked:
12971 // - HFA-ness (on platform that support HFAs)
12973 // - Position of GC references
12975 BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob)
12977 STANDARD_VM_CONTRACT;
12979 SigPointer p(pBlob);
12980 IfFailThrow(p.SkipExactlyOne());
12983 IfFailThrow(p.GetData(&dwFlags));
12985 // Size is checked unconditionally
12986 DWORD dwExpectedSize;
12987 IfFailThrow(p.GetData(&dwExpectedSize));
12989 DWORD dwActualSize = pMT->GetNumInstanceFieldBytes();
12990 if (dwExpectedSize != dwActualSize)
12994 if (dwFlags & READYTORUN_LAYOUT_HFA)
12996 DWORD dwExpectedHFAType;
12997 IfFailThrow(p.GetData(&dwExpectedHFAType));
12999 DWORD dwActualHFAType = pMT->GetHFAType();
13000 if (dwExpectedHFAType != dwActualHFAType)
13009 _ASSERTE(!(dwFlags & READYTORUN_LAYOUT_HFA));
13012 if (dwFlags & READYTORUN_LAYOUT_Alignment)
13014 DWORD dwExpectedAlignment = sizeof(void *);
13015 if (!(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
13017 IfFailThrow(p.GetData(&dwExpectedAlignment));
13020 DWORD dwActualAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
13021 if (dwExpectedAlignment != dwActualAlignment)
13026 if (dwFlags & READYTORUN_LAYOUT_GCLayout)
13028 if (dwFlags & READYTORUN_LAYOUT_GCLayout_Empty)
13030 if (pMT->ContainsPointers())
13035 size_t cbGCRefMap = (dwActualSize / sizeof(TADDR) + 7) / 8;
13036 _ASSERTE(cbGCRefMap > 0);
13038 BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
13040 ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
13042 if (memcmp(pGCRefMap, p.GetPtr(), cbGCRefMap) != 0)
13050 #endif // FEATURE_READYTORUN
13052 BOOL LoadDynamicInfoEntry(Module *currentModule,
13056 STANDARD_VM_CONTRACT;
13058 PCCOR_SIGNATURE pBlob = currentModule->GetNativeFixupBlobData(fixupRva);
13060 BYTE kind = *pBlob++;
13062 Module * pInfoModule = currentModule;
13064 if (kind & ENCODE_MODULE_OVERRIDE)
13066 pInfoModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13067 kind &= ~ENCODE_MODULE_OVERRIDE;
13070 MethodDesc * pMD = NULL;
13072 PCCOR_SIGNATURE pSig;
13081 case ENCODE_MODULE_HANDLE:
13082 result = (size_t)pInfoModule;
13085 case ENCODE_TYPE_HANDLE:
13086 case ENCODE_TYPE_DICTIONARY:
13088 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13090 if (!th.IsTypeDesc())
13092 if (currentModule->IsReadyToRun())
13094 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13095 th.AsMethodTable()->EnsureInstanceActive();
13099 #ifdef FEATURE_WINMD_RESILIENT
13100 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13101 th.AsMethodTable()->EnsureInstanceActive();
13106 result = (size_t)th.AsPtr();
13110 case ENCODE_METHOD_HANDLE:
13111 case ENCODE_METHOD_DICTIONARY:
13113 MethodDesc * pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13115 if (currentModule->IsReadyToRun())
13117 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13118 pMD->EnsureActive();
13121 result = (size_t)pMD;
13125 case ENCODE_FIELD_HANDLE:
13126 result = (size_t) ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13129 #ifndef CROSSGEN_COMPILE
13130 case ENCODE_STRING_HANDLE:
13132 // We need to update strings atomically (due to NoStringInterning attribute). Note
13133 // that modules with string interning dont really need this, as the hash tables have
13134 // their own locking, but dont add more complexity for what will be the non common
13137 // We will have to lock and update the entry. (this is really a double check, where
13138 // the first check is done in the caller of this function)
13139 DWORD rid = CorSigUncompressData(pBlob);
13143 result = (size_t)StringObject::GetEmptyStringRefPtr();
13147 CrstHolder ch(pInfoModule->GetFixupCrst());
13149 if (!CORCOMPILE_IS_POINTER_TAGGED(*entry) && (*entry != NULL))
13151 // We lost the race, just return
13155 // For generic instantiations compiled into the ngen image of some other
13156 // client assembly, we need to ensure that we intern the string
13157 // in the defining assembly.
13158 bool mayNeedToSyncWithFixups = pInfoModule != currentModule;
13160 result = (size_t) pInfoModule->ResolveStringRef(TokenFromRid(rid, mdtString), currentModule->GetDomain(), mayNeedToSyncWithFixups);
13165 case ENCODE_VARARGS_SIG:
13167 mdSignature token = TokenFromRid(
13168 CorSigUncompressData(pBlob),
13171 IfFailThrow(pInfoModule->GetMDImport()->GetSigFromToken(token, &cSig, &pSig));
13177 case ENCODE_VARARGS_METHODREF:
13179 mdSignature token = TokenFromRid(
13180 CorSigUncompressData(pBlob),
13183 LPCSTR szName_Ignore;
13184 IfFailThrow(pInfoModule->GetMDImport()->GetNameAndSigOfMemberRef(token, &pSig, &cSig, &szName_Ignore));
13190 case ENCODE_VARARGS_METHODDEF:
13192 token = TokenFromRid(
13193 CorSigUncompressData(pBlob),
13196 IfFailThrow(pInfoModule->GetMDImport()->GetSigOfMethodDef(token, &cSig, &pSig));
13199 result = (size_t) CORINFO_VARARGS_HANDLE(currentModule->GetVASigCookie(Signature(pSig, cSig)));
13203 // ENCODE_METHOD_NATIVECALLABLE_HANDLE is same as ENCODE_METHOD_ENTRY_DEF_TOKEN
13204 // except for AddrOfCode
13205 case ENCODE_METHOD_NATIVE_ENTRY:
13206 case ENCODE_METHOD_ENTRY_DEF_TOKEN:
13208 mdToken MethodDef = TokenFromRid(CorSigUncompressData(pBlob), mdtMethodDef);
13209 pMD = MemberLoader::GetMethodDescFromMethodDef(pInfoModule, MethodDef, FALSE);
13211 pMD->PrepareForUseAsADependencyOfANativeImage();
13213 if (currentModule->IsReadyToRun())
13215 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13216 pMD->EnsureActive();
13222 case ENCODE_METHOD_ENTRY_REF_TOKEN:
13224 SigTypeContext typeContext;
13225 mdToken MemberRef = TokenFromRid(CorSigUncompressData(pBlob), mdtMemberRef);
13226 FieldDesc * pFD = NULL;
13229 MemberLoader::GetDescFromMemberRef(pInfoModule, MemberRef, &pMD, &pFD, &typeContext, FALSE /* strict metadata checks */, &th);
13230 _ASSERTE(pMD != NULL);
13232 pMD->PrepareForUseAsADependencyOfANativeImage();
13234 if (currentModule->IsReadyToRun())
13236 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13237 pMD->EnsureActive();
13241 #ifdef FEATURE_WINMD_RESILIENT
13242 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13243 pMD->EnsureActive();
13250 case ENCODE_METHOD_ENTRY:
13252 pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13254 if (currentModule->IsReadyToRun())
13256 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13257 pMD->EnsureActive();
13261 if (kind == ENCODE_METHOD_NATIVE_ENTRY)
13263 result = COMDelegate::ConvertToCallback(pMD);
13267 result = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY);
13270 #ifndef _TARGET_ARM_
13271 if (CORCOMPILE_IS_PCODE_TAGGED(result))
13273 // There is a rare case where the function entrypoint may not be aligned. This could happen only for FCalls,
13274 // only on x86 and only if we failed to hardbind the fcall (e.g. ngen image for mscorlib.dll does not exist
13275 // and /nodependencies flag for ngen was used). The function entrypoints should be aligned in all other cases.
13277 // We will wrap the unaligned method entrypoint by funcptr stub with aligned entrypoint.
13278 _ASSERTE(pMD->IsFCall());
13279 result = pMD->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pMD);
13285 case ENCODE_SYNC_LOCK:
13287 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13289 result = (size_t) GetClassSync(th.AsMethodTable());
13293 case ENCODE_INDIRECT_PINVOKE_TARGET:
13295 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13297 _ASSERTE(pMethod->IsNDirect());
13298 NDirectMethodDesc *pMD = (NDirectMethodDesc*)pMethod;
13299 result = (size_t)(LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
13303 #if defined(PROFILING_SUPPORTED)
13304 case ENCODE_PROFILING_HANDLE:
13306 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13308 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
13309 // they shouldnever come here as they are called out in GetCompileFlag
13310 _ASSERTE(!pMethod->IsNoMetadata());
13312 FunctionID funId = (FunctionID)pMethod;
13314 BOOL bHookFunction = TRUE;
13315 CORINFO_PROFILING_HANDLE profilerHandle = (CORINFO_PROFILING_HANDLE)funId;
13318 BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled());
13319 profilerHandle = (CORINFO_PROFILING_HANDLE) g_profControlBlock.pProfInterface->EEFunctionIDMapper(funId, &bHookFunction);
13320 END_PIN_PROFILER();
13323 // Profiling handle is opaque token. It does not have to be aligned thus we can not store it in the same location as token.
13324 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexClientData) = (SIZE_T)profilerHandle;
13328 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER].pfnHelper;
13329 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE].pfnHelper;
13330 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL].pfnHelper;
13334 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13335 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13336 *EnsureWritablePages(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13340 #endif // PROFILING_SUPPORTED
13342 case ENCODE_STATIC_FIELD_ADDRESS:
13344 FieldDesc *pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13346 pField->GetEnclosingMethodTable()->CheckRestore();
13348 // We can take address of RVA field only since ngened code is domain neutral
13349 _ASSERTE(pField->IsRVA());
13351 // Field address is not aligned thus we can not store it in the same location as token.
13352 *EnsureWritablePages(entry+1) = (size_t)pField->GetStaticAddressHandle(NULL);
13356 case ENCODE_VIRTUAL_ENTRY_SLOT:
13358 DWORD slot = CorSigUncompressData(pBlob);
13360 TypeHandle ownerType = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13362 LOG((LF_ZAP, LL_INFO100000, " Fixup stub dispatch\n"));
13364 VirtualCallStubManager * pMgr = currentModule->GetLoaderAllocator()->GetVirtualCallStubManager();
13367 // We should be generating a stub indirection here, but the zapper already uses one level
13368 // of indirection, i.e. we would have to return IAT_PPVALUE to the JIT, and on the whole the JITs
13369 // aren't quite set up to accept that. Furthermore the call sequences would be different - at
13370 // the moment an indirection cell uses "call [cell-addr]" on x86, and instead we would want the
13371 // euqivalent of "call [[call-addr]]". This could perhaps be implemented as "call [eax]" </REVISIT_TODO>
13372 result = pMgr->GetCallStub(ownerType, slot);
13376 case ENCODE_CLASS_ID_FOR_STATICS:
13378 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13380 MethodTable * pMT = th.AsMethodTable();
13381 if (pMT->IsDynamicStatics())
13383 result = pMT->GetModuleDynamicEntryID();
13387 result = pMT->GetClassIndex();
13392 case ENCODE_MODULE_ID_FOR_STATICS:
13394 result = pInfoModule->GetModuleID();
13398 case ENCODE_MODULE_ID_FOR_GENERIC_STATICS:
13400 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13402 MethodTable * pMT = th.AsMethodTable();
13404 result = pMT->GetModuleForStatics()->GetModuleID();
13408 case ENCODE_ACTIVE_DEPENDENCY:
13410 Module* pModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13412 STRESS_LOG3(LF_ZAP,LL_INFO10000,"Modules are: %08x,%08x,%08x",currentModule,pInfoModule,pModule);
13413 pInfoModule->AddActiveDependency(pModule, FALSE);
13417 #ifdef FEATURE_READYTORUN
13418 case ENCODE_READYTORUN_HELPER:
13420 DWORD helperNum = CorSigUncompressData(pBlob);
13422 CorInfoHelpFunc corInfoHelpFunc = MapReadyToRunHelper((ReadyToRunHelper)helperNum);
13423 if (corInfoHelpFunc != CORINFO_HELP_UNDEF)
13425 result = (size_t)CEEJitInfo::getHelperFtnStatic(corInfoHelpFunc);
13431 case READYTORUN_HELPER_Module:
13433 Module * pPrevious = InterlockedCompareExchangeT(EnsureWritablePages((Module **)entry), pInfoModule, NULL);
13434 if (pPrevious != pInfoModule && pPrevious != NULL)
13435 COMPlusThrowHR(COR_E_FILELOAD, IDS_NATIVE_IMAGE_CANNOT_BE_LOADED_MULTIPLE_TIMES, pInfoModule->GetPath());
13440 case READYTORUN_HELPER_GSCookie:
13441 result = (size_t)GetProcessGSCookie();
13444 case READYTORUN_HELPER_DelayLoad_MethodCall:
13445 result = (size_t)GetEEFuncEntryPoint(DelayLoad_MethodCall);
13448 case READYTORUN_HELPER_DelayLoad_Helper:
13449 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper);
13452 case READYTORUN_HELPER_DelayLoad_Helper_Obj:
13453 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_Obj);
13456 case READYTORUN_HELPER_DelayLoad_Helper_ObjObj:
13457 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_ObjObj);
13461 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown READYTORUN_HELPER %d\n", helperNum);
13462 _ASSERTE(!"Unknown READYTORUN_HELPER");
13469 case ENCODE_FIELD_OFFSET:
13471 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13472 _ASSERTE(!pFD->IsStatic());
13473 _ASSERTE(!pFD->IsFieldOfValueType());
13475 DWORD dwOffset = (DWORD)sizeof(Object) + pFD->GetOffset();
13477 if (dwOffset > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13483 case ENCODE_FIELD_BASE_OFFSET:
13485 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13487 MethodTable * pMT = th.AsMethodTable();
13488 _ASSERTE(!pMT->IsValueType());
13490 DWORD dwOffsetBase = ReadyToRunInfo::GetFieldBaseOffset(pMT);
13491 if (dwOffsetBase > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13493 result = dwOffsetBase;
13497 case ENCODE_CHECK_TYPE_LAYOUT:
13499 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13500 MethodTable * pMT = th.AsMethodTable();
13501 _ASSERTE(pMT->IsValueType());
13503 if (!TypeLayoutCheck(pMT, pBlob))
13510 case ENCODE_CHECK_FIELD_OFFSET:
13512 DWORD dwExpectedOffset = CorSigUncompressData(pBlob);
13514 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13515 _ASSERTE(!pFD->IsStatic());
13517 DWORD dwOffset = pFD->GetOffset();
13518 if (!pFD->IsFieldOfValueType())
13519 dwOffset += sizeof(Object);
13521 if (dwExpectedOffset != dwOffset)
13527 #endif // FEATURE_READYTORUN
13529 #endif // CROSSGEN_COMPILE
13532 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown FIXUP_BLOB_KIND %d\n", kind);
13533 _ASSERTE(!"Unknown FIXUP_BLOB_KIND");
13538 *EnsureWritablePages(entry) = result;
13542 #endif // FEATURE_PREJIT
13544 void* CEEInfo::getTailCallCopyArgsThunk(CORINFO_SIG_INFO *pSig,
13545 CorInfoHelperTailCallSpecialHandling flags)
13556 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_)
13558 JIT_TO_EE_TRANSITION();
13560 Stub* pStub = CPUSTUBLINKER::CreateTailCallCopyArgsThunk(pSig, flags);
13562 ftn = (void*)pStub->GetEntryPoint();
13564 EE_TO_JIT_TRANSITION();
13566 #endif // _TARGET_AMD64_ || _TARGET_ARM_
13571 void CEEInfo::allocMem (
13572 ULONG hotCodeSize, /* IN */
13573 ULONG coldCodeSize, /* IN */
13574 ULONG roDataSize, /* IN */
13575 ULONG xcptnsCount, /* IN */
13576 CorJitAllocMemFlag flag, /* IN */
13577 void ** hotCodeBlock, /* OUT */
13578 void ** coldCodeBlock, /* OUT */
13579 void ** roDataBlock /* OUT */
13582 LIMITED_METHOD_CONTRACT;
13583 UNREACHABLE(); // only called on derived class.
13586 void CEEInfo::reserveUnwindInfo (
13587 BOOL isFunclet, /* IN */
13588 BOOL isColdCode, /* IN */
13589 ULONG unwindSize /* IN */
13592 LIMITED_METHOD_CONTRACT;
13593 UNREACHABLE(); // only called on derived class.
13596 void CEEInfo::allocUnwindInfo (
13597 BYTE * pHotCode, /* IN */
13598 BYTE * pColdCode, /* IN */
13599 ULONG startOffset, /* IN */
13600 ULONG endOffset, /* IN */
13601 ULONG unwindSize, /* IN */
13602 BYTE * pUnwindBlock, /* IN */
13603 CorJitFuncKind funcKind /* IN */
13606 LIMITED_METHOD_CONTRACT;
13607 UNREACHABLE(); // only called on derived class.
13610 void * CEEInfo::allocGCInfo (
13611 size_t size /* IN */
13614 LIMITED_METHOD_CONTRACT;
13615 UNREACHABLE_RET(); // only called on derived class.
13618 void CEEInfo::setEHcount (
13619 unsigned cEH /* IN */
13622 LIMITED_METHOD_CONTRACT;
13623 UNREACHABLE(); // only called on derived class.
13626 void CEEInfo::setEHinfo (
13627 unsigned EHnumber, /* IN */
13628 const CORINFO_EH_CLAUSE *clause /* IN */
13631 LIMITED_METHOD_CONTRACT;
13632 UNREACHABLE(); // only called on derived class.
13635 InfoAccessType CEEInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
13639 LIMITED_METHOD_CONTRACT;
13640 UNREACHABLE(); // only called on derived class.
13643 InfoAccessType CEEInfo::emptyStringLiteral(void ** ppValue)
13645 LIMITED_METHOD_CONTRACT;
13646 _ASSERTE(isVerifyOnly());
13647 *ppValue = (void *)0x10;
13651 void* CEEInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd,
13652 void **ppIndirection)
13654 LIMITED_METHOD_CONTRACT;
13655 _ASSERTE(isVerifyOnly());
13656 if (ppIndirection != NULL)
13657 *ppIndirection = NULL;
13658 return (void *)0x10;
13661 void* CEEInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
13662 void **ppIndirection)
13664 LIMITED_METHOD_CONTRACT;
13665 UNREACHABLE(); // only called on derived class.
13668 HRESULT CEEInfo::allocBBProfileBuffer (
13669 ULONG count, // The number of basic blocks that we have
13670 ProfileBuffer ** profileBuffer
13673 LIMITED_METHOD_CONTRACT;
13674 UNREACHABLE_RET(); // only called on derived class.
13677 HRESULT CEEInfo::getBBProfileData(
13678 CORINFO_METHOD_HANDLE ftnHnd,
13679 ULONG * count, // The number of basic blocks that we have
13680 ProfileBuffer ** profileBuffer,
13684 LIMITED_METHOD_CONTRACT;
13685 UNREACHABLE_RET(); // only called on derived class.
13689 void CEEInfo::recordCallSite(
13690 ULONG instrOffset, /* IN */
13691 CORINFO_SIG_INFO * callSig, /* IN */
13692 CORINFO_METHOD_HANDLE methodHandle /* IN */
13695 LIMITED_METHOD_CONTRACT;
13696 UNREACHABLE(); // only called on derived class.
13699 void CEEInfo::recordRelocation(
13700 void * location, /* IN */
13701 void * target, /* IN */
13702 WORD fRelocType, /* IN */
13703 WORD slotNum, /* IN */
13704 INT32 addlDelta /* IN */
13707 LIMITED_METHOD_CONTRACT;
13708 UNREACHABLE(); // only called on derived class.
13711 WORD CEEInfo::getRelocTypeHint(void * target)
13713 LIMITED_METHOD_CONTRACT;
13714 UNREACHABLE_RET(); // only called on derived class.
13717 void CEEInfo::getModuleNativeEntryPointRange(
13718 void ** pStart, /* OUT */
13719 void ** pEnd /* OUT */
13722 LIMITED_METHOD_CONTRACT;
13723 UNREACHABLE(); // only called on derived class.
13726 DWORD CEEInfo::getExpectedTargetArchitecture()
13728 LIMITED_METHOD_CONTRACT;
13730 return IMAGE_FILE_MACHINE_NATIVE;
13733 void CEEInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
13734 ICorDebugInfo::OffsetMapping *pMap)
13736 LIMITED_METHOD_CONTRACT;
13737 UNREACHABLE(); // only called on derived class.
13740 void CEEInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
13742 LIMITED_METHOD_CONTRACT;
13743 UNREACHABLE(); // only called on derived class.
13746 void* CEEInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
13747 void ** ppIndirection) /* OUT */
13749 LIMITED_METHOD_CONTRACT;
13750 UNREACHABLE(); // only called on derived class.
13753 // Active dependency helpers
13754 void CEEInfo::addActiveDependency(CORINFO_MODULE_HANDLE moduleFrom,CORINFO_MODULE_HANDLE moduleTo)
13756 LIMITED_METHOD_CONTRACT;
13757 UNREACHABLE(); // only called on derived class.
13760 void CEEInfo::GetProfilingHandle(BOOL *pbHookFunction,
13761 void **pProfilerHandle,
13762 BOOL *pbIndirectedHandles)
13764 LIMITED_METHOD_CONTRACT;
13765 UNREACHABLE(); // only called on derived class.
13768 #endif // !DACCESS_COMPILE
13770 EECodeInfo::EECodeInfo()
13772 WRAPPER_NO_CONTRACT;
13774 m_codeAddress = NULL;
13780 #ifdef WIN64EXCEPTIONS
13781 m_pFunctionEntry = NULL;
13785 void EECodeInfo::Init(PCODE codeAddress)
13793 Init(codeAddress, ExecutionManager::GetScanFlags());
13796 void EECodeInfo::Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag)
13804 m_codeAddress = codeAddress;
13806 RangeSection * pRS = ExecutionManager::FindCodeRange(codeAddress, scanFlag);
13810 if (!pRS->pjit->JitCodeToMethodInfo(pRS, codeAddress, &m_pMD, this))
13821 #ifdef WIN64EXCEPTIONS
13822 m_pFunctionEntry = NULL;
13826 TADDR EECodeInfo::GetSavedMethodCode()
13829 // All EECodeInfo methods must be NOTHROW/GC_NOTRIGGER since they can
13830 // be used during GC.
13837 #if defined(HAVE_GCCOVER)
13838 _ASSERTE (!m_pMD->m_GcCover || GCStress<cfg_instr>::IsEnabled());
13839 if (GCStress<cfg_instr>::IsEnabled()
13840 && m_pMD->m_GcCover)
13842 _ASSERTE(m_pMD->m_GcCover->savedCode);
13844 // Make sure we return the TADDR of savedCode here. The byte array is not marshaled automatically.
13845 // The caller is responsible for any necessary marshaling.
13846 return PTR_TO_MEMBER_TADDR(GCCoverageInfo, m_pMD->m_GcCover, savedCode);
13848 #endif //defined(HAVE_GCCOVER)
13851 return GetStartAddress();
13854 TADDR EECodeInfo::GetStartAddress()
13863 return m_pJM->JitTokenToStartAddress(m_methodToken);
13866 #if defined(WIN64EXCEPTIONS)
13868 // ----------------------------------------------------------------------------
13869 // EECodeInfo::GetMainFunctionInfo
13872 // Simple helper to transform a funclet's EECodeInfo into a parent function EECodeInfo.
13875 // An EECodeInfo for the start of the main function body (offset 0).
13878 EECodeInfo EECodeInfo::GetMainFunctionInfo()
13880 LIMITED_METHOD_CONTRACT;
13883 EECodeInfo result = *this;
13884 result.m_relOffset = 0;
13885 result.m_codeAddress = this->GetStartAddress();
13886 result.m_pFunctionEntry = NULL;
13891 PTR_RUNTIME_FUNCTION EECodeInfo::GetFunctionEntry()
13893 LIMITED_METHOD_CONTRACT;
13896 if (m_pFunctionEntry == NULL)
13897 m_pFunctionEntry = m_pJM->LazyGetFunctionEntry(this);
13898 return m_pFunctionEntry;
13901 #if defined(_TARGET_AMD64_)
13903 BOOL EECodeInfo::HasFrameRegister()
13905 LIMITED_METHOD_CONTRACT;
13907 PTR_RUNTIME_FUNCTION pFuncEntry = GetFunctionEntry();
13908 _ASSERTE(pFuncEntry != NULL);
13910 BOOL fHasFrameRegister = FALSE;
13911 PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(GetModuleBase() + pFuncEntry->UnwindData);
13912 if (pUnwindInfo->FrameRegister != 0)
13914 fHasFrameRegister = TRUE;
13915 _ASSERTE(pUnwindInfo->FrameRegister == kRBP);
13918 return fHasFrameRegister;
13920 #endif // defined(_TARGET_AMD64_)
13922 #endif // defined(WIN64EXCEPTIONS)
13925 #if defined(_TARGET_AMD64_)
13926 // ----------------------------------------------------------------------------
13927 // EECodeInfo::GetUnwindInfoHelper
13930 // Simple helper to return a pointer to the UNWIND_INFO given the offset to the unwind info.
13931 // On DAC builds, this function will read the memory from the target process and create a host copy.
13934 // * unwindInfoOffset - This is the offset to the unwind info, relative to the beginning of the code heap
13935 // for jitted code or to the module base for ngned code. this->GetModuleBase() will return the correct
13939 // Return a pointer to the UNWIND_INFO. On DAC builds, this function will create a host copy of the
13940 // UNWIND_INFO and return a host pointer. It will correctly read all of the memory for the variable-sized
13944 UNWIND_INFO * EECodeInfo::GetUnwindInfoHelper(ULONG unwindInfoOffset)
13946 #if defined(DACCESS_COMPILE)
13947 return DacGetUnwindInfo(static_cast<TADDR>(this->GetModuleBase() + unwindInfoOffset));
13948 #else // !DACCESS_COMPILE
13949 return reinterpret_cast<UNWIND_INFO *>(this->GetModuleBase() + unwindInfoOffset);
13950 #endif // !DACCESS_COMPILE
13953 // ----------------------------------------------------------------------------
13954 // EECodeInfo::GetFixedStackSize
13957 // Return the fixed stack size of a specified managed method. This function DOES NOT take current control
13958 // PC into account. So the fixed stack size returned by this function is not valid in the prolog or
13962 // Return the fixed stack size.
13965 // * For method with dynamic stack allocations, this function will return the fixed stack size on X64 (the
13966 // stack size immediately after the prolog), and it will return 0 on IA64. This difference is due to
13967 // the different unwind info encoding.
13970 ULONG EECodeInfo::GetFixedStackSize()
13972 WRAPPER_NO_CONTRACT;
13975 ULONG uFixedStackSize = 0;
13978 GetOffsetsFromUnwindInfo(&uFixedStackSize, &uDummy);
13980 return uFixedStackSize;
13984 // The information returned by this method is only valid if we are not in a prolog or an epilog.
13985 // Since this method is only used for the security stackwalk cache, this assumption is valid, since
13986 // we cannot make a call in a prolog or an epilog.
13988 // The next assumption is that only rbp is used as a frame register in jitted code. There is an
13989 // assert below to guard this assumption.
13990 void EECodeInfo::GetOffsetsFromUnwindInfo(ULONG* pRSPOffset, ULONG* pRBPOffset)
13992 LIMITED_METHOD_CONTRACT;
13995 _ASSERTE((pRSPOffset != NULL) && (pRBPOffset != NULL));
13997 // moduleBase is a target address.
13998 TADDR moduleBase = GetModuleBase();
14000 DWORD unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(GetFunctionEntry());
14002 if ((unwindInfo & RUNTIME_FUNCTION_INDIRECT) != 0)
14004 unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(PTR_RUNTIME_FUNCTION(moduleBase + (unwindInfo & ~RUNTIME_FUNCTION_INDIRECT)));
14007 UNWIND_INFO * pInfo = GetUnwindInfoHelper(unwindInfo);
14008 if (pInfo->Flags & UNW_FLAG_CHAININFO)
14010 _ASSERTE(!"GetRbpOffset() - chained unwind info used, violating assumptions of the security stackwalk cache");
14014 // Either we are not using a frame pointer, or we are using rbp as the frame pointer.
14015 if ( (pInfo->FrameRegister != 0) && (pInfo->FrameRegister != kRBP) )
14017 _ASSERTE(!"GetRbpOffset() - non-RBP frame pointer used, violating assumptions of the security stackwalk cache");
14021 // Walk the unwind info.
14022 ULONG StackOffset = 0;
14023 ULONG StackSize = 0;
14024 for (int i = 0; i < pInfo->CountOfUnwindCodes; i++)
14026 ULONG UnwindOp = pInfo->UnwindCode[i].UnwindOp;
14027 ULONG OpInfo = pInfo->UnwindCode[i].OpInfo;
14029 if (UnwindOp == UWOP_SAVE_NONVOL)
14031 if (OpInfo == kRBP)
14033 StackOffset = pInfo->UnwindCode[i+1].FrameOffset * 8;
14036 else if (UnwindOp == UWOP_SAVE_NONVOL_FAR)
14038 if (OpInfo == kRBP)
14040 StackOffset = pInfo->UnwindCode[i + 1].FrameOffset;
14041 StackOffset += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14044 else if (UnwindOp == UWOP_ALLOC_SMALL)
14046 StackSize += (OpInfo * 8) + 8;
14048 else if (UnwindOp == UWOP_ALLOC_LARGE)
14050 ULONG IncrementalStackSize = pInfo->UnwindCode[i + 1].FrameOffset;
14053 IncrementalStackSize *= 8;
14057 IncrementalStackSize += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14059 // This is a special opcode. We need to increment the index by 1 in addition to the normal adjustments.
14062 StackSize += IncrementalStackSize;
14064 else if (UnwindOp == UWOP_PUSH_NONVOL)
14066 // Because of constraints on epilogs, this unwind opcode is always last in the unwind code array.
14067 // This means that StackSize has been initialized already when we first see this unwind opcode.
14068 // Note that the intial value of StackSize does not include the stack space used for pushes.
14069 // Thus, here we only need to increment StackSize 8 bytes at a time until we see the unwind code for "push rbp".
14070 if (OpInfo == kRBP)
14072 StackOffset = StackSize;
14078 // Adjust the index into the unwind code array.
14079 i += UnwindOpExtraSlotTable[UnwindOp];
14082 *pRSPOffset = StackSize + 8; // add 8 for the return address
14083 *pRBPOffset = StackOffset;
14088 #if defined(_DEBUG) && defined(HAVE_GCCOVER)
14090 LPVOID EECodeInfo::findNextFunclet (LPVOID pvFuncletStart, SIZE_T cbCode, LPVOID *ppvFuncletEnd)
14099 PT_RUNTIME_FUNCTION pFunctionEntry;
14100 ULONGLONG uImageBase;
14102 EECodeInfo codeInfo;
14103 codeInfo.Init((PCODE)pvFuncletStart);
14104 pFunctionEntry = codeInfo.GetFunctionEntry();
14105 uImageBase = (ULONGLONG)codeInfo.GetModuleBase();
14106 #else // !FEATURE_PAL
14108 // This is GCStress debug only - use the slow OS APIs to enumerate funclets
14111 pFunctionEntry = (PT_RUNTIME_FUNCTION) RtlLookupFunctionEntry((ULONGLONG)pvFuncletStart,
14117 if (pFunctionEntry != NULL)
14119 #ifdef FEATURE_PREJIT
14120 // workaround: Check for indirect entry that is generated for cold part of main method body.
14121 if ((TADDR)pvFuncletStart < (TADDR)uImageBase + pFunctionEntry->BeginAddress ||
14122 (TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart)
14124 Module * pZapModule = ExecutionManager::FindZapModule((TADDR)pvFuncletStart);
14125 NGenLayoutInfo * pLayoutInfo = pZapModule->GetNGenLayoutInfo();
14127 int ColdFunctionIndex = NativeUnwindInfoLookupTable::LookupUnwindInfoForMethod((DWORD)((TADDR)pvFuncletStart - uImageBase),
14128 pLayoutInfo->m_pRuntimeFunctions[2],
14129 0, pLayoutInfo->m_nRuntimeFunctions[2] - 1);
14131 pFunctionEntry = pLayoutInfo->m_pRuntimeFunctions[2] + ColdFunctionIndex;
14135 _ASSERTE((TADDR)pvFuncletStart == (TADDR)uImageBase + pFunctionEntry->BeginAddress);
14136 _ASSERTE((TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart + cbCode);
14137 *ppvFuncletEnd = (LPVOID)(uImageBase + pFunctionEntry->EndAddress);
14138 return (LPVOID)(uImageBase + pFunctionEntry->BeginAddress);
14141 pvFuncletStart = (LPVOID)((TADDR)pvFuncletStart + 1);
14147 #endif // defined(_DEBUG) && !defined(HAVE_GCCOVER)
14148 #endif // defined(_TARGET_AMD64_)