From e4c6f996d4c34a0bd79edb2ae617d12e9cc92a4f Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Thu, 24 Oct 2024 17:19:38 -0700 Subject: [PATCH 1/7] JIT: enable devirtualization/inlining of other array interface methods The JIT recently enabled devirtualization of `GetEnumerator`, but other methods were inhibited from devirtualization because the runtime was returning an instantiating stub instead of the actual method. This blocked inlining and the JIT currently will not GDV unless it can also inline. So for instance `ICollection.Count` would not devirtualize. We think we know enough to pass the right inst parameter (the exact method desc) so enable this for the array case, at least for normal jitting. For NAOT array devirtualization happens via normal paths thanks to `Array` so should already fpr these cases. For R2R we don't do array interface devirt (yet). There was an existing field on `CORINFO_DEVIRTUALIZATION_INFO` to record the need for an inst parameter, but it was unused and so I renamed it and use it for this case. Contributes to #108913. --- src/coreclr/inc/corinfo.h | 4 +- src/coreclr/jit/importercalls.cpp | 47 ++++++++++++++++--- .../tools/Common/JitInterface/CorInfoImpl.cs | 4 +- .../tools/Common/JitInterface/CorInfoTypes.cs | 6 +-- .../tools/superpmi/superpmi-shared/agnostic.h | 2 +- .../superpmi-shared/methodcontext.cpp | 6 +-- src/coreclr/vm/jitinterface.cpp | 17 +++++-- 7 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 4f99061c5e1a18..4d45aeb3b1c75f 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1511,7 +1511,7 @@ struct CORINFO_DEVIRTUALIZATION_INFO // - details on the computation done by the jit host // - If pResolvedTokenDevirtualizedMethod is not set to NULL and targeting an R2R image // use it as the parameter to getCallInfo - // - requiresInstMethodTableArg is set to TRUE if the devirtualized method requires a type handle arg. + // - requiresInstMethodDescArg is set to TRUE if the devirtualized method requires a method desc arg. // - wasArrayInterfaceDevirt is set TRUE for array interface method devirtualization // (in which case the method handle and context will be a generic method) // @@ -1520,7 +1520,7 @@ struct CORINFO_DEVIRTUALIZATION_INFO CORINFO_DEVIRTUALIZATION_DETAIL detail; CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedMethod; CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedUnboxedMethod; - bool requiresInstMethodTableArg; + bool requiresInstMethodDescArg; bool wasArrayInterfaceDevirt; }; diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 24f2ddb17a4cec..4a75f6118463d3 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -8189,8 +8189,35 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, const char* derivedClassName = "?derivedClass"; const char* derivedMethodName = "?derivedMethod"; const char* note = "inexact or not final"; + const char* instArg = ""; #endif + if (dvInfo.requiresInstMethodDescArg) + { + // We should only end up with generic methods for array interface devirt. + // + assert(dvInfo.wasArrayInterfaceDevirt); + + // We don't expect NAOT to end up here, since it has Array + // and normal devirtualization. + // + assert(!IsTargetAbi(CORINFO_NATIVEAOT_ABI)); + + // We don't expect R2R to end up here, since it does not (yet) support + // array interface devirtualization. + // + assert(!opts.IsReadyToRun()); + + // We don't expect there to be an existing inst param arg. + // + CallArg* const instParam = call->gtArgs.FindWellKnownArg(WellKnownArg::InstParam); + if (instParam != nullptr) + { + assert(!"unexpected inst param in virtual/interface call"); + return; + } + } + // If we failed to get a method handle, we can't directly devirtualize. // // This can happen when prejitting, if the devirtualization crosses @@ -8219,6 +8246,10 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, { note = "final method"; } + if (dvInfo.requiresInstMethodDescArg) + { + instArg = " + requires inst arg"; + } if (verbose || doPrint) { @@ -8226,7 +8257,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, derivedClassName = eeGetClassName(derivedClass); if (verbose) { - printf(" devirt to %s::%s -- %s\n", derivedClassName, derivedMethodName, note); + printf(" devirt to %s::%s -- %s%s\n", derivedClassName, derivedMethodName, note, instArg); gtDispTree(call); } } @@ -8267,11 +8298,6 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // All checks done. Time to transform the call. // - // We should always have an exact class context. - // - // Note that wouldnt' be true if the runtime side supported array interface devirt, - // the resulting method would be a generic method of the non-generic SZArrayHelper class. - // assert(canDevirtualize); Metrics.DevirtualizedCall++; @@ -8285,6 +8311,15 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, call->gtControlExpr = nullptr; INDEBUG(call->gtCallDebugFlags |= GTF_CALL_MD_DEVIRTUALIZED); + if (dvInfo.requiresInstMethodDescArg) + { + // Pass the method desc as the inst param arg. + // Need to make sure this works in all cases. We might need more complex embedding. + // + GenTree* const instParam = gtNewIconNode((ssize_t)derivedMethod, TYP_I_IMPL); + call->gtArgs.InsertInstParam(this, instParam); + } + // Virtual calls include an implicit null check, which we may // now need to make explicit. if (!objIsNonNull) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 5038448f8cafc4..18fb2c06f91aa1 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1302,7 +1302,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) info->devirtualizedMethod = null; info->exactContext = null; info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_UNKNOWN; - info->requiresInstMethodTableArg = false; + info->requiresInstMethodDescArg = false; info->wasArrayInterfaceDevirt = false; TypeDesc objType = HandleToObject(info->objClass); @@ -1450,7 +1450,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) #endif info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_SUCCESS; info->devirtualizedMethod = ObjectToHandle(impl); - info->requiresInstMethodTableArg = false; + info->requiresInstMethodDescArg = false; info->exactContext = contextFromType(owningType); return true; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index b6fbb9cbb84ae4..9be2cf8ffd2429 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1083,7 +1083,7 @@ public unsafe struct CORINFO_DEVIRTUALIZATION_INFO // invariant is `resolveVirtualMethod(...) == (devirtualizedMethod != nullptr)`. // - exactContext is set to wrapped CORINFO_CLASS_HANDLE of devirt'ed method table. // - detail describes the computation done by the jit host - // - requiresInstMethodTableArg is set to TRUE if the devirtualized method requires a type handle arg. + // - requiresInstMethodDescArg is set to TRUE if the devirtualized method requires a method desc arg. // - wasArrayInterfaceDevirt is set TRUE for array interface method devirtualization // (in which case the method handle and context will be a generic method) // @@ -1092,8 +1092,8 @@ public unsafe struct CORINFO_DEVIRTUALIZATION_INFO public CORINFO_DEVIRTUALIZATION_DETAIL detail; public CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedMethod; public CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedUnboxedMethod; - public byte _requiresInstMethodTableArg; - public bool requiresInstMethodTableArg { get { return _requiresInstMethodTableArg != 0; } set { _requiresInstMethodTableArg = value ? (byte)1 : (byte)0; } } + public byte _requiresInstMethodDescArg; + public bool requiresInstMethodDescArg { get { return _requiresInstMethodDescArg != 0; } set { _requiresInstMethodDescArg = value ? (byte)1 : (byte)0; } } public byte _wasArrayInterfaceDevirt; public bool wasArrayInterfaceDevirt { get { return _wasArrayInterfaceDevirt != 0; } set { _wasArrayInterfaceDevirt = value ? (byte)1 : (byte)0; } } } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index a0138db26532b5..946e29e452d443 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -654,7 +654,7 @@ struct Agnostic_ResolveVirtualMethodResult { bool returnValue; DWORDLONG devirtualizedMethod; - bool requiresInstMethodTableArg; + bool requiresInstMethodDescArg; bool wasArrayInterfaceDevirt; DWORDLONG exactContext; DWORD detail; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 8455abdb80d61c..8a2c6b208a0fc1 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3290,7 +3290,7 @@ void MethodContext::recResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info Agnostic_ResolveVirtualMethodResult result; result.returnValue = returnValue; result.devirtualizedMethod = CastHandle(info->devirtualizedMethod); - result.requiresInstMethodTableArg = info->requiresInstMethodTableArg; + result.requiresInstMethodDescArg = info->requiresInstMethodDescArg; result.exactContext = CastHandle(info->exactContext); result.detail = (DWORD) info->detail; result.wasArrayInterfaceDevirt = info->wasArrayInterfaceDevirt; @@ -3321,7 +3321,7 @@ void MethodContext::dmpResolveVirtualMethod(const Agnostic_ResolveVirtualMethodK printf(", value returnValue-%s, devirtMethod-%016" PRIX64 ", requiresInstArg-%s, wasArrayInterfaceDevirt-%s, exactContext-%016" PRIX64 ", detail-%d, tokDvMeth{%s}, tokDvUnboxMeth{%s}", result.returnValue ? "true" : "false", result.devirtualizedMethod, - result.requiresInstMethodTableArg ? "true" : "false", + result.requiresInstMethodDescArg ? "true" : "false", result.wasArrayInterfaceDevirt ? "true" : "false", result.exactContext, result.detail, @@ -3346,7 +3346,7 @@ bool MethodContext::repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info DEBUG_REP(dmpResolveVirtualMethod(key, result)); info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) result.devirtualizedMethod; - info->requiresInstMethodTableArg = result.requiresInstMethodTableArg; + info->requiresInstMethodDescArg = result.requiresInstMethodDescArg; info->wasArrayInterfaceDevirt = result.wasArrayInterfaceDevirt; info->exactContext = (CORINFO_CONTEXT_HANDLE) result.exactContext; info->detail = (CORINFO_DEVIRTUALIZATION_DETAIL) result.detail; diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 8d16aa72051147..fe7ca81a384655 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -8561,7 +8561,7 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) info->detail = CORINFO_DEVIRTUALIZATION_UNKNOWN; memset(&info->resolvedTokenDevirtualizedMethod, 0, sizeof(info->resolvedTokenDevirtualizedMethod)); memset(&info->resolvedTokenDevirtualizedUnboxedMethod, 0, sizeof(info->resolvedTokenDevirtualizedUnboxedMethod)); - info->requiresInstMethodTableArg = false; + info->requiresInstMethodDescArg = false; info->wasArrayInterfaceDevirt = false; MethodDesc* pBaseMD = GetMethod(info->virtualMethod); @@ -8765,21 +8765,28 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) // Success! Pass back the results. // - info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) pDevirtMD; - if (isArray) { + // If array devirtualization produced an instantiation stub, + // find the wrapped method and return that instead. + // + if (pDevirtMD->IsInstantiatingStub()) + { + pDevirtMD = pDevirtMD->GetWrappedMethodDesc(); + } + info->exactContext = MAKE_METHODCONTEXT((CORINFO_METHOD_HANDLE) pDevirtMD); - info->requiresInstMethodTableArg = pDevirtMD->RequiresInstMethodTableArg(); + info->requiresInstMethodDescArg = pDevirtMD->RequiresInstMethodDescArg(); info->wasArrayInterfaceDevirt = true; } else { info->exactContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT); - info->requiresInstMethodTableArg = false; + info->requiresInstMethodDescArg = false; info->wasArrayInterfaceDevirt = false; } + info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) pDevirtMD; info->detail = CORINFO_DEVIRTUALIZATION_SUCCESS; return true; From c58bb4af364f1acd36685aba8acde7c480c5a0bc Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Sat, 26 Oct 2024 08:35:05 -0700 Subject: [PATCH 2/7] need to pass the wrapper method desc as the inst arg, not the wrapped method desc --- src/coreclr/jit/importercalls.cpp | 2 +- src/coreclr/vm/jitinterface.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 4a75f6118463d3..02f41534a9e186 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -8316,7 +8316,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // Pass the method desc as the inst param arg. // Need to make sure this works in all cases. We might need more complex embedding. // - GenTree* const instParam = gtNewIconNode((ssize_t)derivedMethod, TYP_I_IMPL); + GenTree* const instParam = gtNewIconNode((ssize_t)dvInfo.virtualMethod, TYP_I_IMPL); call->gtArgs.InsertInstParam(this, instParam); } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index fe7ca81a384655..0c57734078d670 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -8772,11 +8772,13 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) // if (pDevirtMD->IsInstantiatingStub()) { + // hack + info->virtualMethod = (CORINFO_METHOD_HANDLE)pDevirtMD; pDevirtMD = pDevirtMD->GetWrappedMethodDesc(); } - info->exactContext = MAKE_METHODCONTEXT((CORINFO_METHOD_HANDLE) pDevirtMD); info->requiresInstMethodDescArg = pDevirtMD->RequiresInstMethodDescArg(); + info->exactContext = MAKE_METHODCONTEXT((CORINFO_METHOD_HANDLE) pDevirtMD); info->wasArrayInterfaceDevirt = true; } else From 6afc434d16265c1a7c681efa6a6c512d1c20f925 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Sat, 26 Oct 2024 18:34:48 -0700 Subject: [PATCH 3/7] extend jit interface --- src/coreclr/inc/corinfo.h | 19 +- src/coreclr/inc/icorjitinfoimpl_generated.h | 9 + src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/jit/ICorJitInfo_names_generated.h | 2 + .../jit/ICorJitInfo_wrapper_generated.hpp | 21 ++ src/coreclr/jit/compiler.h | 7 + src/coreclr/jit/gentree.cpp | 46 +++ src/coreclr/jit/importercalls.cpp | 28 +- .../tools/Common/JitInterface/CorInfoImpl.cs | 17 +- .../JitInterface/CorInfoImpl_generated.cs | 350 ++++++++++-------- .../tools/Common/JitInterface/CorInfoTypes.cs | 6 +- .../ThunkGenerator/ThunkInput.txt | 3 + .../aot/jitinterface/jitinterface_generated.h | 23 ++ .../tools/superpmi/superpmi-shared/agnostic.h | 9 +- .../tools/superpmi/superpmi-shared/lwmlist.h | 2 + .../superpmi-shared/methodcontext.cpp | 80 +++- .../superpmi/superpmi-shared/methodcontext.h | 15 + .../superpmi-shim-collector/icorjitinfo.cpp | 16 + .../icorjitinfo_generated.cpp | 17 + .../icorjitinfo_generated.cpp | 15 + .../tools/superpmi/superpmi/icorjitinfo.cpp | 14 + src/coreclr/vm/jitinterface.cpp | 82 +++- 22 files changed, 593 insertions(+), 198 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 4d45aeb3b1c75f..7872606a7aa32e 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1511,7 +1511,7 @@ struct CORINFO_DEVIRTUALIZATION_INFO // - details on the computation done by the jit host // - If pResolvedTokenDevirtualizedMethod is not set to NULL and targeting an R2R image // use it as the parameter to getCallInfo - // - requiresInstMethodDescArg is set to TRUE if the devirtualized method requires a method desc arg. + // - isInstantiatingStub is set to TRUE if the devirtualized method is a generic method instantiating stub // - wasArrayInterfaceDevirt is set TRUE for array interface method devirtualization // (in which case the method handle and context will be a generic method) // @@ -1520,7 +1520,7 @@ struct CORINFO_DEVIRTUALIZATION_INFO CORINFO_DEVIRTUALIZATION_DETAIL detail; CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedMethod; CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedUnboxedMethod; - bool requiresInstMethodDescArg; + bool isInstantiatingStub; bool wasArrayInterfaceDevirt; }; @@ -2111,6 +2111,14 @@ class ICorStaticInfo bool* requiresInstMethodTableArg ) = 0; + // Get the wrapped entry point for an instantiating stub, if possible. + // Sets methodArg for method instantiations, classArg for class instantiations. + virtual CORINFO_METHOD_HANDLE getInstantiatedEntry( + CORINFO_METHOD_HANDLE ftn, + CORINFO_METHOD_HANDLE* methodArg, + CORINFO_CLASS_HANDLE* classArg + ) = 0; + // Given T, return the type of the default Comparer. // Returns null if the type can't be determined exactly. virtual CORINFO_CLASS_HANDLE getDefaultComparerClass( @@ -2292,6 +2300,13 @@ class ICorStaticInfo unsigned index ) = 0; + // Return the type argument of the instantiated generic method, + // which is specified by the index + virtual CORINFO_CLASS_HANDLE getMethodInstantiationArgument( + CORINFO_METHOD_HANDLE ftn, + unsigned index + ) = 0; + // Prints the name for a specified class including namespaces and enclosing // classes. // See printObjectDescription for documentation for the parameters. diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index fa242d29793392..1744b5dcf20380 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -99,6 +99,11 @@ CORINFO_METHOD_HANDLE getUnboxedEntry( CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg) override; +CORINFO_METHOD_HANDLE getInstantiatedEntry( + CORINFO_METHOD_HANDLE ftn, + CORINFO_METHOD_HANDLE* methodArg, + CORINFO_CLASS_HANDLE* classArg) override; + CORINFO_CLASS_HANDLE getDefaultComparerClass( CORINFO_CLASS_HANDLE elemType) override; @@ -184,6 +189,10 @@ CORINFO_CLASS_HANDLE getTypeInstantiationArgument( CORINFO_CLASS_HANDLE cls, unsigned index) override; +CORINFO_CLASS_HANDLE getMethodInstantiationArgument( + CORINFO_METHOD_HANDLE ftn, + unsigned index) override; + size_t printClassName( CORINFO_CLASS_HANDLE cls, char* buffer, diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 44087c266f74ff..12f0f1b765605a 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* ac04f79d-8d06-4a15-9692-1b4f59265825 */ - 0xac04f79d, - 0x8d06, - 0x4a15, - {0x96, 0x92, 0x1b, 0x4f, 0x59, 0x26, 0x58, 0x25} +constexpr GUID JITEEVersionIdentifier = { /* d63b852f-8a9b-4306-89ff-7fe135eaaa5d */ + 0xd63b852f, + 0x8a9b, + 0x4306, + {0x89, 0xff, 0x7f, 0xe1, 0x35, 0xea, 0xaa, 0x5d} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 0d21b1b92cf5a1..b903dcb19709f4 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -22,6 +22,7 @@ DEF_CLR_API(getMethodClass) DEF_CLR_API(getMethodVTableOffset) DEF_CLR_API(resolveVirtualMethod) DEF_CLR_API(getUnboxedEntry) +DEF_CLR_API(getInstantiatedEntry) DEF_CLR_API(getDefaultComparerClass) DEF_CLR_API(getDefaultEqualityComparerClass) DEF_CLR_API(getSZArrayHelperEnumeratorClass) @@ -43,6 +44,7 @@ DEF_CLR_API(printObjectDescription) DEF_CLR_API(asCorInfoType) DEF_CLR_API(getClassNameFromMetadata) DEF_CLR_API(getTypeInstantiationArgument) +DEF_CLR_API(getMethodInstantiationArgument) DEF_CLR_API(printClassName) DEF_CLR_API(isValueClass) DEF_CLR_API(getClassAttribs) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 9283effbb7428f..70f4ec545e8d7e 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -191,6 +191,17 @@ CORINFO_METHOD_HANDLE WrapICorJitInfo::getUnboxedEntry( return temp; } +CORINFO_METHOD_HANDLE WrapICorJitInfo::getInstantiatedEntry( + CORINFO_METHOD_HANDLE ftn, + CORINFO_METHOD_HANDLE* methodArg, + CORINFO_CLASS_HANDLE* classArg) +{ + API_ENTER(getInstantiatedEntry); + CORINFO_METHOD_HANDLE temp = wrapHnd->getInstantiatedEntry(ftn, methodArg, classArg); + API_LEAVE(getInstantiatedEntry); + return temp; +} + CORINFO_CLASS_HANDLE WrapICorJitInfo::getDefaultComparerClass( CORINFO_CLASS_HANDLE elemType) { @@ -395,6 +406,16 @@ CORINFO_CLASS_HANDLE WrapICorJitInfo::getTypeInstantiationArgument( return temp; } +CORINFO_CLASS_HANDLE WrapICorJitInfo::getMethodInstantiationArgument( + CORINFO_METHOD_HANDLE ftn, + unsigned index) +{ + API_ENTER(getMethodInstantiationArgument); + CORINFO_CLASS_HANDLE temp = wrapHnd->getMethodInstantiationArgument(ftn, index); + API_LEAVE(getMethodInstantiationArgument); + return temp; +} + size_t WrapICorJitInfo::printClassName( CORINFO_CLASS_HANDLE cls, char* buffer, diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index be988a53b5767f..4145cf812df0b7 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3742,6 +3742,8 @@ class Compiler CORINFO_CLASS_HANDLE gtGetArrayElementClassHandle(GenTree* array); // Get a class handle from a helper call argument CORINFO_CLASS_HANDLE gtGetHelperArgClassHandle(GenTree* array); + // Get a method handle from a helper call argument + CORINFO_METHOD_HANDLE gtGetHelperArgMethodHandle(GenTree* array); // Get the class handle for a field CORINFO_CLASS_HANDLE gtGetFieldClassHandle(CORINFO_FIELD_HANDLE fieldHnd, bool* pIsExact, bool* pIsNonNull); // Check if this tree is a typeof() @@ -8991,6 +8993,11 @@ class Compiler return info.compCompHnd->getTypeInstantiationArgument(cls, index); } + CORINFO_CLASS_HANDLE getMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index) + { + return info.compCompHnd->getMethodInstantiationArgument(ftn, index); + } + bool isNumericsNamespace(const char* ns) { return strcmp(ns, "System.Numerics") == 0; diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 748f31087980d0..62cbaedf55aaa0 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -14238,6 +14238,52 @@ CORINFO_CLASS_HANDLE Compiler::gtGetHelperArgClassHandle(GenTree* tree) return result; } +//------------------------------------------------------------------------ +// gtGetHelperArgMethodHandle: find the compile time method handle from +// a helper call argument tree +// +// Arguments: +// tree - tree that passes the handle to the helper +// +// Returns: +// The compile time method handle, if known. +// +CORINFO_METHOD_HANDLE Compiler::gtGetHelperArgMethodHandle(GenTree* tree) +{ + CORINFO_METHOD_HANDLE result = NO_METHOD_HANDLE; + + // The handle could be a literal constant + if ((tree->OperGet() == GT_CNS_INT) && (tree->TypeGet() == TYP_I_IMPL)) + { + assert(tree->IsIconHandle(GTF_ICON_METHOD_HDL)); + result = (CORINFO_METHOD_HANDLE)tree->AsIntCon()->gtCompileTimeHandle; + } + // Or the result of a runtime lookup + else if (tree->OperGet() == GT_RUNTIMELOOKUP) + { + result = tree->AsRuntimeLookup()->GetMethodHandle(); + } + // Or something reached indirectly + else if (tree->gtOper == GT_IND) + { + // The handle indirs we are looking for will be marked as non-faulting. + // Certain others (eg from refanytype) may not be. + if (tree->gtFlags & GTF_IND_NONFAULTING) + { + GenTree* handleTreeInternal = tree->AsOp()->gtOp1; + + if ((handleTreeInternal->OperGet() == GT_CNS_INT) && (handleTreeInternal->TypeGet() == TYP_I_IMPL)) + { + // These handle constants should be method handles. + assert(handleTreeInternal->IsIconHandle(GTF_ICON_METHOD_HDL)); + result = (CORINFO_METHOD_HANDLE)handleTreeInternal->AsIntCon()->gtCompileTimeHandle; + } + } + } + + return result; +} + //------------------------------------------------------------------------ // gtFoldExprSpecial -- optimize binary ops with one constant operand // diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 02f41534a9e186..de755c3f295bea 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -8192,7 +8192,9 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, const char* instArg = ""; #endif - if (dvInfo.requiresInstMethodDescArg) + CORINFO_METHOD_HANDLE instantiatingStub = NO_METHOD_HANDLE; + + if (dvInfo.isInstantiatingStub) { // We should only end up with generic methods for array interface devirt. // @@ -8216,6 +8218,13 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, assert(!"unexpected inst param in virtual/interface call"); return; } + + // We want to inline the instantiating stub. Fetch the relevant info. + // + CORINFO_CLASS_HANDLE ignored = NO_CLASS_HANDLE; + derivedMethod = info.compCompHnd->getInstantiatedEntry(derivedMethod, &instantiatingStub, &ignored); + assert(ignored == NO_CLASS_HANDLE); + assert((derivedMethod == NO_METHOD_HANDLE) || (instantiatingStub != NO_METHOD_HANDLE)); } // If we failed to get a method handle, we can't directly devirtualize. @@ -8246,9 +8255,9 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, { note = "final method"; } - if (dvInfo.requiresInstMethodDescArg) + if (dvInfo.isInstantiatingStub) { - instArg = " + requires inst arg"; + instArg = " [instantiating stub]"; } if (verbose || doPrint) @@ -8311,12 +8320,11 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, call->gtControlExpr = nullptr; INDEBUG(call->gtCallDebugFlags |= GTF_CALL_MD_DEVIRTUALIZED); - if (dvInfo.requiresInstMethodDescArg) + if (dvInfo.isInstantiatingStub) { - // Pass the method desc as the inst param arg. - // Need to make sure this works in all cases. We might need more complex embedding. + // Pass the instantiating stub method desc as the inst param arg. // - GenTree* const instParam = gtNewIconNode((ssize_t)dvInfo.virtualMethod, TYP_I_IMPL); + GenTree* const instParam = gtNewIconHandleNode((size_t)instantiatingStub, GTF_ICON_METHOD_HDL); call->gtArgs.InsertInstParam(this, instParam); } @@ -8877,10 +8885,10 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall if (instParam != nullptr) { assert(instParam->GetNext() == nullptr); - CORINFO_CLASS_HANDLE hClass = gtGetHelperArgClassHandle(instParam->GetNode()); - if (hClass != NO_CLASS_HANDLE) + CORINFO_METHOD_HANDLE hMethod = gtGetHelperArgMethodHandle(instParam->GetNode()); + if (hMethod != NO_METHOD_HANDLE) { - typeHnd = getTypeInstantiationArgument(hClass, 0); + typeHnd = getMethodInstantiationArgument(hMethod, 0); } } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 18fb2c06f91aa1..08e0e5df8e8fd0 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1302,7 +1302,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) info->devirtualizedMethod = null; info->exactContext = null; info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_UNKNOWN; - info->requiresInstMethodDescArg = false; + info->isInstantiatingStub = false; info->wasArrayInterfaceDevirt = false; TypeDesc objType = HandleToObject(info->objClass); @@ -1450,7 +1450,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) #endif info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_SUCCESS; info->devirtualizedMethod = ObjectToHandle(impl); - info->requiresInstMethodDescArg = false; + info->isInstantiatingStub = false; info->exactContext = contextFromType(owningType); return true; @@ -1508,6 +1508,13 @@ static CORINFO_RESOLVED_TOKEN CreateResolvedTokenFromMethod(CorInfoImpl jitInter return result != null ? ObjectToHandle(result) : null; } + private CORINFO_METHOD_STRUCT_* getInstantiatedEntry(CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_STRUCT_** methodArg, CORINFO_CLASS_STRUCT_** classArg) + { + *methodArg = null; + *classArg = null; + return null; + } + private CORINFO_CLASS_STRUCT_* getDefaultComparerClass(CORINFO_CLASS_STRUCT_* elemType) { TypeDesc comparand = HandleToObject(elemType); @@ -2010,6 +2017,12 @@ private CorInfoType asCorInfoType(CORINFO_CLASS_STRUCT_* cls) return index < (uint)inst.Length ? ObjectToHandle(inst[(int)index]) : null; } +#pragma warning disable CA1822 // Mark members as static + private CORINFO_CLASS_STRUCT_* getMethodInstantiationArgument(CORINFO_METHOD_STRUCT_* ftn, uint index) + { +#pragma warning restore CA1822 // Mark members as static + return null; + } private nuint printClassName(CORINFO_CLASS_STRUCT_* cls, byte* buffer, nuint bufferSize, nuint* pRequiredBufferSize) { diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 11dad67fc416f8..ddf080c72b4457 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -275,6 +275,21 @@ private static byte _resolveVirtualMethod(IntPtr thisHandle, IntPtr* ppException } } + [UnmanagedCallersOnly] + private static CORINFO_METHOD_STRUCT_* _getInstantiatedEntry(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, CORINFO_METHOD_STRUCT_** methodArg, CORINFO_CLASS_STRUCT_** classArg) + { + var _this = GetThis(thisHandle); + try + { + return _this.getInstantiatedEntry(ftn, methodArg, classArg); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] private static CORINFO_CLASS_STRUCT_* _getDefaultComparerClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* elemType) { @@ -583,6 +598,21 @@ private static CorInfoType _asCorInfoType(IntPtr thisHandle, IntPtr* ppException } } + [UnmanagedCallersOnly] + private static CORINFO_CLASS_STRUCT_* _getMethodInstantiationArgument(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftn, uint index) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMethodInstantiationArgument(ftn, index); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] private static UIntPtr _printClassName(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte* buffer, UIntPtr bufferSize, UIntPtr* pRequiredBufferSize) { @@ -2608,7 +2638,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 176); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 178); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage; @@ -2628,164 +2658,166 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[15] = (delegate* unmanaged)&_getMethodVTableOffset; callbacks[16] = (delegate* unmanaged)&_resolveVirtualMethod; callbacks[17] = (delegate* unmanaged)&_getUnboxedEntry; - callbacks[18] = (delegate* unmanaged)&_getDefaultComparerClass; - callbacks[19] = (delegate* unmanaged)&_getDefaultEqualityComparerClass; - callbacks[20] = (delegate* unmanaged)&_getSZArrayHelperEnumeratorClass; - callbacks[21] = (delegate* unmanaged)&_expandRawHandleIntrinsic; - callbacks[22] = (delegate* unmanaged)&_isIntrinsicType; - callbacks[23] = (delegate* unmanaged)&_getUnmanagedCallConv; - callbacks[24] = (delegate* unmanaged)&_pInvokeMarshalingRequired; - callbacks[25] = (delegate* unmanaged)&_satisfiesMethodConstraints; - callbacks[26] = (delegate* unmanaged)&_methodMustBeLoadedBeforeCodeIsRun; - callbacks[27] = (delegate* unmanaged)&_getGSCookie; - callbacks[28] = (delegate* unmanaged)&_setPatchpointInfo; - callbacks[29] = (delegate* unmanaged)&_getOSRInfo; - callbacks[30] = (delegate* unmanaged)&_resolveToken; - callbacks[31] = (delegate* unmanaged)&_findSig; - callbacks[32] = (delegate* unmanaged)&_findCallSiteSig; - callbacks[33] = (delegate* unmanaged)&_getTokenTypeAsHandle; - callbacks[34] = (delegate* unmanaged)&_getStringLiteral; - callbacks[35] = (delegate* unmanaged)&_printObjectDescription; - callbacks[36] = (delegate* unmanaged)&_asCorInfoType; - callbacks[37] = (delegate* unmanaged)&_getClassNameFromMetadata; - callbacks[38] = (delegate* unmanaged)&_getTypeInstantiationArgument; - callbacks[39] = (delegate* unmanaged)&_printClassName; - callbacks[40] = (delegate* unmanaged)&_isValueClass; - callbacks[41] = (delegate* unmanaged)&_getClassAttribs; - callbacks[42] = (delegate* unmanaged)&_getClassAssemblyName; - callbacks[43] = (delegate* unmanaged)&_LongLifetimeMalloc; - callbacks[44] = (delegate* unmanaged)&_LongLifetimeFree; - callbacks[45] = (delegate* unmanaged)&_getIsClassInitedFlagAddress; - callbacks[46] = (delegate* unmanaged)&_getClassThreadStaticDynamicInfo; - callbacks[47] = (delegate* unmanaged)&_getClassStaticDynamicInfo; - callbacks[48] = (delegate* unmanaged)&_getStaticBaseAddress; - callbacks[49] = (delegate* unmanaged)&_getClassSize; - callbacks[50] = (delegate* unmanaged)&_getHeapClassSize; - callbacks[51] = (delegate* unmanaged)&_canAllocateOnStack; - callbacks[52] = (delegate* unmanaged)&_getClassAlignmentRequirement; - callbacks[53] = (delegate* unmanaged)&_getClassGClayout; - callbacks[54] = (delegate* unmanaged)&_getClassNumInstanceFields; - callbacks[55] = (delegate* unmanaged)&_getFieldInClass; - callbacks[56] = (delegate* unmanaged)&_getTypeLayout; - callbacks[57] = (delegate* unmanaged)&_checkMethodModifier; - callbacks[58] = (delegate* unmanaged)&_getNewHelper; - callbacks[59] = (delegate* unmanaged)&_getNewArrHelper; - callbacks[60] = (delegate* unmanaged)&_getCastingHelper; - callbacks[61] = (delegate* unmanaged)&_getSharedCCtorHelper; - callbacks[62] = (delegate* unmanaged)&_getTypeForBox; - callbacks[63] = (delegate* unmanaged)&_getTypeForBoxOnStack; - callbacks[64] = (delegate* unmanaged)&_getBoxHelper; - callbacks[65] = (delegate* unmanaged)&_getUnBoxHelper; - callbacks[66] = (delegate* unmanaged)&_getRuntimeTypePointer; - callbacks[67] = (delegate* unmanaged)&_isObjectImmutable; - callbacks[68] = (delegate* unmanaged)&_getStringChar; - callbacks[69] = (delegate* unmanaged)&_getObjectType; - callbacks[70] = (delegate* unmanaged)&_getReadyToRunHelper; - callbacks[71] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; - callbacks[72] = (delegate* unmanaged)&_initClass; - callbacks[73] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; - callbacks[74] = (delegate* unmanaged)&_getBuiltinClass; - callbacks[75] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; - callbacks[76] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; - callbacks[77] = (delegate* unmanaged)&_canCast; - callbacks[78] = (delegate* unmanaged)&_compareTypesForCast; - callbacks[79] = (delegate* unmanaged)&_compareTypesForEquality; - callbacks[80] = (delegate* unmanaged)&_isMoreSpecificType; - callbacks[81] = (delegate* unmanaged)&_isExactType; - callbacks[82] = (delegate* unmanaged)&_isGenericType; - callbacks[83] = (delegate* unmanaged)&_isNullableType; - callbacks[84] = (delegate* unmanaged)&_isEnum; - callbacks[85] = (delegate* unmanaged)&_getParentType; - callbacks[86] = (delegate* unmanaged)&_getChildType; - callbacks[87] = (delegate* unmanaged)&_isSDArray; - callbacks[88] = (delegate* unmanaged)&_getArrayRank; - callbacks[89] = (delegate* unmanaged)&_getArrayIntrinsicID; - callbacks[90] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[91] = (delegate* unmanaged)&_canAccessClass; - callbacks[92] = (delegate* unmanaged)&_printFieldName; - callbacks[93] = (delegate* unmanaged)&_getFieldClass; - callbacks[94] = (delegate* unmanaged)&_getFieldType; - callbacks[95] = (delegate* unmanaged)&_getFieldOffset; - callbacks[96] = (delegate* unmanaged)&_getFieldInfo; - callbacks[97] = (delegate* unmanaged)&_getThreadLocalFieldInfo; - callbacks[98] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; - callbacks[99] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; - callbacks[100] = (delegate* unmanaged)&_isFieldStatic; - callbacks[101] = (delegate* unmanaged)&_getArrayOrStringLength; - callbacks[102] = (delegate* unmanaged)&_getBoundaries; - callbacks[103] = (delegate* unmanaged)&_setBoundaries; - callbacks[104] = (delegate* unmanaged)&_getVars; - callbacks[105] = (delegate* unmanaged)&_setVars; - callbacks[106] = (delegate* unmanaged)&_reportRichMappings; - callbacks[107] = (delegate* unmanaged)&_reportMetadata; - callbacks[108] = (delegate* unmanaged)&_allocateArray; - callbacks[109] = (delegate* unmanaged)&_freeArray; - callbacks[110] = (delegate* unmanaged)&_getArgNext; - callbacks[111] = (delegate* unmanaged)&_getArgType; - callbacks[112] = (delegate* unmanaged)&_getExactClasses; - callbacks[113] = (delegate* unmanaged)&_getArgClass; - callbacks[114] = (delegate* unmanaged)&_getHFAType; - callbacks[115] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[116] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[117] = (delegate* unmanaged)&_getEEInfo; - callbacks[118] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[119] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[120] = (delegate* unmanaged)&_printMethodName; - callbacks[121] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[122] = (delegate* unmanaged)&_getMethodHash; - callbacks[123] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[124] = (delegate* unmanaged)&_getSwiftLowering; - callbacks[125] = (delegate* unmanaged)&_getFpStructLowering; - callbacks[126] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[127] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[128] = (delegate* unmanaged)&_getHelperFtn; - callbacks[129] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[130] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[131] = (delegate* unmanaged)&_getMethodSync; - callbacks[132] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[133] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[134] = (delegate* unmanaged)&_embedClassHandle; - callbacks[135] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[136] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[137] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[138] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[139] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[140] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[141] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[142] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[143] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[144] = (delegate* unmanaged)&_getCallInfo; - callbacks[145] = (delegate* unmanaged)&_getStaticFieldContent; - callbacks[146] = (delegate* unmanaged)&_getObjectContent; - callbacks[147] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[148] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[149] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[150] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[151] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[152] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[153] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[154] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[155] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[156] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[157] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[158] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[159] = (delegate* unmanaged)&_allocMem; - callbacks[160] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[161] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[162] = (delegate* unmanaged)&_allocGCInfo; - callbacks[163] = (delegate* unmanaged)&_setEHcount; - callbacks[164] = (delegate* unmanaged)&_setEHinfo; - callbacks[165] = (delegate* unmanaged)&_logMsg; - callbacks[166] = (delegate* unmanaged)&_doAssert; - callbacks[167] = (delegate* unmanaged)&_reportFatalError; - callbacks[168] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[169] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[170] = (delegate* unmanaged)&_recordCallSite; - callbacks[171] = (delegate* unmanaged)&_recordRelocation; - callbacks[172] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[173] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[174] = (delegate* unmanaged)&_getJitFlags; - callbacks[175] = (delegate* unmanaged)&_getSpecialCopyHelper; + callbacks[18] = (delegate* unmanaged)&_getInstantiatedEntry; + callbacks[19] = (delegate* unmanaged)&_getDefaultComparerClass; + callbacks[20] = (delegate* unmanaged)&_getDefaultEqualityComparerClass; + callbacks[21] = (delegate* unmanaged)&_getSZArrayHelperEnumeratorClass; + callbacks[22] = (delegate* unmanaged)&_expandRawHandleIntrinsic; + callbacks[23] = (delegate* unmanaged)&_isIntrinsicType; + callbacks[24] = (delegate* unmanaged)&_getUnmanagedCallConv; + callbacks[25] = (delegate* unmanaged)&_pInvokeMarshalingRequired; + callbacks[26] = (delegate* unmanaged)&_satisfiesMethodConstraints; + callbacks[27] = (delegate* unmanaged)&_methodMustBeLoadedBeforeCodeIsRun; + callbacks[28] = (delegate* unmanaged)&_getGSCookie; + callbacks[29] = (delegate* unmanaged)&_setPatchpointInfo; + callbacks[30] = (delegate* unmanaged)&_getOSRInfo; + callbacks[31] = (delegate* unmanaged)&_resolveToken; + callbacks[32] = (delegate* unmanaged)&_findSig; + callbacks[33] = (delegate* unmanaged)&_findCallSiteSig; + callbacks[34] = (delegate* unmanaged)&_getTokenTypeAsHandle; + callbacks[35] = (delegate* unmanaged)&_getStringLiteral; + callbacks[36] = (delegate* unmanaged)&_printObjectDescription; + callbacks[37] = (delegate* unmanaged)&_asCorInfoType; + callbacks[38] = (delegate* unmanaged)&_getClassNameFromMetadata; + callbacks[39] = (delegate* unmanaged)&_getTypeInstantiationArgument; + callbacks[40] = (delegate* unmanaged)&_getMethodInstantiationArgument; + callbacks[41] = (delegate* unmanaged)&_printClassName; + callbacks[42] = (delegate* unmanaged)&_isValueClass; + callbacks[43] = (delegate* unmanaged)&_getClassAttribs; + callbacks[44] = (delegate* unmanaged)&_getClassAssemblyName; + callbacks[45] = (delegate* unmanaged)&_LongLifetimeMalloc; + callbacks[46] = (delegate* unmanaged)&_LongLifetimeFree; + callbacks[47] = (delegate* unmanaged)&_getIsClassInitedFlagAddress; + callbacks[48] = (delegate* unmanaged)&_getClassThreadStaticDynamicInfo; + callbacks[49] = (delegate* unmanaged)&_getClassStaticDynamicInfo; + callbacks[50] = (delegate* unmanaged)&_getStaticBaseAddress; + callbacks[51] = (delegate* unmanaged)&_getClassSize; + callbacks[52] = (delegate* unmanaged)&_getHeapClassSize; + callbacks[53] = (delegate* unmanaged)&_canAllocateOnStack; + callbacks[54] = (delegate* unmanaged)&_getClassAlignmentRequirement; + callbacks[55] = (delegate* unmanaged)&_getClassGClayout; + callbacks[56] = (delegate* unmanaged)&_getClassNumInstanceFields; + callbacks[57] = (delegate* unmanaged)&_getFieldInClass; + callbacks[58] = (delegate* unmanaged)&_getTypeLayout; + callbacks[59] = (delegate* unmanaged)&_checkMethodModifier; + callbacks[60] = (delegate* unmanaged)&_getNewHelper; + callbacks[61] = (delegate* unmanaged)&_getNewArrHelper; + callbacks[62] = (delegate* unmanaged)&_getCastingHelper; + callbacks[63] = (delegate* unmanaged)&_getSharedCCtorHelper; + callbacks[64] = (delegate* unmanaged)&_getTypeForBox; + callbacks[65] = (delegate* unmanaged)&_getTypeForBoxOnStack; + callbacks[66] = (delegate* unmanaged)&_getBoxHelper; + callbacks[67] = (delegate* unmanaged)&_getUnBoxHelper; + callbacks[68] = (delegate* unmanaged)&_getRuntimeTypePointer; + callbacks[69] = (delegate* unmanaged)&_isObjectImmutable; + callbacks[70] = (delegate* unmanaged)&_getStringChar; + callbacks[71] = (delegate* unmanaged)&_getObjectType; + callbacks[72] = (delegate* unmanaged)&_getReadyToRunHelper; + callbacks[73] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; + callbacks[74] = (delegate* unmanaged)&_initClass; + callbacks[75] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; + callbacks[76] = (delegate* unmanaged)&_getBuiltinClass; + callbacks[77] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; + callbacks[78] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; + callbacks[79] = (delegate* unmanaged)&_canCast; + callbacks[80] = (delegate* unmanaged)&_compareTypesForCast; + callbacks[81] = (delegate* unmanaged)&_compareTypesForEquality; + callbacks[82] = (delegate* unmanaged)&_isMoreSpecificType; + callbacks[83] = (delegate* unmanaged)&_isExactType; + callbacks[84] = (delegate* unmanaged)&_isGenericType; + callbacks[85] = (delegate* unmanaged)&_isNullableType; + callbacks[86] = (delegate* unmanaged)&_isEnum; + callbacks[87] = (delegate* unmanaged)&_getParentType; + callbacks[88] = (delegate* unmanaged)&_getChildType; + callbacks[89] = (delegate* unmanaged)&_isSDArray; + callbacks[90] = (delegate* unmanaged)&_getArrayRank; + callbacks[91] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[92] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[93] = (delegate* unmanaged)&_canAccessClass; + callbacks[94] = (delegate* unmanaged)&_printFieldName; + callbacks[95] = (delegate* unmanaged)&_getFieldClass; + callbacks[96] = (delegate* unmanaged)&_getFieldType; + callbacks[97] = (delegate* unmanaged)&_getFieldOffset; + callbacks[98] = (delegate* unmanaged)&_getFieldInfo; + callbacks[99] = (delegate* unmanaged)&_getThreadLocalFieldInfo; + callbacks[100] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; + callbacks[101] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; + callbacks[102] = (delegate* unmanaged)&_isFieldStatic; + callbacks[103] = (delegate* unmanaged)&_getArrayOrStringLength; + callbacks[104] = (delegate* unmanaged)&_getBoundaries; + callbacks[105] = (delegate* unmanaged)&_setBoundaries; + callbacks[106] = (delegate* unmanaged)&_getVars; + callbacks[107] = (delegate* unmanaged)&_setVars; + callbacks[108] = (delegate* unmanaged)&_reportRichMappings; + callbacks[109] = (delegate* unmanaged)&_reportMetadata; + callbacks[110] = (delegate* unmanaged)&_allocateArray; + callbacks[111] = (delegate* unmanaged)&_freeArray; + callbacks[112] = (delegate* unmanaged)&_getArgNext; + callbacks[113] = (delegate* unmanaged)&_getArgType; + callbacks[114] = (delegate* unmanaged)&_getExactClasses; + callbacks[115] = (delegate* unmanaged)&_getArgClass; + callbacks[116] = (delegate* unmanaged)&_getHFAType; + callbacks[117] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[118] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[119] = (delegate* unmanaged)&_getEEInfo; + callbacks[120] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[121] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[122] = (delegate* unmanaged)&_printMethodName; + callbacks[123] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[124] = (delegate* unmanaged)&_getMethodHash; + callbacks[125] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[126] = (delegate* unmanaged)&_getSwiftLowering; + callbacks[127] = (delegate* unmanaged)&_getFpStructLowering; + callbacks[128] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[129] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[130] = (delegate* unmanaged)&_getHelperFtn; + callbacks[131] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[132] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[133] = (delegate* unmanaged)&_getMethodSync; + callbacks[134] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[135] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[136] = (delegate* unmanaged)&_embedClassHandle; + callbacks[137] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[138] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[139] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[140] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[141] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[142] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[143] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[144] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[145] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[146] = (delegate* unmanaged)&_getCallInfo; + callbacks[147] = (delegate* unmanaged)&_getStaticFieldContent; + callbacks[148] = (delegate* unmanaged)&_getObjectContent; + callbacks[149] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[150] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[151] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[152] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[153] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[154] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[155] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[156] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[157] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[158] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[159] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[160] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[161] = (delegate* unmanaged)&_allocMem; + callbacks[162] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[163] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[164] = (delegate* unmanaged)&_allocGCInfo; + callbacks[165] = (delegate* unmanaged)&_setEHcount; + callbacks[166] = (delegate* unmanaged)&_setEHinfo; + callbacks[167] = (delegate* unmanaged)&_logMsg; + callbacks[168] = (delegate* unmanaged)&_doAssert; + callbacks[169] = (delegate* unmanaged)&_reportFatalError; + callbacks[170] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[171] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[172] = (delegate* unmanaged)&_recordCallSite; + callbacks[173] = (delegate* unmanaged)&_recordRelocation; + callbacks[174] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[175] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[176] = (delegate* unmanaged)&_getJitFlags; + callbacks[177] = (delegate* unmanaged)&_getSpecialCopyHelper; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 9be2cf8ffd2429..94beeae55c00ff 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1083,7 +1083,7 @@ public unsafe struct CORINFO_DEVIRTUALIZATION_INFO // invariant is `resolveVirtualMethod(...) == (devirtualizedMethod != nullptr)`. // - exactContext is set to wrapped CORINFO_CLASS_HANDLE of devirt'ed method table. // - detail describes the computation done by the jit host - // - requiresInstMethodDescArg is set to TRUE if the devirtualized method requires a method desc arg. + // - isInstantiatingStub is set to TRUE if the devirtualized method is a method instantiation stub // - wasArrayInterfaceDevirt is set TRUE for array interface method devirtualization // (in which case the method handle and context will be a generic method) // @@ -1092,8 +1092,8 @@ public unsafe struct CORINFO_DEVIRTUALIZATION_INFO public CORINFO_DEVIRTUALIZATION_DETAIL detail; public CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedMethod; public CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedUnboxedMethod; - public byte _requiresInstMethodDescArg; - public bool requiresInstMethodDescArg { get { return _requiresInstMethodDescArg != 0; } set { _requiresInstMethodDescArg = value ? (byte)1 : (byte)0; } } + public byte _isInstantiatingStub; + public bool isInstantiatingStub { get { return _isInstantiatingStub != 0; } set { _isInstantiatingStub = value ? (byte)1 : (byte)0; } } public byte _wasArrayInterfaceDevirt; public bool wasArrayInterfaceDevirt { get { return _wasArrayInterfaceDevirt != 0; } set { _wasArrayInterfaceDevirt = value ? (byte)1 : (byte)0; } } } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index fd3e2961ed1dda..f964d4d4a22d42 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -141,6 +141,7 @@ GetTypeLayoutResult ; Handle types CORINFO_MODULE_HANDLE,CORINFO_MODULE_STRUCT_* CORINFO_METHOD_HANDLE,CORINFO_METHOD_STRUCT_* +CORINFO_METHOD_HANDLE*,CORINFO_METHOD_STRUCT_** CORINFO_FIELD_HANDLE,CORINFO_FIELD_STRUCT_* CORINFO_OBJECT_HANDLE,CORINFO_OBJECT_STRUCT_* CORINFO_CLASS_HANDLE,CORINFO_CLASS_STRUCT_* @@ -181,6 +182,7 @@ FUNCTIONS void getMethodVTableOffset( CORINFO_METHOD_HANDLE method, unsigned* offsetOfIndirection, unsigned* offsetAfterIndirection, bool* isRelative); bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info); CORINFO_METHOD_HANDLE getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg); + CORINFO_METHOD_HANDLE getInstantiatedEntry(CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_HANDLE* methodArg, CORINFO_CLASS_HANDLE* classArg); CORINFO_CLASS_HANDLE getDefaultComparerClass(CORINFO_CLASS_HANDLE elemType); CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE elemType); CORINFO_CLASS_HANDLE getSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE elemType); @@ -202,6 +204,7 @@ FUNCTIONS CorInfoType asCorInfoType(CORINFO_CLASS_HANDLE cls) const char* getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const char **namespaceName) CORINFO_CLASS_HANDLE getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index) + CORINFO_CLASS_HANDLE getMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index) size_t printClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) bool isValueClass(CORINFO_CLASS_HANDLE cls) uint32_t getClassAttribs(CORINFO_CLASS_HANDLE cls) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 414beda8c98906..356920821be8ae 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -29,6 +29,7 @@ struct JitInterfaceCallbacks void (* getMethodVTableOffset)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE method, unsigned* offsetOfIndirection, unsigned* offsetAfterIndirection, bool* isRelative); bool (* resolveVirtualMethod)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_DEVIRTUALIZATION_INFO* info); CORINFO_METHOD_HANDLE (* getUnboxedEntry)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg); + CORINFO_METHOD_HANDLE (* getInstantiatedEntry)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_HANDLE* methodArg, CORINFO_CLASS_HANDLE* classArg); CORINFO_CLASS_HANDLE (* getDefaultComparerClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE elemType); CORINFO_CLASS_HANDLE (* getDefaultEqualityComparerClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE elemType); CORINFO_CLASS_HANDLE (* getSZArrayHelperEnumeratorClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE elemType); @@ -50,6 +51,7 @@ struct JitInterfaceCallbacks CorInfoType (* asCorInfoType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); const char* (* getClassNameFromMetadata)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, const char** namespaceName); CORINFO_CLASS_HANDLE (* getTypeInstantiationArgument)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, unsigned index); + CORINFO_CLASS_HANDLE (* getMethodInstantiationArgument)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, unsigned index); size_t (* printClassName)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize); bool (* isValueClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); uint32_t (* getClassAttribs)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); @@ -381,6 +383,17 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual CORINFO_METHOD_HANDLE getInstantiatedEntry( + CORINFO_METHOD_HANDLE ftn, + CORINFO_METHOD_HANDLE* methodArg, + CORINFO_CLASS_HANDLE* classArg) +{ + CorInfoExceptionClass* pException = nullptr; + CORINFO_METHOD_HANDLE temp = _callbacks->getInstantiatedEntry(_thisHandle, &pException, ftn, methodArg, classArg); + if (pException != nullptr) throw pException; + return temp; +} + virtual CORINFO_CLASS_HANDLE getDefaultComparerClass( CORINFO_CLASS_HANDLE elemType) { @@ -585,6 +598,16 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual CORINFO_CLASS_HANDLE getMethodInstantiationArgument( + CORINFO_METHOD_HANDLE ftn, + unsigned index) +{ + CorInfoExceptionClass* pException = nullptr; + CORINFO_CLASS_HANDLE temp = _callbacks->getMethodInstantiationArgument(_thisHandle, &pException, ftn, index); + if (pException != nullptr) throw pException; + return temp; +} + virtual size_t printClassName( CORINFO_CLASS_HANDLE cls, char* buffer, diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 946e29e452d443..771951a68baea8 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -654,7 +654,7 @@ struct Agnostic_ResolveVirtualMethodResult { bool returnValue; DWORDLONG devirtualizedMethod; - bool requiresInstMethodDescArg; + bool isInstantiatingStub; bool wasArrayInterfaceDevirt; DWORDLONG exactContext; DWORD detail; @@ -662,6 +662,13 @@ struct Agnostic_ResolveVirtualMethodResult Agnostic_CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedUnboxedMethod; }; +struct Agnostic_GetInstantiatedEntryResult +{ + DWORDLONG methodHandle; + DWORDLONG classHandle; + DWORDLONG result; +}; + struct ResolveTokenValue { Agnostic_CORINFO_RESOLVED_TOKENout tokenOut; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 7994772771b699..b1a9ee644077fe 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -68,6 +68,7 @@ LWM(GetIsClassInitedFlagAddress, DWORDLONG, Agnostic_GetIsClassInitedFlagAddress LWM(GetStaticBaseAddress, DLD, Agnostic_GetStaticBaseAddress) LWM(GetClassNameFromMetadata, DLD, DD) LWM(GetTypeInstantiationArgument, DLD, DWORDLONG) +LWM(GetMethodInstantiationArgument, DLD, DWORDLONG) LWM(GetClassNumInstanceFields, DWORDLONG, DWORD) LWM(GetClassSize, DWORDLONG, DWORD) LWM(GetHeapClassSize, DWORDLONG, DWORD) @@ -138,6 +139,7 @@ LWM(GetTypeForBoxOnStack, DWORDLONG, DWORDLONG) LWM(GetTypeForPrimitiveValueClass, DWORDLONG, DWORD) LWM(GetTypeForPrimitiveNumericClass, DWORDLONG, DWORD) LWM(GetUnboxedEntry, DWORDLONG, DLD); +LWM(GetInstantiatedEntry, DWORDLONG, Agnostic_GetInstantiatedEntryResult); LWM(GetUnBoxHelper, DWORDLONG, DWORD) LWM(GetRuntimeTypePointer, DWORDLONG, DWORDLONG) LWM(IsObjectImmutable, DWORDLONG, DWORD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 8a2c6b208a0fc1..04c20ee645dbda 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3290,7 +3290,7 @@ void MethodContext::recResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info Agnostic_ResolveVirtualMethodResult result; result.returnValue = returnValue; result.devirtualizedMethod = CastHandle(info->devirtualizedMethod); - result.requiresInstMethodDescArg = info->requiresInstMethodDescArg; + result.isInstantiatingStub = info->isInstantiatingStub; result.exactContext = CastHandle(info->exactContext); result.detail = (DWORD) info->detail; result.wasArrayInterfaceDevirt = info->wasArrayInterfaceDevirt; @@ -3318,10 +3318,10 @@ void MethodContext::dmpResolveVirtualMethod(const Agnostic_ResolveVirtualMethodK key.context, key.pResolvedTokenVirtualMethodNonNull, key.pResolvedTokenVirtualMethodNonNull ? SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.pResolvedTokenVirtualMethod).c_str() : "???"); - printf(", value returnValue-%s, devirtMethod-%016" PRIX64 ", requiresInstArg-%s, wasArrayInterfaceDevirt-%s, exactContext-%016" PRIX64 ", detail-%d, tokDvMeth{%s}, tokDvUnboxMeth{%s}", + printf(", value returnValue-%s, devirtMethod-%016" PRIX64 ", instantiatingStub-%s, wasArrayInterfaceDevirt-%s, exactContext-%016" PRIX64 ", detail-%d, tokDvMeth{%s}, tokDvUnboxMeth{%s}", result.returnValue ? "true" : "false", result.devirtualizedMethod, - result.requiresInstMethodDescArg ? "true" : "false", + result.isInstantiatingStub ? "true" : "false", result.wasArrayInterfaceDevirt ? "true" : "false", result.exactContext, result.detail, @@ -3346,7 +3346,7 @@ bool MethodContext::repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info DEBUG_REP(dmpResolveVirtualMethod(key, result)); info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) result.devirtualizedMethod; - info->requiresInstMethodDescArg = result.requiresInstMethodDescArg; + info->isInstantiatingStub = result.isInstantiatingStub; info->wasArrayInterfaceDevirt = result.wasArrayInterfaceDevirt; info->exactContext = (CORINFO_CONTEXT_HANDLE) result.exactContext; info->detail = (CORINFO_DEVIRTUALIZATION_DETAIL) result.detail; @@ -3402,6 +3402,46 @@ CORINFO_METHOD_HANDLE MethodContext::repGetUnboxedEntry(CORINFO_METHOD_HANDLE ft return (CORINFO_METHOD_HANDLE)(value.A); } +void MethodContext::recGetInstantiatedEntry(CORINFO_METHOD_HANDLE ftn, + CORINFO_METHOD_HANDLE methodHandle, + CORINFO_CLASS_HANDLE classHandle, + CORINFO_METHOD_HANDLE result) +{ + if (GetInstantiatedEntry == nullptr) + { + GetInstantiatedEntry = new LightWeightMap(); + } + + DWORDLONG key = CastHandle(ftn); + Agnostic_GetInstantiatedEntryResult value; + value.methodHandle = CastHandle(methodHandle); + value.classHandle = CastHandle(classHandle); + value.result = CastHandle(result); + + GetInstantiatedEntry->Add(key, value); + DEBUG_REC(dmpGetUnboxedEntry(key, value)); +} + +void MethodContext::dmpGetInstantiatedEntry(DWORDLONG key, const Agnostic_GetInstantiatedEntryResult& value) +{ + printf("GetUnboxedEntry ftn-%016" PRIX64 ", methodHnd-%016" PRIX64 ", classHnd-%016" PRIX64 ", result-%016" PRIX64 "\n", + key, value.methodHandle, value.classHandle, value.result); +} + +CORINFO_METHOD_HANDLE MethodContext::repGetInstantiatedEntry(CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_HANDLE* methodHandle, CORINFO_CLASS_HANDLE* classHandle) +{ + DWORDLONG key = CastHandle(ftn); + + Agnostic_GetInstantiatedEntryResult value = LookupByKeyOrMiss(GetInstantiatedEntry, key, ": key %016" PRIX64 "", key); + + DEBUG_REP(dmpGetInstantiatedEntryEntry(key, value)); + + *methodHandle = (CORINFO_METHOD_HANDLE)value.methodHandle; + *classHandle = (CORINFO_CLASS_HANDLE)value.classHandle; + + return (CORINFO_METHOD_HANDLE)(value.result); +} + void MethodContext::recGetDefaultComparerClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result) { if (GetDefaultComparerClass == nullptr) @@ -6627,6 +6667,38 @@ CORINFO_CLASS_HANDLE MethodContext::repGetTypeInstantiationArgument(CORINFO_CLAS return (CORINFO_CLASS_HANDLE)value; } +void MethodContext::recGetMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, + unsigned index, + CORINFO_CLASS_HANDLE result) +{ + if (GetMethodInstantiationArgument == nullptr) + GetMethodInstantiationArgument = new LightWeightMap(); + + DLD key; + ZeroMemory(&key, sizeof(key)); + key.A = CastHandle(ftn); + key.B = index; + DWORDLONG value = CastHandle(result); + GetTypeInstantiationArgument->Add(key, value); + DEBUG_REC(dmpGetTypeInstantiationArgument(key, value)); +} +void MethodContext::dmpGetMethodInstantiationArgument(DLD key, DWORDLONG value) +{ + printf("GetMethodInstantiationArgument key - methodNonNull-%" PRIu64 ", index-%u, value NonNull-%" PRIu64 "", key.A, key.B, value); + GetTypeInstantiationArgument->Unlock(); +} +CORINFO_CLASS_HANDLE MethodContext::repGetMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index) +{ + DLD key; + ZeroMemory(&key, sizeof(key)); + key.A = CastHandle(ftn); + key.B = index; + + DWORDLONG value = LookupByKeyOrMissNoMessage(GetMethodInstantiationArgument, key); + DEBUG_REP(dmpGetTypeInstantiationArgument(key, value)); + return (CORINFO_CLASS_HANDLE)value; +} + void MethodContext::recPrint( const char* name, LightWeightMap*& map, diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 7ac90cce89793b..109d3ba9854fc3 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -460,6 +460,15 @@ class MethodContext void dmpGetUnboxedEntry(DWORDLONG key, DLD value); CORINFO_METHOD_HANDLE repGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg); + void recGetInstantiatedEntry(CORINFO_METHOD_HANDLE ftn, + CORINFO_METHOD_HANDLE methodHandle, + CORINFO_CLASS_HANDLE classHandle, + CORINFO_METHOD_HANDLE result); + void dmpGetInstantiatedEntry(DWORDLONG key, const Agnostic_GetInstantiatedEntryResult& value); + CORINFO_METHOD_HANDLE repGetInstantiatedEntry(CORINFO_METHOD_HANDLE ftn, + CORINFO_METHOD_HANDLE* methodHandle, + CORINFO_CLASS_HANDLE* classHandle); + void recGetDefaultComparerClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result); void dmpGetDefaultComparerClass(DWORDLONG key, DWORDLONG value); CORINFO_CLASS_HANDLE repGetDefaultComparerClass(CORINFO_CLASS_HANDLE cls); @@ -809,6 +818,10 @@ class MethodContext void dmpGetTypeInstantiationArgument(DLD key, DWORDLONG value); CORINFO_CLASS_HANDLE repGetTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index); + void recGetMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index, CORINFO_CLASS_HANDLE result); + void dmpGetMethodInstantiationArgument(DLD key, DWORDLONG value); + CORINFO_CLASS_HANDLE repGetMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index); + void recPrint( const char* name, LightWeightMap*& map, @@ -1192,6 +1205,8 @@ enum mcPackets Packet_GetSpecialCopyHelper = 224, Packet_GetClassAssemblyName = 225, Packet_GetSZArrayHelperEnumeratorClass = 226, + Packet_GetMethodInstantiationArgument = 227, + Packet_GetInstantiatedEntry = 228, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index f48e29362d18d1..a39adab7a9bffc 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -247,6 +247,14 @@ CORINFO_METHOD_HANDLE interceptor_ICJI::getUnboxedEntry(CORINFO_METHOD_HANDLE ft return result; } +CORINFO_METHOD_HANDLE interceptor_ICJI::getInstantiatedEntry(CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_HANDLE* methodHandle, CORINFO_CLASS_HANDLE* classHandle) +{ + mc->cr->AddCall("getInstantaitedEntry"); + CORINFO_METHOD_HANDLE result = original_ICorJitInfo->getInstantiatedEntry(ftn, methodHandle, classHandle); + mc->recGetInstantiatedEntry(ftn, *methodHandle, *classHandle, result); + return result; +} + // Given T, return the type of the default Comparer. // Returns null if the type can't be determined exactly. CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultComparerClass(CORINFO_CLASS_HANDLE cls) @@ -474,6 +482,14 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeInstantiationArgument(CORINFO_CLAS return result; } +CORINFO_CLASS_HANDLE interceptor_ICJI::getMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index) +{ + mc->cr->AddCall("getMethodInstantiationArgument"); + CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getMethodInstantiationArgument(ftn, index); + mc->recGetMethodInstantiationArgument(ftn, index, result); + return result; +} + size_t interceptor_ICJI::printClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) { mc->cr->AddCall("printClassName"); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index b548b1fb1c2bf5..1f6d8a0530b201 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -162,6 +162,15 @@ CORINFO_METHOD_HANDLE interceptor_ICJI::getUnboxedEntry( return original_ICorJitInfo->getUnboxedEntry(ftn, requiresInstMethodTableArg); } +CORINFO_METHOD_HANDLE interceptor_ICJI::getInstantiatedEntry( + CORINFO_METHOD_HANDLE ftn, + CORINFO_METHOD_HANDLE* methodArg, + CORINFO_CLASS_HANDLE* classArg) +{ + mcs->AddCall("getInstantiatedEntry"); + return original_ICorJitInfo->getInstantiatedEntry(ftn, methodArg, classArg); +} + CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultComparerClass( CORINFO_CLASS_HANDLE elemType) { @@ -331,6 +340,14 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeInstantiationArgument( return original_ICorJitInfo->getTypeInstantiationArgument(cls, index); } +CORINFO_CLASS_HANDLE interceptor_ICJI::getMethodInstantiationArgument( + CORINFO_METHOD_HANDLE ftn, + unsigned index) +{ + mcs->AddCall("getMethodInstantiationArgument"); + return original_ICorJitInfo->getMethodInstantiationArgument(ftn, index); +} + size_t interceptor_ICJI::printClassName( CORINFO_CLASS_HANDLE cls, char* buffer, diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 5e4e57b7ba6378..8df26208b464fa 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -144,6 +144,14 @@ CORINFO_METHOD_HANDLE interceptor_ICJI::getUnboxedEntry( return original_ICorJitInfo->getUnboxedEntry(ftn, requiresInstMethodTableArg); } +CORINFO_METHOD_HANDLE interceptor_ICJI::getInstantiatedEntry( + CORINFO_METHOD_HANDLE ftn, + CORINFO_METHOD_HANDLE* methodArg, + CORINFO_CLASS_HANDLE* classArg) +{ + return original_ICorJitInfo->getInstantiatedEntry(ftn, methodArg, classArg); +} + CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultComparerClass( CORINFO_CLASS_HANDLE elemType) { @@ -292,6 +300,13 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeInstantiationArgument( return original_ICorJitInfo->getTypeInstantiationArgument(cls, index); } +CORINFO_CLASS_HANDLE interceptor_ICJI::getMethodInstantiationArgument( + CORINFO_METHOD_HANDLE ftn, + unsigned index) +{ + return original_ICorJitInfo->getMethodInstantiationArgument(ftn, index); +} + size_t interceptor_ICJI::printClassName( CORINFO_CLASS_HANDLE cls, char* buffer, diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 0c18e39ebe9710..c8b36d5203e0c0 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -211,6 +211,13 @@ CORINFO_METHOD_HANDLE MyICJI::getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* r return result; } +CORINFO_METHOD_HANDLE MyICJI::getInstantiatedEntry(CORINFO_METHOD_HANDLE ftn, CORINFO_METHOD_HANDLE* methodHandle, CORINFO_CLASS_HANDLE* classHandle) +{ + jitInstance->mc->cr->AddCall("getInstantiatedEntry"); + CORINFO_METHOD_HANDLE result = jitInstance->mc->repGetInstantiatedEntry(ftn, methodHandle, classHandle); + return result; +} + // Given T, return the type of the default Comparer. // Returns null if the type can't be determined exactly. CORINFO_CLASS_HANDLE MyICJI::getDefaultComparerClass(CORINFO_CLASS_HANDLE cls) @@ -404,6 +411,13 @@ CORINFO_CLASS_HANDLE MyICJI::getTypeInstantiationArgument(CORINFO_CLASS_HANDLE c return result; } +CORINFO_CLASS_HANDLE MyICJI::getMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index) +{ + jitInstance->mc->cr->AddCall("getMethodInstantiationArgument"); + CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetMethodInstantiationArgument(ftn, index); + return result; +} + size_t MyICJI::printClassName(CORINFO_CLASS_HANDLE cls, char* buffer, size_t bufferSize, size_t* pRequiredBufferSize) { jitInstance->mc->cr->AddCall("printClassName"); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 0c57734078d670..75bb81d27d6b4a 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -6383,6 +6383,30 @@ CORINFO_CLASS_HANDLE CEEInfo::getTypeInstantiationArgument(CORINFO_CLASS_HANDLE return result; } +CORINFO_CLASS_HANDLE CEEInfo::getMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + CORINFO_CLASS_HANDLE result = NULL; + + JIT_TO_EE_TRANSITION_LEAF(); + + MethodDesc* method = (MethodDesc*) ftn; + _ASSERTE(method->GetNumGenericMethodArgs() == 1); + Instantiation inst = method->GetMethodInstantiation(); + + TypeHandle typeArg = index < inst.GetNumArgs() ? inst[index] : NULL; + result = CORINFO_CLASS_HANDLE(typeArg.AsPtr()); + + EE_TO_JIT_TRANSITION_LEAF(); + + return result; +} + /*********************************************************************/ bool CEEInfo::isIntrinsic(CORINFO_METHOD_HANDLE ftn) { @@ -8561,7 +8585,7 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) info->detail = CORINFO_DEVIRTUALIZATION_UNKNOWN; memset(&info->resolvedTokenDevirtualizedMethod, 0, sizeof(info->resolvedTokenDevirtualizedMethod)); memset(&info->resolvedTokenDevirtualizedUnboxedMethod, 0, sizeof(info->resolvedTokenDevirtualizedUnboxedMethod)); - info->requiresInstMethodDescArg = false; + info->isInstantiatingStub = false; info->wasArrayInterfaceDevirt = false; MethodDesc* pBaseMD = GetMethod(info->virtualMethod); @@ -8767,24 +8791,17 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) // if (isArray) { - // If array devirtualization produced an instantiation stub, - // find the wrapped method and return that instead. + // Note if array devirtualization produced an instantiation stub + // so jit can try and inline it. // - if (pDevirtMD->IsInstantiatingStub()) - { - // hack - info->virtualMethod = (CORINFO_METHOD_HANDLE)pDevirtMD; - pDevirtMD = pDevirtMD->GetWrappedMethodDesc(); - } - - info->requiresInstMethodDescArg = pDevirtMD->RequiresInstMethodDescArg(); + info->isInstantiatingStub = pDevirtMD->IsInstantiatingStub(); info->exactContext = MAKE_METHODCONTEXT((CORINFO_METHOD_HANDLE) pDevirtMD); info->wasArrayInterfaceDevirt = true; } else { info->exactContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT); - info->requiresInstMethodDescArg = false; + info->isInstantiatingStub = false; info->wasArrayInterfaceDevirt = false; } @@ -8847,6 +8864,47 @@ CORINFO_METHOD_HANDLE CEEInfo::getUnboxedEntry( return result; } +/*********************************************************************/ +CORINFO_METHOD_HANDLE CEEInfo::getInstantiatedEntry( + CORINFO_METHOD_HANDLE ftn, + CORINFO_METHOD_HANDLE* methodArg, + CORINFO_CLASS_HANDLE* classArg) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + CORINFO_METHOD_HANDLE result = NULL; + + JIT_TO_EE_TRANSITION(); + + *methodArg = NULL; + *classArg = NULL; + + MethodDesc* pMD = GetMethod(ftn); + bool requiresInstMTArg = false; + + if (pMD->IsInstantiatingStub()) + { + result = (CORINFO_METHOD_HANDLE) pMD->GetWrappedMethodDesc(); + + if (pMD->HasMethodInstantiation()) + { + *methodArg = ftn; + } + else + { + *classArg = (CORINFO_CLASS_HANDLE)pMD->GetMethodTable(); + } + } + + EE_TO_JIT_TRANSITION(); + + return result; +} + /*********************************************************************/ void CEEInfo::expandRawHandleIntrinsic( CORINFO_RESOLVED_TOKEN * pResolvedToken, From aecf6a025057bfced89e3a2a572ada1fe2664e44 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Sun, 27 Oct 2024 08:44:07 -0700 Subject: [PATCH 4/7] unblock inlining for instantiating stubs + gdvs --- src/coreclr/jit/compiler.h | 1 + src/coreclr/jit/importercalls.cpp | 76 +++++++++++++++++++++---------- src/coreclr/jit/inline.h | 2 +- 3 files changed, 53 insertions(+), 26 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 4145cf812df0b7..56410dfd3035a9 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -7567,6 +7567,7 @@ class Compiler unsigned classAttr, unsigned likelihood, bool arrayInterface, + bool instantiatingStub, CORINFO_CONTEXT_HANDLE originalContextHandle); int getGDVMaxTypeChecks() diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index de755c3f295bea..6d72f045b6f677 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -7127,7 +7127,7 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, addGuardedDevirtualizationCandidate(call, exactMethod, exactCls, exactContext, exactMethodAttrs, clsAttrs, likelyHood, dvInfo.wasArrayInterfaceDevirt, - originalContext); + dvInfo.isInstantiatingStub, originalContext); } if (call->GetInlineCandidatesCount() == numExactClasses) @@ -7150,10 +7150,11 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, // Iterate over the guesses for (int candidateId = 0; candidateId < candidatesCount; candidateId++) { - CORINFO_CLASS_HANDLE likelyClass = likelyClasses[candidateId]; - CORINFO_METHOD_HANDLE likelyMethod = likelyMethods[candidateId]; - unsigned likelihood = likelihoods[candidateId]; - bool arrayInterface = false; + CORINFO_CLASS_HANDLE likelyClass = likelyClasses[candidateId]; + CORINFO_METHOD_HANDLE likelyMethod = likelyMethods[candidateId]; + unsigned likelihood = likelihoods[candidateId]; + bool arrayInterface = false; + bool instantiatingStub = false; CORINFO_CONTEXT_HANDLE likelyContext = originalContext; @@ -7195,9 +7196,10 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, break; } - likelyContext = dvInfo.exactContext; - likelyMethod = dvInfo.devirtualizedMethod; - arrayInterface = dvInfo.wasArrayInterfaceDevirt; + likelyContext = dvInfo.exactContext; + likelyMethod = dvInfo.devirtualizedMethod; + arrayInterface = dvInfo.wasArrayInterfaceDevirt; + instantiatingStub = dvInfo.isInstantiatingStub; } else { @@ -7272,7 +7274,8 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, // Add this as a potential candidate. // addGuardedDevirtualizationCandidate(call, likelyMethod, likelyClass, likelyContext, likelyMethodAttribs, - likelyClassAttribs, likelihood, arrayInterface, originalContext); + likelyClassAttribs, likelihood, arrayInterface, instantiatingStub, + originalContext); } } @@ -7298,6 +7301,7 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, // classAttr - attributes of the class // likelihood - odds that this class is the class seen at runtime // arrayInterface - devirtualization of an array interface call +// instantiatingStub - devirtualized method in an instantiating stub // originalContextHandle - context for the original call // void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, @@ -7308,6 +7312,7 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, unsigned classAttr, unsigned likelihood, bool arrayInterface, + bool instantiatingStub, CORINFO_CONTEXT_HANDLE originalContextHandle) { // This transformation only makes sense for delegate and virtual calls @@ -7376,14 +7381,32 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, // InlineCandidateInfo* pInfo = new (this, CMK_Inlining) InlineCandidateInfo; - pInfo->guardedMethodHandle = methodHandle; - pInfo->guardedMethodUnboxedEntryHandle = nullptr; - pInfo->guardedClassHandle = classHandle; - pInfo->originalContextHandle = originalContextHandle; - pInfo->likelihood = likelihood; - pInfo->requiresInstMethodTableArg = false; - pInfo->exactContextHandle = contextHandle; - pInfo->arrayInterface = arrayInterface; + pInfo->guardedMethodHandle = methodHandle; + pInfo->guardedMethodUnboxedEntryHandle = nullptr; + pInfo->guardedMethodInstantiatedEntryHandle = nullptr; + pInfo->guardedClassHandle = classHandle; + pInfo->originalContextHandle = originalContextHandle; + pInfo->likelihood = likelihood; + pInfo->exactContextHandle = contextHandle; + pInfo->arrayInterface = arrayInterface; + + // If the guarded method is an instantiating stub, find the instantiated method + // + if (instantiatingStub) + { + JITDUMP(" ... method is an instantiating stub, looking for instantiated entry\n"); + CORINFO_CLASS_HANDLE ignoredClass = NO_CLASS_HANDLE; + CORINFO_METHOD_HANDLE ignoredMethod = NO_METHOD_HANDLE; + CORINFO_METHOD_HANDLE instantiatedMethod = + info.compCompHnd->getInstantiatedEntry(methodHandle, &ignoredMethod, &ignoredClass); + assert(ignoredClass == NO_CLASS_HANDLE); + + if (instantiatedMethod != NO_METHOD_HANDLE) + { + JITDUMP(" ... updating GDV candidate with instantiated entry info\n"); + pInfo->guardedMethodInstantiatedEntryHandle = instantiatedMethod; + } + } // If the guarded class is a value class, look for an unboxed entry point. // @@ -7398,7 +7421,6 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, { JITDUMP(" ... updating GDV candidate with unboxed entry info\n"); pInfo->guardedMethodUnboxedEntryHandle = unboxedEntryMethodHandle; - pInfo->requiresInstMethodTableArg = requiresInstMethodTableArg; } } @@ -7617,6 +7639,10 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call, { fncHandle = gdvCandidate->guardedMethodUnboxedEntryHandle; } + else if (gdvCandidate->guardedMethodInstantiatedEntryHandle != nullptr) + { + fncHandle = gdvCandidate->guardedMethodInstantiatedEntryHandle; + } else { fncHandle = gdvCandidate->guardedMethodHandle; @@ -9187,13 +9213,13 @@ void Compiler::impCheckCanInline(GenTreeCall* call, // Null out bits we don't use when we're just inlining // - pInfo->guardedClassHandle = nullptr; - pInfo->guardedMethodHandle = nullptr; - pInfo->guardedMethodUnboxedEntryHandle = nullptr; - pInfo->originalContextHandle = nullptr; - pInfo->likelihood = 0; - pInfo->requiresInstMethodTableArg = false; - pInfo->arrayInterface = false; + pInfo->guardedClassHandle = nullptr; + pInfo->guardedMethodHandle = nullptr; + pInfo->guardedMethodUnboxedEntryHandle = nullptr; + pInfo->guardedMethodInstantiatedEntryHandle = nullptr; + pInfo->originalContextHandle = nullptr; + pInfo->likelihood = 0; + pInfo->arrayInterface = false; } pInfo->methInfo = methInfo; diff --git a/src/coreclr/jit/inline.h b/src/coreclr/jit/inline.h index 8467996715736d..ce50b2cc93dba8 100644 --- a/src/coreclr/jit/inline.h +++ b/src/coreclr/jit/inline.h @@ -596,8 +596,8 @@ struct InlineCandidateInfo : public HandleHistogramProfileCandidateInfo CORINFO_CLASS_HANDLE guardedClassHandle; CORINFO_METHOD_HANDLE guardedMethodHandle; CORINFO_METHOD_HANDLE guardedMethodUnboxedEntryHandle; + CORINFO_METHOD_HANDLE guardedMethodInstantiatedEntryHandle; unsigned likelihood; - bool requiresInstMethodTableArg; bool arrayInterface; CORINFO_METHOD_INFO methInfo; From 5d214161d1a967a71d4f1f4b0528570161b88861 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Sun, 27 Oct 2024 10:48:50 -0700 Subject: [PATCH 5/7] fix embedding of inst param --- src/coreclr/jit/importercalls.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 6d72f045b6f677..7a664b242c8c9d 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -8350,7 +8350,11 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, { // Pass the instantiating stub method desc as the inst param arg. // - GenTree* const instParam = gtNewIconHandleNode((size_t)instantiatingStub, GTF_ICON_METHOD_HDL); + // Note different embedding would be needed for NAOT/R2R, + // but we have ruled those out above. + // + GenTree* const instParam = + gtNewIconEmbHandleNode(instantiatingStub, null, GTF_ICON_METHOD_HDL, instantiatingStub); call->gtArgs.InsertInstParam(this, instParam); } From baec53f243e0aca159d18f790f4fa60a1a6a42ae Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Sun, 27 Oct 2024 10:50:37 -0700 Subject: [PATCH 6/7] fix contracts --- src/coreclr/vm/jitinterface.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 75bb81d27d6b4a..db76cec75f1a43 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -6364,8 +6364,8 @@ const char* CEEInfo::getClassNameFromMetadata(CORINFO_CLASS_HANDLE cls, const ch CORINFO_CLASS_HANDLE CEEInfo::getTypeInstantiationArgument(CORINFO_CLASS_HANDLE cls, unsigned index) { CONTRACTL { - THROWS; - GC_TRIGGERS; + NOTHROW; + GC_NOTRIGGER; MODE_PREEMPTIVE; } CONTRACTL_END; @@ -6386,8 +6386,8 @@ CORINFO_CLASS_HANDLE CEEInfo::getTypeInstantiationArgument(CORINFO_CLASS_HANDLE CORINFO_CLASS_HANDLE CEEInfo::getMethodInstantiationArgument(CORINFO_METHOD_HANDLE ftn, unsigned index) { CONTRACTL { - THROWS; - GC_TRIGGERS; + NOTHROW; + GC_NOTRIGGER; MODE_PREEMPTIVE; } CONTRACTL_END; From 4126e4d81cf4513ce03fe15af9f09ebaa824e636 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Sun, 27 Oct 2024 11:09:34 -0700 Subject: [PATCH 7/7] really fix embedding --- src/coreclr/jit/importercalls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 7a664b242c8c9d..c09fe821cdae1e 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -8354,7 +8354,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // but we have ruled those out above. // GenTree* const instParam = - gtNewIconEmbHandleNode(instantiatingStub, null, GTF_ICON_METHOD_HDL, instantiatingStub); + gtNewIconEmbHndNode(instantiatingStub, nullptr, GTF_ICON_METHOD_HDL, instantiatingStub); call->gtArgs.InsertInstParam(this, instParam); }