diff --git a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs index e66b7c172c379..7386b1689866a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs @@ -740,6 +740,8 @@ private SZArrayHelper() Debug.Fail("Hey! How'd I get here?"); } + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal IEnumerator GetEnumerator() { // ! Warning: "this" is an array, not an SZArrayHelper. See comments above diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 464bcb47a4ab1..2eb4669781d14 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1510,18 +1510,21 @@ struct CORINFO_DEVIRTUALIZATION_INFO // [Out] results of resolveVirtualMethod. // - devirtualizedMethod is set to MethodDesc of devirt'ed method iff we were able to devirtualize. // invariant is `resolveVirtualMethod(...) == (devirtualizedMethod != nullptr)`. - // - requiresInstMethodTableArg is set to TRUE if the devirtualized method requires a type handle arg. // - exactContext is set to wrapped CORINFO_CLASS_HANDLE of devirt'ed method table. // - 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. + // - wasArrayInterfaceDevirt is set TRUE for array interface method devirtualization + // (in which case the method handle and context will be a generic method) // CORINFO_METHOD_HANDLE devirtualizedMethod; - bool requiresInstMethodTableArg; CORINFO_CONTEXT_HANDLE exactContext; CORINFO_DEVIRTUALIZATION_DETAIL detail; CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedMethod; CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedUnboxedMethod; + bool requiresInstMethodTableArg; + bool wasArrayInterfaceDevirt; }; //---------------------------------------------------------------------------- @@ -2123,6 +2126,12 @@ class ICorStaticInfo CORINFO_CLASS_HANDLE elemType ) = 0; + // Given T, return the type of the SZArrayHelper enumerator + // Returns null if the type can't be determined exactly. + virtual CORINFO_CLASS_HANDLE getSZArrayHelperEnumeratorClass( + CORINFO_CLASS_HANDLE elemType + ) = 0; + // Given resolved token that corresponds to an intrinsic classified to // get a raw handle (NI_System_Activator_AllocatorOf etc.), fetch the // handle associated with the token. If this is not possible at diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index ffc4659cb9fb8..fa242d2979339 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -105,6 +105,9 @@ CORINFO_CLASS_HANDLE getDefaultComparerClass( CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass( CORINFO_CLASS_HANDLE elemType) override; +CORINFO_CLASS_HANDLE getSZArrayHelperEnumeratorClass( + CORINFO_CLASS_HANDLE elemType) override; + void expandRawHandleIntrinsic( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index bce13e8aabcc3..977ba815a18a9 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 = { /* b75a5475-ff22-4078-9551-2024ce03d383 */ - 0xb75a5475, - 0xff22, - 0x4078, - {0x95, 0x51, 0x20, 0x24, 0xce, 0x03, 0xd3, 0x83} +constexpr GUID JITEEVersionIdentifier = { /* 9b8ef809-94d4-41b6-9d4c-dd61379abbe0 */ + 0x9b8ef809, + 0x94d4, + 0x41b6, + {0x9d, 0x4c, 0xdd, 0x61, 0x37, 0x9a, 0xbb, 0xe0} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 15665a14b69ba..0d21b1b92cf5a 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -24,6 +24,7 @@ DEF_CLR_API(resolveVirtualMethod) DEF_CLR_API(getUnboxedEntry) DEF_CLR_API(getDefaultComparerClass) DEF_CLR_API(getDefaultEqualityComparerClass) +DEF_CLR_API(getSZArrayHelperEnumeratorClass) DEF_CLR_API(expandRawHandleIntrinsic) DEF_CLR_API(isIntrinsicType) DEF_CLR_API(getUnmanagedCallConv) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index f45110fe0caba..9283effbb7428 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -209,6 +209,15 @@ CORINFO_CLASS_HANDLE WrapICorJitInfo::getDefaultEqualityComparerClass( return temp; } +CORINFO_CLASS_HANDLE WrapICorJitInfo::getSZArrayHelperEnumeratorClass( + CORINFO_CLASS_HANDLE elemType) +{ + API_ENTER(getSZArrayHelperEnumeratorClass); + CORINFO_CLASS_HANDLE temp = wrapHnd->getSZArrayHelperEnumeratorClass(elemType); + API_LEAVE(getSZArrayHelperEnumeratorClass); + return temp; +} + void WrapICorJitInfo::expandRawHandleIntrinsic( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index f847ca8f0bc9d..97853ad6fc8d3 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -7573,7 +7573,9 @@ class Compiler CORINFO_CONTEXT_HANDLE contextHandle, unsigned methodAttr, unsigned classAttr, - unsigned likelihood); + unsigned likelihood, + bool arrayInterface, + CORINFO_CONTEXT_HANDLE originalContextHandle); int getGDVMaxTypeChecks() { diff --git a/src/coreclr/jit/fginline.cpp b/src/coreclr/jit/fginline.cpp index 3bebd027138c1..a3858e664ec20 100644 --- a/src/coreclr/jit/fginline.cpp +++ b/src/coreclr/jit/fginline.cpp @@ -69,7 +69,7 @@ bool Compiler::IsDisallowedRecursiveInline(InlineContext* ancestor, InlineInfo* { // We disallow inlining the exact same instantiation. if ((ancestor->GetCallee() == inlineInfo->fncHandle) && - (ancestor->GetRuntimeContext() == inlineInfo->inlineCandidateInfo->exactContextHnd)) + (ancestor->GetRuntimeContext() == inlineInfo->inlineCandidateInfo->exactContextHandle)) { JITDUMP("Call site is trivially recursive\n"); return true; @@ -80,7 +80,7 @@ bool Compiler::IsDisallowedRecursiveInline(InlineContext* ancestor, InlineInfo* // involved this can quickly consume a large amount of resources, so try to // verify that we aren't inlining recursively with complex contexts. if (info.compCompHnd->haveSameMethodDefinition(inlineInfo->fncHandle, ancestor->GetCallee()) && - ContextComplexityExceeds(inlineInfo->inlineCandidateInfo->exactContextHnd, 64)) + ContextComplexityExceeds(inlineInfo->inlineCandidateInfo->exactContextHandle, 64)) { JITDUMP("Call site is recursive with a complex generic context\n"); return true; @@ -1300,7 +1300,7 @@ void Compiler::fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* inlineRe ->NewContext(pParam->inlineInfo->inlineCandidateInfo->inlinersContext, pParam->inlineInfo->iciStmt, pParam->inlineInfo->iciCall); pParam->inlineInfo->argCnt = pParam->inlineCandidateInfo->methInfo.args.totalILArgs(); - pParam->inlineInfo->tokenLookupContextHandle = pParam->inlineCandidateInfo->exactContextHnd; + pParam->inlineInfo->tokenLookupContextHandle = pParam->inlineCandidateInfo->exactContextHandle; JITLOG_THIS(pParam->pThis, (LL_INFO100000, "INLINER: inlineInfo.tokenLookupContextHandle for %s set to 0x%p:\n", @@ -2042,7 +2042,7 @@ Statement* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo) if (inlineInfo->inlineCandidateInfo->initClassResult & CORINFO_INITCLASS_USE_HELPER) { - CORINFO_CLASS_HANDLE exactClass = eeGetClassFromContext(inlineInfo->inlineCandidateInfo->exactContextHnd); + CORINFO_CLASS_HANDLE exactClass = eeGetClassFromContext(inlineInfo->inlineCandidateInfo->exactContextHandle); tree = fgGetSharedCCtor(exactClass); newStmt = gtNewStmt(tree, callDI); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index e021613381de5..6969c41666213 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -12981,9 +12981,10 @@ void Compiler::gtDispTree(GenTree* tree, { inlineInfo = call->GetSingleInlineCandidateInfo(); } - if ((inlineInfo != nullptr) && (inlineInfo->exactContextHnd != nullptr)) + + if ((inlineInfo != nullptr) && (inlineInfo->exactContextHandle != nullptr)) { - printf(" (exactContextHnd=0x%p)", dspPtr(inlineInfo->exactContextHnd)); + printf(" (exactContextHandle=0x%p)", dspPtr(inlineInfo->exactContextHandle)); } } @@ -19048,7 +19049,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b // of the inlinee. if (eeIsSharedInst(objClass)) { - CORINFO_CONTEXT_HANDLE context = inlInfo->exactContextHnd; + CORINFO_CONTEXT_HANDLE context = inlInfo->exactContextHandle; if (context != nullptr) { diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 243829e086b9e..2e18cd9015028 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -972,6 +972,13 @@ var_types Compiler::impImportCall(OPCODE opcode, // Devirtualization may change which method gets invoked. Update our local cache. // methHnd = callInfo->hMethod; + + // If we devirtualized to an intrinsic, assume this is one of the special cases. + // + if ((callInfo->methodFlags & CORINFO_FLG_INTRINSIC) != 0) + { + call->AsCall()->gtCallMoreFlags |= GTF_CALL_M_SPECIAL_INTRINSIC; + } } else if (call->AsCall()->IsDelegateInvoke()) { @@ -1349,12 +1356,26 @@ var_types Compiler::impImportCall(OPCODE opcode, eeGetCallSiteSig(pResolvedToken->token, pResolvedToken->tokenScope, pResolvedToken->tokenContext, sig); } + CORINFO_CLASS_HANDLE retTypeClass = sig->retTypeClass; + // Sometimes "call" is not a GT_CALL (if we imported an intrinsic that didn't turn into a call) if (!bIntrinsicImported) { assert(call->IsCall()); + GenTreeCall* const origCall = call->AsCall(); - GenTreeCall* origCall = call->AsCall(); + // If the call is a special intrisic, we may know a more exact return type. + // + if (origCall->IsSpecialIntrinsic()) + { + CORINFO_CLASS_HANDLE updatedRetTypeClass = impGetSpecialIntrinsicExactReturnType(origCall); + + if (updatedRetTypeClass != NO_CLASS_HANDLE) + { + JITDUMP("Updating method return type to %s\n", eeGetClassName(updatedRetTypeClass)); + retTypeClass = updatedRetTypeClass; + } + } const bool isFatPointerCandidate = origCall->IsFatPointerCandidate(); const bool isInlineCandidate = origCall->IsInlineCandidate(); @@ -1363,7 +1384,7 @@ var_types Compiler::impImportCall(OPCODE opcode, if (varTypeIsStruct(callRetTyp)) { // Need to treat all "split tree" cases here, not just inline candidates - call = impFixupCallStructReturn(call->AsCall(), sig->retTypeClass); + call = impFixupCallStructReturn(call->AsCall(), retTypeClass); callRetTyp = call->TypeGet(); } @@ -1516,7 +1537,7 @@ var_types Compiler::impImportCall(OPCODE opcode, } } - typeInfo tiRetVal = verMakeTypeInfo(sig->retType, sig->retTypeClass); + typeInfo tiRetVal = verMakeTypeInfo(sig->retType, retTypeClass); impPushOnStack(call, tiRetVal); } @@ -4673,6 +4694,14 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, break; } + case NI_System_SZArrayHelper_GetEnumerator: + case NI_System_Array_T_GetEnumerator: + { + // We may know the exact type these return + isSpecial = true; + break; + } + case NI_System_BitConverter_DoubleToInt64Bits: { GenTree* op1 = impStackTop().val; @@ -6979,6 +7008,14 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, unsigned likelihoods[MAX_GDV_TYPE_CHECKS] = {}; int candidatesCount = 0; + // Remember the original context, if any. + // + CORINFO_CONTEXT_HANDLE originalContext = nullptr; + if (pContextHandle != nullptr) + { + originalContext = *pContextHandle; + } + // We currently only get likely class guesses when there is PGO data // with class profiles. // @@ -7040,10 +7077,13 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, CORINFO_DEVIRTUALIZATION_INFO dvInfo; dvInfo.virtualMethod = baseMethod; dvInfo.objClass = exactCls; - dvInfo.context = *pContextHandle; - dvInfo.exactContext = *pContextHandle; + dvInfo.context = originalContext; + dvInfo.exactContext = originalContext; dvInfo.pResolvedTokenVirtualMethod = nullptr; + JITDUMP("GDV exact: resolveVirtualMethod (method %p class %p context %p)\n", dvInfo.virtualMethod, + dvInfo.objClass, dvInfo.context); + if (!info.compCompHnd->resolveVirtualMethod(&dvInfo)) { JITDUMP("Can't figure out which method would be invoked, sorry\n"); @@ -7052,8 +7092,9 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, break; } - CORINFO_METHOD_HANDLE exactMethod = dvInfo.devirtualizedMethod; - uint32_t exactMethodAttrs = info.compCompHnd->getMethodAttribs(exactMethod); + CORINFO_CONTEXT_HANDLE exactContext = dvInfo.exactContext; + CORINFO_METHOD_HANDLE exactMethod = dvInfo.devirtualizedMethod; + uint32_t exactMethodAttrs = info.compCompHnd->getMethodAttribs(exactMethod); // NOTE: This is currently used only with NativeAOT. In theory, we could also check if we // have static PGO data to decide which class to guess first. Presumably, this is a rare case. @@ -7067,8 +7108,9 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, likelyHood += 100 - likelyHood * numExactClasses; } - addGuardedDevirtualizationCandidate(call, exactMethod, exactCls, dvInfo.exactContext, exactMethodAttrs, - clsAttrs, likelyHood); + addGuardedDevirtualizationCandidate(call, exactMethod, exactCls, exactContext, exactMethodAttrs, + clsAttrs, likelyHood, dvInfo.wasArrayInterfaceDevirt, + originalContext); } if (call->GetInlineCandidatesCount() == numExactClasses) @@ -7091,11 +7133,12 @@ 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]; + CORINFO_CLASS_HANDLE likelyClass = likelyClasses[candidateId]; + CORINFO_METHOD_HANDLE likelyMethod = likelyMethods[candidateId]; + unsigned likelihood = likelihoods[candidateId]; + bool arrayInterface = false; - CORINFO_CONTEXT_HANDLE likelyContext = NULL; + CORINFO_CONTEXT_HANDLE likelyContext = originalContext; uint32_t likelyClassAttribs = 0; if (likelyClass != NO_CLASS_HANDLE) @@ -7118,10 +7161,13 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, CORINFO_DEVIRTUALIZATION_INFO dvInfo; dvInfo.virtualMethod = baseMethod; dvInfo.objClass = likelyClass; - dvInfo.context = *pContextHandle; - dvInfo.exactContext = *pContextHandle; + dvInfo.context = originalContext; + dvInfo.exactContext = originalContext; dvInfo.pResolvedTokenVirtualMethod = nullptr; + JITDUMP("GDV likely: resolveVirtualMethod (method %p class %p context %p)\n", dvInfo.virtualMethod, + dvInfo.objClass, dvInfo.context); + const bool canResolve = info.compCompHnd->resolveVirtualMethod(&dvInfo); if (!canResolve) @@ -7132,8 +7178,9 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, break; } - likelyContext = dvInfo.exactContext; - likelyMethod = dvInfo.devirtualizedMethod; + likelyContext = dvInfo.exactContext; + likelyMethod = dvInfo.devirtualizedMethod; + arrayInterface = dvInfo.wasArrayInterfaceDevirt; } else { @@ -7208,7 +7255,7 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, // Add this as a potential candidate. // addGuardedDevirtualizationCandidate(call, likelyMethod, likelyClass, likelyContext, likelyMethodAttribs, - likelyClassAttribs, likelihood); + likelyClassAttribs, likelihood, arrayInterface, originalContext); } } @@ -7229,9 +7276,12 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call, // call - potential guarded devirtualization candidate // methodHandle - method that will be invoked if the class test succeeds // classHandle - class that will be tested for at runtime +// contextHandle - context for the devirtualized method/class // methodAttr - attributes of the method // classAttr - attributes of the class // likelihood - odds that this class is the class seen at runtime +// arrayInterface - devirtualization of an array interface call +// originalContextHandle - context for the original call // void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, CORINFO_METHOD_HANDLE methodHandle, @@ -7239,7 +7289,9 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, CORINFO_CONTEXT_HANDLE contextHandle, unsigned methodAttr, unsigned classAttr, - unsigned likelihood) + unsigned likelihood, + bool arrayInterface, + CORINFO_CONTEXT_HANDLE originalContextHandle) { // This transformation only makes sense for delegate and virtual calls assert(call->IsDelegateInvoke() || call->IsVirtual()); @@ -7310,9 +7362,11 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, pInfo->guardedMethodHandle = methodHandle; pInfo->guardedMethodUnboxedEntryHandle = nullptr; pInfo->guardedClassHandle = classHandle; + pInfo->originalContextHandle = originalContextHandle; pInfo->likelihood = likelihood; pInfo->requiresInstMethodTableArg = false; - pInfo->exactContextHnd = contextHandle; + pInfo->exactContextHandle = contextHandle; + pInfo->arrayInterface = arrayInterface; // If the guarded class is a value class, look for an unboxed entry point. // @@ -7550,7 +7604,7 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call, { fncHandle = gdvCandidate->guardedMethodHandle; } - exactContextHnd = gdvCandidate->exactContextHnd; + exactContextHnd = gdvCandidate->exactContextHandle; methAttr = info.compCompHnd->getMethodAttribs(fncHandle); } else @@ -7971,8 +8025,8 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // might become virtual in some update. // // In non-R2R modes CALLVIRT will be turned into a - // regular call+nullcheck upstream, so we won't reach this - // point. + // regular call+nullcheck by normal call importation. + // if ((baseMethodAttribs & CORINFO_FLG_VIRTUAL) == 0) { assert(call->IsVirtualStub()); @@ -8081,6 +8135,9 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, dvInfo.detail = CORINFO_DEVIRTUALIZATION_UNKNOWN; dvInfo.pResolvedTokenVirtualMethod = pResolvedToken; + JITDUMP("ResolveVirtualMethod (method %p class %p context %p)\n", dvInfo.virtualMethod, dvInfo.objClass, + dvInfo.context); + info.compCompHnd->resolveVirtualMethod(&dvInfo); CORINFO_METHOD_HANDLE derivedMethod = dvInfo.devirtualizedMethod; @@ -8091,8 +8148,20 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, if (derivedMethod != nullptr) { assert(exactContext != nullptr); - assert(((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS); - derivedClass = (CORINFO_CLASS_HANDLE)((size_t)exactContext & ~CORINFO_CONTEXTFLAGS_MASK); + + if (((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS) + { + assert(!dvInfo.wasArrayInterfaceDevirt); + derivedClass = (CORINFO_CLASS_HANDLE)((size_t)exactContext & ~CORINFO_CONTEXTFLAGS_MASK); + } + else + { + // Array interface devirt can return a nonvirtual generic method of the non-generic SZArrayHelper class. + // + assert(dvInfo.wasArrayInterfaceDevirt); + assert(((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD); + derivedClass = info.compCompHnd->getMethodClass(derivedMethod); + } } DWORD derivedMethodAttribs = 0; @@ -8526,7 +8595,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // if (pExactContextHandle != nullptr) { - *pExactContextHandle = MAKE_CLASSCONTEXT(derivedClass); + *pExactContextHandle = exactContext; } // We might have created a new recursive tail call candidate. @@ -8675,6 +8744,11 @@ Compiler::GDVProbeType Compiler::compClassifyGDVProbeType(GenTreeCall* call) // Returns: // Exact class handle returned by the intrinsic call, if known. // Nullptr if not known, or not likely to lead to beneficial optimization. +// +// Notes: +// This computes the return type for generic factory methods, where +// the type returned is determined by a generic method or class parameter. +// CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall* call) { CORINFO_METHOD_HANDLE methodHnd = call->gtCallMethHnd; @@ -8688,6 +8762,7 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall { case NI_System_Collections_Generic_Comparer_get_Default: case NI_System_Collections_Generic_EqualityComparer_get_Default: + case NI_System_Array_T_GetEnumerator: { // Expect one class generic parameter; figure out which it is. CORINFO_SIG_INFO sig; @@ -8712,11 +8787,15 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall { result = info.compCompHnd->getDefaultEqualityComparerClass(typeHnd); } - else + else if (ni == NI_System_Collections_Generic_Comparer_get_Default) { - assert(ni == NI_System_Collections_Generic_Comparer_get_Default); result = info.compCompHnd->getDefaultComparerClass(typeHnd); } + else + { + assert(ni == NI_System_Array_T_GetEnumerator); + result = info.compCompHnd->getSZArrayHelperEnumeratorClass(typeHnd); + } if (result != NO_CLASS_HANDLE) { @@ -8725,7 +8804,44 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall } else { - JITDUMP("Special intrinsic for type %s: type undetermined, so deferring opt\n", + JITDUMP("Special intrinsic for type %s: return type undetermined, so deferring opt\n", + eeGetClassName(typeHnd)); + } + break; + } + + case NI_System_SZArrayHelper_GetEnumerator: + { + // Expect one method generic parameter; figure out which it is. + CORINFO_SIG_INFO sig; + info.compCompHnd->getMethodSig(methodHnd, &sig); + assert(sig.sigInst.methInstCount == 1); + assert(sig.sigInst.classInstCount == 0); + + CORINFO_CLASS_HANDLE typeHnd = sig.sigInst.methInst[0]; + assert(typeHnd != nullptr); + + CallArg* instParam = call->gtArgs.FindWellKnownArg(WellKnownArg::InstParam); + if (instParam != nullptr) + { + assert(instParam->GetNext() == nullptr); + CORINFO_CLASS_HANDLE hClass = gtGetHelperArgClassHandle(instParam->GetNode()); + if (hClass != NO_CLASS_HANDLE) + { + typeHnd = getTypeInstantiationArgument(hClass, 0); + } + } + + result = info.compCompHnd->getSZArrayHelperEnumeratorClass(typeHnd); + + if (result != NO_CLASS_HANDLE) + { + JITDUMP("Special intrinsic for type %s: return type is %s\n", eeGetClassName(typeHnd), + result != nullptr ? eeGetClassName(result) : "unknown"); + } + else + { + JITDUMP("Special intrinsic for type %s: return type undetermined, so deferring opt\n", eeGetClassName(typeHnd)); } break; @@ -9014,14 +9130,16 @@ void Compiler::impCheckCanInline(GenTreeCall* call, pInfo->guardedClassHandle = nullptr; pInfo->guardedMethodHandle = nullptr; pInfo->guardedMethodUnboxedEntryHandle = nullptr; + pInfo->originalContextHandle = nullptr; pInfo->likelihood = 0; pInfo->requiresInstMethodTableArg = false; + pInfo->arrayInterface = false; } pInfo->methInfo = methInfo; pInfo->ilCallerHandle = pParam->pThis->info.compMethodHnd; pInfo->clsHandle = clsHandle; - pInfo->exactContextHnd = pParam->exactContextHnd; + pInfo->exactContextHandle = pParam->exactContextHnd; pInfo->retExpr = nullptr; pInfo->preexistingSpillTemp = BAD_VAR_NUM; pInfo->clsAttr = clsAttr; @@ -9983,6 +10101,13 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) result = NI_System_Array_GetUpperBound; } } + else if (strcmp(className, "Array`1") == 0) + { + if (strcmp(methodName, "GetEnumerator") == 0) + { + result = NI_System_Array_T_GetEnumerator; + } + } break; } @@ -10214,6 +10339,14 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) result = NI_System_String_EndsWith; } } + else if (strcmp(className, "SZArrayHelper") == 0) + { + if (strcmp(methodName, "GetEnumerator") == 0) + { + result = NI_System_SZArrayHelper_GetEnumerator; + } + } + break; } diff --git a/src/coreclr/jit/indirectcalltransformer.cpp b/src/coreclr/jit/indirectcalltransformer.cpp index c08ab7cd2849d..9fbac3b55a46e 100644 --- a/src/coreclr/jit/indirectcalltransformer.cpp +++ b/src/coreclr/jit/indirectcalltransformer.cpp @@ -899,9 +899,18 @@ class IndirectCallTransformer JITDUMP("Direct call [%06u] in block " FMT_BB "\n", compiler->dspTreeID(call), block->bbNum); CORINFO_METHOD_HANDLE methodHnd = inlineInfo->guardedMethodHandle; - CORINFO_CONTEXT_HANDLE context = inlineInfo->exactContextHnd; + CORINFO_CONTEXT_HANDLE context = inlineInfo->exactContextHandle; if (clsHnd != NO_CLASS_HANDLE) { + // If we devirtualized an array interface call, + // pass the original method handle and original context handle to the devirtualizer. + // + if (inlineInfo->arrayInterface) + { + methodHnd = call->gtCallMethHnd; + context = inlineInfo->originalContextHandle; + } + // Then invoke impDevirtualizeCall to actually transform the call for us, // given the original (base) method and the exact guarded class. It should succeed. // @@ -995,7 +1004,7 @@ class IndirectCallTransformer // GenTreeRetExpr* oldRetExpr = inlineInfo->retExpr; inlineInfo->clsHandle = compiler->info.compCompHnd->getMethodClass(methodHnd); - inlineInfo->exactContextHnd = context; + inlineInfo->exactContextHandle = context; inlineInfo->preexistingSpillTemp = returnTemp; call->SetSingleInlineCandidateInfo(inlineInfo); diff --git a/src/coreclr/jit/inline.cpp b/src/coreclr/jit/inline.cpp index bebd5622d3f87..bcbf92fe8e736 100644 --- a/src/coreclr/jit/inline.cpp +++ b/src/coreclr/jit/inline.cpp @@ -1289,7 +1289,7 @@ InlineContext* InlineStrategy::NewContext(InlineContext* parentContext, Statemen context->m_Code = info->methInfo.ILCode; context->m_ILSize = info->methInfo.ILCodeSize; context->m_ActualCallOffset = info->ilOffset; - context->m_RuntimeContext = info->exactContextHnd; + context->m_RuntimeContext = info->exactContextHandle; #ifdef DEBUG // All inline candidates should get their own statements that have diff --git a/src/coreclr/jit/inline.h b/src/coreclr/jit/inline.h index a2aeba6fed725..8467996715736 100644 --- a/src/coreclr/jit/inline.h +++ b/src/coreclr/jit/inline.h @@ -598,13 +598,22 @@ struct InlineCandidateInfo : public HandleHistogramProfileCandidateInfo CORINFO_METHOD_HANDLE guardedMethodUnboxedEntryHandle; unsigned likelihood; bool requiresInstMethodTableArg; + bool arrayInterface; CORINFO_METHOD_INFO methInfo; // the logical IL caller of this inlinee. - CORINFO_METHOD_HANDLE ilCallerHandle; - CORINFO_CLASS_HANDLE clsHandle; - CORINFO_CONTEXT_HANDLE exactContextHnd; + CORINFO_METHOD_HANDLE ilCallerHandle; + CORINFO_CLASS_HANDLE clsHandle; + + // Context handle to use when inlining. + // + CORINFO_CONTEXT_HANDLE exactContextHandle; + + // Context handle of the call before any + // GDV/Inlining evaluation + // + CORINFO_CONTEXT_HANDLE originalContextHandle; // The GT_RET_EXPR node linking back to the inline candidate. GenTreeRetExpr* retExpr; diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 54d4d954abf68..d71903bea8e76 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -251,6 +251,12 @@ enum NamedIntrinsic : unsigned short NI_PRIMITIVE_TrailingZeroCount, NI_PRIMITIVE_END, + + // + // Array Intrinsics + // + NI_System_SZArrayHelper_GetEnumerator, + NI_System_Array_T_GetEnumerator, }; #endif // _NAMEDINTRINSICLIST_H_ diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs index faa4d51e93532..dc30aaecd1f06 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.NativeAot.cs @@ -897,6 +897,7 @@ internal class Array : Array, IEnumerable, ICollection, IList, IRead // Prevent the C# compiler from generating a public default constructor private Array() { } + [Intrinsic] public new IEnumerator GetEnumerator() { T[] @this = Unsafe.As(this); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index d766ded60142e..5038448f8cafc 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1300,9 +1300,10 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) { // Initialize OUT fields info->devirtualizedMethod = null; - info->requiresInstMethodTableArg = false; info->exactContext = null; info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_UNKNOWN; + info->requiresInstMethodTableArg = false; + info->wasArrayInterfaceDevirt = false; TypeDesc objType = HandleToObject(info->objClass); @@ -1521,6 +1522,17 @@ static CORINFO_RESOLVED_TOKEN CreateResolvedTokenFromMethod(CorInfoImpl jitInter return comparer != null ? ObjectToHandle(comparer) : null; } + private CORINFO_CLASS_STRUCT_* getSZArrayHelperEnumeratorClass(CORINFO_CLASS_STRUCT_* elemType) + { + TypeDesc elementType = HandleToObject(elemType); + MetadataType placeholderType = _compilation.TypeSystemContext.SystemModule.GetType("System", "SZGenericArrayEnumerator`1", throwIfNotFound: false); + if (placeholderType == null) + { + return null; + } + return ObjectToHandle(placeholderType.MakeInstantiatedType(elementType)); + } + private bool isIntrinsicType(CORINFO_CLASS_STRUCT_* classHnd) { TypeDesc type = HandleToObject(classHnd); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 26291e015b428..11dad67fc416f 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -305,6 +305,21 @@ private static byte _resolveVirtualMethod(IntPtr thisHandle, IntPtr* ppException } } + [UnmanagedCallersOnly] + private static CORINFO_CLASS_STRUCT_* _getSZArrayHelperEnumeratorClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* elemType) + { + var _this = GetThis(thisHandle); + try + { + return _this.getSZArrayHelperEnumeratorClass(elemType); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] private static void _expandRawHandleIntrinsic(IntPtr thisHandle, IntPtr* ppException, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_STRUCT_* callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) { @@ -2593,7 +2608,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 175); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 176); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage; @@ -2615,161 +2630,162 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[17] = (delegate* unmanaged)&_getUnboxedEntry; callbacks[18] = (delegate* unmanaged)&_getDefaultComparerClass; callbacks[19] = (delegate* unmanaged)&_getDefaultEqualityComparerClass; - callbacks[20] = (delegate* unmanaged)&_expandRawHandleIntrinsic; - callbacks[21] = (delegate* unmanaged)&_isIntrinsicType; - callbacks[22] = (delegate* unmanaged)&_getUnmanagedCallConv; - callbacks[23] = (delegate* unmanaged)&_pInvokeMarshalingRequired; - callbacks[24] = (delegate* unmanaged)&_satisfiesMethodConstraints; - callbacks[25] = (delegate* unmanaged)&_methodMustBeLoadedBeforeCodeIsRun; - callbacks[26] = (delegate* unmanaged)&_getGSCookie; - callbacks[27] = (delegate* unmanaged)&_setPatchpointInfo; - callbacks[28] = (delegate* unmanaged)&_getOSRInfo; - callbacks[29] = (delegate* unmanaged)&_resolveToken; - callbacks[30] = (delegate* unmanaged)&_findSig; - callbacks[31] = (delegate* unmanaged)&_findCallSiteSig; - callbacks[32] = (delegate* unmanaged)&_getTokenTypeAsHandle; - callbacks[33] = (delegate* unmanaged)&_getStringLiteral; - callbacks[34] = (delegate* unmanaged)&_printObjectDescription; - callbacks[35] = (delegate* unmanaged)&_asCorInfoType; - callbacks[36] = (delegate* unmanaged)&_getClassNameFromMetadata; - callbacks[37] = (delegate* unmanaged)&_getTypeInstantiationArgument; - callbacks[38] = (delegate* unmanaged)&_printClassName; - callbacks[39] = (delegate* unmanaged)&_isValueClass; - callbacks[40] = (delegate* unmanaged)&_getClassAttribs; - callbacks[41] = (delegate* unmanaged)&_getClassAssemblyName; - callbacks[42] = (delegate* unmanaged)&_LongLifetimeMalloc; - callbacks[43] = (delegate* unmanaged)&_LongLifetimeFree; - callbacks[44] = (delegate* unmanaged)&_getIsClassInitedFlagAddress; - callbacks[45] = (delegate* unmanaged)&_getClassThreadStaticDynamicInfo; - callbacks[46] = (delegate* unmanaged)&_getClassStaticDynamicInfo; - callbacks[47] = (delegate* unmanaged)&_getStaticBaseAddress; - callbacks[48] = (delegate* unmanaged)&_getClassSize; - callbacks[49] = (delegate* unmanaged)&_getHeapClassSize; - callbacks[50] = (delegate* unmanaged)&_canAllocateOnStack; - callbacks[51] = (delegate* unmanaged)&_getClassAlignmentRequirement; - callbacks[52] = (delegate* unmanaged)&_getClassGClayout; - callbacks[53] = (delegate* unmanaged)&_getClassNumInstanceFields; - callbacks[54] = (delegate* unmanaged)&_getFieldInClass; - callbacks[55] = (delegate* unmanaged)&_getTypeLayout; - callbacks[56] = (delegate* unmanaged)&_checkMethodModifier; - callbacks[57] = (delegate* unmanaged)&_getNewHelper; - callbacks[58] = (delegate* unmanaged)&_getNewArrHelper; - callbacks[59] = (delegate* unmanaged)&_getCastingHelper; - callbacks[60] = (delegate* unmanaged)&_getSharedCCtorHelper; - callbacks[61] = (delegate* unmanaged)&_getTypeForBox; - callbacks[62] = (delegate* unmanaged)&_getTypeForBoxOnStack; - callbacks[63] = (delegate* unmanaged)&_getBoxHelper; - callbacks[64] = (delegate* unmanaged)&_getUnBoxHelper; - callbacks[65] = (delegate* unmanaged)&_getRuntimeTypePointer; - callbacks[66] = (delegate* unmanaged)&_isObjectImmutable; - callbacks[67] = (delegate* unmanaged)&_getStringChar; - callbacks[68] = (delegate* unmanaged)&_getObjectType; - callbacks[69] = (delegate* unmanaged)&_getReadyToRunHelper; - callbacks[70] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; - callbacks[71] = (delegate* unmanaged)&_initClass; - callbacks[72] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; - callbacks[73] = (delegate* unmanaged)&_getBuiltinClass; - callbacks[74] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; - callbacks[75] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; - callbacks[76] = (delegate* unmanaged)&_canCast; - callbacks[77] = (delegate* unmanaged)&_compareTypesForCast; - callbacks[78] = (delegate* unmanaged)&_compareTypesForEquality; - callbacks[79] = (delegate* unmanaged)&_isMoreSpecificType; - callbacks[80] = (delegate* unmanaged)&_isExactType; - callbacks[81] = (delegate* unmanaged)&_isGenericType; - callbacks[82] = (delegate* unmanaged)&_isNullableType; - callbacks[83] = (delegate* unmanaged)&_isEnum; - callbacks[84] = (delegate* unmanaged)&_getParentType; - callbacks[85] = (delegate* unmanaged)&_getChildType; - callbacks[86] = (delegate* unmanaged)&_isSDArray; - callbacks[87] = (delegate* unmanaged)&_getArrayRank; - callbacks[88] = (delegate* unmanaged)&_getArrayIntrinsicID; - callbacks[89] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[90] = (delegate* unmanaged)&_canAccessClass; - callbacks[91] = (delegate* unmanaged)&_printFieldName; - callbacks[92] = (delegate* unmanaged)&_getFieldClass; - callbacks[93] = (delegate* unmanaged)&_getFieldType; - callbacks[94] = (delegate* unmanaged)&_getFieldOffset; - callbacks[95] = (delegate* unmanaged)&_getFieldInfo; - callbacks[96] = (delegate* unmanaged)&_getThreadLocalFieldInfo; - callbacks[97] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; - callbacks[98] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; - callbacks[99] = (delegate* unmanaged)&_isFieldStatic; - callbacks[100] = (delegate* unmanaged)&_getArrayOrStringLength; - callbacks[101] = (delegate* unmanaged)&_getBoundaries; - callbacks[102] = (delegate* unmanaged)&_setBoundaries; - callbacks[103] = (delegate* unmanaged)&_getVars; - callbacks[104] = (delegate* unmanaged)&_setVars; - callbacks[105] = (delegate* unmanaged)&_reportRichMappings; - callbacks[106] = (delegate* unmanaged)&_reportMetadata; - callbacks[107] = (delegate* unmanaged)&_allocateArray; - callbacks[108] = (delegate* unmanaged)&_freeArray; - callbacks[109] = (delegate* unmanaged)&_getArgNext; - callbacks[110] = (delegate* unmanaged)&_getArgType; - callbacks[111] = (delegate* unmanaged)&_getExactClasses; - callbacks[112] = (delegate* unmanaged)&_getArgClass; - callbacks[113] = (delegate* unmanaged)&_getHFAType; - callbacks[114] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[115] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[116] = (delegate* unmanaged)&_getEEInfo; - callbacks[117] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[118] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[119] = (delegate* unmanaged)&_printMethodName; - callbacks[120] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[121] = (delegate* unmanaged)&_getMethodHash; - callbacks[122] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[123] = (delegate* unmanaged)&_getSwiftLowering; - callbacks[124] = (delegate* unmanaged)&_getFpStructLowering; - callbacks[125] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[126] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[127] = (delegate* unmanaged)&_getHelperFtn; - callbacks[128] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[129] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[130] = (delegate* unmanaged)&_getMethodSync; - callbacks[131] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[132] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[133] = (delegate* unmanaged)&_embedClassHandle; - callbacks[134] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[135] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[136] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[137] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[138] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[139] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[140] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[141] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[142] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[143] = (delegate* unmanaged)&_getCallInfo; - callbacks[144] = (delegate* unmanaged)&_getStaticFieldContent; - callbacks[145] = (delegate* unmanaged)&_getObjectContent; - callbacks[146] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[147] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[148] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[149] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[150] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[151] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[152] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[153] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[154] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[155] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[156] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[157] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[158] = (delegate* unmanaged)&_allocMem; - callbacks[159] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[160] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[161] = (delegate* unmanaged)&_allocGCInfo; - callbacks[162] = (delegate* unmanaged)&_setEHcount; - callbacks[163] = (delegate* unmanaged)&_setEHinfo; - callbacks[164] = (delegate* unmanaged)&_logMsg; - callbacks[165] = (delegate* unmanaged)&_doAssert; - callbacks[166] = (delegate* unmanaged)&_reportFatalError; - callbacks[167] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[168] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[169] = (delegate* unmanaged)&_recordCallSite; - callbacks[170] = (delegate* unmanaged)&_recordRelocation; - callbacks[171] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[172] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[173] = (delegate* unmanaged)&_getJitFlags; - callbacks[174] = (delegate* unmanaged)&_getSpecialCopyHelper; + 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; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 74b260578fd00..b6fbb9cbb84ae 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1081,17 +1081,21 @@ public unsafe struct CORINFO_DEVIRTUALIZATION_INFO // [Out] results of resolveVirtualMethod. // - devirtualizedMethod is set to MethodDesc of devirt'ed method iff we were able to devirtualize. // invariant is `resolveVirtualMethod(...) == (devirtualizedMethod != nullptr)`. - // - requiresInstMethodTableArg is set to TRUE if the devirtualized method requires a type handle arg. // - 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. + // - wasArrayInterfaceDevirt is set TRUE for array interface method devirtualization + // (in which case the method handle and context will be a generic method) // public CORINFO_METHOD_STRUCT_* devirtualizedMethod; - public byte _requiresInstMethodTableArg; - public bool requiresInstMethodTableArg { get { return _requiresInstMethodTableArg != 0; } set { _requiresInstMethodTableArg = value ? (byte)1 : (byte)0; } } public CORINFO_CONTEXT_STRUCT* exactContext; 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 _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 bf98cf70a7e2d..fd3e2961ed1dd 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -183,6 +183,7 @@ FUNCTIONS CORINFO_METHOD_HANDLE getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg); CORINFO_CLASS_HANDLE getDefaultComparerClass(CORINFO_CLASS_HANDLE elemType); CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE elemType); + CORINFO_CLASS_HANDLE getSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE elemType); void expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_GENERICHANDLE_RESULT * pResult); bool isIntrinsicType( CORINFO_CLASS_HANDLE classHnd ); CorInfoCallConvExtension getUnmanagedCallConv( CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition); diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 0e9bde0b4def1..414beda8c9890 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -31,6 +31,7 @@ struct JitInterfaceCallbacks CORINFO_METHOD_HANDLE (* getUnboxedEntry)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg); 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); void (* expandRawHandleIntrinsic)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult); bool (* isIntrinsicType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE classHnd); CorInfoCallConvExtension (* getUnmanagedCallConv)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* callSiteSig, bool* pSuppressGCTransition); @@ -398,6 +399,15 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual CORINFO_CLASS_HANDLE getSZArrayHelperEnumeratorClass( + CORINFO_CLASS_HANDLE elemType) +{ + CorInfoExceptionClass* pException = nullptr; + CORINFO_CLASS_HANDLE temp = _callbacks->getSZArrayHelperEnumeratorClass(_thisHandle, &pException, elemType); + if (pException != nullptr) throw pException; + return temp; +} + virtual void expandRawHandleIntrinsic( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 032284ce3a98a..a0138db26532b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -655,6 +655,7 @@ struct Agnostic_ResolveVirtualMethodResult bool returnValue; DWORDLONG devirtualizedMethod; bool requiresInstMethodTableArg; + bool wasArrayInterfaceDevirt; DWORDLONG exactContext; DWORD detail; Agnostic_CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedMethod; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 64b394309f567..7994772771b69 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -75,6 +75,7 @@ LWM(CanAllocateOnStack, DWORDLONG, DWORD) LWM(GetCookieForPInvokeCalliSig, GetCookieForPInvokeCalliSigValue, DLDL) LWM(GetDefaultComparerClass, DWORDLONG, DWORDLONG) LWM(GetDefaultEqualityComparerClass, DWORDLONG, DWORDLONG) +LWM(GetSZArrayHelperEnumeratorClass, DWORDLONG, DWORDLONG) LWM(GetDelegateCtor, Agnostic_GetDelegateCtorIn, Agnostic_GetDelegateCtorOut) LWM(GetEEInfo, DWORD, Agnostic_CORINFO_EE_INFO) LWM(GetEHinfo, DLD, Agnostic_CORINFO_EH_CLAUSE) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 36974d6534a71..8455abdb80d61 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3293,6 +3293,7 @@ void MethodContext::recResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info result.requiresInstMethodTableArg = info->requiresInstMethodTableArg; result.exactContext = CastHandle(info->exactContext); result.detail = (DWORD) info->detail; + result.wasArrayInterfaceDevirt = info->wasArrayInterfaceDevirt; if (returnValue) { @@ -3317,10 +3318,11 @@ 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, exactContext-%016" PRIX64 ", detail-%d, tokDvMeth{%s}, tokDvUnboxMeth{%s}", + 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.wasArrayInterfaceDevirt ? "true" : "false", result.exactContext, result.detail, result.returnValue ? SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(result.resolvedTokenDevirtualizedMethod).c_str() : "???", @@ -3345,6 +3347,7 @@ bool MethodContext::repResolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO * info info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) result.devirtualizedMethod; info->requiresInstMethodTableArg = result.requiresInstMethodTableArg; + info->wasArrayInterfaceDevirt = result.wasArrayInterfaceDevirt; info->exactContext = (CORINFO_CONTEXT_HANDLE) result.exactContext; info->detail = (CORINFO_DEVIRTUALIZATION_DETAIL) result.detail; if (result.returnValue) @@ -3445,6 +3448,29 @@ CORINFO_CLASS_HANDLE MethodContext::repGetDefaultEqualityComparerClass(CORINFO_C return result; } +void MethodContext::recGetSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result) +{ + if (GetSZArrayHelperEnumeratorClass == nullptr) + GetSZArrayHelperEnumeratorClass = new LightWeightMap(); + + DWORDLONG key = CastHandle(cls); + DWORDLONG value = CastHandle(result); + GetSZArrayHelperEnumeratorClass->Add(key, value); + DEBUG_REC(dmpGetSZArrayHelperEnumeratorClass(key, value)); +} +void MethodContext::dmpGetSZArrayHelperEnumeratorClass(DWORDLONG key, DWORDLONG value) +{ + printf("GetSZArrayHelperEnumeratorClass key cls-%016" PRIX64 ", value cls-%016" PRIX64 "", key, value); +} +CORINFO_CLASS_HANDLE MethodContext::repGetSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE cls) +{ + DWORDLONG key = CastHandle(cls); + DWORDLONG value = LookupByKeyOrMiss(GetSZArrayHelperEnumeratorClass, key, ": key %016" PRIX64 "", key); + DEBUG_REP(dmpGetSZArrayHelperEnumeratorClass(key, value)); + CORINFO_CLASS_HANDLE result = (CORINFO_CLASS_HANDLE)value; + return result; +} + void MethodContext::recGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CLASS_HANDLE result) { if (GetTokenTypeAsHandle == nullptr) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 0fd63deb1bad4..7ac90cce89793 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -468,6 +468,10 @@ class MethodContext void dmpGetDefaultEqualityComparerClass(DWORDLONG key, DWORDLONG value); CORINFO_CLASS_HANDLE repGetDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls); + void recGetSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result); + void dmpGetSZArrayHelperEnumeratorClass(DWORDLONG key, DWORDLONG value); + CORINFO_CLASS_HANDLE repGetSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE cls); + void recGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CLASS_HANDLE result); void dmpGetTokenTypeAsHandle(const GetTokenTypeAsHandleValue& key, DWORDLONG value); CORINFO_CLASS_HANDLE repGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken); @@ -1187,6 +1191,7 @@ enum mcPackets Packet_GetFpStructLowering = 223, Packet_GetSpecialCopyHelper = 224, Packet_GetClassAssemblyName = 225, + Packet_GetSZArrayHelperEnumeratorClass = 226, }; 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 274ebcaa7eb00..f48e29362d18d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -267,6 +267,16 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass(CORINFO_C return result; } +// Given T, return the type of the SZGenericArrayEnumerator. +// Returns null if the type can't be determined exactly. +CORINFO_CLASS_HANDLE interceptor_ICJI::getSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE cls) +{ + mc->cr->AddCall("getSZArrayHelperEnumeratorClass"); + CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getSZArrayHelperEnumeratorClass(cls); + mc->recGetSZArrayHelperEnumeratorClass(cls, result); + return result; +} + void interceptor_ICJI::expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) 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 bba12312ee908..b548b1fb1c2bf 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -176,6 +176,13 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass( return original_ICorJitInfo->getDefaultEqualityComparerClass(elemType); } +CORINFO_CLASS_HANDLE interceptor_ICJI::getSZArrayHelperEnumeratorClass( + CORINFO_CLASS_HANDLE elemType) +{ + mcs->AddCall("getSZArrayHelperEnumeratorClass"); + return original_ICorJitInfo->getSZArrayHelperEnumeratorClass(elemType); +} + void interceptor_ICJI::expandRawHandleIntrinsic( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, 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 2c789226b7f56..5e4e57b7ba637 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -156,6 +156,12 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass( return original_ICorJitInfo->getDefaultEqualityComparerClass(elemType); } +CORINFO_CLASS_HANDLE interceptor_ICJI::getSZArrayHelperEnumeratorClass( + CORINFO_CLASS_HANDLE elemType) +{ + return original_ICorJitInfo->getSZArrayHelperEnumeratorClass(elemType); +} + void interceptor_ICJI::expandRawHandleIntrinsic( CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 0fc1df067dd7d..0c18e39ebe971 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -229,6 +229,15 @@ CORINFO_CLASS_HANDLE MyICJI::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDL return result; } +// Given T, return the type of the SZGenericArrayEnumerator. +// Returns null if the type can't be determined exactly. +CORINFO_CLASS_HANDLE MyICJI::getSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE cls) +{ + jitInstance->mc->cr->AddCall("getSZArrayHelperEnumeratorClass"); + CORINFO_CLASS_HANDLE result = jitInstance->mc->repGetSZArrayHelperEnumeratorClass(cls); + return result; +} + void MyICJI::expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult) { jitInstance->mc->cr->AddCall("expandRawHandleIntrinsic"); diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 17ee79fb96858..de6e16cbe25eb 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1072,6 +1072,8 @@ DEFINE_METHOD(SZARRAYHELPER, INDEXOF, IndexOf, DEFINE_METHOD(SZARRAYHELPER, INSERT, Insert, NoSig) DEFINE_METHOD(SZARRAYHELPER, REMOVEAT, RemoveAt, NoSig) +DEFINE_CLASS(SZGENERICARRAYENUMERATOR, System, SZGenericArrayEnumerator`1) + DEFINE_CLASS(IENUMERABLEGENERIC, CollectionsGeneric, IEnumerable`1) DEFINE_CLASS(IENUMERATORGENERIC, CollectionsGeneric, IEnumerator`1) DEFINE_CLASS(ICOLLECTIONGENERIC, CollectionsGeneric, ICollection`1) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 9e26592648170..28d95e523f6cd 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -8558,10 +8558,12 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) // Initialize OUT fields info->devirtualizedMethod = NULL; - info->requiresInstMethodTableArg = false; info->exactContext = NULL; + info->detail = CORINFO_DEVIRTUALIZATION_UNKNOWN; memset(&info->resolvedTokenDevirtualizedMethod, 0, sizeof(info->resolvedTokenDevirtualizedMethod)); memset(&info->resolvedTokenDevirtualizedUnboxedMethod, 0, sizeof(info->resolvedTokenDevirtualizedUnboxedMethod)); + info->requiresInstMethodTableArg = false; + info->wasArrayInterfaceDevirt = false; MethodDesc* pBaseMD = GetMethod(info->virtualMethod); MethodTable* pBaseMT = pBaseMD->GetMethodTable(); @@ -8609,7 +8611,27 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) // // We must ensure that pObjMT actually implements the // interface corresponding to pBaseMD. - if (!pObjMT->CanCastToInterface(pBaseMT)) + // + if (pObjMT->IsArray()) + { + // If we're in a shared context we'll devirt to a shared + // generic method and won't be able to inline, so just bail. + // + if (pBaseMT->IsSharedByGenericInstantiations()) + { + info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CANON; + return false; + } + + // Ensure we can cast the array to the interface type + // + if (!TypeHandle(pObjMT).CanCastTo(TypeHandle(pBaseMT))) + { + info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CAST; + return false; + } + } + else if (!pObjMT->CanCastToInterface(pBaseMT)) { info->detail = CORINFO_DEVIRTUALIZATION_FAILED_CAST; return false; @@ -8719,8 +8741,12 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) // We may fail to get an exact context if the method is a default // interface method. If so, we'll use the method's class. // + // For array -> interface devirt, the devirtualized methods + // will be defined by SZArrayHelper. + // MethodTable* pApproxMT = pDevirtMD->GetMethodTable(); MethodTable* pExactMT = pApproxMT; + bool isArray = false; if (pApproxMT->IsInterface()) { @@ -8729,6 +8755,10 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) _ASSERTE(!pDevirtMD->HasClassInstantiation()); } + else if (pBaseMT->IsInterface() && pObjMT->IsArray()) + { + isArray = true; + } else { pExactMT = pDevirtMD->GetExactDeclaringType(pObjMT); @@ -8737,8 +8767,20 @@ bool CEEInfo::resolveVirtualMethodHelper(CORINFO_DEVIRTUALIZATION_INFO * info) // Success! Pass back the results. // info->devirtualizedMethod = (CORINFO_METHOD_HANDLE) pDevirtMD; - info->exactContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT); - info->requiresInstMethodTableArg = false; + + if (isArray) + { + info->exactContext = MAKE_METHODCONTEXT((CORINFO_METHOD_HANDLE) pDevirtMD); + info->requiresInstMethodTableArg = pDevirtMD->RequiresInstMethodTableArg(); + info->wasArrayInterfaceDevirt = true; + } + else + { + info->exactContext = MAKE_CLASSCONTEXT((CORINFO_CLASS_HANDLE) pExactMT); + info->requiresInstMethodTableArg = false; + info->wasArrayInterfaceDevirt = false; + } + info->detail = CORINFO_DEVIRTUALIZATION_SUCCESS; return true; @@ -8951,6 +8993,44 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLAS return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); } +/*********************************************************************/ +CORINFO_CLASS_HANDLE CEEInfo::getSZArrayHelperEnumeratorClass(CORINFO_CLASS_HANDLE elemType) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + CORINFO_CLASS_HANDLE result = NULL; + + JIT_TO_EE_TRANSITION(); + + result = getSZArrayHelperEnumeratorClassHelper(elemType); + + EE_TO_JIT_TRANSITION(); + + return result; +} + +CORINFO_CLASS_HANDLE CEEInfo::getSZArrayHelperEnumeratorClassHelper(CORINFO_CLASS_HANDLE elemType) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + // Mirrors the logic in BCL's SZArrayHelper::GetEnumerator + TypeHandle elemTypeHnd(elemType); + + // We need to find the appropriate instantiation. + Instantiation inst(&elemTypeHnd, 1); + + TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__SZGENERICARRAYENUMERATOR)).Instantiate(inst); + return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); +} + /*********************************************************************/ void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CONST_LOOKUP * pResult, diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index e65d2f9b1dc6d..e5b11aa9d656c 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -452,6 +452,11 @@ class CEEInfo : public ICorJitInfo CORINFO_CLASS_HANDLE elemType ); + CORINFO_CLASS_HANDLE getSZArrayHelperEnumeratorClassHelper( + CORINFO_CLASS_HANDLE elemType + ); + + CorInfoType getFieldTypeInternal (CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE* structType = NULL,CORINFO_CLASS_HANDLE owner = NULL); protected: diff --git a/src/libraries/System.Private.CoreLib/src/System/Array.Enumerators.cs b/src/libraries/System.Private.CoreLib/src/System/Array.Enumerators.cs index 8c2204b7d61e3..c2bbd78c474f2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Array.Enumerators.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Array.Enumerators.cs @@ -78,6 +78,7 @@ protected SZGenericArrayEnumeratorBase(int endIndex) _endIndex = endIndex; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() { int index = _index + 1;