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 // ===========================================================================
4 // File: JITinterface.CPP
7 // ===========================================================================
10 #include "jitinterface.h"
17 #include "virtualcallstub.h"
23 #include "float.h" // for isnan
24 #include "dbginterface.h"
25 #include "dllimport.h"
26 #include "callconvbuilder.hpp"
27 #include "gcheaputilities.h"
28 #include "comdelegate.h"
30 #include "eeprofinterfaces.h"
31 #ifdef PROFILING_SUPPORTED
32 #include "proftoeeinterfaceimpl.h"
33 #include "eetoprofinterfaceimpl.h"
34 #include "eetoprofinterfaceimpl.inl"
35 #include "profilepriv.h"
37 #endif // PROFILING_SUPPORTED
40 #include "typestring.h"
42 #include "genericdict.h"
44 #include "debuginfostore.h"
46 #include "runtimehandles.h"
47 #include "sigbuilder.h"
49 #include "fieldmarshaler.h"
52 #endif // HAVE_GCCOVER
54 #ifdef FEATURE_INTERPRETER
55 #include "interpreter.h"
56 #endif // FEATURE_INTERPRETER
58 #ifdef FEATURE_PERFMAP
66 #include "tailcallhelp.h"
69 EXTERN_C uint32_t _tls_index;
72 struct ThreadStaticBlockInfo
74 uint32_t NonGCMaxThreadStaticBlocks;
75 void** NonGCThreadStaticBlocks;
77 uint32_t GCMaxThreadStaticBlocks;
78 void** GCThreadStaticBlocks;
81 __declspec(selectany) __declspec(thread) ThreadStaticBlockInfo t_ThreadStatics;
82 __declspec(selectany) __declspec(thread) uint32_t t_NonGCThreadStaticBlocksSize;
83 __declspec(selectany) __declspec(thread) uint32_t t_GCThreadStaticBlocksSize;
85 extern "C" void* __tls_get_addr(void* ti);
86 __thread ThreadStaticBlockInfo t_ThreadStatics;
87 __thread uint32_t t_NonGCThreadStaticBlocksSize;
88 __thread uint32_t t_GCThreadStaticBlocksSize;
91 // The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro
94 #define JIT_TO_EE_TRANSITION() MAKE_CURRENT_THREAD_AVAILABLE_EX(m_pThread); \
95 INSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE; \
96 COOPERATIVE_TRANSITION_BEGIN(); \
98 #define EE_TO_JIT_TRANSITION() COOPERATIVE_TRANSITION_END(); \
99 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER_NO_PROBE;
101 #define JIT_TO_EE_TRANSITION_LEAF()
102 #define EE_TO_JIT_TRANSITION_LEAF()
104 #ifdef DACCESS_COMPILE
106 // The real definitions are in jithelpers.cpp. However, those files are not included in the DAC build.
107 // Hence, we add them here.
108 GARY_IMPL(VMHELPDEF, hlpFuncTable, CORINFO_HELP_COUNT);
109 GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);
111 #else // DACCESS_COMPILE
113 Volatile<int64_t> g_cbILJitted = 0;
114 Volatile<int64_t> g_cMethodsJitted = 0;
115 Volatile<int64_t> g_c100nsTicksInJit = 0;
116 thread_local int64_t t_cbILJittedForThread = 0;
117 thread_local int64_t t_cMethodsJittedForThread = 0;
118 thread_local int64_t t_c100nsTicksInJitForThread = 0;
120 // This prevents tearing of 64 bit values on 32 bit systems
122 int64_t AtomicLoad64WithoutTearing(int64_t volatile *valueRef)
126 return VolatileLoad(valueRef);
128 return InterlockedCompareExchangeT((LONG64 volatile *)valueRef, (LONG64)0, (LONG64)0);
129 #endif // TARGET_64BIT
132 FCIMPL1(INT64, GetCompiledILBytes, CLR_BOOL currentThread)
136 return currentThread ? t_cbILJittedForThread : AtomicLoad64WithoutTearing(&g_cbILJitted);
140 FCIMPL1(INT64, GetCompiledMethodCount, CLR_BOOL currentThread)
144 return currentThread ? t_cMethodsJittedForThread : AtomicLoad64WithoutTearing(&g_cMethodsJitted);
148 FCIMPL1(INT64, GetCompilationTimeInTicks, CLR_BOOL currentThread)
152 return currentThread ? t_c100nsTicksInJitForThread : AtomicLoad64WithoutTearing(&g_c100nsTicksInJit);
156 /*********************************************************************/
158 inline CORINFO_MODULE_HANDLE GetScopeHandle(MethodDesc* method)
160 LIMITED_METHOD_CONTRACT;
161 if (method->IsDynamicMethod())
163 return MakeDynamicScope(method->AsDynamicMethodDesc()->GetResolver());
167 return GetScopeHandle(method->GetModule());
171 //This is common refactored code from within several of the access check functions.
172 static BOOL ModifyCheckForDynamicMethod(DynamicResolver *pResolver,
173 TypeHandle *pOwnerTypeForSecurity,
174 AccessCheckOptions::AccessCheckType *pAccessCheckType,
175 DynamicResolver** ppAccessContext)
179 PRECONDITION(CheckPointer(pResolver));
180 PRECONDITION(CheckPointer(pOwnerTypeForSecurity));
181 PRECONDITION(CheckPointer(pAccessCheckType));
182 PRECONDITION(CheckPointer(ppAccessContext));
183 PRECONDITION(*pAccessCheckType == AccessCheckOptions::kNormalAccessibilityChecks);
186 BOOL doAccessCheck = TRUE;
188 //Do not blindly initialize fields, since they've already got important values.
189 DynamicResolver::SecurityControlFlags dwSecurityFlags = DynamicResolver::Default;
191 TypeHandle dynamicOwner;
192 pResolver->GetJitContext(&dwSecurityFlags, &dynamicOwner);
193 if (!dynamicOwner.IsNull())
194 *pOwnerTypeForSecurity = dynamicOwner;
196 if (dwSecurityFlags & DynamicResolver::SkipVisibilityChecks)
198 doAccessCheck = FALSE;
200 else if (dwSecurityFlags & DynamicResolver::RestrictedSkipVisibilityChecks)
202 *pAccessCheckType = AccessCheckOptions::kRestrictedMemberAccessNoTransparency;
206 *pAccessCheckType = AccessCheckOptions::kNormalAccessNoTransparency;
209 return doAccessCheck;
212 TransientMethodDetails::TransientMethodDetails(MethodDesc* pMD, _In_opt_ COR_ILMETHOD_DECODER* header, CORINFO_MODULE_HANDLE scope)
217 LIMITED_METHOD_CONTRACT;
218 _ASSERTE(Method != NULL);
219 _ASSERTE(Scope == NULL || IsDynamicScope(Scope));
222 TransientMethodDetails::TransientMethodDetails(TransientMethodDetails&& other)
224 LIMITED_METHOD_CONTRACT;
225 *this = std::move(other);
228 TransientMethodDetails::~TransientMethodDetails()
238 // If the supplied scope is dynamic, release resources.
239 if (IsDynamicScope(Scope))
241 DynamicResolver* resolver = GetDynamicResolver(Scope);
242 resolver->FreeCompileTimeState();
247 TransientMethodDetails& TransientMethodDetails::operator=(TransientMethodDetails&& other)
249 LIMITED_METHOD_CONTRACT;
252 Method = other.Method;
253 Header = other.Header;
262 /*****************************************************************************/
264 // Initialize from data we passed across to the JIT
265 void CEEInfo::GetTypeContext(const CORINFO_SIG_INST *info, SigTypeContext *pTypeContext)
267 LIMITED_METHOD_CONTRACT;
268 SigTypeContext::InitTypeContext(
269 Instantiation((TypeHandle *) info->classInst, info->classInstCount),
270 Instantiation((TypeHandle *) info->methInst, info->methInstCount),
274 MethodDesc* CEEInfo::GetMethodFromContext(CORINFO_CONTEXT_HANDLE context)
276 LIMITED_METHOD_CONTRACT;
278 if (context == METHOD_BEING_COMPILED_CONTEXT())
279 return m_pMethodBeingCompiled;
281 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
287 return GetMethod((CORINFO_METHOD_HANDLE)((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
291 TypeHandle CEEInfo::GetTypeFromContext(CORINFO_CONTEXT_HANDLE context)
293 LIMITED_METHOD_CONTRACT;
295 if (context == METHOD_BEING_COMPILED_CONTEXT())
296 return m_pMethodBeingCompiled->GetMethodTable();
298 if (((size_t) context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
300 return TypeHandle((CORINFO_CLASS_HANDLE) ((size_t) context & ~CORINFO_CONTEXTFLAGS_MASK));
304 return GetMethod((CORINFO_METHOD_HANDLE)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK))->GetMethodTable();
308 // Initialize from a context parameter passed to the JIT and back. This is a parameter
309 // that indicates which method is being jitted.
311 void CEEInfo::GetTypeContext(CORINFO_CONTEXT_HANDLE context, SigTypeContext *pTypeContext)
318 PRECONDITION(context != NULL);
321 MethodDesc* pMD = GetMethodFromContext(context);
324 SigTypeContext::InitTypeContext(pMD, pTypeContext);
328 SigTypeContext::InitTypeContext(GetTypeFromContext(context), pTypeContext);
332 /*********************************************************************/
333 // This normalizes EE type information into the form expected by the JIT.
335 // If typeHnd contains exact type information, then *clsRet will contain
336 // the normalized CORINFO_CLASS_HANDLE information on return.
339 CorInfoType CEEInfo::asCorInfoType(CorElementType eeType,
340 TypeHandle typeHnd, /* optional in */
341 CORINFO_CLASS_HANDLE *clsRet/* optional out */ ) {
342 CONTRACT(CorInfoType) {
345 PRECONDITION((CorTypeInfo::IsGenericVariable(eeType)) ==
346 (!typeHnd.IsNull() && typeHnd.IsGenericVariable()));
347 PRECONDITION(eeType != ELEMENT_TYPE_GENERICINST);
350 TypeHandle typeHndUpdated = typeHnd;
352 if (!typeHnd.IsNull())
354 CorElementType normType = typeHnd.GetInternalCorElementType();
355 // If we have a type handle, then it has the better type
357 if (eeType == ELEMENT_TYPE_VALUETYPE && !CorTypeInfo::IsObjRef(normType))
360 // Zap the typeHnd when the type _really_ is a primitive
361 // as far as verification is concerned. Returning a null class
362 // handle means it is a primitive.
364 // Enums are exactly like primitives, even from a verification standpoint,
365 // so we zap the type handle in this case.
367 // However RuntimeTypeHandle etc. are reported as E_T_INT (or something like that)
368 // but don't count as primitives as far as verification is concerned...
370 // To make things stranger, TypedReference returns true for "IsTruePrimitive".
371 // However the JIT likes us to report the type handle in that case.
372 if (!typeHnd.IsTypeDesc() && (
373 (typeHnd.AsMethodTable()->IsTruePrimitive() && typeHnd != TypeHandle(g_TypedReferenceMT))
374 || typeHnd.AsMethodTable()->IsEnum()) )
376 typeHndUpdated = TypeHandle();
381 static const BYTE map[] = {
397 CORINFO_TYPE_PTR, // PTR
399 CORINFO_TYPE_VALUECLASS,
401 CORINFO_TYPE_VAR, // VAR (type variable)
402 CORINFO_TYPE_CLASS, // ARRAY
403 CORINFO_TYPE_CLASS, // WITH
405 CORINFO_TYPE_UNDEF, // VALUEARRAY_UNSUPPORTED
406 CORINFO_TYPE_NATIVEINT, // I
407 CORINFO_TYPE_NATIVEUINT, // U
408 CORINFO_TYPE_UNDEF, // R_UNSUPPORTED
410 // put the correct type when we know our implementation
411 CORINFO_TYPE_PTR, // FNPTR
412 CORINFO_TYPE_CLASS, // OBJECT
413 CORINFO_TYPE_CLASS, // SZARRAY
414 CORINFO_TYPE_VAR, // MVAR
416 CORINFO_TYPE_UNDEF, // CMOD_REQD
417 CORINFO_TYPE_UNDEF, // CMOD_OPT
418 CORINFO_TYPE_UNDEF, // INTERNAL
421 _ASSERTE(sizeof(map) == ELEMENT_TYPE_MAX);
422 _ASSERTE(eeType < (CorElementType) sizeof(map));
423 // spot check of the map
424 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_I4] == CORINFO_TYPE_INT);
425 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_PTR] == CORINFO_TYPE_PTR);
426 _ASSERTE((CorInfoType) map[ELEMENT_TYPE_TYPEDBYREF] == CORINFO_TYPE_REFANY);
428 CorInfoType res = ((unsigned)eeType < ELEMENT_TYPE_MAX) ? ((CorInfoType) map[(unsigned)eeType]) : CORINFO_TYPE_UNDEF;
431 *clsRet = CORINFO_CLASS_HANDLE(typeHndUpdated.AsPtr());
437 inline static CorInfoType toJitType(TypeHandle typeHnd, CORINFO_CLASS_HANDLE *clsRet = NULL)
440 return CEEInfo::asCorInfoType(typeHnd.GetInternalCorElementType(), typeHnd, clsRet);
443 enum ConvToJitSigFlags : int
445 CONV_TO_JITSIG_FLAGS_NONE = 0x0,
446 CONV_TO_JITSIG_FLAGS_LOCALSIG = 0x1,
449 //---------------------------------------------------------------------------------------
452 // The method handle is used to instantiate method and class type parameters
453 // It's also used to determine whether an extra dictionary parameter is required
455 // sig - Input metadata signature
456 // scopeHnd - The signature is to be interpreted in the context of this scope (module)
457 // token - Metadata token used to refer to the signature (may be mdTokenNil for dynamic methods)
458 // sigRet - Resulting output signature in a format that is understood by native compilers
459 // pContextMD - The method with any instantiation information (may be NULL)
460 // localSig - Is it a local variables declaration, or a method signature (with return type, etc).
461 // contextType - The type with any instantiaton information
463 static void ConvToJitSig(
464 PCCOR_SIGNATURE pSig,
466 CORINFO_MODULE_HANDLE scopeHnd,
468 SigTypeContext* typeContext,
469 ConvToJitSigFlags flags,
470 CORINFO_SIG_INFO * sigRet)
477 uint32_t sigRetFlags = 0;
479 static_assert_no_msg(CORINFO_CALLCONV_DEFAULT == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_DEFAULT);
480 static_assert_no_msg(CORINFO_CALLCONV_VARARG == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_VARARG);
481 static_assert_no_msg(CORINFO_CALLCONV_MASK == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_MASK);
482 static_assert_no_msg(CORINFO_CALLCONV_HASTHIS == (CorInfoCallConv) IMAGE_CEE_CS_CALLCONV_HASTHIS);
484 TypeHandle typeHnd = TypeHandle();
487 sigRet->cbSig = cbSig;
488 sigRet->methodSignature = 0;
489 sigRet->retTypeClass = 0;
490 sigRet->retTypeSigClass = 0;
491 sigRet->scope = scopeHnd;
492 sigRet->token = token;
493 sigRet->sigInst.classInst = (CORINFO_CLASS_HANDLE *) typeContext->m_classInst.GetRawArgs();
494 sigRet->sigInst.classInstCount = (unsigned) typeContext->m_classInst.GetNumArgs();
495 sigRet->sigInst.methInst = (CORINFO_CLASS_HANDLE *) typeContext->m_methodInst.GetRawArgs();
496 sigRet->sigInst.methInstCount = (unsigned) typeContext->m_methodInst.GetNumArgs();
498 SigPointer sig(pSig, cbSig);
500 if ((flags & CONV_TO_JITSIG_FLAGS_LOCALSIG) == 0)
502 // This is a method signature which includes calling convention, return type,
505 _ASSERTE(!sig.IsNull());
506 Module * module = GetModule(scopeHnd);
509 IfFailThrow(sig.GetCallingConvInfo(&data));
510 sigRet->callConv = (CorInfoCallConv) data;
512 #if defined(TARGET_UNIX) || defined(TARGET_ARM)
513 if ((isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_VARARG)) ||
514 (isCallConv(sigRet->callConv, IMAGE_CEE_CS_CALLCONV_NATIVEVARARG)))
516 // This signature corresponds to a method that uses varargs, which are not supported.
517 COMPlusThrow(kInvalidProgramException, IDS_EE_VARARG_NOT_SUPPORTED);
519 #endif // defined(TARGET_UNIX) || defined(TARGET_ARM)
521 // Skip number of type arguments
522 if (sigRet->callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
523 IfFailThrow(sig.GetData(NULL));
526 IfFailThrow(sig.GetData(&numArgs));
527 if (numArgs != (unsigned short) numArgs)
528 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
530 sigRet->numArgs = (unsigned short) numArgs;
532 CorElementType type = sig.PeekElemTypeClosed(module, typeContext);
534 if (!CorTypeInfo::IsPrimitiveType(type))
536 typeHnd = sig.GetTypeHandleThrowing(module, typeContext);
537 _ASSERTE(!typeHnd.IsNull());
539 // I believe it doesn't make any diff. if this is
540 // GetInternalCorElementType or GetSignatureCorElementType
541 type = typeHnd.GetSignatureCorElementType();
544 sigRet->retType = CEEInfo::asCorInfoType(type, typeHnd, &sigRet->retTypeClass);
545 sigRet->retTypeSigClass = CORINFO_CLASS_HANDLE(typeHnd.AsPtr());
547 IfFailThrow(sig.SkipExactlyOne()); // must to a skip so we skip any class tokens associated with the return type
548 _ASSERTE(sigRet->retType < CORINFO_TYPE_COUNT);
550 sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
554 // This is local variables declaration
555 sigRetFlags |= CORINFO_SIGFLAG_IS_LOCAL_SIG;
557 sigRet->callConv = CORINFO_CALLCONV_DEFAULT;
558 sigRet->retType = CORINFO_TYPE_VOID;
563 IfFailThrow(sig.GetCallingConvInfo(&callConv));
564 if (callConv != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG)
566 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_CALLCONV_NOT_LOCAL_SIG);
570 IfFailThrow(sig.GetData(&numArgs));
572 if (numArgs != (unsigned short) numArgs)
573 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
575 sigRet->numArgs = (unsigned short) numArgs;
578 sigRet->args = (CORINFO_ARG_LIST_HANDLE)sig.GetPtr();
581 // Set computed flags
582 sigRet->flags = sigRetFlags;
584 _ASSERTE(SigInfoFlagsAreValid(sigRet));
587 //---------------------------------------------------------------------------------------
589 CORINFO_CLASS_HANDLE CEEInfo::getTokenTypeAsHandle (CORINFO_RESOLVED_TOKEN * pResolvedToken)
597 CORINFO_CLASS_HANDLE tokenType = NULL;
599 JIT_TO_EE_TRANSITION();
601 _ASSERTE((pResolvedToken->hMethod == NULL) || (pResolvedToken->hField == NULL));
603 BinderClassID classID = CLASS__TYPE_HANDLE;
605 if (pResolvedToken->hMethod != NULL)
607 classID = CLASS__METHOD_HANDLE;
610 if (pResolvedToken->hField != NULL)
612 classID = CLASS__FIELD_HANDLE;
615 tokenType = CORINFO_CLASS_HANDLE(CoreLibBinder::GetClass(classID));
617 EE_TO_JIT_TRANSITION();
623 int CEEInfo::getStringLiteral (
624 CORINFO_MODULE_HANDLE moduleHnd,
636 Module* module = GetModule(moduleHnd);
638 _ASSERTE(bufferSize >= 0);
639 _ASSERTE(startIndex >= 0);
643 JIT_TO_EE_TRANSITION();
645 if (IsDynamicScope(moduleHnd))
648 STRINGREF strRef = GetDynamicResolver(moduleHnd)->GetStringLiteral(metaTOK);
651 StringObject* strObj = STRINGREFToObject(strRef);
652 int length = (int)strObj->GetStringLength();
653 result = (length >= startIndex) ? (length - startIndex) : 0;
654 if (buffer != NULL && result != 0)
656 memcpyNoGCRefs(buffer, strObj->GetBuffer() + startIndex, min(bufferSize, result) * sizeof(char16_t));
664 if (!FAILED((module)->GetMDImport()->GetUserString(metaTOK, &dwCharCount, NULL, &pString)))
666 _ASSERTE(dwCharCount >= 0 && dwCharCount <= INT_MAX);
667 int length = (int)dwCharCount;
668 result = (length >= startIndex) ? (length - startIndex) : 0;
669 if (buffer != NULL && result != 0)
671 memcpyNoGCRefs(buffer, pString + startIndex, min(bufferSize, result) * sizeof(char16_t));
676 EE_TO_JIT_TRANSITION();
681 size_t CEEInfo::printObjectDescription (
682 CORINFO_OBJECT_HANDLE handle,
685 size_t* pRequiredBufferSize)
693 size_t bytesWritten = 0;
695 _ASSERT(handle != nullptr);
697 JIT_TO_EE_TRANSITION();
700 OBJECTREF obj = getObjectFromJitHandle(handle);
701 StackSString stackStr;
703 // Currently only supported for String and RuntimeType
704 if (obj->GetMethodTable()->IsString())
706 ((STRINGREF)obj)->GetSString(stackStr);
708 else if (obj->GetMethodTable() == g_pRuntimeTypeClass)
710 ((REFLECTCLASSBASEREF)obj)->GetType().GetName(stackStr);
714 obj->GetMethodTable()->_GetFullyQualifiedNameForClass(stackStr);
717 const UTF8* utf8data = stackStr.GetUTF8();
720 bytesWritten = min(bufferSize - 1, stackStr.GetCount());
721 memcpy((BYTE*)buffer, (BYTE*)utf8data, bytesWritten);
723 // Always null-terminate
724 buffer[bytesWritten] = 0;
727 if (pRequiredBufferSize != nullptr)
729 *pRequiredBufferSize = stackStr.GetCount() + 1;
732 EE_TO_JIT_TRANSITION();
738 size_t CEEInfo::findNameOfToken (Module* module,
740 _Out_writes_ (FQNameCapacity) char * szFQName,
741 size_t FQNameCapacity)
749 PCCOR_SIGNATURE sig = NULL;
751 LPCUTF8 pszNamespace = NULL;
752 LPCUTF8 pszClassName = NULL;
754 mdToken tokType = TypeFromToken(metaTOK);
759 if (FAILED(module->GetMDImport()->GetNameOfTypeRef(metaTOK, &pszNamespace, &pszClassName)))
761 pszNamespace = pszClassName = "Invalid TypeRef record";
763 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
768 if (FAILED(module->GetMDImport()->GetNameOfTypeDef(metaTOK, &pszClassName, &pszNamespace)))
770 pszClassName = pszNamespace = "Invalid TypeDef record";
772 ns::MakePath(szFQName, (int)FQNameCapacity, pszNamespace, pszClassName);
778 if (FAILED(module->GetMDImport()->GetNameOfFieldDef(metaTOK, &szFieldName)))
780 szFieldName = "Invalid FieldDef record";
782 strncpy_s(szFQName, FQNameCapacity, (char*)szFieldName, FQNameCapacity - 1);
788 if (FAILED(module->GetMDImport()->GetNameOfMethodDef(metaTOK, &szMethodName)))
790 szMethodName = "Invalid MethodDef record";
792 strncpy_s(szFQName, FQNameCapacity, (char*)szMethodName, FQNameCapacity - 1);
798 if (FAILED(module->GetMDImport()->GetNameAndSigOfMemberRef((mdMemberRef)metaTOK, &sig, &cSig, &szName)))
800 szName = "Invalid MemberRef record";
802 strncpy_s(szFQName, FQNameCapacity, (char *)szName, FQNameCapacity - 1);
806 sprintf_s(szFQName, FQNameCapacity, "!TK_%x", metaTOK);
811 strncpy_s (szFQName, FQNameCapacity, "<UNKNOWN>", FQNameCapacity - 1);
815 return strlen (szFQName);
818 CorInfoHelpFunc CEEInfo::getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle)
826 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
828 JIT_TO_EE_TRANSITION_LEAF();
830 result = IsDynamicScope(handle) ? CORINFO_HELP_UNDEF : CORINFO_HELP_STRCNS;
832 EE_TO_JIT_TRANSITION_LEAF();
838 CHECK CheckContext(CORINFO_MODULE_HANDLE scopeHnd, CORINFO_CONTEXT_HANDLE context)
840 if (context != METHOD_BEING_COMPILED_CONTEXT())
842 CHECK_MSG(scopeHnd != NULL, "Illegal null scope");
843 CHECK_MSG(((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK) != NULL, "Illegal null context");
844 if (((size_t)context & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
846 TypeHandle handle((CORINFO_CLASS_HANDLE)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK));
847 CHECK_MSG(handle.GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
851 MethodDesc* handle = (MethodDesc*)((size_t)context & ~CORINFO_CONTEXTFLAGS_MASK);
852 CHECK_MSG(handle->GetModule() == GetModule(scopeHnd), "Inconsistent scope and context");
860 static DECLSPEC_NORETURN void ThrowBadTokenException(CORINFO_RESOLVED_TOKEN * pResolvedToken)
862 switch (pResolvedToken->tokenType & CORINFO_TOKENKIND_Mask)
864 case CORINFO_TOKENKIND_Class:
865 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_CLASS_TOKEN);
866 case CORINFO_TOKENKIND_Method:
867 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN);
868 case CORINFO_TOKENKIND_Field:
869 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_FIELD_TOKEN);
871 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
875 /*********************************************************************/
876 void CEEInfo::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken)
884 JIT_TO_EE_TRANSITION();
886 _ASSERTE(CheckContext(pResolvedToken->tokenScope, pResolvedToken->tokenContext));
888 pResolvedToken->pTypeSpec = NULL;
889 pResolvedToken->cbTypeSpec = NULL;
890 pResolvedToken->pMethodSpec = NULL;
891 pResolvedToken->cbMethodSpec = NULL;
894 MethodDesc * pMD = NULL;
895 FieldDesc * pFD = NULL;
897 CorInfoTokenKind tokenType = pResolvedToken->tokenType;
899 if (IsDynamicScope(pResolvedToken->tokenScope))
901 GetDynamicResolver(pResolvedToken->tokenScope)->ResolveToken(pResolvedToken->token, &th, &pMD, &pFD);
904 // Check that we got the expected handles and fill in missing data if necessary
907 CorTokenType tkType = (CorTokenType)TypeFromToken(pResolvedToken->token);
911 if ((tkType != mdtMethodDef) && (tkType != mdtMemberRef))
912 ThrowBadTokenException(pResolvedToken);
913 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
914 ThrowBadTokenException(pResolvedToken);
916 th = pMD->GetMethodTable();
918 // "PermitUninstDefOrRef" check
919 if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && pMD->ContainsGenericVariables())
921 COMPlusThrow(kInvalidProgramException);
924 // if this is a BoxedEntryPointStub get the UnboxedEntryPoint one
925 if (pMD->IsUnboxingStub())
927 pMD = pMD->GetMethodTable()->GetUnboxedEntryPointMD(pMD);
930 // Activate target if required
931 if (tokenType != CORINFO_TOKENKIND_Ldtoken)
933 EnsureActive(th, pMD);
936 else if (pFD != NULL)
938 if ((tkType != mdtFieldDef) && (tkType != mdtMemberRef))
939 ThrowBadTokenException(pResolvedToken);
940 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
941 ThrowBadTokenException(pResolvedToken);
943 th = pFD->GetApproxEnclosingMethodTable();
945 if (pFD->IsStatic() && (tokenType != CORINFO_TOKENKIND_Ldtoken))
952 if ((tkType != mdtTypeDef) && (tkType != mdtTypeRef))
953 ThrowBadTokenException(pResolvedToken);
954 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
955 ThrowBadTokenException(pResolvedToken);
957 ThrowBadTokenException(pResolvedToken);
959 if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained)
965 _ASSERTE((pMD == NULL) || (pFD == NULL));
966 _ASSERTE(!th.IsNull());
968 // "PermitUninstDefOrRef" check
969 if ((tokenType != CORINFO_TOKENKIND_Ldtoken) && th.ContainsGenericVariables())
971 COMPlusThrow(kInvalidProgramException);
976 mdToken metaTOK = pResolvedToken->token;
977 Module * pModule = (Module *)pResolvedToken->tokenScope;
979 switch (TypeFromToken(metaTOK))
982 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
983 ThrowBadTokenException(pResolvedToken);
986 DomainAssembly *pTargetModule = pModule->LoadModule(metaTOK);
987 if (pTargetModule == NULL)
988 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
989 th = TypeHandle(pTargetModule->GetModule()->GetGlobalMethodTable());
991 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
997 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
998 ThrowBadTokenException(pResolvedToken);
1000 th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, metaTOK,
1001 ClassLoader::ThrowIfNotFound,
1002 (tokenType == CORINFO_TOKENKIND_Ldtoken) ?
1003 ClassLoader::PermitUninstDefOrRef : ClassLoader::FailIfUninstDefOrRef);
1008 if ((tokenType & CORINFO_TOKENKIND_Class) == 0)
1009 ThrowBadTokenException(pResolvedToken);
1011 IfFailThrow(pModule->GetMDImport()->GetTypeSpecFromToken(metaTOK, &pResolvedToken->pTypeSpec, (ULONG*)&pResolvedToken->cbTypeSpec));
1013 SigTypeContext typeContext;
1014 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1016 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1017 th = sigptr.GetTypeHandleThrowing(pModule, &typeContext);
1022 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1023 ThrowBadTokenException(pResolvedToken);
1025 pMD = MemberLoader::GetMethodDescFromMethodDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1027 th = pMD->GetMethodTable();
1031 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1032 ThrowBadTokenException(pResolvedToken);
1034 pFD = MemberLoader::GetFieldDescFromFieldDef(pModule, metaTOK, (tokenType != CORINFO_TOKENKIND_Ldtoken));
1036 th = pFD->GetEnclosingMethodTable();
1041 SigTypeContext typeContext;
1042 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1044 MemberLoader::GetDescFromMemberRef(pModule, metaTOK, &pMD, &pFD, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken),
1045 &th, TRUE, &pResolvedToken->pTypeSpec, (ULONG*)&pResolvedToken->cbTypeSpec);
1047 _ASSERTE((pMD != NULL) ^ (pFD != NULL));
1048 _ASSERTE(!th.IsNull());
1052 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1053 ThrowBadTokenException(pResolvedToken);
1057 if ((tokenType & CORINFO_TOKENKIND_Field) == 0)
1058 ThrowBadTokenException(pResolvedToken);
1065 if ((tokenType & CORINFO_TOKENKIND_Method) == 0)
1066 ThrowBadTokenException(pResolvedToken);
1068 SigTypeContext typeContext;
1069 GetTypeContext(pResolvedToken->tokenContext, &typeContext);
1071 // We need the method desc to carry exact instantiation, thus allowInstParam == FALSE.
1072 pMD = MemberLoader::GetMethodDescFromMethodSpec(pModule, metaTOK, &typeContext, (tokenType != CORINFO_TOKENKIND_Ldtoken), FALSE /* allowInstParam */,
1073 &th, TRUE, &pResolvedToken->pTypeSpec, (ULONG*)&pResolvedToken->cbTypeSpec, &pResolvedToken->pMethodSpec, (ULONG*)&pResolvedToken->cbMethodSpec);
1078 ThrowBadTokenException(pResolvedToken);
1082 // Module activation tracking
1084 if (!pModule->IsSystem())
1088 EnsureActive(th, pMD);
1093 if (pFD->IsStatic())
1098 // It should not be required to trigger the modules cctors for ldtoken, it is done for backward compatibility only.
1099 if (tokenType == CORINFO_TOKENKIND_Box || tokenType == CORINFO_TOKENKIND_Constrained || tokenType == CORINFO_TOKENKIND_Ldtoken)
1106 // tokenType specific verification and transformations
1108 CorElementType et = th.GetInternalCorElementType();
1111 case CORINFO_TOKENKIND_Ldtoken:
1112 // Allow everything.
1115 case CORINFO_TOKENKIND_Newarr:
1116 // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1117 if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1118 COMPlusThrow(kInvalidProgramException);
1120 th = ClassLoader::LoadArrayTypeThrowing(th);
1124 // Disallow ELEMENT_TYPE_BYREF and ELEMENT_TYPE_VOID
1125 if (et == ELEMENT_TYPE_BYREF || et == ELEMENT_TYPE_VOID)
1126 COMPlusThrow(kInvalidProgramException);
1130 // The JIT interface should always return fully loaded types
1131 _ASSERTE(th.IsFullyLoaded());
1133 pResolvedToken->hClass = CORINFO_CLASS_HANDLE(th.AsPtr());
1134 pResolvedToken->hMethod = CORINFO_METHOD_HANDLE(pMD);
1135 pResolvedToken->hField = CORINFO_FIELD_HANDLE(pFD);
1137 EE_TO_JIT_TRANSITION();
1141 /*********************************************************************/
1142 // We have a few frequently used constants in CoreLib that are defined as
1143 // readonly static fields for historic reasons. Check for them here and
1144 // allow them to be treated as actual constants by the JIT.
1145 static CORINFO_FIELD_ACCESSOR getFieldIntrinsic(FieldDesc * field)
1147 STANDARD_VM_CONTRACT;
1149 if (CoreLibBinder::GetField(FIELD__STRING__EMPTY) == field)
1151 return CORINFO_FIELD_INTRINSIC_EMPTY_STRING;
1154 if ((CoreLibBinder::GetField(FIELD__INTPTR__ZERO) == field) ||
1155 (CoreLibBinder::GetField(FIELD__UINTPTR__ZERO) == field))
1157 return CORINFO_FIELD_INTRINSIC_ZERO;
1160 if (CoreLibBinder::GetField(FIELD__BITCONVERTER__ISLITTLEENDIAN) == field)
1162 return CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN;
1165 return (CORINFO_FIELD_ACCESSOR)-1;
1168 static CorInfoHelpFunc getGenericStaticsHelper(FieldDesc * pField)
1170 STANDARD_VM_CONTRACT;
1172 int helper = CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE;
1174 if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1175 pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1177 helper = CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1180 if (pField->IsThreadStatic())
1182 const int delta = CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE;
1184 static_assert_no_msg(CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE
1185 == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE + delta);
1187 helper += (CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE);
1190 return (CorInfoHelpFunc)helper;
1193 CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable * pFieldMT)
1195 STANDARD_VM_CONTRACT;
1197 int helper = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
1199 if (pField->GetFieldType() == ELEMENT_TYPE_CLASS ||
1200 pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1202 helper = CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1205 if (pFieldMT->IsDynamicStatics())
1207 const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1209 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS
1210 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1215 if ((!pFieldMT->HasClassConstructor() && !pFieldMT->HasBoxedRegularStatics()) || pFieldMT->IsClassInited())
1217 const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1219 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR
1220 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1225 if (pField->IsThreadStatic())
1227 const int delta = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE - CORINFO_HELP_GETSHARED_GCSTATIC_BASE;
1229 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE
1230 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta);
1231 static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR
1232 == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR + delta);
1233 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR
1234 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR + delta);
1235 static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS
1236 == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS + delta);
1237 static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS
1238 == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS + delta);
1243 return (CorInfoHelpFunc)helper;
1246 static CorInfoHelpFunc getInstanceFieldHelper(FieldDesc * pField, CORINFO_ACCESS_FLAGS flags)
1248 STANDARD_VM_CONTRACT;
1252 CorElementType type = pField->GetFieldType();
1254 if (CorTypeInfo::IsObjRef(type))
1255 helper = CORINFO_HELP_GETFIELDOBJ;
1259 case ELEMENT_TYPE_VALUETYPE:
1260 helper = CORINFO_HELP_GETFIELDSTRUCT;
1262 case ELEMENT_TYPE_I1:
1263 case ELEMENT_TYPE_BOOLEAN:
1264 case ELEMENT_TYPE_U1:
1265 helper = CORINFO_HELP_GETFIELD8;
1267 case ELEMENT_TYPE_I2:
1268 case ELEMENT_TYPE_CHAR:
1269 case ELEMENT_TYPE_U2:
1270 helper = CORINFO_HELP_GETFIELD16;
1272 case ELEMENT_TYPE_I4:
1273 case ELEMENT_TYPE_U4:
1274 IN_TARGET_32BIT(default:)
1275 helper = CORINFO_HELP_GETFIELD32;
1277 case ELEMENT_TYPE_I8:
1278 case ELEMENT_TYPE_U8:
1279 IN_TARGET_64BIT(default:)
1280 helper = CORINFO_HELP_GETFIELD64;
1282 case ELEMENT_TYPE_R4:
1283 helper = CORINFO_HELP_GETFIELDFLOAT;
1285 case ELEMENT_TYPE_R8:
1286 helper = CORINFO_HELP_GETFIELDDOUBLE;
1290 if (flags & CORINFO_ACCESS_SET)
1292 const int delta = CORINFO_HELP_SETFIELDOBJ - CORINFO_HELP_GETFIELDOBJ;
1294 static_assert_no_msg(CORINFO_HELP_SETFIELD8 == CORINFO_HELP_GETFIELD8 + delta);
1295 static_assert_no_msg(CORINFO_HELP_SETFIELD16 == CORINFO_HELP_GETFIELD16 + delta);
1296 static_assert_no_msg(CORINFO_HELP_SETFIELD32 == CORINFO_HELP_GETFIELD32 + delta);
1297 static_assert_no_msg(CORINFO_HELP_SETFIELD64 == CORINFO_HELP_GETFIELD64 + delta);
1298 static_assert_no_msg(CORINFO_HELP_SETFIELDSTRUCT == CORINFO_HELP_GETFIELDSTRUCT + delta);
1299 static_assert_no_msg(CORINFO_HELP_SETFIELDFLOAT == CORINFO_HELP_GETFIELDFLOAT + delta);
1300 static_assert_no_msg(CORINFO_HELP_SETFIELDDOUBLE == CORINFO_HELP_GETFIELDDOUBLE + delta);
1305 return (CorInfoHelpFunc)helper;
1310 /*********************************************************************/
1311 uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, bool isGCType)
1319 UINT32 typeIndex = 0;
1321 JIT_TO_EE_TRANSITION();
1323 FieldDesc* fieldDesc = (FieldDesc*)field;
1324 _ASSERTE(fieldDesc->IsThreadStatic());
1328 typeIndex = AppDomain::GetCurrentDomain()->GetGCThreadStaticTypeIndex(fieldDesc->GetEnclosingMethodTable());
1332 typeIndex = AppDomain::GetCurrentDomain()->GetNonGCThreadStaticTypeIndex(fieldDesc->GetEnclosingMethodTable());
1335 assert(typeIndex != TypeIDProvider::INVALID_TYPE_ID);
1337 EE_TO_JIT_TRANSITION();
1341 #if defined(TARGET_WINDOWS)
1342 /*********************************************************************/
1343 static uint32_t ThreadLocalOffset(void* p)
1345 PTEB Teb = NtCurrentTeb();
1346 uint8_t** pTls = (uint8_t**)Teb->ThreadLocalStoragePointer;
1347 uint8_t* pOurTls = pTls[_tls_index];
1348 return (uint32_t)((uint8_t*)p - pOurTls);
1350 #elif defined(TARGET_OSX)
1351 extern "C" void* GetThreadVarsAddress();
1353 static void* GetThreadVarsSectionAddressFromDesc(uint8_t* p)
1355 _ASSERT(p[0] == 0x48 && p[1] == 0x8d && p[2] == 0x3d);
1357 // At this point, `p` contains the instruction pointer and is pointing to the above opcodes.
1358 // These opcodes are patched by the dynamic linker.
1359 // Move beyond the opcodes that we have already checked above.
1362 // The descriptor address is located at *p at this point.
1363 // (p + 4) below skips the descriptor address bytes embedded in the instruction and
1364 // add it to the `instruction pointer` to find out the address.
1365 return *(uint32_t*)p + (p + 4);
1368 static void* GetThreadVarsSectionAddress()
1371 // On x64, the address is related to rip, so, disassemble the function,
1372 // read the offset, and then relative to the IP, find the final address of
1373 // __thread_vars section.
1374 uint8_t* p = reinterpret_cast<uint8_t*>(&GetThreadVarsAddress);
1375 return GetThreadVarsSectionAddressFromDesc(p);
1377 return GetThreadVarsAddress();
1378 #endif // TARGET_AMD64
1387 extern "C" void* GetTlsIndexObjectDescOffset();
1389 static void* GetThreadStaticDescriptor(uint8_t* p)
1391 if (!(p[0] == 0x66 && p[1] == 0x48 && p[2] == 0x8d && p[3] == 0x3d))
1393 // The optimization is disabled if coreclr is not compiled in .so format.
1394 _ASSERTE(false && "Unexpected code sequence");
1398 // At this point, `p` contains the instruction pointer and is pointing to the above opcodes.
1399 // These opcodes are patched by the dynamic linker.
1400 // Move beyond the opcodes that we have already checked above.
1403 // The descriptor address is located at *p at this point. Read that and add
1404 // it to the instruction pointer to locate the address of `ti` that will be used
1405 // to pass to __tls_get_addr during execution.
1406 // (p + 4) below skips the descriptor address bytes embedded in the instruction and
1407 // add it to the `instruction pointer` to find out the address.
1408 return *(uint32_t*)p + (p + 4);
1411 static void* GetTlsIndexObjectAddress()
1413 uint8_t* p = reinterpret_cast<uint8_t*>(&GetTlsIndexObjectDescOffset);
1414 return GetThreadStaticDescriptor(p);
1417 #elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
1419 extern "C" size_t GetThreadStaticsVariableOffset();
1421 #endif // TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64
1422 #endif // TARGET_WINDOWS
1425 void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType)
1433 JIT_TO_EE_TRANSITION_LEAF();
1435 size_t threadStaticBaseOffset = 0;
1437 #if defined(TARGET_WINDOWS)
1438 pInfo->tlsIndex.addr = (void*)static_cast<uintptr_t>(_tls_index);
1439 pInfo->tlsIndex.accessType = IAT_VALUE;
1441 pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer);
1442 threadStaticBaseOffset = ThreadLocalOffset(&t_ThreadStatics);
1444 #elif defined(TARGET_OSX)
1446 pInfo->threadVarsSection = GetThreadVarsSectionAddress();
1448 #elif defined(TARGET_AMD64)
1450 // For Linux/x64, get the address of tls_get_addr system method and the base address
1451 // of struct that we will pass to it.
1452 pInfo->tlsGetAddrFtnPtr = reinterpret_cast<void*>(&__tls_get_addr);
1453 pInfo->tlsIndexObject = GetTlsIndexObjectAddress();
1455 #elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64)
1457 // For Linux arm64/loongarch64/riscv64, just get the offset of thread static variable, and during execution,
1458 // this offset, arm64 taken from trpid_elp0 system register gives back the thread variable address.
1459 // this offset, loongarch64 taken from $tp register gives back the thread variable address.
1460 threadStaticBaseOffset = GetThreadStaticsVariableOffset();
1463 _ASSERTE_MSG(false, "Unsupported scenario of optimizing TLS access on Linux Arm32/x86");
1464 #endif // TARGET_WINDOWS
1468 pInfo->offsetOfMaxThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, GCMaxThreadStaticBlocks));
1469 pInfo->offsetOfThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, GCThreadStaticBlocks));
1473 pInfo->offsetOfMaxThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, NonGCMaxThreadStaticBlocks));
1474 pInfo->offsetOfThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, NonGCThreadStaticBlocks));
1476 pInfo->offsetOfGCDataPointer = static_cast<uint32_t>(PtrArray::GetDataOffset());
1478 EE_TO_JIT_TRANSITION_LEAF();
1481 /*********************************************************************/
1482 void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken,
1483 CORINFO_METHOD_HANDLE callerHandle,
1484 CORINFO_ACCESS_FLAGS flags,
1485 CORINFO_FIELD_INFO *pResult
1494 JIT_TO_EE_TRANSITION();
1496 _ASSERTE((flags & (CORINFO_ACCESS_GET | CORINFO_ACCESS_SET | CORINFO_ACCESS_ADDRESS | CORINFO_ACCESS_INIT_ARRAY)) != 0);
1498 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
1500 FieldDesc * pField = (FieldDesc*)pResolvedToken->hField;
1501 MethodTable * pFieldMT = pField->GetApproxEnclosingMethodTable();
1503 // Helper to use if the field access requires it
1504 CORINFO_FIELD_ACCESSOR fieldAccessor = (CORINFO_FIELD_ACCESSOR)-1;
1505 DWORD fieldFlags = 0;
1507 pResult->offset = pField->GetOffset();
1508 pResult->fieldLookup.addr = nullptr;
1510 if (pField->IsStatic())
1512 fieldFlags |= CORINFO_FLG_FIELD_STATIC;
1514 if (pField->IsRVA())
1516 fieldFlags |= CORINFO_FLG_FIELD_UNMANAGED;
1518 Module* module = pFieldMT->GetModule();
1519 if (module->IsRvaFieldTls(pResult->offset))
1521 fieldAccessor = CORINFO_FIELD_STATIC_TLS;
1523 // Provide helper to use if the JIT is not able to emit the TLS access
1525 pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR_TLS;
1527 pResult->offset = module->GetFieldTlsOffset(pResult->offset);
1531 fieldAccessor = CORINFO_FIELD_STATIC_RVA_ADDRESS;
1532 pResult->fieldLookup.addr = pField->GetStaticAddressHandle(NULL);
1533 pResult->fieldLookup.accessType = IAT_VALUE;
1536 // We are not going through a helper. The constructor has to be triggered explicitly.
1537 if (!pFieldMT->IsClassInited())
1538 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1542 // Regular or thread static
1543 CORINFO_FIELD_ACCESSOR intrinsicAccessor;
1545 if (pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
1546 fieldFlags |= CORINFO_FLG_FIELD_STATIC_IN_HEAP;
1548 if (pFieldMT->IsSharedByGenericInstantiations())
1550 if (pField->IsEnCNew())
1552 fieldAccessor = CORINFO_FIELD_STATIC_ADDR_HELPER;
1554 pResult->helper = CORINFO_HELP_GETSTATICFIELDADDR;
1558 fieldAccessor = CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER;
1560 pResult->helper = getGenericStaticsHelper(pField);
1564 if (pFieldMT->GetModule()->IsSystem() && (flags & CORINFO_ACCESS_GET) &&
1565 (intrinsicAccessor = getFieldIntrinsic(pField)) != (CORINFO_FIELD_ACCESSOR)-1)
1568 fieldAccessor = intrinsicAccessor;
1571 if (pFieldMT->Collectible())
1573 // Static fields are not pinned in collectible types. We will always access
1574 // them using a helper since the address cannot be embedded into the code.
1575 fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
1577 pResult->helper = getSharedStaticsHelper(pField, pFieldMT);
1579 else if (pField->IsThreadStatic())
1581 // We always treat accessing thread statics as if we are in domain neutral code.
1582 fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER;
1584 pResult->helper = getSharedStaticsHelper(pField, pFieldMT);
1585 #if defined(TARGET_ARM)
1586 // Optimization is disabled for linux/windows arm
1587 #elif !defined(TARGET_WINDOWS) && defined(TARGET_X86)
1588 // Optimization is disabled for linux/x86
1589 #elif defined(TARGET_LINUX_MUSL) && defined(TARGET_ARM64)
1590 // Optimization is disabled for linux musl arm64
1592 bool optimizeThreadStaticAccess = true;
1593 #if !defined(TARGET_OSX) && defined(TARGET_UNIX) && defined(TARGET_AMD64)
1594 // For linux/x64, check if compiled coreclr as .so file and not single file.
1595 // For single file, the `tls_index` might not be accurate.
1596 // Do not perform this optimization in such case.
1597 optimizeThreadStaticAccess = GetTlsIndexObjectAddress() != nullptr;
1598 #endif // !TARGET_OSX && TARGET_UNIX && TARGET_AMD64
1600 if (optimizeThreadStaticAccess)
1602 // For windows x64/x86/arm64, linux x64/arm64/loongarch64/riscv64:
1603 // We convert the TLS access to the optimized helper where we will store
1604 // the static blocks in TLS directly and access them via inline code.
1605 if ((pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR) ||
1606 (pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE))
1608 fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED;
1609 pResult->helper = CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED;
1611 else if ((pResult->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR) ||
1612 (pResult->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE))
1614 fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED;
1615 pResult->helper = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED;
1618 #endif // TARGET_ARM
1622 fieldAccessor = CORINFO_FIELD_STATIC_ADDRESS;
1624 // Allocate space for the local class if necessary, but don't trigger
1625 // class construction.
1626 DomainLocalModule* pLocalModule = pFieldMT->GetDomainLocalModule();
1627 pLocalModule->PopulateClass(pFieldMT);
1629 // We are not going through a helper. The constructor has to be triggered explicitly.
1630 if (!pFieldMT->IsClassInited())
1631 fieldFlags |= CORINFO_FLG_FIELD_INITCLASS;
1635 _ASSERT(!pFieldMT->Collectible());
1636 // Field address is expected to be pinned so we don't need to protect it from GC here
1637 pResult->fieldLookup.addr = pField->GetStaticAddressHandle((void*)pField->GetBase());
1638 pResult->fieldLookup.accessType = IAT_VALUE;
1639 if (fieldFlags & CORINFO_FLG_FIELD_STATIC_IN_HEAP)
1641 Object* frozenObj = VolatileLoad((Object**)pResult->fieldLookup.addr);
1643 if (frozenObj == nullptr)
1645 // Boxed static is not yet set, allocate it
1646 pFieldMT->AllocateRegularStaticBox(pField, (Object**)pResult->fieldLookup.addr);
1647 frozenObj = VolatileLoad((Object**)pResult->fieldLookup.addr);
1650 _ASSERT(frozenObj != nullptr);
1652 // ContainsPointers here is unnecessary but it's cheaper than IsInFrozenSegment
1653 // for structs containing gc handles
1654 if (!frozenObj->GetMethodTable()->ContainsPointers() &&
1655 GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(frozenObj))
1657 pResult->fieldLookup.addr = frozenObj->GetData();
1658 fieldFlags &= ~CORINFO_FLG_FIELD_STATIC_IN_HEAP;
1666 if (pField->IsEnCNew())
1668 fieldAccessor = CORINFO_FIELD_INSTANCE_ADDR_HELPER;
1670 pResult->helper = CORINFO_HELP_GETFIELDADDR;
1674 fieldAccessor = CORINFO_FIELD_INSTANCE;
1677 // FieldDesc::GetOffset() does not include the size of Object
1678 if (!pFieldMT->IsValueType())
1680 pResult->offset += OBJECT_SIZE;
1684 // TODO: This is touching metadata. Can we avoid it?
1685 DWORD fieldAttribs = pField->GetAttributes();
1687 if (IsFdFamily(fieldAttribs))
1688 fieldFlags |= CORINFO_FLG_FIELD_PROTECTED;
1690 if (IsFdInitOnly(fieldAttribs))
1691 fieldFlags |= CORINFO_FLG_FIELD_FINAL;
1693 pResult->fieldAccessor = fieldAccessor;
1694 pResult->fieldFlags = fieldFlags;
1696 if (!(flags & CORINFO_ACCESS_INLINECHECK))
1698 //get the field's type. Grab the class for structs.
1699 pResult->fieldType = getFieldTypeInternal(pResolvedToken->hField, &pResult->structType, pResolvedToken->hClass);
1702 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
1705 //Since we can't get the special verify-only instantiated FD like we can with MDs, go back to the parent
1706 //of the memberRef and load that one. That should give us the open instantiation.
1708 //If the field we found is owned by a generic type, you have to go back to the signature and reload.
1709 //Otherwise we filled in !0.
1710 TypeHandle fieldTypeForSecurity = TypeHandle(pResolvedToken->hClass);
1711 if (pResolvedToken->pTypeSpec != NULL)
1713 SigTypeContext typeContext;
1714 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
1716 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
1717 fieldTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
1719 // typeHnd can be a variable type
1720 if (fieldTypeForSecurity.GetMethodTable() == NULL)
1722 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
1726 BOOL doAccessCheck = TRUE;
1727 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
1729 DynamicResolver * pAccessContext = NULL;
1731 //More in code:CEEInfo::getCallInfo, but the short version is that the caller and callee Descs do
1732 //not completely describe the type.
1733 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
1734 if (IsDynamicScope(pResolvedToken->tokenScope))
1736 doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope), &callerTypeForSecurity,
1737 &accessCheckType, &pAccessContext);
1740 //Now for some link time checks.
1741 //Um... where are the field link demands?
1743 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
1747 //Well, let's check some visibility at least.
1748 AccessCheckOptions accessCheckOptions(accessCheckType,
1753 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
1754 AccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
1756 BOOL canAccess = ClassLoader::CanAccess(
1758 fieldTypeForSecurity.GetMethodTable(),
1759 fieldTypeForSecurity.GetAssembly(),
1762 (flags & CORINFO_ACCESS_INIT_ARRAY) ? NULL : pField, // For InitializeArray, we don't need tocheck the type of the field.
1763 accessCheckOptions);
1767 //Set up the throw helper
1768 pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL;
1770 pResult->accessCalloutHelper.helperNum = CORINFO_HELP_FIELD_ACCESS_EXCEPTION;
1771 pResult->accessCalloutHelper.numArgs = 2;
1773 pResult->accessCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
1774 pResult->accessCalloutHelper.args[1].Set(CORINFO_FIELD_HANDLE(pField));
1779 EE_TO_JIT_TRANSITION();
1782 //---------------------------------------------------------------------------------------
1784 bool CEEInfo::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd)
1793 JIT_TO_EE_TRANSITION_LEAF();
1794 FieldDesc* field = (FieldDesc*)fldHnd;
1795 res = (field->IsStatic() != 0);
1796 EE_TO_JIT_TRANSITION_LEAF();
1800 int CEEInfo::getArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd)
1809 JIT_TO_EE_TRANSITION();
1811 _ASSERT(objHnd != NULL);
1815 OBJECTREF obj = getObjectFromJitHandle(objHnd);
1817 if (obj->GetMethodTable()->IsArray())
1819 arrLen = ((ARRAYBASEREF)obj)->GetNumComponents();
1821 else if (obj->GetMethodTable()->IsString())
1823 arrLen = ((STRINGREF)obj)->GetStringLength();
1826 EE_TO_JIT_TRANSITION();
1830 //---------------------------------------------------------------------------------------
1833 CEEInfo::findCallSiteSig(
1834 CORINFO_MODULE_HANDLE scopeHnd,
1835 unsigned sigMethTok,
1836 CORINFO_CONTEXT_HANDLE context,
1837 CORINFO_SIG_INFO * sigRet)
1845 JIT_TO_EE_TRANSITION();
1847 PCCOR_SIGNATURE pSig = NULL;
1850 if (IsDynamicScope(scopeHnd))
1852 DynamicResolver * pResolver = GetDynamicResolver(scopeHnd);
1855 if (TypeFromToken(sigMethTok) == mdtMemberRef)
1857 sig = pResolver->ResolveSignatureForVarArg(sigMethTok);
1861 _ASSERTE(TypeFromToken(sigMethTok) == mdtMethodDef);
1863 TypeHandle classHandle;
1864 MethodDesc * pMD = NULL;
1865 FieldDesc * pFD = NULL;
1867 // in this case a method is asked for its sig. Resolve the method token and get the sig
1868 pResolver->ResolveToken(sigMethTok, &classHandle, &pMD, &pFD);
1870 COMPlusThrow(kInvalidProgramException);
1872 PCCOR_SIGNATURE pSig = NULL;
1874 pMD->GetSig(&pSig, &cbSig);
1875 sig = SigPointer(pSig, cbSig);
1877 context = MAKE_METHODCONTEXT(pMD);
1878 scopeHnd = GetScopeHandle(pMD->GetModule());
1881 sig.GetSignature(&pSig, &cbSig);
1882 sigMethTok = mdTokenNil;
1886 Module * module = (Module *)scopeHnd;
1889 if (TypeFromToken(sigMethTok) == mdtMemberRef)
1891 IfFailThrow(module->GetMDImport()->GetNameAndSigOfMemberRef(sigMethTok, &pSig, (ULONG*)&cbSig, &szName));
1893 else if (TypeFromToken(sigMethTok) == mdtMethodDef)
1895 IfFailThrow(module->GetMDImport()->GetSigOfMethodDef(sigMethTok, (ULONG*)&cbSig, &pSig));
1899 SigTypeContext typeContext;
1900 GetTypeContext(context, &typeContext);
1908 CONV_TO_JITSIG_FLAGS_NONE,
1910 EE_TO_JIT_TRANSITION();
1911 } // CEEInfo::findCallSiteSig
1913 //---------------------------------------------------------------------------------------
1917 CORINFO_MODULE_HANDLE scopeHnd,
1919 CORINFO_CONTEXT_HANDLE context,
1920 CORINFO_SIG_INFO * sigRet)
1928 JIT_TO_EE_TRANSITION();
1930 PCCOR_SIGNATURE pSig = NULL;
1933 if (IsDynamicScope(scopeHnd))
1935 SigPointer sig = GetDynamicResolver(scopeHnd)->ResolveSignature(sigTok);
1936 sig.GetSignature(&pSig, &cbSig);
1937 sigTok = mdTokenNil;
1941 Module * module = (Module *)scopeHnd;
1943 // We need to resolve this stand alone sig
1944 IfFailThrow(module->GetMDImport()->GetSigFromToken(
1945 (mdSignature)sigTok,
1950 SigTypeContext typeContext;
1951 GetTypeContext(context, &typeContext);
1959 CONV_TO_JITSIG_FLAGS_NONE,
1962 EE_TO_JIT_TRANSITION();
1963 } // CEEInfo::findSig
1965 //---------------------------------------------------------------------------------------
1968 CEEInfo::getClassSize(
1969 CORINFO_CLASS_HANDLE clsHnd)
1977 unsigned result = 0;
1979 JIT_TO_EE_TRANSITION_LEAF();
1981 TypeHandle VMClsHnd(clsHnd);
1982 result = VMClsHnd.GetSize();
1984 EE_TO_JIT_TRANSITION_LEAF();
1989 //---------------------------------------------------------------------------------------
1991 // Get the size of a reference type as allocated on the heap. This includes the size of the fields
1992 // (and any padding between the fields) and the size of a method table pointer but doesn't include
1993 // object header size or any padding for minimum size.
1995 CEEInfo::getHeapClassSize(
1996 CORINFO_CLASS_HANDLE clsHnd)
2004 unsigned result = 0;
2006 JIT_TO_EE_TRANSITION_LEAF();
2008 TypeHandle VMClsHnd(clsHnd);
2009 MethodTable* pMT = VMClsHnd.GetMethodTable();
2011 _ASSERTE(!pMT->IsValueType());
2012 _ASSERTE(!pMT->HasComponentSize());
2014 // Add OBJECT_SIZE to account for method table pointer.
2015 result = pMT->GetNumInstanceFieldBytes() + OBJECT_SIZE;
2017 EE_TO_JIT_TRANSITION_LEAF();
2021 //---------------------------------------------------------------------------------------
2023 // Return TRUE if an object of this type can be allocated on the stack.
2024 bool CEEInfo::canAllocateOnStack(CORINFO_CLASS_HANDLE clsHnd)
2032 bool result = false;
2034 JIT_TO_EE_TRANSITION_LEAF();
2036 TypeHandle VMClsHnd(clsHnd);
2037 MethodTable* pMT = VMClsHnd.GetMethodTable();
2039 _ASSERTE(!pMT->IsValueType());
2041 result = !pMT->HasFinalizer();
2043 EE_TO_JIT_TRANSITION_LEAF();
2047 unsigned CEEInfo::getClassAlignmentRequirement(CORINFO_CLASS_HANDLE type, bool fDoubleAlignHint)
2055 // Default alignment is sizeof(void*)
2056 unsigned result = TARGET_POINTER_SIZE;
2058 JIT_TO_EE_TRANSITION_LEAF();
2060 TypeHandle clsHnd(type);
2062 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
2063 if (fDoubleAlignHint)
2065 MethodTable* pMT = clsHnd.GetMethodTable();
2068 // Return the size of the double align hint. Ignore the actual alignment info account
2069 // so that structs with 64-bit integer fields do not trigger double aligned frames on x86.
2070 if (pMT->GetClass()->IsAlign8Candidate())
2077 result = getClassAlignmentRequirementStatic(clsHnd);
2080 EE_TO_JIT_TRANSITION_LEAF();
2085 unsigned CEEInfo::getClassAlignmentRequirementStatic(TypeHandle clsHnd)
2087 LIMITED_METHOD_CONTRACT;
2089 // Default alignment is sizeof(void*)
2090 unsigned result = TARGET_POINTER_SIZE;
2092 MethodTable * pMT = clsHnd.GetMethodTable();
2096 if (pMT->HasLayout())
2098 EEClassLayoutInfo* pInfo = pMT->GetLayoutInfo();
2100 if (clsHnd.IsNativeValueType())
2102 // if it's the unmanaged view of the managed type, we always use the unmanaged alignment requirement
2103 result = pMT->GetNativeLayoutInfo()->GetLargestAlignmentRequirement();
2105 else if (pInfo->IsManagedSequential() || pInfo->IsBlittable())
2107 _ASSERTE(!pMT->ContainsPointers());
2109 // if it's managed sequential, we use the managed alignment requirement
2110 result = pInfo->m_ManagedLargestAlignmentRequirementOfAllMembers;
2114 #ifdef FEATURE_64BIT_ALIGNMENT
2115 if (result < 8 && pMT->RequiresAlign8())
2117 // If the structure contains 64-bit primitive fields and the platform requires 8-byte alignment for
2118 // such fields then make sure we return at least 8-byte alignment. Note that it's technically possible
2119 // to create unmanaged APIs that take unaligned structures containing such fields and this
2120 // unconditional alignment bump would cause us to get the calling convention wrong on platforms such
2121 // as ARM. If we see such cases in the future we'd need to add another control (such as an alignment
2122 // property for the StructLayout attribute or a marshaling directive attribute for p/invoke arguments)
2123 // that allows more precise control. For now we'll go with the likely scenario.
2126 #endif // FEATURE_64BIT_ALIGNMENT
2131 CORINFO_FIELD_HANDLE
2132 CEEInfo::getFieldInClass(CORINFO_CLASS_HANDLE clsHnd, INT num)
2140 CORINFO_FIELD_HANDLE result = NULL;
2142 JIT_TO_EE_TRANSITION_LEAF();
2144 TypeHandle VMClsHnd(clsHnd);
2146 MethodTable* pMT= VMClsHnd.AsMethodTable();
2148 result = (CORINFO_FIELD_HANDLE) ((pMT->GetApproxFieldDescListRaw()) + num);
2150 EE_TO_JIT_TRANSITION_LEAF();
2155 static GetTypeLayoutResult GetTypeLayoutHelper(
2157 unsigned parentIndex,
2160 CORINFO_TYPE_LAYOUT_NODE* treeNodes,
2161 size_t maxTreeNodes,
2162 size_t* numTreeNodes)
2164 STANDARD_VM_CONTRACT;
2166 if (*numTreeNodes >= maxTreeNodes)
2168 return GetTypeLayoutResult::Partial;
2171 unsigned structNodeIndex = (unsigned)(*numTreeNodes)++;
2172 CORINFO_TYPE_LAYOUT_NODE& parNode = treeNodes[structNodeIndex];
2173 parNode.simdTypeHnd = NULL;
2174 parNode.diagFieldHnd = CORINFO_FIELD_HANDLE(pFD);
2175 parNode.parent = parentIndex;
2176 parNode.offset = baseOffs;
2177 parNode.size = pMT->GetNumInstanceFieldBytes();
2178 parNode.numFields = 0;
2179 parNode.type = CorInfoType::CORINFO_TYPE_VALUECLASS;
2181 EEClass* pClass = pMT->GetClass();
2182 parNode.hasSignificantPadding = pClass->HasExplicitFieldOffsetLayout() || pClass->HasExplicitSize();
2184 // The intrinsic SIMD/HW SIMD types have a lot of fields that the JIT does
2185 // not care about since they are considered primitives by the JIT.
2186 if (pMT->IsIntrinsicType())
2189 pMT->GetFullyQualifiedNameInfo(&nsName);
2191 if ((strcmp(nsName, "System.Runtime.Intrinsics") == 0) ||
2192 (strcmp(nsName, "System.Numerics") == 0))
2194 parNode.simdTypeHnd = CORINFO_CLASS_HANDLE(pMT);
2195 if (parentIndex != UINT32_MAX)
2197 return GetTypeLayoutResult::Success;
2202 ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
2203 for (FieldDesc* pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
2205 CorElementType fieldType = pFD->GetFieldType();
2206 parNode.numFields++;
2208 if (fieldType == ELEMENT_TYPE_VALUETYPE)
2210 MethodTable* pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
2211 GetTypeLayoutResult result = GetTypeLayoutHelper(pFieldMT, structNodeIndex, baseOffs + pFD->GetOffset(), pFD, treeNodes, maxTreeNodes, numTreeNodes);
2212 if (result != GetTypeLayoutResult::Success)
2219 if (*numTreeNodes >= maxTreeNodes)
2221 return GetTypeLayoutResult::Partial;
2224 CorInfoType corInfoType = CEEInfo::asCorInfoType(fieldType);
2225 _ASSERTE(corInfoType != CORINFO_TYPE_UNDEF);
2227 CORINFO_TYPE_LAYOUT_NODE& treeNode = treeNodes[(*numTreeNodes)++];
2228 treeNode.simdTypeHnd = NULL;
2229 treeNode.diagFieldHnd = CORINFO_FIELD_HANDLE(pFD);
2230 treeNode.parent = structNodeIndex;
2231 treeNode.offset = baseOffs + pFD->GetOffset();
2232 treeNode.size = GetSizeForCorElementType(fieldType);
2233 treeNode.numFields = 0;
2234 treeNode.type = corInfoType;
2235 treeNode.hasSignificantPadding = false;
2238 if (pMT->GetClass()->IsInlineArray())
2240 size_t treeNodeEnd = *numTreeNodes;
2241 uint32_t elemSize = pFD->GetSize();
2242 uint32_t arrSize = pMT->GetNumInstanceFieldBytes();
2244 // Number of fields added for each element, including all
2245 // subfields. For example, for ValueTuple<int, int>[4]:
2246 // [ 0]: InlineArray
2247 // [ 1]: ValueTuple<int, int> parent = 0 -
2248 // [ 2]: int parent = 1 |
2249 // [ 3]: int parent = 1 |
2250 // [ 4]: ValueTuple<int, int> parent = 0 - stride = 3
2251 // [ 5]: int parent = 4
2252 // [ 6]: int parent = 4
2253 // [ 7]: ValueTuple<int, int> parent = 0
2254 // [ 8]: int parent = 7
2255 // [ 9]: int parent = 7
2256 // [10]: ValueTuple<int, int> parent = 0
2257 // [11]: int parent = 10
2258 // [12]: int parent = 10
2260 unsigned elemFieldsStride = (unsigned)*numTreeNodes - (structNodeIndex + 1);
2262 // Now duplicate the fields of the previous entry for each
2263 // additional element. For each entry we have to update the offset
2264 // and the parent index.
2265 for (uint32_t elemOffset = elemSize; elemOffset < arrSize; elemOffset += elemSize)
2267 size_t prevElemStart = *numTreeNodes - elemFieldsStride;
2268 for (size_t i = 0; i < elemFieldsStride; i++)
2270 if (*numTreeNodes >= maxTreeNodes)
2272 return GetTypeLayoutResult::Partial;
2275 CORINFO_TYPE_LAYOUT_NODE& treeNode = treeNodes[(*numTreeNodes)++];
2276 treeNode = treeNodes[prevElemStart + i];
2277 treeNode.offset += elemSize;
2278 // The first field points back to the inline array and has
2279 // no bias; the rest of them do.
2280 treeNode.parent += (i == 0) ? 0 : elemFieldsStride;
2283 parNode.numFields++;
2288 return GetTypeLayoutResult::Success;
2291 GetTypeLayoutResult CEEInfo::getTypeLayout(
2292 CORINFO_CLASS_HANDLE clsHnd,
2293 CORINFO_TYPE_LAYOUT_NODE* treeNodes,
2294 size_t* numTreeNodes)
2296 STANDARD_VM_CONTRACT;
2298 GetTypeLayoutResult result = GetTypeLayoutResult::Failure;
2300 JIT_TO_EE_TRANSITION_LEAF();
2302 TypeHandle typeHnd(clsHnd);
2304 if (typeHnd.IsNativeValueType())
2306 if (*numTreeNodes > 0)
2309 treeNodes[0].simdTypeHnd = NULL;
2310 treeNodes[0].diagFieldHnd = NULL;
2311 treeNodes[0].parent = UINT32_MAX;
2312 treeNodes[0].offset = 0;
2313 treeNodes[0].size = typeHnd.GetSize();
2314 treeNodes[0].numFields = 0;
2315 treeNodes[0].type = CORINFO_TYPE_VALUECLASS;
2316 treeNodes[0].hasSignificantPadding = true;
2317 result = GetTypeLayoutResult::Success;
2321 result = GetTypeLayoutResult::Partial;
2324 else if (typeHnd.IsValueType())
2326 MethodTable* pMT = typeHnd.AsMethodTable();
2328 size_t maxTreeNodes = *numTreeNodes;
2330 result = GetTypeLayoutHelper(pMT, UINT32_MAX, 0, NULL, treeNodes, maxTreeNodes, numTreeNodes);
2333 EE_TO_JIT_TRANSITION_LEAF();
2339 CEEInfo::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod)
2347 mdMethodDef result = 0;
2349 JIT_TO_EE_TRANSITION_LEAF();
2351 MethodDesc* pMD = GetMethod(hMethod);
2353 if (pMD->IsDynamicMethod())
2355 // Dynamic methods do not have tokens
2356 result = mdMethodDefNil;
2360 result = pMD->GetMemberDef();
2363 EE_TO_JIT_TRANSITION_LEAF();
2368 bool CEEInfo::checkMethodModifier(CORINFO_METHOD_HANDLE hMethod,
2378 bool result = false;
2380 JIT_TO_EE_TRANSITION();
2382 MethodDesc* pMD = GetMethod(hMethod);
2383 Module* pModule = pMD->GetModule();
2385 CorElementType eeType = fOptional ? ELEMENT_TYPE_CMOD_OPT : ELEMENT_TYPE_CMOD_REQD;
2387 // modopts/modreqs for the method are by convention stored on the return type
2388 result = sig.GetReturnProps().HasCustomModifier(pModule, modifier, eeType);
2390 EE_TO_JIT_TRANSITION();
2395 static unsigned MarkGCField(BYTE* gcPtrs, CorInfoGCType type)
2397 STANDARD_VM_CONTRACT;
2399 // Ensure that if we have multiple fields with the same offset,
2400 // that we don't double count the data in the gc layout.
2401 if (*gcPtrs == TYPE_GC_NONE)
2403 *gcPtrs = (BYTE)type;
2406 else if (*gcPtrs != type)
2408 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
2414 static unsigned ComputeGCLayout(MethodTable* pMT, BYTE* gcPtrs)
2416 STANDARD_VM_CONTRACT;
2418 _ASSERTE(pMT->IsValueType());
2420 unsigned result = 0;
2421 bool isInlineArray = pMT->GetClass()->IsInlineArray();
2422 ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
2423 for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
2425 int fieldStartIndex = pFD->GetOffset() / TARGET_POINTER_SIZE;
2427 if (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
2429 MethodTable* pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
2430 result += ComputeGCLayout(pFieldMT, gcPtrs + fieldStartIndex);
2432 else if (pFD->IsObjRef())
2434 result += MarkGCField(gcPtrs + fieldStartIndex, TYPE_GC_REF);
2436 else if (pFD->IsByRef())
2438 result += MarkGCField(gcPtrs + fieldStartIndex, TYPE_GC_BYREF);
2445 _ASSERTE(pFD->GetOffset() == 0);
2446 DWORD totalLayoutSize = pMT->GetNumInstanceFieldBytes() / TARGET_POINTER_SIZE;
2447 DWORD elementLayoutSize = pFD->GetSize() / TARGET_POINTER_SIZE;
2448 DWORD gcPointersInElement = result;
2449 for (DWORD offset = elementLayoutSize; offset < totalLayoutSize; offset += elementLayoutSize)
2451 memcpy(gcPtrs + offset, gcPtrs, elementLayoutSize);
2452 result += gcPointersInElement;
2456 // inline array has only one element field
2463 unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
2471 unsigned result = 0;
2473 JIT_TO_EE_TRANSITION();
2475 TypeHandle VMClsHnd(clsHnd);
2476 result = getClassGClayoutStatic(VMClsHnd, gcPtrs);
2478 EE_TO_JIT_TRANSITION();
2484 unsigned CEEInfo::getClassGClayoutStatic(TypeHandle VMClsHnd, BYTE* gcPtrs)
2486 STANDARD_VM_CONTRACT;
2488 unsigned result = 0;
2489 MethodTable* pMT = VMClsHnd.GetMethodTable();
2491 if (VMClsHnd.IsNativeValueType())
2493 // native value types have no GC pointers
2495 memset(gcPtrs, TYPE_GC_NONE,
2496 (VMClsHnd.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2498 else if (pMT->IsByRefLike())
2500 memset(gcPtrs, TYPE_GC_NONE,
2501 (VMClsHnd.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2502 // ByRefLike structs can contain byref fields or other ByRefLike structs
2503 result = ComputeGCLayout(VMClsHnd.AsMethodTable(), gcPtrs);
2507 _ASSERTE(sizeof(BYTE) == 1);
2509 BOOL isValueClass = pMT->IsValueType();
2510 unsigned int size = isValueClass ? VMClsHnd.GetSize() : pMT->GetNumInstanceFieldBytes() + OBJECT_SIZE;
2512 // assume no GC pointers at first
2514 memset(gcPtrs, TYPE_GC_NONE,
2515 (size + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE);
2517 // walk the GC descriptors, turning on the correct bits
2518 if (pMT->ContainsPointers())
2520 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
2521 CGCDescSeries * pByValueSeries = map->GetLowestSeries();
2523 for (SIZE_T i = 0; i < map->GetNumSeries(); i++)
2525 // Get offset into the value class of the first pointer field (includes a +Object)
2526 size_t cbSeriesSize = pByValueSeries->GetSeriesSize() + pMT->GetBaseSize();
2527 size_t cbSeriesOffset = pByValueSeries->GetSeriesOffset();
2528 size_t cbOffset = isValueClass ? cbSeriesOffset - OBJECT_SIZE : cbSeriesOffset;
2530 _ASSERTE (cbOffset % TARGET_POINTER_SIZE == 0);
2531 _ASSERTE (cbSeriesSize % TARGET_POINTER_SIZE == 0);
2533 result += (unsigned) (cbSeriesSize / TARGET_POINTER_SIZE);
2534 memset(&gcPtrs[cbOffset / TARGET_POINTER_SIZE], TYPE_GC_REF, cbSeriesSize / TARGET_POINTER_SIZE);
2544 // returns the enregister info for a struct based on type of fields, alignment, etc.
2545 bool CEEInfo::getSystemVAmd64PassStructInRegisterDescriptor(
2546 /*IN*/ CORINFO_CLASS_HANDLE structHnd,
2547 /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr)
2555 #if defined(UNIX_AMD64_ABI_ITF)
2556 JIT_TO_EE_TRANSITION();
2558 _ASSERTE(structPassInRegDescPtr != nullptr);
2559 TypeHandle th(structHnd);
2561 structPassInRegDescPtr->passedInRegisters = false;
2563 // Make sure this is a value type.
2564 if (th.IsValueType())
2566 _ASSERTE(CorInfoType2UnixAmd64Classification(th.GetInternalCorElementType()) == SystemVClassificationTypeStruct);
2568 // The useNativeLayout in this case tracks whether the classification
2569 // is for a native layout of the struct or not.
2570 // If the struct has special marshaling it has a native layout.
2571 // In such cases the classifier needs to use the native layout.
2572 // For structs with no native layout, the managed layout should be used
2573 // even if classified for the purposes of marshaling/PInvoke passing.
2574 bool useNativeLayout = false;
2575 MethodTable* methodTablePtr = nullptr;
2576 if (!th.IsTypeDesc())
2578 methodTablePtr = th.AsMethodTable();
2582 _ASSERTE(th.IsNativeValueType());
2584 useNativeLayout = true;
2585 methodTablePtr = th.AsNativeValueType();
2587 _ASSERTE(methodTablePtr != nullptr);
2589 // If we have full support for UNIX_AMD64_ABI, and not just the interface,
2590 // then we've cached whether this is a reg passed struct in the MethodTable, computed during
2591 // MethodTable construction. Otherwise, we are just building in the interface, and we haven't
2592 // computed or cached anything, so we need to compute it now.
2593 #if defined(UNIX_AMD64_ABI)
2594 bool canPassInRegisters = useNativeLayout ? methodTablePtr->GetNativeLayoutInfo()->IsNativeStructPassedInRegisters()
2595 : methodTablePtr->IsRegPassedStruct();
2596 #else // !defined(UNIX_AMD64_ABI)
2597 bool canPassInRegisters = false;
2598 SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2599 if (th.GetSize() <= CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)
2601 canPassInRegisters = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2603 #endif // !defined(UNIX_AMD64_ABI)
2605 if (canPassInRegisters)
2607 #if defined(UNIX_AMD64_ABI)
2608 SystemVStructRegisterPassingHelper helper((unsigned int)th.GetSize());
2609 bool result = methodTablePtr->ClassifyEightBytes(&helper, 0, 0, useNativeLayout);
2611 // The answer must be true at this point.
2613 #endif // UNIX_AMD64_ABI
2615 structPassInRegDescPtr->passedInRegisters = true;
2617 structPassInRegDescPtr->eightByteCount = (uint8_t)helper.eightByteCount;
2618 _ASSERTE(structPassInRegDescPtr->eightByteCount <= CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS);
2620 for (unsigned int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++)
2622 structPassInRegDescPtr->eightByteClassifications[i] = helper.eightByteClassifications[i];
2623 structPassInRegDescPtr->eightByteSizes[i] = (uint8_t)helper.eightByteSizes[i];
2624 structPassInRegDescPtr->eightByteOffsets[i] = (uint8_t)helper.eightByteOffsets[i];
2628 _ASSERTE(structPassInRegDescPtr->passedInRegisters == canPassInRegisters);
2631 EE_TO_JIT_TRANSITION();
2634 #else // !defined(UNIX_AMD64_ABI_ITF)
2636 #endif // !defined(UNIX_AMD64_ABI_ITF)
2639 /*********************************************************************/
2640 unsigned CEEInfo::getClassNumInstanceFields (CORINFO_CLASS_HANDLE clsHnd)
2648 unsigned result = 0;
2650 JIT_TO_EE_TRANSITION_LEAF();
2652 TypeHandle th(clsHnd);
2654 if (!th.IsTypeDesc())
2656 result = th.AsMethodTable()->GetNumInstanceFields();
2660 // native value types are opaque aggregates with explicit size
2664 EE_TO_JIT_TRANSITION_LEAF();
2670 CorInfoType CEEInfo::asCorInfoType (CORINFO_CLASS_HANDLE clsHnd)
2678 CorInfoType result = CORINFO_TYPE_UNDEF;
2680 JIT_TO_EE_TRANSITION();
2682 TypeHandle VMClsHnd(clsHnd);
2683 result = toJitType(VMClsHnd);
2685 EE_TO_JIT_TRANSITION();
2691 void CEEInfo::getLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* pLookupKind)
2699 /* Initialize fields of result for debug build warning */
2700 pLookupKind->needsRuntimeLookup = false;
2701 pLookupKind->runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
2703 JIT_TO_EE_TRANSITION();
2705 MethodDesc *pContextMD = GetMethod(context);
2707 // If the method table is not shared, then return CONST
2708 if (!pContextMD->GetMethodTable()->IsSharedByGenericInstantiations())
2710 pLookupKind->needsRuntimeLookup = false;
2714 pLookupKind->needsRuntimeLookup = true;
2716 // If we've got a vtable extra argument, go through that
2717 if (pContextMD->RequiresInstMethodTableArg())
2719 pLookupKind->runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
2721 // If we've got an object, go through its vtable
2722 else if (pContextMD->AcquiresInstMethodTableFromThis())
2724 pLookupKind->runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
2726 // Otherwise go through the method-desc argument
2729 _ASSERTE(pContextMD->RequiresInstMethodDescArg());
2730 pLookupKind->runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
2734 EE_TO_JIT_TRANSITION();
2737 CORINFO_METHOD_HANDLE CEEInfo::GetDelegateCtor(
2738 CORINFO_METHOD_HANDLE methHnd,
2739 CORINFO_CLASS_HANDLE clsHnd,
2740 CORINFO_METHOD_HANDLE targetMethodHnd,
2741 DelegateCtorArgs *pCtorData)
2749 CORINFO_METHOD_HANDLE result = NULL;
2751 JIT_TO_EE_TRANSITION();
2753 MethodDesc *pCurrentCtor = (MethodDesc*)methHnd;
2754 if (!pCurrentCtor->IsFCall())
2760 MethodDesc *pTargetMethod = (MethodDesc*)targetMethodHnd;
2761 TypeHandle delegateType = (TypeHandle)clsHnd;
2763 MethodDesc *pDelegateCtor = COMDelegate::GetDelegateCtor(delegateType, pTargetMethod, pCtorData);
2765 pDelegateCtor = pCurrentCtor;
2766 result = (CORINFO_METHOD_HANDLE)pDelegateCtor;
2769 EE_TO_JIT_TRANSITION();
2774 void CEEInfo::MethodCompileComplete(CORINFO_METHOD_HANDLE methHnd)
2782 JIT_TO_EE_TRANSITION();
2784 MethodDesc* pMD = GetMethod(methHnd);
2786 if (pMD->IsDynamicMethod())
2788 pMD->AsDynamicMethodDesc()->GetResolver()->FreeCompileTimeState();
2791 EE_TO_JIT_TRANSITION();
2794 // Given a module scope (scopeHnd), a method handle (context) and an metadata token,
2795 // attempt to load the handle (type, field or method) associated with the token.
2796 // If this is not possible at compile-time (because the method code is shared and the token contains type parameters)
2797 // then indicate how the handle should be looked up at run-time.
2799 // See corinfo.h for more details
2801 void CEEInfo::embedGenericHandle(
2802 CORINFO_RESOLVED_TOKEN * pResolvedToken,
2804 CORINFO_GENERICHANDLE_RESULT *pResult)
2812 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
2814 JIT_TO_EE_TRANSITION();
2816 BOOL fRuntimeLookup;
2817 MethodDesc * pTemplateMD = NULL;
2819 if (!fEmbedParent && pResolvedToken->hMethod != NULL)
2821 MethodDesc * pMD = (MethodDesc *)pResolvedToken->hMethod;
2822 TypeHandle th(pResolvedToken->hClass);
2824 pResult->handleType = CORINFO_HANDLETYPE_METHOD;
2826 Instantiation methodInst = pMD->GetMethodInstantiation();
2828 pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, th.GetMethodTable(), FALSE, methodInst, FALSE);
2830 // Normalize the method handle for reflection
2831 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Ldtoken)
2832 pMD = MethodDesc::FindOrCreateAssociatedMethodDescForReflection(pMD, th, methodInst);
2834 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pMD;
2837 // Runtime lookup is only required for stubs. Regular entrypoints are always the same shared MethodDescs.
2838 fRuntimeLookup = pMD->IsWrapperStub() &&
2839 (th.IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(methodInst));
2842 if (!fEmbedParent && pResolvedToken->hField != NULL)
2844 FieldDesc * pFD = (FieldDesc *)pResolvedToken->hField;
2845 TypeHandle th(pResolvedToken->hClass);
2847 pResult->handleType = CORINFO_HANDLETYPE_FIELD;
2849 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pFD;
2851 fRuntimeLookup = th.IsSharedByGenericInstantiations() && pFD->IsStatic();
2855 TypeHandle th(pResolvedToken->hClass);
2857 pResult->handleType = CORINFO_HANDLETYPE_CLASS;
2858 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsPtr();
2860 if (fEmbedParent && pResolvedToken->hMethod != NULL)
2862 MethodDesc * pDeclaringMD = (MethodDesc *)pResolvedToken->hMethod;
2864 if (!pDeclaringMD->GetMethodTable()->HasSameTypeDefAs(th.GetMethodTable()))
2867 // The method type may point to a sub-class of the actual class that declares the method.
2868 // It is important to embed the declaring type in this case.
2871 pTemplateMD = pDeclaringMD;
2873 pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)pDeclaringMD->GetMethodTable();
2877 // IsSharedByGenericInstantiations would not work here. The runtime lookup is required
2878 // even for standalone generic variables that show up as __Canon here.
2879 fRuntimeLookup = th.IsCanonicalSubtype();
2882 _ASSERTE(pResult->compileTimeHandle);
2886 DictionaryEntryKind entryKind = EmptySlot;
2887 switch (pResult->handleType)
2889 case CORINFO_HANDLETYPE_CLASS:
2890 entryKind = (pTemplateMD != NULL) ? DeclaringTypeHandleSlot : TypeHandleSlot;
2892 case CORINFO_HANDLETYPE_METHOD:
2893 entryKind = MethodDescSlot;
2895 case CORINFO_HANDLETYPE_FIELD:
2896 entryKind = FieldDescSlot;
2902 ComputeRuntimeLookupForSharedGenericToken(entryKind,
2910 // If the target is not shared then we've already got our result and
2911 // can simply do a static look up
2912 pResult->lookup.lookupKind.needsRuntimeLookup = false;
2914 pResult->lookup.constLookup.handle = pResult->compileTimeHandle;
2915 pResult->lookup.constLookup.accessType = IAT_VALUE;
2918 EE_TO_JIT_TRANSITION();
2922 // EnsureActive is used to track triggers for creation of per-AppDomain state instead, including allocations required for statics and
2923 // triggering of module cctors.
2925 // The basic rule is: There should be no possibility of a module that is "active" to have a direct call into a module that
2926 // is not "active". And we don't want to intercept every call during runtime, so during compile time we track static calls and
2927 // everything that can result in new virtual calls.
2929 // The current algorithm (scan the parent type chain and instantiation variables) is more than enough to maintain this invariant.
2930 // One could come up with a more efficient algorithm that still maintains the invariant, but it may introduce backward compatibility
2933 void CEEInfo::EnsureActive(TypeHandle th, MethodDesc * pMD)
2935 STANDARD_VM_CONTRACT;
2937 if (pMD != NULL && pMD->HasMethodInstantiation())
2938 pMD->EnsureActive();
2939 if (!th.IsTypeDesc())
2940 th.AsMethodTable()->EnsureInstanceActive();
2943 CORINFO_OBJECT_HANDLE CEEInfo::getJitHandleForObject(OBJECTREF objref, bool knownFrozen)
2953 Object* obj = OBJECTREFToObject(objref);
2954 if (knownFrozen || GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
2956 return (CORINFO_OBJECT_HANDLE)obj;
2959 if (m_pJitHandles == nullptr)
2961 m_pJitHandles = new SArray<OBJECTHANDLE>();
2964 OBJECTHANDLEHolder handle = AppDomain::GetCurrentDomain()->CreateHandle(objref);
2965 m_pJitHandles->Append(handle);
2966 handle.SuppressRelease();
2968 // We know that handle is aligned so we use the lowest bit as a marker
2969 // "this is a handle, not a frozen object".
2970 return (CORINFO_OBJECT_HANDLE)((size_t)handle.GetValue() | 1);
2973 OBJECTREF CEEInfo::getObjectFromJitHandle(CORINFO_OBJECT_HANDLE handle)
2983 size_t intHandle = (size_t)handle;
2986 return ObjectToOBJECTREF(*(Object**)(intHandle - 1));
2990 return ObjectToOBJECTREF((Object*)intHandle);
2993 MethodDesc * CEEInfo::GetMethodForSecurity(CORINFO_METHOD_HANDLE callerHandle)
2995 STANDARD_VM_CONTRACT;
2997 // Cache the cast lookup
2998 if (callerHandle == m_hMethodForSecurity_Key)
3000 return m_pMethodForSecurity_Value;
3003 MethodDesc * pCallerMethod = (MethodDesc *)callerHandle;
3005 //If the caller is generic, load the open type and then load the field again, This allows us to
3006 //differentiate between BadGeneric<T> containing a memberRef for a field of type InaccessibleClass and
3007 //GoodGeneric<T> containing a memberRef for a field of type T instantiated over InaccessibleClass.
3008 MethodDesc * pMethodForSecurity = pCallerMethod->IsILStub() ?
3009 pCallerMethod : pCallerMethod->LoadTypicalMethodDefinition();
3011 m_hMethodForSecurity_Key = callerHandle;
3012 m_pMethodForSecurity_Value = pMethodForSecurity;
3014 return pMethodForSecurity;
3017 // Check that the instantiation is <!/!!0, ..., !/!!(n-1)>
3018 static bool IsSignatureForTypicalInstantiation(SigPointer sigptr, CorElementType varType, ULONG ntypars)
3020 STANDARD_VM_CONTRACT;
3022 for (uint32_t i = 0; i < ntypars; i++)
3024 CorElementType type;
3025 IfFailThrow(sigptr.GetElemType(&type));
3026 if (type != varType)
3030 IfFailThrow(sigptr.GetData(&data));
3039 // Check that methodSpec instantiation is <!!0, ..., !!(n-1)>
3040 static bool IsMethodSpecForTypicalInstantiation(SigPointer sigptr)
3042 STANDARD_VM_CONTRACT;
3045 IfFailThrow(sigptr.GetByte(&etype));
3046 _ASSERTE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST);
3049 IfFailThrow(sigptr.GetData(&ntypars));
3051 return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_MVAR, ntypars);
3054 // Check that typeSpec instantiation is <!0, ..., !(n-1)>
3055 static bool IsTypeSpecForTypicalInstantiation(SigPointer sigptr)
3057 STANDARD_VM_CONTRACT;
3059 CorElementType type;
3060 IfFailThrow(sigptr.GetElemType(&type));
3061 if (type != ELEMENT_TYPE_GENERICINST)
3064 IfFailThrow(sigptr.SkipExactlyOne());
3067 IfFailThrow(sigptr.GetData(&ntypars));
3069 return IsSignatureForTypicalInstantiation(sigptr, ELEMENT_TYPE_VAR, ntypars);
3072 void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entryKind,
3073 CORINFO_RESOLVED_TOKEN * pResolvedToken,
3074 CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
3075 MethodDesc * pTemplateMD /* for method-based slots */,
3076 CORINFO_LOOKUP *pResultLookup)
3080 PRECONDITION(CheckPointer(pResultLookup));
3083 pResultLookup->lookupKind.needsRuntimeLookup = true;
3084 pResultLookup->lookupKind.runtimeLookupFlags = 0;
3086 CORINFO_RUNTIME_LOOKUP *pResult = &pResultLookup->runtimeLookup;
3087 pResult->signature = NULL;
3089 pResult->indirectFirstOffset = 0;
3090 pResult->indirectSecondOffset = 0;
3092 // Dictionary size checks skipped by default, unless we decide otherwise
3093 pResult->sizeOffset = CORINFO_NO_SIZE_CHECK;
3095 // Unless we decide otherwise, just do the lookup via a helper function
3096 pResult->indirections = CORINFO_USEHELPER;
3098 // Runtime lookups in inlined contexts are not supported by the runtime for now
3099 if (pResolvedToken->tokenContext != METHOD_BEING_COMPILED_CONTEXT())
3101 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_NOT_SUPPORTED;
3105 MethodDesc* pContextMD = GetMethodFromContext(pResolvedToken->tokenContext);
3106 MethodTable* pContextMT = pContextMD->GetMethodTable();
3107 bool isStaticVirtual = (pConstrainedResolvedToken != nullptr && pContextMD != nullptr && pContextMD->IsStatic());
3109 // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup.
3110 if (!pContextMD->IsSharedByGenericInstantiations())
3111 COMPlusThrow(kInvalidProgramException);
3113 BOOL fInstrument = FALSE;
3115 if (pContextMD->RequiresInstMethodDescArg())
3117 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_METHODPARAM;
3121 if (pContextMD->RequiresInstMethodTableArg())
3122 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_CLASSPARAM;
3124 pResultLookup->lookupKind.runtimeLookupKind = CORINFO_LOOKUP_THISOBJ;
3127 // If we've got a method type parameter of any kind then we must look in the method desc arg
3128 if (pContextMD->RequiresInstMethodDescArg())
3130 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG : CORINFO_HELP_RUNTIMEHANDLE_METHOD;
3136 // (1) Naked method type variable: look up directly in instantiation hanging off runtime md
3137 // (2) Reference to method-spec of current method (e.g. a recursive call) i.e. currentmeth<!0,...,!(n-1)>
3138 if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3140 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3141 CorElementType type;
3142 IfFailThrow(sigptr.GetElemType(&type));
3143 if (type == ELEMENT_TYPE_MVAR)
3145 pResult->indirections = 2;
3146 pResult->testForNull = 0;
3147 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3150 IfFailThrow(sigptr.GetData(&data));
3151 pResult->offsets[1] = sizeof(TypeHandle) * data;
3156 else if (entryKind == MethodDescSlot)
3158 // It's the context itself (i.e. a recursive call)
3159 if (!pTemplateMD->HasSameMethodDefAs(pContextMD))
3162 // Now just check that the instantiation is (!!0, ..., !!(n-1))
3163 if (!IsMethodSpecForTypicalInstantiation(SigPointer(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec)))
3166 // Type instantiation has to match too if there is one
3167 if (pContextMT->HasInstantiation())
3169 TypeHandle thTemplate(pResolvedToken->hClass);
3171 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3174 // This check filters out method instantiation on generic type definition, like G::M<!!0>()
3175 // We may not ever get it here. Filter it out just to be sure...
3176 if (pResolvedToken->pTypeSpec == NULL)
3179 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3183 // Just use the method descriptor that was passed in!
3184 pResult->indirections = 0;
3185 pResult->testForNull = 0;
3190 // Otherwise we must just have class type variables
3193 _ASSERTE(pContextMT->GetNumGenericArgs() > 0);
3195 if (pContextMD->RequiresInstMethodTableArg())
3197 // If we've got a vtable extra argument, go through that
3198 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3200 // If we've got an object, go through its vtable
3203 _ASSERTE(pContextMD->AcquiresInstMethodTableFromThis());
3204 pResult->helper = fInstrument ? CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG : CORINFO_HELP_RUNTIMEHANDLE_CLASS;
3211 // (1) Naked class type variable: look up directly in instantiation hanging off vtable
3212 // (2) C<!0,...,!(n-1)> where C is the context's class and C is sealed: just return vtable ptr
3213 if ((entryKind == TypeHandleSlot) && (pResolvedToken->tokenType != CORINFO_TOKENKIND_Newarr))
3215 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3216 CorElementType type;
3217 IfFailThrow(sigptr.GetElemType(&type));
3218 if (type == ELEMENT_TYPE_VAR)
3220 pResult->indirections = 3;
3221 pResult->testForNull = 0;
3222 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3223 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3225 IfFailThrow(sigptr.GetData(&data));
3226 pResult->offsets[2] = sizeof(TypeHandle) * data;
3230 else if (type == ELEMENT_TYPE_GENERICINST &&
3231 (pContextMT->IsSealed() || pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_CLASSPARAM))
3233 TypeHandle thTemplate(pResolvedToken->hClass);
3235 if (thTemplate.IsTypeDesc() || !thTemplate.AsMethodTable()->HasSameTypeDefAs(pContextMT))
3238 if (!IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec)))
3241 // Just use the vtable pointer itself!
3242 pResult->indirections = 0;
3243 pResult->testForNull = 0;
3252 SigBuilder sigBuilder;
3254 sigBuilder.AppendData(entryKind);
3256 if (pResultLookup->lookupKind.runtimeLookupKind != CORINFO_LOOKUP_METHODPARAM)
3258 _ASSERTE(pContextMT->GetNumDicts() > 0);
3259 sigBuilder.AppendData(pContextMT->GetNumDicts() - 1);
3262 Module * pModule = (Module *)pResolvedToken->tokenScope;
3266 case DeclaringTypeHandleSlot:
3267 _ASSERTE(pTemplateMD != NULL);
3268 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3269 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3272 case TypeHandleSlot:
3274 if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
3276 sigBuilder.AppendElementType(ELEMENT_TYPE_SZARRAY);
3279 // Note that we can come here with pResolvedToken->pTypeSpec == NULL for invalid IL that
3280 // directly references __Canon
3281 if (pResolvedToken->pTypeSpec != NULL)
3283 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3284 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3288 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3289 sigBuilder.AppendPointer(pResolvedToken->hClass);
3294 case ConstrainedMethodEntrySlot:
3295 // Encode constrained type token
3296 if (pConstrainedResolvedToken->pTypeSpec != NULL)
3298 SigPointer sigptr(pConstrainedResolvedToken->pTypeSpec, pConstrainedResolvedToken->cbTypeSpec);
3299 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3303 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3304 sigBuilder.AppendPointer(pConstrainedResolvedToken->hClass);
3308 case MethodDescSlot:
3309 case MethodEntrySlot:
3310 case DispatchStubAddrSlot:
3312 // Encode containing type
3313 if (pResolvedToken->pTypeSpec != NULL)
3315 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3316 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3320 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3321 sigBuilder.AppendPointer(pResolvedToken->hClass);
3325 _ASSERTE(pTemplateMD != NULL);
3327 mdMethodDef methodToken = pTemplateMD->GetMemberDef();
3328 DWORD methodFlags = 0;
3330 // 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
3331 // like instantiating stub for generic method definition that do not have method spec but that won't be caught by the later conditions either.
3332 BOOL fMethodNeedsInstantiation = (pResolvedToken->pMethodSpec != NULL) && pTemplateMD->HasMethodInstantiation() && !pTemplateMD->IsGenericMethodDefinition();
3334 if (pTemplateMD->IsUnboxingStub())
3335 methodFlags |= ENCODE_METHOD_SIG_UnboxingStub;
3336 // Always create instantiating stub for method entry points even if the template does not ask for it. It saves caller
3337 // from creating throw-away instantiating stub.
3338 if (pTemplateMD->IsInstantiatingStub() || (entryKind == MethodEntrySlot))
3339 methodFlags |= ENCODE_METHOD_SIG_InstantiatingStub;
3340 if (fMethodNeedsInstantiation)
3341 methodFlags |= ENCODE_METHOD_SIG_MethodInstantiation;
3342 if (IsNilToken(methodToken))
3344 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3347 if (entryKind == DispatchStubAddrSlot && pTemplateMD->IsVtableMethod())
3349 // Encode the method for dispatch stub using slot to avoid touching the interface method MethodDesc at runtime
3351 // There should be no other flags set if we are encoding the method using slot for virtual stub dispatch
3352 _ASSERTE(methodFlags == 0);
3354 methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
3357 sigBuilder.AppendData(methodFlags);
3359 if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
3361 // Encode method token and its module context (as method's type)
3362 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3363 sigBuilder.AppendPointer(pTemplateMD->GetMethodTable());
3365 sigBuilder.AppendData(RidFromToken(methodToken));
3369 sigBuilder.AppendData(pTemplateMD->GetSlot());
3372 if (fMethodNeedsInstantiation)
3374 SigPointer sigptr(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
3377 IfFailThrow(sigptr.GetByte(&etype));
3379 // Load the generic method instantiation
3380 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, pModule);
3382 uint32_t nGenericMethodArgs;
3383 IfFailThrow(sigptr.GetData(&nGenericMethodArgs));
3384 sigBuilder.AppendData(nGenericMethodArgs);
3386 _ASSERTE(nGenericMethodArgs == pTemplateMD->GetNumGenericMethodArgs());
3388 for (DWORD i = 0; i < nGenericMethodArgs; i++)
3390 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3398 if (pResolvedToken->pTypeSpec != NULL)
3400 // Encode containing type
3401 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
3402 sigptr.ConvertToInternalExactlyOne(pModule, NULL, &sigBuilder);
3406 sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL);
3407 sigBuilder.AppendPointer(pResolvedToken->hClass);
3410 FieldDesc * pField = (FieldDesc *)pResolvedToken->hField;
3411 _ASSERTE(pField != NULL);
3413 DWORD fieldIndex = pField->GetApproxEnclosingMethodTable()->GetIndexForFieldDesc(pField);
3414 sigBuilder.AppendData(fieldIndex);
3422 DictionaryEntrySignatureSource signatureSource = FromJIT;
3426 // It's a method dictionary lookup
3427 if (pResultLookup->lookupKind.runtimeLookupKind == CORINFO_LOOKUP_METHODPARAM)
3429 _ASSERTE(pContextMD != NULL);
3430 _ASSERTE(pContextMD->HasMethodInstantiation());
3432 if (DictionaryLayout::FindToken(pContextMD, pContextMD->GetLoaderAllocator(), 1, &sigBuilder, NULL, signatureSource, pResult, &slot))
3434 pResult->testForNull = 1;
3435 int minDictSize = pContextMD->GetNumGenericMethodArgs() + 1 + pContextMD->GetDictionaryLayout()->GetNumInitialSlots();
3436 if (slot >= minDictSize)
3438 // Dictionaries are guaranteed to have at least the number of slots allocated initially, so skip size check for smaller indexes
3439 pResult->sizeOffset = (WORD)pContextMD->GetNumGenericMethodArgs() * sizeof(DictionaryEntry);
3442 // Indirect through dictionary table pointer in InstantiatedMethodDesc
3443 pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
3447 // It's a class dictionary lookup (CORINFO_LOOKUP_CLASSPARAM or CORINFO_LOOKUP_THISOBJ)
3450 if (DictionaryLayout::FindToken(pContextMT, pContextMT->GetLoaderAllocator(), 2, &sigBuilder, NULL, signatureSource, pResult, &slot))
3452 pResult->testForNull = 1;
3453 int minDictSize = pContextMT->GetNumGenericArgs() + 1 + pContextMT->GetClass()->GetDictionaryLayout()->GetNumInitialSlots();
3454 if (slot >= minDictSize)
3456 // Dictionaries are guaranteed to have at least the number of slots allocated initially, so skip size check for smaller indexes
3457 pResult->sizeOffset = (WORD)pContextMT->GetNumGenericArgs() * sizeof(DictionaryEntry);
3460 // Indirect through dictionary table pointer in vtable
3461 pResult->offsets[0] = MethodTable::GetOffsetOfPerInstInfo();
3463 // Next indirect through the dictionary appropriate to this instantiated type
3464 pResult->offsets[1] = sizeof(TypeHandle*) * (pContextMT->GetNumDicts() - 1);
3469 void CEEInfo::AddTransientMethodDetails(TransientMethodDetails details)
3471 STANDARD_VM_CONTRACT;
3472 _ASSERTE(details.Method != NULL);
3474 if (m_transientDetails == NULL)
3475 m_transientDetails = new SArray<TransientMethodDetails, FALSE>();
3476 m_transientDetails->Append(std::move(details));
3479 TransientMethodDetails CEEInfo::RemoveTransientMethodDetails(MethodDesc* pMD)
3481 STANDARD_VM_CONTRACT;
3482 _ASSERTE(pMD != NULL);
3484 TransientMethodDetails local{};
3485 TransientMethodDetails* details;
3486 if (FindTransientMethodDetails(pMD, &details))
3488 // Details found, move contents to return
3489 // and default initialize the found instance.
3490 local = std::move(*details);
3496 bool CEEInfo::FindTransientMethodDetails(MethodDesc* pMD, TransientMethodDetails** details)
3498 STANDARD_VM_CONTRACT;
3499 _ASSERTE(pMD != NULL);
3500 _ASSERTE(details != NULL);
3502 if (m_transientDetails != NULL)
3504 TransientMethodDetails* curr = m_transientDetails->GetElements();
3505 TransientMethodDetails* end = curr + m_transientDetails->GetCount();
3506 for (;curr != end; ++curr)
3508 if (curr->Method == pMD)
3518 /*********************************************************************/
3519 size_t CEEInfo::printClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize)
3527 size_t bytesWritten = 0;
3529 JIT_TO_EE_TRANSITION();
3531 size_t requiredBufferSize = 0;
3534 IMDInternalImport* pImport = th.GetMethodTable()->GetMDImport();
3536 auto append = [buffer, bufferSize, &bytesWritten, &requiredBufferSize](const char* str)
3538 size_t strLen = strlen(str);
3540 if ((buffer != nullptr) && (bytesWritten + 1 < bufferSize))
3542 if (bytesWritten + strLen >= bufferSize)
3544 memcpy(buffer + bytesWritten, str, bufferSize - bytesWritten - 1);
3545 bytesWritten = bufferSize - 1;
3549 memcpy(buffer + bytesWritten, str, strLen);
3550 bytesWritten += strLen;
3554 requiredBufferSize += strLen;
3557 // Subset of TypeString that does just what we need while staying in UTF8
3558 // and avoiding expensive copies. This function is called a lot in checked
3560 // One difference is that we do not handle escaping type names here (see
3561 // IsTypeNameReservedChar). The situation is rare and somewhat complicated
3562 // to handle since it requires iterating UTF8 encoded codepoints. Given
3563 // that this function is only needed for diagnostics the complication seems
3565 mdTypeDef td = th.GetCl();
3568 append("(dynamicClass)");
3573 IfFailThrow(pImport->GetTypeDefProps(td, &attr, NULL));
3575 StackSArray<mdTypeDef> nestedHierarchy;
3576 nestedHierarchy.Append(td);
3578 if (IsTdNested(attr))
3580 while (SUCCEEDED(pImport->GetNestedClassProps(td, &td)))
3581 nestedHierarchy.Append(td);
3584 for (SCOUNT_T i = nestedHierarchy.GetCount() - 1; i >= 0; i--)
3588 IfFailThrow(pImport->GetNameOfTypeDef(nestedHierarchy[i], &name, &nameSpace));
3590 if ((nameSpace != NULL) && (*nameSpace != '\0'))
3607 _ASSERTE(bytesWritten < bufferSize);
3608 buffer[bytesWritten] = '\0';
3611 if (pRequiredBufferSize != nullptr)
3613 *pRequiredBufferSize = requiredBufferSize + 1;
3616 EE_TO_JIT_TRANSITION();
3618 return bytesWritten;
3621 /*********************************************************************/
3622 CORINFO_MODULE_HANDLE CEEInfo::getClassModule(CORINFO_CLASS_HANDLE clsHnd)
3630 CORINFO_MODULE_HANDLE result = NULL;
3632 JIT_TO_EE_TRANSITION_LEAF();
3634 TypeHandle VMClsHnd(clsHnd);
3636 result = CORINFO_MODULE_HANDLE(VMClsHnd.GetModule());
3638 EE_TO_JIT_TRANSITION_LEAF();
3643 /*********************************************************************/
3644 CORINFO_ASSEMBLY_HANDLE CEEInfo::getModuleAssembly(CORINFO_MODULE_HANDLE modHnd)
3652 CORINFO_ASSEMBLY_HANDLE result = NULL;
3654 JIT_TO_EE_TRANSITION_LEAF();
3656 result = CORINFO_ASSEMBLY_HANDLE(GetModule(modHnd)->GetAssembly());
3658 EE_TO_JIT_TRANSITION_LEAF();
3663 /*********************************************************************/
3664 const char* CEEInfo::getAssemblyName(CORINFO_ASSEMBLY_HANDLE asmHnd)
3672 const char* result = NULL;
3674 JIT_TO_EE_TRANSITION();
3675 result = ((Assembly*)asmHnd)->GetSimpleName();
3676 EE_TO_JIT_TRANSITION();
3681 /*********************************************************************/
3682 void* CEEInfo::LongLifetimeMalloc(size_t sz)
3690 void* result = NULL;
3692 JIT_TO_EE_TRANSITION_LEAF();
3693 result = new (nothrow) char[sz];
3694 EE_TO_JIT_TRANSITION_LEAF();
3699 /*********************************************************************/
3700 void CEEInfo::LongLifetimeFree(void* obj)
3708 JIT_TO_EE_TRANSITION_LEAF();
3709 (operator delete)(obj);
3710 EE_TO_JIT_TRANSITION_LEAF();
3713 /*********************************************************************/
3714 size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_MODULE_HANDLE *pModuleHandle, void **ppIndirection)
3724 JIT_TO_EE_TRANSITION_LEAF();
3726 TypeHandle VMClsHnd(clsHnd);
3727 Module *pModule = VMClsHnd.AsMethodTable()->GetModuleForStatics();
3729 if (ppIndirection != NULL)
3730 *ppIndirection = NULL;
3732 // The zapper needs the module handle. The jit should not use it at all.
3734 *pModuleHandle = CORINFO_MODULE_HANDLE(pModule);
3736 result = pModule->GetModuleID();
3740 EE_TO_JIT_TRANSITION_LEAF();
3745 /*********************************************************************/
3746 bool CEEInfo::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset)
3756 JIT_TO_EE_TRANSITION_LEAF();
3758 TypeHandle clsTypeHandle(cls);
3759 PTR_MethodTable pMT = clsTypeHandle.AsMethodTable();
3761 // Impl is based on IsPrecomputedClassInitialized()
3762 UINT32 clsIndex = 0;
3763 if (pMT->IsDynamicStatics())
3765 clsIndex = (UINT32)pMT->GetModuleDynamicEntryID();
3769 clsIndex = (UINT32)pMT->GetClassIndex();
3772 size_t moduleId = pMT->GetModuleForStatics()->GetModuleID();
3773 addr->addr = (UINT8*)moduleId + DomainLocalModule::GetOffsetOfDataBlob() + clsIndex;
3774 addr->accessType = IAT_VALUE;
3777 EE_TO_JIT_TRANSITION_LEAF();
3782 /*********************************************************************/
3783 bool CEEInfo::getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr)
3791 JIT_TO_EE_TRANSITION_LEAF();
3793 TypeHandle clsTypeHandle(cls);
3794 PTR_MethodTable pMT = clsTypeHandle.AsMethodTable();
3797 addr->addr = isGc ? pMT->GetGCStaticsBasePointer() : pMT->GetNonGCStaticsBasePointer();
3798 addr->accessType = IAT_VALUE;
3800 EE_TO_JIT_TRANSITION_LEAF();
3805 /*********************************************************************/
3806 bool CEEInfo::isValueClass(CORINFO_CLASS_HANDLE clsHnd)
3816 JIT_TO_EE_TRANSITION_LEAF();
3820 ret = TypeHandle(clsHnd).IsValueType();
3822 EE_TO_JIT_TRANSITION_LEAF();
3827 /*********************************************************************/
3828 // Decides how the JIT should do the optimization to inline the check for
3829 // GetTypeFromHandle(handle) == obj.GetType()
3830 // GetTypeFromHandle(X) == GetTypeFromHandle(Y)
3832 // This will enable to use directly the typehandle instead of going through getClassByHandle
3833 CorInfoInlineTypeCheck CEEInfo::canInlineTypeCheck(CORINFO_CLASS_HANDLE clsHnd, CorInfoInlineTypeCheckSource source)
3835 LIMITED_METHOD_CONTRACT;
3836 return CORINFO_INLINE_TYPECHECK_PASS;
3839 /*********************************************************************/
3840 uint32_t CEEInfo::getClassAttribs (CORINFO_CLASS_HANDLE clsHnd)
3848 // <REVISIT_TODO>@todo FIX need to really fetch the class attributes. at present
3849 // we don't need to because the JIT only cares in the case of COM classes</REVISIT_TODO>
3852 JIT_TO_EE_TRANSITION();
3854 ret = getClassAttribsInternal(clsHnd);
3856 EE_TO_JIT_TRANSITION();
3861 /*********************************************************************/
3862 uint32_t CEEInfo::getClassAttribsInternal (CORINFO_CLASS_HANDLE clsHnd)
3864 STANDARD_VM_CONTRACT;
3870 TypeHandle VMClsHnd(clsHnd);
3872 // Byrefs should only occur in method and local signatures, which are accessed
3873 // using ICorClassInfo and ICorClassInfo.getChildType.
3874 // So getClassAttribs() should not be called for byrefs
3876 if (VMClsHnd.IsByRef())
3878 _ASSERTE(!"Did findClass() return a Byref?");
3879 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3881 else if (VMClsHnd.IsGenericVariable())
3883 //@GENERICSVER: for now, type variables simply report "variable".
3884 ret |= CORINFO_FLG_GENERIC_TYPE_VARIABLE;
3888 MethodTable *pMT = VMClsHnd.GetMethodTable();
3892 _ASSERTE(!"Did findClass() return a Byref?");
3893 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
3896 EEClass * pClass = pMT->GetClass();
3898 // The array flag is used to identify the faked-up methods on
3899 // array types, i.e. .ctor, Get, Set and Address
3901 ret |= CORINFO_FLG_ARRAY;
3903 if (pMT->IsInterface())
3904 ret |= CORINFO_FLG_INTERFACE;
3906 if (pMT->HasComponentSize())
3907 ret |= CORINFO_FLG_VAROBJSIZE;
3909 if (VMClsHnd.IsValueType())
3911 ret |= CORINFO_FLG_VALUECLASS;
3913 if (pMT->IsByRefLike())
3914 ret |= CORINFO_FLG_BYREF_LIKE;
3916 if (pClass->IsUnsafeValueClass())
3917 ret |= CORINFO_FLG_UNSAFE_VALUECLASS;
3919 if (pClass->HasExplicitFieldOffsetLayout() && pClass->HasOverlaidField())
3920 ret |= CORINFO_FLG_OVERLAPPING_FIELDS;
3922 if (pClass->IsInlineArray())
3923 ret |= CORINFO_FLG_INDEXABLE_FIELDS;
3925 if (VMClsHnd.IsCanonicalSubtype())
3926 ret |= CORINFO_FLG_SHAREDINST;
3928 if (pMT->HasVariance())
3929 ret |= CORINFO_FLG_VARIANCE;
3931 if (pMT->ContainsPointers() || pMT == g_TypedReferenceMT)
3932 ret |= CORINFO_FLG_CONTAINS_GC_PTR;
3934 if (pMT->IsDelegate())
3935 ret |= CORINFO_FLG_DELEGATE;
3937 if (pClass->IsBeforeFieldInit())
3938 ret |= CORINFO_FLG_BEFOREFIELDINIT;
3940 if (pClass->IsAbstract())
3941 ret |= CORINFO_FLG_ABSTRACT;
3943 if (pClass->IsSealed())
3944 ret |= CORINFO_FLG_FINAL;
3946 if (pMT->IsIntrinsicType())
3947 ret |= CORINFO_FLG_INTRINSIC_TYPE;
3953 /*********************************************************************/
3955 // See code:CorInfoFlag#ClassConstructionFlags for details.
3957 CorInfoInitClassResult CEEInfo::initClass(
3958 CORINFO_FIELD_HANDLE field,
3959 CORINFO_METHOD_HANDLE method,
3960 CORINFO_CONTEXT_HANDLE context)
3968 DWORD result = CORINFO_INITCLASS_NOT_REQUIRED;
3970 JIT_TO_EE_TRANSITION();
3973 FieldDesc * pFD = (FieldDesc *)field;
3974 _ASSERTE(pFD == NULL || pFD->IsStatic());
3976 MethodDesc* pMD = (method != NULL) ? (MethodDesc*)method : m_pMethodBeingCompiled;
3978 TypeHandle typeToInitTH = (pFD != NULL) ? pFD->GetEnclosingMethodTable() : GetTypeFromContext(context);
3980 MethodDesc *methodBeingCompiled = m_pMethodBeingCompiled;
3982 MethodTable *pTypeToInitMT = typeToInitTH.AsMethodTable();
3984 if (pTypeToInitMT->IsClassInited())
3986 // If the type is initialized there really is nothing to do.
3987 result = CORINFO_INITCLASS_INITIALIZED;
3991 if (pTypeToInitMT->IsGlobalClass())
3993 // For both jitted and ngen code the global class is always considered initialized
3994 result = CORINFO_INITCLASS_NOT_REQUIRED;
4000 if (pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4002 // We can wait for field accesses to run .cctor
4003 result = CORINFO_INITCLASS_NOT_REQUIRED;
4007 // Run .cctor on statics & constructors
4008 if (pMD->IsStatic())
4010 // Except don't class construct on .cctor - it would be circular
4011 if (pMD->IsClassConstructor())
4013 result = CORINFO_INITCLASS_NOT_REQUIRED;
4018 // According to the spec, we should be able to do this optimization for both reference and valuetypes.
4019 // To maintain backward compatibility, we are doing it for reference types only.
4020 // We don't do this for interfaces though, as those don't have instance constructors.
4021 if (!pMD->IsCtor() && !pTypeToInitMT->IsValueType() && !pTypeToInitMT->IsInterface())
4023 // For instance methods of types with precise-initialization
4024 // semantics, we can assume that the .ctor triggered the
4025 // type initialization.
4026 // This does not hold for NULL "this" object. However, the spec does
4027 // not require that case to work.
4028 result = CORINFO_INITCLASS_NOT_REQUIRED;
4033 if (pTypeToInitMT->IsSharedByGenericInstantiations())
4035 if ((pFD == NULL) && (method != NULL) && (context == METHOD_BEING_COMPILED_CONTEXT()))
4037 _ASSERTE(pTypeToInitMT == methodBeingCompiled->GetMethodTable());
4038 // If we're inling a call to a method in our own type, then we should already
4039 // have triggered the .cctor when caller was itself called.
4040 result = CORINFO_INITCLASS_NOT_REQUIRED;
4044 // Shared generic code has to use helper. Moreover, tell JIT not to inline since
4045 // inlining of generic dictionary lookups is not supported.
4046 result = CORINFO_INITCLASS_USE_HELPER | CORINFO_INITCLASS_DONT_INLINE;
4051 // Try to prove that the initialization is not necessary because of nesting
4057 _ASSERTE(!pTypeToInitMT->GetClass()->IsBeforeFieldInit());
4059 if (method != NULL && pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4061 // If we're inling a call to a method in our own type, then we should already
4062 // have triggered the .cctor when caller was itself called.
4063 result = CORINFO_INITCLASS_NOT_REQUIRED;
4069 // This optimization may cause static fields in reference types to be accessed without cctor being triggered
4070 // for NULL "this" object. It does not conform with what the spec says. However, we have been historically
4071 // doing it for perf reasons.
4072 if (!pTypeToInitMT->IsValueType() && !pTypeToInitMT->IsInterface() && !pTypeToInitMT->GetClass()->IsBeforeFieldInit())
4074 if (pTypeToInitMT == GetTypeFromContext(context).AsMethodTable() || pTypeToInitMT == methodBeingCompiled->GetMethodTable())
4076 // The class will be initialized by the time we access the field.
4077 result = CORINFO_INITCLASS_NOT_REQUIRED;
4082 // If we are currently compiling the class constructor for this static field access then we can skip the initClass
4083 if (methodBeingCompiled->GetMethodTable() == pTypeToInitMT && methodBeingCompiled->IsStatic() && methodBeingCompiled->IsClassConstructor())
4085 // The class will be initialized by the time we access the field.
4086 result = CORINFO_INITCLASS_NOT_REQUIRED;
4092 // Optimizations for domain specific code
4095 // Allocate space for the local class if necessary, but don't trigger
4096 // class construction.
4097 DomainLocalModule *pModule = pTypeToInitMT->GetDomainLocalModule();
4098 pModule->PopulateClass(pTypeToInitMT);
4100 if (pTypeToInitMT->IsClassInited())
4102 result = CORINFO_INITCLASS_INITIALIZED;
4106 result = CORINFO_INITCLASS_USE_HELPER;
4109 EE_TO_JIT_TRANSITION();
4111 return (CorInfoInitClassResult)result;
4116 void CEEInfo::classMustBeLoadedBeforeCodeIsRun (CORINFO_CLASS_HANDLE typeToLoadHnd)
4124 JIT_TO_EE_TRANSITION_LEAF();
4126 TypeHandle th = TypeHandle(typeToLoadHnd);
4128 // Type handles returned to JIT at runtime are always fully loaded. Verify that it is the case.
4129 _ASSERTE(th.IsFullyLoaded());
4131 EE_TO_JIT_TRANSITION_LEAF();
4134 /*********************************************************************/
4135 void CEEInfo::methodMustBeLoadedBeforeCodeIsRun (CORINFO_METHOD_HANDLE methHnd)
4143 JIT_TO_EE_TRANSITION_LEAF();
4145 MethodDesc *pMD = (MethodDesc*) methHnd;
4147 // MethodDescs returned to JIT at runtime are always fully loaded. Verify that it is the case.
4148 _ASSERTE(pMD->GetMethodTable()->IsFullyLoaded());
4150 EE_TO_JIT_TRANSITION_LEAF();
4153 /*********************************************************************/
4154 CORINFO_METHOD_HANDLE CEEInfo::mapMethodDeclToMethodImpl(CORINFO_METHOD_HANDLE methHnd)
4162 CORINFO_METHOD_HANDLE result = NULL;
4164 JIT_TO_EE_TRANSITION();
4166 MethodDesc *pMD = GetMethod(methHnd);
4167 pMD = MethodTable::MapMethodDeclToMethodImpl(pMD);
4168 result = (CORINFO_METHOD_HANDLE) pMD;
4170 EE_TO_JIT_TRANSITION();
4175 /*********************************************************************/
4176 CORINFO_CLASS_HANDLE CEEInfo::getBuiltinClass(CorInfoClassId classId)
4184 CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE) 0;
4186 JIT_TO_EE_TRANSITION();
4190 case CLASSID_SYSTEM_OBJECT:
4191 result = CORINFO_CLASS_HANDLE(g_pObjectClass);
4193 case CLASSID_TYPED_BYREF:
4194 result = CORINFO_CLASS_HANDLE(g_TypedReferenceMT);
4196 case CLASSID_TYPE_HANDLE:
4197 result = CORINFO_CLASS_HANDLE(CoreLibBinder::GetClass(CLASS__TYPE_HANDLE));
4199 case CLASSID_FIELD_HANDLE:
4200 result = CORINFO_CLASS_HANDLE(CoreLibBinder::GetClass(CLASS__FIELD_HANDLE));
4202 case CLASSID_METHOD_HANDLE:
4203 result = CORINFO_CLASS_HANDLE(CoreLibBinder::GetClass(CLASS__METHOD_HANDLE));
4205 case CLASSID_ARGUMENT_HANDLE:
4206 result = CORINFO_CLASS_HANDLE(CoreLibBinder::GetClass(CLASS__ARGUMENT_HANDLE));
4208 case CLASSID_STRING:
4209 result = CORINFO_CLASS_HANDLE(g_pStringClass);
4211 case CLASSID_RUNTIME_TYPE:
4212 result = CORINFO_CLASS_HANDLE(g_pRuntimeTypeClass);
4215 _ASSERTE(!"NYI: unknown classId");
4219 EE_TO_JIT_TRANSITION();
4226 /*********************************************************************/
4227 CorInfoType CEEInfo::getTypeForPrimitiveValueClass(
4228 CORINFO_CLASS_HANDLE clsHnd)
4236 CorInfoType result = CORINFO_TYPE_UNDEF;
4238 JIT_TO_EE_TRANSITION();
4240 TypeHandle th(clsHnd);
4241 _ASSERTE (!th.IsGenericVariable());
4243 CorElementType elementType = th.GetVerifierCorElementType();
4244 if (CorIsPrimitiveType(elementType))
4246 result = asCorInfoType(elementType);
4248 EE_TO_JIT_TRANSITION();
4253 /*********************************************************************/
4254 CorInfoType CEEInfo::getTypeForPrimitiveNumericClass(
4255 CORINFO_CLASS_HANDLE clsHnd)
4263 CorInfoType result = CORINFO_TYPE_UNDEF;
4265 JIT_TO_EE_TRANSITION_LEAF();
4267 TypeHandle th(clsHnd);
4268 _ASSERTE (!th.IsGenericVariable());
4270 CorElementType ty = th.GetSignatureCorElementType();
4273 case ELEMENT_TYPE_I1:
4274 result = CORINFO_TYPE_BYTE;
4276 case ELEMENT_TYPE_U1:
4277 result = CORINFO_TYPE_UBYTE;
4279 case ELEMENT_TYPE_I2:
4280 result = CORINFO_TYPE_SHORT;
4282 case ELEMENT_TYPE_U2:
4283 result = CORINFO_TYPE_USHORT;
4285 case ELEMENT_TYPE_I4:
4286 result = CORINFO_TYPE_INT;
4288 case ELEMENT_TYPE_U4:
4289 result = CORINFO_TYPE_UINT;
4291 case ELEMENT_TYPE_I8:
4292 result = CORINFO_TYPE_LONG;
4294 case ELEMENT_TYPE_U8:
4295 result = CORINFO_TYPE_ULONG;
4297 case ELEMENT_TYPE_R4:
4298 result = CORINFO_TYPE_FLOAT;
4300 case ELEMENT_TYPE_R8:
4301 result = CORINFO_TYPE_DOUBLE;
4303 case ELEMENT_TYPE_I:
4304 result = CORINFO_TYPE_NATIVEINT;
4306 case ELEMENT_TYPE_U:
4307 result = CORINFO_TYPE_NATIVEUINT;
4311 // Error case, we will return CORINFO_TYPE_UNDEF
4315 JIT_TO_EE_TRANSITION_LEAF();
4321 void CEEInfo::getGSCookie(GSCookie * pCookieVal, GSCookie ** ppCookieVal)
4329 JIT_TO_EE_TRANSITION();
4333 *pCookieVal = GetProcessGSCookie();
4334 *ppCookieVal = NULL;
4338 *ppCookieVal = GetProcessGSCookiePtr();
4341 EE_TO_JIT_TRANSITION();
4345 /*********************************************************************/
4346 // TRUE if child is a subtype of parent
4347 // if parent is an interface, then does child implement / extend parent
4348 bool CEEInfo::canCast(
4349 CORINFO_CLASS_HANDLE child,
4350 CORINFO_CLASS_HANDLE parent)
4358 bool result = false;
4360 JIT_TO_EE_TRANSITION();
4362 result = !!((TypeHandle)child).CanCastTo((TypeHandle)parent);
4364 EE_TO_JIT_TRANSITION();
4369 /*********************************************************************/
4370 // See if a cast from fromClass to toClass will succeed, fail, or needs
4371 // to be resolved at runtime.
4372 TypeCompareState CEEInfo::compareTypesForCast(
4373 CORINFO_CLASS_HANDLE fromClass,
4374 CORINFO_CLASS_HANDLE toClass)
4382 TypeCompareState result = TypeCompareState::May;
4384 JIT_TO_EE_TRANSITION();
4386 TypeHandle fromHnd = (TypeHandle) fromClass;
4387 TypeHandle toHnd = (TypeHandle) toClass;
4389 #ifdef FEATURE_COMINTEROP
4390 // If casting from a com object class, don't try to optimize.
4391 if (fromHnd.IsComObjectType())
4393 result = TypeCompareState::May;
4396 #endif // FEATURE_COMINTEROP
4398 // If casting from ICastable or IDynamicInterfaceCastable, don't try to optimize
4399 if (fromHnd.GetMethodTable()->IsICastable() || fromHnd.GetMethodTable()->IsIDynamicInterfaceCastable())
4401 result = TypeCompareState::May;
4403 // If casting to Nullable<T>, don't try to optimize
4404 else if (Nullable::IsNullableType(toHnd))
4406 result = TypeCompareState::May;
4408 // If the types are not shared, we can check directly.
4409 else if (!fromHnd.IsCanonicalSubtype() && !toHnd.IsCanonicalSubtype())
4411 result = fromHnd.CanCastTo(toHnd) ? TypeCompareState::Must : TypeCompareState::MustNot;
4413 // Casting from a shared type to an unshared type.
4414 else if (fromHnd.IsCanonicalSubtype() && !toHnd.IsCanonicalSubtype())
4416 // Only handle casts to interface types for now
4417 if (toHnd.IsInterface())
4419 // Do a preliminary check.
4420 BOOL canCast = fromHnd.CanCastTo(toHnd);
4422 // Pass back positive results unfiltered. The unknown type
4423 // parameters in fromClass did not come into play.
4426 result = TypeCompareState::Must;
4428 // We have __Canon parameter(s) in fromClass, somewhere.
4430 // In CanCastTo, these __Canon(s) won't match the interface or
4431 // instantiated types on the interface, so CanCastTo may
4432 // return false negatives.
4434 // Only report MustNot if the fromClass is not __Canon
4435 // and the interface is not instantiated; then there is
4436 // no way for the fromClass __Canon(s) to confuse things.
4438 // __Canon -> IBar May
4439 // IFoo<__Canon> -> IFoo<string> May
4440 // IFoo<__Canon> -> IBar MustNot
4442 else if (fromHnd == TypeHandle(g_pCanonMethodTableClass))
4444 result = TypeCompareState::May;
4446 else if (toHnd.HasInstantiation())
4448 result = TypeCompareState::May;
4452 result = TypeCompareState::MustNot;
4457 EE_TO_JIT_TRANSITION();
4462 /*********************************************************************/
4463 // See if types represented by cls1 and cls2 compare equal, not
4464 // equal, or the comparison needs to be resolved at runtime.
4465 TypeCompareState CEEInfo::compareTypesForEquality(
4466 CORINFO_CLASS_HANDLE cls1,
4467 CORINFO_CLASS_HANDLE cls2)
4475 TypeCompareState result = TypeCompareState::May;
4477 JIT_TO_EE_TRANSITION();
4479 TypeHandle hnd1 = (TypeHandle) cls1;
4480 TypeHandle hnd2 = (TypeHandle) cls2;
4482 // If neither type is a canonical subtype, type handle comparison suffices
4483 if (!hnd1.IsCanonicalSubtype() && !hnd2.IsCanonicalSubtype())
4485 result = (hnd1 == hnd2 ? TypeCompareState::Must : TypeCompareState::MustNot);
4487 // If either or both types are canonical subtypes, we can sometimes prove inequality.
4490 // If either is a value type then the types cannot
4491 // be equal unless the type defs are the same.
4492 if (hnd1.IsValueType() || hnd2.IsValueType())
4494 if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
4496 result = TypeCompareState::MustNot;
4499 // If we have two ref types that are not __Canon, then the
4500 // types cannot be equal unless the type defs are the same.
4503 TypeHandle canonHnd = TypeHandle(g_pCanonMethodTableClass);
4504 if ((hnd1 != canonHnd) && (hnd2 != canonHnd))
4506 if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
4508 result = TypeCompareState::MustNot;
4514 EE_TO_JIT_TRANSITION();
4520 /*********************************************************************/
4521 static BOOL isMoreSpecificTypeHelper(
4522 CORINFO_CLASS_HANDLE cls1,
4523 CORINFO_CLASS_HANDLE cls2)
4531 TypeHandle hnd1 = TypeHandle(cls1);
4532 TypeHandle hnd2 = TypeHandle(cls2);
4534 // We can't really reason about equivalent types. Just
4535 // assume the new type is not more specific.
4536 if (hnd1.HasTypeEquivalence() || hnd2.HasTypeEquivalence())
4541 // If we have a mixture of shared and unshared types,
4542 // consider the unshared type as more specific.
4543 BOOL isHnd1CanonSubtype = hnd1.IsCanonicalSubtype();
4544 BOOL isHnd2CanonSubtype = hnd2.IsCanonicalSubtype();
4545 if (isHnd1CanonSubtype != isHnd2CanonSubtype)
4547 // Only one of hnd1 and hnd2 is shared.
4548 // hdn2 is more specific if hnd1 is the shared type.
4549 return isHnd1CanonSubtype;
4552 // Otherwise both types are either shared or not shared.
4553 // Look for a common parent type.
4554 TypeHandle merged = TypeHandle::MergeTypeHandlesToCommonParent(hnd1, hnd2);
4556 // If the common parent is hnd1, then hnd2 is more specific.
4557 return merged == hnd1;
4560 // Returns true if cls2 is known to be a more specific type
4561 // than cls1 (a subtype or more restrictive shared type).
4562 bool CEEInfo::isMoreSpecificType(
4563 CORINFO_CLASS_HANDLE cls1,
4564 CORINFO_CLASS_HANDLE cls2)
4572 bool result = false;
4574 JIT_TO_EE_TRANSITION();
4576 result = isMoreSpecificTypeHelper(cls1, cls2);
4578 EE_TO_JIT_TRANSITION();
4582 /*********************************************************************/
4583 // Returns TypeCompareState::Must if cls is known to be an enum.
4584 // For enums with known exact type returns the underlying
4585 // type in underlyingType when the provided pointer is
4587 // Returns TypeCompareState::May when a runtime check is required.
4588 TypeCompareState CEEInfo::isEnum(
4589 CORINFO_CLASS_HANDLE cls,
4590 CORINFO_CLASS_HANDLE* underlyingType)
4598 TypeCompareState result = TypeCompareState::May;
4600 if (underlyingType != nullptr)
4602 *underlyingType = nullptr;
4605 JIT_TO_EE_TRANSITION_LEAF();
4609 _ASSERTE(!th.IsNull());
4611 if (!th.IsGenericVariable())
4613 if (!th.IsTypeDesc() && th.AsMethodTable()->IsEnum())
4615 result = TypeCompareState::Must;
4616 if (underlyingType != nullptr)
4618 CorElementType elemType = th.AsMethodTable()->GetInternalCorElementType();
4619 TypeHandle underlyingHandle(CoreLibBinder::GetElementType(elemType));
4620 *underlyingType = CORINFO_CLASS_HANDLE(underlyingHandle.AsPtr());
4625 result = TypeCompareState::MustNot;
4629 EE_TO_JIT_TRANSITION_LEAF();
4633 /*********************************************************************/
4634 // Given a class handle, returns the Parent type.
4635 // For COMObjectType, it returns Class Handle of System.Object.
4636 // Returns 0 if System.Object is passed in.
4637 CORINFO_CLASS_HANDLE CEEInfo::getParentType(
4638 CORINFO_CLASS_HANDLE cls)
4646 CORINFO_CLASS_HANDLE result = NULL;
4648 JIT_TO_EE_TRANSITION();
4652 _ASSERTE(!th.IsNull());
4653 _ASSERTE(!th.IsGenericVariable());
4655 TypeHandle thParent = th.GetParent();
4657 #ifdef FEATURE_COMINTEROP
4658 // If we encounter __ComObject in the hierarchy, we need to skip it
4659 // since this hierarchy is introduced by the EE, but won't be present
4661 if (!thParent.IsNull() && IsComObjectClass(thParent))
4663 result = (CORINFO_CLASS_HANDLE) g_pObjectClass;
4666 #endif // FEATURE_COMINTEROP
4668 result = CORINFO_CLASS_HANDLE(thParent.AsPtr());
4671 EE_TO_JIT_TRANSITION();
4677 /*********************************************************************/
4678 // Returns the CorInfoType of the "child type". If the child type is
4679 // not a primitive type, *clsRet will be set.
4680 // Given an Array of Type Foo, returns Foo.
4681 // Given BYREF Foo, returns Foo
4682 CorInfoType CEEInfo::getChildType (
4683 CORINFO_CLASS_HANDLE clsHnd,
4684 CORINFO_CLASS_HANDLE *clsRet
4693 CorInfoType ret = CORINFO_TYPE_UNDEF;
4695 TypeHandle retType = TypeHandle();
4697 JIT_TO_EE_TRANSITION();
4699 TypeHandle th(clsHnd);
4701 _ASSERTE(!th.IsNull());
4703 // BYREF, pointer types
4704 if (th.HasTypeParam())
4706 retType = th.GetTypeParam();
4709 if (!retType.IsNull()) {
4710 CorElementType type = retType.GetInternalCorElementType();
4711 ret = CEEInfo::asCorInfoType(type,retType, clsRet);
4713 // <REVISIT_TODO>What if this one is a value array ?</REVISIT_TODO>
4716 EE_TO_JIT_TRANSITION();
4721 /*********************************************************************/
4722 // Check if this is a single dimensional, zero based array type
4723 bool CEEInfo::isSDArray(CORINFO_CLASS_HANDLE cls)
4731 bool result = false;
4733 JIT_TO_EE_TRANSITION();
4737 _ASSERTE(!th.IsNull());
4741 // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4742 _ASSERTE(th != TypeHandle(g_pArrayClass));
4744 result = (th.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
4747 EE_TO_JIT_TRANSITION();
4752 /*********************************************************************/
4753 // Get the number of dimensions in an array
4754 unsigned CEEInfo::getArrayRank(CORINFO_CLASS_HANDLE cls)
4762 unsigned result = 0;
4764 JIT_TO_EE_TRANSITION();
4768 _ASSERTE(!th.IsNull());
4772 // Lots of code used to think that System.Array's methodtable returns TRUE for IsArray(). It doesn't.
4773 _ASSERTE(th != TypeHandle(g_pArrayClass));
4775 result = th.GetRank();
4778 EE_TO_JIT_TRANSITION();
4783 /*********************************************************************/
4784 // Get the index of runtime provided array method
4785 CorInfoArrayIntrinsic CEEInfo::getArrayIntrinsicID(CORINFO_METHOD_HANDLE ftn)
4793 CorInfoArrayIntrinsic result = CorInfoArrayIntrinsic::ILLEGAL;
4795 JIT_TO_EE_TRANSITION();
4797 MethodDesc* pMD = GetMethod(ftn);
4801 DWORD index = ((ArrayMethodDesc*)pMD)->GetArrayFuncIndex();
4804 case 0: // ARRAY_FUNC_GET
4805 result = CorInfoArrayIntrinsic::GET;
4807 case 1: // ARRAY_FUNC_SET
4808 result = CorInfoArrayIntrinsic::SET;
4810 case 2: // ARRAY_FUNC_ADDRESS
4811 result = CorInfoArrayIntrinsic::ADDRESS;
4816 EE_TO_JIT_TRANSITION();
4821 /*********************************************************************/
4822 // Get static field data for an array
4823 // Note that it's OK to return NULL from this method. This will cause
4824 // the JIT to make a runtime call to InitializeArray instead of doing
4825 // the inline optimization (thus preserving the original behavior).
4826 void * CEEInfo::getArrayInitializationData(
4827 CORINFO_FIELD_HANDLE field,
4837 void * result = NULL;
4839 JIT_TO_EE_TRANSITION();
4841 FieldDesc* pField = (FieldDesc*) field;
4845 (pField->LoadSize() < size))
4851 result = pField->GetStaticAddressHandle(NULL);
4854 EE_TO_JIT_TRANSITION();
4859 CorInfoIsAccessAllowedResult CEEInfo::canAccessClass(
4860 CORINFO_RESOLVED_TOKEN * pResolvedToken,
4861 CORINFO_METHOD_HANDLE callerHandle,
4862 CORINFO_HELPER_DESC *pAccessHelper
4871 CorInfoIsAccessAllowedResult isAccessAllowed = CORINFO_ACCESS_ALLOWED;
4873 JIT_TO_EE_TRANSITION();
4875 INDEBUG(memset(pAccessHelper, 0xCC, sizeof(*pAccessHelper)));
4877 BOOL doAccessCheck = TRUE;
4878 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
4879 DynamicResolver * pAccessContext = NULL;
4881 //All access checks must be done on the open instantiation.
4882 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle);
4883 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
4885 TypeHandle pCalleeForSecurity = TypeHandle(pResolvedToken->hClass);
4886 if (pResolvedToken->pTypeSpec != NULL)
4888 SigTypeContext typeContext;
4889 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
4891 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
4892 pCalleeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
4895 while (pCalleeForSecurity.HasTypeParam())
4897 pCalleeForSecurity = pCalleeForSecurity.GetTypeParam();
4900 if (IsDynamicScope(pResolvedToken->tokenScope))
4902 doAccessCheck = ModifyCheckForDynamicMethod(GetDynamicResolver(pResolvedToken->tokenScope),
4903 &callerTypeForSecurity, &accessCheckType,
4907 //Since this is a check against a TypeHandle, there are some things we can stick in a TypeHandle that
4908 //don't require access checks.
4909 if (pCalleeForSecurity.IsGenericVariable())
4911 //I don't need to check for access against !!0.
4912 doAccessCheck = FALSE;
4915 //Now do the visibility checks
4918 AccessCheckOptions accessCheckOptions(accessCheckType,
4920 FALSE /*throw on error*/,
4921 pCalleeForSecurity.GetMethodTable());
4923 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
4924 AccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
4926 BOOL canAccessType = ClassLoader::CanAccessClass(&accessContext,
4927 pCalleeForSecurity.GetMethodTable(),
4928 pCalleeForSecurity.GetAssembly(),
4929 accessCheckOptions);
4931 isAccessAllowed = canAccessType ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
4935 if (isAccessAllowed != CORINFO_ACCESS_ALLOWED)
4937 //These all get the throw helper
4938 pAccessHelper->helperNum = CORINFO_HELP_CLASS_ACCESS_EXCEPTION;
4939 pAccessHelper->numArgs = 2;
4941 pAccessHelper->args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
4942 pAccessHelper->args[1].Set(CORINFO_CLASS_HANDLE(pCalleeForSecurity.AsPtr()));
4945 EE_TO_JIT_TRANSITION();
4946 return isAccessAllowed;
4949 //---------------------------------------------------------------------------------------
4950 // Given a method descriptor ftnHnd, extract signature information into sigInfo
4951 // Obtain (representative) instantiation information from ftnHnd's owner class
4952 //@GENERICSVER: added explicit owner parameter
4953 // Internal version without JIT-EE transition
4954 static void getMethodSigInternal(
4955 CORINFO_METHOD_HANDLE ftnHnd,
4956 CORINFO_SIG_INFO * sigRet,
4957 CORINFO_CLASS_HANDLE owner,
4958 SignatureKind signatureKind)
4960 STANDARD_VM_CONTRACT;
4962 MethodDesc * ftn = GetMethod(ftnHnd);
4964 PCCOR_SIGNATURE pSig = NULL;
4966 ftn->GetSig(&pSig, &cbSig);
4968 SigTypeContext context(ftn, (TypeHandle)owner);
4970 // Type parameters in the signature are instantiated
4971 // according to the class/method/array instantiation of ftnHnd and owner
4975 GetScopeHandle(ftn),
4978 CONV_TO_JITSIG_FLAGS_NONE,
4982 // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation
4983 if (ftn->RequiresInstArg())
4986 // If we are making a virtual call to an instance method on an interface, we need to lie to the JIT.
4987 // The reason being that we already made sure target is always directly callable (through instantiation stubs),
4988 // JIT should not generate shared generics aware call code and insert the secret argument again at the callsite.
4989 // Otherwise we would end up with two secret generic dictionary arguments (since the stub also provides one).
4991 BOOL isCallSiteThatGoesThroughInstantiatingStub =
4992 (signatureKind == SK_VIRTUAL_CALLSITE &&
4994 ftn->GetMethodTable()->IsInterface()) ||
4995 signatureKind == SK_STATIC_VIRTUAL_CODEPOINTER_CALLSITE;
4996 if (!isCallSiteThatGoesThroughInstantiatingStub)
4997 sigRet->callConv = (CorInfoCallConv) (sigRet->callConv | CORINFO_CALLCONV_PARAMTYPE);
5000 // We want the calling convention bit to be consistant with the method attribute bit
5001 _ASSERTE( (IsMdStatic(ftn->GetAttrs()) == 0) == ((sigRet->callConv & CORINFO_CALLCONV_HASTHIS) != 0) );
5004 /***********************************************************************/
5005 // return the address of a pointer to a callable stub that will do the
5006 // virtual or interface call
5007 void CEEInfo::getCallInfo(
5008 CORINFO_RESOLVED_TOKEN * pResolvedToken,
5009 CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
5010 CORINFO_METHOD_HANDLE callerHandle,
5011 CORINFO_CALLINFO_FLAGS flags,
5012 CORINFO_CALL_INFO *pResult /*out */)
5020 JIT_TO_EE_TRANSITION();
5022 _ASSERTE(CheckPointer(pResult));
5024 INDEBUG(memset(pResult, 0xCC, sizeof(*pResult)));
5026 pResult->stubLookup.lookupKind.needsRuntimeLookup = false;
5028 MethodDesc* pMD = (MethodDesc *)pResolvedToken->hMethod;
5029 TypeHandle th(pResolvedToken->hClass);
5032 _ASSERTE((size_t(pMD) & 0x1) == 0);
5034 // Spec says that a callvirt lookup ignores static methods. Since static methods
5035 // can't have the exact same signature as instance methods, a lookup that found
5036 // a static method would have never found an instance method.
5037 if (pMD->IsStatic() && (flags & CORINFO_CALLINFO_CALLVIRT))
5039 EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, W("?")));
5042 TypeHandle exactType = TypeHandle(pResolvedToken->hClass);
5044 TypeHandle constrainedType;
5045 if (pConstrainedResolvedToken != NULL)
5047 constrainedType = TypeHandle(pConstrainedResolvedToken->hClass);
5050 BOOL fIsStaticVirtualMethod = (pConstrainedResolvedToken != NULL && pMD->IsInterface() && pMD->IsStatic());
5052 BOOL fResolvedConstraint = FALSE;
5053 BOOL fForceUseRuntimeLookup = FALSE;
5054 BOOL fAbstractSVM = FALSE;
5056 // The below may need to mutate the constrained token, in which case we
5057 // switch to this local copy to avoid mutating the in argument.
5058 CORINFO_RESOLVED_TOKEN constrainedResolvedTokenCopy;
5060 MethodDesc * pMDAfterConstraintResolution = pMD;
5061 if (constrainedType.IsNull())
5063 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5065 // <NICE> Things go wrong when this code path is used when verifying generic code.
5066 // It would be nice if we didn't go down this sort of code path when verifying but
5067 // not generating code. </NICE>
5068 else if (constrainedType.ContainsGenericVariables() || exactType.ContainsGenericVariables())
5070 // <NICE> It shouldn't really matter what we do here - but the x86 JIT is annoyingly sensitive
5071 // about what we do, since it pretend generic variables are reference types and generates
5072 // an internal JIT tree even when just verifying generic code. </NICE>
5073 if (constrainedType.IsGenericVariable())
5075 pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &T --> T
5077 else if (constrainedType.IsValueType())
5079 pResult->thisTransform = CORINFO_BOX_THIS; // convert 'this' of type &VC<T> --> boxed(VC<T>)
5083 pResult->thisTransform = CORINFO_DEREF_THIS; // convert 'this' of type &C<T> --> C<T>
5088 // We have a "constrained." call. Try a partial resolve of the constraint call. Note that this
5089 // will not necessarily resolve the call exactly, since we might be compiling
5090 // shared generic code - it may just resolve it to a candidate suitable for
5091 // JIT compilation, and require a runtime lookup for the actual code pointer
5093 if (constrainedType.IsEnum())
5095 // Optimize constrained calls to enum's GetHashCode method. TryResolveConstraintMethodApprox would return
5096 // null since the virtual method resolves to System.Enum's implementation and that's a reference type.
5097 // We can't do this for any other method since ToString and Equals have different semantics for enums
5098 // and their underlying type.
5099 if (pMD->GetSlot() == CoreLibBinder::GetMethod(METHOD__OBJECT__GET_HASH_CODE)->GetSlot())
5101 // Pretend this was a "constrained. UnderlyingType" instruction prefix
5102 constrainedType = TypeHandle(CoreLibBinder::GetElementType(constrainedType.GetVerifierCorElementType()));
5104 constrainedResolvedTokenCopy = *pConstrainedResolvedToken;
5105 pConstrainedResolvedToken = &constrainedResolvedTokenCopy;
5107 // Native image signature encoder will use this field. It needs to match that pretended type, a bogus signature
5108 // would be produced otherwise.
5109 pConstrainedResolvedToken->hClass = (CORINFO_CLASS_HANDLE)constrainedType.AsPtr();
5111 // Clear the token and typespec because of they do not match hClass anymore.
5112 pConstrainedResolvedToken->token = mdTokenNil;
5113 pConstrainedResolvedToken->pTypeSpec = NULL;
5117 MethodDesc * directMethod = constrainedType.GetMethodTable()->TryResolveConstraintMethodApprox(
5120 &fForceUseRuntimeLookup);
5122 #ifdef FEATURE_DEFAULT_INTERFACES
5123 && !directMethod->IsInterface() /* Could be a default interface method implementation */
5128 // 1. no constraint resolution at compile time (!directMethod)
5129 // OR 2. no code sharing lookup in call
5130 // OR 3. we have resolved to an instantiating stub
5132 pMDAfterConstraintResolution = directMethod;
5133 _ASSERTE(!pMDAfterConstraintResolution->IsInterface());
5134 fResolvedConstraint = TRUE;
5135 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5137 exactType = constrainedType;
5139 #ifdef FEATURE_DEFAULT_INTERFACES
5140 else if (directMethod && pMD->IsStatic())
5142 if (directMethod->IsAbstract())
5144 // This is the result when we call a SVM which is abstract, or re-abstracted
5145 directMethod = NULL;
5146 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5147 fAbstractSVM = true;
5151 // Default interface implementation of static virtual method
5152 pMDAfterConstraintResolution = directMethod;
5153 fResolvedConstraint = TRUE;
5154 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5155 exactType = directMethod->GetMethodTable();
5159 else if (constrainedType.IsValueType())
5161 pResult->thisTransform = CORINFO_BOX_THIS;
5163 else if (!fIsStaticVirtualMethod)
5165 pResult->thisTransform = CORINFO_DEREF_THIS;
5169 pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
5174 // Initialize callee context used for inlining and instantiation arguments
5177 MethodDesc * pTargetMD = pMDAfterConstraintResolution;
5178 DWORD dwTargetMethodAttrs = pTargetMD->GetAttrs();
5180 pResult->exactContextNeedsRuntimeLookup = (fIsStaticVirtualMethod && !fResolvedConstraint && !constrainedType.IsNull() && constrainedType.IsCanonicalSubtype());
5182 if (pTargetMD->HasMethodInstantiation())
5184 pResult->contextHandle = MAKE_METHODCONTEXT(pTargetMD);
5185 if (pTargetMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(pTargetMD->GetMethodInstantiation()))
5187 pResult->exactContextNeedsRuntimeLookup = TRUE;
5192 if (!exactType.IsTypeDesc() && !pTargetMD->IsArray())
5194 // Because of .NET's notion of base calls, exactType may point to a sub-class
5195 // of the actual class that defines pTargetMD. If the JIT decides to inline, it is
5196 // important that they 'match', so we fix exactType here.
5197 exactType = pTargetMD->GetExactDeclaringType(exactType.AsMethodTable());
5198 _ASSERTE(!exactType.IsNull());
5201 pResult->contextHandle = MAKE_CLASSCONTEXT(exactType.AsPtr());
5202 if (exactType.IsSharedByGenericInstantiations())
5204 pResult->exactContextNeedsRuntimeLookup = TRUE;
5207 // Use main method as the context as long as the methods are called on the same type
5208 if (pResult->exactContextNeedsRuntimeLookup &&
5209 pResolvedToken->tokenContext == METHOD_BEING_COMPILED_CONTEXT() &&
5210 constrainedType.IsNull() &&
5211 exactType == m_pMethodBeingCompiled->GetMethodTable() &&
5212 ((pResolvedToken->cbTypeSpec == 0) || IsTypeSpecForTypicalInstantiation(SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec))))
5214 // The typespec signature should be only missing for dynamic methods
5215 _ASSERTE((pResolvedToken->cbTypeSpec != 0) || m_pMethodBeingCompiled->IsDynamicMethod());
5217 pResult->contextHandle = METHOD_BEING_COMPILED_CONTEXT();
5222 // Determine whether to perform direct call
5225 bool directCall = false;
5226 bool resolvedCallVirt = false;
5228 if ((flags & CORINFO_CALLINFO_LDFTN) && (!fIsStaticVirtualMethod || fResolvedConstraint))
5230 // Since the ldvirtftn instruction resolves types
5231 // at run-time we do this earlier than ldftn. The
5232 // ldftn scenario is handled later when the fixed
5233 // address is requested by in the JIT.
5234 // See getFunctionFixedEntryPoint().
5236 // Using ldftn or ldvirtftn on a Generic method
5237 // requires early type loading since instantiation
5238 // occurs at run-time as opposed to JIT time. The
5239 // GC special cases Generic types and relaxes the
5240 // loaded type constraint to permit Generic types
5241 // that are loaded with Canon as opposed to being
5242 // instantiated with an actual type.
5243 if ((flags & CORINFO_CALLINFO_CALLVIRT)
5244 || pTargetMD->HasMethodInstantiation())
5246 pTargetMD->PrepareForUseAsAFunctionPointer();
5252 // Static methods are always direct calls
5253 if (pTargetMD->IsStatic() && (!fIsStaticVirtualMethod || fResolvedConstraint))
5258 if ((!fIsStaticVirtualMethod && !(flags & CORINFO_CALLINFO_CALLVIRT)) || fResolvedConstraint)
5265 if (pTargetMD->GetMethodTable()->IsInterface())
5267 // Handle interface methods specially because the Sealed bit has no meaning on interfaces.
5268 devirt = !IsMdVirtual(dwTargetMethodAttrs);
5272 devirt = !IsMdVirtual(dwTargetMethodAttrs) || IsMdFinal(dwTargetMethodAttrs) || pTargetMD->GetMethodTable()->IsSealed();
5277 resolvedCallVirt = true;
5284 // Direct calls to abstract methods are not allowed
5285 if (IsMdAbstract(dwTargetMethodAttrs) &&
5286 // Compensate for always treating delegates as direct calls above
5287 !(((flags & CORINFO_CALLINFO_LDFTN) && (flags & CORINFO_CALLINFO_CALLVIRT) && !resolvedCallVirt))
5288 && !(IsMdStatic(dwTargetMethodAttrs) && fForceUseRuntimeLookup))
5290 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL);
5293 bool allowInstParam = (flags & CORINFO_CALLINFO_ALLOWINSTPARAM);
5295 // If the target method is resolved via constrained static virtual dispatch
5296 // And it requires an instParam, we do not have the generic dictionary infrastructure
5297 // to load the correct generic context arg via EmbedGenericHandle.
5298 // Instead, force the call to go down the CORINFO_CALL_CODE_POINTER code path
5299 // which should have somewhat inferior performance. This should only actually happen in the case
5300 // of shared generic code calling a shared generic implementation method, which should be rare.
5302 // An alternative design would be to add a new generic dictionary entry kind to hold the MethodDesc
5303 // of the constrained target instead, and use that in some circumstances; however, implementation of
5304 // that design requires refactoring variuos parts of the JIT interface as well as
5305 // TryResolveConstraintMethodApprox. In particular we would need to be abled to embed a constrained lookup
5306 // via EmbedGenericHandle, as well as decide in TryResolveConstraintMethodApprox if the call can be made
5307 // via a single use of CORINFO_CALL_CODE_POINTER, or would be better done with a CORINFO_CALL + embedded
5308 // constrained generic handle, or if there is a case where we would want to use both a CORINFO_CALL and
5309 // embedded constrained generic handle. Given the current expected high performance use case of this feature
5310 // which is generic numerics which will always resolve to exact valuetypes, it is not expected that
5311 // the complexity involved would be worth the risk. Other scenarios are not expected to be as performance
5313 if (IsMdStatic(dwTargetMethodAttrs) && constrainedType != NULL && pResult->exactContextNeedsRuntimeLookup)
5315 allowInstParam = FALSE;
5318 // Create instantiating stub if necessary
5319 if (!allowInstParam && pTargetMD->RequiresInstArg())
5321 pTargetMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pTargetMD,
5322 exactType.AsMethodTable(),
5323 FALSE /* forceBoxedEntryPoint */,
5324 pTargetMD->GetMethodInstantiation(),
5325 FALSE /* allowInstParam */);
5328 // We don't allow a JIT to call the code directly if a runtime lookup is
5329 // needed. This is the case if
5330 // 1. the scan of the call token indicated that it involves code sharing
5331 // AND 2. the method is an instantiating stub
5333 // In these cases the correct instantiating stub is only found via a runtime lookup.
5335 // Note that most JITs don't call instantiating stubs directly if they can help it -
5336 // they call the underlying shared code and provide the type context parameter
5337 // explicitly. However
5338 // (a) some JITs may call instantiating stubs (it makes the JIT simpler) and
5339 // (b) if the method is a remote stub then the EE will force the
5340 // call through an instantiating stub and
5341 // (c) constraint calls that require runtime context lookup are never resolved
5342 // to underlying shared generic code
5344 bool unresolvedLdVirtFtn = (flags & CORINFO_CALLINFO_LDFTN) && (flags & CORINFO_CALLINFO_CALLVIRT) && !resolvedCallVirt;
5346 if (((pResult->exactContextNeedsRuntimeLookup && pTargetMD->IsInstantiatingStub() && (!allowInstParam || fResolvedConstraint)) || fForceUseRuntimeLookup))
5348 _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5350 pResult->kind = CORINFO_CALL_CODE_POINTER;
5352 DictionaryEntryKind entryKind;
5353 if (constrainedType.IsNull() || ((flags & CORINFO_CALLINFO_CALLVIRT) && !constrainedType.IsValueType()))
5355 // For reference types, the constrained type does not affect method resolution on a callvirt, and if there is no
5356 // constraint, it doesn't effect it either
5357 entryKind = MethodEntrySlot;
5361 // constrained. callvirt case where the constraint type is a valuetype
5363 // constrained. call or constrained. ldftn case
5364 entryKind = ConstrainedMethodEntrySlot;
5366 ComputeRuntimeLookupForSharedGenericToken(entryKind,
5368 pConstrainedResolvedToken,
5370 &pResult->codePointerLookup);
5374 if (allowInstParam && pTargetMD->IsInstantiatingStub())
5376 pTargetMD = pTargetMD->GetWrappedMethodDesc();
5379 pResult->kind = CORINFO_CALL;
5381 pResult->nullInstanceCheck = resolvedCallVirt;
5383 // All virtual calls which take method instantiations must
5384 // currently be implemented by an indirect call via a runtime-lookup
5386 else if (pTargetMD->HasMethodInstantiation() && !fIsStaticVirtualMethod)
5388 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN; // stub dispatch can't handle generic method calls yet
5389 pResult->nullInstanceCheck = TRUE;
5391 // Non-interface dispatches go through the vtable.
5392 else if (!pTargetMD->IsInterface() && !fIsStaticVirtualMethod)
5394 pResult->kind = CORINFO_VIRTUALCALL_VTABLE;
5395 pResult->nullInstanceCheck = TRUE;
5399 // No need to null check - the dispatch code will deal with null this.
5400 pResult->nullInstanceCheck = FALSE;
5401 #ifdef STUB_DISPATCH_PORTABLE
5402 pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
5403 #else // STUB_DISPATCH_PORTABLE
5404 pResult->kind = CORINFO_VIRTUALCALL_STUB;
5405 if (fIsStaticVirtualMethod)
5407 pResult->kind = CORINFO_CALL_CODE_POINTER;
5410 // We can't make stub calls when we need exact information
5411 // for interface calls from shared code.
5413 if (pResult->exactContextNeedsRuntimeLookup)
5415 _ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());
5417 ComputeRuntimeLookupForSharedGenericToken(fIsStaticVirtualMethod ? ConstrainedMethodEntrySlot : DispatchStubAddrSlot,
5419 pConstrainedResolvedToken,
5421 &pResult->stubLookup);
5425 BYTE * indcell = NULL;
5427 // We shouldn't be using GetLoaderAllocator here because for LCG, we need to get the
5428 // VirtualCallStubManager from where the stub will be used.
5429 // For normal methods there is no difference.
5430 LoaderAllocator *pLoaderAllocator = m_pMethodBeingCompiled->GetLoaderAllocator();
5431 VirtualCallStubManager *pMgr = pLoaderAllocator->GetVirtualCallStubManager();
5433 PCODE addr = pMgr->GetCallStub(exactType, pTargetMD);
5435 // Now we want to indirect through a cell so that updates can take place atomically.
5436 if (m_pMethodBeingCompiled->IsLCGMethod())
5438 // LCG methods should use recycled indcells to prevent leaks.
5439 indcell = pMgr->GenerateStubIndirection(addr, TRUE);
5441 // Add it to the per DM list so that we can recycle them when the resolver is finalized
5442 LCGMethodResolver *pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetLCGMethodResolver();
5443 pResolver->AddToUsedIndCellList(indcell);
5447 // Normal methods should avoid recycled cells to preserve the locality of all indcells
5448 // used by one method.
5449 indcell = pMgr->GenerateStubIndirection(addr, FALSE);
5452 // We use an indirect call
5453 pResult->stubLookup.constLookup.accessType = IAT_PVALUE;
5454 pResult->stubLookup.constLookup.addr = indcell;
5456 #endif // STUB_DISPATCH_PORTABLE
5459 pResult->hMethod = CORINFO_METHOD_HANDLE(pTargetMD);
5461 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5462 MethodDesc* callerMethod = (MethodDesc*)callerHandle;
5463 if ((flags & CORINFO_CALLINFO_SECURITYCHECKS)
5464 && RequiresAccessCheck(pResolvedToken->tokenScope))
5466 //Our type system doesn't always represent the target exactly with the MethodDesc. In all cases,
5467 //carry around the parent MethodTable for both Caller and Callee.
5468 TypeHandle calleeTypeForSecurity = TypeHandle(pResolvedToken->hClass);
5469 MethodDesc * pCalleeForSecurity = pMD;
5471 MethodDesc * pCallerForSecurity = GetMethodForSecurity(callerHandle); //Should this be the open MD?
5473 if (pCallerForSecurity->HasClassOrMethodInstantiation())
5475 _ASSERTE(!IsDynamicScope(pResolvedToken->tokenScope));
5477 SigTypeContext typeContext;
5478 SigTypeContext::InitTypeContext(pCallerForSecurity, &typeContext);
5479 _ASSERTE(!typeContext.IsEmpty());
5481 //If the caller is generic, load the open type and resolve the token again. Use that for the access
5482 //checks. If we don't do this then we can't tell the difference between:
5484 //BadGeneric<T> containing a methodspec for InaccessibleType::member (illegal)
5486 //BadGeneric<T> containing a methodspec for !!0::member instantiated over InaccessibleType (legal)
5488 if (pResolvedToken->pTypeSpec != NULL)
5490 SigPointer sigptr(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
5491 calleeTypeForSecurity = sigptr.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5493 // typeHnd can be a variable type
5494 if (calleeTypeForSecurity.GetMethodTable() == NULL)
5496 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
5500 if (pCalleeForSecurity->IsArray())
5502 // FindOrCreateAssociatedMethodDesc won't remap array method desc because of array base type
5503 // is not part of instantiation. We have to special case it.
5504 pCalleeForSecurity = calleeTypeForSecurity.GetMethodTable()->GetParallelMethodDesc(pCalleeForSecurity);
5506 else if (pResolvedToken->pMethodSpec != NULL)
5508 uint32_t nGenericMethodArgs = 0;
5509 CQuickBytes qbGenericMethodArgs;
5510 TypeHandle *genericMethodArgs = NULL;
5512 SigPointer sp(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
5515 IfFailThrow(sp.GetByte(&etype));
5517 // Load the generic method instantiation
5518 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, (Module *)pResolvedToken->tokenScope);
5520 IfFailThrow(sp.GetData(&nGenericMethodArgs));
5522 DWORD cbAllocSize = 0;
5523 if (!ClrSafeInt<DWORD>::multiply(nGenericMethodArgs, sizeof(TypeHandle), cbAllocSize))
5525 COMPlusThrowHR(COR_E_OVERFLOW);
5528 genericMethodArgs = reinterpret_cast<TypeHandle *>(qbGenericMethodArgs.AllocThrows(cbAllocSize));
5530 for (uint32_t i = 0; i < nGenericMethodArgs; i++)
5532 genericMethodArgs[i] = sp.GetTypeHandleThrowing((Module *)pResolvedToken->tokenScope, &typeContext);
5533 _ASSERTE (!genericMethodArgs[i].IsNull());
5534 IfFailThrow(sp.SkipExactlyOne());
5537 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(genericMethodArgs, nGenericMethodArgs), FALSE);
5539 else if (pResolvedToken->pTypeSpec != NULL)
5541 pCalleeForSecurity = MethodDesc::FindOrCreateAssociatedMethodDesc(pMD, calleeTypeForSecurity.GetMethodTable(), FALSE, Instantiation(), TRUE);
5545 TypeHandle callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5547 //Passed various link-time checks. Now do access checks.
5549 BOOL doAccessCheck = TRUE;
5550 BOOL canAccessMethod = TRUE;
5551 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
5552 DynamicResolver * pAccessContext = NULL;
5554 callerTypeForSecurity = TypeHandle(pCallerForSecurity->GetMethodTable());
5555 if (pCallerForSecurity->IsDynamicMethod())
5557 doAccessCheck = ModifyCheckForDynamicMethod(pCallerForSecurity->AsDynamicMethodDesc()->GetResolver(),
5558 &callerTypeForSecurity,
5559 &accessCheckType, &pAccessContext);
5562 pResult->accessAllowed = CORINFO_ACCESS_ALLOWED;
5566 AccessCheckOptions accessCheckOptions(accessCheckType,
5569 pCalleeForSecurity);
5571 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5572 AccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5574 canAccessMethod = ClassLoader::CanAccess(&accessContext,
5575 calleeTypeForSecurity.GetMethodTable(),
5576 calleeTypeForSecurity.GetAssembly(),
5577 pCalleeForSecurity->GetAttrs(),
5583 // If we were allowed access to the exact method, but it is on a type that has a type parameter
5584 // (for instance an array), we need to ensure that we also have access to the type parameter.
5585 if (canAccessMethod && calleeTypeForSecurity.HasTypeParam())
5587 TypeHandle typeParam = calleeTypeForSecurity.GetTypeParam();
5588 while (typeParam.HasTypeParam())
5590 typeParam = typeParam.GetTypeParam();
5593 _ASSERTE(pCallerForSecurity != NULL && callerTypeForSecurity != NULL);
5594 AccessCheckContext accessContext(pCallerForSecurity, callerTypeForSecurity.GetMethodTable());
5596 MethodTable* pTypeParamMT = typeParam.GetMethodTable();
5598 // No access check is need for Var, MVar, or FnPtr.
5599 if (pTypeParamMT != NULL)
5600 canAccessMethod = ClassLoader::CanAccessClass(&accessContext,
5602 typeParam.GetAssembly(),
5603 accessCheckOptions);
5606 pResult->accessAllowed = canAccessMethod ? CORINFO_ACCESS_ALLOWED : CORINFO_ACCESS_ILLEGAL;
5607 if (!canAccessMethod)
5609 //Check failed, fill in the throw exception helper.
5610 pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_METHOD_ACCESS_EXCEPTION;
5611 pResult->callsiteCalloutHelper.numArgs = 2;
5613 pResult->callsiteCalloutHelper.args[0].Set(CORINFO_METHOD_HANDLE(pCallerForSecurity));
5614 pResult->callsiteCalloutHelper.args[1].Set(CORINFO_METHOD_HANDLE(pCalleeForSecurity));
5619 //We're pretty much done at this point. Let's grab the rest of the information that the jit is going to
5621 pResult->classFlags = getClassAttribsInternal(pResolvedToken->hClass);
5623 pResult->methodFlags = getMethodAttribsInternal(pResult->hMethod);
5625 SignatureKind signatureKind;
5626 if (flags & CORINFO_CALLINFO_CALLVIRT && !(pResult->kind == CORINFO_CALL))
5628 signatureKind = SK_VIRTUAL_CALLSITE;
5630 else if ((pResult->kind == CORINFO_CALL_CODE_POINTER) && IsMdVirtual(dwTargetMethodAttrs) && IsMdStatic(dwTargetMethodAttrs))
5632 signatureKind = SK_STATIC_VIRTUAL_CODEPOINTER_CALLSITE;
5636 signatureKind = SK_CALLSITE;
5638 getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL, signatureKind);
5639 if (fIsStaticVirtualMethod && !fResolvedConstraint)
5641 if (pResult->exactContextNeedsRuntimeLookup)
5643 // Runtime lookup for static virtual methods always returns exact call addresses not requiring the instantiation argument
5644 pResult->sig.callConv = (CorInfoCallConv)(pResult->sig.callConv & ~CORINFO_CALLCONV_PARAMTYPE);
5648 // Unresolved static virtual method in the absence of shared generics means
5649 // that the runtime needs to throw when reaching the call. SVM resolution within
5650 // shared generics is covered by the ConstrainedMethodEntrySlot dictionary entry.
5651 pResult->kind = CORINFO_CALL;
5652 pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL;
5655 pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_THROW_ENTRYPOINT_NOT_FOUND_EXCEPTION;
5659 pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_THROW_AMBIGUOUS_RESOLUTION_EXCEPTION;
5661 pResult->callsiteCalloutHelper.numArgs = 3;
5662 pResult->callsiteCalloutHelper.args[0].methodHandle = (CORINFO_METHOD_HANDLE)pMD;
5663 pResult->callsiteCalloutHelper.args[0].argType = CORINFO_HELPER_ARG_TYPE_Method;
5664 pResult->callsiteCalloutHelper.args[1].classHandle = (CORINFO_CLASS_HANDLE)th.AsMethodTable();
5665 pResult->callsiteCalloutHelper.args[1].argType = CORINFO_HELPER_ARG_TYPE_Class;
5666 pResult->callsiteCalloutHelper.args[2].classHandle = (CORINFO_CLASS_HANDLE)constrainedType.AsMethodTable();
5667 pResult->callsiteCalloutHelper.args[2].argType = CORINFO_HELPER_ARG_TYPE_Class;
5671 pResult->wrapperDelegateInvoke = FALSE;
5673 if (m_pMethodBeingCompiled->IsDynamicMethod())
5675 auto pMD = m_pMethodBeingCompiled->AsDynamicMethodDesc();
5676 if (pMD->IsILStub() && pMD->IsWrapperDelegateStub())
5678 pResult->wrapperDelegateInvoke = TRUE;
5682 EE_TO_JIT_TRANSITION();
5686 /***********************************************************************/
5687 unsigned CEEInfo::getClassDomainID (CORINFO_CLASS_HANDLE clsHnd,
5688 void **ppIndirection)
5696 unsigned result = 0;
5698 if (ppIndirection != NULL)
5699 *ppIndirection = NULL;
5701 JIT_TO_EE_TRANSITION();
5703 TypeHandle VMClsHnd(clsHnd);
5705 if (VMClsHnd.AsMethodTable()->IsDynamicStatics())
5707 result = (unsigned)VMClsHnd.AsMethodTable()->GetModuleDynamicEntryID();
5711 result = (unsigned)VMClsHnd.AsMethodTable()->GetClassIndex();
5714 EE_TO_JIT_TRANSITION();
5719 //---------------------------------------------------------------------------------------
5721 // Used by the JIT to determine whether the profiler or IBC is tracking object
5725 // bool indicating whether the profiler or IBC is tracking object allocations
5728 // Normally, a profiler would just directly call the inline helper to determine
5729 // whether the profiler set the relevant event flag (e.g.,
5730 // CORProfilerTrackAllocationsEnabled). However, this wrapper also asks whether we're
5731 // running for IBC instrumentation or enabling the object allocated ETW event. If so,
5732 // we treat that the same as if the profiler requested allocation information, so that
5733 // the JIT will still use the profiling-friendly object allocation jit helper, so the
5734 // allocations can be tracked.
5737 bool __stdcall TrackAllocationsEnabled()
5749 #ifdef PROFILING_SUPPORTED
5750 || CORProfilerTrackAllocationsEnabled()
5751 #endif // PROFILING_SUPPORTED
5752 #ifdef FEATURE_EVENT_TRACE
5753 || ETW::TypeSystemLog::IsHeapAllocEventEnabled()
5754 #endif // FEATURE_EVENT_TRACE
5758 /***********************************************************************/
5759 CorInfoHelpFunc CEEInfo::getNewHelper(CORINFO_CLASS_HANDLE classHandle, bool* pHasSideEffects)
5767 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5769 JIT_TO_EE_TRANSITION();
5771 TypeHandle VMClsHnd(classHandle);
5773 if(VMClsHnd.IsTypeDesc())
5775 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateFunctionPointer"));
5778 if(VMClsHnd.IsAbstract())
5780 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_CantInstantiateAbstractClass"));
5783 MethodTable* pMT = VMClsHnd.AsMethodTable();
5784 result = getNewHelperStatic(pMT, pHasSideEffects);
5786 _ASSERTE(result != CORINFO_HELP_UNDEF);
5788 EE_TO_JIT_TRANSITION();
5793 /***********************************************************************/
5794 CorInfoHelpFunc CEEInfo::getNewHelperStatic(MethodTable * pMT, bool * pHasSideEffects)
5796 STANDARD_VM_CONTRACT;
5799 // Slow helper is the default
5800 CorInfoHelpFunc helper = CORINFO_HELP_NEWFAST;
5801 BOOL hasFinalizer = pMT->HasFinalizer();
5802 BOOL isComObjectType = pMT->IsComObjectType();
5804 if (isComObjectType)
5806 *pHasSideEffects = true;
5810 *pHasSideEffects = !!hasFinalizer;
5813 if (isComObjectType)
5816 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5819 if ((pMT->GetBaseSize() >= LARGE_OBJECT_SIZE) ||
5823 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5826 // don't call the super-optimized one since that does not check
5828 if (GCStress<cfg_alloc>::IsEnabled())
5831 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5836 // Super fast version doesn't do logging
5837 if (LoggingOn(LF_GCALLOC, LL_INFO10))
5840 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5845 // Don't use the SFAST allocator when tracking object allocations,
5846 // so we don't have to instrument it.
5847 if (TrackAllocationsEnabled())
5850 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5853 #ifdef FEATURE_64BIT_ALIGNMENT
5854 // @ARMTODO: Force all 8-byte alignment requiring allocations down one slow path. As performance
5855 // measurements dictate we can spread these out to faster, more specialized helpers later.
5856 if (pMT->RequiresAlign8())
5859 _ASSERTE(helper == CORINFO_HELP_NEWFAST);
5864 // Use the fast helper when all conditions are met
5865 helper = CORINFO_HELP_NEWSFAST;
5868 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
5869 // If we are use the fast allocator we also may need the
5870 // specialized varion for align8
5871 if (pMT->GetClass()->IsAlign8Candidate() &&
5872 (helper == CORINFO_HELP_NEWSFAST))
5874 helper = CORINFO_HELP_NEWSFAST_ALIGN8;
5876 #endif // FEATURE_DOUBLE_ALIGNMENT_HINT
5881 /***********************************************************************/
5882 // <REVIEW> this only works for shared generic code because all the
5883 // helpers are actually the same. If they were different then things might
5884 // break because the same helper would end up getting used for different but
5885 // representation-compatible arrays (e.g. one with a default constructor
5886 // and one without) </REVIEW>
5887 CorInfoHelpFunc CEEInfo::getNewArrHelper (CORINFO_CLASS_HANDLE arrayClsHnd)
5895 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5897 JIT_TO_EE_TRANSITION();
5899 TypeHandle arrayType(arrayClsHnd);
5901 result = getNewArrHelperStatic(arrayType);
5903 _ASSERTE(result != CORINFO_HELP_UNDEF);
5905 EE_TO_JIT_TRANSITION();
5910 /***********************************************************************/
5911 CorInfoHelpFunc CEEInfo::getNewArrHelperStatic(TypeHandle clsHnd)
5913 STANDARD_VM_CONTRACT;
5915 _ASSERTE(clsHnd.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
5917 if (GCStress<cfg_alloc>::IsEnabled())
5919 return CORINFO_HELP_NEWARR_1_DIRECT;
5922 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5924 TypeHandle thElemType = clsHnd.GetArrayElementTypeHandle();
5925 CorElementType elemType = thElemType.GetInternalCorElementType();
5927 // This is if we're asked for newarr !0 when verifying generic code
5928 // Of course ideally you wouldn't even be generating code when
5929 // simply doing verification (we run the JIT importer in import-only
5930 // mode), but importing does more than one would like so we try to be
5931 // tolerant when asked for non-sensical helpers.
5932 if (CorTypeInfo::IsGenericVariable(elemType))
5934 result = CORINFO_HELP_NEWARR_1_OBJ;
5936 else if (CorTypeInfo::IsObjRef(elemType))
5938 // It is an array of object refs
5939 result = CORINFO_HELP_NEWARR_1_OBJ;
5943 // These cases always must use the slow helper
5945 #ifdef FEATURE_64BIT_ALIGNMENT
5946 thElemType.RequiresAlign8() ||
5948 (elemType == ELEMENT_TYPE_VOID) ||
5949 LoggingOn(LF_GCALLOC, LL_INFO10) ||
5950 TrackAllocationsEnabled())
5952 // Use the slow helper
5953 result = CORINFO_HELP_NEWARR_1_DIRECT;
5955 #ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
5956 else if (elemType == ELEMENT_TYPE_R8)
5958 // Use the Align8 fast helper
5959 result = CORINFO_HELP_NEWARR_1_ALIGN8;
5964 // Yea, we can do it the fast way!
5965 result = CORINFO_HELP_NEWARR_1_VC;
5972 /***********************************************************************/
5973 CorInfoHelpFunc CEEInfo::getCastingHelper(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fThrowing)
5981 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
5983 JIT_TO_EE_TRANSITION();
5985 bool fClassMustBeRestored;
5986 result = getCastingHelperStatic(TypeHandle(pResolvedToken->hClass), fThrowing, &fClassMustBeRestored);
5987 if (fClassMustBeRestored)
5988 classMustBeLoadedBeforeCodeIsRun(pResolvedToken->hClass);
5990 EE_TO_JIT_TRANSITION();
5995 /***********************************************************************/
5996 CorInfoHelpFunc CEEInfo::getCastingHelperStatic(TypeHandle clsHnd, bool fThrowing, bool * pfClassMustBeRestored)
5998 STANDARD_VM_CONTRACT;
6000 // Slow helper is the default
6001 int helper = CORINFO_HELP_ISINSTANCEOFANY;
6003 *pfClassMustBeRestored = false;
6005 if (clsHnd == TypeHandle(g_pCanonMethodTableClass))
6007 // In shared code just use the catch-all helper for type variables, as the same
6008 // code may be used for interface/array/class instantiations
6010 // We may be able to take advantage of constraints to select a specialized helper.
6011 // This optimizations does not seem to be warranted at the moment.
6012 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6015 if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasVariance())
6017 // Casting to variant type requires the type to be fully loaded
6018 *pfClassMustBeRestored = true;
6020 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6023 if (!clsHnd.IsTypeDesc() && clsHnd.AsMethodTable()->HasTypeEquivalence())
6025 // If the type can be equivalent with something, use the slow helper
6026 // Note: if the type of the instance is the one marked as equivalent, it will be
6027 // caught by the fast helpers in the same way as they catch transparent proxies.
6028 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6031 if (clsHnd.IsInterface())
6033 // If it is a non-variant interface, use the fast interface helper
6034 helper = CORINFO_HELP_ISINSTANCEOFINTERFACE;
6037 if (clsHnd.IsArray())
6039 if (clsHnd.GetInternalCorElementType() != ELEMENT_TYPE_SZARRAY)
6041 // Casting to multidimensional array type requires restored pointer to EEClass to fetch rank
6042 *pfClassMustBeRestored = true;
6045 // If it is an array, use the fast array helper
6046 helper = CORINFO_HELP_ISINSTANCEOFARRAY;
6049 if (!clsHnd.IsTypeDesc() && !Nullable::IsNullableType(clsHnd))
6051 // If it is a non-variant class, use the fast class helper
6052 helper = CORINFO_HELP_ISINSTANCEOFCLASS;
6056 // Otherwise, use the slow helper
6057 _ASSERTE(helper == CORINFO_HELP_ISINSTANCEOFANY);
6062 const int delta = CORINFO_HELP_CHKCASTANY - CORINFO_HELP_ISINSTANCEOFANY;
6064 static_assert_no_msg(CORINFO_HELP_CHKCASTINTERFACE
6065 == CORINFO_HELP_ISINSTANCEOFINTERFACE + delta);
6066 static_assert_no_msg(CORINFO_HELP_CHKCASTARRAY
6067 == CORINFO_HELP_ISINSTANCEOFARRAY + delta);
6068 static_assert_no_msg(CORINFO_HELP_CHKCASTCLASS
6069 == CORINFO_HELP_ISINSTANCEOFCLASS + delta);
6074 return (CorInfoHelpFunc)helper;
6077 /***********************************************************************/
6078 CorInfoHelpFunc CEEInfo::getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd)
6086 CorInfoHelpFunc result = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE;
6088 JIT_TO_EE_TRANSITION_LEAF();
6090 TypeHandle cls(clsHnd);
6091 MethodTable* pMT = cls.AsMethodTable();
6093 if (pMT->IsDynamicStatics())
6095 _ASSERTE(!cls.ContainsGenericVariables());
6096 _ASSERTE(pMT->GetModuleDynamicEntryID() != (unsigned) -1);
6098 result = CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
6101 EE_TO_JIT_TRANSITION_LEAF();
6106 /***********************************************************************/
6107 CorInfoHelpFunc CEEInfo::getUnBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6109 LIMITED_METHOD_CONTRACT;
6111 classMustBeLoadedBeforeCodeIsRun(clsHnd);
6113 TypeHandle VMClsHnd(clsHnd);
6114 if (Nullable::IsNullableType(VMClsHnd))
6115 return CORINFO_HELP_UNBOX_NULLABLE;
6117 return CORINFO_HELP_UNBOX;
6120 /***********************************************************************/
6121 CORINFO_OBJECT_HANDLE CEEInfo::getRuntimeTypePointer(CORINFO_CLASS_HANDLE clsHnd)
6129 CORINFO_OBJECT_HANDLE pointer = NULL;
6131 JIT_TO_EE_TRANSITION();
6133 TypeHandle typeHnd(clsHnd);
6134 if (!typeHnd.IsCanonicalSubtype() && typeHnd.IsManagedClassObjectPinned())
6137 // ManagedClassObject is frozen here
6138 pointer = (CORINFO_OBJECT_HANDLE)OBJECTREFToObject(typeHnd.GetManagedClassObject());
6139 _ASSERT(GCHeapUtilities::GetGCHeap()->IsInFrozenSegment((Object*)pointer));
6142 EE_TO_JIT_TRANSITION();
6148 /***********************************************************************/
6149 bool CEEInfo::isObjectImmutable(CORINFO_OBJECT_HANDLE objHandle)
6157 _ASSERT(objHandle != NULL);
6159 bool isImmutable = false;
6161 JIT_TO_EE_TRANSITION();
6164 OBJECTREF obj = getObjectFromJitHandle(objHandle);
6165 MethodTable* type = obj->GetMethodTable();
6167 if (type->IsString() || type == g_pRuntimeTypeClass)
6169 // These types are always immutable
6172 else if (type->IsArray() && ((ArrayBase*)OBJECTREFToObject(obj))->GetComponentSize() == 0)
6174 // Empty arrays are always immutable
6177 else if (type->IsDelegate() || type->GetNumInstanceFields() == 0)
6179 // Delegates and types without fields are always immutable
6183 EE_TO_JIT_TRANSITION();
6188 /***********************************************************************/
6189 bool CEEInfo::getStringChar(CORINFO_OBJECT_HANDLE obj, int index, uint16_t* value)
6197 _ASSERT(obj != NULL);
6199 bool result = false;
6201 JIT_TO_EE_TRANSITION();
6204 OBJECTREF objRef = getObjectFromJitHandle(obj);
6205 MethodTable* type = objRef->GetMethodTable();
6206 if (type->IsString())
6208 STRINGREF strRef = (STRINGREF)objRef;
6209 if (strRef->GetStringLength() > (DWORD)index)
6211 *value = strRef->GetBuffer()[index];
6216 EE_TO_JIT_TRANSITION();
6221 /***********************************************************************/
6222 CORINFO_CLASS_HANDLE CEEInfo::getObjectType(CORINFO_OBJECT_HANDLE objHandle)
6230 _ASSERT(objHandle != NULL);
6232 CORINFO_CLASS_HANDLE handle = NULL;
6234 JIT_TO_EE_TRANSITION();
6237 OBJECTREF obj = getObjectFromJitHandle(objHandle);
6238 handle = (CORINFO_CLASS_HANDLE)obj->GetMethodTable();
6240 EE_TO_JIT_TRANSITION();
6245 /***********************************************************************/
6246 bool CEEInfo::getReadyToRunHelper(
6247 CORINFO_RESOLVED_TOKEN * pResolvedToken,
6248 CORINFO_LOOKUP_KIND * pGenericLookupKind,
6250 CORINFO_CONST_LOOKUP * pLookup
6253 LIMITED_METHOD_CONTRACT;
6254 UNREACHABLE(); // only called during NGen
6257 /***********************************************************************/
6258 void CEEInfo::getReadyToRunDelegateCtorHelper(
6259 CORINFO_RESOLVED_TOKEN * pTargetMethod,
6260 mdToken targetConstraint,
6261 CORINFO_CLASS_HANDLE delegateType,
6262 CORINFO_LOOKUP * pLookup
6265 LIMITED_METHOD_CONTRACT;
6266 UNREACHABLE(); // only called during NGen
6269 /***********************************************************************/
6270 // see code:Nullable#NullableVerification
6272 CORINFO_CLASS_HANDLE CEEInfo::getTypeForBox(CORINFO_CLASS_HANDLE cls)
6274 LIMITED_METHOD_CONTRACT;
6276 TypeHandle VMClsHnd(cls);
6277 if (Nullable::IsNullableType(VMClsHnd)) {
6278 VMClsHnd = VMClsHnd.AsMethodTable()->GetInstantiation()[0];
6280 return static_cast<CORINFO_CLASS_HANDLE>(VMClsHnd.AsPtr());
6283 /***********************************************************************/
6284 // see code:Nullable#NullableVerification
6285 CorInfoHelpFunc CEEInfo::getBoxHelper(CORINFO_CLASS_HANDLE clsHnd)
6293 CorInfoHelpFunc result = CORINFO_HELP_UNDEF;
6295 JIT_TO_EE_TRANSITION();
6297 TypeHandle VMClsHnd(clsHnd);
6298 if (Nullable::IsNullableType(VMClsHnd))
6300 result = CORINFO_HELP_BOX_NULLABLE;
6304 if (VMClsHnd.IsTypeDesc() || !VMClsHnd.IsValueType())
6305 COMPlusThrow(kInvalidOperationException,W("InvalidOperation_TypeCannotBeBoxed"));
6307 // we shouldn't allow boxing of types that contains stack pointers
6308 // csc and vbc already disallow it.
6309 if (VMClsHnd.AsMethodTable()->IsByRefLike())
6310 COMPlusThrow(kInvalidProgramException,W("NotSupported_ByRefLike"));
6312 result = CORINFO_HELP_BOX;
6315 EE_TO_JIT_TRANSITION();
6320 /***********************************************************************/
6321 // registers a vararg sig & returns a class-specific cookie for it.
6323 CORINFO_VARARGS_HANDLE CEEInfo::getVarArgsHandle(CORINFO_SIG_INFO *sig,
6324 void **ppIndirection)
6332 CORINFO_VARARGS_HANDLE result = NULL;
6334 if (ppIndirection != NULL)
6335 *ppIndirection = NULL;
6337 JIT_TO_EE_TRANSITION();
6339 Module* module = GetModule(sig->scope);
6341 result = CORINFO_VARARGS_HANDLE(module->GetVASigCookie(Signature(sig->pSig, sig->cbSig)));
6343 EE_TO_JIT_TRANSITION();
6348 bool CEEInfo::canGetVarArgsHandle(CORINFO_SIG_INFO *sig)
6350 LIMITED_METHOD_CONTRACT;
6354 /***********************************************************************/
6355 unsigned CEEInfo::getMethodHash (CORINFO_METHOD_HANDLE ftnHnd)
6363 unsigned result = 0;
6365 JIT_TO_EE_TRANSITION();
6367 MethodDesc* ftn = GetMethod(ftnHnd);
6369 result = (unsigned) ftn->GetStableHash();
6371 EE_TO_JIT_TRANSITION();
6376 /***********************************************************************/
6377 size_t CEEInfo::printMethodName(CORINFO_METHOD_HANDLE ftnHnd, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize)
6385 size_t bytesWritten = 0;
6387 JIT_TO_EE_TRANSITION();
6389 MethodDesc* ftn = GetMethod(ftnHnd);
6390 const char* ftnName = ftn->GetName();
6392 size_t len = strlen(ftnName);
6395 bytesWritten = min(len, bufferSize - 1);
6396 memcpy(buffer, ftnName, bytesWritten);
6397 buffer[bytesWritten] = '\0';
6400 if (pRequiredBufferSize != NULL)
6402 *pRequiredBufferSize = len + 1;
6405 EE_TO_JIT_TRANSITION();
6407 return bytesWritten;
6410 const char* CEEInfo::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftnHnd, const char** className, const char** namespaceName, const char **enclosingClassName)
6418 const char* result = NULL;
6420 JIT_TO_EE_TRANSITION();
6422 if (className != NULL)
6427 if (namespaceName != NULL)
6429 *namespaceName = NULL;
6432 if (enclosingClassName != NULL)
6434 *enclosingClassName = NULL;
6437 MethodDesc *ftn = GetMethod(ftnHnd);
6438 mdMethodDef token = ftn->GetMemberDef();
6440 if (!IsNilToken(token))
6442 MethodTable* pMT = ftn->GetMethodTable();
6443 IMDInternalImport* pMDImport = pMT->GetMDImport();
6445 IfFailThrow(pMDImport->GetNameOfMethodDef(token, &result));
6446 if (className != NULL || namespaceName != NULL)
6448 IfFailThrow(pMDImport->GetNameOfTypeDef(pMT->GetCl(), className, namespaceName));
6450 // Query enclosingClassName when the method is in a nested class
6451 // and get the namespace of enclosing classes (nested class's namespace is empty)
6452 if ((enclosingClassName != NULL || namespaceName != NULL) && pMT->GetClass()->IsNested())
6454 IfFailThrow(pMDImport->GetNameOfTypeDef(pMT->GetEnclosingCl(), enclosingClassName, namespaceName));
6458 EE_TO_JIT_TRANSITION();
6463 /*********************************************************************/
6464 const char* CEEInfo::getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char** namespaceName)
6472 const char* result = NULL;
6473 const char* namespaceResult = NULL;
6475 JIT_TO_EE_TRANSITION();
6476 TypeHandle VMClsHnd(cls);
6478 if (!VMClsHnd.IsTypeDesc())
6480 result = VMClsHnd.AsMethodTable()->GetFullyQualifiedNameInfo(&namespaceResult);
6483 if (namespaceName != NULL)
6485 *namespaceName = namespaceResult;
6488 EE_TO_JIT_TRANSITION();
6493 /*********************************************************************/
6494 CORINFO_CLASS_HANDLE CEEInfo::getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index)
6502 CORINFO_CLASS_HANDLE result = NULL;
6504 JIT_TO_EE_TRANSITION_LEAF();
6506 TypeHandle VMClsHnd(cls);
6507 Instantiation inst = VMClsHnd.GetInstantiation();
6508 TypeHandle typeArg = index < inst.GetNumArgs() ? inst[index] : NULL;
6509 result = CORINFO_CLASS_HANDLE(typeArg.AsPtr());
6511 EE_TO_JIT_TRANSITION_LEAF();
6516 /*********************************************************************/
6517 bool CEEInfo::isIntrinsic(CORINFO_METHOD_HANDLE ftn)
6527 JIT_TO_EE_TRANSITION_LEAF();
6531 MethodDesc *pMD = (MethodDesc*)ftn;
6532 ret = pMD->IsIntrinsic();
6534 EE_TO_JIT_TRANSITION_LEAF();
6539 /*********************************************************************/
6540 uint32_t CEEInfo::getMethodAttribs (CORINFO_METHOD_HANDLE ftn)
6550 JIT_TO_EE_TRANSITION();
6552 result = getMethodAttribsInternal(ftn);
6554 EE_TO_JIT_TRANSITION();
6559 /*********************************************************************/
6560 DWORD CEEInfo::getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftn)
6562 STANDARD_VM_CONTRACT;
6565 returns method attribute flags (defined in corhdr.h)
6567 NOTE: This doesn't return certain method flags
6568 (mdAssem, mdFamANDAssem, mdFamORAssem, mdPrivateScope)
6571 MethodDesc* pMD = GetMethod(ftn);
6573 if (pMD->IsLCGMethod())
6575 return CORINFO_FLG_STATIC | CORINFO_FLG_DONT_INLINE;
6580 DWORD attribs = pMD->GetAttrs();
6582 if (IsMdFamily(attribs))
6583 result |= CORINFO_FLG_PROTECTED;
6584 if (IsMdStatic(attribs))
6585 result |= CORINFO_FLG_STATIC;
6586 if (pMD->IsSynchronized())
6587 result |= CORINFO_FLG_SYNCH;
6589 result |= CORINFO_FLG_NOGCCHECK;
6590 if (pMD->IsIntrinsic() || pMD->IsArray())
6591 result |= CORINFO_FLG_INTRINSIC;
6592 if (IsMdVirtual(attribs))
6593 result |= CORINFO_FLG_VIRTUAL;
6594 if (IsMdAbstract(attribs))
6595 result |= CORINFO_FLG_ABSTRACT;
6596 if (IsMdRTSpecialName(attribs))
6598 LPCUTF8 pName = pMD->GetName();
6599 if (IsMdInstanceInitializer(attribs, pName) ||
6600 IsMdClassConstructor(attribs, pName))
6601 result |= CORINFO_FLG_CONSTRUCTOR;
6605 // See if we need to embed a .cctor call at the head of the
6609 MethodTable* pMT = pMD->GetMethodTable();
6611 // method or class might have the final bit
6612 if (IsMdFinal(attribs) || pMT->IsSealed())
6614 result |= CORINFO_FLG_FINAL;
6617 if (pMD->IsEnCAddedMethod())
6619 result |= CORINFO_FLG_EnC;
6622 if (pMD->IsSharedByGenericInstantiations())
6624 result |= CORINFO_FLG_SHAREDINST;
6627 if (pMD->IsNDirect())
6629 result |= CORINFO_FLG_PINVOKE;
6632 if (IsMdRequireSecObject(attribs))
6634 // Assume all methods marked as DynamicSecurity are
6635 // marked that way because they use StackCrawlMark to identify
6637 // See comments in canInline or canTailCall
6638 result |= CORINFO_FLG_DONT_INLINE_CALLER;
6641 // Check for the aggressive optimization directive. AggressiveOptimization only makes sense for IL methods.
6642 DWORD ilMethodImplAttribs = 0;
6645 ilMethodImplAttribs = pMD->GetImplAttrs();
6646 if (IsMiAggressiveOptimization(ilMethodImplAttribs))
6648 result |= CORINFO_FLG_AGGRESSIVE_OPT;
6652 // Check for an inlining directive.
6653 if (pMD->IsNotInline())
6655 /* Function marked as not inlineable */
6656 result |= CORINFO_FLG_DONT_INLINE;
6658 // AggressiveInlining only makes sense for IL methods.
6659 else if (pMD->IsIL() && IsMiAggressiveInlining(ilMethodImplAttribs))
6661 result |= CORINFO_FLG_FORCEINLINE;
6664 if (pMT->IsDelegate() && ((DelegateEEClass*)(pMT->GetClass()))->GetInvokeMethod() == pMD)
6666 // This is now used to emit efficient invoke code for any delegate invoke,
6667 // including multicast.
6668 result |= CORINFO_FLG_DELEGATE_INVOKE;
6671 if (!g_pConfig->TieredCompilation_QuickJitForLoops())
6673 result |= CORINFO_FLG_DISABLE_TIER0_FOR_LOOPS;
6679 /*********************************************************************/
6680 void CEEInfo::setMethodAttribs (
6681 CORINFO_METHOD_HANDLE ftnHnd,
6682 CorInfoMethodRuntimeFlags attribs)
6690 JIT_TO_EE_TRANSITION();
6692 MethodDesc* ftn = GetMethod(ftnHnd);
6694 if (attribs & CORINFO_FLG_BAD_INLINEE)
6696 ftn->SetNotInline(true);
6699 if (attribs & (CORINFO_FLG_SWITCHED_TO_OPTIMIZED | CORINFO_FLG_SWITCHED_TO_MIN_OPT))
6701 PrepareCodeConfig *config = GetThread()->GetCurrentPrepareCodeConfig();
6702 if (config != nullptr)
6704 if (attribs & CORINFO_FLG_SWITCHED_TO_MIN_OPT)
6706 _ASSERTE(!ftn->IsJitOptimizationDisabled());
6707 config->SetJitSwitchedToMinOpt();
6709 #ifdef FEATURE_TIERED_COMPILATION
6710 else if (attribs & CORINFO_FLG_SWITCHED_TO_OPTIMIZED)
6712 _ASSERTE(ftn->IsEligibleForTieredCompilation());
6713 config->SetJitSwitchedToOptimized();
6719 EE_TO_JIT_TRANSITION();
6722 /*********************************************************************/
6724 void getMethodInfoILMethodHeaderHelper(
6725 COR_ILMETHOD_DECODER* header,
6726 CORINFO_METHOD_INFO* methInfo
6729 LIMITED_METHOD_CONTRACT;
6731 methInfo->ILCode = const_cast<BYTE*>(header->Code);
6732 methInfo->ILCodeSize = header->GetCodeSize();
6733 methInfo->maxStack = static_cast<unsigned short>(header->GetMaxStack());
6734 methInfo->EHcount = static_cast<unsigned short>(header->EHCount());
6737 (CorInfoOptions)((header->GetFlags() & CorILMethod_InitLocals) ? CORINFO_OPT_INIT_LOCALS : 0) ;
6740 mdToken FindGenericMethodArgTypeSpec(IMDInternalImport* pInternalImport)
6742 STANDARD_VM_CONTRACT;
6744 HENUMInternalHolder hEnumTypeSpecs(pInternalImport);
6747 static const BYTE signature[] = { ELEMENT_TYPE_MVAR, 0 };
6749 hEnumTypeSpecs.EnumAllInit(mdtTypeSpec);
6750 while (hEnumTypeSpecs.EnumNext(&token))
6752 PCCOR_SIGNATURE pSig;
6754 IfFailThrow(pInternalImport->GetTypeSpecFromToken(token, &pSig, &cbSig));
6755 if (cbSig == sizeof(signature) && memcmp(pSig, signature, cbSig) == 0)
6759 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
6762 static void setILIntrinsicMethodInfo(CORINFO_METHOD_INFO* methInfo,uint8_t* ilcode, int ilsize, int maxstack)
6764 methInfo->ILCode = ilcode;
6765 methInfo->ILCodeSize = ilsize;
6766 methInfo->maxStack = maxstack;
6767 methInfo->EHcount = 0;
6768 methInfo->options = (CorInfoOptions)0;
6771 /*********************************************************************
6773 IL is the most efficient and portable way to implement certain low level methods
6774 in CoreLib. Unfortunately, there is no good way to link IL into CoreLib today.
6775 Until we find a good way to link IL into CoreLib, we will provide the IL implementation here.
6777 - All IL intrinsincs are members of System.Runtime.CompilerServices.JitHelpers class
6778 - All IL intrinsincs should be kept very simple. Implement the minimal reusable version of
6779 unsafe construct and depend on inlining to do the rest.
6780 - The C# implementation of the IL intrinsic should be good enough for functionalily. Everything should work
6781 correctly (but slower) if the IL intrinsics are removed.
6783 *********************************************************************/
6785 bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
6786 CORINFO_METHOD_INFO * methInfo)
6788 STANDARD_VM_CONTRACT;
6790 _ASSERTE(CoreLibBinder::IsClass(ftn->GetMethodTable(), CLASS__UNSAFE));
6792 mdMethodDef tk = ftn->GetMemberDef();
6794 if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__AS_POINTER)->GetMemberDef())
6796 // Return the argument that was passed in.
6797 static const BYTE ilcode[] =
6804 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 1);
6808 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef() ||
6809 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__OBJECT_AS)->GetMemberDef() ||
6810 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__AS_REF_IN)->GetMemberDef())
6812 // Return the argument that was passed in.
6813 static const BYTE ilcode[] =
6819 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 1);
6823 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD)->GetMemberDef() ||
6824 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_ADD)->GetMemberDef())
6826 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
6828 static const BYTE ilcode[] =
6832 CEE_PREFIX1, (CEE_SIZEOF & 0xFF), (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6839 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
6843 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INTPTR_ADD)->GetMemberDef() ||
6844 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_UINTPTR_ADD)->GetMemberDef())
6846 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
6848 static const BYTE ilcode[] =
6852 CEE_PREFIX1, (CEE_SIZEOF & 0xFF), (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6858 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
6862 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INTPTR_ADD_BYTE_OFFSET)->GetMemberDef() ||
6863 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_UINTPTR_ADD_BYTE_OFFSET)->GetMemberDef())
6865 static const BYTE ilcode[] =
6873 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
6877 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_ARE_SAME)->GetMemberDef())
6879 // Compare the two arguments
6880 static const BYTE ilcode[] =
6884 CEE_PREFIX1, (CEE_CEQ & 0xFF),
6888 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
6892 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_BYREF_COPY)->GetMemberDef() ||
6893 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_PTR_COPY)->GetMemberDef())
6895 _ASSERTE(ftn->HasMethodInstantiation());
6896 Instantiation inst = ftn->GetMethodInstantiation();
6897 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
6898 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
6900 static const BYTE ilcode[] =
6904 CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6905 CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
6909 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
6913 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_COPY_BLOCK)->GetMemberDef() ||
6914 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_COPY_BLOCK)->GetMemberDef())
6916 static const BYTE ilcode[] =
6921 CEE_PREFIX1, (CEE_CPBLK & 0xFF),
6925 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
6929 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_COPY_BLOCK_UNALIGNED)->GetMemberDef() ||
6930 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_COPY_BLOCK_UNALIGNED)->GetMemberDef())
6932 static const BYTE ilcode[] =
6937 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 0x01,
6938 CEE_PREFIX1, (CEE_CPBLK & 0xFF),
6942 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
6946 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_GREATER_THAN)->GetMemberDef())
6948 // Compare the two arguments
6949 static const BYTE ilcode[] =
6953 CEE_PREFIX1, (CEE_CGT_UN & 0xFF),
6957 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
6961 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_ADDRESS_LESS_THAN)->GetMemberDef())
6963 // Compare the two arguments
6964 static const BYTE ilcode[] =
6968 CEE_PREFIX1, (CEE_CLT_UN & 0xFF),
6972 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
6976 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_NULLREF)->GetMemberDef())
6978 static const BYTE ilcode[] =
6985 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 1);
6989 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_IS_NULL)->GetMemberDef())
6991 // 'ldnull' opcode would produce type o, and we can't compare & against o (ECMA-335, Table III.4).
6992 // However, we can compare & against native int, so we'll use that instead.
6994 static const BYTE ilcode[] =
6999 CEE_PREFIX1, (CEE_CEQ & 0xFF),
7003 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7007 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INIT_BLOCK)->GetMemberDef() ||
7008 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_INIT_BLOCK)->GetMemberDef())
7010 static const BYTE ilcode[] =
7015 CEE_PREFIX1, (CEE_INITBLK & 0xFF),
7019 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
7023 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INIT_BLOCK_UNALIGNED)->GetMemberDef() ||
7024 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_INIT_BLOCK_UNALIGNED)->GetMemberDef())
7026 static const BYTE ilcode[] =
7031 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 0x01,
7032 CEE_PREFIX1, (CEE_INITBLK & 0xFF),
7036 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
7040 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_BYTE_OFFSET)->GetMemberDef())
7042 static const BYTE ilcode[] =
7050 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7054 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_READ_UNALIGNED)->GetMemberDef() ||
7055 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_READ_UNALIGNED)->GetMemberDef())
7057 _ASSERTE(ftn->HasMethodInstantiation());
7058 Instantiation inst = ftn->GetMethodInstantiation();
7059 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7060 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7062 static const BYTE ilcode[] =
7065 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
7066 CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7070 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7074 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_WRITE_UNALIGNED)->GetMemberDef() ||
7075 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_WRITE_UNALIGNED)->GetMemberDef())
7077 _ASSERTE(ftn->HasMethodInstantiation());
7078 Instantiation inst = ftn->GetMethodInstantiation();
7079 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7080 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7082 static const BYTE ilcode[] =
7086 CEE_PREFIX1, (CEE_UNALIGNED & 0xFF), 1,
7087 CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7091 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7095 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__READ)->GetMemberDef())
7097 _ASSERTE(ftn->HasMethodInstantiation());
7098 Instantiation inst = ftn->GetMethodInstantiation();
7099 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7100 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7102 static const BYTE ilcode[] =
7105 CEE_LDOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7109 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7113 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__SKIPINIT)->GetMemberDef())
7115 static const BYTE ilcode[] =
7120 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 0);
7124 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INT_SUBTRACT)->GetMemberDef() ||
7125 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__PTR_INT_SUBTRACT)->GetMemberDef())
7127 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7129 static const BYTE ilcode[] =
7133 CEE_PREFIX1, (CEE_SIZEOF & 0xFF), (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7140 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
7144 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INTPTR_SUBTRACT)->GetMemberDef() ||
7145 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_UINTPTR_SUBTRACT)->GetMemberDef())
7147 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7149 static const BYTE ilcode[] =
7153 CEE_PREFIX1, (CEE_SIZEOF & 0xFF), (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7159 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 3);
7163 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_INTPTR_SUBTRACT_BYTE_OFFSET)->GetMemberDef() ||
7164 tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_UINTPTR_SUBTRACT_BYTE_OFFSET)->GetMemberDef())
7166 static const BYTE ilcode[] =
7174 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7178 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__WRITE)->GetMemberDef())
7180 _ASSERTE(ftn->HasMethodInstantiation());
7181 Instantiation inst = ftn->GetMethodInstantiation();
7182 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7183 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7185 static const BYTE ilcode[] =
7189 CEE_STOBJ, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7193 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7197 else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__UNBOX)->GetMemberDef())
7199 _ASSERTE(ftn->HasMethodInstantiation());
7200 Instantiation inst = ftn->GetMethodInstantiation();
7201 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7202 mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport());
7204 static const BYTE ilcode[] =
7207 CEE_UNBOX, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
7211 setILIntrinsicMethodInfo(methInfo,const_cast<BYTE*>(ilcode),sizeof(ilcode), 2);
7219 bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn,
7220 CORINFO_METHOD_INFO * methInfo)
7222 STANDARD_VM_CONTRACT;
7224 _ASSERTE(CoreLibBinder::IsClass(ftn->GetMethodTable(), CLASS__INTERLOCKED));
7226 // We are only interested if ftn's token and CompareExchange<T> token match
7227 if (ftn->GetMemberDef() != CoreLibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_T)->GetMemberDef())
7230 // Get MethodDesc for non-generic System.Threading.Interlocked.CompareExchange()
7231 MethodDesc* cmpxchgObject = CoreLibBinder::GetMethod(METHOD__INTERLOCKED__COMPARE_EXCHANGE_OBJECT);
7233 // Setup up the body of the method
7234 static BYTE il[] = {
7242 // Get the token for non-generic System.Threading.Interlocked.CompareExchange(), and patch [target]
7243 mdMethodDef cmpxchgObjectToken = cmpxchgObject->GetMemberDef();
7244 il[4] = (BYTE)((int)cmpxchgObjectToken >> 0);
7245 il[5] = (BYTE)((int)cmpxchgObjectToken >> 8);
7246 il[6] = (BYTE)((int)cmpxchgObjectToken >> 16);
7247 il[7] = (BYTE)((int)cmpxchgObjectToken >> 24);
7249 // Initialize methInfo
7250 methInfo->ILCode = const_cast<BYTE*>(il);
7251 methInfo->ILCodeSize = sizeof(il);
7252 methInfo->maxStack = 3;
7253 methInfo->EHcount = 0;
7254 methInfo->options = (CorInfoOptions)0;
7259 bool IsBitwiseEquatable(TypeHandle typeHandle, MethodTable * methodTable)
7261 if (!methodTable->IsValueType() ||
7262 !CanCompareBitsOrUseFastGetHashCode(methodTable))
7267 // CanCompareBitsOrUseFastGetHashCode checks for an object.Equals override.
7268 // We also need to check for an IEquatable<T> implementation.
7269 Instantiation inst(&typeHandle, 1);
7270 if (typeHandle.CanCastTo(TypeHandle(CoreLibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(inst)))
7278 bool getILIntrinsicImplementationForRuntimeHelpers(MethodDesc * ftn,
7279 CORINFO_METHOD_INFO * methInfo)
7281 STANDARD_VM_CONTRACT;
7283 _ASSERTE(CoreLibBinder::IsClass(ftn->GetMethodTable(), CLASS__RUNTIME_HELPERS));
7285 mdMethodDef tk = ftn->GetMemberDef();
7287 if (tk == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_REFERENCE_OR_CONTAINS_REFERENCES)->GetMemberDef())
7289 _ASSERTE(ftn->HasMethodInstantiation());
7290 Instantiation inst = ftn->GetMethodInstantiation();
7292 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7293 TypeHandle typeHandle = inst[0];
7294 MethodTable * methodTable = typeHandle.GetMethodTable();
7296 static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
7297 static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };
7299 if (!methodTable->IsValueType() || methodTable->ContainsPointers())
7301 methInfo->ILCode = const_cast<BYTE*>(returnTrue);
7305 methInfo->ILCode = const_cast<BYTE*>(returnFalse);
7308 methInfo->ILCodeSize = sizeof(returnTrue);
7309 methInfo->maxStack = 1;
7310 methInfo->EHcount = 0;
7311 methInfo->options = (CorInfoOptions)0;
7315 if (tk == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__IS_BITWISE_EQUATABLE)->GetMemberDef())
7317 _ASSERTE(ftn->HasMethodInstantiation());
7318 Instantiation inst = ftn->GetMethodInstantiation();
7320 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7321 TypeHandle typeHandle = inst[0];
7322 MethodTable * methodTable = typeHandle.GetMethodTable();
7324 static const BYTE returnTrue[] = { CEE_LDC_I4_1, CEE_RET };
7325 static const BYTE returnFalse[] = { CEE_LDC_I4_0, CEE_RET };
7327 // Ideally we could detect automatically whether a type is trivially equatable
7328 // (i.e., its operator == could be implemented via memcmp). The best we can do
7329 // for now is hardcode a list of known supported types and then also include anything
7330 // that doesn't provide its own object.Equals override / IEquatable<T> implementation.
7331 // n.b. This doesn't imply that the type's CompareTo method can be memcmp-implemented,
7332 // as a method like CompareTo may need to take a type's signedness into account.
7334 if (methodTable == CoreLibBinder::GetClass(CLASS__BOOLEAN)
7335 || methodTable == CoreLibBinder::GetClass(CLASS__BYTE)
7336 || methodTable == CoreLibBinder::GetClass(CLASS__SBYTE)
7337 || methodTable == CoreLibBinder::GetClass(CLASS__CHAR)
7338 || methodTable == CoreLibBinder::GetClass(CLASS__INT16)
7339 || methodTable == CoreLibBinder::GetClass(CLASS__UINT16)
7340 || methodTable == CoreLibBinder::GetClass(CLASS__INT32)
7341 || methodTable == CoreLibBinder::GetClass(CLASS__UINT32)
7342 || methodTable == CoreLibBinder::GetClass(CLASS__INT64)
7343 || methodTable == CoreLibBinder::GetClass(CLASS__UINT64)
7344 || methodTable == CoreLibBinder::GetClass(CLASS__INTPTR)
7345 || methodTable == CoreLibBinder::GetClass(CLASS__UINTPTR)
7346 || methodTable == CoreLibBinder::GetClass(CLASS__RUNE)
7347 || methodTable->IsEnum()
7348 || IsBitwiseEquatable(typeHandle, methodTable))
7350 methInfo->ILCode = const_cast<BYTE*>(returnTrue);
7354 methInfo->ILCode = const_cast<BYTE*>(returnFalse);
7357 methInfo->ILCodeSize = sizeof(returnTrue);
7358 methInfo->maxStack = 1;
7359 methInfo->EHcount = 0;
7360 methInfo->options = (CorInfoOptions)0;
7364 if (tk == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__GET_METHOD_TABLE)->GetMemberDef())
7366 mdToken tokRawData = CoreLibBinder::GetField(FIELD__RAW_DATA__DATA)->GetMemberDef();
7368 // In the CLR, an object is laid out as follows.
7369 // [ object_header || MethodTable* (64-bit pointer) || instance_data ]
7370 // ^ ^-- ref <theObj>.firstField points here
7371 // `-- <theObj> reference (type O) points here
7373 // So essentially what we want to do is to turn an object reference (type O) into a
7374 // native int&, then dereference it to get the MethodTable*. (Essentially, an object
7375 // reference is a MethodTable**.) Per ECMA-335, Sec. III.1.5, we can add
7376 // (but not subtract) a & and an int32 to produce a &. So we'll get a reference to
7377 // <theObj>.firstField (type &), then back up one pointer length to get a value of
7378 // essentially type (MethodTable*)&. Both of these are legal GC-trackable references
7379 // to <theObj>, regardless of <theObj>'s actual length.
7381 static BYTE ilcode[] = { CEE_LDARG_0, // stack contains [ O ] = <theObj>
7382 CEE_LDFLDA,0,0,0,0, // stack contains [ & ] = ref <theObj>.firstField
7383 CEE_LDC_I4_S,(BYTE)(-TARGET_POINTER_SIZE), // stack contains [ &, int32 ] = -IntPtr.Size
7384 CEE_ADD, // stack contains [ & ] = ref <theObj>.methodTablePtr
7385 CEE_LDIND_I, // stack contains [ native int ] = <theObj>.methodTablePtr
7388 ilcode[2] = (BYTE)(tokRawData);
7389 ilcode[3] = (BYTE)(tokRawData >> 8);
7390 ilcode[4] = (BYTE)(tokRawData >> 16);
7391 ilcode[5] = (BYTE)(tokRawData >> 24);
7393 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7394 methInfo->ILCodeSize = sizeof(ilcode);
7395 methInfo->maxStack = 2;
7396 methInfo->EHcount = 0;
7397 methInfo->options = (CorInfoOptions)0;
7401 if (tk == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__ENUM_EQUALS)->GetMemberDef())
7403 // Normally we would follow the above pattern and unconditionally replace the IL,
7404 // relying on generic type constraints to guarantee that it will only ever be instantiated
7405 // on the type/size of argument we expect.
7407 // However C#/CLR does not support restricting a generic type to be an Enum, so the best
7408 // we can do is constrain it to be a value type. This is fine for run time, since we only
7409 // ever create instantiations on 4 byte or less Enums. But during NGen we may compile instantiations
7410 // on other value types (to be specific, every value type instatiation of EqualityComparer
7411 // because of its TypeDependencyAttribute; here again we would like to restrict this to
7412 // 4 byte or less Enums but cannot).
7414 // This IL is invalid for those instantiations, and replacing it would lead to all sorts of
7415 // errors at NGen time. So we only replace it for instantiations where it would be valid,
7416 // leaving the others, which we should never execute, with the C# implementation of throwing.
7418 _ASSERTE(ftn->HasMethodInstantiation());
7419 Instantiation inst = ftn->GetMethodInstantiation();
7421 _ASSERTE(inst.GetNumArgs() == 1);
7422 CorElementType et = inst[0].GetVerifierCorElementType();
7423 if (et == ELEMENT_TYPE_I4 ||
7424 et == ELEMENT_TYPE_U4 ||
7425 et == ELEMENT_TYPE_I2 ||
7426 et == ELEMENT_TYPE_U2 ||
7427 et == ELEMENT_TYPE_I1 ||
7428 et == ELEMENT_TYPE_U1 ||
7429 et == ELEMENT_TYPE_I8 ||
7430 et == ELEMENT_TYPE_U8)
7432 static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (CEE_CEQ & 0xFF), CEE_RET };
7433 methInfo->ILCode = const_cast<BYTE*>(ilcode);
7434 methInfo->ILCodeSize = sizeof(ilcode);
7435 methInfo->maxStack = 2;
7436 methInfo->EHcount = 0;
7437 methInfo->options = (CorInfoOptions)0;
7441 else if (tk == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__ENUM_COMPARE_TO)->GetMemberDef())
7443 // The comment above on why this is not an unconditional replacement. This case handles
7444 // Enums backed by 8 byte values.
7446 _ASSERTE(ftn->HasMethodInstantiation());
7447 Instantiation inst = ftn->GetMethodInstantiation();
7449 _ASSERTE(inst.GetNumArgs() == 1);
7450 CorElementType et = inst[0].GetVerifierCorElementType();
7451 if (et == ELEMENT_TYPE_I4 ||
7452 et == ELEMENT_TYPE_U4 ||
7453 et == ELEMENT_TYPE_I2 ||
7454 et == ELEMENT_TYPE_U2 ||
7455 et == ELEMENT_TYPE_I1 ||
7456 et == ELEMENT_TYPE_U1 ||
7457 et == ELEMENT_TYPE_I8 ||
7458 et == ELEMENT_TYPE_U8)
7460 static BYTE ilcode[8][9];
7462 TypeHandle thUnderlyingType = CoreLibBinder::GetElementType(et);
7464 TypeHandle thIComparable = TypeHandle(CoreLibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(Instantiation(&thUnderlyingType, 1));
7466 MethodDesc* pCompareToMD = thUnderlyingType.AsMethodTable()->GetMethodDescForInterfaceMethod(
7467 thIComparable, CoreLibBinder::GetMethod(METHOD__ICOMPARABLEGENERIC__COMPARE_TO), TRUE /* throwOnConflict */);
7469 // Call CompareTo method on the primitive type
7470 int tokCompareTo = pCompareToMD->GetMemberDef();
7472 unsigned int index = (et - ELEMENT_TYPE_I1);
7473 _ASSERTE(index < ARRAY_SIZE(ilcode));
7475 ilcode[index][0] = CEE_LDARGA_S;
7476 ilcode[index][1] = 0;
7477 ilcode[index][2] = CEE_LDARG_1;
7478 ilcode[index][3] = CEE_CALL;
7479 ilcode[index][4] = (BYTE)(tokCompareTo);
7480 ilcode[index][5] = (BYTE)(tokCompareTo >> 8);
7481 ilcode[index][6] = (BYTE)(tokCompareTo >> 16);
7482 ilcode[index][7] = (BYTE)(tokCompareTo >> 24);
7483 ilcode[index][8] = CEE_RET;
7485 methInfo->ILCode = const_cast<BYTE*>(ilcode[index]);
7486 methInfo->ILCodeSize = sizeof(ilcode[index]);
7487 methInfo->maxStack = 2;
7488 methInfo->EHcount = 0;
7489 methInfo->options = (CorInfoOptions)0;
7497 bool getILIntrinsicImplementationForActivator(MethodDesc* ftn,
7498 CORINFO_METHOD_INFO* methInfo,
7501 STANDARD_VM_CONTRACT;
7503 _ASSERTE(CoreLibBinder::IsClass(ftn->GetMethodTable(), CLASS__ACTIVATOR));
7505 // We are only interested if ftn's token and CreateInstance<T> token match
7506 if (ftn->GetMemberDef() != CoreLibBinder::GetMethod(METHOD__ACTIVATOR__CREATE_INSTANCE_OF_T)->GetMemberDef())
7509 _ASSERTE(ftn->HasMethodInstantiation());
7510 Instantiation inst = ftn->GetMethodInstantiation();
7512 _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
7513 TypeHandle typeHandle = inst[0];
7514 MethodTable* methodTable = typeHandle.GetMethodTable();
7516 if (!methodTable->IsValueType() || methodTable->HasDefaultConstructor())
7519 // Replace the body with implementation that just returns "default"
7520 MethodDesc* createDefaultInstance = CoreLibBinder::GetMethod(METHOD__ACTIVATOR__CREATE_DEFAULT_INSTANCE_OF_T);
7521 COR_ILMETHOD_DECODER header(createDefaultInstance->GetILHeader(FALSE), createDefaultInstance->GetMDImport(), NULL);
7522 getMethodInfoILMethodHeaderHelper(&header, methInfo);
7523 *pSig = SigPointer(header.LocalVarSig, header.cbLocalVarSig);
7528 //---------------------------------------------------------------------------------------
7531 class MethodInfoHelperContext final
7535 COR_ILMETHOD_DECODER* Header;
7536 DynamicResolver* TransientResolver;
7538 MethodInfoHelperContext(MethodDesc* pMD, _In_opt_ COR_ILMETHOD_DECODER* header = NULL)
7541 , TransientResolver{}
7543 LIMITED_METHOD_CONTRACT;
7544 _ASSERTE(pMD != NULL);
7547 MethodInfoHelperContext(const MethodInfoHelperContext&) = delete;
7548 MethodInfoHelperContext(MethodInfoHelperContext&& other) = delete;
7550 ~MethodInfoHelperContext()
7552 STANDARD_VM_CONTRACT;
7553 delete TransientResolver;
7556 MethodInfoHelperContext& operator=(const MethodInfoHelperContext&) = delete;
7557 MethodInfoHelperContext& operator=(MethodInfoHelperContext&& other) = delete;
7559 bool HasTransientMethodDetails() const
7561 LIMITED_METHOD_CONTRACT;
7562 return TransientResolver != NULL;
7565 CORINFO_MODULE_HANDLE CreateScopeHandle() const
7567 LIMITED_METHOD_CONTRACT;
7568 _ASSERTE(HasTransientMethodDetails());
7569 return MakeDynamicScope(TransientResolver);
7572 // This operation transfers any ownership to a
7573 // TransientMethodDetails instance.
7574 TransientMethodDetails CreateTransientMethodDetails()
7576 STANDARD_VM_CONTRACT;
7577 _ASSERTE(HasTransientMethodDetails());
7579 CORINFO_MODULE_HANDLE handle = CreateScopeHandle();
7580 TransientResolver = NULL;
7581 return TransientMethodDetails{ Method, Header, handle };
7584 void UpdateWith(const TransientMethodDetails& details)
7586 LIMITED_METHOD_CONTRACT;
7587 Header = details.Header;
7588 TransientResolver = details.Scope != NULL ? GetDynamicResolver(details.Scope) : NULL;
7591 void TakeOwnership(TransientMethodDetails details)
7593 LIMITED_METHOD_CONTRACT;
7594 UpdateWith(details);
7596 // Default initialize local instance since we are
7597 // taking ownership of the transient method details.
7602 static void getMethodInfoHelper(
7603 MethodInfoHelperContext& cxt,
7604 CORINFO_METHOD_INFO* methInfo,
7605 CORINFO_CONTEXT_HANDLE exactContext = NULL)
7607 STANDARD_VM_CONTRACT;
7608 _ASSERTE(methInfo != NULL);
7610 MethodDesc* ftn = cxt.Method;
7611 methInfo->ftn = (CORINFO_METHOD_HANDLE)ftn;
7612 methInfo->regionKind = CORINFO_REGION_JIT;
7614 CORINFO_MODULE_HANDLE scopeHnd = NULL;
7616 /* Grab information from the IL header */
7617 PCCOR_SIGNATURE pLocalSig = NULL;
7618 uint32_t cbLocalSig = 0;
7620 // Having a header means there is backing IL for the method.
7621 if (NULL != cxt.Header)
7623 scopeHnd = cxt.HasTransientMethodDetails()
7624 ? cxt.CreateScopeHandle()
7625 : GetScopeHandle(ftn);
7626 bool fILIntrinsic = false;
7628 MethodTable * pMT = ftn->GetMethodTable();
7630 if (ftn->IsIntrinsic())
7632 if (CoreLibBinder::IsClass(pMT, CLASS__UNSAFE))
7634 fILIntrinsic = getILIntrinsicImplementationForUnsafe(ftn, methInfo);
7636 else if (CoreLibBinder::IsClass(pMT, CLASS__INTERLOCKED))
7638 fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo);
7640 else if (CoreLibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS))
7642 fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo);
7644 else if (CoreLibBinder::IsClass(pMT, CLASS__ACTIVATOR))
7646 SigPointer localSig;
7647 fILIntrinsic = getILIntrinsicImplementationForActivator(ftn, methInfo, &localSig);
7650 localSig.GetSignature(&pLocalSig, &cbLocalSig);
7657 getMethodInfoILMethodHeaderHelper(cxt.Header, methInfo);
7658 pLocalSig = cxt.Header->LocalVarSig;
7659 cbLocalSig = cxt.Header->cbLocalVarSig;
7662 else if (ftn->IsDynamicMethod())
7664 DynamicResolver* pResolver = ftn->AsDynamicMethodDesc()->GetResolver();
7665 scopeHnd = MakeDynamicScope(pResolver);
7667 unsigned int EHCount;
7668 methInfo->ILCode = pResolver->GetCodeInfo(&methInfo->ILCodeSize,
7669 &methInfo->maxStack,
7672 methInfo->EHcount = (unsigned short)EHCount;
7673 SigPointer localSig = pResolver->GetLocalSig();
7674 localSig.GetSignature(&pLocalSig, &cbLocalSig);
7678 if (!ftn->TryGenerateUnsafeAccessor(&cxt.TransientResolver, &cxt.Header))
7679 ThrowHR(COR_E_BADIMAGEFORMAT);
7681 scopeHnd = cxt.CreateScopeHandle();
7683 _ASSERTE(cxt.Header != NULL);
7684 getMethodInfoILMethodHeaderHelper(cxt.Header, methInfo);
7685 pLocalSig = cxt.Header->LocalVarSig;
7686 cbLocalSig = cxt.Header->cbLocalVarSig;
7689 _ASSERTE(scopeHnd != NULL);
7690 methInfo->scope = scopeHnd;
7691 methInfo->options = (CorInfoOptions)(((UINT32)methInfo->options) |
7692 ((ftn->AcquiresInstMethodTableFromThis() ? CORINFO_GENERICS_CTXT_FROM_THIS : 0) |
7693 (ftn->RequiresInstMethodTableArg() ? CORINFO_GENERICS_CTXT_FROM_METHODTABLE : 0) |
7694 (ftn->RequiresInstMethodDescArg() ? CORINFO_GENERICS_CTXT_FROM_METHODDESC : 0)));
7696 // EEJitManager::ResolveEHClause and CrawlFrame::GetExactGenericInstantiations
7697 // need to be able to get to CORINFO_GENERICS_CTXT_MASK if there are any
7698 // catch clauses like "try {} catch(MyException<T> e) {}".
7699 // Such constructs are rare, and having to extend the lifetime of variable
7700 // for such cases is reasonable
7702 if (methInfo->options & CORINFO_GENERICS_CTXT_MASK)
7704 #if defined(PROFILING_SUPPORTED)
7705 BOOL fProfilerRequiresGenericsContextForEnterLeave = FALSE;
7707 BEGIN_PROFILER_CALLBACK(CORProfilerPresent());
7708 if ((&g_profControlBlock)->RequiresGenericsContextForEnterLeave())
7710 fProfilerRequiresGenericsContextForEnterLeave = TRUE;
7712 END_PROFILER_CALLBACK();
7714 if (fProfilerRequiresGenericsContextForEnterLeave)
7716 methInfo->options = CorInfoOptions(methInfo->options|CORINFO_GENERICS_CTXT_KEEP_ALIVE);
7718 #endif // defined(PROFILING_SUPPORTED)
7721 PCCOR_SIGNATURE pSig = NULL;
7723 ftn->GetSig(&pSig, &cbSig);
7725 SigTypeContext context;
7727 if (exactContext == NULL || exactContext == METHOD_BEING_COMPILED_CONTEXT())
7729 SigTypeContext::InitTypeContext(ftn, &context);
7731 else if (((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD)
7733 MethodDesc* contextMD = (MethodDesc*)((size_t)exactContext & ~CORINFO_CONTEXTFLAGS_MASK);
7734 SigTypeContext::InitTypeContext(contextMD, &context);
7738 _ASSERT(((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS);
7739 TypeHandle th = TypeHandle((CORINFO_CLASS_HANDLE)((size_t)exactContext & ~CORINFO_CONTEXTFLAGS_MASK));
7740 SigTypeContext::InitTypeContext(th, &context);
7743 /* Fetch the method signature */
7744 // Type parameters in the signature should be instantiated according to the
7745 // class/method/array instantiation of ftnHnd
7752 CONV_TO_JITSIG_FLAGS_NONE,
7755 // Shared generic or static per-inst methods and shared methods on generic structs
7756 // take an extra argument representing their instantiation
7757 if (ftn->RequiresInstArg())
7758 methInfo->args.callConv = (CorInfoCallConv)(methInfo->args.callConv | CORINFO_CALLCONV_PARAMTYPE);
7760 _ASSERTE((IsMdStatic(ftn->GetAttrs()) == 0) == ((methInfo->args.callConv & CORINFO_CALLCONV_HASTHIS) != 0));
7762 /* And its local variables */
7763 // Type parameters in the signature should be instantiated according to the
7764 // class/method/array instantiation of ftnHnd
7771 CONV_TO_JITSIG_FLAGS_LOCALSIG,
7773 } // getMethodInfoHelper
7775 //---------------------------------------------------------------------------------------
7778 CEEInfo::getMethodInfo(
7779 CORINFO_METHOD_HANDLE ftnHnd,
7780 CORINFO_METHOD_INFO * methInfo,
7781 CORINFO_CONTEXT_HANDLE context)
7789 bool result = false;
7791 JIT_TO_EE_TRANSITION();
7793 MethodDesc * ftn = GetMethod(ftnHnd);
7795 // Get the IL header
7796 MethodInfoHelperContext cxt{ ftn };
7797 if (ftn->IsDynamicMethod())
7799 getMethodInfoHelper(cxt, methInfo, context);
7802 else if (!ftn->IsWrapperStub() && ftn->HasILHeader())
7804 COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
7805 cxt.Header = &header;
7806 getMethodInfoHelper(cxt, methInfo, context);
7809 else if (ftn->IsIL() && ftn->GetRVA() == 0)
7811 // We will either find or create transient method details.
7812 _ASSERTE(!cxt.HasTransientMethodDetails());
7814 // IL methods with no RVA indicate there is no implementation defined in metadata.
7815 // Check if we previously generated details/implementation for this method.
7816 TransientMethodDetails* detailsMaybe = NULL;
7817 if (FindTransientMethodDetails(ftn, &detailsMaybe))
7818 cxt.UpdateWith(*detailsMaybe);
7820 getMethodInfoHelper(cxt, methInfo);
7822 // If we have transient method details we need to handle
7823 // the lifetime of the details.
7824 if (cxt.HasTransientMethodDetails())
7826 // If we didn't find transient details, but we have them
7827 // after getting method info, store them for cleanup.
7828 if (detailsMaybe == NULL)
7829 AddTransientMethodDetails(cxt.CreateTransientMethodDetails());
7831 // Reset the context because ownership has either been
7832 // transferred or was found in this instance.
7841 LOG((LF_JIT, LL_INFO100000, "Getting method info (possible inline) %s::%s%s\n",
7842 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
7845 EE_TO_JIT_TRANSITION();
7850 bool CEEInfo::haveSameMethodDefinition(
7851 CORINFO_METHOD_HANDLE meth1Hnd,
7852 CORINFO_METHOD_HANDLE meth2Hnd)
7860 bool result = false;
7862 JIT_TO_EE_TRANSITION_LEAF();
7864 MethodDesc* meth1 = GetMethod(meth1Hnd);
7865 MethodDesc* meth2 = GetMethod(meth2Hnd);
7866 result = meth1->HasSameMethodDefAs(meth2);
7868 EE_TO_JIT_TRANSITION_LEAF();
7873 /*************************************************************
7874 * Check if the caller and calle are in the same assembly
7875 * i.e. do not inline across assemblies
7876 *************************************************************/
7878 CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller,
7879 CORINFO_METHOD_HANDLE hCallee)
7887 CorInfoInline result = INLINE_PASS; // By default we pass.
7888 // Do not set pass in the rest of the method.
7889 const char * szFailReason = NULL; // for reportInlineDecision
7891 JIT_TO_EE_TRANSITION();
7893 // This does not work in the multi-threaded case
7895 // Caller should check this condition first
7896 _ASSERTE(!(CORINFO_FLG_DONT_INLINE & getMethodAttribsInternal(hCallee)));
7899 MethodDesc* pCaller = GetMethod(hCaller);
7900 MethodDesc* pCallee = GetMethod(hCallee);
7902 if (pCallee->IsNoMetadata())
7904 result = INLINE_FAIL;
7905 szFailReason = "Inlinee is NoMetadata";
7909 #ifdef DEBUGGING_SUPPORTED
7911 // If the callee wants debuggable code, don't allow it to be inlined
7914 // Combining the next two lines, and eliminating jitDebuggerFlags, leads to bad codegen in x86 Release builds using Visual C++ 19.00.24215.1.
7915 CORJIT_FLAGS jitDebuggerFlags = GetDebuggerCompileFlags(pCallee->GetModule(), CORJIT_FLAGS());
7916 if (jitDebuggerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE))
7918 result = INLINE_NEVER;
7919 szFailReason = "Inlinee is debuggable";
7925 // The original caller is the current method
7926 MethodDesc * pOrigCaller;
7927 pOrigCaller = m_pMethodBeingCompiled;
7928 Module * pOrigCallerModule;
7929 pOrigCallerModule = pOrigCaller->GetLoaderModule();
7931 if (pCallee->IsNotInline())
7933 result = INLINE_NEVER;
7934 szFailReason = "Inlinee is marked as no inline";
7938 // Also check to see if the method requires a security object. This means they call demand and
7939 // shouldn't be inlined.
7940 if (IsMdRequireSecObject(pCallee->GetAttrs()))
7942 result = INLINE_NEVER;
7943 szFailReason = "Inlinee requires a security object (or contains StackCrawlMark)";
7947 // If the method is MethodImpl'd by another method within the same type, then we have
7948 // an issue that the importer will import the wrong body. In this case, we'll just
7949 // disallow inlining because getFunctionEntryPoint will do the right thing.
7951 MethodDesc *pMDDecl = pCallee;
7952 MethodTable *pMT = pMDDecl->GetMethodTable();
7953 MethodDesc *pMDImpl = pMT->MapMethodDeclToMethodImpl(pMDDecl);
7955 if (pMDDecl != pMDImpl)
7957 result = INLINE_NEVER;
7958 szFailReason = "Inlinee is MethodImpl'd by another method within the same type";
7963 #ifdef PROFILING_SUPPORTED
7964 if (CORProfilerPresent())
7968 // Currently the rejit path is the only path which sets this.
7969 // If we get more reasons to set this then we may need to change
7970 // the failure reason message or disambiguate them.
7971 if (!m_allowInlining)
7973 result = INLINE_FAIL;
7974 szFailReason = "ReJIT request disabled inlining from caller";
7978 // If the profiler has set a mask preventing inlining, always return
7979 // false to the jit.
7980 if (CORProfilerDisableInlining())
7982 result = INLINE_FAIL;
7983 szFailReason = "Profiler disabled inlining globally";
7987 #if defined(FEATURE_REJIT) && !defined(DACCESS_COMPILE)
7988 if (CORProfilerEnableRejit())
7990 CodeVersionManager* pCodeVersionManager = pCallee->GetCodeVersionManager();
7991 CodeVersionManager::LockHolder codeVersioningLockHolder;
7992 ILCodeVersion ilVersion = pCodeVersionManager->GetActiveILCodeVersion(pCallee);
7993 if (ilVersion.GetRejitState() != ILCodeVersion::kStateActive || !ilVersion.HasDefaultIL())
7995 result = INLINE_FAIL;
7996 szFailReason = "ReJIT methods cannot be inlined.";
8000 #endif // defined(FEATURE_REJIT) && !defined(DACCESS_COMPILE)
8002 // If the profiler wishes to be notified of JIT events and the result from
8003 // the above tests will cause a function to be inlined, we need to tell the
8004 // profiler that this inlining is going to take place, and give them a
8005 // chance to prevent it.
8007 BEGIN_PROFILER_CALLBACK(CORProfilerTrackJITInfo());
8008 if (pCaller->IsILStub() || pCallee->IsILStub())
8015 HRESULT hr = (&g_profControlBlock)->JITInlining(
8016 (FunctionID)pCaller,
8017 (FunctionID)pCallee,
8020 if (SUCCEEDED(hr) && !fShouldInline)
8022 result = INLINE_FAIL;
8023 szFailReason = "Profiler disabled inlining locally";
8027 END_PROFILER_CALLBACK();
8030 #endif // PROFILING_SUPPORTED
8034 EE_TO_JIT_TRANSITION();
8036 if (dontInline(result))
8038 // If you hit this assert, it means you added a new way to prevent inlining
8039 // without documenting it for ETW!
8040 _ASSERTE(szFailReason != NULL);
8041 reportInliningDecision(hCaller, hCallee, result, szFailReason);
8047 void CEEInfo::beginInlining(CORINFO_METHOD_HANDLE inlinerHnd,
8048 CORINFO_METHOD_HANDLE inlineeHnd)
8053 void CEEInfo::reportInliningDecision (CORINFO_METHOD_HANDLE inlinerHnd,
8054 CORINFO_METHOD_HANDLE inlineeHnd,
8055 CorInfoInline inlineResult,
8056 const char * reason)
8058 STATIC_CONTRACT_THROWS;
8059 STATIC_CONTRACT_GC_TRIGGERS;
8061 JIT_TO_EE_TRANSITION();
8064 if (LoggingOn(LF_JIT, LL_INFO100000))
8066 SString currentMethodName;
8067 currentMethodName.AppendUTF8(m_pMethodBeingCompiled->GetModule()->GetPEAssembly()->GetSimpleName());
8068 currentMethodName.Append(L'/');
8069 TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled, TypeString::FormatBasic);
8071 SString inlineeMethodName;
8072 if (GetMethod(inlineeHnd))
8074 inlineeMethodName.AppendUTF8(GetMethod(inlineeHnd)->GetModule()->GetPEAssembly()->GetSimpleName());
8075 inlineeMethodName.Append(L'/');
8076 TypeString::AppendMethodInternal(inlineeMethodName, GetMethod(inlineeHnd), TypeString::FormatBasic);
8080 inlineeMethodName.AppendASCII( "<null>" );
8083 SString inlinerMethodName;
8084 if (GetMethod(inlinerHnd))
8086 inlinerMethodName.AppendUTF8(GetMethod(inlinerHnd)->GetModule()->GetPEAssembly()->GetSimpleName());
8087 inlinerMethodName.Append(L'/');
8088 TypeString::AppendMethodInternal(inlinerMethodName, GetMethod(inlinerHnd), TypeString::FormatBasic);
8092 inlinerMethodName.AppendASCII("<null>");
8095 if (dontInline(inlineResult))
8097 LOG((LF_JIT, LL_INFO100000,
8098 "While compiling '%s', inline of '%s' into '%s' failed because: '%s'.\n",
8099 currentMethodName.GetUTF8(), inlineeMethodName.GetUTF8(),
8100 inlinerMethodName.GetUTF8(), reason));
8102 else if(inlineResult == INLINE_PASS)
8104 LOG((LF_JIT, LL_INFO100000, "While compiling '%s', inline of '%s' into '%s' succeeded.\n",
8105 currentMethodName.GetUTF8(), inlineeMethodName.GetUTF8(),
8106 inlinerMethodName.GetUTF8()));
8112 //I'm gonna duplicate this code because the format is slightly different. And LoggingOn is debug only.
8113 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
8114 TRACE_LEVEL_VERBOSE,
8115 CLR_JITTRACING_KEYWORD) &&
8116 (inlineResult <= INLINE_PASS)) // Only report pass, and failure inliner information. The various informative reports such as INLINE_CHECK_CAN_INLINE_SUCCESS are not to be reported via ETW
8118 SString methodBeingCompiledNames[3];
8119 SString inlinerNames[3];
8120 SString inlineeNames[3];
8121 MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8122 #define GMI(pMD, strArray) \
8125 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8127 (strArray)[0].Set(W("<null>")); \
8128 (strArray)[1].Set(W("<null>")); \
8129 (strArray)[2].Set(W("<null>")); \
8132 GMI(methodBeingCompiled, methodBeingCompiledNames);
8133 GMI(GetMethod(inlinerHnd), inlinerNames);
8134 GMI(GetMethod(inlineeHnd), inlineeNames);
8136 if (dontInline(inlineResult))
8138 const char * str = (reason ? reason : "");
8140 strReason.SetUTF8(str);
8143 FireEtwMethodJitInliningFailed(methodBeingCompiledNames[0].GetUnicode(),
8144 methodBeingCompiledNames[1].GetUnicode(),
8145 methodBeingCompiledNames[2].GetUnicode(),
8146 inlinerNames[0].GetUnicode(),
8147 inlinerNames[1].GetUnicode(),
8148 inlinerNames[2].GetUnicode(),
8149 inlineeNames[0].GetUnicode(),
8150 inlineeNames[1].GetUnicode(),
8151 inlineeNames[2].GetUnicode(),
8152 inlineResult == INLINE_NEVER,
8153 strReason.GetUnicode(),
8154 GetClrInstanceId());
8156 else if(inlineResult == INLINE_PASS)
8158 FireEtwMethodJitInliningSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8159 methodBeingCompiledNames[1].GetUnicode(),
8160 methodBeingCompiledNames[2].GetUnicode(),
8161 inlinerNames[0].GetUnicode(),
8162 inlinerNames[1].GetUnicode(),
8163 inlinerNames[2].GetUnicode(),
8164 inlineeNames[0].GetUnicode(),
8165 inlineeNames[1].GetUnicode(),
8166 inlineeNames[2].GetUnicode(),
8167 GetClrInstanceId());
8173 #if defined FEATURE_REJIT && !defined(DACCESS_COMPILE)
8174 if(inlineResult == INLINE_PASS)
8176 // We don't want to track the chain of methods, so intentionally use m_pMethodBeingCompiled
8177 // to just track the methods that pCallee is eventually inlined in
8178 MethodDesc *pCallee = GetMethod(inlineeHnd);
8179 MethodDesc *pCaller = m_pMethodBeingCompiled;
8180 pCallee->GetModule()->AddInlining(pCaller, pCallee);
8182 if (CORProfilerEnableRejit())
8184 // If ReJIT is enabled, there is a chance that a race happened where the profiler
8185 // requested a ReJIT on a method, but before the ReJIT occurred an inlining happened.
8186 // If we end up reporting an inlining on a method with non-default IL it means the race
8187 // happened and we need to manually request ReJIT for it since it was missed.
8188 CodeVersionManager* pCodeVersionManager = pCallee->GetCodeVersionManager();
8189 CodeVersionManager::LockHolder codeVersioningLockHolder;
8190 ILCodeVersion ilVersion = pCodeVersionManager->GetActiveILCodeVersion(pCallee);
8191 if (ilVersion.GetRejitState() != ILCodeVersion::kStateActive || !ilVersion.HasDefaultIL())
8193 ModuleID modId = pCaller->GetModule()->GetModuleID();
8194 mdMethodDef methodDef = pCaller->GetMemberDef();
8195 ReJitManager::RequestReJIT(1, &modId, &methodDef, static_cast<COR_PRF_REJIT_FLAGS>(0));
8199 #endif // defined FEATURE_REJIT && !defined(DACCESS_COMPILE)
8201 EE_TO_JIT_TRANSITION();
8205 /*************************************************************
8206 * Similar to above, but perform check for tail call
8207 * eligibility. The callee can be passed as NULL if not known
8208 * (calli and callvirt).
8209 *************************************************************/
8211 bool CEEInfo::canTailCall (CORINFO_METHOD_HANDLE hCaller,
8212 CORINFO_METHOD_HANDLE hDeclaredCallee,
8213 CORINFO_METHOD_HANDLE hExactCallee,
8222 bool result = false;
8223 const char * szFailReason = NULL;
8225 JIT_TO_EE_TRANSITION();
8227 // See comments in canInline above.
8229 MethodDesc* pCaller = GetMethod(hCaller);
8230 MethodDesc* pDeclaredCallee = GetMethod(hDeclaredCallee);
8231 MethodDesc* pExactCallee = GetMethod(hExactCallee);
8233 _ASSERTE(pCaller->GetModule());
8234 _ASSERTE(pCaller->GetModule()->GetClassLoader());
8236 _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule());
8237 _ASSERTE((pExactCallee == NULL) || pExactCallee->GetModule()->GetClassLoader());
8241 mdMethodDef callerToken = pCaller->GetMemberDef();
8243 // We don't want to tailcall the entrypoint for an application; JIT64 will sometimes
8244 // do this for simple entrypoints and it results in a rather confusing debugging
8246 if (callerToken == pCaller->GetModule()->GetEntryPointToken())
8249 szFailReason = "Caller is the entry point";
8253 if (!pCaller->IsNoMetadata())
8255 // Do not tailcall from methods that are marked as noinline (people often use no-inline
8256 // to mean "I want to always see this method in stacktrace")
8257 DWORD dwImplFlags = 0;
8258 IfFailThrow(pCaller->GetMDImport()->GetMethodImplProps(callerToken, NULL, &dwImplFlags));
8260 if (IsMiNoInlining(dwImplFlags))
8263 szFailReason = "Caller is marked as no inline";
8268 // Methods with StackCrawlMark depend on finding their caller on the stack.
8269 // If we tail call one of these guys, they get confused. For lack of
8270 // a better way of identifying them, we use DynamicSecurity attribute to identify
8271 // them. We have an assert in canInline that ensures all StackCrawlMark
8272 // methods are appropriately marked.
8274 if ((pExactCallee != NULL) && IsMdRequireSecObject(pExactCallee->GetAttrs()))
8277 szFailReason = "Callee might have a StackCrawlMark.LookForMyCaller";
8287 EE_TO_JIT_TRANSITION();
8291 // If you hit this assert, it means you added a new way to prevent tail calls
8292 // without documenting it for ETW!
8293 _ASSERTE(szFailReason != NULL);
8294 reportTailCallDecision(hCaller, hExactCallee, fIsTailPrefix, TAILCALL_FAIL, szFailReason);
8300 void CEEInfo::reportTailCallDecision (CORINFO_METHOD_HANDLE callerHnd,
8301 CORINFO_METHOD_HANDLE calleeHnd,
8303 CorInfoTailCall tailCallResult,
8304 const char * reason)
8306 STATIC_CONTRACT_THROWS;
8307 STATIC_CONTRACT_GC_TRIGGERS;
8309 JIT_TO_EE_TRANSITION();
8311 //put code here. Make sure to report the method being compiled in addition to inliner and inlinee.
8313 if (LoggingOn(LF_JIT, LL_INFO100000))
8315 SString currentMethodName;
8316 TypeString::AppendMethodInternal(currentMethodName, m_pMethodBeingCompiled,
8317 TypeString::FormatBasic);
8319 SString calleeMethodName;
8320 if (GetMethod(calleeHnd))
8322 TypeString::AppendMethodInternal(calleeMethodName, GetMethod(calleeHnd),
8323 TypeString::FormatBasic);
8327 calleeMethodName.AppendASCII( "<null>" );
8330 SString callerMethodName;
8331 if (GetMethod(callerHnd))
8333 TypeString::AppendMethodInternal(callerMethodName, GetMethod(callerHnd),
8334 TypeString::FormatBasic);
8338 callerMethodName.AppendASCII( "<null>" );
8340 if (tailCallResult == TAILCALL_FAIL)
8342 LOG((LF_JIT, LL_INFO100000,
8343 "While compiling '%s', %splicit tail call from '%s' to '%s' failed because: '%s'.\n",
8344 currentMethodName.GetUTF8(), fIsTailPrefix ? "ex" : "im",
8345 callerMethodName.GetUTF8(), calleeMethodName.GetUTF8(), reason));
8349 static const char * const tailCallType[] = {
8350 "optimized tail call", "recursive loop", "helper assisted tailcall"
8352 _ASSERTE(tailCallResult >= 0 && (size_t)tailCallResult < ARRAY_SIZE(tailCallType));
8353 LOG((LF_JIT, LL_INFO100000,
8354 "While compiling '%s', %splicit tail call from '%s' to '%s' generated as a %s.\n",
8355 currentMethodName.GetUTF8(), fIsTailPrefix ? "ex" : "im",
8356 callerMethodName.GetUTF8(), calleeMethodName.GetUTF8(), tailCallType[tailCallResult]));
8362 // I'm gonna duplicate this code because the format is slightly different. And LoggingOn is debug only.
8363 if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context,
8364 TRACE_LEVEL_VERBOSE,
8365 CLR_JITTRACING_KEYWORD))
8367 SString methodBeingCompiledNames[3];
8368 SString callerNames[3];
8369 SString calleeNames[3];
8370 MethodDesc * methodBeingCompiled = m_pMethodBeingCompiled;
8371 #define GMI(pMD, strArray) \
8374 (pMD)->GetMethodInfo((strArray)[0], (strArray)[1], (strArray)[2]); \
8376 (strArray)[0].Set(W("<null>")); \
8377 (strArray)[1].Set(W("<null>")); \
8378 (strArray)[2].Set(W("<null>")); \
8381 GMI(methodBeingCompiled, methodBeingCompiledNames);
8382 GMI(GetMethod(callerHnd), callerNames);
8383 GMI(GetMethod(calleeHnd), calleeNames);
8385 if (tailCallResult == TAILCALL_FAIL)
8387 const char * str = (reason ? reason : "");
8389 strReason.SetUTF8(str);
8391 FireEtwMethodJitTailCallFailed(methodBeingCompiledNames[0].GetUnicode(),
8392 methodBeingCompiledNames[1].GetUnicode(),
8393 methodBeingCompiledNames[2].GetUnicode(),
8394 callerNames[0].GetUnicode(),
8395 callerNames[1].GetUnicode(),
8396 callerNames[2].GetUnicode(),
8397 calleeNames[0].GetUnicode(),
8398 calleeNames[1].GetUnicode(),
8399 calleeNames[2].GetUnicode(),
8401 strReason.GetUnicode(),
8402 GetClrInstanceId());
8406 FireEtwMethodJitTailCallSucceeded(methodBeingCompiledNames[0].GetUnicode(),
8407 methodBeingCompiledNames[1].GetUnicode(),
8408 methodBeingCompiledNames[2].GetUnicode(),
8409 callerNames[0].GetUnicode(),
8410 callerNames[1].GetUnicode(),
8411 callerNames[2].GetUnicode(),
8412 calleeNames[0].GetUnicode(),
8413 calleeNames[1].GetUnicode(),
8414 calleeNames[2].GetUnicode(),
8417 GetClrInstanceId());
8423 EE_TO_JIT_TRANSITION();
8426 static void getEHinfoHelper(
8427 CORINFO_METHOD_HANDLE ftnHnd,
8429 CORINFO_EH_CLAUSE* clause,
8430 COR_ILMETHOD_DECODER* pILHeader)
8432 STANDARD_VM_CONTRACT;
8434 _ASSERTE(CheckPointer(pILHeader->EH));
8435 _ASSERTE(EHnumber < pILHeader->EH->EHCount());
8437 COR_ILMETHOD_SECT_EH_CLAUSE_FAT ehClause;
8438 const COR_ILMETHOD_SECT_EH_CLAUSE_FAT* ehInfo;
8439 ehInfo = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)pILHeader->EH->EHClause(EHnumber, &ehClause);
8441 clause->Flags = (CORINFO_EH_CLAUSE_FLAGS)ehInfo->GetFlags();
8442 clause->TryOffset = ehInfo->GetTryOffset();
8443 clause->TryLength = ehInfo->GetTryLength();
8444 clause->HandlerOffset = ehInfo->GetHandlerOffset();
8445 clause->HandlerLength = ehInfo->GetHandlerLength();
8446 if ((clause->Flags & CORINFO_EH_CLAUSE_FILTER) == 0)
8447 clause->ClassToken = ehInfo->GetClassToken();
8449 clause->FilterOffset = ehInfo->GetFilterOffset();
8452 /*********************************************************************/
8453 // get individual exception handler
8454 void CEEInfo::getEHinfo(
8455 CORINFO_METHOD_HANDLE ftnHnd,
8457 CORINFO_EH_CLAUSE* clause)
8465 JIT_TO_EE_TRANSITION();
8467 MethodDesc * ftn = GetMethod(ftnHnd);
8469 if (IsDynamicMethodHandle(ftnHnd))
8471 GetMethod(ftnHnd)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
8475 COR_ILMETHOD_DECODER header(ftn->GetILHeader(TRUE), ftn->GetMDImport(), NULL);
8476 getEHinfoHelper(ftnHnd, EHnumber, clause, &header);
8479 EE_TO_JIT_TRANSITION();
8482 //---------------------------------------------------------------------------------------
8485 CEEInfo::getMethodSig(
8486 CORINFO_METHOD_HANDLE ftnHnd,
8487 CORINFO_SIG_INFO * sigRet,
8488 CORINFO_CLASS_HANDLE owner)
8496 JIT_TO_EE_TRANSITION();
8498 getMethodSigInternal(ftnHnd, sigRet, owner, SK_NOT_CALLSITE);
8500 EE_TO_JIT_TRANSITION();
8503 //---------------------------------------------------------------------------------------
8505 //@GENERICSVER: for a method desc in a typical instantiation of a generic class,
8506 // this will return the typical instantiation of the generic class,
8507 // but only provided type variables are never shared.
8508 // The JIT verifier relies on this behaviour to extract the typical class from an instantiated method's typical method handle.
8510 CORINFO_CLASS_HANDLE
8511 CEEInfo::getMethodClass(
8512 CORINFO_METHOD_HANDLE methodHnd)
8520 CORINFO_CLASS_HANDLE result = NULL;
8522 JIT_TO_EE_TRANSITION();
8524 MethodDesc* method = GetMethod(methodHnd);
8526 if (method->IsDynamicMethod())
8528 DynamicResolver::SecurityControlFlags securityControlFlags = DynamicResolver::Default;
8529 TypeHandle typeOwner;
8531 DynamicResolver* pResolver = method->AsDynamicMethodDesc()->GetResolver();
8532 pResolver->GetJitContext(&securityControlFlags, &typeOwner);
8534 if (!typeOwner.IsNull() && (method == pResolver->GetDynamicMethod()))
8536 result = CORINFO_CLASS_HANDLE(typeOwner.AsPtr());
8542 TypeHandle th = TypeHandle(method->GetMethodTable());
8544 result = CORINFO_CLASS_HANDLE(th.AsPtr());
8547 EE_TO_JIT_TRANSITION();
8552 /*********************************************************************/
8553 bool CEEInfo::isIntrinsicType(CORINFO_CLASS_HANDLE classHnd)
8561 bool result = false;
8562 JIT_TO_EE_TRANSITION_LEAF();
8564 TypeHandle VMClsHnd(classHnd);
8565 PTR_MethodTable methodTable = VMClsHnd.GetMethodTable();
8566 result = methodTable->IsIntrinsicType();
8568 EE_TO_JIT_TRANSITION_LEAF();
8572 /*********************************************************************/
8573 void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd,
8574 unsigned * pOffsetOfIndirection,
8575 unsigned * pOffsetAfterIndirection,
8584 JIT_TO_EE_TRANSITION_LEAF();
8586 MethodDesc* method = GetMethod(methodHnd);
8588 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8589 _ASSERTE(!method->HasMethodInstantiation());
8591 _ASSERTE(MethodTable::GetVtableOffset() < 256); // a rough sanity check
8593 // better be in the vtable
8594 _ASSERTE(method->GetSlot() < method->GetMethodTable()->GetNumVirtuals());
8596 *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * TARGET_POINTER_SIZE /* sizeof(MethodTable::VTableIndir_t) */;
8597 *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * TARGET_POINTER_SIZE /* sizeof(MethodTable::VTableIndir2_t) */;
8598 *isRelative = false;
8600 EE_TO_JIT_TRANSITION_LEAF();
8603 /*********************************************************************/
8604 bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info)
8612 // Initialize OUT fields
8613 info->devirtualizedMethod = NULL;
8614 info->requiresInstMethodTableArg = false;
8615 info->exactContext = NULL;
8616 memset(&info->resolvedTokenDevirtualizedMethod, 0, sizeof(info->resolvedTokenDevirtualizedMethod));
8617 memset(&info->resolvedTokenDevirtualizedUnboxedMethod, 0, sizeof(info->resolvedTokenDevirtualizedUnboxedMethod));
8619 MethodDesc* pBaseMD = GetMethod(info->virtualMethod);
8620 MethodTable* pBaseMT = pBaseMD->GetMethodTable();
8622 // Method better be from a fully loaded class
8623 _ASSERTE(pBaseMT->IsFullyLoaded());
8625 //@GENERICS: shouldn't be doing this for instantiated methods as they live elsewhere
8626 _ASSERTE(!pBaseMD->HasMethodInstantiation());
8628 // Method better be virtual
8629 _ASSERTE(pBaseMD->IsVirtual());
8631 MethodDesc* pDevirtMD = nullptr;
8633 TypeHandle ObjClassHnd(info->objClass);
8634 MethodTable* pObjMT = ObjClassHnd.GetMethodTable();
8635 _ASSERTE(pObjMT->IsRestored() && pObjMT->IsFullyLoaded());
8637 // Can't devirtualize from __Canon.
8638 if (ObjClassHnd == TypeHandle(g_pCanonMethodTableClass))
8640 info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON;
8644 if (pBaseMT->IsInterface())
8647 #ifdef FEATURE_COMINTEROP
8648 // Don't try and devirtualize com interface calls.
8649 if (pObjMT->IsComObjectType())
8651 info->detail = CORINFO_DEVIRTUALIZATION_FAILED_COM;
8654 #endif // FEATURE_COMINTEROP
8656 if (info->context != nullptr)
8658 pBaseMT = GetTypeFromContext(info->context).GetMethodTable();
8661 // Interface call devirtualization.
8663 // We must ensure that pObjMT actually implements the
8664 // interface corresponding to pBaseMD.
8665 if (!pObjMT->CanCastToInterface(pBaseMT))
8667 info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CAST;
8671 // For generic interface methods we must have context to
8672 // safely devirtualize.
8673 if (info->context != nullptr)
8675 // If the derived class is a shared class, make sure the
8676 // owner class is too.
8677 if (pObjMT->IsSharedByGenericInstantiations())
8679 MethodTable* pCanonBaseMT = pBaseMT->GetCanonicalMethodTable();
8681 // Check to see if the derived class implements multiple variants of a matching interface.
8682 // If so, we cannot predict exactly which implementation is in use here.
8683 MethodTable::InterfaceMapIterator it = pObjMT->IterateInterfaceMap();
8684 int canonicallyMatchingInterfacesFound = 0;
8687 if (it.GetInterface(pObjMT)->GetCanonicalMethodTable() == pCanonBaseMT)
8689 canonicallyMatchingInterfacesFound++;
8690 if (canonicallyMatchingInterfacesFound > 1)
8692 // Multiple canonically identical interfaces found when attempting to devirtualize an inexact interface dispatch
8693 info->detail = CORINFO_DEVIRTUALIZATION_MULTIPLE_IMPL;
8700 pDevirtMD = pObjMT->GetMethodDescForInterfaceMethod(TypeHandle(pBaseMT), pBaseMD, FALSE /* throwOnConflict */);
8702 else if (!pBaseMD->HasClassOrMethodInstantiation())
8704 pDevirtMD = pObjMT->GetMethodDescForInterfaceMethod(pBaseMD, FALSE /* throwOnConflict */);
8707 if (pDevirtMD == nullptr)
8709 info->detail = CORINFO_DEVIRTUALIZATION_FAILED_LOOKUP;
8713 // If we devirtualized into a default interface method on a generic type, we should actually return an
8714 // instantiating stub but this is not happening.
8715 // Making this work is tracked by https://github.com/dotnet/runtime/issues/9588
8716 if (pDevirtMD->GetMethodTable()->IsInterface() && pDevirtMD->HasClassInstantiation())
8718 info->detail = CORINFO_DEVIRTUALIZATION_FAILED_DIM;
8724 // Virtual call devirtualization.
8726 // The derived class should be a subclass of the base class.
8727 MethodTable* pCheckMT = pObjMT;
8729 while (pCheckMT != nullptr)
8731 if (pCheckMT->HasSameTypeDefAs(pBaseMT))
8736 pCheckMT = pCheckMT->GetParentMethodTable();
8739 if (pCheckMT == nullptr)
8741 info->detail = CORINFO_DEVIRTUALIZATION_FAILED_SUBCLASS;
8745 // The base method should be in the base vtable
8746 WORD slot = pBaseMD->GetSlot();
8747 _ASSERTE(slot < pBaseMT->GetNumVirtuals());
8749 // Fetch the method that would be invoked if the class were
8750 // exactly derived class. It is up to the jit to determine whether
8751 // directly calling this method is correct.
8752 pDevirtMD = pObjMT->GetMethodDescForSlot(slot);
8754 // If the derived method's slot does not match the vtable slot,
8755 // bail on devirtualization, as the method was installed into
8756 // the vtable slot via an explicit override and even if the
8757 // method is final, the slot may not be.
8759 // Note the jit could still safely devirtualize if it had an exact
8760 // class, but such cases are likely rare.
8761 WORD dslot = pDevirtMD->GetSlot();
8765 info->detail = CORINFO_DEVIRTUALIZATION_FAILED_SLOT;
8770 // Determine the exact class.
8772 // We may fail to get an exact context if the method is a default
8773 // interface method. If so, we'll use the method's class.
8775 MethodTable* pApproxMT = pDevirtMD->GetMethodTable();
8776 MethodTable* pExactMT = pApproxMT;
8778 if (pApproxMT->IsInterface())
8780 // As noted above, we can't yet handle generic interfaces
8781 // with default methods.
8782 _ASSERTE(!pDevirtMD->HasClassInstantiation());
8787 pExactMT = pDevirtMD->GetExactDeclaringType(pObjMT);
8790 // Success! Pass back the results.
8792 info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) pDevirtMD;
8793 info->exactContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT);
8794 info->requiresInstMethodTableArg = false;
8795 info->detail = CORINFO_DEVIRTUALIZATION_SUCCESS;
8800 bool CEEInfo::resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info)
8808 bool result = false;
8810 JIT_TO_EE_TRANSITION();
8812 result = resolveVirtualMethodHelper(info);
8814 EE_TO_JIT_TRANSITION();
8819 /*********************************************************************/
8820 CORINFO_METHOD_HANDLE CEEInfo::getUnboxedEntry(
8821 CORINFO_METHOD_HANDLE ftn,
8822 bool* requiresInstMethodTableArg)
8830 CORINFO_METHOD_HANDLE result = NULL;
8832 JIT_TO_EE_TRANSITION();
8834 MethodDesc* pMD = GetMethod(ftn);
8835 bool requiresInstMTArg = false;
8837 if (pMD->IsUnboxingStub())
8839 MethodTable* pMT = pMD->GetMethodTable();
8840 MethodDesc* pUnboxedMD = pMT->GetUnboxedEntryPointMD(pMD);
8842 result = (CORINFO_METHOD_HANDLE)pUnboxedMD;
8843 requiresInstMTArg = !!pUnboxedMD->RequiresInstMethodTableArg();
8846 *requiresInstMethodTableArg = requiresInstMTArg;
8848 EE_TO_JIT_TRANSITION();
8853 /*********************************************************************/
8854 void CEEInfo::expandRawHandleIntrinsic(
8855 CORINFO_RESOLVED_TOKEN * pResolvedToken,
8856 CORINFO_GENERICHANDLE_RESULT * pResult)
8858 LIMITED_METHOD_CONTRACT;
8859 UNREACHABLE(); // only called with NativeAOT.
8862 /*********************************************************************/
8863 CORINFO_CLASS_HANDLE CEEInfo::getDefaultComparerClass(CORINFO_CLASS_HANDLE elemType)
8871 CORINFO_CLASS_HANDLE result = NULL;
8873 JIT_TO_EE_TRANSITION();
8875 result = getDefaultComparerClassHelper(elemType);
8877 EE_TO_JIT_TRANSITION();
8882 CORINFO_CLASS_HANDLE CEEInfo::getDefaultComparerClassHelper(CORINFO_CLASS_HANDLE elemType)
8890 TypeHandle elemTypeHnd(elemType);
8892 // Mirrors the logic in BCL's CompareHelpers.CreateDefaultComparer
8893 // And in compile.cpp's SpecializeComparer
8895 // We need to find the appropriate instantiation
8896 Instantiation inst(&elemTypeHnd, 1);
8899 if (Nullable::IsNullableType(elemTypeHnd))
8901 Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
8902 TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__NULLABLE_COMPARER)).Instantiate(nullableInst);
8903 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8906 // We need to special case the Enum comparers based on their underlying type to avoid boxing
8907 if (elemTypeHnd.IsEnum())
8909 TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__ENUM_COMPARER)).Instantiate(inst);
8910 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8913 if (elemTypeHnd.IsCanonicalSubtype())
8918 // If T implements IComparable<T>
8919 if (elemTypeHnd.CanCastTo(TypeHandle(CoreLibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(inst)))
8921 TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__GENERIC_COMPARER)).Instantiate(inst);
8922 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8926 TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__OBJECT_COMPARER)).Instantiate(inst);
8928 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8931 /*********************************************************************/
8932 CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE elemType)
8940 CORINFO_CLASS_HANDLE result = NULL;
8942 JIT_TO_EE_TRANSITION();
8944 result = getDefaultEqualityComparerClassHelper(elemType);
8946 EE_TO_JIT_TRANSITION();
8951 CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLASS_HANDLE elemType)
8959 // Mirrors the logic in BCL's CompareHelpers.CreateDefaultEqualityComparer
8960 // And in compile.cpp's SpecializeEqualityComparer
8961 TypeHandle elemTypeHnd(elemType);
8963 // Mirrors the logic in BCL's CompareHelpers.CreateDefaultComparer
8964 // And in compile.cpp's SpecializeComparer
8966 // We need to find the appropriate instantiation
8967 Instantiation inst(&elemTypeHnd, 1);
8970 if (Nullable::IsNullableType(elemTypeHnd))
8972 Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation();
8973 TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__NULLABLE_EQUALITYCOMPARER)).Instantiate(nullableInst);
8974 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8979 // We need to special case the Enum comparers based on their underlying type,
8980 // to avoid boxing and call the correct versions of GetHashCode.
8981 if (elemTypeHnd.IsEnum())
8983 TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__ENUM_EQUALITYCOMPARER)).Instantiate(inst);
8984 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
8987 if (elemTypeHnd.IsCanonicalSubtype())
8992 // If T implements IEquatable<T>
8993 if (elemTypeHnd.CanCastTo(TypeHandle(CoreLibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(inst)))
8995 TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__GENERIC_EQUALITYCOMPARER)).Instantiate(inst);
8996 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
9000 TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__OBJECT_EQUALITYCOMPARER)).Instantiate(inst);
9002 return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable());
9005 /*********************************************************************/
9006 void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd,
9007 CORINFO_CONST_LOOKUP * pResult,
9008 CORINFO_ACCESS_FLAGS accessFlags)
9017 InfoAccessType accessType = IAT_VALUE;
9019 JIT_TO_EE_TRANSITION();
9021 MethodDesc * ftn = GetMethod(ftnHnd);
9022 #if defined(FEATURE_GDBJIT)
9023 MethodDesc * orig_ftn = ftn;
9026 // Resolve methodImpl.
9027 ftn = ftn->GetMethodTable()->MapMethodDeclToMethodImpl(ftn);
9029 if (!ftn->IsFCall() && ftn->IsVersionableWithPrecode() && (ftn->GetPrecodeType() == PRECODE_FIXUP) && !ftn->IsPointingToStableNativeCode())
9031 ret = ((FixupPrecode*)ftn->GetOrCreatePrecode())->GetTargetSlot();
9032 accessType = IAT_PVALUE;
9036 ret = (void *)ftn->TryGetMultiCallableAddrOfCode(accessFlags);
9038 // TryGetMultiCallableAddrOfCode returns NULL if indirect access is desired
9041 // should never get here for EnC methods or if interception via remoting stub is required
9042 _ASSERTE(!ftn->InEnCEnabledModule());
9044 ret = (void *)ftn->GetAddrOfSlot();
9046 accessType = IAT_PVALUE;
9050 #if defined(FEATURE_GDBJIT)
9051 CalledMethod * pCM = new CalledMethod(orig_ftn, ret, m_pCalledMethods);
9052 m_pCalledMethods = pCM;
9055 EE_TO_JIT_TRANSITION();
9057 _ASSERTE(ret != NULL);
9059 pResult->accessType = accessType;
9060 pResult->addr = ret;
9063 /*********************************************************************/
9064 void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn,
9065 bool isUnsafeFunctionPointer,
9066 CORINFO_CONST_LOOKUP * pResult)
9074 JIT_TO_EE_TRANSITION();
9076 MethodDesc * pMD = GetMethod(ftn);
9078 if (isUnsafeFunctionPointer)
9079 pMD->PrepareForUseAsAFunctionPointer();
9081 pResult->accessType = IAT_VALUE;
9082 pResult->addr = (void*)pMD->GetMultiCallableAddrOfCode();
9084 EE_TO_JIT_TRANSITION();
9087 /*********************************************************************/
9088 size_t CEEInfo::printFieldName(CORINFO_FIELD_HANDLE fieldHnd, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize)
9096 size_t bytesWritten = 0;
9097 JIT_TO_EE_TRANSITION();
9099 FieldDesc* field = (FieldDesc*) fieldHnd;
9100 const char* fieldName = field->GetName();
9102 size_t len = strlen(fieldName);
9105 bytesWritten = min(len, bufferSize - 1);
9106 memcpy(buffer, fieldName, len);
9107 buffer[bytesWritten] = '\0';
9110 if (pRequiredBufferSize != NULL)
9112 *pRequiredBufferSize = len + 1;
9115 EE_TO_JIT_TRANSITION();
9117 return bytesWritten;
9120 /*********************************************************************/
9121 // Get the type that declares the field
9122 CORINFO_CLASS_HANDLE CEEInfo::getFieldClass (CORINFO_FIELD_HANDLE fieldHnd)
9130 CORINFO_CLASS_HANDLE result = NULL;
9132 JIT_TO_EE_TRANSITION_LEAF();
9134 FieldDesc* field = (FieldDesc*) fieldHnd;
9135 result = CORINFO_CLASS_HANDLE(field->GetApproxEnclosingMethodTable());
9137 EE_TO_JIT_TRANSITION_LEAF();
9142 /*********************************************************************/
9143 // Returns the basic type of the field (not the type that declares the field)
9145 // pTypeHnd - Optional. If not null then on return, for reference and value types,
9146 // *pTypeHnd will contain the normalized type of the field.
9147 // owner - Optional. For resolving in a generic context
9149 CorInfoType CEEInfo::getFieldType (CORINFO_FIELD_HANDLE fieldHnd,
9150 CORINFO_CLASS_HANDLE* pTypeHnd,
9151 CORINFO_CLASS_HANDLE owner)
9159 CorInfoType result = CORINFO_TYPE_UNDEF;
9161 JIT_TO_EE_TRANSITION();
9163 result = getFieldTypeInternal(fieldHnd, pTypeHnd, owner);
9165 EE_TO_JIT_TRANSITION();
9170 /*********************************************************************/
9171 CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd,
9172 CORINFO_CLASS_HANDLE* pTypeHnd,
9173 CORINFO_CLASS_HANDLE owner)
9175 STANDARD_VM_CONTRACT;
9177 if (pTypeHnd != nullptr)
9182 TypeHandle clsHnd = TypeHandle();
9183 FieldDesc* field = (FieldDesc*) fieldHnd;
9184 CorElementType type = field->GetFieldType();
9185 if (!CorTypeInfo::IsPrimitiveType(type))
9187 PCCOR_SIGNATURE sig;
9189 CorCallingConvention conv;
9191 field->GetSig(&sig, &sigCount);
9193 conv = (CorCallingConvention)CorSigUncompressCallingConv(sig);
9194 _ASSERTE(isCallConv(conv, IMAGE_CEE_CS_CALLCONV_FIELD));
9196 SigPointer ptr(sig, sigCount);
9198 // For verifying code involving generics, use the class instantiation
9199 // of the optional owner (to provide exact, not representative,
9200 // type information)
9201 SigTypeContext typeContext(field, (TypeHandle)owner);
9203 clsHnd = ptr.GetTypeHandleThrowing(field->GetModule(), &typeContext);
9204 _ASSERTE(!clsHnd.IsNull());
9206 // I believe it doesn't make any diff. if this is GetInternalCorElementType
9207 // or GetSignatureCorElementType.
9208 type = clsHnd.GetSignatureCorElementType();
9211 return CEEInfo::asCorInfoType(type, clsHnd, pTypeHnd);
9214 /*********************************************************************/
9215 unsigned CEEInfo::getFieldOffset (CORINFO_FIELD_HANDLE fieldHnd)
9223 unsigned result = (unsigned) -1;
9225 JIT_TO_EE_TRANSITION();
9227 FieldDesc* field = (FieldDesc*) fieldHnd;
9229 // GetOffset() does not include the size of Object
9230 result = field->GetOffset();
9232 // So if it is not a value class, add the Object into it
9233 if (field->IsStatic())
9235 Module* pModule = field->GetModule();
9236 if (field->IsRVA() && pModule->IsRvaFieldTls(field->GetOffset()))
9238 result = pModule->GetFieldTlsOffset(field->GetOffset());
9241 else if (!field->GetApproxEnclosingMethodTable()->IsValueType())
9243 result += OBJECT_SIZE;
9246 EE_TO_JIT_TRANSITION();
9251 /*********************************************************************/
9252 uint32_t CEEInfo::getFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE fieldHnd, void **ppIndirection)
9260 uint32_t result = 0;
9262 if (ppIndirection != NULL)
9263 *ppIndirection = NULL;
9265 JIT_TO_EE_TRANSITION();
9267 FieldDesc* field = (FieldDesc*) fieldHnd;
9268 Module* module = field->GetModule();
9270 _ASSERTE(field->IsRVA()); // Only RVA statics can be thread local
9271 _ASSERTE(module->IsRvaFieldTls(field->GetOffset()));
9273 result = module->GetTlsIndex();
9275 EE_TO_JIT_TRANSITION();
9280 void *CEEInfo::allocateArray(size_t cBytes)
9288 void * result = NULL;
9290 JIT_TO_EE_TRANSITION();
9292 result = new BYTE [cBytes];
9294 EE_TO_JIT_TRANSITION();
9299 void CEEInfo::freeArrayInternal(void* array)
9307 delete [] ((BYTE*) array);
9310 void CEEInfo::freeArray(void *array)
9318 JIT_TO_EE_TRANSITION();
9320 freeArrayInternal(array);
9322 EE_TO_JIT_TRANSITION();
9325 void CEEInfo::getBoundaries(CORINFO_METHOD_HANDLE ftn,
9326 unsigned int *cILOffsets, uint32_t **pILOffsets,
9327 ICorDebugInfo::BoundaryTypes *implicitBoundaries)
9335 JIT_TO_EE_TRANSITION();
9337 #ifdef DEBUGGING_SUPPORTED
9338 if (g_pDebugInterface)
9340 g_pDebugInterface->getBoundaries(GetMethod(ftn), cILOffsets, (DWORD**)pILOffsets,
9341 implicitBoundaries);
9347 *implicitBoundaries = ICorDebugInfo::DEFAULT_BOUNDARIES;
9349 #endif // DEBUGGING_SUPPORTED
9351 EE_TO_JIT_TRANSITION();
9354 void CEEInfo::getVars(CORINFO_METHOD_HANDLE ftn, ULONG32 *cVars, ICorDebugInfo::ILVarInfo **vars,
9363 JIT_TO_EE_TRANSITION();
9365 #ifdef DEBUGGING_SUPPORTED
9366 if (g_pDebugInterface)
9368 g_pDebugInterface->getVars(GetMethod(ftn), cVars, vars, extendOthers);
9375 // Just tell the JIT to extend everything.
9376 *extendOthers = true;
9378 #endif // DEBUGGING_SUPPORTED
9380 EE_TO_JIT_TRANSITION();
9383 /*********************************************************************/
9384 CORINFO_ARG_LIST_HANDLE CEEInfo::getArgNext(CORINFO_ARG_LIST_HANDLE args)
9392 CORINFO_ARG_LIST_HANDLE result = NULL;
9394 JIT_TO_EE_TRANSITION();
9396 SigPointer ptr((unsigned __int8*) args);
9397 IfFailThrow(ptr.SkipExactlyOne());
9399 result = (CORINFO_ARG_LIST_HANDLE) ptr.GetPtr();
9401 EE_TO_JIT_TRANSITION();
9407 /*********************************************************************/
9409 CorInfoTypeWithMod CEEInfo::getArgType (
9410 CORINFO_SIG_INFO* sig,
9411 CORINFO_ARG_LIST_HANDLE args,
9412 CORINFO_CLASS_HANDLE* vcTypeRet
9421 CorInfoTypeWithMod result = CorInfoTypeWithMod(CORINFO_TYPE_UNDEF);
9423 JIT_TO_EE_TRANSITION();
9425 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args && (BYTE*) args < (BYTE*) sig->pSig + sig->cbSig);
9426 _ASSERTE((BYTE*) sig->args <= (BYTE*) args);
9427 INDEBUG(*vcTypeRet = CORINFO_CLASS_HANDLE((size_t)INVALID_POINTER_CC));
9429 SigPointer ptr((unsigned __int8*) args);
9430 CorElementType eType;
9431 IfFailThrow(ptr.PeekElemType(&eType));
9432 while (eType == ELEMENT_TYPE_PINNED)
9434 result = CORINFO_TYPE_MOD_PINNED;
9435 IfFailThrow(ptr.GetElemType(NULL));
9436 IfFailThrow(ptr.PeekElemType(&eType));
9439 // Now read off the "real" element type after taking any instantiations into consideration
9440 SigTypeContext typeContext;
9441 GetTypeContext(&sig->sigInst,&typeContext);
9443 Module* pModule = GetModule(sig->scope);
9445 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9447 TypeHandle typeHnd = TypeHandle();
9449 case ELEMENT_TYPE_VAR :
9450 case ELEMENT_TYPE_MVAR :
9451 case ELEMENT_TYPE_VALUETYPE :
9452 case ELEMENT_TYPE_TYPEDBYREF :
9453 case ELEMENT_TYPE_INTERNAL :
9455 typeHnd = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9456 _ASSERTE(!typeHnd.IsNull());
9458 CorElementType normType = typeHnd.GetInternalCorElementType();
9460 // if we are looking up a value class, don't morph it to a refernece type
9461 // (This can only happen in illegal IL)
9462 if (!CorTypeInfo::IsObjRef(normType) || type != ELEMENT_TYPE_VALUETYPE)
9469 case ELEMENT_TYPE_PTR:
9470 // Load the type eagerly under debugger to make the eval work
9471 if (CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
9473 // NOTE: in some IJW cases, when the type pointed at is unmanaged,
9474 // the GetTypeHandle may fail, because there is no TypeDef for such type.
9475 // Usage of GetTypeHandleThrowing would lead to class load exception
9476 TypeHandle thPtr = ptr.GetTypeHandleNT(pModule, &typeContext);
9479 classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(thPtr.AsPtr()));
9484 case ELEMENT_TYPE_VOID:
9485 // void is not valid in local sigs
9486 if (sig->flags & CORINFO_SIGFLAG_IS_LOCAL_SIG)
9487 COMPlusThrowHR(COR_E_INVALIDPROGRAM);
9490 case ELEMENT_TYPE_END:
9491 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9498 result = CorInfoTypeWithMod(result | CEEInfo::asCorInfoType(type, typeHnd, vcTypeRet));
9499 EE_TO_JIT_TRANSITION();
9504 // Now the implementation is only focused on the float fields info,
9505 // while a struct-arg has no more than two fields and total size is no larger than two-pointer-size.
9506 // These depends on the platform's ABI rules.
9508 // The returned value's encoding details how a struct argument uses float registers:
9509 // see the enum `StructFloatFieldInfoFlags`.
9510 uint32_t CEEInfo::getLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls)
9518 JIT_TO_EE_TRANSITION_LEAF();
9520 uint32_t size = STRUCT_NO_FLOAT_FIELD;
9522 #if defined(TARGET_LOONGARCH64)
9523 size = (uint32_t)MethodTable::GetLoongArch64PassStructInRegisterFlags(TypeHandle(cls));
9526 EE_TO_JIT_TRANSITION_LEAF();
9531 uint32_t CEEInfo::getRISCV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE cls)
9539 JIT_TO_EE_TRANSITION_LEAF();
9541 uint32_t size = STRUCT_NO_FLOAT_FIELD;
9543 #if defined(TARGET_RISCV64)
9544 size = (uint32_t)MethodTable::GetRiscV64PassStructInRegisterFlags(TypeHandle(cls));
9545 #endif // TARGET_RISCV64
9547 EE_TO_JIT_TRANSITION_LEAF();
9552 /*********************************************************************/
9554 int CEEInfo::getExactClasses (
9555 CORINFO_CLASS_HANDLE baseType,
9556 int maxExactClasses,
9557 CORINFO_CLASS_HANDLE* exactClsRet
9566 int exactClassesCount = 0;
9568 JIT_TO_EE_TRANSITION();
9570 // This function is currently implemented only on NativeAOT
9571 // but can be implemented for CoreCLR as well (e.g. for internal types)
9573 EE_TO_JIT_TRANSITION();
9575 return exactClassesCount;
9578 /*********************************************************************/
9580 CORINFO_CLASS_HANDLE CEEInfo::getArgClass (
9581 CORINFO_SIG_INFO* sig,
9582 CORINFO_ARG_LIST_HANDLE args
9591 CORINFO_CLASS_HANDLE result = NULL;
9593 JIT_TO_EE_TRANSITION();
9595 // make certain we dont have a completely wacked out sig pointer
9596 _ASSERTE((BYTE*) sig->pSig <= (BYTE*) sig->args);
9597 _ASSERTE((BYTE*) sig->args <= (BYTE*) args && (BYTE*) args < &((BYTE*) sig->args)[0x10000*5]);
9599 Module* pModule = GetModule(sig->scope);
9601 SigPointer ptr((unsigned __int8*) args);
9603 CorElementType eType;
9604 IfFailThrow(ptr.PeekElemType(&eType));
9606 while (eType == ELEMENT_TYPE_PINNED)
9608 IfFailThrow(ptr.GetElemType(NULL));
9609 IfFailThrow(ptr.PeekElemType(&eType));
9611 // Now read off the "real" element type after taking any instantiations into consideration
9612 SigTypeContext typeContext;
9613 GetTypeContext(&sig->sigInst, &typeContext);
9614 CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext);
9616 if (!CorTypeInfo::IsPrimitiveType(type)) {
9617 TypeHandle th = ptr.GetTypeHandleThrowing(pModule, &typeContext);
9618 result = CORINFO_CLASS_HANDLE(th.AsPtr());
9621 EE_TO_JIT_TRANSITION();
9626 /*********************************************************************/
9628 CorInfoHFAElemType CEEInfo::getHFAType(CORINFO_CLASS_HANDLE hClass)
9636 CorInfoHFAElemType result = CORINFO_HFA_ELEM_NONE;
9638 JIT_TO_EE_TRANSITION();
9640 TypeHandle VMClsHnd(hClass);
9642 result = VMClsHnd.GetHFAType();
9644 EE_TO_JIT_TRANSITION();
9651 CorInfoCallConvExtension getUnmanagedCallConvForSig(CORINFO_MODULE_HANDLE mod, PCCOR_SIGNATURE pSig, DWORD cbSig, bool* pSuppressGCTransition)
9653 STANDARD_VM_CONTRACT;
9655 SigParser parser(pSig, cbSig);
9656 uint32_t rawCallConv;
9657 if (FAILED(parser.GetCallingConv(&rawCallConv)))
9659 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9661 switch ((CorCallingConvention)rawCallConv)
9663 case IMAGE_CEE_CS_CALLCONV_DEFAULT:
9664 _ASSERTE_MSG(false, "bad callconv");
9665 return CorInfoCallConvExtension::Managed;
9666 case IMAGE_CEE_CS_CALLCONV_C:
9667 return CorInfoCallConvExtension::C;
9668 case IMAGE_CEE_CS_CALLCONV_STDCALL:
9669 return CorInfoCallConvExtension::Stdcall;
9670 case IMAGE_CEE_CS_CALLCONV_THISCALL:
9671 return CorInfoCallConvExtension::Thiscall;
9672 case IMAGE_CEE_CS_CALLCONV_FASTCALL:
9673 return CorInfoCallConvExtension::Fastcall;
9674 case IMAGE_CEE_CS_CALLCONV_UNMANAGED:
9676 CallConvBuilder builder;
9678 HRESULT hr = CallConv::TryGetUnmanagedCallingConventionFromModOpt(mod, pSig, cbSig, &builder, &errorResID);
9681 COMPlusThrowHR(hr, errorResID);
9683 CorInfoCallConvExtension callConvLocal = builder.GetCurrentCallConv();
9684 if (callConvLocal == CallConvBuilder::UnsetValue)
9686 callConvLocal = CallConv::GetDefaultUnmanagedCallingConvention();
9689 *pSuppressGCTransition = builder.IsCurrentCallConvModSet(CallConvBuilder::CALL_CONV_MOD_SUPPRESSGCTRANSITION);
9690 return callConvLocal;
9692 case IMAGE_CEE_CS_CALLCONV_NATIVEVARARG:
9693 return CorInfoCallConvExtension::C;
9695 _ASSERTE_MSG(false, "bad callconv");
9696 return CorInfoCallConvExtension::Managed;
9700 CorInfoCallConvExtension getUnmanagedCallConvForMethod(MethodDesc* pMD, bool* pSuppressGCTransition)
9702 STANDARD_VM_CONTRACT;
9704 uint32_t methodCallConv;
9705 PCCOR_SIGNATURE pSig;
9707 pMD->GetSig(&pSig, &cbSig);
9708 if (FAILED(SigParser(pSig, cbSig).GetCallingConv(&methodCallConv)))
9710 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
9713 if (methodCallConv == CORINFO_CALLCONV_DEFAULT || methodCallConv == CORINFO_CALLCONV_VARARG)
9715 _ASSERTE(pMD->IsNDirect() || pMD->HasUnmanagedCallersOnlyAttribute());
9716 if (pMD->IsNDirect())
9718 CorInfoCallConvExtension unmanagedCallConv;
9719 NDirect::GetCallingConvention_IgnoreErrors(pMD, &unmanagedCallConv, pSuppressGCTransition);
9720 return unmanagedCallConv;
9724 CorInfoCallConvExtension unmanagedCallConv;
9725 if (CallConv::TryGetCallingConventionFromUnmanagedCallersOnly(pMD, &unmanagedCallConv))
9727 if (methodCallConv == IMAGE_CEE_CS_CALLCONV_VARARG)
9729 return CorInfoCallConvExtension::C;
9731 return unmanagedCallConv;
9733 return CallConv::GetDefaultUnmanagedCallingConvention();
9738 return getUnmanagedCallConvForSig(GetScopeHandle(pMD->GetModule()), pSig, cbSig, pSuppressGCTransition);
9743 /*********************************************************************/
9745 // return the entry point calling convention for any of the following
9747 // - a method marked with UnmanagedCallersOnly
9748 // - a function pointer with the CORINFO_CALLCONV_UNMANAGED calling convention.
9749 CorInfoCallConvExtension CEEInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition)
9757 CorInfoCallConvExtension callConv = CorInfoCallConvExtension::Managed;
9759 JIT_TO_EE_TRANSITION();
9761 if (pSuppressGCTransition)
9763 *pSuppressGCTransition = false;
9768 callConv = getUnmanagedCallConvForMethod(GetMethod(method), pSuppressGCTransition);
9772 _ASSERTE(callSiteSig != nullptr);
9773 callConv = getUnmanagedCallConvForSig(callSiteSig->scope, callSiteSig->pSig, callSiteSig->cbSig, pSuppressGCTransition);
9776 EE_TO_JIT_TRANSITION();
9781 /*********************************************************************/
9782 bool CEEInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig)
9790 bool result = false;
9792 JIT_TO_EE_TRANSITION();
9796 // check the call site signature
9797 result = NDirect::MarshalingRequired(
9800 GetModule(callSiteSig->scope));
9804 MethodDesc* ftn = GetMethod(method);
9805 _ASSERTE(ftn->IsNDirect());
9806 NDirectMethodDesc *pMD = (NDirectMethodDesc*)ftn;
9808 #if defined(HAS_NDIRECT_IMPORT_PRECODE)
9809 if (pMD->IsVarArg())
9811 // Varag P/Invoke must not be inlined because its NDirectMethodDesc
9812 // does not contain a meaningful stack size (it is call site specific).
9813 // See code:InlinedCallFrame.UpdateRegDisplay where this is needed.
9816 else if (pMD->MarshalingRequired())
9818 // This is not a no-marshal signature.
9823 // This is a no-marshal non-vararg signature.
9827 // Marshalling is required to lazy initialize the indirection cell
9828 // without NDirectImportPrecode.
9833 PrepareCodeConfig *config = GetThread()->GetCurrentPrepareCodeConfig();
9834 if (config != nullptr && config->IsForMulticoreJit())
9836 bool suppressGCTransition = false;
9837 CorInfoCallConvExtension unmanagedCallConv = getUnmanagedCallConv(method, callSiteSig, &suppressGCTransition);
9839 if (suppressGCTransition)
9841 // MultiCoreJit thread can't inline PInvoke with SuppressGCTransitionAttribute,
9842 // because it can't be resolved in mcj thread
9847 EE_TO_JIT_TRANSITION();
9852 /*********************************************************************/
9853 // Generate a cookie based on the signature that would needs to be passed
9854 // to CORINFO_HELP_PINVOKE_CALLI
9855 LPVOID CEEInfo::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig,
9856 void **ppIndirection)
9858 WRAPPER_NO_CONTRACT;
9860 return getVarArgsHandle(szMetaSig, ppIndirection);
9863 bool CEEInfo::canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig)
9865 LIMITED_METHOD_CONTRACT;
9870 // Check any constraints on method type arguments
9871 bool CEEInfo::satisfiesMethodConstraints(
9872 CORINFO_CLASS_HANDLE parent,
9873 CORINFO_METHOD_HANDLE method)
9881 bool result = false;
9883 JIT_TO_EE_TRANSITION();
9885 _ASSERTE(parent != NULL);
9886 _ASSERTE(method != NULL);
9887 result = !!GetMethod(method)->SatisfiesMethodConstraints(TypeHandle(parent));
9889 EE_TO_JIT_TRANSITION();
9895 /*********************************************************************/
9896 // return address of fixup area for late-bound N/Direct calls.
9897 void CEEInfo::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method,
9898 CORINFO_CONST_LOOKUP *pLookup)
9906 JIT_TO_EE_TRANSITION();
9908 MethodDesc* pMD = GetMethod(method);
9909 _ASSERTE(pMD->IsNDirect());
9911 NDirectMethodDesc* pNMD = reinterpret_cast<NDirectMethodDesc*>(pMD);
9914 if (NDirectMethodDesc::TryGetResolvedNDirectTarget(pNMD, &pIndirection))
9916 pLookup->accessType = IAT_VALUE;
9917 pLookup->addr = pIndirection;
9921 pLookup->accessType = IAT_PVALUE;
9922 pLookup->addr = (LPVOID)&(pNMD->GetWriteableData()->m_pNDirectTarget);
9925 EE_TO_JIT_TRANSITION();
9928 /*********************************************************************/
9929 CORINFO_JUST_MY_CODE_HANDLE CEEInfo::getJustMyCodeHandle(
9930 CORINFO_METHOD_HANDLE method,
9931 CORINFO_JUST_MY_CODE_HANDLE**ppIndirection)
9939 CORINFO_JUST_MY_CODE_HANDLE result = NULL;
9942 *ppIndirection = NULL;
9944 JIT_TO_EE_TRANSITION_LEAF();
9946 // Get the flag from the debugger.
9947 MethodDesc* ftn = GetMethod(method);
9948 DWORD * pFlagAddr = NULL;
9950 if (g_pDebugInterface)
9952 pFlagAddr = g_pDebugInterface->GetJMCFlagAddr(ftn->GetModule());
9955 result = (CORINFO_JUST_MY_CODE_HANDLE) pFlagAddr;
9957 EE_TO_JIT_TRANSITION_LEAF();
9962 /*********************************************************************/
9963 void InlinedCallFrame::GetEEInfo(CORINFO_EE_INFO::InlinedCallFrameInfo *pInfo)
9965 LIMITED_METHOD_CONTRACT;
9967 pInfo->size = sizeof(GSCookie) + sizeof(InlinedCallFrame);
9969 pInfo->offsetOfGSCookie = 0;
9970 pInfo->offsetOfFrameVptr = sizeof(GSCookie);
9971 pInfo->offsetOfFrameLink = sizeof(GSCookie) + Frame::GetOffsetOfNextLink();
9972 pInfo->offsetOfCallSiteSP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallSiteSP);
9973 pInfo->offsetOfCalleeSavedFP = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCalleeSavedFP);
9974 pInfo->offsetOfCallTarget = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_Datum);
9975 pInfo->offsetOfReturnAddress = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pCallerReturnAddress);
9977 pInfo->offsetOfSPAfterProlog = sizeof(GSCookie) + offsetof(InlinedCallFrame, m_pSPAfterProlog);
9978 #endif // TARGET_ARM
9981 CORINFO_OS getClrVmOs()
9984 return CORINFO_MACOS;
9985 #elif defined(TARGET_UNIX)
9986 return CORINFO_UNIX;
9988 return CORINFO_WINNT;
9992 /*********************************************************************/
9993 // Return details about EE internal data structures
9994 void CEEInfo::getEEInfo(CORINFO_EE_INFO *pEEInfoOut)
10002 INDEBUG(memset(pEEInfoOut, 0xCC, sizeof(*pEEInfoOut)));
10004 JIT_TO_EE_TRANSITION();
10006 InlinedCallFrame::GetEEInfo(&pEEInfoOut->inlinedCallFrameInfo);
10008 // Offsets into the Thread structure
10009 pEEInfoOut->offsetOfThreadFrame = Thread::GetOffsetOfCurrentFrame();
10010 pEEInfoOut->offsetOfGCState = Thread::GetOffsetOfGCFlag();
10012 #ifndef CROSSBITNESS_COMPILE
10013 // The assertions must hold in every non-crossbitness scenario
10014 _ASSERTE(OFFSETOF__DelegateObject__target == DelegateObject::GetOffsetOfTarget());
10015 _ASSERTE(OFFSETOF__DelegateObject__methodPtr == DelegateObject::GetOffsetOfMethodPtr());
10016 _ASSERTE(OFFSETOF__DelegateObject__methodPtrAux == DelegateObject::GetOffsetOfMethodPtrAux());
10017 _ASSERTE(OFFSETOF__PtrArray__m_Array_ == PtrArray::GetDataOffset());
10020 // Delegate offsets
10021 pEEInfoOut->offsetOfDelegateInstance = OFFSETOF__DelegateObject__target;
10022 pEEInfoOut->offsetOfDelegateFirstTarget = OFFSETOF__DelegateObject__methodPtr;
10024 // Wrapper delegate offsets
10025 pEEInfoOut->offsetOfWrapperDelegateIndirectCell = OFFSETOF__DelegateObject__methodPtrAux;
10027 pEEInfoOut->sizeOfReversePInvokeFrame = TARGET_POINTER_SIZE * READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits;
10029 // The following assert doesn't work in cross-bitness scenarios since the pointer size differs.
10030 #if (defined(TARGET_64BIT) && defined(HOST_64BIT)) || (defined(TARGET_32BIT) && defined(HOST_32BIT))
10031 _ASSERTE(sizeof(ReversePInvokeFrame) <= pEEInfoOut->sizeOfReversePInvokeFrame);
10034 pEEInfoOut->osPageSize = GetOsPageSize();
10035 pEEInfoOut->maxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
10036 pEEInfoOut->targetAbi = CORINFO_CORECLR_ABI;
10037 pEEInfoOut->osType = getClrVmOs();
10039 EE_TO_JIT_TRANSITION();
10042 const char16_t * CEEInfo::getJitTimeLogFilename()
10050 LPCWSTR result = NULL;
10052 JIT_TO_EE_TRANSITION();
10053 result = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitTimeLogFile);
10054 EE_TO_JIT_TRANSITION();
10056 return (const char16_t *)result;
10061 // Return details about EE internal data structures
10062 uint32_t CEEInfo::getThreadTLSIndex(void **ppIndirection)
10070 uint32_t result = (uint32_t)-1;
10072 if (ppIndirection != NULL)
10073 *ppIndirection = NULL;
10079 int32_t * CEEInfo::getAddrOfCaptureThreadGlobal(void **ppIndirection)
10087 int32_t * result = NULL;
10089 if (ppIndirection != NULL)
10090 *ppIndirection = NULL;
10092 JIT_TO_EE_TRANSITION_LEAF();
10094 result = (int32_t *)&g_TrapReturningThreads;
10096 EE_TO_JIT_TRANSITION_LEAF();
10102 // This method is called from CEEInfo::FilterException which
10103 // is run as part of the SEH filter clause for the JIT.
10104 // It is fatal to throw an exception while running a SEH filter clause
10105 // so our contract is NOTHROW, NOTRIGGER.
10107 LONG EEFilterException(struct _EXCEPTION_POINTERS *pExceptionPointers, void *unused)
10116 JIT_TO_EE_TRANSITION_LEAF();
10118 unsigned code = pExceptionPointers->ExceptionRecord->ExceptionCode;
10121 if (code == EXCEPTION_ACCESS_VIOLATION)
10123 static int hit = 0;
10126 _ASSERTE(!"Access violation while Jitting!");
10127 // If you set the debugger to catch access violations and 'go'
10128 // you will get back to the point at which the access violation occurred
10129 result = EXCEPTION_CONTINUE_EXECUTION;
10133 result = EXCEPTION_CONTINUE_SEARCH;
10138 // No one should be catching breakpoint
10139 // Similarly the JIT doesn't know how to reset the guard page, so it shouldn't
10140 // be catching a hard stack overflow
10141 if (code == EXCEPTION_BREAKPOINT || code == EXCEPTION_SINGLE_STEP || code == EXCEPTION_STACK_OVERFLOW)
10143 result = EXCEPTION_CONTINUE_SEARCH;
10145 else if (!IsComPlusException(pExceptionPointers->ExceptionRecord))
10147 result = EXCEPTION_EXECUTE_HANDLER;
10153 // This is actually the LastThrown exception object.
10154 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10156 if (throwable != NULL)
10160 OBJECTREF oLastThrownObject;
10163 ZeroMemory(&_gc, sizeof(_gc));
10165 // Setup the throwables
10166 _gc.oLastThrownObject = throwable;
10168 GCPROTECT_BEGIN(_gc);
10170 // Don't catch ThreadAbort and other uncatchable exceptions
10171 if (IsUncatchable(&_gc.oLastThrownObject))
10172 result = EXCEPTION_CONTINUE_SEARCH;
10174 result = EXCEPTION_EXECUTE_HANDLER;
10180 EE_TO_JIT_TRANSITION_LEAF();
10185 // This code is called if FilterException chose to handle the exception.
10186 void CEEInfo::HandleException(struct _EXCEPTION_POINTERS *pExceptionPointers)
10193 JIT_TO_EE_TRANSITION_LEAF();
10195 if (IsComPlusException(pExceptionPointers->ExceptionRecord))
10199 // This is actually the LastThrown exception object.
10200 OBJECTREF throwable = CLRException::GetThrowableFromExceptionRecord(pExceptionPointers->ExceptionRecord);
10202 if (throwable != NULL)
10206 OBJECTREF oLastThrownObject;
10207 OBJECTREF oCurrentThrowable;
10210 ZeroMemory(&_gc, sizeof(_gc));
10212 PTR_Thread pCurThread = GetThread();
10214 // Setup the throwables
10215 _gc.oLastThrownObject = throwable;
10217 // This will be NULL if no managed exception is active. Otherwise,
10218 // it will reference the active throwable.
10219 _gc.oCurrentThrowable = pCurThread->GetThrowable();
10221 GCPROTECT_BEGIN(_gc);
10223 // JIT does not use or reference managed exceptions at all and simply swallows them,
10224 // or lets them fly through so that they will either get caught in managed code, the VM
10225 // or will go unhandled.
10227 // Blind swallowing of managed exceptions can break the semantic of "which exception handler"
10228 // gets to process the managed exception first. The expected handler is managed code exception
10229 // handler (e.g. COMPlusFrameHandler on x86 and ProcessCLRException on 64bit) which will setup
10230 // the exception tracker for the exception that will enable the expected sync between the
10231 // LastThrownObject (LTO), setup in RaiseTheExceptionInternalOnly, and the exception tracker.
10233 // However, JIT can break this by swallowing the managed exception before managed code exception
10234 // handler gets a chance to setup an exception tracker for it. Since there is no cleanup
10235 // done for the swallowed exception as part of the unwind (because no exception tracker may have been setup),
10236 // we need to reset the LTO, if it is out of sync from the active throwable.
10238 // Hence, check if the LastThrownObject and active-exception throwable are in sync or not.
10239 // If not, bring them in sync.
10243 // It is possible that an exception was already in progress and while processing it (e.g.
10244 // invoking finally block), we invoked JIT that had another managed exception @ JIT-EE transition boundary
10245 // that is swallowed by the JIT before managed code exception handler sees it. This breaks the sync between
10246 // LTO and the active exception in the exception tracker.
10247 if (_gc.oCurrentThrowable != _gc.oLastThrownObject)
10251 // Note: Incase of OOM, this will get set to OOM instance.
10252 pCurThread->SafeSetLastThrownObject(_gc.oCurrentThrowable);
10259 EE_TO_JIT_TRANSITION_LEAF();
10262 CORINFO_MODULE_HANDLE CEEInfo::embedModuleHandle(CORINFO_MODULE_HANDLE handle,
10263 void **ppIndirection)
10269 PRECONDITION(!IsDynamicScope(handle));
10273 if (ppIndirection != NULL)
10274 *ppIndirection = NULL;
10276 JIT_TO_EE_TRANSITION_LEAF();
10278 EE_TO_JIT_TRANSITION_LEAF();
10283 CORINFO_CLASS_HANDLE CEEInfo::embedClassHandle(CORINFO_CLASS_HANDLE handle,
10284 void **ppIndirection)
10293 if (ppIndirection != NULL)
10294 *ppIndirection = NULL;
10296 JIT_TO_EE_TRANSITION_LEAF();
10298 EE_TO_JIT_TRANSITION_LEAF();
10303 CORINFO_FIELD_HANDLE CEEInfo::embedFieldHandle(CORINFO_FIELD_HANDLE handle,
10304 void **ppIndirection)
10313 if (ppIndirection != NULL)
10314 *ppIndirection = NULL;
10316 JIT_TO_EE_TRANSITION_LEAF();
10318 EE_TO_JIT_TRANSITION_LEAF();
10323 CORINFO_METHOD_HANDLE CEEInfo::embedMethodHandle(CORINFO_METHOD_HANDLE handle,
10324 void **ppIndirection)
10333 if (ppIndirection != NULL)
10334 *ppIndirection = NULL;
10336 JIT_TO_EE_TRANSITION_LEAF();
10338 EE_TO_JIT_TRANSITION_LEAF();
10343 /*********************************************************************/
10344 void CEEInfo::setJitFlags(const CORJIT_FLAGS& jitFlags)
10346 LIMITED_METHOD_CONTRACT;
10348 m_jitFlags = jitFlags;
10351 /*********************************************************************/
10352 uint32_t CEEInfo::getJitFlags(CORJIT_FLAGS* jitFlags, uint32_t sizeInBytes)
10360 JIT_TO_EE_TRANSITION_LEAF();
10362 _ASSERTE(sizeInBytes >= sizeof(m_jitFlags));
10363 *jitFlags = m_jitFlags;
10365 EE_TO_JIT_TRANSITION_LEAF();
10367 return sizeof(m_jitFlags);
10370 /*********************************************************************/
10371 #if !defined(TARGET_UNIX)
10373 struct RunWithErrorTrapFilterParam
10375 ICorDynamicInfo* m_corInfo;
10376 void (*m_function)(void*);
10378 EXCEPTION_POINTERS m_exceptionPointers;
10381 static LONG RunWithErrorTrapFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam)
10383 WRAPPER_NO_CONTRACT;
10385 auto* param = reinterpret_cast<RunWithErrorTrapFilterParam*>(theParam);
10386 param->m_exceptionPointers = *exceptionPointers;
10387 return EEFilterException(exceptionPointers, nullptr);
10390 #endif // !defined(TARGET_UNIX)
10392 bool CEEInfo::runWithSPMIErrorTrap(void (*function)(void*), void* param)
10394 // No dynamic contract here because SEH is used
10395 STATIC_CONTRACT_THROWS;
10396 STATIC_CONTRACT_GC_TRIGGERS;
10397 STATIC_CONTRACT_MODE_PREEMPTIVE;
10399 // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
10400 // transitions into the EE proper should occur either via JIT/EE
10401 // interface calls made by `function`.
10403 // As we aren't SPMI, we don't need to do anything other than call the function.
10409 bool CEEInfo::runWithErrorTrap(void (*function)(void*), void* param)
10411 // No dynamic contract here because SEH is used
10412 STATIC_CONTRACT_THROWS;
10413 STATIC_CONTRACT_GC_TRIGGERS;
10414 STATIC_CONTRACT_MODE_PREEMPTIVE;
10416 // NOTE: the lack of JIT/EE transition markers in this method is intentional. Any
10417 // transitions into the EE proper should occur either via the call to
10418 // `EEFilterException` (which is appropriately marked) or via JIT/EE
10419 // interface calls made by `function`.
10421 bool success = true;
10423 #if !defined(TARGET_UNIX)
10425 RunWithErrorTrapFilterParam trapParam;
10426 trapParam.m_corInfo = this;
10427 trapParam.m_function = function;
10428 trapParam.m_param = param;
10430 PAL_TRY(RunWithErrorTrapFilterParam*, pTrapParam, &trapParam)
10432 pTrapParam->m_function(pTrapParam->m_param);
10434 PAL_EXCEPT_FILTER(RunWithErrorTrapFilter)
10436 HandleException(&trapParam.m_exceptionPointers);
10441 #else // !defined(TARGET_UNIX)
10443 // We shouldn't need PAL_TRY on *nix: any exceptions that we are able to catch
10444 // ought to originate from the runtime itself and should be catchable inside of
10445 // EX_TRY/EX_CATCH, including emulated SEH exceptions.
10454 EX_END_CATCH(RethrowTerminalExceptions);
10461 /*********************************************************************/
10462 int CEEInfo::doAssert(const char* szFile, int iLine, const char* szExpr)
10464 STATIC_CONTRACT_THROWS;
10465 STATIC_CONTRACT_GC_TRIGGERS;
10466 STATIC_CONTRACT_MODE_PREEMPTIVE;
10467 STATIC_CONTRACT_DEBUG_ONLY;
10471 JIT_TO_EE_TRANSITION();
10475 BEGIN_DEBUG_ONLY_CODE;
10476 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitThrowOnAssertionFailure) != 0)
10480 "JIT assert failed:\n"
10482 " File: %s Line: %d\n",
10483 szExpr, szFile, iLine);
10484 COMPlusThrowNonLocalized(kInvalidProgramException, output.GetUnicode());
10487 result = _DbgBreakCheck(szFile, iLine, szExpr);
10488 END_DEBUG_ONLY_CODE;
10490 result = 1; // break into debugger
10494 EE_TO_JIT_TRANSITION();
10499 void CEEInfo::reportFatalError(CorJitResult result)
10501 STATIC_CONTRACT_THROWS;
10502 STATIC_CONTRACT_GC_TRIGGERS;
10503 STATIC_CONTRACT_MODE_PREEMPTIVE;
10505 JIT_TO_EE_TRANSITION_LEAF();
10507 STRESS_LOG2(LF_JIT,LL_ERROR, "Jit reported error 0x%x while compiling 0x%p\n",
10508 (int)result, (INT_PTR)getMethodBeingCompiled());
10510 EE_TO_JIT_TRANSITION_LEAF();
10513 bool CEEInfo::logMsg(unsigned level, const char* fmt, va_list args)
10515 STATIC_CONTRACT_THROWS;
10516 STATIC_CONTRACT_GC_TRIGGERS;
10517 STATIC_CONTRACT_MODE_PREEMPTIVE;
10518 STATIC_CONTRACT_DEBUG_ONLY;
10520 bool result = false;
10522 JIT_TO_EE_TRANSITION_LEAF();
10525 if (LoggingOn(LF_JIT, level))
10527 LogSpewValist(LF_JIT, level, (char*) fmt, args);
10532 EE_TO_JIT_TRANSITION_LEAF();
10538 /*********************************************************************/
10540 void* CEEJitInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
10541 void ** ppIndirection) /* OUT */
10549 void* result = NULL;
10551 if (ppIndirection != NULL)
10552 *ppIndirection = NULL;
10554 JIT_TO_EE_TRANSITION_LEAF();
10556 _ASSERTE(ftnNum < CORINFO_HELP_COUNT);
10558 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10560 size_t dynamicFtnNum = ((size_t)pfnHelper - 1);
10561 if (dynamicFtnNum < DYNAMIC_CORINFO_HELP_COUNT)
10564 #pragma warning(push)
10565 #pragma warning(disable:26001) // "Bounds checked above using the underflow trick"
10566 #endif /*_PREFAST_ */
10568 #if defined(TARGET_AMD64)
10569 // To avoid using a jump stub we always call certain helpers using an indirect call.
10570 // Because when using a direct call and the target is father away than 2^31 bytes,
10571 // the direct call instead goes to a jump stub which jumps to the jit helper.
10572 // However in this process the jump stub will corrupt RAX.
10574 // The set of helpers for which RAX must be preserved are profiler probes, CFG dispatcher
10575 // and the STOP_FOR_GC helper which maps to JIT_RareDisableHelper.
10576 // In the case of the STOP_FOR_GC helper RAX can be holding a function return value.
10578 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_STOP_FOR_GC ||
10579 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER ||
10580 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE ||
10581 dynamicFtnNum == DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL ||
10582 dynamicFtnNum == DYNAMIC_CORINFO_HELP_DISPATCH_INDIRECT_CALL)
10584 _ASSERTE(ppIndirection != NULL);
10585 *ppIndirection = &hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10590 if (dynamicFtnNum == DYNAMIC_CORINFO_HELP_ISINSTANCEOFINTERFACE ||
10591 dynamicFtnNum == DYNAMIC_CORINFO_HELP_ISINSTANCEOFANY ||
10592 dynamicFtnNum == DYNAMIC_CORINFO_HELP_ISINSTANCEOFARRAY ||
10593 dynamicFtnNum == DYNAMIC_CORINFO_HELP_ISINSTANCEOFCLASS ||
10594 dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTANY ||
10595 dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTARRAY ||
10596 dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTINTERFACE ||
10597 dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTCLASS ||
10598 dynamicFtnNum == DYNAMIC_CORINFO_HELP_CHKCASTCLASS_SPECIAL ||
10599 dynamicFtnNum == DYNAMIC_CORINFO_HELP_UNBOX)
10601 Precode* pPrecode = Precode::GetPrecodeFromEntryPoint((PCODE)hlpDynamicFuncTable[dynamicFtnNum].pfnHelper);
10602 _ASSERTE(pPrecode->GetType() == PRECODE_FIXUP);
10603 *ppIndirection = ((FixupPrecode*)pPrecode)->GetTargetSlot();
10607 pfnHelper = hlpDynamicFuncTable[dynamicFtnNum].pfnHelper;
10610 #pragma warning(pop)
10611 #endif /*_PREFAST_*/
10614 _ASSERTE(pfnHelper);
10616 result = (LPVOID)GetEEFuncEntryPoint(pfnHelper);
10618 EE_TO_JIT_TRANSITION_LEAF();
10623 PCODE CEEJitInfo::getHelperFtnStatic(CorInfoHelpFunc ftnNum)
10625 LIMITED_METHOD_CONTRACT;
10627 void* pfnHelper = hlpFuncTable[ftnNum].pfnHelper;
10629 // If pfnHelper is an index into the dynamic helper table, it should be less
10630 // than DYNAMIC_CORINFO_HELP_COUNT. In this case we need to find the actual pfnHelper
10631 // using an extra indirection. Note the special case
10632 // where pfnHelper==0 where pfnHelper-1 will underflow and we will avoid the indirection.
10633 if (((size_t)pfnHelper - 1) < DYNAMIC_CORINFO_HELP_COUNT)
10635 pfnHelper = hlpDynamicFuncTable[((size_t)pfnHelper - 1)].pfnHelper;
10638 _ASSERTE(pfnHelper != NULL);
10640 return GetEEFuncEntryPoint(pfnHelper);
10643 // Wrapper around CEEInfo::GetProfilingHandle. The first time this is called for a
10644 // method desc, it calls through to EEToProfInterfaceImpl::EEFunctionIDMappe and caches the
10645 // result in CEEJitInfo::GetProfilingHandleCache. Thereafter, this wrapper regurgitates the cached values
10646 // rather than calling into CEEInfo::GetProfilingHandle each time. This avoids
10647 // making duplicate calls into the profiler's FunctionIDMapper callback.
10648 void CEEJitInfo::GetProfilingHandle(bool *pbHookFunction,
10649 void **pProfilerHandle,
10650 bool *pbIndirectedHandles)
10658 _ASSERTE(pbHookFunction != NULL);
10659 _ASSERTE(pProfilerHandle != NULL);
10660 _ASSERTE(pbIndirectedHandles != NULL);
10662 if (!m_gphCache.m_bGphIsCacheValid)
10664 #ifdef PROFILING_SUPPORTED
10665 JIT_TO_EE_TRANSITION();
10667 // Cache not filled in, so make our first and only call to CEEInfo::GetProfilingHandle here
10669 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
10670 // they shouldnever come here as they are called out in GetCompileFlag
10671 _ASSERTE(!m_pMethodBeingCompiled->IsNoMetadata());
10673 // We pass in the typical method definition to the function mapper because in
10674 // Whidbey all the profiling API transactions are done in terms of typical
10675 // method definitions not instantiations.
10676 BOOL bHookFunction = TRUE;
10677 void * profilerHandle = m_pMethodBeingCompiled;
10680 BEGIN_PROFILER_CALLBACK(CORProfilerFunctionIDMapperEnabled());
10681 profilerHandle = (void *)(&g_profControlBlock)->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction);
10682 END_PROFILER_CALLBACK();
10685 m_gphCache.m_pvGphProfilerHandle = profilerHandle;
10686 m_gphCache.m_bGphHookFunction = (bHookFunction != FALSE);
10687 m_gphCache.m_bGphIsCacheValid = true;
10689 EE_TO_JIT_TRANSITION();
10690 #endif //PROFILING_SUPPORTED
10693 // Our cache of these values are bitfield bools, but the interface requires
10694 // bool. So to avoid setting aside a staging area on the stack for these
10695 // values, we filled them in directly in the if (not cached yet) case.
10696 *pbHookFunction = (m_gphCache.m_bGphHookFunction != false);
10698 // At this point, the remaining values must be in the cache by now, so use them
10699 *pProfilerHandle = m_gphCache.m_pvGphProfilerHandle;
10702 // This is the JIT case, which is never indirected.
10704 *pbIndirectedHandles = false;
10707 /*********************************************************************/
10708 void CEEJitInfo::WriteCodeBytes()
10710 LIMITED_METHOD_CONTRACT;
10712 #ifdef USE_INDIRECT_CODEHEADER
10713 if (m_pRealCodeHeader != NULL)
10715 // Restore the read only version of the real code header
10716 m_CodeHeaderRW->SetRealCodeHeader(m_pRealCodeHeader);
10717 m_pRealCodeHeader = NULL;
10719 #endif // USE_INDIRECT_CODEHEADER
10721 if (m_CodeHeaderRW != m_CodeHeader)
10723 ExecutableWriterHolder<void> codeWriterHolder((void *)m_CodeHeader, m_codeWriteBufferSize);
10724 memcpy(codeWriterHolder.GetRW(), m_CodeHeaderRW, m_codeWriteBufferSize);
10728 /*********************************************************************/
10729 void CEEJitInfo::BackoutJitData(EEJitManager * jitMgr)
10736 // The RemoveJitData call below requires the m_CodeHeader to be valid, so we need to write
10737 // the code bytes to the target memory location.
10740 CodeHeader* pCodeHeader = m_CodeHeader;
10742 jitMgr->RemoveJitData(pCodeHeader, m_GCinfo_len, m_EHinfo_len);
10745 /*********************************************************************/
10746 void CEEJitInfo::WriteCode(EEJitManager * jitMgr)
10753 #ifdef FEATURE_INTERPRETER
10754 // TODO: the InterpterCEEInfo doesn't support features about W^X.
10756 if (m_pCodeHeap == nullptr) return;
10761 // Now that the code header was written to the final location, publish the code via the nibble map
10762 jitMgr->NibbleMapSet(m_pCodeHeap, m_CodeHeader->GetCodeStartAddress(), TRUE);
10764 #if defined(TARGET_AMD64)
10765 // Publish the new unwind information in a way that the ETW stack crawler can find
10766 _ASSERTE(m_usedUnwindInfos == m_totalUnwindInfos);
10767 UnwindInfoTable::PublishUnwindInfoForMethod(m_moduleBase, m_CodeHeader->GetUnwindInfo(0), m_totalUnwindInfos);
10768 #endif // defined(TARGET_AMD64)
10773 /*********************************************************************/
10774 // Route jit information to the Jit Debug store.
10775 void CEEJitInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, uint32_t cMap,
10776 ICorDebugInfo::OffsetMapping *pMap)
10784 JIT_TO_EE_TRANSITION();
10786 // We receive ownership of the array
10787 _ASSERTE(m_pOffsetMapping == NULL && m_iOffsetMapping == 0);
10788 m_iOffsetMapping = cMap;
10789 m_pOffsetMapping = pMap;
10791 EE_TO_JIT_TRANSITION();
10794 void CEEJitInfo::setVars(CORINFO_METHOD_HANDLE ftn, uint32_t cVars, ICorDebugInfo::NativeVarInfo *vars)
10802 JIT_TO_EE_TRANSITION();
10804 // We receive ownership of the array
10805 _ASSERTE(m_pNativeVarInfo == NULL && m_iNativeVarInfo == 0);
10806 m_iNativeVarInfo = cVars;
10807 m_pNativeVarInfo = vars;
10809 EE_TO_JIT_TRANSITION();
10812 void CEEJitInfo::reportRichMappings(
10813 ICorDebugInfo::InlineTreeNode* inlineTreeNodes,
10814 uint32_t numInlineTreeNodes,
10815 ICorDebugInfo::RichOffsetMapping* mappings,
10816 uint32_t numMappings)
10824 JIT_TO_EE_TRANSITION();
10826 if (m_jitManager->IsStoringRichDebugInfo())
10828 m_inlineTreeNodes = inlineTreeNodes;
10829 m_numInlineTreeNodes = numInlineTreeNodes;
10830 m_richOffsetMappings = mappings;
10831 m_numRichOffsetMappings = numMappings;
10835 freeArrayInternal(inlineTreeNodes);
10836 freeArrayInternal(mappings);
10839 EE_TO_JIT_TRANSITION();
10842 void CEEJitInfo::setPatchpointInfo(PatchpointInfo* patchpointInfo)
10850 JIT_TO_EE_TRANSITION();
10852 #ifdef FEATURE_ON_STACK_REPLACEMENT
10853 // We receive ownership of the array
10854 _ASSERTE(m_pPatchpointInfoFromJit == NULL);
10855 m_pPatchpointInfoFromJit = patchpointInfo;
10860 EE_TO_JIT_TRANSITION();
10863 PatchpointInfo* CEEJitInfo::getOSRInfo(unsigned* ilOffset)
10871 PatchpointInfo* result = NULL;
10874 JIT_TO_EE_TRANSITION();
10876 #ifdef FEATURE_ON_STACK_REPLACEMENT
10877 result = m_pPatchpointInfoFromRuntime;
10878 *ilOffset = m_ilOffset;
10881 EE_TO_JIT_TRANSITION();
10886 void CEEJitInfo::CompressDebugInfo()
10894 #ifdef FEATURE_ON_STACK_REPLACEMENT
10895 PatchpointInfo* patchpointInfo = m_pPatchpointInfoFromJit;
10897 PatchpointInfo* patchpointInfo = NULL;
10900 // Don't track JIT info for DynamicMethods.
10901 if (m_pMethodBeingCompiled->IsDynamicMethod() && !g_pConfig->GetTrackDynamicMethodDebugInfo())
10903 _ASSERTE(patchpointInfo == NULL);
10907 if ((m_iOffsetMapping == 0) && (m_iNativeVarInfo == 0) && (patchpointInfo == NULL) && (m_numInlineTreeNodes == 0) && (m_numRichOffsetMappings == 0))
10910 JIT_TO_EE_TRANSITION();
10914 BOOL writeFlagByte = FALSE;
10915 #ifdef FEATURE_ON_STACK_REPLACEMENT
10916 writeFlagByte = TRUE;
10918 if (m_jitManager->IsStoringRichDebugInfo())
10919 writeFlagByte = TRUE;
10921 PTR_BYTE pDebugInfo = CompressDebugInfo::CompressBoundariesAndVars(
10922 m_pOffsetMapping, m_iOffsetMapping,
10923 m_pNativeVarInfo, m_iNativeVarInfo,
10925 m_inlineTreeNodes, m_numInlineTreeNodes,
10926 m_richOffsetMappings, m_numRichOffsetMappings,
10928 m_pMethodBeingCompiled->GetLoaderAllocator()->GetLowFrequencyHeap());
10930 m_CodeHeaderRW->SetDebugInfo(pDebugInfo);
10934 // Just ignore exceptions here. The debugger's structures will still be in a consistent state.
10936 EX_END_CATCH(SwallowAllExceptions)
10938 EE_TO_JIT_TRANSITION();
10941 void reservePersonalityRoutineSpace(uint32_t &unwindSize)
10943 #if defined(TARGET_X86)
10945 #elif defined(TARGET_AMD64)
10946 // Add space for personality routine, it must be 4-byte aligned.
10947 // Everything in the UNWIND_INFO up to the variable-sized UnwindCodes
10948 // array has already had its size included in unwindSize by the caller.
10949 unwindSize += sizeof(ULONG);
10951 // Note that the count of unwind codes (2 bytes each) is stored as a UBYTE
10952 // So the largest size could be 510 bytes, plus the header and language
10953 // specific stuff. This can't overflow.
10955 _ASSERTE(FitsInU4(unwindSize + sizeof(ULONG)));
10956 unwindSize = (ULONG)(ALIGN_UP(unwindSize, sizeof(ULONG)));
10957 #elif defined(TARGET_ARM) || defined(TARGET_ARM64)
10958 // The JIT passes in a 4-byte aligned block of unwind data.
10959 _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
10961 // Add space for personality routine, it must be 4-byte aligned.
10962 unwindSize += sizeof(ULONG);
10963 #elif defined(TARGET_LOONGARCH64)
10964 // The JIT passes in a 4-byte aligned block of unwind data.
10965 _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
10967 // Add space for personality routine, it must be 4-byte aligned.
10968 unwindSize += sizeof(ULONG);
10969 #elif defined(TARGET_RISCV64)
10970 // The JIT passes in a 4-byte aligned block of unwind data.
10971 _ASSERTE(IS_ALIGNED(unwindSize, sizeof(ULONG)));
10973 // Add space for personality routine, it must be 4-byte aligned.
10974 unwindSize += sizeof(ULONG);
10976 PORTABILITY_ASSERT("reservePersonalityRoutineSpace");
10977 #endif // !defined(TARGET_AMD64)
10980 // Reserve memory for the method/funclet's unwind information.
10981 // Note that this must be called before allocMem. It should be
10982 // called once for the main method, once for every funclet, and
10983 // once for every block of cold code for which allocUnwindInfo
10986 // This is necessary because jitted code must allocate all the
10987 // memory needed for the unwindInfo at the allocMem call.
10988 // For prejitted code we split up the unwinding information into
10989 // separate sections .rdata and .pdata.
10991 void CEEJitInfo::reserveUnwindInfo(bool isFunclet, bool isColdCode, uint32_t unwindSize)
10993 #ifdef FEATURE_EH_FUNCLETS
11001 JIT_TO_EE_TRANSITION_LEAF();
11003 CONSISTENCY_CHECK_MSG(!isColdCode, "Hot/Cold splitting is not supported in jitted code");
11004 _ASSERTE_MSG(m_theUnwindBlock == NULL,
11005 "reserveUnwindInfo() can only be called before allocMem(), but allocMem() has already been called. "
11006 "This may indicate the JIT has hit a NO_WAY assert after calling allocMem(), and is re-JITting. "
11007 "Set DOTNET_JitBreakOnBadCode=1 and rerun to get the real error.");
11009 uint32_t currentSize = unwindSize;
11011 reservePersonalityRoutineSpace(currentSize);
11013 m_totalUnwindSize += currentSize;
11015 m_totalUnwindInfos++;
11017 EE_TO_JIT_TRANSITION_LEAF();
11018 #else // FEATURE_EH_FUNCLETS
11019 LIMITED_METHOD_CONTRACT;
11020 // Dummy implementation to make cross-platform altjit work
11021 #endif // FEATURE_EH_FUNCLETS
11024 // Allocate and initialize the .rdata and .pdata for this method or
11025 // funclet and get the block of memory needed for the machine specific
11026 // unwind information (the info for crawling the stack frame).
11027 // Note that allocMem must be called first.
11029 // The pHotCode parameter points at the first byte of the code of the method
11030 // The startOffset and endOffset are the region (main or funclet) that
11031 // we are to allocate and create .rdata and .pdata for.
11032 // The pUnwindBlock is copied and contains the .pdata unwind area
11036 // pHotCode main method code buffer, always filled in
11037 // pColdCode always NULL for jitted code
11038 // startOffset start of code block, relative to pHotCode
11039 // endOffset end of code block, relative to pHotCode
11040 // unwindSize size of unwind info pointed to by pUnwindBlock
11041 // pUnwindBlock pointer to unwind info
11042 // funcKind type of funclet (main method code, handler, filter)
11044 void CEEJitInfo::allocUnwindInfo (
11045 uint8_t * pHotCode, /* IN */
11046 uint8_t * pColdCode, /* IN */
11047 uint32_t startOffset, /* IN */
11048 uint32_t endOffset, /* IN */
11049 uint32_t unwindSize, /* IN */
11050 uint8_t * pUnwindBlock, /* IN */
11051 CorJitFuncKind funcKind /* IN */
11054 #ifdef FEATURE_EH_FUNCLETS
11059 PRECONDITION(m_theUnwindBlock != NULL);
11060 PRECONDITION(m_usedUnwindSize < m_totalUnwindSize);
11061 PRECONDITION(m_usedUnwindInfos < m_totalUnwindInfos);
11062 PRECONDITION(endOffset <= m_codeSize);
11065 CONSISTENCY_CHECK_MSG(pColdCode == NULL, "Hot/Cold code splitting not supported for jitted code");
11067 JIT_TO_EE_TRANSITION();
11070 // We add one callback-type dynamic function table per range section.
11071 // Therefore, the RUNTIME_FUNCTION info is always relative to the
11072 // image base contained in the dynamic function table, which happens
11073 // to be the LowAddress of the range section. The JIT has no
11074 // knowledge of the range section, so it gives us offsets that are
11075 // relative to the beginning of the method (pHotCode) and we allocate
11076 // and initialize the RUNTIME_FUNCTION data and record its location
11077 // in this function.
11080 if (funcKind != CORJIT_FUNC_ROOT)
11082 // The main method should be emitted before funclets
11083 _ASSERTE(m_usedUnwindInfos > 0);
11086 PT_RUNTIME_FUNCTION pRuntimeFunction = m_CodeHeaderRW->GetUnwindInfo(m_usedUnwindInfos);
11088 m_usedUnwindInfos++;
11090 // Make sure that the RUNTIME_FUNCTION is aligned on a DWORD sized boundary
11091 _ASSERTE(IS_ALIGNED(pRuntimeFunction, sizeof(DWORD)));
11094 size_t writeableOffset = (BYTE *)m_CodeHeaderRW - (BYTE *)m_CodeHeader;
11095 UNWIND_INFO * pUnwindInfo = (UNWIND_INFO *) &(m_theUnwindBlock[m_usedUnwindSize]);
11096 UNWIND_INFO * pUnwindInfoRW = (UNWIND_INFO *)((BYTE*)pUnwindInfo + writeableOffset);
11098 m_usedUnwindSize += unwindSize;
11100 reservePersonalityRoutineSpace(m_usedUnwindSize);
11102 _ASSERTE(m_usedUnwindSize <= m_totalUnwindSize);
11104 // Make sure that the UnwindInfo is aligned
11105 _ASSERTE(IS_ALIGNED(pUnwindInfo, sizeof(ULONG)));
11107 /* Calculate Image Relative offset to add to the jit generated unwind offsets */
11109 TADDR baseAddress = m_moduleBase;
11111 size_t currentCodeSizeT = (size_t)pHotCode - baseAddress;
11113 /* Check if currentCodeSizeT offset fits in 32-bits */
11114 if (!FitsInU4(currentCodeSizeT))
11116 _ASSERTE(!"Bad currentCodeSizeT");
11117 COMPlusThrowHR(E_FAIL);
11120 /* Check if EndAddress offset fits in 32-bit */
11121 if (!FitsInU4(currentCodeSizeT + endOffset))
11123 _ASSERTE(!"Bad currentCodeSizeT");
11124 COMPlusThrowHR(E_FAIL);
11127 unsigned currentCodeOffset = (unsigned) currentCodeSizeT;
11129 /* Calculate Unwind Info delta */
11130 size_t unwindInfoDeltaT = (size_t) pUnwindInfo - baseAddress;
11132 /* Check if unwindDeltaT offset fits in 32-bits */
11133 if (!FitsInU4(unwindInfoDeltaT))
11135 _ASSERTE(!"Bad unwindInfoDeltaT");
11136 COMPlusThrowHR(E_FAIL);
11139 unsigned unwindInfoDelta = (unsigned) unwindInfoDeltaT;
11141 RUNTIME_FUNCTION__SetBeginAddress(pRuntimeFunction, currentCodeOffset + startOffset);
11143 #ifdef TARGET_AMD64
11144 pRuntimeFunction->EndAddress = currentCodeOffset + endOffset;
11147 RUNTIME_FUNCTION__SetUnwindInfoAddress(pRuntimeFunction, unwindInfoDelta);
11150 if (funcKind != CORJIT_FUNC_ROOT)
11152 // Check the new funclet doesn't overlap any existing funclet.
11154 for (ULONG iUnwindInfo = 0; iUnwindInfo < m_usedUnwindInfos - 1; iUnwindInfo++)
11156 PT_RUNTIME_FUNCTION pOtherFunction = m_CodeHeaderRW->GetUnwindInfo(iUnwindInfo);
11157 _ASSERTE(( RUNTIME_FUNCTION__BeginAddress(pOtherFunction) >= RUNTIME_FUNCTION__EndAddress(pRuntimeFunction, baseAddress + writeableOffset)
11158 || RUNTIME_FUNCTION__EndAddress(pOtherFunction, baseAddress + writeableOffset) <= RUNTIME_FUNCTION__BeginAddress(pRuntimeFunction)));
11163 memcpy(pUnwindInfoRW, pUnwindBlock, unwindSize);
11165 #if defined(TARGET_X86)
11169 #elif defined(TARGET_AMD64)
11171 pUnwindInfoRW->Flags = UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER;
11173 ULONG * pPersonalityRoutineRW = (ULONG*)ALIGN_UP(&(pUnwindInfoRW->UnwindCode[pUnwindInfoRW->CountOfUnwindCodes]), sizeof(ULONG));
11174 *pPersonalityRoutineRW = ExecutionManager::GetCLRPersonalityRoutineValue();
11176 #elif defined(TARGET_ARM64)
11178 *(LONG *)pUnwindInfoRW |= (1 << 20); // X bit
11180 ULONG * pPersonalityRoutineRW = (ULONG*)((BYTE *)pUnwindInfoRW + ALIGN_UP(unwindSize, sizeof(ULONG)));
11181 *pPersonalityRoutineRW = ExecutionManager::GetCLRPersonalityRoutineValue();
11183 #elif defined(TARGET_ARM)
11185 *(LONG *)pUnwindInfoRW |= (1 << 20); // X bit
11187 ULONG * pPersonalityRoutineRW = (ULONG*)((BYTE *)pUnwindInfoRW + ALIGN_UP(unwindSize, sizeof(ULONG)));
11188 *pPersonalityRoutineRW = (TADDR)ProcessCLRException - baseAddress;
11190 #elif defined(TARGET_LOONGARCH64)
11192 *(LONG *)pUnwindInfoRW |= (1 << 20); // X bit
11194 ULONG * pPersonalityRoutineRW = (ULONG*)((BYTE *)pUnwindInfoRW + ALIGN_UP(unwindSize, sizeof(ULONG)));
11195 *pPersonalityRoutineRW = ExecutionManager::GetCLRPersonalityRoutineValue();
11197 #elif defined(TARGET_RISCV64)
11198 *(LONG *)pUnwindInfoRW |= (1 << 20); // X bit
11200 ULONG * pPersonalityRoutineRW = (ULONG*)((BYTE *)pUnwindInfoRW + ALIGN_UP(unwindSize, sizeof(ULONG)));
11201 *pPersonalityRoutineRW = ExecutionManager::GetCLRPersonalityRoutineValue();
11205 EE_TO_JIT_TRANSITION();
11206 #else // FEATURE_EH_FUNCLETS
11207 LIMITED_METHOD_CONTRACT;
11208 // Dummy implementation to make cross-platform altjit work
11209 #endif // FEATURE_EH_FUNCLETS
11212 void CEEJitInfo::recordCallSite(uint32_t instrOffset,
11213 CORINFO_SIG_INFO * callSig,
11214 CORINFO_METHOD_HANDLE methodHandle)
11216 // Currently, only testing tools use this method. The EE itself doesn't need record this information.
11217 // N.B. The memory that callSig points to is managed by the JIT and isn't guaranteed to be around after
11218 // this function returns, so future implementations should copy the sig info if they want it to persist.
11219 LIMITED_METHOD_CONTRACT;
11222 // This is a variant for AMD64 or other machines that
11223 // cannot always hold the destination address in a 32-bit location
11224 // A relocation is recorded if we are pre-jitting.
11225 // A jump thunk may be inserted if we are jitting
11227 void CEEJitInfo::recordRelocation(void * location,
11240 JIT_TO_EE_TRANSITION();
11244 switch (fRelocType)
11246 case IMAGE_REL_BASED_DIR64:
11247 // Write 64-bits into location
11248 *((UINT64 *) locationRW) = (UINT64) target;
11251 #ifdef TARGET_AMD64
11252 case IMAGE_REL_BASED_REL32:
11254 target = (BYTE *)target + addlDelta;
11256 INT32 * fixupLocation = (INT32 *) location;
11257 INT32 * fixupLocationRW = (INT32 *) locationRW;
11258 BYTE * baseAddr = (BYTE *)fixupLocation + sizeof(INT32);
11260 delta = (INT64)((BYTE *)target - baseAddr);
11263 // Do we need to insert a jump stub to make the source reach the target?
11265 // Note that we cannot stress insertion of jump stub by inserting it unconditionally. JIT records the relocations
11266 // for intra-module jumps and calls. It does not expect the register used by the jump stub to be trashed.
11268 if (!FitsInI4(delta))
11273 // When m_fAllowRel32 == TRUE, the JIT will use REL32s for both data addresses and direct code targets.
11274 // Since we cannot tell what the relocation is for, we have to defensively retry.
11276 m_fJumpStubOverflow = TRUE;
11282 // When m_fAllowRel32 == FALSE, the JIT will use a REL32s for direct code targets only.
11285 delta = rel32UsingJumpStub(fixupLocation, (PCODE)target, m_pMethodBeingCompiled, NULL, false /* throwOnOutOfMemoryWithinRange */);
11288 // This forces the JIT to retry the method, which allows us to reserve more space for jump stubs and have a higher chance that
11289 // we will find space for them.
11290 m_fJumpStubOverflow = TRUE;
11293 // Keep track of conservative estimate of how much memory may be needed by jump stubs. We will use it to reserve extra memory
11294 // on retry to increase chances that the retry succeeds.
11295 m_reserveForJumpStubs = max(0x400, m_reserveForJumpStubs + 0x10);
11299 LOG((LF_JIT, LL_INFO100000, "Encoded a PCREL32 at" FMT_ADDR "to" FMT_ADDR "+%d, delta is 0x%04x\n",
11300 DBG_ADDR(fixupLocation), DBG_ADDR(target), addlDelta, delta));
11302 // Write the 32-bits pc-relative delta into location
11303 *fixupLocationRW = (INT32) delta;
11306 #endif // TARGET_AMD64
11308 #ifdef TARGET_ARM64
11309 case IMAGE_REL_ARM64_BRANCH26: // 26 bit offset << 2 & sign ext, for B and BL
11311 _ASSERTE(addlDelta == 0);
11313 PCODE branchTarget = (PCODE) target;
11314 _ASSERTE((branchTarget & 0x3) == 0); // the low two bits must be zero
11316 PCODE fixupLocation = (PCODE) location;
11317 PCODE fixupLocationRW = (PCODE) locationRW;
11318 _ASSERTE((fixupLocation & 0x3) == 0); // the low two bits must be zero
11320 delta = (INT64)(branchTarget - fixupLocation);
11321 _ASSERTE((delta & 0x3) == 0); // the low two bits must be zero
11323 UINT32 branchInstr = *((UINT32*) fixupLocationRW);
11324 branchInstr &= 0xFC000000; // keep bits 31-26
11325 _ASSERTE((branchInstr & 0x7FFFFFFF) == 0x14000000); // Must be B or BL
11328 // Do we need to insert a jump stub to make the source reach the target?
11331 if (!FitsInRel28(delta))
11335 TADDR baseAddr = (TADDR)fixupLocation;
11336 TADDR loAddr = baseAddr - 0x08000000; // -2^27
11337 TADDR hiAddr = baseAddr + 0x07FFFFFF; // +2^27-1
11339 // Check for the wrap around cases
11340 if (loAddr > baseAddr)
11341 loAddr = UINT64_MIN; // overflow
11342 if (hiAddr < baseAddr)
11343 hiAddr = UINT64_MAX; // overflow
11345 PCODE jumpStubAddr = ExecutionManager::jumpStub(m_pMethodBeingCompiled,
11352 // Keep track of conservative estimate of how much memory may be needed by jump stubs. We will use it to reserve extra memory
11353 // on retry to increase chances that the retry succeeds.
11354 m_reserveForJumpStubs = max(0x400, m_reserveForJumpStubs + 2*BACK_TO_BACK_JUMP_ALLOCATE_SIZE);
11356 if (jumpStubAddr == 0)
11358 // This forces the JIT to retry the method, which allows us to reserve more space for jump stubs and have a higher chance that
11359 // we will find space for them.
11360 m_fJumpStubOverflow = TRUE;
11364 delta = (INT64)(jumpStubAddr - fixupLocation);
11366 if (!FitsInRel28(delta))
11368 _ASSERTE(!"jump stub was not in expected range");
11369 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
11372 LOG((LF_JIT, LL_INFO100000, "Using JumpStub at" FMT_ADDR "that jumps to" FMT_ADDR "\n",
11373 DBG_ADDR(jumpStubAddr), DBG_ADDR(target)));
11376 LOG((LF_JIT, LL_INFO100000, "Encoded a BRANCH26 at" FMT_ADDR "to" FMT_ADDR ", delta is 0x%04x\n",
11377 DBG_ADDR(fixupLocation), DBG_ADDR(target), delta));
11379 _ASSERTE(FitsInRel28(delta));
11381 PutArm64Rel28((UINT32*) fixupLocationRW, (INT32)delta);
11385 case IMAGE_REL_ARM64_PAGEBASE_REL21:
11387 _ASSERTE(addlDelta == 0);
11389 // Write the 21 bits pc-relative page address into location.
11390 INT64 targetPage = (INT64)target & 0xFFFFFFFFFFFFF000LL;
11391 INT64 locationPage = (INT64)location & 0xFFFFFFFFFFFFF000LL;
11392 INT64 relPage = (INT64)(targetPage - locationPage);
11393 INT32 imm21 = (INT32)(relPage >> 12) & 0x1FFFFF;
11394 PutArm64Rel21((UINT32 *)locationRW, imm21);
11398 case IMAGE_REL_ARM64_PAGEOFFSET_12A:
11400 _ASSERTE(addlDelta == 0);
11402 // Write the 12 bits page offset into location.
11403 INT32 imm12 = (INT32)(SIZE_T)target & 0xFFFLL;
11404 PutArm64Rel12((UINT32 *)locationRW, imm12);
11408 #endif // TARGET_ARM64
11411 _ASSERTE(!"Unknown reloc type");
11415 EE_TO_JIT_TRANSITION();
11416 #else // HOST_64BIT
11417 JIT_TO_EE_TRANSITION_LEAF();
11419 // Nothing to do on 32-bit
11421 EE_TO_JIT_TRANSITION_LEAF();
11422 #endif // HOST_64BIT
11425 // Get a hint for whether the relocation kind to use for the target address.
11426 // Note that this is currently a best-guess effort as we do not know exactly
11427 // where the jitted code will end up at. Instead we try to keep executable code
11428 // and static fields in a preferred memory region and base the decision on this
11431 // If we guess wrong we will recover in recordRelocation if we notice that we
11432 // cannot actually use the kind of reloc: in that case we will rejit the
11433 // function and turn off the use of those relocs in the future. This scheme
11434 // works based on two assumptions:
11436 // 1) The JIT will ask about relocs only for memory that was allocated by the
11437 // loader heap in the preferred region.
11438 // 2) The loader heap allocates memory in the preferred region in a circular fashion;
11439 // the region itself might be larger than 2 GB, but the current compilation should
11440 // only be hitting the preferred region within 2 GB.
11442 // Under these assumptions we should only hit the "recovery" case once the
11443 // preferred range is actually full.
11444 WORD CEEJitInfo::getRelocTypeHint(void * target)
11452 #ifdef TARGET_AMD64
11455 if (ExecutableAllocator::IsPreferredExecutableRange(target))
11456 return IMAGE_REL_BASED_REL32;
11458 #endif // TARGET_AMD64
11464 uint32_t CEEJitInfo::getExpectedTargetArchitecture()
11466 LIMITED_METHOD_CONTRACT;
11468 return IMAGE_FILE_MACHINE_NATIVE;
11471 void CEEInfo::JitProcessShutdownWork()
11473 LIMITED_METHOD_CONTRACT;
11475 EEJitManager* jitMgr = ExecutionManager::GetEEJitManager();
11477 // If we didn't load the JIT, there is no work to do.
11478 if (jitMgr->m_jit != NULL)
11480 // Do the shutdown work.
11481 jitMgr->m_jit->ProcessShutdownWork(this);
11484 #ifdef ALLOW_SXS_JIT
11485 if (jitMgr->m_alternateJit != NULL)
11487 jitMgr->m_alternateJit->ProcessShutdownWork(this);
11489 #endif // ALLOW_SXS_JIT
11492 /*********************************************************************/
11493 InfoAccessType CEEJitInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
11503 InfoAccessType result = IAT_PVALUE;
11505 JIT_TO_EE_TRANSITION();
11507 _ASSERTE(ppValue != NULL);
11509 if (IsDynamicScope(scopeHnd))
11511 *ppValue = (LPVOID)GetDynamicResolver(scopeHnd)->ConstructStringLiteral(metaTok);
11515 // If ConstructStringLiteral returns a pinned reference we can return it by value (IAT_VALUE)
11516 void* ppPinnedString = nullptr;
11517 void** ptr = (void**)ConstructStringLiteral(scopeHnd, metaTok, &ppPinnedString);
11519 if (ppPinnedString != nullptr)
11521 *ppValue = ppPinnedString;
11522 result = IAT_VALUE;
11526 *ppValue = (void*)ptr;
11530 EE_TO_JIT_TRANSITION();
11535 /*********************************************************************/
11536 InfoAccessType CEEJitInfo::emptyStringLiteral(void ** ppValue)
11544 InfoAccessType result = IAT_PVALUE;
11546 JIT_TO_EE_TRANSITION();
11547 void* pinnedStr = nullptr;
11548 void* pinnedStrHandlePtr = StringObject::GetEmptyStringRefPtr(&pinnedStr);
11550 if (pinnedStr != nullptr)
11552 *ppValue = pinnedStr;
11553 result = IAT_VALUE;
11557 *ppValue = pinnedStrHandlePtr;
11560 EE_TO_JIT_TRANSITION();
11565 bool CEEInfo::getStaticObjRefContent(OBJECTREF obj, uint8_t* buffer, bool ignoreMovableObjects)
11576 // GC handle is null
11577 memset(buffer, 0, sizeof(CORINFO_OBJECT_HANDLE));
11580 else if (!ignoreMovableObjects || GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(OBJECTREFToObject(obj)))
11582 CORINFO_OBJECT_HANDLE handle = getJitHandleForObject(obj);
11583 memcpy(buffer, &handle, sizeof(CORINFO_OBJECT_HANDLE));
11589 bool CEEInfo::getStaticFieldContent(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects)
11597 _ASSERT(fieldHnd != NULL);
11598 _ASSERT(buffer != NULL);
11599 _ASSERT(bufferSize > 0);
11600 _ASSERT(valueOffset >= 0);
11602 bool result = false;
11604 JIT_TO_EE_TRANSITION();
11606 FieldDesc* field = (FieldDesc*)fieldHnd;
11607 _ASSERTE(field->IsStatic());
11609 MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
11610 _ASSERTE(!pEnclosingMT->IsSharedByGenericInstantiations());
11611 _ASSERTE(!pEnclosingMT->ContainsGenericVariables());
11613 // Allocate space for the local class if necessary, but don't trigger
11614 // class construction.
11615 DomainLocalModule* pLocalModule = pEnclosingMT->GetDomainLocalModule();
11616 pLocalModule->PopulateClass(pEnclosingMT);
11618 if (!field->IsThreadStatic() && pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes()))
11620 if (field->IsObjRef())
11624 _ASSERT(!field->IsRVA());
11625 _ASSERT(valueOffset == 0); // there is no point in returning a chunk of a gc handle
11626 _ASSERT((UINT)bufferSize == field->GetSize());
11628 result = getStaticObjRefContent(field->GetStaticOBJECTREF(), buffer, ignoreMovableObjects);
11632 UINT size = field->GetSize();
11633 _ASSERTE(size > 0);
11635 if (size >= (UINT)bufferSize && valueOffset >= 0 && (UINT)valueOffset <= size - (UINT)bufferSize)
11637 bool useMemcpy = false;
11639 // For structs containing GC pointers we want to make sure those GC pointers belong to FOH
11640 // so we expect valueOffset to be a real field offset (same for bufferSize)
11641 if (!field->IsRVA() && field->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
11643 TypeHandle structType = field->GetFieldTypeHandleThrowing();
11644 PTR_MethodTable structTypeMT = structType.AsMethodTable();
11645 if (!structTypeMT->ContainsPointers())
11647 // Fast-path: no GC pointers in the struct, we can use memcpy
11652 // The struct contains GC pointer(s), but we still can use memcpy if we don't intersect with them.
11653 unsigned numSlots = (structType.GetSize() + TARGET_POINTER_SIZE - 1) / TARGET_POINTER_SIZE;
11654 CQuickBytes gcPtrs;
11655 BYTE* ptr = static_cast<BYTE*>(gcPtrs.AllocThrows(numSlots));
11656 CEEInfo::getClassGClayoutStatic(structType, ptr);
11658 _ASSERT(numSlots > 0);
11661 for (unsigned i = 0; i < numSlots; i++)
11663 if (ptr[i] == TYPE_GC_NONE)
11669 const unsigned gcSlotBegin = i * TARGET_POINTER_SIZE;
11670 const unsigned gcSlotEnd = gcSlotBegin + TARGET_POINTER_SIZE;
11672 if (gcSlotBegin >= (unsigned)valueOffset && gcSlotEnd <= (unsigned)(valueOffset + bufferSize))
11674 // GC slot intersects with our valueOffset + bufferSize - we can't use memcpy...
11677 // ...unless we're interested in that GC slot's value itself
11678 if (gcSlotBegin == (unsigned)valueOffset && gcSlotEnd == (unsigned)(valueOffset + bufferSize) && ptr[i] == TYPE_GC_REF)
11682 size_t baseAddr = (size_t)field->GetCurrentStaticAddress();
11684 _ASSERT((UINT)bufferSize == sizeof(CORINFO_OBJECT_HANDLE));
11685 result = getStaticObjRefContent(ObjectToOBJECTREF(*(Object**)((uint8_t*)baseAddr + gcSlotBegin)), buffer, ignoreMovableObjects);
11688 // We had an intersection with a gc slot - no point in looking futher.
11696 // RVA data, no gc pointers
11705 size_t baseAddr = (size_t)field->GetCurrentStaticAddress();
11706 _ASSERT(baseAddr != 0);
11707 memcpy(buffer, (uint8_t*)baseAddr + valueOffset, bufferSize);
11713 EE_TO_JIT_TRANSITION();
11718 bool CEEInfo::getObjectContent(CORINFO_OBJECT_HANDLE handle, uint8_t* buffer, int bufferSize, int valueOffset)
11726 _ASSERT(handle != NULL);
11727 _ASSERT(buffer != NULL);
11728 _ASSERT(bufferSize > 0);
11729 _ASSERT(valueOffset >= 0);
11731 bool result = false;
11733 JIT_TO_EE_TRANSITION();
11736 OBJECTREF objRef = getObjectFromJitHandle(handle);
11737 _ASSERTE(objRef != NULL);
11739 // TODO: support types containing GC pointers
11740 if (bufferSize + valueOffset <= (int)objRef->GetSize())
11742 Object* obj = OBJECTREFToObject(objRef);
11743 PTR_MethodTable type = obj->GetMethodTable();
11744 if (type->ContainsPointers())
11746 // RuntimeType has a gc field (object m_keepAlive), but if the object is in a frozen segment
11747 // it means that field is always nullptr so we can read any part of the object:
11748 if (type == g_pRuntimeTypeClass && GCHeapUtilities::GetGCHeap()->IsInFrozenSegment(obj))
11750 memcpy(buffer, (uint8_t*)obj + valueOffset, bufferSize);
11756 memcpy(buffer, (uint8_t*)obj + valueOffset, bufferSize);
11761 EE_TO_JIT_TRANSITION();
11766 /*********************************************************************/
11767 CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
11768 bool* pIsSpeculative)
11776 CORINFO_CLASS_HANDLE result = NULL;
11778 if (pIsSpeculative != NULL)
11780 *pIsSpeculative = true;
11783 JIT_TO_EE_TRANSITION();
11785 FieldDesc* field = (FieldDesc*) fieldHnd;
11786 bool isClassInitialized = false;
11788 // We're only interested in ref class typed static fields
11789 // where the field handle specifies a unique location.
11790 if (field->IsStatic() && field->IsObjRef() && !field->IsThreadStatic())
11792 MethodTable* pEnclosingMT = field->GetEnclosingMethodTable();
11794 if (!pEnclosingMT->IsSharedByGenericInstantiations())
11796 // Allocate space for the local class if necessary, but don't trigger
11797 // class construction.
11798 DomainLocalModule *pLocalModule = pEnclosingMT->GetDomainLocalModule();
11799 pLocalModule->PopulateClass(pEnclosingMT);
11803 OBJECTREF fieldObj = field->GetStaticOBJECTREF();
11804 VALIDATEOBJECTREF(fieldObj);
11806 // Check for initialization before looking at the value
11807 isClassInitialized = !!pEnclosingMT->IsClassInited();
11809 if (fieldObj != NULL)
11811 MethodTable *pObjMT = fieldObj->GetMethodTable();
11813 // TODO: Check if the jit is allowed to embed this handle in jitted code.
11814 // Note for the initonly cases it probably won't embed.
11815 result = (CORINFO_CLASS_HANDLE) pObjMT;
11820 // Did we find a class?
11821 if (result != NULL)
11823 // Figure out what to report back.
11824 bool isResultImmutable = isClassInitialized && IsFdInitOnly(field->GetAttributes());
11826 if (pIsSpeculative != NULL)
11828 // Caller is ok with potentially mutable results.
11829 *pIsSpeculative = !isResultImmutable;
11833 // Caller only wants to see immutable results.
11834 if (!isResultImmutable)
11841 EE_TO_JIT_TRANSITION();
11846 /*********************************************************************/
11847 static void *GetClassSync(MethodTable *pMT)
11849 STANDARD_VM_CONTRACT;
11853 OBJECTREF ref = pMT->GetManagedClassObject();
11854 return (void*)ref->GetSyncBlock()->GetMonitor();
11857 /*********************************************************************/
11858 void* CEEJitInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
11859 void **ppIndirection)
11867 void * result = NULL;
11869 if (ppIndirection != NULL)
11870 *ppIndirection = NULL;
11872 JIT_TO_EE_TRANSITION();
11874 result = GetClassSync((GetMethod(ftnHnd))->GetMethodTable());
11876 EE_TO_JIT_TRANSITION();
11881 /*********************************************************************/
11882 HRESULT CEEJitInfo::allocPgoInstrumentationBySchema(
11883 CORINFO_METHOD_HANDLE ftnHnd, /* IN */
11884 PgoInstrumentationSchema* pSchema, /* IN/OUT */
11885 uint32_t countSchemaItems, /* IN */
11886 uint8_t** pInstrumentationData /* OUT */
11895 HRESULT hr = E_FAIL;
11897 JIT_TO_EE_TRANSITION();
11899 // We need to know the code size. Typically we can get the code size
11900 // from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so
11901 // for that case we need to use DynamicResolver to get the code size.
11903 unsigned codeSize = 0;
11904 if (m_pMethodBeingCompiled->IsDynamicMethod())
11906 unsigned stackSize, ehSize;
11907 CorInfoOptions options;
11908 DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver();
11909 pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize);
11913 codeSize = m_ILHeader->GetCodeSize();
11917 hr = PgoManager::allocPgoInstrumentationBySchema(m_pMethodBeingCompiled, pSchema, countSchemaItems, pInstrumentationData);
11919 _ASSERTE(!"allocMethodBlockCounts not implemented on CEEJitInfo!");
11921 #endif // !FEATURE_PGO
11923 EE_TO_JIT_TRANSITION();
11928 // Consider implementing getBBProfileData on CEEJitInfo. This will allow us
11929 // to use profile info in codegen for non zapped images.
11930 HRESULT CEEJitInfo::getPgoInstrumentationResults(
11931 CORINFO_METHOD_HANDLE ftnHnd,
11932 PgoInstrumentationSchema **pSchema, // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes)
11933 uint32_t * pCountSchemaItems, // pointer to the count schema items
11934 uint8_t ** pInstrumentationData, // pointer to the actual instrumentation data (pointer will not remain valid after jit completes)
11935 PgoSource * pPgoSource // source of pgo data
11944 HRESULT hr = E_FAIL;
11945 *pCountSchemaItems = 0;
11946 *pInstrumentationData = NULL;
11947 *pPgoSource = PgoSource::Unknown;
11949 JIT_TO_EE_TRANSITION();
11953 MethodDesc* pMD = (MethodDesc*)ftnHnd;
11954 ComputedPgoData* pDataCur = m_foundPgoData;
11956 // Search linked list of previously found pgo information
11957 for (; pDataCur != nullptr; pDataCur = pDataCur->m_next)
11959 if (pDataCur->m_pMD == pMD)
11965 if (pDataCur == nullptr)
11967 // If not found in previous list, gather it here, and add to linked list
11968 NewHolder<ComputedPgoData> newPgoData = new ComputedPgoData(pMD);
11969 newPgoData->m_next = m_foundPgoData;
11970 m_foundPgoData = newPgoData;
11971 newPgoData.SuppressRelease();
11973 newPgoData->m_hr = PgoManager::getPgoInstrumentationResults(pMD, &newPgoData->m_allocatedData, &newPgoData->m_schema,
11974 &newPgoData->m_cSchemaElems, &newPgoData->m_pInstrumentationData, &newPgoData->m_pgoSource);
11975 pDataCur = m_foundPgoData;
11978 *pSchema = pDataCur->m_schema;
11979 *pCountSchemaItems = pDataCur->m_cSchemaElems;
11980 *pInstrumentationData = pDataCur->m_pInstrumentationData;
11981 *pPgoSource = pDataCur->m_pgoSource;
11982 hr = pDataCur->m_hr;
11984 _ASSERTE(!"getPgoInstrumentationResults not implemented on CEEJitInfo!");
11988 EE_TO_JIT_TRANSITION();
11993 void CEEJitInfo::allocMem (AllocMemArgs *pArgs)
12001 JIT_TO_EE_TRANSITION();
12003 _ASSERTE(pArgs->coldCodeSize == 0);
12004 if (pArgs->coldCodeBlock)
12006 pArgs->coldCodeBlock = NULL;
12009 ULONG codeSize = pArgs->hotCodeSize;
12010 void **codeBlock = &pArgs->hotCodeBlock;
12011 void **codeBlockRW = &pArgs->hotCodeBlockRW;
12013 S_SIZE_T totalSize = S_SIZE_T(codeSize);
12015 size_t roDataAlignment = sizeof(void*);
12016 if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_RODATA_64BYTE_ALIGN)!= 0)
12018 roDataAlignment = 64;
12020 else if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_RODATA_32BYTE_ALIGN)!= 0)
12022 roDataAlignment = 32;
12024 else if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN)!= 0)
12026 roDataAlignment = 16;
12028 else if (pArgs->roDataSize >= 8)
12030 roDataAlignment = 8;
12032 if (pArgs->roDataSize > 0)
12034 size_t codeAlignment = sizeof(void*);
12036 if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_32BYTE_ALIGN) != 0)
12038 codeAlignment = 32;
12040 else if ((pArgs->flag & CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN) != 0)
12042 codeAlignment = 16;
12044 totalSize.AlignUp(codeAlignment);
12046 if (roDataAlignment > codeAlignment) {
12047 // Add padding to align read-only data.
12048 totalSize += (roDataAlignment - codeAlignment);
12050 totalSize += pArgs->roDataSize;
12053 #ifdef FEATURE_EH_FUNCLETS
12054 totalSize.AlignUp(sizeof(DWORD));
12055 totalSize += m_totalUnwindSize;
12058 _ASSERTE(m_CodeHeader == 0 &&
12059 // The jit-compiler sometimes tries to compile a method a second time
12060 // if it failed the first time. In such a situation, m_CodeHeader may
12061 // have already been assigned. Its OK to ignore this assert in such a
12062 // situation - we will leak some memory, but that is acceptable
12063 // since this should happen very rarely.
12064 "Note that this may fire if the JITCompiler tries to recompile a method");
12066 if( totalSize.IsOverflow() )
12068 COMPlusThrowHR(CORJIT_OUTOFMEM);
12071 if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, MethodJitMemoryAllocatedForCode))
12073 ULONGLONG ullMethodIdentifier = 0;
12074 ULONGLONG ullModuleID = 0;
12076 if (m_pMethodBeingCompiled)
12078 Module* pModule = m_pMethodBeingCompiled->GetModule();
12079 ullModuleID = (ULONGLONG)(TADDR)pModule;
12080 ullMethodIdentifier = (ULONGLONG)m_pMethodBeingCompiled;
12083 FireEtwMethodJitMemoryAllocatedForCode(ullMethodIdentifier, ullModuleID,
12084 pArgs->hotCodeSize + pArgs->coldCodeSize, pArgs->roDataSize, totalSize.Value(), pArgs->flag, GetClrInstanceId());
12087 m_jitManager->allocCode(m_pMethodBeingCompiled, totalSize.Value(), GetReserveForJumpStubs(), pArgs->flag, &m_CodeHeader, &m_CodeHeaderRW, &m_codeWriteBufferSize, &m_pCodeHeap
12088 #ifdef USE_INDIRECT_CODEHEADER
12089 , &m_pRealCodeHeader
12091 #ifdef FEATURE_EH_FUNCLETS
12092 , m_totalUnwindInfos
12096 #ifdef FEATURE_EH_FUNCLETS
12097 m_moduleBase = m_pCodeHeap->GetModuleBase();
12100 BYTE* current = (BYTE *)m_CodeHeader->GetCodeStartAddress();
12101 size_t writeableOffset = (BYTE *)m_CodeHeaderRW - (BYTE *)m_CodeHeader;
12103 *codeBlock = current;
12104 *codeBlockRW = current + writeableOffset;
12105 current += codeSize;
12107 if (pArgs->roDataSize > 0)
12109 current = (BYTE *)ALIGN_UP(current, roDataAlignment);
12110 pArgs->roDataBlock = current;
12111 pArgs->roDataBlockRW = current + writeableOffset;
12112 current += pArgs->roDataSize;
12116 pArgs->roDataBlock = NULL;
12117 pArgs->roDataBlockRW = NULL;
12120 #ifdef FEATURE_EH_FUNCLETS
12121 current = (BYTE *)ALIGN_UP(current, sizeof(DWORD));
12123 m_theUnwindBlock = current;
12124 current += m_totalUnwindSize;
12127 _ASSERTE((SIZE_T)(current - (BYTE *)m_CodeHeader->GetCodeStartAddress()) <= totalSize.Value());
12130 m_codeSize = codeSize;
12133 EE_TO_JIT_TRANSITION();
12136 /*********************************************************************/
12137 void * CEEJitInfo::allocGCInfo (size_t size)
12145 void * block = NULL;
12147 JIT_TO_EE_TRANSITION();
12149 _ASSERTE(m_CodeHeaderRW != 0);
12150 _ASSERTE(m_CodeHeaderRW->GetGCInfo() == 0);
12153 if (size & 0xFFFFFFFF80000000LL)
12155 COMPlusThrowHR(CORJIT_OUTOFMEM);
12157 #endif // HOST_64BIT
12159 block = m_jitManager->allocGCInfo(m_CodeHeaderRW,(DWORD)size, &m_GCinfo_len);
12162 COMPlusThrowHR(CORJIT_OUTOFMEM);
12165 _ASSERTE(m_CodeHeaderRW->GetGCInfo() != 0 && block == m_CodeHeaderRW->GetGCInfo());
12167 EE_TO_JIT_TRANSITION();
12172 /*********************************************************************/
12173 void CEEJitInfo::setEHcount (
12182 JIT_TO_EE_TRANSITION();
12184 _ASSERTE(cEH != 0);
12185 _ASSERTE(m_CodeHeaderRW != 0);
12186 _ASSERTE(m_CodeHeaderRW->GetEHInfo() == 0);
12188 EE_ILEXCEPTION* ret;
12189 ret = m_jitManager->allocEHInfo(m_CodeHeaderRW,cEH, &m_EHinfo_len);
12190 _ASSERTE(ret); // allocEHInfo throws if there's not enough memory
12192 _ASSERTE(m_CodeHeaderRW->GetEHInfo() != 0 && m_CodeHeaderRW->GetEHInfo()->EHCount() == cEH);
12194 EE_TO_JIT_TRANSITION();
12197 /*********************************************************************/
12198 void CEEJitInfo::setEHinfo (
12200 const CORINFO_EH_CLAUSE* clause)
12208 JIT_TO_EE_TRANSITION();
12210 // <REVISIT_TODO> Fix make the Code Manager EH clauses EH_INFO+</REVISIT_TODO>
12211 _ASSERTE(m_CodeHeaderRW->GetEHInfo() != 0 && EHnumber < m_CodeHeaderRW->GetEHInfo()->EHCount());
12213 EE_ILEXCEPTION_CLAUSE* pEHClause = m_CodeHeaderRW->GetEHInfo()->EHClause(EHnumber);
12215 pEHClause->TryStartPC = clause->TryOffset;
12216 pEHClause->TryEndPC = clause->TryLength;
12217 pEHClause->HandlerStartPC = clause->HandlerOffset;
12218 pEHClause->HandlerEndPC = clause->HandlerLength;
12219 pEHClause->ClassToken = clause->ClassToken;
12220 pEHClause->Flags = (CorExceptionFlag)clause->Flags;
12222 LOG((LF_EH, LL_INFO1000000, "Setting EH clause #%d for %s::%s\n", EHnumber, m_pMethodBeingCompiled->m_pszDebugClassName, m_pMethodBeingCompiled->m_pszDebugMethodName));
12223 LOG((LF_EH, LL_INFO1000000, " Flags : 0x%08lx -> 0x%08lx\n", clause->Flags, pEHClause->Flags));
12224 LOG((LF_EH, LL_INFO1000000, " TryOffset : 0x%08lx -> 0x%08lx (startpc)\n", clause->TryOffset, pEHClause->TryStartPC));
12225 LOG((LF_EH, LL_INFO1000000, " TryLength : 0x%08lx -> 0x%08lx (endpc)\n", clause->TryLength, pEHClause->TryEndPC));
12226 LOG((LF_EH, LL_INFO1000000, " HandlerOffset : 0x%08lx -> 0x%08lx\n", clause->HandlerOffset, pEHClause->HandlerStartPC));
12227 LOG((LF_EH, LL_INFO1000000, " HandlerLength : 0x%08lx -> 0x%08lx\n", clause->HandlerLength, pEHClause->HandlerEndPC));
12228 LOG((LF_EH, LL_INFO1000000, " ClassToken : 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->ClassToken));
12229 LOG((LF_EH, LL_INFO1000000, " FilterOffset : 0x%08lx -> 0x%08lx\n", clause->FilterOffset, pEHClause->FilterOffset));
12231 if (m_pMethodBeingCompiled->IsDynamicMethod() &&
12232 ((pEHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER) == 0) &&
12233 (clause->ClassToken != NULL))
12235 MethodDesc * pMD; FieldDesc * pFD;
12236 m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver()->ResolveToken(clause->ClassToken, (TypeHandle *)&pEHClause->TypeHandle, &pMD, &pFD);
12237 SetHasCachedTypeHandle(pEHClause);
12238 LOG((LF_EH, LL_INFO1000000, " CachedTypeHandle: 0x%08lx -> 0x%08lx\n", clause->ClassToken, pEHClause->TypeHandle));
12241 EE_TO_JIT_TRANSITION();
12244 /*********************************************************************/
12245 // get individual exception handler
12246 void CEEJitInfo::getEHinfo(
12247 CORINFO_METHOD_HANDLE ftn, /* IN */
12248 unsigned EHnumber, /* IN */
12249 CORINFO_EH_CLAUSE* clause) /* OUT */
12257 JIT_TO_EE_TRANSITION();
12259 if (IsDynamicMethodHandle(ftn))
12261 GetMethod(ftn)->AsDynamicMethodDesc()->GetResolver()->GetEHInfo(EHnumber, clause);
12265 _ASSERTE(ftn == CORINFO_METHOD_HANDLE(m_pMethodBeingCompiled)); // For now only support if the method being jitted
12266 getEHinfoHelper(ftn, EHnumber, clause, m_ILHeader);
12269 EE_TO_JIT_TRANSITION();
12275 #ifdef FEATURE_INTERPRETER
12276 static CorJitResult CompileMethodWithEtwWrapper(EEJitManager *jitMgr,
12278 struct CORINFO_METHOD_INFO *info,
12280 BYTE **nativeEntry,
12281 ULONG *nativeSizeOfCode)
12283 STATIC_CONTRACT_THROWS;
12284 STATIC_CONTRACT_GC_TRIGGERS;
12285 STATIC_CONTRACT_MODE_PREEMPTIVE;
12287 SString namespaceOrClassName, methodName, methodSignature;
12288 // Fire an ETW event to mark the beginning of JIT'ing
12289 ETW::MethodLog::MethodJitting(reinterpret_cast<MethodDesc*>(info->ftn), NULL, &namespaceOrClassName, &methodName, &methodSignature);
12291 CorJitResult ret = jitMgr->m_jit->compileMethod(comp, info, flags, nativeEntry, nativeSizeOfCode);
12293 // Logically, it would seem that the end-of-JITting ETW even should go here, but it must come after the native code has been
12294 // set for the given method desc, which happens in a caller.
12298 #endif // FEATURE_INTERPRETER
12301 // Helper function because can't have dtors in BEGIN_SO_TOLERANT_CODE.
12303 CorJitResult invokeCompileMethodHelper(EEJitManager *jitMgr,
12305 struct CORINFO_METHOD_INFO *info,
12306 CORJIT_FLAGS jitFlags,
12307 BYTE **nativeEntry,
12308 uint32_t *nativeSizeOfCode)
12310 STATIC_CONTRACT_THROWS;
12311 STATIC_CONTRACT_GC_TRIGGERS;
12312 STATIC_CONTRACT_MODE_PREEMPTIVE;
12314 CorJitResult ret = CORJIT_SKIPPED; // Note that CORJIT_SKIPPED is an error exit status code
12316 #if defined(ALLOW_SXS_JIT)
12317 if (FAILED(ret) && jitMgr->m_alternateJit)
12319 CORJIT_FLAGS altJitFlags = jitFlags;
12320 altJitFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_ALT_JIT);
12321 comp->setJitFlags(altJitFlags);
12322 ret = jitMgr->m_alternateJit->compileMethod( comp,
12324 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12328 // If we failed to jit, then fall back to the primary Jit.
12331 ((CEEJitInfo*)comp)->BackoutJitData(jitMgr);
12332 ((CEEJitInfo*)comp)->ResetForJitRetry();
12333 ret = CORJIT_SKIPPED;
12336 #endif // defined(ALLOW_SXS_JIT)
12337 comp->setJitFlags(jitFlags);
12339 #ifdef FEATURE_INTERPRETER
12340 static ConfigDWORD s_InterpreterFallback;
12341 static ConfigDWORD s_ForceInterpreter;
12343 bool isInterpreterStub = false;
12344 bool interpreterFallback = (s_InterpreterFallback.val(CLRConfig::INTERNAL_InterpreterFallback) != 0);
12345 bool forceInterpreter = (s_ForceInterpreter.val(CLRConfig::INTERNAL_ForceInterpreter) != 0);
12347 if (interpreterFallback == false)
12349 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
12350 // (We assume that importation is completely architecture-independent, or at least nearly so.)
12352 (forceInterpreter || !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE)))
12354 if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
12356 isInterpreterStub = true;
12361 if (FAILED(ret) && jitMgr->m_jit)
12363 ret = CompileMethodWithEtwWrapper(jitMgr,
12366 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12371 if (interpreterFallback == true)
12373 // If we're doing an "import_only" compilation, it's for verification, so don't interpret.
12374 // (We assume that importation is completely architecture-independent, or at least nearly so.)
12376 (forceInterpreter || !jitFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE)))
12378 if (SUCCEEDED(ret = Interpreter::GenerateInterpreterStub(comp, info, nativeEntry, nativeSizeOfCode)))
12380 isInterpreterStub = true;
12387 ret = jitMgr->m_jit->compileMethod( comp,
12389 CORJIT_FLAGS::CORJIT_FLAG_CALL_GETJITFLAGS,
12393 #endif // FEATURE_INTERPRETER
12395 // Cleanup any internal data structures allocated
12396 // such as IL code after a successful JIT compile
12397 // If the JIT fails we keep the IL around and will
12398 // try reJIT the same IL. VSW 525059
12400 if (SUCCEEDED(ret) && !((CEEJitInfo*)comp)->JitAgain())
12402 ((CEEJitInfo*)comp)->CompressDebugInfo();
12404 #ifdef FEATURE_INTERPRETER
12405 // We do this cleanup in the prestub, where we know whether the method
12406 // has been interpreted.
12408 comp->MethodCompileComplete(info->ftn);
12409 #endif // FEATURE_INTERPRETER
12413 #if defined(FEATURE_GDBJIT)
12414 bool isJittedEntry = SUCCEEDED(ret) && *nativeEntry != NULL;
12416 #ifdef FEATURE_INTERPRETER
12417 isJittedEntry &= !isInterpreterStub;
12418 #endif // FEATURE_INTERPRETER
12422 CodeHeader* pCH = ((CodeHeader*)((PCODE)*nativeEntry & ~1)) - 1;
12423 pCH->SetCalledMethods((PTR_VOID)comp->GetCalledMethods());
12431 /*********************************************************************/
12432 CorJitResult invokeCompileMethod(EEJitManager *jitMgr,
12434 struct CORINFO_METHOD_INFO *info,
12435 CORJIT_FLAGS jitFlags,
12436 BYTE **nativeEntry,
12437 uint32_t *nativeSizeOfCode)
12445 // The JIT runs in preemptive mode
12450 CorJitResult ret = invokeCompileMethodHelper(jitMgr, comp, info, jitFlags, nativeEntry, nativeSizeOfCode);
12453 // Verify that we are still in preemptive mode when we return
12457 _ASSERTE(GetThread()->PreemptiveGCDisabled() == FALSE);
12462 /*********************************************************************/
12463 // Figures out the compile flags that are used by both JIT and NGen
12465 /* static */ CORJIT_FLAGS CEEInfo::GetBaseCompileFlags(MethodDesc * ftn)
12473 // Figure out the code quality flags
12476 CORJIT_FLAGS flags;
12477 if (g_pConfig->JitFramed())
12478 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12480 // Set flags based on method's ImplFlags.
12481 if (!ftn->IsNoMetadata())
12483 DWORD dwImplFlags = 0;
12484 IfFailThrow(ftn->GetMDImport()->GetMethodImplProps(ftn->GetMemberDef(), NULL, &dwImplFlags));
12486 if (IsMiNoOptimization(dwImplFlags))
12488 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12491 // Always emit frames for methods marked no-inline (see #define ETW_EBP_FRAMED in the JIT)
12492 if (IsMiNoInlining(dwImplFlags))
12494 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FRAMED);
12498 if (ftn->HasUnmanagedCallersOnlyAttribute())
12500 // If the stub was generated by the runtime, don't validate
12501 // it for UnmanagedCallersOnlyAttribute usage. There are cases
12502 // where the validation doesn't handle all of the cases we can
12503 // permit during stub generation (e.g. Vector2 returns).
12504 if (!ftn->IsILStub())
12505 COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(ftn);
12507 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_REVERSE_PINVOKE);
12509 // If we're a reverse IL stub, we need to use the TrackTransitions variant
12510 // so we have the target MethodDesc entrypoint to tell the debugger about.
12511 if (CORProfilerTrackTransitions() || ftn->IsILStub())
12513 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_TRACK_TRANSITIONS);
12520 /*********************************************************************/
12521 // Figures out (some of) the flags to use to compile the method
12522 // Returns the new set to use
12524 CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags)
12526 STANDARD_VM_CONTRACT;
12528 //Right now if we don't have a debug interface on CoreCLR, we can't generate debug info. So, in those
12529 //cases don't attempt it.
12530 if (!g_pDebugInterface)
12533 #ifdef DEBUGGING_SUPPORTED
12536 if (g_pConfig->GenDebuggableCode())
12537 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12540 #ifdef EnC_SUPPORTED
12541 if (pModule->IsEditAndContinueEnabled())
12543 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_EnC);
12545 #endif // EnC_SUPPORTED
12547 // Debug info is always tracked
12548 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12549 #endif // DEBUGGING_SUPPORTED
12551 if (CORDisableJITOptimizations(pModule->GetDebuggerInfoBits()))
12553 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
12559 static CORJIT_FLAGS GetCompileFlags(PrepareCodeConfig* prepareConfig, MethodDesc* ftn, CORINFO_METHOD_INFO* methodInfo)
12561 STANDARD_VM_CONTRACT;
12562 _ASSERTE(prepareConfig != NULL);
12563 _ASSERTE(ftn != NULL);
12564 _ASSERTE(methodInfo->regionKind == CORINFO_REGION_JIT);
12566 CORJIT_FLAGS flags = prepareConfig->GetJitCompilationFlags();
12569 // Get the compile flags that are shared between JIT and NGen
12571 flags.Add(CEEInfo::GetBaseCompileFlags(ftn));
12574 // Get CPU specific flags
12576 flags.Add(ExecutionManager::GetEEJitManager()->GetCPUCompileFlags());
12579 // Find the debugger and profiler related flags
12582 #ifdef DEBUGGING_SUPPORTED
12583 flags.Add(GetDebuggerCompileFlags(ftn->GetModule(), flags));
12586 #ifdef PROFILING_SUPPORTED
12587 if (CORProfilerTrackEnterLeave() && !ftn->IsNoMetadata())
12588 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_ENTERLEAVE);
12590 if (CORProfilerTrackTransitions())
12591 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_PROF_NO_PINVOKE_INLINE);
12592 #endif // PROFILING_SUPPORTED
12594 // Don't allow allocations on FOH from collectible contexts to avoid memory leaks
12595 if (!ftn->GetLoaderAllocator()->CanUnload())
12597 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_FROZEN_ALLOC_ALLOWED);
12600 // Set optimization flags
12601 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT))
12603 unsigned optType = g_pConfig->GenOptimizeType();
12604 _ASSERTE(optType <= OPT_RANDOM);
12606 if (optType == OPT_RANDOM)
12607 optType = methodInfo->ILCodeSize % OPT_RANDOM;
12609 if (g_pConfig->JitMinOpts())
12611 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MIN_OPT);
12615 if (!flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER0))
12616 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBOPT);
12619 if (optType == OPT_SIZE)
12621 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SIZE_OPT);
12623 else if (optType == OPT_SPEED)
12625 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SPEED_OPT);
12629 if (IsDynamicScope(methodInfo->scope))
12631 // no debug info available for IL stubs
12632 if (!g_pConfig->GetTrackDynamicMethodDebugInfo())
12633 flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
12635 DynamicResolver* pResolver = GetDynamicResolver(methodInfo->scope);
12636 flags.Add(pResolver->GetJitFlags());
12640 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_SOFTFP_ABI);
12641 #endif // ARM_SOFTFP
12645 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ReadPGOData) > 0)
12647 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBOPT);
12649 else if (g_pConfig->TieredPGO() && flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER1))
12651 flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBOPT);
12659 // ********************************************************************
12661 // Throw the right type of exception for the given JIT result
12663 void ThrowExceptionForJit(HRESULT res)
12674 case CORJIT_OUTOFMEM:
12678 case CORJIT_INTERNALERROR:
12679 COMPlusThrow(kInvalidProgramException, (UINT) IDS_EE_JIT_COMPILER_ERROR);
12682 case CORJIT_BADCODE:
12683 case CORJIT_IMPLLIMITATION:
12685 COMPlusThrow(kInvalidProgramException);
12690 // ********************************************************************
12691 //#define PERF_TRACK_METHOD_JITTIMES
12692 #ifdef TARGET_AMD64
12693 BOOL g_fAllowRel32 = TRUE;
12697 // ********************************************************************
12699 // ********************************************************************
12701 // The reason that this is named UnsafeJitFunction is that this helper
12702 // method is not thread safe! When multiple threads get in here for
12703 // the same pMD, ALL of them MUST return the SAME value.
12704 // To insure that this happens you must call MakeJitWorker.
12705 // It creates a DeadlockAware list of methods being jitted and prevents us
12706 // from trying to jit the same method more that once.
12708 // Calls to this method that occur to check if inlining can occur on x86,
12709 // are OK since they discard the return value of this method.
12710 PCODE UnsafeJitFunction(PrepareCodeConfig* config,
12711 _In_opt_ COR_ILMETHOD_DECODER* ILHeader,
12712 _In_ CORJIT_FLAGS* pJitFlags,
12713 _In_opt_ ULONG* pSizeOfCode)
12715 STANDARD_VM_CONTRACT;
12716 _ASSERTE(config != NULL);
12717 _ASSERTE(pJitFlags != NULL);
12719 NativeCodeVersion nativeCodeVersion = config->GetCodeVersion();
12720 MethodDesc* ftn = nativeCodeVersion.GetMethodDesc();
12723 NormalizedTimer timer;
12724 int64_t c100nsTicksInJit = 0;
12726 COOPERATIVE_TRANSITION_BEGIN();
12730 EEJitManager *jitMgr = ExecutionManager::GetEEJitManager();
12731 if (!jitMgr->LoadJIT())
12733 #ifdef ALLOW_SXS_JIT
12734 if (!jitMgr->IsMainJitLoaded())
12736 // Don't want to throw InvalidProgram from here.
12737 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12739 if (!jitMgr->IsAltJitLoaded())
12741 // Don't want to throw InvalidProgram from here.
12742 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load alternative JIT compiler"));
12744 #else // ALLOW_SXS_JIT
12745 // Don't want to throw InvalidProgram from here.
12746 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_EXECUTIONENGINE, W("Failed to load JIT compiler"));
12747 #endif // ALLOW_SXS_JIT
12751 // This is here so we can see the name and class easily in the debugger
12753 LPCUTF8 cls = ftn->GetMethodTable()->GetDebugClassName();
12754 LPCUTF8 name = ftn->GetName();
12756 if (ftn->IsNoMetadata())
12758 if (ftn->IsILStub())
12760 LOG((LF_JIT, LL_INFO10000, "{ Jitting IL Stub }\n"));
12764 LOG((LF_JIT, LL_INFO10000, "{ Jitting dynamic method }\n"));
12769 SString methodString;
12770 if (LoggingOn(LF_JIT, LL_INFO10000))
12771 TypeString::AppendMethodDebug(methodString, ftn);
12773 LOG((LF_JIT, LL_INFO10000, "{ Jitting method (%p) %s %s\n", ftn, methodString.GetUTF8(), ftn->m_pszDebugMethodSignature));
12777 MethodInfoHelperContext cxt{ ftn, ILHeader };
12778 CORINFO_METHOD_INFO methodInfo;
12779 getMethodInfoHelper(cxt, &methodInfo);
12781 // If it's generic then we can only enter through an instantiated MethodDesc
12782 _ASSERTE(!ftn->IsGenericMethodDefinition());
12784 // method attributes and signature are consistant
12785 _ASSERTE(!!ftn->IsStatic() == ((methodInfo.args.callConv & CORINFO_CALLCONV_HASTHIS) == 0));
12787 *pJitFlags = GetCompileFlags(config, ftn, &methodInfo);
12789 #if defined(TARGET_AMD64) || defined(TARGET_ARM64)
12790 BOOL fForceJumpStubOverflow = FALSE;
12793 // Always exercise the overflow codepath with force relocs
12794 if (PEDecoder::GetForceRelocs())
12795 fForceJumpStubOverflow = TRUE;
12798 #if defined(TARGET_AMD64)
12799 BOOL fAllowRel32 = (g_fAllowRel32 | fForceJumpStubOverflow) && g_pConfig->JitEnableOptionalRelocs();
12802 size_t reserveForJumpStubs = 0;
12804 #endif // defined(TARGET_AMD64) || defined(TARGET_ARM64)
12808 CEEJitInfo jitInfo(ftn, ILHeader, jitMgr, !pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING));
12810 #if defined(TARGET_AMD64) || defined(TARGET_ARM64)
12811 #if defined(TARGET_AMD64)
12812 if (fForceJumpStubOverflow)
12813 jitInfo.SetJumpStubOverflow(fAllowRel32);
12814 jitInfo.SetAllowRel32(fAllowRel32);
12816 if (fForceJumpStubOverflow)
12817 jitInfo.SetJumpStubOverflow(fForceJumpStubOverflow);
12819 jitInfo.SetReserveForJumpStubs(reserveForJumpStubs);
12820 #endif // defined(TARGET_AMD64) || defined(TARGET_ARM64)
12822 #ifdef FEATURE_ON_STACK_REPLACEMENT
12823 // If this is an OSR jit request, grab the OSR info so we can pass it to the jit
12824 if (pJitFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_OSR))
12826 unsigned ilOffset = 0;
12827 PatchpointInfo* patchpointInfo = nativeCodeVersion.GetOSRInfo(&ilOffset);
12828 jitInfo.SetOSRInfo(patchpointInfo, ilOffset);
12830 #endif // FEATURE_ON_STACK_REPLACEMENT
12832 if (cxt.HasTransientMethodDetails())
12833 jitInfo.AddTransientMethodDetails(cxt.CreateTransientMethodDetails());
12835 MethodDesc * pMethodForSecurity = jitInfo.GetMethodForSecurity(methodInfo.ftn);
12837 //Since the check could trigger a demand, we have to do this every time.
12838 //This is actually an overly complicated way to make sure that a method can access all its arguments
12839 //and its return type.
12840 AccessCheckOptions::AccessCheckType accessCheckType = AccessCheckOptions::kNormalAccessibilityChecks;
12841 TypeHandle ownerTypeForSecurity = TypeHandle(pMethodForSecurity->GetMethodTable());
12842 DynamicResolver *pAccessContext = NULL;
12843 BOOL doAccessCheck = TRUE;
12844 if (pMethodForSecurity->IsDynamicMethod())
12846 doAccessCheck = ModifyCheckForDynamicMethod(pMethodForSecurity->AsDynamicMethodDesc()->GetResolver(),
12847 &ownerTypeForSecurity,
12848 &accessCheckType, &pAccessContext);
12852 AccessCheckOptions accessCheckOptions(accessCheckType,
12854 TRUE /*Throw on error*/,
12855 pMethodForSecurity);
12857 AccessCheckContext accessContext(pMethodForSecurity, ownerTypeForSecurity.GetMethodTable());
12859 // We now do an access check from pMethodForSecurity to pMethodForSecurity, its sole purpose is to
12860 // verify that pMethodForSecurity/ownerTypeForSecurity has access to all its parameters.
12862 // ownerTypeForSecurity.GetMethodTable() can be null if the pMethodForSecurity is a DynamicMethod
12863 // associated with a TypeDesc (Array, Ptr, Ref, or FnPtr). That doesn't make any sense, but we will
12864 // just do an access check from a NULL context which means only public types are accessible.
12865 if (!ClassLoader::CanAccess(&accessContext,
12866 ownerTypeForSecurity.GetMethodTable(),
12867 ownerTypeForSecurity.GetAssembly(),
12868 pMethodForSecurity->GetAttrs(),
12869 pMethodForSecurity,
12871 accessCheckOptions))
12873 EX_THROW(EEMethodException, (pMethodForSecurity));
12879 uint32_t sizeOfCode;
12884 /* There is a double indirection to call compileMethod - can we
12885 improve this with the new structure? */
12887 #ifdef PERF_TRACK_METHOD_JITTIMES
12888 //Because we're not calling QPC enough. I'm not going to track times if we're just importing.
12889 LARGE_INTEGER methodJitTimeStart = {0};
12890 QueryPerformanceCounter (&methodJitTimeStart);
12893 LOG((LF_CORDB, LL_EVERYTHING, "Calling invokeCompileMethod...\n"));
12895 res = invokeCompileMethod(jitMgr,
12902 LOG((LF_CORDB, LL_EVERYTHING, "Got through invokeCompileMethod\n"));
12904 #if FEATURE_PERFMAP
12905 // Save the code size so that it can be reported to the perfmap.
12906 if (pSizeOfCode != NULL)
12908 *pSizeOfCode = sizeOfCode;
12912 #ifdef PERF_TRACK_METHOD_JITTIMES
12913 //store the time in the string buffer. Module name and token are unique enough. Also, do not
12914 //capture importing time, just actual compilation time.
12916 LARGE_INTEGER methodJitTimeStop;
12917 QueryPerformanceCounter(&methodJitTimeStop);
12919 SString moduleName;
12920 ftn->GetModule()->GetDomainAssembly()->GetPEAssembly()->GetPathOrCodeBase(moduleName);
12923 codeBase.AppendPrintf("%s,0x%x,%d,%d\n",
12924 moduleName.GetUTF8(), //module name
12925 ftn->GetMemberDef(), //method token
12926 (unsigned)(methodJitTimeStop.QuadPart - methodJitTimeStart.QuadPart), //cycle count
12927 methodInfo.ILCodeSize //il size
12929 OutputDebugStringUtf8(codeBase.GetUTF8());
12931 #endif // PERF_TRACK_METHOD_JITTIMES
12935 LOG((LF_JIT, LL_INFO10000, "Done Jitting method %s::%s %s }\n",cls,name, ftn->m_pszDebugMethodSignature));
12937 if (SUCCEEDED(res))
12939 jitInfo.WriteCode(jitMgr);
12940 #if defined(DEBUGGING_SUPPORTED)
12942 // Notify the debugger that we have successfully jitted the function
12944 if (g_pDebugInterface)
12946 if (!jitInfo.JitAgain())
12948 g_pDebugInterface->JITComplete(nativeCodeVersion, (TADDR)nativeEntry);
12951 #endif // DEBUGGING_SUPPORTED
12955 jitInfo.BackoutJitData(jitMgr);
12956 ThrowExceptionForJit(res);
12960 COMPlusThrow(kInvalidProgramException);
12962 #if (defined(TARGET_AMD64) || defined(TARGET_ARM64))
12963 if (jitInfo.IsJumpStubOverflow())
12965 // Backout and try again with fAllowRel32 == FALSE.
12966 jitInfo.BackoutJitData(jitMgr);
12968 #ifdef TARGET_AMD64
12969 // Disallow rel32 relocs in future.
12970 g_fAllowRel32 = FALSE;
12972 fAllowRel32 = FALSE;
12973 #endif // TARGET_AMD64
12974 #ifdef TARGET_ARM64
12975 fForceJumpStubOverflow = FALSE;
12976 #endif // TARGET_ARM64
12978 reserveForJumpStubs = jitInfo.GetReserveForJumpStubs();
12980 // Get any transient method details and take ownership
12981 // from the JITInfo instance. We are going to be recreating
12982 // a new JITInfo and will reuse these details there.
12983 TransientMethodDetails details = jitInfo.RemoveTransientMethodDetails(ftn);
12984 cxt.TakeOwnership(std::move(details));
12987 #endif // (TARGET_AMD64 || TARGET_ARM64)
12989 LOG((LF_JIT, LL_INFO10000,
12990 "Jitted Entry at" FMT_ADDR "method %s::%s %s\n", DBG_ADDR(nativeEntry),
12991 ftn->m_pszDebugClassName, ftn->m_pszDebugMethodName, ftn->m_pszDebugMethodSignature));
12994 LPCUTF8 pszDebugClassName = ftn->m_pszDebugClassName;
12995 LPCUTF8 pszDebugMethodName = ftn->m_pszDebugMethodName;
12996 LPCUTF8 pszDebugMethodSignature = ftn->m_pszDebugMethodSignature;
12998 LPCUTF8 pszNamespace;
12999 LPCUTF8 pszDebugClassName = ftn->GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace);
13000 LPCUTF8 pszDebugMethodName = ftn->GetName();
13001 LPCUTF8 pszDebugMethodSignature = "";
13004 //DbgPrintf("Jitted Entry at" FMT_ADDR "method %s::%s %s size %08x\n", DBG_ADDR(nativeEntry),
13005 // pszDebugClassName, pszDebugMethodName, pszDebugMethodSignature, sizeOfCode);
13007 // For dynamic method, the code memory may be reused, thus we are passing in the hasCodeExecutedBefore set to true
13008 ClrFlushInstructionCache(nativeEntry, sizeOfCode, /* hasCodeExecutedBefore */ true);
13009 ret = (PCODE)nativeEntry;
13020 static BOOL fHeartbeat = -1;
13022 if (fHeartbeat == -1)
13023 fHeartbeat = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_JitHeartbeat);
13030 c100nsTicksInJit = timer.Elapsed100nsTicks();
13032 InterlockedExchangeAdd64((LONG64*)&g_c100nsTicksInJit, c100nsTicksInJit);
13033 t_c100nsTicksInJitForThread += c100nsTicksInJit;
13035 InterlockedExchangeAdd64((LONG64*)&g_cbILJitted, methodInfo.ILCodeSize);
13036 t_cbILJittedForThread += methodInfo.ILCodeSize;
13038 InterlockedIncrement64((LONG64*)&g_cMethodsJitted);
13039 t_cMethodsJittedForThread++;
13041 COOPERATIVE_TRANSITION_END();
13045 #ifdef FEATURE_READYTORUN
13046 CorInfoHelpFunc MapReadyToRunHelper(ReadyToRunHelper helperNum)
13048 LIMITED_METHOD_CONTRACT;
13052 #define HELPER(readyToRunHelper, corInfoHelpFunc, flags) \
13053 case readyToRunHelper: return corInfoHelpFunc;
13054 #include "readytorunhelpers.h"
13056 case READYTORUN_HELPER_GetString: return CORINFO_HELP_STRCNS;
13058 default: return CORINFO_HELP_UNDEF;
13062 void ComputeGCRefMap(MethodTable * pMT, BYTE * pGCRefMap, size_t cbGCRefMap)
13064 STANDARD_VM_CONTRACT;
13066 ZeroMemory(pGCRefMap, cbGCRefMap);
13068 if (!pMT->ContainsPointers())
13071 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
13072 CGCDescSeries* cur = map->GetHighestSeries();
13073 CGCDescSeries* last = map->GetLowestSeries();
13074 DWORD size = pMT->GetBaseSize();
13075 _ASSERTE(cur >= last);
13079 // offset to embedded references in this series must be
13080 // adjusted by the VTable pointer, when in the unboxed state.
13081 size_t offset = cur->GetSeriesOffset() - TARGET_POINTER_SIZE;
13082 size_t offsetStop = offset + cur->GetSeriesSize() + size;
13083 while (offset < offsetStop)
13085 size_t bit = offset / TARGET_POINTER_SIZE;
13087 size_t index = bit / 8;
13088 _ASSERTE(index < cbGCRefMap);
13089 pGCRefMap[index] |= (1 << (bit & 7));
13091 offset += TARGET_POINTER_SIZE;
13094 } while (cur >= last);
13098 // Type layout check verifies that there was no incompatible change in the value type layout.
13099 // If there was one, we will fall back to JIT instead of using the pre-generated code from the ready to run image.
13100 // This should be rare situation. Changes in value type layout not common.
13102 // The following properties of the value type layout are checked:
13104 // - HFA-ness (on platform that support HFAs)
13106 // - Position of GC references
13108 BOOL TypeLayoutCheck(MethodTable * pMT, PCCOR_SIGNATURE pBlob, BOOL printDiff)
13110 STANDARD_VM_CONTRACT;
13112 SigPointer p(pBlob);
13113 IfFailThrow(p.SkipExactlyOne());
13116 IfFailThrow(p.GetData(&dwFlags));
13118 BOOL result = TRUE;
13120 // Size is checked unconditionally
13121 uint32_t dwExpectedSize;
13122 IfFailThrow(p.GetData(&dwExpectedSize));
13124 DWORD dwActualSize = pMT->GetNumInstanceFieldBytes();
13125 if (dwExpectedSize != dwActualSize)
13131 DefineFullyQualifiedNameForClass();
13132 printf("Type %s: expected size 0x%08x, actual size 0x%08x\n",
13133 GetFullyQualifiedNameForClass(pMT), dwExpectedSize, dwActualSize);
13142 if (dwFlags & READYTORUN_LAYOUT_HFA)
13144 uint32_t dwExpectedHFAType;
13145 IfFailThrow(p.GetData(&dwExpectedHFAType));
13147 DWORD dwActualHFAType = pMT->GetHFAType();
13148 if (dwExpectedHFAType != dwActualHFAType)
13154 DefineFullyQualifiedNameForClass();
13155 printf("Type %s: expected HFA type %08x, actual %08x\n",
13156 GetFullyQualifiedNameForClass(pMT), dwExpectedHFAType, dwActualHFAType);
13172 DefineFullyQualifiedNameForClass();
13173 printf("Type %s: type is HFA but READYTORUN_LAYOUT_HFA flag is not set\n",
13174 GetFullyQualifiedNameForClass(pMT));
13183 _ASSERTE(!(dwFlags & READYTORUN_LAYOUT_HFA));
13186 if (dwFlags & READYTORUN_LAYOUT_Alignment)
13188 uint32_t dwExpectedAlignment = TARGET_POINTER_SIZE;
13189 if (!(dwFlags & READYTORUN_LAYOUT_Alignment_Native))
13191 IfFailThrow(p.GetData(&dwExpectedAlignment));
13194 DWORD dwActualAlignment = CEEInfo::getClassAlignmentRequirementStatic(pMT);
13195 if (dwExpectedAlignment != dwActualAlignment)
13201 DefineFullyQualifiedNameForClass();
13202 printf("Type %s: expected alignment 0x%08x, actual 0x%08x\n",
13203 GetFullyQualifiedNameForClass(pMT), dwExpectedAlignment, dwActualAlignment);
13213 if (dwFlags & READYTORUN_LAYOUT_GCLayout)
13215 if (dwFlags & READYTORUN_LAYOUT_GCLayout_Empty)
13217 if (pMT->ContainsPointers())
13223 DefineFullyQualifiedNameForClass();
13224 printf("Type %s contains pointers but READYTORUN_LAYOUT_GCLayout_Empty is set\n",
13225 GetFullyQualifiedNameForClass(pMT));
13235 size_t cbGCRefMap = (dwActualSize / TARGET_POINTER_SIZE + 7) / 8;
13236 _ASSERTE(cbGCRefMap > 0);
13238 BYTE * pGCRefMap = (BYTE *)_alloca(cbGCRefMap);
13240 ComputeGCRefMap(pMT, pGCRefMap, cbGCRefMap);
13242 if (memcmp(pGCRefMap, p.GetPtr(), cbGCRefMap) != 0)
13248 DefineFullyQualifiedNameForClass();
13249 printf("Type %s: GC refmap content doesn't match\n",
13250 GetFullyQualifiedNameForClass(pMT));
13263 #endif // FEATURE_READYTORUN
13265 bool IsInstructionSetSupported(CORJIT_FLAGS jitFlags, ReadyToRunInstructionSet r2rInstructionSet)
13267 CORINFO_InstructionSet instructionSet = InstructionSetFromR2RInstructionSet(r2rInstructionSet);
13268 return jitFlags.IsSet(instructionSet);
13271 BOOL LoadDynamicInfoEntry(Module *currentModule,
13274 BOOL mayUsePrecompiledNDirectMethods)
13276 STANDARD_VM_CONTRACT;
13278 PCCOR_SIGNATURE pBlob = currentModule->GetNativeFixupBlobData(fixupRva);
13280 BYTE kind = *pBlob++;
13282 ModuleBase * pInfoModule = currentModule;
13284 if (kind & ENCODE_MODULE_OVERRIDE)
13286 pInfoModule = currentModule->GetModuleFromIndex(CorSigUncompressData(pBlob));
13287 kind &= ~ENCODE_MODULE_OVERRIDE;
13290 MethodDesc * pMD = NULL;
13292 PCCOR_SIGNATURE pSig;
13299 case ENCODE_MODULE_HANDLE:
13300 result = (size_t)pInfoModule;
13303 case ENCODE_TYPE_HANDLE:
13304 case ENCODE_TYPE_DICTIONARY:
13306 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13308 if (!th.IsTypeDesc())
13310 if (currentModule->IsReadyToRun())
13312 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13313 th.AsMethodTable()->EnsureInstanceActive();
13317 result = (size_t)th.AsPtr();
13321 case ENCODE_METHOD_HANDLE:
13322 case ENCODE_METHOD_DICTIONARY:
13324 MethodDesc * pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13326 if (currentModule->IsReadyToRun())
13328 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13329 pMD->EnsureActive();
13332 result = (size_t)pMD;
13336 case ENCODE_FIELD_HANDLE:
13337 result = (size_t) ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13340 case ENCODE_STRING_HANDLE:
13342 // We need to update strings atomically (due to NoStringInterning attribute). Note
13343 // that modules with string interning dont really need this, as the hash tables have
13344 // their own locking, but dont add more complexity for what will be the non common
13347 // We will have to lock and update the entry. (this is really a double check, where
13348 // the first check is done in the caller of this function)
13349 DWORD rid = CorSigUncompressData(pBlob);
13353 result = (size_t)StringObject::GetEmptyStringRefPtr(nullptr);
13357 result = (size_t) pInfoModule->ResolveStringRef(TokenFromRid(rid, mdtString));
13362 case ENCODE_VARARGS_SIG:
13364 mdSignature token = TokenFromRid(
13365 CorSigUncompressData(pBlob),
13368 IfFailThrow(pInfoModule->GetMDImport()->GetSigFromToken(token, &cSig, &pSig));
13374 case ENCODE_VARARGS_METHODREF:
13376 mdSignature token = TokenFromRid(
13377 CorSigUncompressData(pBlob),
13380 LPCSTR szName_Ignore;
13381 IfFailThrow(pInfoModule->GetMDImport()->GetNameAndSigOfMemberRef(token, &pSig, &cSig, &szName_Ignore));
13387 case ENCODE_VARARGS_METHODDEF:
13389 mdSignature token = TokenFromRid(
13390 CorSigUncompressData(pBlob),
13393 IfFailThrow(pInfoModule->GetMDImport()->GetSigOfMethodDef(token, &cSig, &pSig));
13397 result = (size_t) CORINFO_VARARGS_HANDLE(currentModule->GetVASigCookie(Signature(pSig, cSig)));
13401 case ENCODE_METHOD_ENTRY_DEF_TOKEN:
13403 mdToken MethodDef = TokenFromRid(CorSigUncompressData(pBlob), mdtMethodDef);
13404 _ASSERTE(pInfoModule->IsFullModule());
13405 pMD = MemberLoader::GetMethodDescFromMethodDef(static_cast<Module*>(pInfoModule), MethodDef, FALSE);
13407 pMD->PrepareForUseAsADependencyOfANativeImage();
13409 if (currentModule->IsReadyToRun())
13411 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13412 pMD->EnsureActive();
13418 case ENCODE_METHOD_ENTRY_REF_TOKEN:
13420 SigTypeContext typeContext;
13421 mdToken MemberRef = TokenFromRid(CorSigUncompressData(pBlob), mdtMemberRef);
13422 FieldDesc * pFD = NULL;
13425 MemberLoader::GetDescFromMemberRef(pInfoModule, MemberRef, &pMD, &pFD, &typeContext, FALSE /* strict metadata checks */, &th);
13426 _ASSERTE(pMD != NULL);
13428 pMD->PrepareForUseAsADependencyOfANativeImage();
13430 if (currentModule->IsReadyToRun())
13432 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13433 pMD->EnsureActive();
13439 case ENCODE_METHOD_ENTRY:
13441 pMD = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13443 if (currentModule->IsReadyToRun())
13445 // We do not emit activation fixups for version resilient references. Activate the target explicitly.
13446 pMD->EnsureActive();
13450 result = pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY);
13454 case ENCODE_SYNC_LOCK:
13456 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13458 result = (size_t) GetClassSync(th.AsMethodTable());
13462 case ENCODE_INDIRECT_PINVOKE_TARGET:
13464 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13466 _ASSERTE(pMethod->IsNDirect());
13467 NDirectMethodDesc *pMD = (NDirectMethodDesc*)pMethod;
13468 result = (size_t)(LPVOID)&(pMD->GetWriteableData()->m_pNDirectTarget);
13472 case ENCODE_PINVOKE_TARGET:
13474 if (mayUsePrecompiledNDirectMethods)
13476 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13478 _ASSERTE(pMethod->IsNDirect());
13479 result = (size_t)(LPVOID)NDirectMethodDesc::ResolveAndSetNDirectTarget((NDirectMethodDesc*)pMethod);
13488 #if defined(PROFILING_SUPPORTED)
13489 case ENCODE_PROFILING_HANDLE:
13491 MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13493 // methods with no metadata behind cannot be exposed to tools expecting metadata (profiler, debugger...)
13494 // they shouldnever come here as they are called out in GetCompileFlag
13495 _ASSERTE(!pMethod->IsNoMetadata());
13497 FunctionID funId = (FunctionID)pMethod;
13499 BOOL bHookFunction = TRUE;
13500 CORINFO_PROFILING_HANDLE profilerHandle = (CORINFO_PROFILING_HANDLE)funId;
13503 BEGIN_PROFILER_CALLBACK(CORProfilerFunctionIDMapperEnabled());
13504 profilerHandle = (CORINFO_PROFILING_HANDLE)(&g_profControlBlock)->EEFunctionIDMapper(funId, &bHookFunction);
13505 END_PROFILER_CALLBACK();
13508 // Profiling handle is opaque token. It does not have to be aligned thus we can not store it in the same location as token.
13509 *(entry+kZapProfilingHandleImportValueIndexClientData) = (SIZE_T)profilerHandle;
13513 *(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_ENTER].pfnHelper;
13514 *(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_LEAVE].pfnHelper;
13515 *(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)hlpDynamicFuncTable[DYNAMIC_CORINFO_HELP_PROF_FCN_TAILCALL].pfnHelper;
13519 *(entry+kZapProfilingHandleImportValueIndexEnterAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13520 *(entry+kZapProfilingHandleImportValueIndexLeaveAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13521 *(entry+kZapProfilingHandleImportValueIndexTailcallAddr) = (SIZE_T)(void *)JIT_ProfilerEnterLeaveTailcallStub;
13525 #endif // PROFILING_SUPPORTED
13527 case ENCODE_FIELD_ADDRESS:
13529 FieldDesc *pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13531 pField->GetEnclosingMethodTable()->CheckRestore();
13533 // We can take address of RVA field only since ngened code is domain neutral
13534 _ASSERTE(pField->IsRVA());
13536 result = (size_t)pField->GetStaticAddressHandle(NULL);
13540 case ENCODE_VIRTUAL_ENTRY_SLOT:
13542 DWORD slot = CorSigUncompressData(pBlob);
13544 TypeHandle ownerType = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13546 LOG((LF_ZAP, LL_INFO100000, " Fixup stub dispatch\n"));
13548 VirtualCallStubManager * pMgr = currentModule->GetLoaderAllocator()->GetVirtualCallStubManager();
13551 // We should be generating a stub indirection here, but the zapper already uses one level
13552 // of indirection, i.e. we would have to return IAT_PPVALUE to the JIT, and on the whole the JITs
13553 // aren't quite set up to accept that. Furthermore the call sequences would be different - at
13554 // the moment an indirection cell uses "call [cell-addr]" on x86, and instead we would want the
13555 // euqivalent of "call [[call-addr]]". This could perhaps be implemented as "call [eax]" </REVISIT_TODO>
13556 result = pMgr->GetCallStub(ownerType, slot);
13560 case ENCODE_CLASS_ID_FOR_STATICS:
13562 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13564 MethodTable * pMT = th.AsMethodTable();
13565 if (pMT->IsDynamicStatics())
13567 result = pMT->GetModuleDynamicEntryID();
13571 result = pMT->GetClassIndex();
13576 case ENCODE_MODULE_ID_FOR_GENERIC_STATICS:
13578 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13580 MethodTable * pMT = th.AsMethodTable();
13582 result = pMT->GetModuleForStatics()->GetModuleID();
13586 #ifdef FEATURE_READYTORUN
13587 case ENCODE_READYTORUN_HELPER:
13589 DWORD helperNum = CorSigUncompressData(pBlob);
13591 CorInfoHelpFunc corInfoHelpFunc = MapReadyToRunHelper((ReadyToRunHelper)helperNum);
13592 if (corInfoHelpFunc != CORINFO_HELP_UNDEF)
13594 result = (size_t)CEEJitInfo::getHelperFtnStatic(corInfoHelpFunc);
13600 case READYTORUN_HELPER_Module:
13602 _ASSERTE(pInfoModule->IsFullModule());
13603 Module *fullModule = static_cast<Module*>(pInfoModule);
13604 Module * pPrevious = InterlockedCompareExchangeT((Module **)entry, fullModule, NULL);
13605 if (pPrevious != pInfoModule && pPrevious != NULL)
13606 COMPlusThrowHR(COR_E_FILELOAD, IDS_NATIVE_IMAGE_CANNOT_BE_LOADED_MULTIPLE_TIMES, fullModule->GetPath());
13611 case READYTORUN_HELPER_GSCookie:
13612 result = (size_t)GetProcessGSCookie();
13615 case READYTORUN_HELPER_IndirectTrapThreads:
13616 result = (size_t)&g_TrapReturningThreads;
13619 case READYTORUN_HELPER_DelayLoad_MethodCall:
13620 result = (size_t)GetEEFuncEntryPoint(DelayLoad_MethodCall);
13623 case READYTORUN_HELPER_DelayLoad_Helper:
13624 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper);
13627 case READYTORUN_HELPER_DelayLoad_Helper_Obj:
13628 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_Obj);
13631 case READYTORUN_HELPER_DelayLoad_Helper_ObjObj:
13632 result = (size_t)GetEEFuncEntryPoint(DelayLoad_Helper_ObjObj);
13636 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown READYTORUN_HELPER %d\n", helperNum);
13637 _ASSERTE(!"Unknown READYTORUN_HELPER");
13644 case ENCODE_FIELD_OFFSET:
13646 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13647 _ASSERTE(!pFD->IsStatic());
13648 _ASSERTE(!pFD->IsFieldOfValueType());
13650 DWORD dwOffset = (DWORD)sizeof(Object) + pFD->GetOffset();
13652 if (dwOffset > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13658 case ENCODE_FIELD_BASE_OFFSET:
13660 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13662 MethodTable * pMT = th.AsMethodTable();
13663 _ASSERTE(!pMT->IsValueType());
13665 DWORD dwOffsetBase = ReadyToRunInfo::GetFieldBaseOffset(pMT);
13666 if (dwOffsetBase > MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT)
13668 result = dwOffsetBase;
13672 case ENCODE_CHECK_TYPE_LAYOUT:
13673 case ENCODE_VERIFY_TYPE_LAYOUT:
13675 TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob);
13676 MethodTable * pMT = th.AsMethodTable();
13677 _ASSERTE(pMT->IsValueType());
13679 if (!TypeLayoutCheck(pMT, pBlob, /* printDiff */ kind == ENCODE_VERIFY_TYPE_LAYOUT))
13681 if (kind == ENCODE_CHECK_TYPE_LAYOUT)
13687 // Verification failures are failfast events
13688 DefineFullyQualifiedNameForClass();
13689 SString fatalErrorString;
13690 fatalErrorString.Printf("Verify_TypeLayout '%s' failed to verify type layout",
13691 GetFullyQualifiedNameForClass(pMT));
13695 _ASSERTE_MSG(false, fatalErrorString.GetUTF8());
13696 // Run through the type layout logic again, after the assert, makes debugging easy
13697 TypeLayoutCheck(pMT, pBlob, /* printDiff */ TRUE);
13701 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(-1, fatalErrorString.GetUnicode());
13710 case ENCODE_CHECK_FIELD_OFFSET:
13712 DWORD dwExpectedOffset = CorSigUncompressData(pBlob);
13714 FieldDesc * pFD = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13715 _ASSERTE(!pFD->IsStatic());
13717 DWORD dwOffset = pFD->GetOffset();
13718 if (!pFD->IsFieldOfValueType())
13719 dwOffset += sizeof(Object);
13721 if (dwExpectedOffset != dwOffset)
13728 case ENCODE_VERIFY_FIELD_OFFSET:
13730 DWORD baseOffset = CorSigUncompressData(pBlob);
13731 DWORD fieldOffset = CorSigUncompressData(pBlob);
13732 FieldDesc* pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
13733 MethodTable *pEnclosingMT = pField->GetApproxEnclosingMethodTable();
13734 pEnclosingMT->CheckRestore();
13735 DWORD actualFieldOffset = pField->GetOffset();
13736 if (!pField->IsStatic() && !pField->IsFieldOfValueType())
13738 actualFieldOffset += sizeof(Object);
13741 DWORD actualBaseOffset = 0;
13742 if (!pField->IsStatic() &&
13743 pEnclosingMT->GetParentMethodTable() != NULL &&
13744 !pEnclosingMT->IsValueType())
13746 actualBaseOffset = ReadyToRunInfo::GetFieldBaseOffset(pEnclosingMT);
13749 if (baseOffset == 0)
13751 // Relative verification of just the field offset when the base class
13752 // is outside of the current R2R version bubble
13753 actualFieldOffset -= actualBaseOffset;
13754 actualBaseOffset = 0;
13757 if ((fieldOffset != actualFieldOffset) || (baseOffset != actualBaseOffset))
13759 // Verification failures are failfast events
13760 DefineFullyQualifiedNameForClass();
13762 SString fatalErrorString;
13763 fatalErrorString.Printf("Verify_FieldOffset '%s.%s' Field offset %d!=%d(actual) || baseOffset %d!=%d(actual)",
13764 GetFullyQualifiedNameForClass(pEnclosingMT),
13770 _ASSERTE_MSG(false, fatalErrorString.GetUTF8());
13772 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(-1, fatalErrorString.GetUnicode());
13779 case ENCODE_VERIFY_VIRTUAL_FUNCTION_OVERRIDE:
13780 case ENCODE_CHECK_VIRTUAL_FUNCTION_OVERRIDE:
13782 PCCOR_SIGNATURE updatedSignature = pBlob;
13784 ReadyToRunVirtualFunctionOverrideFlags flags = (ReadyToRunVirtualFunctionOverrideFlags)CorSigUncompressData(updatedSignature);
13786 SigTypeContext typeContext; // empty context is OK: encoding should not contain type variables.
13787 ZapSig::Context zapSigContext(pInfoModule, (void *)currentModule, ZapSig::NormalTokens);
13788 MethodDesc *pDeclMethod = ZapSig::DecodeMethod(pInfoModule, updatedSignature, &typeContext, &zapSigContext, NULL, NULL, NULL, &updatedSignature, TRUE);
13789 TypeHandle thImpl = ZapSig::DecodeType(currentModule, pInfoModule, updatedSignature, CLASS_LOADED, &updatedSignature);
13791 MethodDesc *pImplMethodCompiler = NULL;
13793 if ((flags & READYTORUN_VIRTUAL_OVERRIDE_VirtualFunctionOverridden) != 0)
13795 pImplMethodCompiler = ZapSig::DecodeMethod(currentModule, pInfoModule, updatedSignature);
13798 MethodDesc *pImplMethodRuntime;
13799 if (pDeclMethod->IsInterface())
13801 if (!thImpl.CanCastTo(pDeclMethod->GetMethodTable()))
13803 MethodTable *pInterfaceTypeCanonical = pDeclMethod->GetMethodTable()->GetCanonicalMethodTable();
13805 // Its possible for the decl method to need to be found on the only canonically compatible interface on the owning type
13806 MethodTable::InterfaceMapIterator it = thImpl.GetMethodTable()->IterateInterfaceMap();
13809 MethodTable *pItfInMap = it.GetInterface(thImpl.GetMethodTable());
13810 if (pInterfaceTypeCanonical == pItfInMap->GetCanonicalMethodTable())
13812 pDeclMethod = MethodDesc::FindOrCreateAssociatedMethodDesc(pDeclMethod, pItfInMap, FALSE, pDeclMethod->GetMethodInstantiation(), FALSE, TRUE);
13817 DispatchSlot slot = thImpl.GetMethodTable()->FindDispatchSlotForInterfaceMD(pDeclMethod, /*throwOnConflict*/ FALSE);
13818 pImplMethodRuntime = slot.GetMethodDesc();
13822 MethodTable *pCheckMT = thImpl.GetMethodTable();
13823 MethodTable *pBaseMT = pDeclMethod->GetMethodTable();
13824 WORD slot = pDeclMethod->GetSlot();
13826 while (pCheckMT != nullptr)
13828 if (pCheckMT->HasSameTypeDefAs(pBaseMT))
13833 pCheckMT = pCheckMT->GetParentMethodTable();
13836 if (pCheckMT == nullptr)
13838 pImplMethodRuntime = NULL;
13840 else if (IsMdFinal(pDeclMethod->GetAttrs()))
13842 pImplMethodRuntime = pDeclMethod;
13846 _ASSERTE(slot < pBaseMT->GetNumVirtuals());
13847 pImplMethodRuntime = thImpl.GetMethodTable()->GetMethodDescForSlot(slot);
13851 if (pImplMethodRuntime != pImplMethodCompiler)
13853 if (kind == ENCODE_CHECK_VIRTUAL_FUNCTION_OVERRIDE)
13859 // Verification failures are failfast events
13860 DefineFullyQualifiedNameForClass();
13861 SString methodNameDecl;
13862 SString methodNameImplRuntime(W("(NULL)"));
13863 SString methodNameImplCompiler(W("(NULL)"));
13865 pDeclMethod->GetFullMethodInfo(methodNameDecl);
13867 if (pImplMethodRuntime != NULL)
13869 methodNameImplRuntime.Clear();
13870 pImplMethodRuntime->GetFullMethodInfo(methodNameImplRuntime);
13873 if (pImplMethodCompiler != NULL)
13875 methodNameImplCompiler.Clear();
13876 pImplMethodCompiler->GetFullMethodInfo(methodNameImplCompiler);
13879 SString fatalErrorString;
13880 fatalErrorString.Printf("Verify_VirtualFunctionOverride Decl Method '%s' on type '%s' is '%s'(actual) instead of expected '%s'(from compiler)",
13881 methodNameDecl.GetUTF8(),
13882 GetFullyQualifiedNameForClass(thImpl.GetMethodTable()),
13883 methodNameImplRuntime.GetUTF8(),
13884 methodNameImplCompiler.GetUTF8());
13886 _ASSERTE_MSG(false, fatalErrorString.GetUTF8());
13887 _ASSERTE(!IsDebuggerPresent() && "Stop on assert here instead of fatal error for ease of live debugging");
13889 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(-1, fatalErrorString.GetUnicode());
13900 case ENCODE_CHECK_INSTRUCTION_SET_SUPPORT:
13902 DWORD dwInstructionSetCount = CorSigUncompressData(pBlob);
13903 CORJIT_FLAGS corjitFlags = ExecutionManager::GetEEJitManager()->GetCPUCompileFlags();
13905 for (DWORD dwinstructionSetIndex = 0; dwinstructionSetIndex < dwInstructionSetCount; dwinstructionSetIndex++)
13907 DWORD instructionSetEncoded = CorSigUncompressData(pBlob);
13908 bool mustInstructionSetBeSupported = !!(instructionSetEncoded & 1);
13909 ReadyToRunInstructionSet instructionSet = (ReadyToRunInstructionSet)(instructionSetEncoded >> 1);
13910 if (IsInstructionSetSupported(corjitFlags, instructionSet) != mustInstructionSetBeSupported)
13919 case ENCODE_CHECK_IL_BODY:
13920 case ENCODE_VERIFY_IL_BODY:
13922 DWORD dwBlobSize = CorSigUncompressData(pBlob);
13923 const uint8_t *const pBlobStart = pBlob;
13924 pBlob += dwBlobSize;
13925 StackSArray<TypeHandle> types;
13926 DWORD cTypes = CorSigUncompressData(pBlob);
13929 for (DWORD iType = 0; iType < cTypes && !fail; iType++)
13931 if (kind == ENCODE_CHECK_IL_BODY)
13935 types.Append(ZapSig::DecodeType(currentModule, pInfoModule, pBlob, CLASS_LOAD_APPROXPARENTS, &pBlob));
13941 EX_END_CATCH(SwallowAllExceptions)
13946 types.Append(ZapSig::DecodeType(currentModule, pInfoModule, pBlob, CLASS_LOAD_APPROXPARENTS, &pBlob));
13950 MethodDesc *pMDCompare = NULL;
13954 if (kind == ENCODE_CHECK_IL_BODY)
13958 pMDCompare = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13964 EX_END_CATCH(SwallowAllExceptions)
13968 pMDCompare = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
13972 ReadyToRunStandaloneMethodMetadata *pMethodMetadata = NULL;
13975 pMethodMetadata = GetReadyToRunStandaloneMethodMetadata(pMDCompare);
13976 if (pMethodMetadata == NULL)
13979 fail = fail || (pMethodMetadata->cByteData != dwBlobSize);
13984 fail = 0 != memcmp(pBlobStart, pMethodMetadata->pByteData, dwBlobSize);
13989 fail = cTypes != pMethodMetadata->cTypes;
13994 for (COUNT_T i = 0; i < cTypes && !fail; i++)
13996 fail = types[i] != pMethodMetadata->pTypes[i];
14000 if (!fail && !currentModule->GetReadyToRunInfo()->IsForbidProcessMoreILBodyFixups())
14002 result = (size_t)pMDCompare;
14006 if (kind == ENCODE_CHECK_IL_BODY || (!fail && currentModule->GetReadyToRunInfo()->IsForbidProcessMoreILBodyFixups()))
14012 DefineFullyQualifiedNameForClass();
14013 SString methodName;
14014 pMDCompare->GetFullMethodInfo(methodName);
14015 void* compileTimeTypes = types.OpenRawBuffer();
14017 int runtimeMethodDataSize = pMethodMetadata != NULL ? (int)pMethodMetadata->cByteData : 0;
14018 void* runtimeMethodData = pMethodMetadata != NULL ? (void*)pMethodMetadata->pByteData : (void*)NULL;
14020 int runtimeTypeCount = pMethodMetadata != NULL ? (int)pMethodMetadata->cTypes : 0;
14021 void* runtimeTypeData = pMethodMetadata != NULL ? (void*)pMethodMetadata->pTypes : (void*)NULL;
14023 SString fatalErrorString;
14024 fatalErrorString.Printf("VERIFY_IL_BODY Method '%s' type '%s' does not match IL body expected DEBUGINFO MethodData {%d} {%p} RuntimeMethodData {%d} {%p} Types {%d} {%p} RuntimeTypes {%d} {%p}",
14025 methodName.GetUTF8(),
14026 GetFullyQualifiedNameForClass(pMDCompare->GetMethodTable()),
14027 (int)dwBlobSize, pBlobStart,
14028 runtimeMethodDataSize, runtimeMethodData,
14029 (int)cTypes, compileTimeTypes,
14030 runtimeTypeCount, runtimeTypeData
14033 _ASSERTE_MSG(false, fatalErrorString.GetUTF8());
14034 _ASSERTE(!IsDebuggerPresent() && "Stop on assert here instead of fatal error for ease of live debugging");
14036 EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(-1, fatalErrorString.GetUnicode());
14042 #endif // FEATURE_READYTORUN
14044 STRESS_LOG1(LF_ZAP, LL_WARNING, "Unknown FIXUP_BLOB_KIND %d\n", kind);
14045 _ASSERTE(!"Unknown FIXUP_BLOB_KIND");
14055 bool CEEInfo::getTailCallHelpersInternal(CORINFO_RESOLVED_TOKEN* callToken,
14056 CORINFO_SIG_INFO* sig,
14057 CORINFO_GET_TAILCALL_HELPERS_FLAGS flags,
14058 CORINFO_TAILCALL_HELPERS* pResult)
14060 MethodDesc* pTargetMD = NULL;
14062 if (callToken != NULL)
14064 pTargetMD = (MethodDesc*)callToken->hMethod;
14065 _ASSERTE(pTargetMD != NULL);
14067 if (pTargetMD->IsWrapperStub())
14069 pTargetMD = pTargetMD->GetWrappedMethodDesc();
14072 // We currently do not handle generating the proper call to managed
14073 // varargs methods.
14074 if (pTargetMD->IsVarArg())
14080 SigTypeContext typeCtx;
14081 GetTypeContext(&sig->sigInst, &typeCtx);
14083 MetaSig msig(sig->pSig, sig->cbSig, GetModule(sig->scope), &typeCtx);
14085 bool isCallvirt = (flags & CORINFO_TAILCALL_IS_CALLVIRT) != 0;
14086 bool isThisArgByRef = (flags & CORINFO_TAILCALL_THIS_ARG_IS_BYREF) != 0;
14088 MethodDesc* pStoreArgsMD;
14089 MethodDesc* pCallTargetMD;
14092 TailCallHelp::CreateTailCallHelperStubs(
14093 m_pMethodBeingCompiled, pTargetMD,
14094 msig, isCallvirt, isThisArgByRef, sig->hasTypeArg(),
14095 &pStoreArgsMD, &needsTarget,
14098 unsigned outFlags = 0;
14101 outFlags |= CORINFO_TAILCALL_STORE_TARGET;
14104 pResult->flags = (CORINFO_TAILCALL_HELPERS_FLAGS)outFlags;
14105 pResult->hStoreArgs = (CORINFO_METHOD_HANDLE)pStoreArgsMD;
14106 pResult->hCallTarget = (CORINFO_METHOD_HANDLE)pCallTargetMD;
14107 pResult->hDispatcher = (CORINFO_METHOD_HANDLE)TailCallHelp::GetOrLoadTailCallDispatcherMD();
14111 bool CEEInfo::getTailCallHelpers(CORINFO_RESOLVED_TOKEN* callToken,
14112 CORINFO_SIG_INFO* sig,
14113 CORINFO_GET_TAILCALL_HELPERS_FLAGS flags,
14114 CORINFO_TAILCALL_HELPERS* pResult)
14122 bool success = false;
14124 JIT_TO_EE_TRANSITION();
14126 success = getTailCallHelpersInternal(callToken, sig, flags, pResult);
14128 EE_TO_JIT_TRANSITION();
14133 bool CEEInfo::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert)
14138 void CEEInfo::updateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint)
14140 // No update necessary, all entry points are tail callable in runtime.
14143 void CEEInfo::allocMem (AllocMemArgs *pArgs)
14145 LIMITED_METHOD_CONTRACT;
14146 UNREACHABLE(); // only called on derived class.
14149 void CEEInfo::reserveUnwindInfo (
14150 bool isFunclet, /* IN */
14151 bool isColdCode, /* IN */
14152 uint32_t unwindSize /* IN */
14155 LIMITED_METHOD_CONTRACT;
14156 UNREACHABLE(); // only called on derived class.
14159 void CEEInfo::allocUnwindInfo (
14160 uint8_t * pHotCode, /* IN */
14161 uint8_t * pColdCode, /* IN */
14162 uint32_t startOffset, /* IN */
14163 uint32_t endOffset, /* IN */
14164 uint32_t unwindSize, /* IN */
14165 uint8_t * pUnwindBlock, /* IN */
14166 CorJitFuncKind funcKind /* IN */
14169 LIMITED_METHOD_CONTRACT;
14170 UNREACHABLE(); // only called on derived class.
14173 void * CEEInfo::allocGCInfo (
14174 size_t size /* IN */
14177 LIMITED_METHOD_CONTRACT;
14178 UNREACHABLE_RET(); // only called on derived class.
14181 void CEEInfo::setEHcount (
14182 unsigned cEH /* IN */
14185 LIMITED_METHOD_CONTRACT;
14186 UNREACHABLE(); // only called on derived class.
14189 void CEEInfo::setEHinfo (
14190 unsigned EHnumber, /* IN */
14191 const CORINFO_EH_CLAUSE *clause /* IN */
14194 LIMITED_METHOD_CONTRACT;
14195 UNREACHABLE(); // only called on derived class.
14198 InfoAccessType CEEInfo::constructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd,
14202 LIMITED_METHOD_CONTRACT;
14203 UNREACHABLE(); // only called on derived class.
14206 InfoAccessType CEEInfo::emptyStringLiteral(void ** ppValue)
14208 LIMITED_METHOD_CONTRACT;
14209 UNREACHABLE(); // only called on derived class.
14212 CORINFO_CLASS_HANDLE CEEInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE fieldHnd,
14213 bool* pIsSpeculative)
14215 LIMITED_METHOD_CONTRACT;
14216 UNREACHABLE(); // only called on derived class.
14219 void* CEEInfo::getMethodSync(CORINFO_METHOD_HANDLE ftnHnd,
14220 void **ppIndirection)
14222 LIMITED_METHOD_CONTRACT;
14223 UNREACHABLE(); // only called on derived class.
14226 HRESULT CEEInfo::allocPgoInstrumentationBySchema(
14227 CORINFO_METHOD_HANDLE ftnHnd, /* IN */
14228 PgoInstrumentationSchema* pSchema, /* IN/OUT */
14229 uint32_t countSchemaItems, /* IN */
14230 uint8_t** pInstrumentationData /* OUT */
14233 LIMITED_METHOD_CONTRACT;
14234 UNREACHABLE_RET(); // only called on derived class.
14237 HRESULT CEEInfo::getPgoInstrumentationResults(
14238 CORINFO_METHOD_HANDLE ftnHnd,
14239 PgoInstrumentationSchema **pSchema, // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes)
14240 uint32_t * pCountSchemaItems, // pointer to the count schema items
14241 uint8_t ** pInstrumentationData, // pointer to the actual instrumentation data (pointer will not remain valid after jit completes)
14242 PgoSource * pPgoSource
14245 LIMITED_METHOD_CONTRACT;
14246 UNREACHABLE_RET(); // only called on derived class.
14249 void CEEInfo::recordCallSite(
14250 uint32_t instrOffset, /* IN */
14251 CORINFO_SIG_INFO * callSig, /* IN */
14252 CORINFO_METHOD_HANDLE methodHandle /* IN */
14255 LIMITED_METHOD_CONTRACT;
14256 UNREACHABLE(); // only called on derived class.
14259 void CEEInfo::recordRelocation(
14260 void * location, /* IN */
14261 void * locationRW, /* IN */
14262 void * target, /* IN */
14263 WORD fRelocType, /* IN */
14264 INT32 addlDelta /* IN */
14267 LIMITED_METHOD_CONTRACT;
14268 UNREACHABLE(); // only called on derived class.
14271 WORD CEEInfo::getRelocTypeHint(void * target)
14273 LIMITED_METHOD_CONTRACT;
14274 UNREACHABLE_RET(); // only called on derived class.
14277 uint32_t CEEInfo::getExpectedTargetArchitecture()
14279 LIMITED_METHOD_CONTRACT;
14281 return IMAGE_FILE_MACHINE_NATIVE;
14284 void CEEInfo::setBoundaries(CORINFO_METHOD_HANDLE ftn, ULONG32 cMap,
14285 ICorDebugInfo::OffsetMapping *pMap)
14287 LIMITED_METHOD_CONTRACT;
14288 UNREACHABLE(); // only called on derived class.
14291 void CEEInfo::setVars(CORINFO_METHOD_HANDLE ftn, ULONG32 cVars, ICorDebugInfo::NativeVarInfo *vars)
14293 LIMITED_METHOD_CONTRACT;
14294 UNREACHABLE(); // only called on derived class.
14297 void CEEInfo::reportRichMappings(
14298 ICorDebugInfo::InlineTreeNode* inlineTreeNodes,
14299 uint32_t numInlineTreeNodes,
14300 ICorDebugInfo::RichOffsetMapping* mappings,
14301 uint32_t numMappings)
14303 LIMITED_METHOD_CONTRACT;
14304 UNREACHABLE(); // only called on derived class.
14307 void CEEInfo::setPatchpointInfo(PatchpointInfo* patchpointInfo)
14309 LIMITED_METHOD_CONTRACT;
14310 UNREACHABLE(); // only called on derived class.
14313 PatchpointInfo* CEEInfo::getOSRInfo(unsigned* ilOffset)
14315 LIMITED_METHOD_CONTRACT;
14316 UNREACHABLE(); // only called on derived class.
14319 void* CEEInfo::getHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
14320 void ** ppIndirection) /* OUT */
14322 LIMITED_METHOD_CONTRACT;
14323 UNREACHABLE(); // only called on derived class.
14326 void CEEInfo::GetProfilingHandle(bool *pbHookFunction,
14327 void **pProfilerHandle,
14328 bool *pbIndirectedHandles)
14330 LIMITED_METHOD_CONTRACT;
14331 UNREACHABLE(); // only called on derived class.
14334 bool CEEInfo::notifyInstructionSetUsage(CORINFO_InstructionSet instructionSet,
14335 bool supportEnabled)
14337 LIMITED_METHOD_CONTRACT;
14338 // Do nothing. This api does not provide value in JIT scenarios and
14339 // crossgen does not utilize the api either.
14340 return supportEnabled;
14343 #endif // !DACCESS_COMPILE
14345 EECodeInfo::EECodeInfo()
14347 WRAPPER_NO_CONTRACT;
14349 m_codeAddress = NULL;
14355 #ifdef FEATURE_EH_FUNCLETS
14356 m_pFunctionEntry = NULL;
14360 void EECodeInfo::Init(PCODE codeAddress)
14367 Init(codeAddress, ExecutionManager::GetScanFlags());
14370 void EECodeInfo::Init(PCODE codeAddress, ExecutionManager::ScanFlag scanFlag)
14377 m_codeAddress = codeAddress;
14379 RangeSection * pRS = ExecutionManager::FindCodeRange(codeAddress, scanFlag);
14383 if (!pRS->_pjit->JitCodeToMethodInfo(pRS, codeAddress, &m_pMD, this))
14386 m_pJM = pRS->_pjit;
14394 #ifdef FEATURE_EH_FUNCLETS
14395 m_pFunctionEntry = NULL;
14399 TADDR EECodeInfo::GetSavedMethodCode()
14402 // All EECodeInfo methods must be NOTHROW/GC_NOTRIGGER since they can
14403 // be used during GC.
14410 #if defined(HAVE_GCCOVER)
14412 PTR_GCCoverageInfo gcCover = GetNativeCodeVersion().GetGCCoverageInfo();
14413 _ASSERTE (!gcCover || GCStress<cfg_instr>::IsEnabled());
14414 if (GCStress<cfg_instr>::IsEnabled()
14417 _ASSERTE(gcCover->savedCode);
14419 // Make sure we return the TADDR of savedCode here. The byte array is not marshaled automatically.
14420 // The caller is responsible for any necessary marshaling.
14421 return PTR_TO_MEMBER_TADDR(GCCoverageInfo, gcCover, savedCode);
14423 #endif //defined(HAVE_GCCOVER)
14426 return GetStartAddress();
14429 TADDR EECodeInfo::GetStartAddress()
14438 return m_pJM->JitTokenToStartAddress(m_methodToken);
14441 NativeCodeVersion EECodeInfo::GetNativeCodeVersion()
14450 PTR_MethodDesc pMD = PTR_MethodDesc(GetMethodDesc());
14453 return NativeCodeVersion();
14456 #ifdef FEATURE_CODE_VERSIONING
14457 if (pMD->IsVersionable())
14459 CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
14460 CodeVersionManager::LockHolder codeVersioningLockHolder;
14461 return pCodeVersionManager->GetNativeCodeVersion(pMD, PINSTRToPCODE(GetStartAddress()));
14464 return NativeCodeVersion(pMD);
14467 #if defined(FEATURE_EH_FUNCLETS)
14469 // ----------------------------------------------------------------------------
14470 // EECodeInfo::GetMainFunctionInfo
14473 // Simple helper to transform a funclet's EECodeInfo into a parent function EECodeInfo.
14476 // An EECodeInfo for the start of the main function body (offset 0).
14479 EECodeInfo EECodeInfo::GetMainFunctionInfo()
14481 LIMITED_METHOD_CONTRACT;
14484 EECodeInfo result = *this;
14485 result.m_relOffset = 0;
14486 result.m_codeAddress = this->GetStartAddress();
14487 result.m_pFunctionEntry = NULL;
14492 PTR_RUNTIME_FUNCTION EECodeInfo::GetFunctionEntry()
14494 LIMITED_METHOD_CONTRACT;
14497 if (m_pFunctionEntry == NULL)
14498 m_pFunctionEntry = m_pJM->LazyGetFunctionEntry(this);
14499 return m_pFunctionEntry;
14502 #if defined(TARGET_AMD64)
14504 BOOL EECodeInfo::HasFrameRegister()
14506 LIMITED_METHOD_CONTRACT;
14508 PTR_RUNTIME_FUNCTION pFuncEntry = GetFunctionEntry();
14509 _ASSERTE(pFuncEntry != NULL);
14511 BOOL fHasFrameRegister = FALSE;
14512 PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(GetModuleBase() + pFuncEntry->UnwindData);
14513 if (pUnwindInfo->FrameRegister != 0)
14515 fHasFrameRegister = TRUE;
14516 _ASSERTE(pUnwindInfo->FrameRegister == kRBP);
14519 return fHasFrameRegister;
14521 #endif // defined(TARGET_AMD64)
14523 #endif // defined(FEATURE_EH_FUNCLETS)
14526 #if defined(TARGET_AMD64)
14527 // ----------------------------------------------------------------------------
14528 // EECodeInfo::GetUnwindInfoHelper
14531 // Simple helper to return a pointer to the UNWIND_INFO given the offset to the unwind info.
14532 // On DAC builds, this function will read the memory from the target process and create a host copy.
14535 // * unwindInfoOffset - This is the offset to the unwind info, relative to the beginning of the code heap
14536 // for jitted code or to the module base for ngned code. this->GetModuleBase() will return the correct
14540 // Return a pointer to the UNWIND_INFO. On DAC builds, this function will create a host copy of the
14541 // UNWIND_INFO and return a host pointer. It will correctly read all of the memory for the variable-sized
14545 UNWIND_INFO * EECodeInfo::GetUnwindInfoHelper(ULONG unwindInfoOffset)
14547 #if defined(DACCESS_COMPILE)
14548 return DacGetUnwindInfo(static_cast<TADDR>(this->GetModuleBase() + unwindInfoOffset));
14549 #else // !DACCESS_COMPILE
14550 UNWIND_INFO * pUnwindInfo = reinterpret_cast<UNWIND_INFO *>(this->GetModuleBase() + unwindInfoOffset);
14551 #if defined(TARGET_AMD64)
14552 if (pUnwindInfo->Flags & UNW_FLAG_CHAININFO)
14554 unwindInfoOffset = ((PTR_RUNTIME_FUNCTION)(&(pUnwindInfo->UnwindCode)))->UnwindData;
14555 pUnwindInfo = reinterpret_cast<UNWIND_INFO *>(this->GetModuleBase() + unwindInfoOffset);
14557 #endif // TARGET_AMD64
14558 return pUnwindInfo;
14559 #endif // !DACCESS_COMPILE
14562 // ----------------------------------------------------------------------------
14563 // EECodeInfo::GetFixedStackSize
14566 // Return the fixed stack size of a specified managed method. This function DOES NOT take current control
14567 // PC into account. So the fixed stack size returned by this function is not valid in the prolog or
14571 // Return the fixed stack size.
14574 // * For method with dynamic stack allocations, this function will return the fixed stack size on X64 (the
14575 // stack size immediately after the prolog), and it will return 0 on IA64. This difference is due to
14576 // the different unwind info encoding.
14579 ULONG EECodeInfo::GetFixedStackSize()
14581 WRAPPER_NO_CONTRACT;
14584 ULONG uFixedStackSize = 0;
14587 GetOffsetsFromUnwindInfo(&uFixedStackSize, &uDummy);
14589 return uFixedStackSize;
14593 // The information returned by this method is only valid if we are not in a prolog or an epilog.
14594 // Since this method is only used for the security stackwalk cache and EnC transition, this assumption is
14595 // valid, since we cannot see these in a prolog or an epilog.
14597 // The next assumption is that only rbp is used as a frame register in jitted code. There is an
14598 // assert below to guard this assumption.
14599 void EECodeInfo::GetOffsetsFromUnwindInfo(ULONG* pRSPOffset, ULONG* pRBPOffset)
14601 LIMITED_METHOD_CONTRACT;
14604 _ASSERTE((pRSPOffset != NULL) && (pRBPOffset != NULL));
14606 // moduleBase is a target address.
14607 TADDR moduleBase = GetModuleBase();
14609 DWORD unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(GetFunctionEntry());
14611 if ((unwindInfo & RUNTIME_FUNCTION_INDIRECT) != 0)
14613 unwindInfo = RUNTIME_FUNCTION__GetUnwindInfoAddress(PTR_RUNTIME_FUNCTION(moduleBase + (unwindInfo & ~RUNTIME_FUNCTION_INDIRECT)));
14616 UNWIND_INFO * pInfo = GetUnwindInfoHelper(unwindInfo);
14617 _ASSERTE((pInfo->Flags & UNW_FLAG_CHAININFO) == 0);
14619 // Either we are not using a frame pointer, or we are using rbp as the frame pointer.
14620 if ( (pInfo->FrameRegister != 0) && (pInfo->FrameRegister != kRBP) )
14622 _ASSERTE(!"GetRbpOffset() - non-RBP frame pointer used, violating assumptions of the security stackwalk cache");
14626 // Walk the unwind info.
14627 ULONG StackOffset = 0;
14628 ULONG StackSize = 0;
14629 for (int i = 0; i < pInfo->CountOfUnwindCodes; i++)
14631 ULONG UnwindOp = pInfo->UnwindCode[i].UnwindOp;
14632 ULONG OpInfo = pInfo->UnwindCode[i].OpInfo;
14634 if (UnwindOp == UWOP_SAVE_NONVOL)
14636 if (OpInfo == kRBP)
14638 StackOffset = pInfo->UnwindCode[i+1].FrameOffset * 8;
14641 else if (UnwindOp == UWOP_SAVE_NONVOL_FAR)
14643 if (OpInfo == kRBP)
14645 StackOffset = pInfo->UnwindCode[i + 1].FrameOffset;
14646 StackOffset += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14649 else if (UnwindOp == UWOP_ALLOC_SMALL)
14651 StackSize += (OpInfo * 8) + 8;
14653 else if (UnwindOp == UWOP_ALLOC_LARGE)
14655 ULONG IncrementalStackSize = pInfo->UnwindCode[i + 1].FrameOffset;
14658 IncrementalStackSize *= 8;
14662 IncrementalStackSize += (pInfo->UnwindCode[i + 2].FrameOffset << 16);
14664 // This is a special opcode. We need to increment the index by 1 in addition to the normal adjustments.
14667 StackSize += IncrementalStackSize;
14669 else if (UnwindOp == UWOP_PUSH_NONVOL)
14671 // Because of constraints on epilogs, this unwind opcode is always last in the unwind code array.
14672 // This means that StackSize has been initialized already when we first see this unwind opcode.
14673 // Note that the initial value of StackSize does not include the stack space used for pushes.
14674 // Thus, here we only need to increment StackSize 8 bytes at a time until we see the unwind code for "push rbp".
14675 if (OpInfo == kRBP)
14677 StackOffset = StackSize;
14683 // Adjust the index into the unwind code array.
14684 i += UnwindOpExtraSlotTable[UnwindOp];
14687 *pRSPOffset = StackSize + 8; // add 8 for the return address
14688 *pRBPOffset = StackOffset;
14693 #if defined(_DEBUG) && defined(HAVE_GCCOVER)
14695 LPVOID EECodeInfo::findNextFunclet (LPVOID pvFuncletStart, SIZE_T cbCode, LPVOID *ppvFuncletEnd)
14704 PT_RUNTIME_FUNCTION pFunctionEntry;
14705 ULONGLONG uImageBase;
14707 EECodeInfo codeInfo;
14708 codeInfo.Init((PCODE)pvFuncletStart);
14709 pFunctionEntry = codeInfo.GetFunctionEntry();
14710 uImageBase = (ULONGLONG)codeInfo.GetModuleBase();
14711 #else // !TARGET_UNIX
14713 // This is GCStress debug only - use the slow OS APIs to enumerate funclets
14716 pFunctionEntry = (PT_RUNTIME_FUNCTION) RtlLookupFunctionEntry((ULONGLONG)pvFuncletStart,
14722 if (pFunctionEntry != NULL)
14725 _ASSERTE((TADDR)pvFuncletStart == (TADDR)uImageBase + pFunctionEntry->BeginAddress);
14726 _ASSERTE((TADDR)uImageBase + pFunctionEntry->EndAddress <= (TADDR)pvFuncletStart + cbCode);
14727 *ppvFuncletEnd = (LPVOID)(uImageBase + pFunctionEntry->EndAddress);
14728 return (LPVOID)(uImageBase + pFunctionEntry->BeginAddress);
14731 pvFuncletStart = (LPVOID)((TADDR)pvFuncletStart + 1);
14737 #endif // defined(_DEBUG) && !defined(HAVE_GCCOVER)
14738 #endif // defined(TARGET_AMD64)