diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index aabc86d3cd65a..00607533cce11 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2326,7 +2326,7 @@ class ICorStaticInfo CORINFO_CLASS_HANDLE cls ) = 0; - // Returns the assembly name of the class "cls", or nullptr if there is none. + // Returns the assembly name of the class "cls", or nullptr if there is none. virtual const char* getClassAssemblyName ( CORINFO_CLASS_HANDLE cls ) = 0; @@ -2611,6 +2611,14 @@ class ICorStaticInfo CorInfoClassId classId ) = 0; + // returns the method the delegate object calls + virtual CORINFO_METHOD_HANDLE getMethodFromDelegate ( + CORINFO_CLASS_HANDLE calledCls, + CORINFO_OBJECT_HANDLE delObj, + CORINFO_CLASS_HANDLE* methodCls, + CORINFO_CLASS_HANDLE* targetCls + ) = 0; + // "System.Int32" ==> CORINFO_TYPE_INT.. virtual CorInfoType getTypeForPrimitiveValueClass( CORINFO_CLASS_HANDLE cls diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 08b1004d4642d..f8ad78102e853 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -329,6 +329,12 @@ void classMustBeLoadedBeforeCodeIsRun( CORINFO_CLASS_HANDLE getBuiltinClass( CorInfoClassId classId) override; +CORINFO_METHOD_HANDLE getMethodFromDelegate( + CORINFO_CLASS_HANDLE calledCls, + CORINFO_OBJECT_HANDLE delegateObj, + CORINFO_CLASS_HANDLE* methodCls, + CORINFO_CLASS_HANDLE* targetCls) override; + CorInfoType getTypeForPrimitiveValueClass( CORINFO_CLASS_HANDLE cls) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 82fbaf1c0d108..b30d832ad61d3 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 = { /* 64146448-11b1-4f94-b1f2-edce91fbcb33 */ - 0x64146448, - 0x11b1, - 0x4f94, - {0xb1, 0xf2, 0xed, 0xce, 0x91, 0xfb, 0xcb, 0x33} +constexpr GUID JITEEVersionIdentifier = { /* 50ca4d0a-3ca6-4755-9b43-d955f72be103 */ + 0x50ca4d0a, + 0x3ca6, + 0x4755, + {0x9b, 0x43, 0xd9, 0x55, 0xf7, 0x2b, 0xe1, 0x03} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 94e244c0749bf..3e24e51019f40 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -81,6 +81,7 @@ DEF_CLR_API(getReadyToRunDelegateCtorHelper) DEF_CLR_API(initClass) DEF_CLR_API(classMustBeLoadedBeforeCodeIsRun) DEF_CLR_API(getBuiltinClass) +DEF_CLR_API(getMethodFromDelegate) DEF_CLR_API(getTypeForPrimitiveValueClass) DEF_CLR_API(getTypeForPrimitiveNumericClass) DEF_CLR_API(canCast) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 9c7e6c1099826..8e6cec514e4fd 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -765,6 +765,18 @@ CORINFO_CLASS_HANDLE WrapICorJitInfo::getBuiltinClass( return temp; } +CORINFO_METHOD_HANDLE WrapICorJitInfo::getMethodFromDelegate( + CORINFO_CLASS_HANDLE calledCls, + CORINFO_OBJECT_HANDLE delegateObj, + CORINFO_CLASS_HANDLE* methodCls, + CORINFO_CLASS_HANDLE* targetCls) +{ + API_ENTER(getMethodFromDelegate); + CORINFO_METHOD_HANDLE temp = wrapHnd->getMethodFromDelegate(calledCls, delegateObj, methodCls, targetCls); + API_LEAVE(getMethodFromDelegate); + return temp; +} + CorInfoType WrapICorJitInfo::getTypeForPrimitiveValueClass( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 045e3eade03e4..3ca1bd6abcb04 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3919,7 +3919,7 @@ class Compiler // false: we can add new tracked variables. // true: We cannot add new 'tracked' variable - bool lvaTrackedFixed = false; + bool lvaTrackedFixed = false; unsigned lvaCount; // total number of locals, which includes function arguments, // special arguments, IL local variables, and JIT temporary variables @@ -4559,6 +4559,7 @@ class Compiler void impPopArgsForUnmanagedCall(GenTreeCall* call, CORINFO_SIG_INFO* sig, GenTree** swiftErrorNode); void impPopArgsForSwiftCall(GenTreeCall* call, CORINFO_SIG_INFO* sig, GenTree** swiftErrorNode); void impRetypeUnmanagedCallArgs(GenTreeCall* call); + bool impCanSubstituteSig(CORINFO_SIG_INFO* sourceSig, CORINFO_SIG_INFO* targetSig); #ifdef SWIFT_SUPPORT void impAppendSwiftErrorStore(GenTree* const swiftErrorNode); @@ -6819,7 +6820,7 @@ class Compiler unsigned acdCount = 0; // Get the index to use as part of the AddCodeDsc key for sharing throw blocks - unsigned bbThrowIndex(BasicBlock* blk, AcdKeyDesignator* dsg); + unsigned bbThrowIndex(BasicBlock* blk, AcdKeyDesignator* dsg); struct AddCodeDscKey { @@ -6827,7 +6828,7 @@ class Compiler AddCodeDscKey(): acdKind(SCK_NONE), acdData(0) {} AddCodeDscKey(SpecialCodeKind kind, BasicBlock* block, Compiler* comp); AddCodeDscKey(AddCodeDsc* add); - + static bool Equals(const AddCodeDscKey& x, const AddCodeDscKey& y) { return (x.acdData == y.acdData) && (x.acdKind == y.acdKind); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 720b49ed1d2b3..233803d3a8931 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -12067,7 +12067,7 @@ void Compiler::gtDispConst(GenTree* tree) } else if (tree->IsIconHandle(GTF_ICON_OBJ_HDL)) { - eePrintObjectDescription(" ", (CORINFO_OBJECT_HANDLE)tree->AsIntCon()->gtIconVal); + eePrintObjectDescription(" ", tree->AsIntCon()->GetFrozenObject()); } else { @@ -19073,7 +19073,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b { if (obj->IsIconHandle(GTF_ICON_OBJ_HDL)) { - objClass = info.compCompHnd->getObjectType((CORINFO_OBJECT_HANDLE)obj->AsIntCon()->IconValue()); + objClass = info.compCompHnd->getObjectType(obj->AsIntCon()->GetFrozenObject()); if (objClass != NO_CLASS_HANDLE) { // if we managed to get a class handle it's definitely not null diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 2e61ba6ed2811..91ea55bc2a868 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -3288,6 +3288,20 @@ struct GenTreeIntCon : public GenTreeIntConCommon { } #endif + + CORINFO_OBJECT_HANDLE GetFrozenObject() + { + assert(IsIconHandle(GTF_ICON_OBJ_HDL)); + return (CORINFO_OBJECT_HANDLE)IconValue(); + } + + CORINFO_FIELD_HANDLE GetStaticFieldHandle() + { + assert(IsIconHandle(GTF_ICON_STATIC_BOX_PTR) || IsIconHandle(GTF_ICON_CONST_PTR) || + IsIconHandle(GTF_ICON_STATIC_HDL)); + assert(gtFieldSeq != nullptr); + return gtFieldSeq->GetFieldHandle(); + } }; /* gtLngCon -- long constant (GT_CNS_LNG) */ diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 033ea50dc20e2..9673e82a826dd 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -95,17 +95,23 @@ var_types Compiler::impImportCall(OPCODE opcode, bool checkForSmallType = false; bool bIntrinsicImported = false; - CORINFO_SIG_INFO calliSig; + CORINFO_SIG_INFO originalSig = {}; NewCallArg extraArg; // Swift calls that might throw use a SwiftError* arg that requires additional IR to handle, // so if we're importing a Swift call, look for this type in the signature GenTree* swiftErrorNode = nullptr; - /*------------------------------------------------------------------------- - * First create the call node - */ + // prepare data for calli/delegate call replacement + bool optimizedOrInstrumented = opts.OptimizationEnabled() || opts.IsInstrumented(); + CORINFO_CLASS_HANDLE replacementClass = NO_CLASS_HANDLE; // real class called by the calli/delegate + CORINFO_METHOD_HANDLE replacementMethod = NO_METHOD_HANDLE; // real method called by the calli/delegate + CORINFO_SIG_INFO replacementSig = {}; // signature of the read method + GenTree* newThis = nullptr; // new instance for the delegate call + CORINFO_CLASS_HANDLE newThisClass = NO_CLASS_HANDLE; // class of the new instance object + int firstArgPos = -1; // position of the first arg after delegate + // handle special import cases if (opcode == CEE_CALLI) { if (IsTargetAbi(CORINFO_NATIVEAOT_ABI)) @@ -120,25 +126,235 @@ var_types Compiler::impImportCall(OPCODE opcode, } /* Get the call site sig */ - eeGetSig(pResolvedToken->token, pResolvedToken->tokenScope, pResolvedToken->tokenContext, &calliSig); + eeGetSig(pResolvedToken->token, pResolvedToken->tokenScope, pResolvedToken->tokenContext, &originalSig); + + if (!optimizedOrInstrumented) + { + // ignore + } + else if (originalSig.getCallConv() == CORINFO_CALLCONV_DEFAULT) + { + JITDUMP("\n\nimpImportCall trying to import calli as call\n"); + // TODO-Perf: Add an importer forward substitution to handle more cases here. + GenTree* fptr = impStackTop().val; + + // We can only handle known valid pointers here since the VM crashes + // when querying invalid method addresses. + // As such, we can't handle static readonly function pointers here. + if (originalSig.hasImplicitThis()) + { + JITDUMP("impImportCall failed to transform calli - implicit this not supported\n"); + } + else if (fptr->OperIs(GT_FTN_ADDR)) + { + // Ldftn should never point to a method from another unloadable context + CORINFO_METHOD_HANDLE method = fptr->AsFptrVal()->gtFptrMethod; + assert(method != NO_METHOD_HANDLE); + + replacementClass = info.compCompHnd->getMethodClass(method); + info.compCompHnd->getMethodSig(method, &replacementSig, replacementClass); + + if (replacementSig.hasThis() && eeIsValueClass(replacementClass)) + { + JITDUMP( + "impImportCall failed to transform calli - value type instance methods are not supported\n"); + } + else if (!impCanSubstituteSig(&originalSig, &replacementSig)) + { + JITDUMP("impImportCall failed to transform calli - incompatible signature\n"); + } + else + { + replacementMethod = method; + } + } + else + { + JITDUMP("impImportCall failed to transform calli - address node not found\n"); + } + } + else + { + JITDUMP("\n\nimpImportCall failed to transform calli - call conv %u is not managed\n", + originalSig.getCallConv()); + } + } + else if (optimizedOrInstrumented && callInfo->methodFlags & CORINFO_FLG_DELEGATE_INVOKE) + { + JITDUMP("\n\nimpImportCall trying to transform delegate - checking delegate call\n"); + + CORINFO_CLASS_HANDLE delegateClass = info.compCompHnd->getMethodClass(callInfo->hMethod); + info.compCompHnd->getMethodSig(callInfo->hMethod, &originalSig, delegateClass); + + // TODO-Perf: Add an importer forward substitution to handle more cases here. + GenTree* instance = impStackTop(originalSig.numArgs).val; + CORINFO_OBJECT_HANDLE object = NO_OBJECT_HANDLE; + + if (instance->IsIconHandle(GTF_ICON_OBJ_HDL)) + { + // Frozen delegates should never point to collectible contexts. + object = instance->AsIntCon()->GetFrozenObject(); + JITDUMP("impImportCall trying to transform delegate - found frozen\n"); + } + else if (instance->OperIs(GT_IND)) + { + GenTree* address = instance->AsIndir()->gtOp1; + if (address->IsIconHandle(GTF_ICON_CONST_PTR)) + { + // Const static addresses only exist in non-unloadable contexts, + // such context will keep the delegate permanently alive so even + // if it points to an unloadable method, we can still handle it safely. + // This lets us inline DynamicMethods. + CORINFO_FIELD_HANDLE field = address->AsIntCon()->GetStaticFieldHandle(); + JITDUMP("impImportCall trying to transform delegate - found field %s\n", eeGetFieldName(field, true)); + if (info.compCompHnd->getStaticFieldContent(field, (uint8_t*)&object, sizeof(CORINFO_OBJECT_HANDLE), 0, + false)) + { + JITDUMP("impImportCall trying to transform delegate - found static readonly value\n"); + } + else + { + object = NO_OBJECT_HANDLE; + JITDUMP("impImportCall trying to transform delegate - failed to read field value\n"); + } + } + } + // TODO-Perf: Handle unloadable delegates in the same context. + + if (object == NO_OBJECT_HANDLE) + { + JITDUMP("impImportCall failed to transform delegate - target delegate not found\n"); + } + else + { + JITDUMP("impImportCall trying to transform delegate - found delegate at 0x%llx\n", object); + replacementMethod = info.compCompHnd->getMethodFromDelegate(pResolvedToken->hClass, object, + &replacementClass, &newThisClass); + + if (replacementMethod == NO_METHOD_HANDLE) + { + JITDUMP("impImportCall failed to transform delegate - failed to obtain method from delegate\n"); + } + else + { + firstArgPos = (int)(stackState.esStackDepth - originalSig.numArgs); + assert(firstArgPos >= 0); + + info.compCompHnd->getMethodSig(replacementMethod, &replacementSig, replacementClass); + + if (newThisClass != NO_CLASS_HANDLE) + { + newThis = + gtNewIndir(TYP_REF, + gtNewOperNode(GT_ADD, TYP_BYREF, instance, + gtNewIconNode(eeGetEEInfo()->offsetOfDelegateFirstTarget, TYP_I_IMPL)), + GTF_IND_INVARIANT | GTF_IND_NONNULL | GTF_IND_NONFAULTING); + } + } + } + } + + if (replacementMethod != NO_METHOD_HANDLE) + { + assert(replacementClass != NO_CLASS_HANDLE); + assert(firstArgPos >= -1); + + JITDUMP("impImportCall trying to transform call - found target method %s:%s\n", + eeGetClassName(replacementClass), eeGetMethodName(replacementMethod)); + + unsigned replacementFlags = info.compCompHnd->getMethodAttribs(replacementMethod); + + if ((replacementFlags & CORINFO_FLG_PINVOKE) != 0) + { + JITDUMP("impImportCall failed call transformation - found PInvoke\n"); + } + else + { +#ifdef DEBUG + if (firstArgPos >= 0) + { + // check if we are at a valid position and + // had a valid delegate instance beforehand. + assert(&stackState.esStack[firstArgPos - 1] >= stackState.esStack); + assert(stackState.esStack[firstArgPos - 1].seTypeInfo.GetType() == TYP_REF); + } + + if ((newThisClass != NO_CLASS_HANDLE) || (firstArgPos < 0)) + { + // for closed delegates and calli those should be equal + assert(originalSig.totalILArgs() == replacementSig.totalILArgs()); + } + else + { + // for open delegates there should be 1 less arg since we remove the instance + assert((originalSig.totalILArgs() - 1) == replacementSig.totalILArgs()); + } +#endif + + if (newThisClass != NO_CLASS_HANDLE) + { + // closed delegates + assert(firstArgPos >= 0); + assert(newThis != nullptr); + assert(newThis->TypeGet() == TYP_REF); + // replace delegate instance with the new this + stackState.esStack[firstArgPos - 1].seTypeInfo = typeInfo(newThisClass); + stackState.esStack[firstArgPos - 1].val = newThis; + } + else + { + // open delegates and calli + // shift args if needed + if (firstArgPos > 0) + { + memmove(&stackState.esStack[firstArgPos - 1], &stackState.esStack[firstArgPos], + (stackState.esStackDepth - firstArgPos) * sizeof(StackEntry)); + } + // we can just pop the top arg after shifting + impPopStack(); + } + + JITDUMP("impImportCall transforming call\n"); + + // we need to update the token and info to the real method + pResolvedToken->tokenContext = impTokenLookupContextHandle; + pResolvedToken->tokenScope = info.compScopeHnd; + pResolvedToken->tokenType = CORINFO_TOKENKIND_Method; + pResolvedToken->token = replacementSig.token; + pResolvedToken->hMethod = replacementMethod; + pResolvedToken->hClass = replacementClass; + + eeGetCallInfo(pResolvedToken, nullptr, CORINFO_CALLINFO_ALLOWINSTPARAM, callInfo); + callInfo->nullInstanceCheck = false; + callInfo->accessAllowed = CORINFO_ACCESS_ALLOWED; + + return impImportCall(CEE_CALL, pResolvedToken, nullptr, nullptr, prefixFlags, callInfo, rawILOffset); + } + } + + /*------------------------------------------------------------------------- + * First create the call node + */ - callRetTyp = JITtype2varType(calliSig.retType); + if (opcode == CEE_CALLI) + { + callRetTyp = JITtype2varType(originalSig.retType); - call = impImportIndirectCall(&calliSig, di); + call = impImportIndirectCall(&originalSig, di); // We don't know the target method, so we have to infer the flags, or // assume the worst-case. - mflags = (calliSig.callConv & CORINFO_CALLCONV_HASTHIS) ? 0 : CORINFO_FLG_STATIC; + mflags = (originalSig.callConv & CORINFO_CALLCONV_HASTHIS) ? 0 : CORINFO_FLG_STATIC; #ifdef DEBUG if (verbose) { - unsigned structSize = (callRetTyp == TYP_STRUCT) ? eeTryGetClassSize(calliSig.retTypeSigClass) : 0; + unsigned structSize = (callRetTyp == TYP_STRUCT) ? eeTryGetClassSize(originalSig.retTypeSigClass) : 0; printf("\nIn Compiler::impImportCall: opcode is %s, kind=%d, callRetType is %s, structSize is %u\n", opcodeNames[opcode], callInfo->kind, varTypeName(callRetTyp), structSize); } #endif - sig = &calliSig; + sig = &originalSig; } else // (opcode != CEE_CALLI) { @@ -1927,6 +2143,117 @@ GenTree* Compiler::impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HAN #endif // FEATURE_MULTIREG_RET } +//----------------------------------------------------------------------------------- +// impCanSubstituteSig: Checks whether it's safe to replace a call with another one. +// This DOES NOT check if the calls are actually compatible, it only checks if their trees are. +// Use ONLY when code will call the method with target sig anyway. +// +// Arguments: +// sourceSig - original call signature +// targetSig - new call signature +// +// Return Value: +// Whether it's safe to change the IR to call the target method +// +bool Compiler::impCanSubstituteSig(CORINFO_SIG_INFO* sourceSig, CORINFO_SIG_INFO* targetSig) +{ + if (sourceSig->getCallConv() != targetSig->getCallConv()) + { + JITDUMP("impCanSubstituteSig returning false - call conv %u != %u\n", sourceSig->callConv, targetSig->callConv); + return false; + } + + unsigned sourceArgCount = sourceSig->totalILArgs(); + unsigned targetArgCount = targetSig->totalILArgs(); + if (sourceArgCount != targetArgCount) + { + JITDUMP("impCanSubstituteSig returning false - args count %u != %u\n", sourceArgCount, targetArgCount); + return false; + } + + if (sourceSig->retType != targetSig->retType) + { + JITDUMP("impCanSubstituteSig returning false - return type %u != %u\n", (unsigned)sourceSig->retType, + (unsigned)targetSig->retType); + return false; + } + + if (sourceSig->retType == CORINFO_TYPE_VALUECLASS || sourceSig->retType == CORINFO_TYPE_REFANY) + { + ClassLayout* layoutRetSource = typGetObjLayout(sourceSig->retTypeClass); + ClassLayout* layoutRetTarget = typGetObjLayout(targetSig->retTypeClass); + + if (!ClassLayout::AreCompatible(layoutRetSource, layoutRetTarget)) + { + JITDUMP("impCanSubstituteSig returning false - return type %s is incompatible with %s\n", + eeGetClassName(targetSig->retTypeClass), eeGetClassName(sourceSig->retTypeClass)); + return false; + } + } + + CORINFO_ARG_LIST_HANDLE sourceArg = sourceSig->args; + CORINFO_ARG_LIST_HANDLE targetArg = targetSig->args; + + for (unsigned i = 0; i < targetArgCount; i++) + { + var_types sourceType; + var_types targetType; + + ClassLayout* sourceLayout = nullptr; + ClassLayout* targetLayout = nullptr; + if (i == 0 && sourceSig->hasImplicitThis()) + { + // assume ref type on implicit this + sourceType = TYP_REF; + } + else + { + sourceType = eeGetArgType(sourceArg, sourceSig); + if (varTypeIsStruct(sourceType)) + { + CORINFO_CLASS_HANDLE sourceClassHnd = NO_CLASS_HANDLE; + info.compCompHnd->getArgType(sourceSig, sourceArg, &sourceClassHnd); + sourceLayout = typGetObjLayout(sourceClassHnd); + } + sourceArg = info.compCompHnd->getArgNext(sourceArg); + } + + if (i == 0 && targetSig->hasImplicitThis()) + { + // assume ref type on implicit this + targetType = TYP_REF; + } + else + { + targetType = eeGetArgType(targetArg, targetSig); + if (varTypeIsStruct(targetType)) + { + CORINFO_CLASS_HANDLE targetClassHnd = NO_CLASS_HANDLE; + info.compCompHnd->getArgType(targetSig, targetArg, &targetClassHnd); + targetLayout = typGetObjLayout(targetClassHnd); + } + targetArg = info.compCompHnd->getArgNext(targetArg); + } + + if (sourceType != targetType) + { + JITDUMP("impCanSubstituteSig returning false - parameter %u type %s != %s\n", i, varTypeName(sourceType), + varTypeName(targetType)); + return false; + } + + assert((sourceLayout == nullptr) == (targetLayout == nullptr)); + if ((sourceLayout != nullptr) && !ClassLayout::AreCompatible(sourceLayout, targetLayout)) + { + JITDUMP("impCanSubstituteSig returning false - parameter %u type %s is incompatible with %s\n", i, + varTypeName(sourceType), varTypeName(targetType)); + return false; + } + } + + return true; +} + GenTreeCall* Compiler::impImportIndirectCall(CORINFO_SIG_INFO* sig, const DebugInfo& di) { var_types callRetTyp = JITtype2varType(sig->retType); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 91df884c58272..8bf3902e013a6 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1150,6 +1150,21 @@ private static void _classMustBeLoadedBeforeCodeIsRun(IntPtr thisHandle, IntPtr* } } + [UnmanagedCallersOnly] + private static CORINFO_METHOD_STRUCT_* _getMethodFromDelegate(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* calledCls, CORINFO_OBJECT_STRUCT_* delegateObj, CORINFO_CLASS_STRUCT_** methodCls, CORINFO_CLASS_STRUCT_** targetCls) + { + var _this = GetThis(thisHandle); + try + { + return _this.getMethodFromDelegate(calledCls, delegateObj, methodCls, targetCls); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] private static CorInfoType _getTypeForPrimitiveValueClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) { @@ -2623,7 +2638,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 177); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 178); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage; @@ -2702,106 +2717,107 @@ private static IntPtr GetUnmanagedCallbacks() 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)&_getMethodDefFromMethod; - callbacks[121] = (delegate* unmanaged)&_printMethodName; - callbacks[122] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[123] = (delegate* unmanaged)&_getMethodHash; - callbacks[124] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[125] = (delegate* unmanaged)&_getSwiftLowering; - callbacks[126] = (delegate* unmanaged)&_getFpStructLowering; - callbacks[127] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[128] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[129] = (delegate* unmanaged)&_getHelperFtn; - callbacks[130] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[131] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[132] = (delegate* unmanaged)&_getMethodSync; - callbacks[133] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[134] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[135] = (delegate* unmanaged)&_embedClassHandle; - callbacks[136] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[137] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[138] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[139] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[140] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[141] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[142] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[143] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[144] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[145] = (delegate* unmanaged)&_getCallInfo; - callbacks[146] = (delegate* unmanaged)&_getStaticFieldContent; - callbacks[147] = (delegate* unmanaged)&_getObjectContent; - callbacks[148] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[149] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[150] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[151] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[152] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[153] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[154] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[155] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[156] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[157] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[158] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[159] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[160] = (delegate* unmanaged)&_allocMem; - callbacks[161] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[162] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[163] = (delegate* unmanaged)&_allocGCInfo; - callbacks[164] = (delegate* unmanaged)&_setEHcount; - callbacks[165] = (delegate* unmanaged)&_setEHinfo; - callbacks[166] = (delegate* unmanaged)&_logMsg; - callbacks[167] = (delegate* unmanaged)&_doAssert; - callbacks[168] = (delegate* unmanaged)&_reportFatalError; - callbacks[169] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[170] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[171] = (delegate* unmanaged)&_recordCallSite; - callbacks[172] = (delegate* unmanaged)&_recordRelocation; - callbacks[173] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[174] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[175] = (delegate* unmanaged)&_getJitFlags; - callbacks[176] = (delegate* unmanaged)&_getSpecialCopyHelper; + callbacks[77] = (delegate* unmanaged)&_getMethodFromDelegate; + callbacks[78] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; + callbacks[79] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; + callbacks[80] = (delegate* unmanaged)&_canCast; + callbacks[81] = (delegate* unmanaged)&_compareTypesForCast; + callbacks[82] = (delegate* unmanaged)&_compareTypesForEquality; + callbacks[83] = (delegate* unmanaged)&_isMoreSpecificType; + callbacks[84] = (delegate* unmanaged)&_isExactType; + callbacks[85] = (delegate* unmanaged)&_isGenericType; + callbacks[86] = (delegate* unmanaged)&_isNullableType; + callbacks[87] = (delegate* unmanaged)&_isEnum; + callbacks[88] = (delegate* unmanaged)&_getParentType; + callbacks[89] = (delegate* unmanaged)&_getChildType; + callbacks[90] = (delegate* unmanaged)&_isSDArray; + callbacks[91] = (delegate* unmanaged)&_getArrayRank; + callbacks[92] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[93] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[94] = (delegate* unmanaged)&_canAccessClass; + callbacks[95] = (delegate* unmanaged)&_printFieldName; + callbacks[96] = (delegate* unmanaged)&_getFieldClass; + callbacks[97] = (delegate* unmanaged)&_getFieldType; + callbacks[98] = (delegate* unmanaged)&_getFieldOffset; + callbacks[99] = (delegate* unmanaged)&_getFieldInfo; + callbacks[100] = (delegate* unmanaged)&_getThreadLocalFieldInfo; + callbacks[101] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; + callbacks[102] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; + callbacks[103] = (delegate* unmanaged)&_isFieldStatic; + callbacks[104] = (delegate* unmanaged)&_getArrayOrStringLength; + callbacks[105] = (delegate* unmanaged)&_getBoundaries; + callbacks[106] = (delegate* unmanaged)&_setBoundaries; + callbacks[107] = (delegate* unmanaged)&_getVars; + callbacks[108] = (delegate* unmanaged)&_setVars; + callbacks[109] = (delegate* unmanaged)&_reportRichMappings; + callbacks[110] = (delegate* unmanaged)&_reportMetadata; + callbacks[111] = (delegate* unmanaged)&_allocateArray; + callbacks[112] = (delegate* unmanaged)&_freeArray; + callbacks[113] = (delegate* unmanaged)&_getArgNext; + callbacks[114] = (delegate* unmanaged)&_getArgType; + callbacks[115] = (delegate* unmanaged)&_getExactClasses; + callbacks[116] = (delegate* unmanaged)&_getArgClass; + callbacks[117] = (delegate* unmanaged)&_getHFAType; + callbacks[118] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[119] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[120] = (delegate* unmanaged)&_getEEInfo; + 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/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 3aaa80673334f..078bdddeb9a99 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -241,6 +241,7 @@ FUNCTIONS CorInfoInitClassResult initClass(CORINFO_FIELD_HANDLE field, CORINFO_METHOD_HANDLE method, CORINFO_CONTEXT_HANDLE context) void classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE cls) CORINFO_CLASS_HANDLE getBuiltinClass(CorInfoClassId classId) + CORINFO_METHOD_HANDLE getMethodFromDelegate(CORINFO_CLASS_HANDLE calledCls, CORINFO_OBJECT_HANDLE delegateObj, CORINFO_CLASS_HANDLE* methodCls, CORINFO_CLASS_HANDLE* targetCls) CorInfoType getTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls) CorInfoType getTypeForPrimitiveNumericClass(CORINFO_CLASS_HANDLE cls) bool canCast(CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs index 2d1bcefd4fd56..51cced1a78c0f 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs @@ -26,6 +26,8 @@ int ISymbolDefinitionNode.Offset public abstract TypeDesc ObjectType { get; } public abstract int? ArrayLength { get; } + public abstract MethodDesc DelegateMethod { get; } + public abstract TypeDesc DelegateTargetType { get; } public abstract bool IsKnownImmutable { get; } public int Size => ObjectType.Context.Target.PointerSize + ContentSize; // SyncBlock + size of contents protected abstract int ContentSize { get; } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenRuntimeTypeNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenRuntimeTypeNode.cs index df38758e7deee..a07c31522bb39 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenRuntimeTypeNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenRuntimeTypeNode.cs @@ -49,6 +49,8 @@ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer } public override int? ArrayLength => null; + public override MethodDesc DelegateMethod => null; + public override TypeDesc DelegateTargetType => null; public override bool IsKnownImmutable => false; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenStringNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenStringNode.cs index a115db34764ba..82386bbe2ee31 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenStringNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenStringNode.cs @@ -51,6 +51,8 @@ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer public string Data => _data; public override int? ArrayLength => _data.Length; + public override MethodDesc DelegateMethod => null; + public override TypeDesc DelegateTargetType => null; public override bool IsKnownImmutable => true; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/SerializedFrozenObjectNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/SerializedFrozenObjectNode.cs index fbe021414800b..05465cd82ab98 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/SerializedFrozenObjectNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/SerializedFrozenObjectNode.cs @@ -48,6 +48,9 @@ protected override int ContentSize public override int? ArrayLength => _data.Type.IsArray ? _data.ArrayLength : null; + public override MethodDesc DelegateMethod => _data.Type.IsDelegate ? _data.DelegateMethod : null; + public override TypeDesc DelegateTargetType => _data.Type.IsDelegate ? _data.DelegateTargetType : null; + public override void EncodeContents(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly) { // byte contents diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs index a5851aba72f2f..a424ff7065238 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs @@ -2210,6 +2210,8 @@ public interface ISerializableReference : ISerializableValue void GetConditionalDependencies(ref CombinedDependencyList dependencies, NodeFactory factory); bool IsKnownImmutable { get; } int ArrayLength { get; } + MethodDesc DelegateMethod { get; } + TypeDesc DelegateTargetType { get; } } /// @@ -2767,20 +2769,20 @@ public virtual void GetConditionalDependencies(ref CombinedDependencyList depend private sealed class DelegateInstance : AllocatedReferenceTypeValue, ISerializableReference { - private readonly MethodDesc _methodPointed; + public MethodDesc DelegateMethod { get; } private readonly ReferenceTypeValue _firstParameter; public DelegateInstance(TypeDesc delegateType, MethodDesc methodPointed, ReferenceTypeValue firstParameter, AllocationSite allocationSite) : base(delegateType, allocationSite) { - _methodPointed = methodPointed; + DelegateMethod = methodPointed; _firstParameter = firstParameter; } private DelegateCreationInfo GetDelegateCreationInfo(NodeFactory factory) => DelegateCreationInfo.Create( Type.ConvertToCanonForm(CanonicalFormKind.Specific), - _methodPointed, + DelegateMethod, constrainedType: null, factory, followVirtualDispatch: false); @@ -2799,7 +2801,7 @@ public override void GetConditionalDependencies(ref CombinedDependencyList depen public void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory) { - Debug.Assert(_methodPointed.Signature.IsStatic == (_firstParameter == null)); + Debug.Assert(DelegateMethod.Signature.IsStatic == (_firstParameter == null)); DelegateCreationInfo creationInfo = GetDelegateCreationInfo(factory); @@ -2810,7 +2812,7 @@ public void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, No Debug.Assert(!node.RepresentsIndirectionCell); // Shouldn't have allowed this builder.EmitPointerReloc(node); - if (_methodPointed.Signature.IsStatic) + if (DelegateMethod.Signature.IsStatic) { Debug.Assert(creationInfo.Constructor.Method.Name == "InitializeOpenStaticThunk"); @@ -2850,7 +2852,9 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f builder.EmitPointerReloc(factory.SerializedFrozenObject(AllocationSite.OwningType, AllocationSite.InstructionCounter, this)); } - public bool IsKnownImmutable => _methodPointed.Signature.IsStatic; + public bool IsKnownImmutable => DelegateMethod.Signature.IsStatic; + + public TypeDesc DelegateTargetType => _firstParameter?.Type; public int ArrayLength => throw new NotSupportedException(); } @@ -2954,6 +2958,9 @@ public bool TryGetReadOnlySpan(out ReadOnlySpanValue value) public bool IsKnownImmutable => _elementCount == 0; public int ArrayLength => Length; + + public MethodDesc DelegateMethod => throw new NotSupportedException(); + public TypeDesc DelegateTargetType => throw new NotSupportedException(); } private sealed class ForeignTypeInstance : AllocatedReferenceTypeValue @@ -3121,6 +3128,8 @@ public void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, No public bool IsKnownImmutable => !Type.GetFields().GetEnumerator().MoveNext(); public int ArrayLength => throw new NotSupportedException(); + public MethodDesc DelegateMethod => throw new NotSupportedException(); + public TypeDesc DelegateTargetType => throw new NotSupportedException(); } private struct FieldAccessor diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 500863a90d934..b669b8f81166f 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -2111,7 +2111,7 @@ private void ceeInfoGetCallInfo( // of shared generic code calling a shared generic implementation method, which should be rare. // // An alternative design would be to add a new generic dictionary entry kind to hold the MethodDesc - // of the constrained target instead, and use that in some circumstances; however, implementation of + // of the constrained target instead, and use that in some circumstances; however, implementation of // that design requires refactoring variuos parts of the JIT interface as well as // TryResolveConstraintMethodApprox. In particular we would need to be abled to embed a constrained lookup // via EmbedGenericHandle, as well as decide in TryResolveConstraintMethodApprox if the call can be made @@ -3301,6 +3301,11 @@ private bool getObjectContent(CORINFO_OBJECT_STRUCT_* obj, byte* buffer, int buf throw new NotSupportedException(); } + private CORINFO_METHOD_STRUCT_* getMethodFromDelegate(CORINFO_CLASS_STRUCT_* calledCls, CORINFO_OBJECT_STRUCT_* delegateObj, CORINFO_CLASS_STRUCT_** methodCls, CORINFO_CLASS_STRUCT_** targetCls) + { + throw new NotSupportedException(); + } + private bool isObjectImmutable(CORINFO_OBJECT_STRUCT_* objPtr) { throw new NotSupportedException(); diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs index 34c5a1a3b16cc..02088152b2326 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Internal.IL; @@ -2401,6 +2402,37 @@ private bool getObjectContent(CORINFO_OBJECT_STRUCT_* objPtr, byte* buffer, int return ObjectToHandle(HandleToObject(objPtr).ObjectType); } + private CORINFO_METHOD_STRUCT_* getMethodFromDelegate(CORINFO_CLASS_STRUCT_* calledCls, CORINFO_OBJECT_STRUCT_* delegateObj, CORINFO_CLASS_STRUCT_** methodCls, CORINFO_CLASS_STRUCT_** targetCls) + { + Debug.Assert(calledCls != null); + Debug.Assert(delegateObj != null); + + FrozenObjectNode frozenObject = HandleToObject(delegateObj); + MethodDesc method = frozenObject.DelegateMethod; + + TypeDesc calledType = HandleToObject(calledCls); + if (!frozenObject.ObjectType.CanCastTo(calledType)) + { + return null; + } + + if (methodCls != null) + { + *methodCls = ObjectToHandle(method.OwningType); + } + + if (targetCls != null) + { + TypeDesc targetType = frozenObject.DelegateTargetType; + Debug.Assert(method.Signature.IsStatic == (targetType == null)); + + // NativeAOT doesn't support delegates closed over null so we don't need to do signature checks + *targetCls = targetType == null ? null : ObjectToHandle(targetType); + } + + return ObjectToHandle(method); + } + private CORINFO_OBJECT_STRUCT_* getRuntimeTypePointer(CORINFO_CLASS_STRUCT_* cls) { TypeDesc type = HandleToObject(cls); diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index a1a6122037d27..74c4f792a81b1 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -88,6 +88,7 @@ struct JitInterfaceCallbacks CorInfoInitClassResult (* initClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, CORINFO_METHOD_HANDLE method, CORINFO_CONTEXT_HANDLE context); void (* classMustBeLoadedBeforeCodeIsRun)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); CORINFO_CLASS_HANDLE (* getBuiltinClass)(void * thisHandle, CorInfoExceptionClass** ppException, CorInfoClassId classId); + CORINFO_METHOD_HANDLE (* getMethodFromDelegate)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE calledCls, CORINFO_OBJECT_HANDLE delegateObj, CORINFO_CLASS_HANDLE* methodCls, CORINFO_CLASS_HANDLE* targetCls); CorInfoType (* getTypeForPrimitiveValueClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); CorInfoType (* getTypeForPrimitiveNumericClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); bool (* canCast)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent); @@ -956,6 +957,18 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual CORINFO_METHOD_HANDLE getMethodFromDelegate( + CORINFO_CLASS_HANDLE calledCls, + CORINFO_OBJECT_HANDLE delegateObj, + CORINFO_CLASS_HANDLE* methodCls, + CORINFO_CLASS_HANDLE* targetCls) +{ + CorInfoExceptionClass* pException = nullptr; + CORINFO_METHOD_HANDLE temp = _callbacks->getMethodFromDelegate(_thisHandle, &pException, calledCls, delegateObj, methodCls, targetCls); + if (pException != nullptr) throw pException; + return temp; +} + virtual CorInfoType getTypeForPrimitiveValueClass( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 771951a68baea..cf1dc30e80d2b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -64,6 +64,13 @@ struct DLDL DWORDLONG B; }; +struct DLDLDL +{ + DWORDLONG A; + DWORDLONG B; + DWORDLONG C; +}; + struct Agnostic_CanInline { DWORD result; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index b9be6659ed773..5cc0c81c036ad 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -135,6 +135,7 @@ LWM(GetThreadTLSIndex, DWORD, DLD) LWM(GetTokenTypeAsHandle, GetTokenTypeAsHandleValue, DWORDLONG) LWM(GetTypeForBox, DWORDLONG, DWORDLONG) LWM(GetTypeForBoxOnStack, DWORDLONG, DWORDLONG) +LWM(GetMethodFromDelegate, DLDL, DLDLDL) LWM(GetTypeForPrimitiveValueClass, DWORDLONG, DWORD) LWM(GetTypeForPrimitiveNumericClass, DWORDLONG, DWORD) LWM(GetUnboxedEntry, DWORDLONG, DLD); diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 191e18718bc56..2935a3316dc70 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -1954,6 +1954,55 @@ CORINFO_CLASS_HANDLE MethodContext::repGetBuiltinClass(CorInfoClassId classId) return result; } +void MethodContext::recGetMethodFromDelegate(CORINFO_CLASS_HANDLE calledCls, + CORINFO_OBJECT_HANDLE delegateObj, + CORINFO_CLASS_HANDLE methodCls, + CORINFO_CLASS_HANDLE targetCls, + CORINFO_METHOD_HANDLE result) +{ + if (GetMethodFromDelegate == nullptr) + GetMethodFromDelegate = new LightWeightMap(); + + DLDL key; + ZeroMemory(&key, sizeof(key)); + key.A = CastHandle(calledCls); + key.B = CastHandle(delegateObj); + + DLDLDL value; + ZeroMemory(&value, sizeof(value)); + value.A = CastHandle(methodCls); + value.B = CastHandle(targetCls); + value.C = CastHandle(result); + + GetMethodFromDelegate->Add(key, value); + DEBUG_REC(dmpGetMethodFromDelegate(key, value)); +} +void MethodContext::dmpGetMethodFromDelegate(DLDL key, DLDLDL value) +{ + printf("GetMethodFromDelegate key type-%016" PRIX64 " object-%016" PRIX64 ", value type-%016" PRIX64 + " target type-%016" PRIX64 " method-%016" PRIX64, + key.A, key.B, value.A, value.B, value.C); +} +CORINFO_METHOD_HANDLE MethodContext::repGetMethodFromDelegate(CORINFO_CLASS_HANDLE calledCls, + CORINFO_OBJECT_HANDLE delegateObj, + CORINFO_CLASS_HANDLE* methodCls, + CORINFO_CLASS_HANDLE* targetCls) +{ + DLDL key; + ZeroMemory(&key, sizeof(key)); + key.A = (DWORDLONG)calledCls; + key.B = (DWORDLONG)delegateObj; + + DLDLDL value = LookupByKeyOrMiss(GetMethodFromDelegate, key, ": key type-%016" PRIX64 " object-%016" PRIX64, + key.A, key.B); + DEBUG_REP(dmpGetMethodFromDelegate(key, value)); + if (methodCls != nullptr) + *methodCls = (CORINFO_CLASS_HANDLE)value.A; + if (targetCls != nullptr) + *targetCls = (CORINFO_CLASS_HANDLE)value.B; + return (CORINFO_METHOD_HANDLE)value.C; +} + void MethodContext::recGetTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls, CorInfoType result) { if (GetTypeForPrimitiveValueClass == nullptr) @@ -4556,7 +4605,7 @@ size_t MethodContext::repGetClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, DWORDLONG key = CastHandle(cls); Agnostic_GetClassModuleIdForStatics value = LookupByKeyOrMiss(GetClassModuleIdForStatics, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetClassModuleIdForStatics(key, value)); + DEBUG_REP(dmpGetClassModuleIdForStatics(key, value)); if (pModule != nullptr) *pModule = (CORINFO_MODULE_HANDLE)value.Module; @@ -4656,7 +4705,7 @@ DWORD MethodContext::repGetThreadTLSIndex(void** ppIndirection) { DLD value = LookupByKeyOrMissNoMessage(GetThreadTLSIndex, 0); - DEBUG_REP(dmpGetThreadTLSIndex(0, value)); + DEBUG_REP(dmpGetThreadTLSIndex(0, value)); if (ppIndirection != nullptr) *ppIndirection = (void*)value.A; @@ -4781,7 +4830,7 @@ void MethodContext::repGetLocationOfThisType(CORINFO_METHOD_HANDLE context, CORI { DWORDLONG key = CastHandle(context); Agnostic_CORINFO_LOOKUP_KIND value = LookupByKeyOrMiss(GetLocationOfThisType, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetLocationOfThisType(key, value)); + DEBUG_REP(dmpGetLocationOfThisType(key, value)); *pLookupKind = SpmiRecordsHelper::RestoreCORINFO_LOOKUP_KIND(value); } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index b6997b94e6c25..89585670c5d86 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -250,6 +250,10 @@ class MethodContext void dmpGetBuiltinClass(DWORD key, DWORDLONG value); CORINFO_CLASS_HANDLE repGetBuiltinClass(CorInfoClassId classId); + void recGetMethodFromDelegate(CORINFO_CLASS_HANDLE calledCls, CORINFO_OBJECT_HANDLE delegateObj, CORINFO_CLASS_HANDLE methodCls, CORINFO_CLASS_HANDLE targetCls, CORINFO_METHOD_HANDLE result); + void dmpGetMethodFromDelegate(DLDL key, DLDLDL value); + CORINFO_METHOD_HANDLE repGetMethodFromDelegate(CORINFO_CLASS_HANDLE calledCls, CORINFO_OBJECT_HANDLE delegateObj, CORINFO_CLASS_HANDLE* methodCls, CORINFO_CLASS_HANDLE* targetCls); + void recGetTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls, CorInfoType result); void dmpGetTypeForPrimitiveValueClass(DWORDLONG key, DWORD value); CorInfoType repGetTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls); @@ -456,13 +460,13 @@ class MethodContext void dmpGetUnboxedEntry(DWORDLONG key, DLD value); CORINFO_METHOD_HANDLE repGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg); - void recGetInstantiatedEntry(CORINFO_METHOD_HANDLE ftn, + 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_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); @@ -1203,6 +1207,7 @@ enum mcPackets Packet_GetSZArrayHelperEnumeratorClass = 226, Packet_GetMethodInstantiationArgument = 227, Packet_GetInstantiatedEntry = 228, + Packet_GetMethodFromDelegate = 229, }; 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 fdf27620abb21..db68cc0e21314 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -865,6 +865,21 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getBuiltinClass(CorInfoClassId classId) return temp; } +// returns the class handle for the special builtin classes +CORINFO_METHOD_HANDLE interceptor_ICJI::getMethodFromDelegate(CORINFO_CLASS_HANDLE calledCls, CORINFO_OBJECT_HANDLE delegateObj, CORINFO_CLASS_HANDLE* methodCls, CORINFO_CLASS_HANDLE* targetCls) +{ + mc->cr->AddCall("getMethodFromDelegate"); + CORINFO_CLASS_HANDLE methodType = nullptr; + CORINFO_CLASS_HANDLE targetType = nullptr; + CORINFO_METHOD_HANDLE temp = original_ICorJitInfo->getMethodFromDelegate(calledCls, delegateObj, &methodType, &targetType); + mc->recGetMethodFromDelegate(calledCls, delegateObj, methodType, targetType, temp); + if (methodCls != nullptr) + *methodCls = methodType; + if (targetCls != nullptr) + *targetCls = targetType; + return temp; +} + // "System.Int32" ==> CORINFO_TYPE_INT.. CorInfoType interceptor_ICJI::getTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls) { 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 d14acec9674bb..d3a5826584bde 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -628,6 +628,16 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getBuiltinClass( return original_ICorJitInfo->getBuiltinClass(classId); } +CORINFO_METHOD_HANDLE interceptor_ICJI::getMethodFromDelegate( + CORINFO_CLASS_HANDLE calledCls, + CORINFO_OBJECT_HANDLE delegateObj, + CORINFO_CLASS_HANDLE* methodCls, + CORINFO_CLASS_HANDLE* targetCls) +{ + mcs->AddCall("getMethodFromDelegate"); + return original_ICorJitInfo->getMethodFromDelegate(calledCls, delegateObj, methodCls, targetCls); +} + CorInfoType interceptor_ICJI::getTypeForPrimitiveValueClass( CORINFO_CLASS_HANDLE cls) { 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 ee04f7d948bb0..6fde6f7d7f261 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -551,6 +551,15 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getBuiltinClass( return original_ICorJitInfo->getBuiltinClass(classId); } +CORINFO_METHOD_HANDLE interceptor_ICJI::getMethodFromDelegate( + CORINFO_CLASS_HANDLE calledCls, + CORINFO_OBJECT_HANDLE delegateObj, + CORINFO_CLASS_HANDLE* methodCls, + CORINFO_CLASS_HANDLE* targetCls) +{ + return original_ICorJitInfo->getMethodFromDelegate(calledCls, delegateObj, methodCls, targetCls); +} + CorInfoType interceptor_ICJI::getTypeForPrimitiveValueClass( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index d190ffe727303..46e5802c3610f 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -730,6 +730,14 @@ CORINFO_CLASS_HANDLE MyICJI::getBuiltinClass(CorInfoClassId classId) return jitInstance->mc->repGetBuiltinClass(classId); } +// returns the class handle for the special builtin classes +CORINFO_METHOD_HANDLE MyICJI::getMethodFromDelegate(CORINFO_CLASS_HANDLE calledCls, CORINFO_OBJECT_HANDLE delegateObj, + CORINFO_CLASS_HANDLE* methodCls, CORINFO_CLASS_HANDLE* targetCls) +{ + jitInstance->mc->cr->AddCall("getMethodFromDelegate"); + return jitInstance->mc->repGetMethodFromDelegate(calledCls, delegateObj, methodCls, targetCls); +} + // "System.Int32" ==> CORINFO_TYPE_INT.. CorInfoType MyICJI::getTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 205c5105d5a2d..39b555a7a1c99 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -1645,7 +1645,7 @@ extern "C" PCODE QCALLTYPE Delegate_AdjustTarget(QCall::ObjectHandleOnStack targ extern "C" void * _ReturnAddress(void); #endif // _MSC_VER && !TARGET_UNIX -uint32_t MethodDescToNumFixedArgs(MethodDesc *pMD) +uint32_t COMDelegate::MethodDescToNumFixedArgs(MethodDesc *pMD) { WRAPPER_NO_CONTRACT; @@ -1716,8 +1716,8 @@ extern "C" void QCALLTYPE Delegate_Construct(QCall::ObjectHandleOnStack _this, Q MethodDesc* pDelegateInvoke = COMDelegate::FindDelegateInvokeMethod(pDelMT); - UINT invokeArgCount = MethodDescToNumFixedArgs(pDelegateInvoke); - UINT methodArgCount = MethodDescToNumFixedArgs(pMeth); + UINT invokeArgCount = COMDelegate::MethodDescToNumFixedArgs(pDelegateInvoke); + UINT methodArgCount = COMDelegate::MethodDescToNumFixedArgs(pMeth); BOOL isStatic = pMeth->IsStatic(); if (!isStatic) methodArgCount++; // count 'this' @@ -2991,7 +2991,6 @@ MethodDesc* COMDelegate::GetDelegateCtor(TypeHandle delegateType, MethodDesc *pT return pRealCtor; } - BOOL COMDelegate::IsWrapperDelegate(DELEGATEREF dRef) { CONTRACTL diff --git a/src/coreclr/vm/comdelegate.h b/src/coreclr/vm/comdelegate.h index be68b5ef40dd4..d0818951a8d75 100644 --- a/src/coreclr/vm/comdelegate.h +++ b/src/coreclr/vm/comdelegate.h @@ -68,6 +68,7 @@ class COMDelegate // Get the cpu stub for a delegate invoke. static Stub* GetInvokeMethodStub(EEImplMethodDesc* pMD); + static uint32_t MethodDescToNumFixedArgs(MethodDesc* pMD); static MethodDesc * __fastcall GetMethodDesc(OBJECTREF obj); static OBJECTREF GetTargetObject(OBJECTREF obj); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index ff5cf24a4ac01..2d04bf8985dd6 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -3985,7 +3985,97 @@ CORINFO_CLASS_HANDLE CEEInfo::getBuiltinClass(CorInfoClassId classId) return result; } +/*********************************************************************/ +CORINFO_METHOD_HANDLE CEEInfo::getMethodFromDelegate(CORINFO_CLASS_HANDLE calledCls, CORINFO_OBJECT_HANDLE delegateObj, + CORINFO_CLASS_HANDLE* methodCls, CORINFO_CLASS_HANDLE* targetCls) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + CORINFO_METHOD_HANDLE result = NULL; + + JIT_TO_EE_TRANSITION(); + + _ASSERTE (delegateObj != nullptr); + + MethodDesc* method = NULL; + PTR_MethodTable targetTable = NULL; + + { + // We get a direct pointer for frozen delegates + // and a pointer to a static location for normal ones. + // As such we need to deref the pointer if needed. + // We technically don't need to care about the GC + // for frozen delegates, but APIs used here require COOP. + GCX_COOP(); + DELEGATEREF delegate = (DELEGATEREF)getObjectFromJitHandle(delegateObj); + _ASSERTE (delegate != nullptr); + + GCPROTECT_BEGIN(delegate); + TypeHandle delegateType(delegate->GetMethodTable()); + TypeHandle calledType(calledCls); + if (delegateType.CanCastTo(calledType)) + { + if (delegate->GetInvocationCount() == 0) + { + method = COMDelegate::GetMethodDesc(delegate); + + MethodDesc* pDelegateInvoke = COMDelegate::FindDelegateInvokeMethod(calledType.GetMethodTable()); + UINT invokeArgCount = COMDelegate::MethodDescToNumFixedArgs(pDelegateInvoke); + + UINT methodArgCount = COMDelegate::MethodDescToNumFixedArgs(method); + if (!method->IsStatic()) + methodArgCount++; // count 'this' + + if (invokeArgCount != methodArgCount) + { + OBJECTREF target = COMDelegate::GetTargetObject(delegate); + if (target == NULL) + { + // avoid delegates closed over null + method = NULL; + } + else + { + targetTable = target->GetMethodTable(); + } + } + } + } + GCPROTECT_END(); + } + if (method != NULL) + { + if (targetCls != NULL) + { + *targetCls = CORINFO_CLASS_HANDLE(targetTable); + } + + if (methodCls != NULL) + { + PTR_MethodTable method_table; + if (!method->IsStatic() && targetTable != NULL) + { + method_table = method->GetExactDeclaringType(targetTable); + } + else + { + method_table = method->GetMethodTable(); + } + *methodCls = CORINFO_CLASS_HANDLE(method_table); + } + } + + result = (CORINFO_METHOD_HANDLE)method; + + EE_TO_JIT_TRANSITION(); + + return result; +} /*********************************************************************/ CorInfoType CEEInfo::getTypeForPrimitiveValueClass(