diff --git a/docs/design/coreclr/botr/clr-abi.md b/docs/design/coreclr/botr/clr-abi.md index 0585bfee301291..f0510bfa4afeee 100644 --- a/docs/design/coreclr/botr/clr-abi.md +++ b/docs/design/coreclr/botr/clr-abi.md @@ -148,8 +148,6 @@ ARM64-only: When a method returns a structure that is larger than 16 bytes the c *Stub dispatch* - when a virtual call uses a VSD stub, rather than back-patching the calling code (or disassembling it), the JIT must place the address of the stub used to load the call target, the "stub indirection cell", in (x86) `EAX` / (AMD64) `R11` / (ARM) `R12` / (ARM64) `R11`. In the JIT, this is encapsulated in the `VirtualStubParamInfo` class. -*Calli Pinvoke* - The VM wants the address of the PInvoke in (AMD64) `R10` / (ARM) `R12` / (ARM64) `R14` (In the JIT: `REG_PINVOKE_TARGET_PARAM`), and the signature (the pinvoke cookie) in (AMD64) `R11` / (ARM) `R4` / (ARM64) `R15` (in the JIT: `REG_PINVOKE_COOKIE_PARAM`). - *Normal PInvoke* - The VM shares IL stubs based on signatures, but wants the right method to show up in call stack and exceptions, so the MethodDesc for the exact PInvoke is passed in the (x86) `EAX` / (AMD64) `R10` / (ARM, ARM64) `R12` (in the JIT: `REG_SECRET_STUB_PARAM`). Then in the IL stub, when the JIT gets `CORJIT_FLG_PUBLISH_SECRET_PARAM`, it must move the register into a compiler temp. The value is returned for the intrinsic `NI_System_StubHelpers_GetStubContext`. ## Small primitive returns diff --git a/docs/design/coreclr/botr/guide-for-porting.md b/docs/design/coreclr/botr/guide-for-porting.md index ff90ba5c7df419..f569807cb63389 100644 --- a/docs/design/coreclr/botr/guide-for-porting.md +++ b/docs/design/coreclr/botr/guide-for-porting.md @@ -400,10 +400,8 @@ Here is an annotated list of the stubs implemented for Unix on Arm64. for ReadyToRun pre-compiled pinvoke calls, so that they do not cause GC starvation - 15. `VarargPInvokeStub`/ `GenericPInvokeCalliHelper` Used to support calli - pinvokes. It is expected that C\# 8.0 will increase use of this feature. - Today use of this feature on Unix requires hand-written IL. On Windows - this feature is commonly used by C++/CLI + 15. `VarargPInvokeStub` – Used to support vararg pinvokes, which are commonly + used by C++/CLI. Not necessary for non-Windows platforms at this time. #### cgencpu.h diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index 3d5f7da15005ef..2daa7a7b2e4148 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -2180,6 +2180,9 @@ internal static partial class StubHelpers [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "StubHelpers_ThrowInteropParamException")] internal static partial void ThrowInteropParamException(int resID, int paramIdx); + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "StubHelpers_ThrowInteropException")] + internal static partial void ThrowInteropException(int exceptionKind, int resID); + internal static IntPtr AddToCleanupList(ref CleanupWorkListElement? pCleanupWorkList, SafeHandle handle) { SafeHandleCleanupWorkListElement element = new SafeHandleCleanupWorkListElement(handle); diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 4c39bed1aea091..42c824deb19f1f 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -481,7 +481,6 @@ enum CorInfoHelpFunc /* Miscellaneous */ - CORINFO_HELP_PINVOKE_CALLI, // Indirect pinvoke call CORINFO_HELP_TAILCALL, // Perform a tail call CORINFO_HELP_GETCURRENTMANAGEDTHREADID, @@ -3363,12 +3362,6 @@ class ICorDynamicInfo : public ICorStaticInfo CORINFO_CONST_LOOKUP * pLookup ) = 0; - // Generate a cookie based on the signature to pass to CORINFO_HELP_PINVOKE_CALLI - virtual void* GetCookieForPInvokeCalliSig( - CORINFO_SIG_INFO* szMetaSig, - void** ppIndirection = NULL - ) = 0; - // Generate a cookie based on the signature to pass to INTOP_CALLI in the interpreter. virtual void* GetCookieForInterpreterCalliSig( CORINFO_SIG_INFO* szMetaSig) = 0; @@ -3512,6 +3505,7 @@ class ICorDynamicInfo : public ICorStaticInfo ) = 0; // Optionally, convert calli to regular method call. This is for PInvoke argument marshalling. + // On success, pResolvedToken->hMethod is set to the method that should be called instead. virtual bool convertPInvokeCalliToCall( CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 21dfb633498260..61b2f2a16f2269 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -597,10 +597,6 @@ void getAddressOfPInvokeTarget( CORINFO_METHOD_HANDLE method, CORINFO_CONST_LOOKUP* pLookup) override; -void* GetCookieForPInvokeCalliSig( - CORINFO_SIG_INFO* szMetaSig, - void** ppIndirection) override; - void* GetCookieForInterpreterCalliSig( CORINFO_SIG_INFO* szMetaSig) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index ed763baa880121..75775cf0096d46 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -37,11 +37,11 @@ #include -constexpr GUID JITEEVersionIdentifier = { /* 134b051a-e1ec-4f52-a1bf-f919908aa33c */ - 0x134b051a, - 0xe1ec, - 0x4f52, - {0xa1, 0xbf, 0xf9, 0x19, 0x90, 0x8a, 0xa3, 0x3c} +constexpr GUID JITEEVersionIdentifier = { /* 311b47c4-f2ef-4500-887d-a493343940d7 */ + 0x311b47c4, + 0xf2ef, + 0x4500, + {0x88, 0x7d, 0xa4, 0x93, 0x34, 0x39, 0x40, 0xd7} }; #endif // JIT_EE_VERSIONING_GUID_H diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 7742945b23e7e4..3ba323077d060d 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -216,8 +216,6 @@ DYNAMICJITHELPER(CORINFO_HELP_PROF_FCN_TAILCALL, JIT_ProfilerEnterLeaveTailcallStub, METHOD__NIL) // Miscellaneous - JITHELPER(CORINFO_HELP_PINVOKE_CALLI, GenericPInvokeCalliHelper, METHOD__NIL) - #if defined(TARGET_X86) && !defined(UNIX_X86_ABI) JITHELPER(CORINFO_HELP_TAILCALL, JIT_TailCall, METHOD__NIL) #else diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index fe8fa377332a9a..f55abaf7dc98e4 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -148,7 +148,6 @@ DEF_CLR_API(embedFieldHandle) DEF_CLR_API(embedGenericHandle) DEF_CLR_API(getLocationOfThisType) DEF_CLR_API(getAddressOfPInvokeTarget) -DEF_CLR_API(GetCookieForPInvokeCalliSig) DEF_CLR_API(GetCookieForInterpreterCalliSig) DEF_CLR_API(getJustMyCodeHandle) DEF_CLR_API(GetProfilingHandle) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 5291f7a8c8d287..b5ccc82ea89a59 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1413,16 +1413,6 @@ void WrapICorJitInfo::getAddressOfPInvokeTarget( API_LEAVE(getAddressOfPInvokeTarget); } -void* WrapICorJitInfo::GetCookieForPInvokeCalliSig( - CORINFO_SIG_INFO* szMetaSig, - void** ppIndirection) -{ - API_ENTER(GetCookieForPInvokeCalliSig); - void* temp = wrapHnd->GetCookieForPInvokeCalliSig(szMetaSig, ppIndirection); - API_LEAVE(GetCookieForPInvokeCalliSig); - return temp; -} - void* WrapICorJitInfo::GetCookieForInterpreterCalliSig( CORINFO_SIG_INFO* szMetaSig) { diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index f9cf55b8feeecb..8de5a895d6b170 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -9574,8 +9574,6 @@ class Compiler // Get the offset of a MDArray's lower bound for a given dimension. static unsigned eeGetMDArrayLowerBoundOffset(unsigned rank, unsigned dimension); - CORINFO_CONST_LOOKUP eeConvertToLookup(void* value, void* pValue); - // Returns the page size for the target machine as reported by the EE. target_size_t eeGetPageSize() { diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index 47af3c1f9b7e06..f996735d520c6f 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -504,34 +504,6 @@ unsigned Compiler::eeGetArgSizeAlignment(var_types type, bool isFloatHfa) } } -//------------------------------------------------------------------------ -// eeConvertToLookup: Convert a tuple of "{ value, pValue }" to "CORINFO_CONST_LOOKUP". -// -// Arguments: -// value - The direct value (IAT_VALUE) -// pValue - The indirect value (IAT_PVALUE) -// -// Return Value: -// The lookup. -// -CORINFO_CONST_LOOKUP Compiler::eeConvertToLookup(void* value, void* pValue) -{ - CORINFO_CONST_LOOKUP lookup; - if (value != nullptr) - { - assert(pValue == nullptr); - lookup.accessType = IAT_VALUE; - lookup.addr = value; - } - else - { - assert(pValue != nullptr); - lookup.accessType = IAT_PVALUE; - lookup.addr = pValue; - } - return lookup; -} - //------------------------------------------------------------------------ // eeGetArrayDataOffset: Gets the offset of a SDArray's first element // diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 0cb12dfca24794..c75f990052ce30 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -1607,14 +1607,6 @@ bool CallArgs::GetCustomRegister(Compiler* comp, CorInfoCallConvExtension cc, We *reg = comp->virtualStubParamInfo->GetReg(); return true; - case WellKnownArg::PInvokeCookie: - *reg = REG_PINVOKE_COOKIE_PARAM; - return true; - - case WellKnownArg::PInvokeTarget: - *reg = REG_PINVOKE_TARGET_PARAM; - return true; - case WellKnownArg::R2RIndirectionCell: *reg = REG_R2R_INDIRECT_PARAM; return true; @@ -2396,12 +2388,6 @@ int GenTreeCall::GetNonStandardAddedArgCount(Compiler* compiler) const // R11 = Virtual stub param return 1; } - else if ((gtCallType == CT_INDIRECT) && (gtCallCookie != nullptr)) - { - // R10 = PInvoke target param - // R11 = PInvoke cookie param - return 2; - } return 0; } @@ -2619,18 +2605,6 @@ bool GenTreeCall::Equals(GenTreeCall* c1, GenTreeCall* c2) } } } - else if (!c1->IsVirtualStub()) - { - if ((c1->gtCallCookie == nullptr) != (c2->gtCallCookie == nullptr)) - { - return false; - } - - if ((c1->gtCallCookie != nullptr) && !sameLookup(*c1->gtCallCookie, *c2->gtCallCookie)) - { - return false; - } - } auto sameArgMetadata = [](CallArg* a1, CallArg* a2) { return (a1->GetSignatureType() == a2->GetSignatureType()) && @@ -10118,11 +10092,10 @@ GenTreeCall* Compiler::gtNewCallNode(gtCallTypes callType, node->gtRetClsHnd = nullptr; node->gtCallMoreFlags = GTF_CALL_M_EMPTY; INDEBUG(node->gtCallDebugFlags = GTF_CALL_MD_EMPTY); - node->gtInlineInfoCount = 0; + node->ClearInlineInfo(); if (callType == CT_INDIRECT) { - node->gtCallCookie = nullptr; node->gtCallMethHnd = NO_METHOD_HANDLE; node->gtControlExpr = (GenTree*)callHnd; } @@ -10130,7 +10103,6 @@ GenTreeCall* Compiler::gtNewCallNode(gtCallTypes callType, { node->gtCallMethHnd = callHnd; node->gtControlExpr = nullptr; - node->ClearInlineInfo(); } node->gtReturnType = type; @@ -11741,15 +11713,15 @@ GenTreeCall* Compiler::gtCloneExprCallHelper(GenTreeCall* tree) copy->gtStubCallStubAddr = tree->gtStubCallStubAddr; /* Copy the union */ + copy->gtInlineCandidateInfo = tree->gtInlineCandidateInfo; + if (tree->gtCallType == CT_INDIRECT) { - copy->gtCallCookie = tree->gtCallCookie; copy->gtCallMethHnd = NO_METHOD_HANDLE; } else { - copy->gtCallMethHnd = tree->gtCallMethHnd; - copy->gtInlineCandidateInfo = tree->gtInlineCandidateInfo; + copy->gtCallMethHnd = tree->gtCallMethHnd; } copy->gtInlineInfoCount = tree->gtInlineInfoCount; diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index ab02812f445863..6c339cafe9dc11 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -5875,9 +5875,6 @@ struct GenTreeCall final : public GenTree union { - // The serialized CALLI unmanaged call (CT_INDIRECT) cookie; reified into argument IR in morph - CORINFO_CONST_LOOKUP* gtCallCookie; - // gtInlineCandidateInfo is only used when inlining methods InlineCandidateInfo* gtInlineCandidateInfo; // gtInlineCandidateInfoList is used when we have more than one GDV candidate diff --git a/src/coreclr/jit/handlekinds.h b/src/coreclr/jit/handlekinds.h index 9516c5193c8baf..d575617302b638 100644 --- a/src/coreclr/jit/handlekinds.h +++ b/src/coreclr/jit/handlekinds.h @@ -16,7 +16,6 @@ HANDLE_KIND(GTF_ICON_OBJ_HDL , "object" , 0) HANDLE_KIND(GTF_ICON_CONST_PTR , "const ptr" , HKF_INVARIANT) // pointer to immutable data, (e.g. IAT_PPVALUE) HANDLE_KIND(GTF_ICON_GLOBAL_PTR , "global ptr" , 0) // pointer to mutable data (e.g. from the VM state) HANDLE_KIND(GTF_ICON_VARG_HDL , "vararg" , HKF_INVARIANT) // var arg cookie handle -HANDLE_KIND(GTF_ICON_PINVKI_HDL , "pinvoke" , 0) // pinvoke calli handle HANDLE_KIND(GTF_ICON_TOKEN_HDL , "token" , HKF_INVARIANT) // token handle (other than class, method or field) HANDLE_KIND(GTF_ICON_TLS_HDL , "tls" , HKF_INVARIANT) // TLS ref with offset HANDLE_KIND(GTF_ICON_FTN_ADDR , "ftn" , 0) // function address diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 775339048a6af1..42d49f17e21430 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -230,13 +230,12 @@ var_types Compiler::impImportCall(OPCODE opcode, if (opcode == CEE_CALLI) { - if (IsTargetAbi(CORINFO_NATIVEAOT_ABI)) + if (info.compCompHnd->convertPInvokeCalliToCall(pResolvedToken, !impCanPInvokeInlineCallSite(compCurBB))) { - if (info.compCompHnd->convertPInvokeCalliToCall(pResolvedToken, !impCanPInvokeInlineCallSite(compCurBB))) - { - eeGetCallInfo(pResolvedToken, nullptr, CORINFO_CALLINFO_ALLOWINSTPARAM, callInfo); - return impImportCall(CEE_CALL, pResolvedToken, nullptr, nullptr, prefixFlags, callInfo, rawILOffset); - } + // The VM only fills in hMethod; derive the rest of the token from it. + pResolvedToken->hClass = info.compCompHnd->getMethodClass(pResolvedToken->hMethod); + eeGetCallInfo(pResolvedToken, nullptr, CORINFO_CALLINFO_ALLOWINSTPARAM, callInfo); + return impImportCall(CEE_CALL, pResolvedToken, nullptr, nullptr, prefixFlags, callInfo, rawILOffset); } /* Get the call site sig */ @@ -826,20 +825,6 @@ var_types Compiler::impImportCall(OPCODE opcode, goto DONE; } - else if ((opcode == CEE_CALLI) && ((sig->callConv & CORINFO_CALLCONV_MASK) != CORINFO_CALLCONV_DEFAULT) && - ((sig->callConv & CORINFO_CALLCONV_MASK) != CORINFO_CALLCONV_VARARG)) - { - void* pCookie; - void* cookie = info.compCompHnd->GetCookieForPInvokeCalliSig(sig, &pCookie); - CORINFO_CONST_LOOKUP cookieLookup = eeConvertToLookup(cookie, pCookie); - call->AsCall()->gtCallCookie = new (getAllocator(CMK_ASTNode)) CORINFO_CONST_LOOKUP(cookieLookup); - - if (canTailCall) - { - canTailCall = false; - szCanTailCallFailReason = "PInvoke calli"; - } - } if (sig->isAsyncCall()) { @@ -7185,8 +7170,6 @@ void Compiler::impCheckForPInvokeCall( } unmanagedCallConv = info.compCompHnd->getUnmanagedCallConv(nullptr, sig, &suppressGCTransition); - - assert(!call->gtCallCookie); } if (suppressGCTransition) @@ -7209,13 +7192,11 @@ void Compiler::impCheckForPInvokeCall( } optNativeCallCount++; - if (methHnd == nullptr && (IsTargetAbi(CORINFO_NATIVEAOT_ABI) || - (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB) && !compIsForInlining()))) + if (methHnd == nullptr) { - // PInvoke CALLI in NativeAOT ABI must be always inlined. Non-inlineable CALLI cases have been - // converted to regular method calls earlier using convertPInvokeCalliToCall. - - // PInvoke CALLI in IL stubs must be inlined + // PInvoke CALLI must always be inlined. Call sites that cannot be inlined have been converted + // to a call to a marshalling stub earlier using convertPInvokeCalliToCall, or, in ReadyToRun, + // have aborted the compilation of this method. } else if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB) && IsReadyToRun()) { @@ -8402,17 +8383,6 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, return; } - // CT_INDIRECT calls may use the cookie, bail if so... - // - // If transforming these provides a benefit, we could save this off in the same way - // we save the stub address below. - if ((call->gtCallType == CT_INDIRECT) && (call->AsCall()->gtCallCookie != nullptr)) - { - JITDUMP("NOT Marking call [%06u] as guarded devirtualization candidate -- CT_INDIRECT with cookie\n", - dspTreeID(call)); - return; - } - #ifdef DEBUG // See if disabled by range diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 54bca2b4a8995c..379c83c2b3f2ef 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -2044,7 +2044,10 @@ void Lowering::LowerSpecialCopyArgs(GenTreeCall* call) // which will be first in the list. // The this parameter is always passed in registers, so we can ignore it. unsigned argIndex = call->gtArgs.CountUserArgs() - 1; - assert(call->gtArgs.CountUserArgs() == m_compiler->info.compILargsCount); + // The arguments of the unmanaged call are the leading arguments of the IL stub, so the stub + // cannot have fewer of them. It can have more: an unmanaged CALLI stub takes the call target + // as an extra trailing argument that is not passed on to the unmanaged call. + assert(call->gtArgs.CountUserArgs() <= m_compiler->info.compILargsCount); bool checkForUnmanagedThisArg = call->GetUnmanagedCallConv() == CorInfoCallConvExtension::Thiscall; for (CallArg& arg : call->gtArgs.Args()) { @@ -2903,11 +2906,7 @@ GenTree* Lowering::LowerCall(GenTree* node) { controlExpr = LowerNonvirtPinvokeCall(call); } - else if (call->gtCallType == CT_INDIRECT) - { - controlExpr = LowerIndirectNonvirtCall(call); - } - else + else if (call->gtCallType != CT_INDIRECT) { controlExpr = LowerDirectCall(call); } @@ -6631,14 +6630,6 @@ void Lowering::OptimizeCallIndirectTargetEvaluation(GenTreeCall* call) DISPTREERANGE(BlockRange(), call); } -GenTree* Lowering::LowerIndirectNonvirtCall(GenTreeCall* call) -{ - // Indirect cookie calls gets transformed by fgMorphArgs as indirect call with non-standard args. - // Hence we should never see this type of call in lower. - noway_assert(call->gtCallCookie == nullptr); - return nullptr; -} - //------------------------------------------------------------------------ // CreateReturnTrapSeq: Create a tree to perform a "return trap", used in PInvoke // epilogs to invoke a GC under a condition. The return trap checks some global diff --git a/src/coreclr/jit/lower.h b/src/coreclr/jit/lower.h index eb7b257709ac3f..a748ee110b0ed2 100644 --- a/src/coreclr/jit/lower.h +++ b/src/coreclr/jit/lower.h @@ -199,7 +199,6 @@ class Lowering final : public Phase #endif // WINDOWS_AMD64_ABI GenTree* LowerDelegateInvoke(GenTreeCall* call); void OptimizeCallIndirectTargetEvaluation(GenTreeCall* call); - GenTree* LowerIndirectNonvirtCall(GenTreeCall* call); GenTree* LowerDirectCall(GenTreeCall* call); GenTree* LowerNonvirtPinvokeCall(GenTreeCall* call); GenTree* LowerTailCallViaJitHelper(GenTreeCall* callNode, GenTree* callTarget); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index bebaf78c3f59ea..3e3e495345314f 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -1756,34 +1756,6 @@ void CallArgs::AddFinalArgsAndDetermineABIInfo(Compiler* comp, GenTreeCall* call // add as a non-standard arg. } } - else if ((call->gtCallType == CT_INDIRECT) && !call->IsVirtualStub() && (call->gtCallCookie != nullptr)) - { - assert(!call->IsUnmanaged()); - - GenTree* arg = comp->gtNewIconEmbHndNode(call->gtCallCookie, GTF_ICON_PINVKI_HDL, nullptr); - call->gtCallCookie = nullptr; - - // TODO: this is preserving existing behavior, but do we actually need these NO_CSEs? - GenTree* argConst = arg->OperIs(GT_IND) ? arg->AsIndir()->Addr() : arg; - argConst->gtFlags |= GTF_DONT_CSE; - arg->gtFlags |= GTF_DONT_CSE; - - // All architectures pass the cookie in a register. - InsertAfterThisOrFirst(comp, NewCallArg::Primitive(arg).WellKnown(WellKnownArg::PInvokeCookie)); - // put destination into R10/EAX - arg = comp->gtClone(call->gtControlExpr, true); - // On x64 the pinvoke target is passed in r10 which is the same - // register as the gs cookie check may use. That would be a problem if - // this was a tailcall, but we do not tailcall functions with - // non-standard added args except indirection cells currently. - assert(!call->IsFastTailCall()); - InsertAfterThisOrFirst(comp, NewCallArg::Primitive(arg).WellKnown(WellKnownArg::PInvokeTarget)); - - // finally change this call to a helper call - call->gtCallType = CT_HELPER; - call->gtControlExpr = nullptr; - call->gtCallMethHnd = comp->eeFindHelper(CORINFO_HELP_PINVOKE_CALLI); - } #if defined(FEATURE_READYTORUN) #ifdef TARGET_WASM @@ -5811,7 +5783,6 @@ void Compiler::fgMorphTailCallViaJitHelper(GenTreeCall* call) // Check for PInvoke call types that we don't handle in codegen yet. assert(!call->IsUnmanaged()); - assert(call->IsVirtual() || (call->gtCallType != CT_INDIRECT) || (call->gtCallCookie == nullptr)); // Don't support tail calling helper methods assert(!call->IsHelperCall()); diff --git a/src/coreclr/jit/targetamd64.h b/src/coreclr/jit/targetamd64.h index f0ab6b24f44d78..56a4d5b0eeb876 100644 --- a/src/coreclr/jit/targetamd64.h +++ b/src/coreclr/jit/targetamd64.h @@ -384,14 +384,6 @@ // See ImportThunk.Kind.DelayLoadHelperWithExistingIndirectionCell in crossgen2. #define RBM_R2R_INDIRECT_PARAM RBM_RAX -// GenericPInvokeCalliHelper VASigCookie Parameter -#define REG_PINVOKE_COOKIE_PARAM REG_R11 -#define RBM_PINVOKE_COOKIE_PARAM RBM_R11 - -// GenericPInvokeCalliHelper unmanaged target Parameter -#define REG_PINVOKE_TARGET_PARAM REG_R10 -#define RBM_PINVOKE_TARGET_PARAM RBM_R10 - // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM) #define REG_SECRET_STUB_PARAM REG_R10 #define RBM_SECRET_STUB_PARAM RBM_R10 diff --git a/src/coreclr/jit/targetarm.h b/src/coreclr/jit/targetarm.h index 006bd4e0559b6b..9b431efcdaaa7c 100644 --- a/src/coreclr/jit/targetarm.h +++ b/src/coreclr/jit/targetarm.h @@ -162,14 +162,6 @@ // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF. #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_WRITEBARRIER -// GenericPInvokeCalliHelper VASigCookie Parameter -#define REG_PINVOKE_COOKIE_PARAM REG_R4 -#define RBM_PINVOKE_COOKIE_PARAM RBM_R4 - -// GenericPInvokeCalliHelper unmanaged target Parameter -#define REG_PINVOKE_TARGET_PARAM REG_R12 -#define RBM_PINVOKE_TARGET_PARAM RBM_R12 - // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM) #define REG_SECRET_STUB_PARAM REG_R12 #define RBM_SECRET_STUB_PARAM RBM_R12 diff --git a/src/coreclr/jit/targetarm64.h b/src/coreclr/jit/targetarm64.h index 0f196cacf5e836..cc9c48583641c0 100644 --- a/src/coreclr/jit/targetarm64.h +++ b/src/coreclr/jit/targetarm64.h @@ -184,14 +184,6 @@ // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF. #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_NOGC -// GenericPInvokeCalliHelper VASigCookie Parameter -#define REG_PINVOKE_COOKIE_PARAM REG_R15 -#define RBM_PINVOKE_COOKIE_PARAM RBM_R15 - -// GenericPInvokeCalliHelper unmanaged target Parameter -#define REG_PINVOKE_TARGET_PARAM REG_R12 -#define RBM_PINVOKE_TARGET_PARAM RBM_R12 - // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM) #define REG_SECRET_STUB_PARAM REG_R12 #define RBM_SECRET_STUB_PARAM RBM_R12 diff --git a/src/coreclr/jit/targetloongarch64.h b/src/coreclr/jit/targetloongarch64.h index 6acd2a67dfeebd..c4d9deae15789b 100644 --- a/src/coreclr/jit/targetloongarch64.h +++ b/src/coreclr/jit/targetloongarch64.h @@ -163,14 +163,6 @@ // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF. #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_NOGC -// GenericPInvokeCalliHelper VASigCookie Parameter -#define REG_PINVOKE_COOKIE_PARAM REG_T3 -#define RBM_PINVOKE_COOKIE_PARAM RBM_T3 - -// GenericPInvokeCalliHelper unmanaged target Parameter -#define REG_PINVOKE_TARGET_PARAM REG_T2 -#define RBM_PINVOKE_TARGET_PARAM RBM_T2 - // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM) #define REG_SECRET_STUB_PARAM REG_T2 #define RBM_SECRET_STUB_PARAM RBM_T2 diff --git a/src/coreclr/jit/targetriscv64.h b/src/coreclr/jit/targetriscv64.h index 9679439d637025..3ec1ad135e5fd0 100644 --- a/src/coreclr/jit/targetriscv64.h +++ b/src/coreclr/jit/targetriscv64.h @@ -158,14 +158,6 @@ // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF. #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_NOGC -// GenericPInvokeCalliHelper VASigCookie Parameter -#define REG_PINVOKE_COOKIE_PARAM REG_T3 -#define RBM_PINVOKE_COOKIE_PARAM RBM_T3 - -// GenericPInvokeCalliHelper unmanaged target Parameter -#define REG_PINVOKE_TARGET_PARAM REG_T2 -#define RBM_PINVOKE_TARGET_PARAM RBM_T2 - // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM) #define REG_SECRET_STUB_PARAM REG_T2 #define RBM_SECRET_STUB_PARAM RBM_T2 diff --git a/src/coreclr/jit/targetwasm.h b/src/coreclr/jit/targetwasm.h index 4c2ac831cb07d1..00ad95fe143f3b 100644 --- a/src/coreclr/jit/targetwasm.h +++ b/src/coreclr/jit/targetwasm.h @@ -155,14 +155,6 @@ // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF. #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_CALLEE_TRASH_NOGC -// GenericPInvokeCalliHelper VASigCookie Parameter -#define REG_PINVOKE_COOKIE_PARAM REG_NA -#define RBM_PINVOKE_COOKIE_PARAM RBM_NONE - -// GenericPInvokeCalliHelper unmanaged target Parameter -#define REG_PINVOKE_TARGET_PARAM REG_NA -#define RBM_PINVOKE_TARGET_PARAM RBM_NONE - // IL stub's secret MethodDesc parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM) #define REG_SECRET_STUB_PARAM REG_NA #define RBM_SECRET_STUB_PARAM RBM_NONE diff --git a/src/coreclr/jit/targetx86.h b/src/coreclr/jit/targetx86.h index dd338c316a3d0d..8d3d6c7eb5b8af 100644 --- a/src/coreclr/jit/targetx86.h +++ b/src/coreclr/jit/targetx86.h @@ -226,13 +226,6 @@ // Registers no longer containing GC pointers after CORINFO_HELP_ASSIGN_REF and CORINFO_HELP_CHECKED_ASSIGN_REF. #define RBM_CALLEE_GCTRASH_WRITEBARRIER RBM_EDX -// GenericPInvokeCalliHelper unmanaged target parameter -#define REG_PINVOKE_TARGET_PARAM REG_EAX -#define RBM_PINVOKE_TARGET_PARAM RBM_EAX - -// GenericPInvokeCalliHelper cookie parameter -#define REG_PINVOKE_COOKIE_PARAM REG_EBX - // IL stub's secret parameter (JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM) #define REG_SECRET_STUB_PARAM REG_EAX #define RBM_SECRET_STUB_PARAM RBM_EAX diff --git a/src/coreclr/jit/wellknownargs.h b/src/coreclr/jit/wellknownargs.h index 56e3ad962095dd..02e4b480df6bc1 100644 --- a/src/coreclr/jit/wellknownargs.h +++ b/src/coreclr/jit/wellknownargs.h @@ -26,8 +26,6 @@ WELL_KNOWN_ARG(PInvokeFrame, "pinv frame", false, false) WELL_KNOWN_ARG(ShiftLow, "shift low", false, false) WELL_KNOWN_ARG(ShiftHigh, "shift high", false, false) WELL_KNOWN_ARG(VirtualStubCell, "vsd cell", false, true) -WELL_KNOWN_ARG(PInvokeCookie, "pinv cookie", false, true) -WELL_KNOWN_ARG(PInvokeTarget, "pinv tgt", false, true) WELL_KNOWN_ARG(R2RIndirectionCell, "r2r cell", false, true) WELL_KNOWN_ARG(ValidateIndirectCallTarget, "cfg tgt", false, false) WELL_KNOWN_ARG(DispatchIndirectCallTarget, "cfg tgt", false, false) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs index 68f7b52f6ec048..ab7ca8480c7a54 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -179,7 +179,6 @@ which is the right helper to use to allocate an object of a given type. */ /* Miscellaneous */ - CORINFO_HELP_PINVOKE_CALLI, // Indirect pinvoke call CORINFO_HELP_TAILCALL, // Perform a tail call CORINFO_HELP_GETCURRENTMANAGEDTHREADID, diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index acbf063ada8c5b..7a52094b772b69 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -4072,14 +4072,6 @@ private void getLocationOfThisType(CORINFO_METHOD_STRUCT_* context, ref CORINFO_ private void* GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) { throw new NotImplementedException("GetCookieForInterpreterCalliSig"); } - private void* GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, ref void* ppIndirection) - { -#if READYTORUN - throw new RequiresRuntimeJitException($"{MethodBeingCompiled} -> {nameof(GetCookieForPInvokeCalliSig)}"); -#else - throw new NotImplementedException(nameof(GetCookieForPInvokeCalliSig)); -#endif - } #pragma warning disable CA1822 // Mark members as static private CORINFO_JUST_MY_CODE_HANDLE_* getJustMyCodeHandle(CORINFO_METHOD_STRUCT_* method, ref CORINFO_JUST_MY_CODE_HANDLE_* ppIndirection) #pragma warning restore CA1822 // Mark members as static diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 5be5fd01b69eb9..1f45c9bf3f3602 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -164,7 +164,6 @@ static ICorJitInfoCallbacks() s_callbacks.embedGenericHandle = &_embedGenericHandle; s_callbacks.getLocationOfThisType = &_getLocationOfThisType; s_callbacks.getAddressOfPInvokeTarget = &_getAddressOfPInvokeTarget; - s_callbacks.GetCookieForPInvokeCalliSig = &_GetCookieForPInvokeCalliSig; s_callbacks.GetCookieForInterpreterCalliSig = &_GetCookieForInterpreterCalliSig; s_callbacks.getJustMyCodeHandle = &_getJustMyCodeHandle; s_callbacks.GetProfilingHandle = &_GetProfilingHandle; @@ -349,7 +348,6 @@ static ICorJitInfoCallbacks() public delegate* unmanaged embedGenericHandle; public delegate* unmanaged getLocationOfThisType; public delegate* unmanaged getAddressOfPInvokeTarget; - public delegate* unmanaged GetCookieForPInvokeCalliSig; public delegate* unmanaged GetCookieForInterpreterCalliSig; public delegate* unmanaged getJustMyCodeHandle; public delegate* unmanaged GetProfilingHandle; @@ -2516,21 +2514,6 @@ private static void _getAddressOfPInvokeTarget(IntPtr thisHandle, IntPtr* ppExce } } - [UnmanagedCallersOnly] - private static void* _GetCookieForPInvokeCalliSig(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* szMetaSig, void** ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.GetCookieForPInvokeCalliSig(szMetaSig, ref *ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default; - } - } - [UnmanagedCallersOnly] private static void* _GetCookieForInterpreterCalliSig(IntPtr thisHandle, IntPtr* ppException, CORINFO_SIG_INFO* szMetaSig) { diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index f478dc79563f29..bcb7e99a428b80 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -319,7 +319,6 @@ FUNCTIONS void embedGenericHandle(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fEmbedParent, CORINFO_METHOD_HANDLE callerHandle, CORINFO_GENERICHANDLE_RESULT * pResult); void getLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* pLookupKind); void getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method, REF_CORINFO_CONST_LOOKUP pLookup); - void* GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void ** ppIndirection); void* GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig); CORINFO_JUST_MY_CODE_HANDLE getJustMyCodeHandle(CORINFO_METHOD_HANDLE method, CORINFO_JUST_MY_CODE_HANDLE**ppIndirection); void GetProfilingHandle(bool* pbHookFunction, void **pProfilerHandle, bool* pbIndirectedHandles); 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 565034235355b5..887a3774d2584d 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -3332,7 +3332,33 @@ private bool pInvokeMarshalingRequired(CORINFO_METHOD_STRUCT_* handle, CORINFO_S private bool convertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken, bool mustConvert) { - throw new NotImplementedException(); + var methodIL = (MethodIL)HandleToObject((void*)pResolvedToken.tokenScope); + var signature = (MethodSignature)methodIL.GetObject((int)pResolvedToken.token); + + switch (signature.Flags & MethodSignatureFlags.UnmanagedCallingConventionMask) + { + case MethodSignatureFlags.None: + case MethodSignatureFlags.CallingConventionVarargs: + // Not an unmanaged call site. + return false; + } + + CorInfoCallConvExtension unmanagedCallConv = GetUnmanagedCallConv(signature, out _); + + // ReadyToRun has no way to refer to the marshalling stub the runtime creates for an unmanaged + // calli, so the JIT has to expand the call site inline. Everything it cannot expand - a call site + // where an inline P/Invoke frame is not allowed, a calling convention the JIT refuses to inline, + // an unmanaged signature carrying an instance 'this', or a signature that needs marshalling - + // leaves the method to the runtime JIT. + if (mustConvert || + !signature.IsStatic || signature.IsExplicitThis || + unmanagedCallConv is CorInfoCallConvExtension.Fastcall or CorInfoCallConvExtension.FastcallMemberFunction || + Marshaller.IsMarshallingRequired(signature, Array.Empty(), ((MetadataType)methodIL.OwningMethod.OwningType).Module)) + { + throw new RequiresRuntimeJitException($"{MethodBeingCompiled} -> {nameof(convertPInvokeCalliToCall)}"); + } + + return false; } private int SizeOfPInvokeTransitionFrame => ReadyToRunRuntimeConstants.READYTORUN_PInvokeTransitionFrameSizeInPointerUnits * PointerSize; 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 14f0f9b6c1e33a..0d486b639a870e 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2021,7 +2021,6 @@ private bool convertPInvokeCalliToCall(ref CORINFO_RESOLVED_TOKEN pResolvedToken return false; pResolvedToken.hMethod = ObjectToHandle(stub); - pResolvedToken.hClass = ObjectToHandle(stub.OwningType); return true; } diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 75648980ac0a7b..04baed86f08c8e 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -155,7 +155,6 @@ struct JitInterfaceCallbacks void (* embedGenericHandle)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool fEmbedParent, CORINFO_METHOD_HANDLE callerHandle, CORINFO_GENERICHANDLE_RESULT* pResult); void (* getLocationOfThisType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* pLookupKind); void (* getAddressOfPInvokeTarget)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE method, CORINFO_CONST_LOOKUP* pLookup); - void* (* GetCookieForPInvokeCalliSig)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_SIG_INFO* szMetaSig, void** ppIndirection); void* (* GetCookieForInterpreterCalliSig)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_SIG_INFO* szMetaSig); CORINFO_JUST_MY_CODE_HANDLE (* getJustMyCodeHandle)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE method, CORINFO_JUST_MY_CODE_HANDLE** ppIndirection); void (* GetProfilingHandle)(void * thisHandle, CorInfoExceptionClass** ppException, bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles); @@ -1598,16 +1597,6 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; } - virtual void* GetCookieForPInvokeCalliSig( - CORINFO_SIG_INFO* szMetaSig, - void** ppIndirection) -{ - CorInfoExceptionClass* pException = nullptr; - void* temp = _callbacks->GetCookieForPInvokeCalliSig(_thisHandle, &pException, szMetaSig, ppIndirection); - if (pException != nullptr) throw pException; - return temp; -} - virtual void* GetCookieForInterpreterCalliSig( CORINFO_SIG_INFO* szMetaSig) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 42c1f462755b4d..4855a7f851845d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -728,14 +728,6 @@ struct GetVarArgsHandleValue DWORDLONG methHnd; }; -struct GetCookieForPInvokeCalliSigValue -{ - DWORD cbSig; - DWORD pSig_Index; - DWORDLONG scope; - DWORD token; -}; - struct GetCookieForInterpreterCalliSigValue { DWORD cbSig; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 1616fc79d2916f..2165d8aba1991c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -71,7 +71,6 @@ LWM(GetClassNumInstanceFields, DWORDLONG, DWORD) LWM(GetClassSize, DWORDLONG, DWORD) LWM(GetHeapClassSize, DWORDLONG, DWORD) LWM(CanAllocateOnStack, DWORDLONG, DWORD) -LWM(GetCookieForPInvokeCalliSig, GetCookieForPInvokeCalliSigValue, DLDL) LWM(GetCookieForInterpreterCalliSig, GetCookieForInterpreterCalliSigValue, DLDL) LWM(GetDefaultComparerClass, DWORDLONG, DWORDLONG) LWM(GetDefaultEqualityComparerClass, DWORDLONG, DWORDLONG) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 7d90db055b4d3d..61a96fc2b11ff8 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -6049,52 +6049,6 @@ TypeCompareState MethodContext::repIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLAS return (TypeCompareState)value.B; } -void MethodContext::recGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection, LPVOID result) -{ - if (GetCookieForPInvokeCalliSig == nullptr) - GetCookieForPInvokeCalliSig = new LightWeightMap(); - - GetCookieForPInvokeCalliSigValue key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.cbSig = (DWORD)szMetaSig->cbSig; - key.pSig_Index = (DWORD)GetCookieForPInvokeCalliSig->AddBuffer((unsigned char*)szMetaSig->pSig, szMetaSig->cbSig); - key.scope = CastHandle(szMetaSig->scope); - key.token = (DWORD)szMetaSig->token; - - DLDL value; - if (ppIndirection != nullptr) - value.A = CastPointer(*ppIndirection); - else - value.A = 0; - value.B = CastPointer(result); - - GetCookieForPInvokeCalliSig->Add(key, value); - DEBUG_REC(dmpGetCookieForPInvokeCalliSig(key, value)); -} -void MethodContext::dmpGetCookieForPInvokeCalliSig(const GetCookieForPInvokeCalliSigValue& key, DLDL value) -{ - printf("GetCookieForPInvokeCalliSig NYI"); -} -LPVOID MethodContext::repGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection) -{ - AssertMapExistsNoMessage(GetCookieForPInvokeCalliSig); - - GetCookieForPInvokeCalliSigValue key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key.cbSig = (DWORD)szMetaSig->cbSig; - key.pSig_Index = (DWORD)GetCookieForPInvokeCalliSig->Contains((unsigned char*)szMetaSig->pSig, szMetaSig->cbSig); - key.scope = CastHandle(szMetaSig->scope); - key.token = (DWORD)szMetaSig->token; - - DLDL value = LookupByKeyOrMissNoMessage(GetCookieForPInvokeCalliSig, key); - - DEBUG_REP(dmpGetCookieForPInvokeCalliSig(key, value)); - - if (ppIndirection != nullptr) - *ppIndirection = (void*)value.A; - return (CORINFO_VARARGS_HANDLE)value.B; -} - void MethodContext::recGetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig, LPVOID result) { if (GetCookieForInterpreterCalliSig == nullptr) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 32eb7aef721b6d..78ba8c9d3575f6 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -743,10 +743,6 @@ class MethodContext void dmpIsEnum(DWORDLONG key, DLD value); TypeCompareState repIsEnum(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE* underlyingType); - void recGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection, LPVOID result); - void dmpGetCookieForPInvokeCalliSig(const GetCookieForPInvokeCalliSigValue& key, DLDL value); - LPVOID repGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection); - LPVOID repGetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig); void recGetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig, LPVOID result); void dmpGetCookieForInterpreterCalliSig(const GetCookieForInterpreterCalliSigValue& key, DLDL value); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 9a708cd3f7b420..969f5d09dc8163 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1621,15 +1621,6 @@ void interceptor_ICJI::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method, C mc->recGetAddressOfPInvokeTarget(method, pLookup); } -// Generate a cookie based on the signature to pass to CORINFO_HELP_PINVOKE_CALLI -LPVOID interceptor_ICJI::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection) -{ - mc->cr->AddCall("GetCookieForPInvokeCalliSig"); - LPVOID temp = original_ICorJitInfo->GetCookieForPInvokeCalliSig(szMetaSig, ppIndirection); - mc->recGetCookieForPInvokeCalliSig(szMetaSig, ppIndirection, temp); - return temp; -} - // Generate a cookie based on the signature to pass to INTOP_CALLI LPVOID interceptor_ICJI::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) { 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 931dad3bb9cce0..f288135513ae0e 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1164,14 +1164,6 @@ void interceptor_ICJI::getAddressOfPInvokeTarget( original_ICorJitInfo->getAddressOfPInvokeTarget(method, pLookup); } -void* interceptor_ICJI::GetCookieForPInvokeCalliSig( - CORINFO_SIG_INFO* szMetaSig, - void** ppIndirection) -{ - mcs->AddCall("GetCookieForPInvokeCalliSig"); - return original_ICorJitInfo->GetCookieForPInvokeCalliSig(szMetaSig, ppIndirection); -} - void* interceptor_ICJI::GetCookieForInterpreterCalliSig( CORINFO_SIG_INFO* szMetaSig) { 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 023658229bbf74..bdc9f19050b835 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -1020,13 +1020,6 @@ void interceptor_ICJI::getAddressOfPInvokeTarget( original_ICorJitInfo->getAddressOfPInvokeTarget(method, pLookup); } -void* interceptor_ICJI::GetCookieForPInvokeCalliSig( - CORINFO_SIG_INFO* szMetaSig, - void** ppIndirection) -{ - return original_ICorJitInfo->GetCookieForPInvokeCalliSig(szMetaSig, ppIndirection); -} - void* interceptor_ICJI::GetCookieForInterpreterCalliSig( CORINFO_SIG_INFO* szMetaSig) { diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index e5d65f8e046f0a..e77b71b5a9cb0d 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1389,13 +1389,6 @@ void MyICJI::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method, CORINFO_CON jitInstance->mc->repGetAddressOfPInvokeTarget(method, pLookup); } -// Generate a cookie based on the signature to pass to CORINFO_HELP_PINVOKE_CALLI -LPVOID MyICJI::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, void** ppIndirection) -{ - jitInstance->mc->cr->AddCall("GetCookieForPInvokeCalliSig"); - return jitInstance->mc->repGetCookieForPInvokeCalliSig(szMetaSig, ppIndirection); -} - // Generate a cookie based on the signature to pass to INTOP_CALLI LPVOID MyICJI::GetCookieForInterpreterCalliSig(CORINFO_SIG_INFO* szMetaSig) { diff --git a/src/coreclr/vm/FrameTypes.h b/src/coreclr/vm/FrameTypes.h index 03ea0dd0f4cdb6..42601a1b8bcfea 100644 --- a/src/coreclr/vm/FrameTypes.h +++ b/src/coreclr/vm/FrameTypes.h @@ -20,7 +20,6 @@ FRAME_TYPE_NAME(FuncEvalFrame) #endif // DEBUGGING_SUPPORTED #ifdef FEATURE_COMINTEROP #endif // FEATURE_COMINTEROP -FRAME_TYPE_NAME(PInvokeCalliFrame) #ifdef FEATURE_HIJACK FRAME_TYPE_NAME(HijackFrame) #endif // FEATURE_HIJACK diff --git a/src/coreclr/vm/amd64/PInvokeStubs.asm b/src/coreclr/vm/amd64/PInvokeStubs.asm index 9913dbd3c53f5b..6a837c67a983e0 100644 --- a/src/coreclr/vm/amd64/PInvokeStubs.asm +++ b/src/coreclr/vm/amd64/PInvokeStubs.asm @@ -4,72 +4,11 @@ include AsmMacros.inc include AsmConstants.inc -extern GenericPInvokeCalliStubWorker:proc extern VarargPInvokeStubWorker:proc extern JIT_PInvokeEndRarePath:proc extern g_TrapReturningThreads:DWORD -; -; in: -; PINVOKE_CALLI_TARGET_REGISTER (r10) = unmanaged target -; PINVOKE_CALLI_SIGTOKEN_REGNUM (r11) = sig token -; -; out: -; METHODDESC_REGISTER (r10) = unmanaged target -; -LEAF_ENTRY GenericPInvokeCalliHelper, _TEXT - - ; - ; check for existing IL stub - ; - mov rax, [PINVOKE_CALLI_SIGTOKEN_REGISTER + OFFSETOF__VASigCookie__pPInvokeILStub] - test rax, rax - jz GenericPInvokeCalliGenILStub - - ; - ; We need to distinguish between a MethodDesc* and an unmanaged target. - ; The way we do this is to shift the managed target to the left by one bit and then set the - ; least significant bit to 1. This works because MethodDesc* are always 8-byte aligned. - ; - shl PINVOKE_CALLI_TARGET_REGISTER, 1 - or PINVOKE_CALLI_TARGET_REGISTER, 1 - - ; - ; jump to existing IL stub - ; - jmp rax - -LEAF_END GenericPInvokeCalliHelper, _TEXT - -NESTED_ENTRY GenericPInvokeCalliGenILStub, _TEXT - - PROLOG_WITH_TRANSITION_BLOCK - - ; - ; save target - ; - mov r12, METHODDESC_REGISTER - mov r13, PINVOKE_CALLI_SIGTOKEN_REGISTER - - ; - ; GenericPInvokeCalliStubWorker(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget) - ; - lea rcx, [rsp + __PWTB_TransitionBlock] ; pTransitionBlock* - mov rdx, PINVOKE_CALLI_SIGTOKEN_REGISTER ; pVASigCookie - mov r8, METHODDESC_REGISTER ; pUnmanagedTarget - call GenericPInvokeCalliStubWorker - - ; - ; restore target - ; - mov METHODDESC_REGISTER, r12 - mov PINVOKE_CALLI_SIGTOKEN_REGISTER, r13 - - EPILOG_WITH_TRANSITION_BLOCK_TAILCALL - jmp GenericPInvokeCalliHelper - -NESTED_END GenericPInvokeCalliGenILStub, _TEXT LEAF_ENTRY VarargPInvokeStub, _TEXT mov PINVOKE_CALLI_SIGTOKEN_REGISTER, rcx diff --git a/src/coreclr/vm/amd64/asmconstants.h b/src/coreclr/vm/amd64/asmconstants.h index f6507886d6bda0..4afd23572e6d53 100644 --- a/src/coreclr/vm/amd64/asmconstants.h +++ b/src/coreclr/vm/amd64/asmconstants.h @@ -53,9 +53,6 @@ ASMCONSTANTS_C_ASSERT(ASM_ELEMENT_TYPE_R8 == ELEMENT_TYPE_R8); #define METHODDESC_REGNUM 10 #define METHODDESC_REGISTER r10 -#define PINVOKE_CALLI_TARGET_REGNUM 10 -#define PINVOKE_CALLI_TARGET_REGISTER r10 - #define PINVOKE_CALLI_SIGTOKEN_REGNUM 11 #define PINVOKE_CALLI_SIGTOKEN_REGISTER r11 diff --git a/src/coreclr/vm/amd64/pinvokestubs.S b/src/coreclr/vm/amd64/pinvokestubs.S index 49bc602afee105..ae1e1b166f5fed 100644 --- a/src/coreclr/vm/amd64/pinvokestubs.S +++ b/src/coreclr/vm/amd64/pinvokestubs.S @@ -6,67 +6,6 @@ #include "asmconstants.h" -// -// in: -// PINVOKE_CALLI_TARGET_REGISTER (r10) = unmanaged target -// PINVOKE_CALLI_SIGTOKEN_REGNUM (r11) = sig token -// -// out: -// METHODDESC_REGISTER (r10) = unmanaged target -// -LEAF_ENTRY GenericPInvokeCalliHelper, _TEXT - - // - // check for existing IL stub - // - mov rax, [PINVOKE_CALLI_SIGTOKEN_REGISTER + OFFSETOF__VASigCookie__pPInvokeILStub] - test rax, rax - jz C_FUNC(GenericPInvokeCalliGenILStub) - - // - // We need to distinguish between a MethodDesc* and an unmanaged target. - // The way we do this is to shift the managed target to the left by one bit and then set the - // least significant bit to 1. This works because MethodDesc* are always 8-byte aligned. - // - shl PINVOKE_CALLI_TARGET_REGISTER, 1 - or PINVOKE_CALLI_TARGET_REGISTER, 1 - - // - // jump to existing IL stub - // - jmp rax - -LEAF_END GenericPInvokeCalliHelper, _TEXT - -NESTED_ENTRY GenericPInvokeCalliGenILStub, _TEXT, NoHandler - - PROLOG_WITH_TRANSITION_BLOCK - - // - // save target - // - mov r12, METHODDESC_REGISTER - mov r13, PINVOKE_CALLI_SIGTOKEN_REGISTER - - // - // GenericPInvokeCalliStubWorker(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget) - // - lea rdi, [rsp + __PWTB_TransitionBlock] // pTransitionBlock* - mov rsi, PINVOKE_CALLI_SIGTOKEN_REGISTER // pVASigCookie - mov rdx, METHODDESC_REGISTER // pUnmanagedTarget - call C_FUNC(GenericPInvokeCalliStubWorker) - - // - // restore target - // - mov METHODDESC_REGISTER, r12 - mov PINVOKE_CALLI_SIGTOKEN_REGISTER, r13 - - EPILOG_WITH_TRANSITION_BLOCK_TAILCALL - jmp C_FUNC(GenericPInvokeCalliHelper) - -NESTED_END GenericPInvokeCalliGenILStub, _TEXT - LEAF_ENTRY VarargPInvokeStub, _TEXT mov PINVOKE_CALLI_SIGTOKEN_REGISTER, rdi jmp C_FUNC(VarargPInvokeStubHelper) diff --git a/src/coreclr/vm/arm/pinvokestubs.S b/src/coreclr/vm/arm/pinvokestubs.S index b102ae12d793e4..f0d22819a5fb9f 100644 --- a/src/coreclr/vm/arm/pinvokestubs.S +++ b/src/coreclr/vm/arm/pinvokestubs.S @@ -200,16 +200,6 @@ LOCAL_LABEL(RarePath): // PINVOKE_STUB VarargPInvokeStub, VarargPInvokeGenILStub, VarargPInvokeStubWorker, r0, 0 -// ------------------------------------------------------------------ -// GenericPInvokeCalliHelper & GenericPInvokeCalliGenILStub -// Helper for generic pinvoke calli instruction -// -// in: -// r4 = VASigCookie* -// r12 = Unmanaged target -// -PINVOKE_STUB GenericPInvokeCalliHelper, GenericPInvokeCalliGenILStub, GenericPInvokeCalliStubWorker r4, 1 - // ------------------------------------------------------------------ // VarargPInvokeStub_RetBuffArg & VarargPInvokeGenILStub_RetBuffArg // Vararg PInvoke Stub when the method has a hidden return buffer arg diff --git a/src/coreclr/vm/arm64/PInvokeStubs.asm b/src/coreclr/vm/arm64/PInvokeStubs.asm index 180dca18de7f69..dcbacd39d97722 100644 --- a/src/coreclr/vm/arm64/PInvokeStubs.asm +++ b/src/coreclr/vm/arm64/PInvokeStubs.asm @@ -9,7 +9,6 @@ IMPORT VarargPInvokeStubWorker - IMPORT GenericPInvokeCalliStubWorker IMPORT JIT_PInvokeEndRarePath IMPORT g_TrapReturningThreads @@ -21,7 +20,7 @@ ; ; Params :- ; $FuncPrefix : prefix of the function name for the stub -; Eg. VarargPinvoke, GenericPInvokeCalli +; Eg. VarargPinvoke ; $VASigCookieReg : register which contains the VASigCookie ; $SaveFPArgs : "Yes" or "No" . For varidic functions FP Args are not present in FP regs ; So need not save FP Args registers for vararg Pinvoke @@ -33,11 +32,7 @@ GBLS __PInvokeGenStubFuncName GBLS __PInvokeStubWorkerName - IF "$FuncPrefix" == "GenericPInvokeCalli" -__PInvokeStubFuncName SETS "$FuncPrefix":CC:"Helper" - ELSE __PInvokeStubFuncName SETS "$FuncPrefix":CC:"Stub" - ENDIF __PInvokeGenStubFuncName SETS "$FuncPrefix":CC:"GenILStub" __PInvokeStubWorkerName SETS "$FuncPrefix":CC:"StubWorker" @@ -49,16 +44,6 @@ __PInvokeStubWorkerName SETS "$FuncPrefix":CC:"StubWorker" ; if null goto stub generation cbz x9, %0 - IF "$FuncPrefix" == "GenericPInvokeCalli" - ; - ; We need to distinguish between a MethodDesc* and an unmanaged target. - ; The way we do this is to shift the managed target to the left by one bit and then set the - ; least significant bit to 1. This works because MethodDesc* are always 8-byte aligned. - ; - lsl $HiddenArg, $HiddenArg, #1 - orr $HiddenArg, $HiddenArg, #1 - ENDIF - EPILOG_BRANCH_REG x9 0 @@ -186,16 +171,5 @@ RarePath PINVOKE_STUB VarargPInvoke, x0, x12, {false} -; ------------------------------------------------------------------ -; GenericPInvokeCalliHelper & GenericPInvokeCalliGenILStub -; Helper for generic pinvoke calli instruction -; -; in: -; x15 = VASigCookie* -; x12 = Unmanaged target -; - PINVOKE_STUB GenericPInvokeCalli, x15, x12, {true} - - ; Must be at very end of file END diff --git a/src/coreclr/vm/arm64/pinvokestubs.S b/src/coreclr/vm/arm64/pinvokestubs.S index de2a23cf06cb31..a6dce447ef5219 100644 --- a/src/coreclr/vm/arm64/pinvokestubs.S +++ b/src/coreclr/vm/arm64/pinvokestubs.S @@ -11,11 +11,11 @@ // // Params :- // $FuncPrefix : prefix of the function name for the stub -// Eg. VarargPinvoke, GenericPInvokeCalli +// Eg. VarargPinvoke // $VASigCookieReg : register which contains the VASigCookie // $SaveFPArgs : "Yes" or "No" . For varidic functions FP Args are not present in FP regs // So need not save FP Args registers for vararg Pinvoke -.macro PINVOKE_STUB __PInvokeStubFuncName,__PInvokeGenStubFuncName,__PInvokeStubWorkerName,VASigCookieReg,HiddenArg,SaveFPArgs,ShiftLeftAndOrSecret=0 +.macro PINVOKE_STUB __PInvokeStubFuncName,__PInvokeGenStubFuncName,__PInvokeStubWorkerName,VASigCookieReg,HiddenArg,SaveFPArgs NESTED_ENTRY \__PInvokeStubFuncName, _TEXT, NoHandler @@ -26,16 +26,6 @@ // if null goto stub generation cbz x9, LOCAL_LABEL(\__PInvokeStubFuncName\()_0) - .if (\ShiftLeftAndOrSecret == 1) - // - // We need to distinguish between a MethodDesc* and an unmanaged target. - // The way we do this is to shift the managed target to the left by one bit and then set the - // least significant bit to 1. This works because MethodDesc* are always 8-byte aligned. - // - lsl \HiddenArg, \HiddenArg, #1 - orr \HiddenArg, \HiddenArg, #1 - .endif - EPILOG_BRANCH_REG x9 LOCAL_LABEL(\__PInvokeStubFuncName\()_0): @@ -167,14 +157,3 @@ LOCAL_LABEL(RarePath): // x12 = MethodDesc * // PINVOKE_STUB VarargPInvokeStub, VarargPInvokeGenILStub, VarargPInvokeStubWorker, x0, x12, 0 - - -// ------------------------------------------------------------------ -// GenericPInvokeCalliHelper & GenericPInvokeCalliGenILStub -// Helper for generic pinvoke calli instruction -// -// in: -// x15 = VASigCookie* -// x12 = Unmanaged target -// -PINVOKE_STUB GenericPInvokeCalliHelper, GenericPInvokeCalliGenILStub, GenericPInvokeCalliStubWorker, x15, x12, 1, 1 diff --git a/src/coreclr/vm/callconvbuilder.cpp b/src/coreclr/vm/callconvbuilder.cpp index a42b3b908a07f7..c3ad9a2800b61e 100644 --- a/src/coreclr/vm/callconvbuilder.cpp +++ b/src/coreclr/vm/callconvbuilder.cpp @@ -393,7 +393,6 @@ HRESULT CallConv::TryGetUnmanagedCallingConventionFromModOptSigStartingAtRetType LPCSTR typeName; if (*pWalk == ELEMENT_TYPE_CMOD_INTERNAL) { - // Skip internal modifiers pWalk++; if (pWalk + 1 + sizeof(void*) > pSig + cSig) { @@ -405,10 +404,14 @@ HRESULT CallConv::TryGetUnmanagedCallingConventionFromModOptSigStartingAtRetType void* pType; pWalk += CorSigUncompressPointer(pWalk, &pType); TypeHandle type = TypeHandle::FromPtr(pType); - - if (!required) + + // Calling conventions are only ever expressed as optional modifiers. A module + // independent signature encodes ELEMENT_TYPE_CMOD_OPT as an internal modifier with + // the "is required" byte cleared (see code:SigPointer::ConvertToInternalExactlyOne), + // so skip the required ones just like the token based case below does. + if (required) continue; - + tokenLookupModule = GetScopeHandle(type.GetModule()); tk = type.GetCl(); } @@ -430,7 +433,7 @@ HRESULT CallConv::TryGetUnmanagedCallingConventionFromModOptSigStartingAtRetType } // Check for CallConv types specified in modopt - if (FAILED(GetNameOfTypeRefOrDef(pModule, tk, &typeNamespace, &typeName))) + if (FAILED(GetNameOfTypeRefOrDef(tokenLookupModule, tk, &typeNamespace, &typeName))) continue; if (::strcmp(typeNamespace, CMOD_CALLCONV_NAMESPACE) != 0) diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index c8e7e987be3f7a..c1c6346c34acb1 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -4231,46 +4231,59 @@ static bool MethodSignatureContainsGenericVariables(SigParser& sp) } //========================================================================== -// Enregisters a VASig. +// Computes the module that should own runtime artifacts (VASigCookies, CALLI IL stubs) +// created for the given standalone signature. +// +// The generic context is stripped if it is not actually used by the signature. This is +// necessary for both: +// - Performance: allows more sharing of the created artifacts +// - Functionality: built-in runtime marshalling is disallowed for generic signatures //========================================================================== -VASigCookie *Module::GetVASigCookie(Signature vaSignature, const SigTypeContext* typeContext) +Module* Module::GetLoaderModuleForSignature(Signature signature, SigTypeContext* pTypeContext) { CONTRACTL { INSTANCE_CHECK; STANDARD_VM_CHECK; - INJECT_FAULT(COMPlusThrowOM()); + PRECONDITION(CheckPointer(pTypeContext)); } CONTRACTL_END; - SigTypeContext emptyContext; + SigParser sigParser = signature.CreateSigParser(); - Module* pLoaderModule = this; - if (!typeContext->IsEmpty()) - { - // Strip the generic context if it is not actually used by the signature. It is nececessary for both: - // - Performance: allow more sharing of vasig cookies - // - Functionality: built-in runtime marshalling is disallowed for generic signatures - SigParser sigParser = vaSignature.CreateSigParser(); - if (MethodSignatureContainsGenericVariables(sigParser)) - { - pLoaderModule = ClassLoader::ComputeLoaderModuleWorker(this, mdTokenNil, typeContext->m_classInst, typeContext->m_methodInst); - } - else - { - typeContext = &emptyContext; - } - } - else + if (pTypeContext->IsEmpty()) { -#ifdef _DEBUG // The method signature should not contain any generic variables if the generic context is not provided. - SigParser sigParser = vaSignature.CreateSigParser(); _ASSERTE(!MethodSignatureContainsGenericVariables(sigParser)); -#endif + return this; } - VASigCookie *pCookie = GetVASigCookieWorker(this, pLoaderModule, vaSignature, typeContext); + if (!MethodSignatureContainsGenericVariables(sigParser)) + { + *pTypeContext = SigTypeContext(); + return this; + } + + return ClassLoader::ComputeLoaderModuleWorker(this, mdTokenNil, pTypeContext->m_classInst, pTypeContext->m_methodInst); +} + +//========================================================================== +// Enregisters a VASig. +//========================================================================== +VASigCookie *Module::GetVASigCookie(Signature vaSignature, const SigTypeContext* typeContext) +{ + CONTRACTL + { + INSTANCE_CHECK; + STANDARD_VM_CHECK; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END; + + SigTypeContext localContext = *typeContext; + Module* pLoaderModule = GetLoaderModuleForSignature(vaSignature, &localContext); + + VASigCookie *pCookie = GetVASigCookieWorker(this, pLoaderModule, vaSignature, &localContext); return pCookie; } diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index 8f0d190464fa87..16a6d1afb66dd1 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -1418,6 +1418,10 @@ class Module : public ModuleBase // Enregisters a VASig. VASigCookie *GetVASigCookie(Signature vaSignature, const SigTypeContext* typeContext); + + // Computes the module that owns runtime artifacts created for a standalone signature. + // Clears *pTypeContext if the signature does not actually use the generic context. + Module* GetLoaderModuleForSignature(Signature signature, SigTypeContext* pTypeContext); private: static VASigCookie *GetVASigCookieWorker(Module* pDefiningModule, Module* pLoaderModule, Signature vaSignature, const SigTypeContext* typeContext); diff --git a/src/coreclr/vm/cgensys.h b/src/coreclr/vm/cgensys.h index 3f32aca5cdcecb..bdb5345d3832ba 100644 --- a/src/coreclr/vm/cgensys.h +++ b/src/coreclr/vm/cgensys.h @@ -51,8 +51,6 @@ extern "C" void STDCALL VarargPInvokeStubWorker(TransitionBlock* pTransitionBloc extern "C" void STDCALL VarargPInvokeStub(void); extern "C" void STDCALL VarargPInvokeStub_RetBuffArg(void); -extern "C" void STDCALL GenericPInvokeCalliStubWorker(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget); -extern "C" void STDCALL GenericPInvokeCalliHelper(void); extern "C" PCODE STDCALL ExternalMethodFixupWorker(TransitionBlock * pTransitionBlock, TADDR pIndirection, DWORD sectionIndex, Module * pModule); diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 84f6ff9bf88230..cabb495628270c 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1066,6 +1066,7 @@ DEFINE_METHOD(STUBHELPERS, SET_LAST_ERROR, SetLastError, DEFINE_METHOD(STUBHELPERS, CLEAR_LAST_ERROR, ClearLastError, SM_RetVoid) DEFINE_METHOD(STUBHELPERS, THROW_INTEROP_PARAM_EXCEPTION, ThrowInteropParamException, SM_Int_Int_RetVoid) +DEFINE_METHOD(STUBHELPERS, THROW_INTEROP_EXCEPTION, ThrowInteropException, SM_Int_Int_RetVoid) DEFINE_METHOD(STUBHELPERS, ADD_TO_CLEANUP_LIST_SAFEHANDLE, AddToCleanupList, SM_RefCleanupWorkListElement_SafeHandle_RetIntPtr) DEFINE_METHOD(STUBHELPERS, DESTROY_CLEANUP_LIST, DestroyCleanupList, SM_RefCleanupWorkListElement_RetVoid) DEFINE_METHOD(STUBHELPERS, GET_HR_EXCEPTION_OBJECT, GetHRExceptionObject, SM_Int_RetException) diff --git a/src/coreclr/vm/datadescriptor/datadescriptor.inc b/src/coreclr/vm/datadescriptor/datadescriptor.inc index 6242f9f49da888..c0acd22dee842f 100644 --- a/src/coreclr/vm/datadescriptor/datadescriptor.inc +++ b/src/coreclr/vm/datadescriptor/datadescriptor.inc @@ -1306,11 +1306,6 @@ CDAC_TYPE_SIZE(sizeof(ExternalMethodFrame)) CDAC_TYPE_FIELD(ExternalMethodFrame, T_POINTER, Indirection, cdac_data::Indirection) CDAC_TYPE_END(ExternalMethodFrame) -CDAC_TYPE_BEGIN(PInvokeCalliFrame) -CDAC_TYPE_SIZE(sizeof(PInvokeCalliFrame)) -CDAC_TYPE_FIELD(PInvokeCalliFrame, T_POINTER, VASigCookiePtr, cdac_data::VASigCookiePtr) -CDAC_TYPE_END(PInvokeCalliFrame) - CDAC_TYPE_BEGIN(DynamicHelperFrame) CDAC_TYPE_SIZE(sizeof(DynamicHelperFrame)) CDAC_TYPE_FIELD(DynamicHelperFrame, T_INT32, DynamicHelperFrameFlags, cdac_data::DynamicHelperFrameFlags) diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 1598b2b45e498e..589a72690c5b25 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -238,6 +238,15 @@ class ILStubState m_fSetLastError = fSetLastError; } + // Records a failure that must be reported when the stub is called instead of while it is being + // generated. Marshaling still runs, but FinishEmit discards its output and emits only the throw. + void SetInteropExceptionInfo(RuntimeExceptionKind kind, UINT resID) + { + LIMITED_METHOD_CONTRACT; + + m_slIL.SetInteropExceptionInfo(kind, resID); + } + // We use three stub linkers to generate IL stubs. The pre linker is the main one. It does all the marshaling and // then calls the target method. The post return linker is only used to unmarshal the return value after we return // from the target method. The post linker handles all the unmarshaling for by ref arguments and clean-up. It @@ -258,6 +267,12 @@ class ILStubState _ASSERTE(m_dwStubFlags == dwStubFlags); } + void SetCalliTargetArgIndex(UINT uArgIdx) + { + WRAPPER_NO_CONTRACT; + m_slIL.SetCalliTargetArgIndex(uArgIdx); + } + virtual void MarshalReturn(MarshalInfo* pInfo, int argOffset) { CONTRACTL @@ -756,7 +771,14 @@ class ILStubState CORJIT_FLAGS jitFlags(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB); - if (m_slIL.HasInteropParamExceptionInfo()) + if (m_slIL.HasInteropExceptionInfo()) + { + // This code will not use the secret parameter, so we do not + // tell the JIT to bother with it. + m_slIL.ClearCode(); + m_slIL.GenerateInteropException(pcsMarshal); + } + else if (m_slIL.HasInteropParamExceptionInfo()) { // This code will not use the secret parameter, so we do not // tell the JIT to bother with it. @@ -772,10 +794,10 @@ class ILStubState // Forward delegate stubs get all the context they need in 'this' so they // don't use the secret parameter. } - else if (SF_IsForwardPInvokeStub(m_dwStubFlags) - && !SF_IsCALLIStub(m_dwStubFlags) && !SF_IsVarArgStub(m_dwStubFlags)) + else if (SF_IsForwardPInvokeStub(m_dwStubFlags) && !SF_IsVarArgStub(m_dwStubFlags)) { - // Regular PInvokes don't use the secret parameter + // Regular PInvokes and unmanaged CALLI stubs don't use the secret parameter. + // Unmanaged CALLI stubs receive the native target as their last argument. } else { @@ -1864,7 +1886,10 @@ PInvokeStubLinker::PInvokeStubLinker( m_dwRetValLocalNum(-1), m_ErrorResID(-1), m_ErrorParamIdx(-1), + m_ExceptionKind(kLastException), + m_ExceptionResID(-1), m_iLCIDParamIdx(iLCIDParamIdx), + m_uCalliTargetArgIdx(0), m_dwStubFlags(dwStubFlags) { STANDARD_VM_CONTRACT; @@ -1916,6 +1941,13 @@ void PInvokeStubLinker::SetCallingConvention(CorInfoCallConvExtension unmngCallC } } +void PInvokeStubLinker::SetCalliTargetArgIndex(UINT uArgIdx) +{ + LIMITED_METHOD_CONTRACT; + _ASSERTE(SF_IsCALLIStub(m_dwStubFlags)); + m_uCalliTargetArgIdx = uArgIdx; +} + void PInvokeStubLinker::EmitSetArgMarshalIndex(ILCodeStream* pcsEmit, UINT uArgIdx) { WRAPPER_NO_CONTRACT; @@ -2058,6 +2090,39 @@ void PInvokeStubLinker::GenerateInteropParamException(ILCodeStream* pcsEmit) pcsEmit->EmitTHROW(); } +void PInvokeStubLinker::SetInteropExceptionInfo(RuntimeExceptionKind kind, UINT resID) +{ + LIMITED_METHOD_CONTRACT; + + // only keep the first one + if (HasInteropExceptionInfo()) + { + return; + } + + m_ExceptionKind = kind; + m_ExceptionResID = resID; +} + +bool PInvokeStubLinker::HasInteropExceptionInfo() +{ + LIMITED_METHOD_CONTRACT; + + return m_ExceptionResID != (UINT)-1; +} + +void PInvokeStubLinker::GenerateInteropException(ILCodeStream* pcsEmit) +{ + STANDARD_VM_CONTRACT; + + pcsEmit->EmitLDC(static_cast(m_ExceptionKind)); + pcsEmit->EmitLDC(m_ExceptionResID); + pcsEmit->EmitCALL(METHOD__STUBHELPERS__THROW_INTEROP_EXCEPTION, 2, 0); + + pcsEmit->EmitLDNULL(); + pcsEmit->EmitTHROW(); +} + #ifdef FEATURE_COMINTEROP DWORD PInvokeStubLinker::GetTargetInterfacePointerLocalNum() { @@ -2361,14 +2426,9 @@ void PInvokeStubLinker::DoPInvoke(ILCodeStream *pcsEmit, DWORD dwStubFlags, Meth #endif // FEATURE_COMINTEROP else if (SF_IsCALLIStub(dwStubFlags)) // unmanaged CALLI { - // for managed-to-unmanaged CALLI that requires marshaling, the target is passed - // as the secret argument to the stub by GenericPInvokeCalliHelper (asmhelpers.asm) - EmitLoadStubContext(pcsEmit, dwStubFlags); -#ifdef TARGET_64BIT - // the secret arg has been shifted to left and ORed with 1 (see code:GenericPInvokeCalliHelper) - pcsEmit->EmitLDC(1); - pcsEmit->EmitSHR_UN(); -#endif // TARGET_64BIT + // For managed-to-unmanaged CALLI that requires marshaling, the JIT passes the native + // target as the last argument of the stub (see code:CEEInfo::convertPInvokeCalliToCall). + pcsEmit->EmitLDARG(m_uCalliTargetArgIdx); } else if (SF_IsVarArgStub(dwStubFlags)) // vararg P/Invoke { @@ -2442,8 +2502,8 @@ void PInvokeStubLinker::EmitLogNativeArgument(ILCodeStream* pslILEmit, DWORD dwP if (SF_IsCALLIStub(m_dwStubFlags)) { - // get the secret argument via intrinsic - pslILEmit->EmitCALL(METHOD__STUBHELPERS__GET_STUB_CONTEXT, 0, 1); + // The native target is passed as the last argument of the stub. + pslILEmit->EmitLDARG(m_uCalliTargetArgIdx); } else { @@ -3582,6 +3642,7 @@ static MarshalInfo::MarshalType DoMarshalReturnValue(MetaSig& msig, CorNativeLinkType nlType, CorNativeLinkFlags nlFlags, UINT argidx, // this is used for reverse pinvoke hresult swapping + int numArgs, // number of marshaled arguments ILStubState* pss, int argOffset, DWORD dwStubFlags, @@ -3627,7 +3688,7 @@ static MarshalInfo::MarshalType DoMarshalReturnValue(MetaSig& msig, nlFlags, FALSE, argidx, - msig.NumFixedArgs(), + numArgs, SF_IsBestFit(dwStubFlags), SF_IsThrowOnUnmappableChar(dwStubFlags), TRUE, @@ -3816,6 +3877,16 @@ static COR_ILMETHOD_DECODER* CreatePInvokeStubWorker( int numArgs = msig.NumFixedArgs(); + if (SF_IsCALLIStub(dwStubFlags)) + { + // The last argument of an unmanaged CALLI stub is the native target, which the JIT + // supplies from the top of the evaluation stack at the original calli site. It is not + // part of the native signature, so exclude it from marshaling. + _ASSERTE(numArgs > 0); + numArgs--; + pss->SetCalliTargetArgIndex((UINT)numArgs); + } + // thiscall must have at least one parameter (the "this") if (fThisCall && numArgs == 0) COMPlusThrow(kMarshalDirectiveException, IDS_EE_NDIRECT_BADNATL_THISCALL); @@ -3944,6 +4015,7 @@ static COR_ILMETHOD_DECODER* CreatePInvokeStubWorker( nlType, nlFlags, argidx, + numArgs, pss, argOffset, dwStubFlags, @@ -4549,7 +4621,12 @@ static void CreatePInvokeStubAccessMetadata( unmgdCallConv == CorInfoCallConvExtension::Fastcall || unmgdCallConv == CorInfoCallConvExtension::FastcallMemberFunction) { - COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV); + // For an unmanaged CALLI stub the caller has already recorded this so that it is + // reported when the stub is called - see code:TryGetCalliStubCallConv. + if (!SF_IsCALLIStub(*pdwStubFlags)) + { + COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV); + } } } @@ -5392,7 +5469,9 @@ namespace if (SF_IsCALLIStub(dwStubFlags) && PInvoke::MarshalingRequired(NULL, pStubMD->GetSigPointer(), pSigDesc->m_pModule, &pSigDesc->m_typeContext)) { - COMPlusThrow(kMarshalDirectiveException, IDS_EE_BADMARSHAL_GENERICS_RESTRICTION); + // The stub is created while the calli's caller is jitted, so report + // this when the stub is called instead of failing that compilation. + pss->SetInteropExceptionInfo(kMarshalDirectiveException, IDS_EE_BADMARSHAL_GENERICS_RESTRICTION); } // We don't want to support generic varargs, so block it else if (SF_IsVarArgStub(dwStubFlags)) @@ -5484,6 +5563,7 @@ namespace return pStubMD; } + } MethodDesc* PInvoke::CreateCLRToNativeILStub( @@ -6037,10 +6117,10 @@ EXTERN_C void* PInvokeImportWorker(PInvokeMethodDesc* pMD) } //=========================================================================== -// Support for Pinvoke Calli instruction +// Support for vararg Pinvoke and the Pinvoke Calli instruction // //=========================================================================== -static void GetILStubForCalli(VASigCookie* pVASigCookie, MethodDesc* pMD) +static void GetILStubForVarargPInvoke(VASigCookie* pVASigCookie, MethodDesc* pMD) { CONTRACTL { @@ -6049,7 +6129,8 @@ static void GetILStubForCalli(VASigCookie* pVASigCookie, MethodDesc* pMD) ENTRY_POINT; MODE_ANY; PRECONDITION(CheckPointer(pVASigCookie)); - PRECONDITION(CheckPointer(pMD, NULL_OK)); + PRECONDITION(CheckPointer(pMD)); + PRECONDITION(pMD->IsPInvoke()); } CONTRACTL_END; @@ -6067,126 +6148,314 @@ static void GetILStubForCalli(VASigCookie* pVASigCookie, MethodDesc* pMD) GCX_PREEMP(); - Signature signature = pVASigCookie->signature; - CorInfoCallConvExtension unmgdCallConv = CorInfoCallConvExtension::Managed; + _ASSERTE(!pMD->IsAsyncMethod()); + + DWORD dwStubFlags = PINVOKESTUB_FL_BESTFIT | PINVOKESTUB_FL_CONVSIGASVARARG; - DWORD dwStubFlags = PINVOKESTUB_FL_BESTFIT; + // vararg P/Invoke must be cdecl + CorInfoCallConvExtension unmgdCallConv = CorInfoCallConvExtension::C; - if (pMD == NULL) + PInvokeStaticSigInfo sigInfo(pMD); + CorNativeLinkFlags nlFlags = sigInfo.GetLinkFlags(); + CorNativeLinkType nlType = sigInfo.GetCharSet(); + + StubSigDesc sigDesc(pMD, pVASigCookie->signature, pVASigCookie->pModule, pVASigCookie->pLoaderModule); + sigDesc.InitTypeContext(pVASigCookie->classInst, pVASigCookie->methodInst); + + MethodDesc* pStubMD = PInvoke::CreateCLRToNativeILStub(&sigDesc, + nlType, + nlFlags, + unmgdCallConv, + dwStubFlags); + + pTempILStub = JitILStub(pStubMD); + + InterlockedCompareExchangeT(&pVASigCookie->pPInvokeILStub, + pTempILStub, + (PCODE)NULL); + + UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; + UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; + UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME; +} + +// Build the managed signature of the IL stub that implements an unmanaged CALLI call site. +// +// The stub signature is the call site signature with a managed (default) calling convention +// and an extra trailing native int parameter that carries the unmanaged target. The target is +// the value at the top of the evaluation stack at the calli site, so appending it as the last +// parameter lets the JIT rewrite the calli into a direct call to the stub. +// +// The calling convention of the call site is not part of this signature. It does not need to be: +// the IL stub cache keys on it separately through PInvokeStubHashBlob::m_unmgdCallConv and +// PInvokeStubHashBlob::m_StubFlags, so call sites that differ only in calling convention or in +// SuppressGCTransition still get distinct stubs. +// +// A call site with an instance 'this' cannot be described by any unmanaged calling convention and +// is rejected, but the rejection is reported when the stub is called. That requires a stub the JIT +// can call, so the 'this' becomes an explicit leading native int parameter and the stub pops the +// call site correctly. +static void BuildCalliILStubSignature( + const Signature& calliSignature, + SigBuilder* pSigBuilder) +{ + STANDARD_VM_CONTRACT; + + SigParser sigParser = calliSignature.CreateSigParser(); + + uint32_t callConv; + IfFailThrow(sigParser.GetCallingConvInfo(&callConv)); + + // Only signatures that describe a standalone method signature get here. + _ASSERTE((callConv & IMAGE_CEE_CS_CALLCONV_GENERIC) == 0); + + bool hasImplicitThis = (callConv & IMAGE_CEE_CS_CALLCONV_HASTHIS) != 0 && + (callConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS) == 0; + + uint32_t numArgs; + IfFailThrow(sigParser.GetData(&numArgs)); + + pSigBuilder->AppendByte(IMAGE_CEE_CS_CALLCONV_DEFAULT); + pSigBuilder->AppendData(numArgs + (hasImplicitThis ? 2 : 1)); + + // The return type, copied verbatim. + PCCOR_SIGNATURE pRetTypeStart = sigParser.GetPtr(); + IfFailThrow(sigParser.SkipExactlyOne()); + PCCOR_SIGNATURE pRetTypeEnd = sigParser.GetPtr(); + pSigBuilder->AppendBlob((PVOID)pRetTypeStart, (DWORD)(pRetTypeEnd - pRetTypeStart)); + + // The instance pointer, if the call site has an implicit 'this', ahead of the declared parameters. + // For EXPLICITTHIS signatures the this parameter is already part of numArgs, so no extra parameter + // is added. + if (hasImplicitThis) { - dwStubFlags |= PINVOKESTUB_FL_UNMANAGED_CALLI; + pSigBuilder->AppendElementType(ELEMENT_TYPE_I); + } - // need to convert the CALLI signature to stub signature with managed calling convention - BYTE callConv = MetaSig::GetCallingConvention(signature); + // The declared parameters, copied verbatim. + PCCOR_SIGNATURE pArgsStart = sigParser.GetPtr(); + for (uint32_t i = 0; i < numArgs; i++) + { + IfFailThrow(sigParser.SkipExactlyOne()); + } + PCCOR_SIGNATURE pArgsEnd = sigParser.GetPtr(); + pSigBuilder->AppendBlob((PVOID)pArgsStart, (DWORD)(pArgsEnd - pArgsStart)); + + // The unmanaged target is the last parameter. + pSigBuilder->AppendElementType(ELEMENT_TYPE_I); +} - // Unmanaged calling convention indicates modopt should be read - if (callConv != IMAGE_CEE_CS_CALLCONV_UNMANAGED) +// A failure detected while classifying an unmanaged CALLI call site. It is reported when the stub +// is called rather than while the caller is being jitted, so it is carried alongside a usable +// calling convention that lets stub creation run to completion. +struct CalliStubDeferredError +{ + RuntimeExceptionKind Kind = kLastException; + UINT ResID = 0; + + bool IsSet() const { LIMITED_METHOD_CONTRACT; return Kind != kLastException; } + + void Set(RuntimeExceptionKind kind, UINT resID) + { + LIMITED_METHOD_CONTRACT; + // Only keep the first one. + if (!IsSet()) { - unmgdCallConv = (CorInfoCallConvExtension)callConv; + Kind = kind; + ResID = resID; } - else + } +}; + +// Determines the unmanaged calling convention of an unmanaged CALLI call site and the +// corresponding stub flags. Returns false if the signature does not describe a P/Invoke. +// +// A signature that describes a P/Invoke the runtime cannot express records the failure in +// *pError and still returns a usable calling convention, so that a stub can be created to report +// it when it is called. Only a signature that is not a standalone method signature at all - one +// the stub signature cannot even be built from - throws. +static bool TryGetCalliStubCallConv( + Module* pModule, + const Signature& calliSignature, + CorInfoCallConvExtension* pUnmgdCallConv, + DWORD* pdwStubFlags, + CalliStubDeferredError* pError) +{ + STANDARD_VM_CONTRACT; + + SigParser sigParser = calliSignature.CreateSigParser(); + uint32_t rawCallConv; + IfFailThrow(sigParser.GetCallingConvInfo(&rawCallConv)); + + switch (rawCallConv & IMAGE_CEE_CS_CALLCONV_MASK) + { + case IMAGE_CEE_CS_CALLCONV_C: + case IMAGE_CEE_CS_CALLCONV_STDCALL: + case IMAGE_CEE_CS_CALLCONV_THISCALL: + case IMAGE_CEE_CS_CALLCONV_FASTCALL: + *pUnmgdCallConv = (CorInfoCallConvExtension)(rawCallConv & IMAGE_CEE_CS_CALLCONV_MASK); + break; + + case IMAGE_CEE_CS_CALLCONV_UNMANAGED: { + // The unmanaged calling convention is encoded in modopts. CallConvBuilder builder; UINT errorResID; - HRESULT hr = CallConv::TryGetUnmanagedCallingConventionFromModOpt(GetScopeHandle(pVASigCookie->pModule), signature.GetRawSig(), signature.GetRawSigLen(), &builder, &errorResID); - if (FAILED(hr)) - COMPlusThrowHR(hr, errorResID); + HRESULT hr = CallConv::TryGetUnmanagedCallingConventionFromModOpt(GetScopeHandle(pModule), calliSignature.GetRawSig(), calliSignature.GetRawSigLen(), &builder, &errorResID); - unmgdCallConv = builder.GetCurrentCallConv(); - if (unmgdCallConv == CallConvBuilder::UnsetValue) + CorInfoCallConvExtension unmgdCallConv; + if (FAILED(hr)) { + // Report the failure the same way COMPlusThrowHR(hr, errorResID) would have: + // the exception kind comes from the HRESULT, not from the parser's failure mode. + pError->Set(EEException::GetKindFromHR(hr), errorResID); unmgdCallConv = CallConv::GetDefaultUnmanagedCallingConvention(); } - - if (builder.IsCurrentCallConvModSet(CallConvBuilder::CALL_CONV_MOD_SUPPRESSGCTRANSITION)) + else { - dwStubFlags |= PINVOKESTUB_FL_SUPPRESSGCTRANSITION; + unmgdCallConv = builder.GetCurrentCallConv(); + if (unmgdCallConv == CallConvBuilder::UnsetValue) + { + unmgdCallConv = CallConv::GetDefaultUnmanagedCallingConvention(); + } + + if (builder.IsCurrentCallConvModSet(CallConvBuilder::CALL_CONV_MOD_SUPPRESSGCTRANSITION)) + { + *pdwStubFlags |= PINVOKESTUB_FL_SUPPRESSGCTRANSITION; + } } + + *pUnmgdCallConv = unmgdCallConv; + break; } - LoaderHeap *pHeap = pVASigCookie->pLoaderModule->GetLoaderAllocator()->GetHighFrequencyHeap(); - PCOR_SIGNATURE new_sig = (PCOR_SIGNATURE)(void *)pHeap->AllocMem(S_SIZE_T(signature.GetRawSigLen())); - CopyMemory(new_sig, signature.GetRawSig(), signature.GetRawSigLen()); + case IMAGE_CEE_CS_CALLCONV_DEFAULT: + case IMAGE_CEE_CS_CALLCONV_VARARG: + case IMAGE_CEE_CS_CALLCONV_NATIVEVARARG: + case IMAGE_CEE_CS_CALLCONV_ASYNC: + // Managed call sites - including the runtime-internal native-vararg and async + // conventions used by IL stubs - are not P/Invokes. + return false; - // make the stub IMAGE_CEE_CS_CALLCONV_DEFAULT - *new_sig &= ~IMAGE_CEE_CS_CALLCONV_MASK; - *new_sig |= IMAGE_CEE_CS_CALLCONV_DEFAULT; + default: + // Not a method signature at all, so no stub signature can be built from it. + COMPlusThrowHR(COR_E_BADIMAGEFORMAT); + } - signature = Signature(new_sig, signature.GetRawSigLen()); + if ((rawCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC) != 0) + { + // An unmanaged standalone signature is never generic, and its argument count is not where + // the stub signature builder expects it, so no stub can be built from it either. + COMPlusThrowHR(COR_E_BADIMAGEFORMAT); } - else + + // An unmanaged call site carrying an instance 'this' is not expressible as a stub, and the JIT + // cannot emit it inline either. Reject it the same way a P/Invoke declared on an instance method + // is rejected - see code:CreatePInvokeStubAccessMetadata. Note that a native member function is + // expressed as a static signature whose first parameter is the 'this' pointer, so this only + // rejects signatures that no calling convention can describe. + if ((rawCallConv & (IMAGE_CEE_CS_CALLCONV_HASTHIS | IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)) != 0) { - _ASSERTE(pMD->IsPInvoke()); - dwStubFlags |= PINVOKESTUB_FL_CONVSIGASVARARG; + pError->Set(kInvalidProgramException, VLDTR_E_FMD_PINVOKENOTSTATIC); + } - // vararg P/Invoke must be cdecl - unmgdCallConv = CorInfoCallConvExtension::C; + // The JIT refuses to emit these inline, and stub creation cannot express them either. + if (*pUnmgdCallConv == CorInfoCallConvExtension::Managed || + *pUnmgdCallConv == CorInfoCallConvExtension::Fastcall || + *pUnmgdCallConv == CorInfoCallConvExtension::FastcallMemberFunction) + { + pError->Set(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV); } - mdMethodDef md = mdMethodDefNil; - CorNativeLinkFlags nlFlags = nlfNone; - CorNativeLinkType nlType = nltAnsi; + return true; +} - if (pMD != NULL) +MethodDesc* PInvoke::CreateCalliILStub( + Module* pModule, + const Signature& calliSignature, + const SigTypeContext* pTypeContext, + bool fMustCreate) +{ + CONTRACTL { - _ASSERTE(pMD->IsPInvoke()); - _ASSERTE(!pMD->IsAsyncMethod()); - PInvokeStaticSigInfo sigInfo(pMD); - - md = pMD->GetMemberDef(); - nlFlags = sigInfo.GetLinkFlags(); - nlType = sigInfo.GetCharSet(); + STANDARD_VM_CHECK; + PRECONDITION(CheckPointer(pModule)); + PRECONDITION(CheckPointer(pTypeContext)); } + CONTRACTL_END; - StubSigDesc sigDesc(pMD, signature, pVASigCookie->pModule, pVASigCookie->pLoaderModule); - sigDesc.InitTypeContext(pVASigCookie->classInst, pVASigCookie->methodInst); + DWORD dwStubFlags = PINVOKESTUB_FL_BESTFIT | PINVOKESTUB_FL_UNMANAGED_CALLI; + CorInfoCallConvExtension unmgdCallConv; + CalliStubDeferredError deferredError; + if (!TryGetCalliStubCallConv(pModule, calliSignature, &unmgdCallConv, &dwStubFlags, &deferredError)) + return NULL; - MethodDesc* pStubMD = PInvoke::CreateCLRToNativeILStub(&sigDesc, - nlType, - nlFlags, - unmgdCallConv, - dwStubFlags); + // The generic context is stripped if the signature does not actually use it. That is + // required for correctness: built-in runtime marshalling is disallowed for generic + // signatures, and it also lets the stub be shared across instantiations. + SigTypeContext typeContext = *pTypeContext; + Module* pLoaderModule = pModule->GetLoaderModuleForSignature(calliSignature, &typeContext); - pTempILStub = JitILStub(pStubMD); + // If no marshaling is needed and nothing is wrong with the call site, let the caller emit the + // unmanaged call inline unless it explicitly asked for a stub. + if (!fMustCreate + && !deferredError.IsSet() + && !PInvoke::MarshalingRequired(NULL, calliSignature.CreateSigPointer(), pModule, &typeContext)) + { + return NULL; + } - InterlockedCompareExchangeT(&pVASigCookie->pPInvokeILStub, - pTempILStub, - (PCODE)NULL); + SigBuilder sigBuilder; + BuildCalliILStubSignature(calliSignature, &sigBuilder); - UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; - UNINSTALL_MANAGED_EXCEPTION_DISPATCHER; - UNINSTALL_RESUME_AFTER_CATCH_HANDLER_WITH_FRAME; -} + DWORD cbStubSig; + PCCOR_SIGNATURE pStubSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cbStubSig); -EXTERN_C void STDCALL VarargPInvokeStubWorker(TransitionBlock* pTransitionBlock, VASigCookie *pVASigCookie, MethodDesc *pMD) -{ - PreserveLastErrorHolder preserveLastError; + // The stub MethodDesc references this buffer for as long as it lives, so it has to be owned + // by the loader allocator the stub lives in. It is backed out below if the stub did not keep it. + AllocMemHolder pStubSigCopy(pLoaderModule->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(cbStubSig))); + memcpy(pStubSigCopy, pStubSig, cbStubSig); - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_COOPERATIVE; - STATIC_CONTRACT_ENTRY_POINT; + StubSigDesc sigDesc(NULL, Signature((PCCOR_SIGNATURE)(BYTE*)pStubSigCopy, cbStubSig), pModule, pLoaderModule); + sigDesc.InitTypeContext(typeContext.m_classInst, typeContext.m_methodInst); - MAKE_CURRENT_THREAD_AVAILABLE(); + int iLCIDArg = 0; + int numArgs = 0; + CreatePInvokeStubAccessMetadata(&sigDesc, unmgdCallConv, &dwStubFlags, &iLCIDArg, &numArgs); -#ifdef _DEBUG - Thread::ObjectRefFlush(CURRENT_THREAD); -#endif + int numParamTokens = numArgs + 1; + mdParamDef* pParamTokenArray = (mdParamDef*)_alloca(numParamTokens * sizeof(mdParamDef)); + CollateParamTokens(pModule->GetMDImport(), sigDesc.m_tkMethodDef, numArgs, pParamTokenArray); - PrestubMethodFrame frame(pTransitionBlock, pMD); - PrestubMethodFrame * pFrame = &frame; + PInvoke_ILStubState stubState(pModule, sigDesc.m_sig, &sigDesc.m_typeContext, dwStubFlags, unmgdCallConv, iLCIDArg, NULL); - pFrame->Push(CURRENT_THREAD); + if (deferredError.IsSet()) + { + // The call site cannot be marshaled. Generate a stub whose body throws so that the failure + // is reported when the call site executes rather than while its caller is jitted. + stubState.SetInteropExceptionInfo(deferredError.Kind, deferredError.ResID); + } - _ASSERTE(pVASigCookie == pFrame->GetVASigCookie()); - _ASSERTE(pMD == pFrame->GetFunction()); + MethodDesc* pStubMD = CreateInteropILStub( + &stubState, + &sigDesc, + nltAnsi, + nlfNone, + unmgdCallConv, + numParamTokens, + pParamTokenArray, + iLCIDArg); - GetILStubForCalli(pVASigCookie, pMD); + PCCOR_SIGNATURE pFinalSig; + DWORD cbFinalSig; + pStubMD->GetSig(&pFinalSig, &cbFinalSig); + if (pFinalSig == (PCCOR_SIGNATURE)(BYTE*)pStubSigCopy) + pStubSigCopy.SuppressRelease(); - pFrame->Pop(CURRENT_THREAD); + return pStubMD; } -EXTERN_C void STDCALL GenericPInvokeCalliStubWorker(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget) +EXTERN_C void STDCALL VarargPInvokeStubWorker(TransitionBlock* pTransitionBlock, VASigCookie *pVASigCookie, MethodDesc *pMD) { PreserveLastErrorHolder preserveLastError; @@ -6201,14 +6470,15 @@ EXTERN_C void STDCALL GenericPInvokeCalliStubWorker(TransitionBlock * pTransitio Thread::ObjectRefFlush(CURRENT_THREAD); #endif - PInvokeCalliFrame frame(pTransitionBlock, pVASigCookie, pUnmanagedTarget); - PInvokeCalliFrame * pFrame = &frame; + PrestubMethodFrame frame(pTransitionBlock, pMD); + PrestubMethodFrame * pFrame = &frame; pFrame->Push(CURRENT_THREAD); _ASSERTE(pVASigCookie == pFrame->GetVASigCookie()); + _ASSERTE(pMD == pFrame->GetFunction()); - GetILStubForCalli(pVASigCookie, NULL); + GetILStubForVarargPInvoke(pVASigCookie, pMD); pFrame->Pop(CURRENT_THREAD); } diff --git a/src/coreclr/vm/dllimport.h b/src/coreclr/vm/dllimport.h index 7e1fc77d5513e7..3c5b42b2ce92dd 100644 --- a/src/coreclr/vm/dllimport.h +++ b/src/coreclr/vm/dllimport.h @@ -127,6 +127,16 @@ class PInvoke CorInfoCallConvExtension unmgdCallConv, DWORD dwStubFlags); // PInvokeStubFlags + // Creates the IL stub that marshals an unmanaged calli call site described by + // calliSignature. Returns NULL if the call site does not describe an unmanaged call, or if + // no marshaling is required and fMustCreate is false (in which case the caller - the JIT - + // can emit the unmanaged call inline instead). + static MethodDesc* CreateCalliILStub( + Module* pModule, + const Signature& calliSignature, + const SigTypeContext* pTypeContext, + bool fMustCreate); + static COR_ILMETHOD_DECODER* CreatePInvokeMethodIL( PInvokeMethodDesc* pMD, DynamicResolver** ppResolver); @@ -461,6 +471,9 @@ class PInvokeStubLinker : public ILStubLinker void SetCallingConvention(CorInfoCallConvExtension unmngCallConv, BOOL fIsVarArg); + // For unmanaged CALLI stubs, the native target is passed in as the last argument of the stub. + void SetCalliTargetArgIndex(UINT uArgIdx); + void Begin(DWORD dwStubFlags); void End(DWORD dwStubFlags); void DoPInvoke(ILCodeStream *pcsEmit, DWORD dwStubFlags, MethodDesc * pStubMD); @@ -491,6 +504,19 @@ class PInvokeStubLinker : public ILStubLinker void SetInteropParamExceptionInfo(UINT resID, UINT paramIdx); bool HasInteropParamExceptionInfo(); + + // Records an interop failure that is not tied to a single parameter and that must be reported + // when the stub is called rather than while it is being generated. The stub body becomes a + // single throw - see code:PInvokeStubLinker::GenerateInteropException. + void SetInteropExceptionInfo(RuntimeExceptionKind kind, UINT resID); + bool HasInteropExceptionInfo(); + void GenerateInteropException(ILCodeStream* pcsEmit); + + DWORD GetStubFlags() const + { + LIMITED_METHOD_CONTRACT; + return m_dwStubFlags; + } bool TargetHasThis() { return m_targetHasThis == TRUE; @@ -557,7 +583,10 @@ class PInvokeStubLinker : public ILStubLinker UINT m_ErrorResID; UINT m_ErrorParamIdx; + RuntimeExceptionKind m_ExceptionKind; + UINT m_ExceptionResID; int m_iLCIDParamIdx; + UINT m_uCalliTargetArgIdx; DWORD m_dwStubFlags; }; diff --git a/src/coreclr/vm/frames.cpp b/src/coreclr/vm/frames.cpp index 202864af98c65b..09e03980527329 100644 --- a/src/coreclr/vm/frames.cpp +++ b/src/coreclr/vm/frames.cpp @@ -328,16 +328,9 @@ void Frame::Log() { STRESS_LOG3(LF_STUBS, LL_INFO1000000, "STUBS: In Stub with Frame %p assoc Method %pM FrameType = %pV\n", this, method, *((void**) this)); - char buff[64]; const char* frameType; if (GetFrameIdentifier() == FrameIdentifier::PrestubMethodFrame) frameType = "PreStub"; - else if (GetFrameIdentifier() == FrameIdentifier::PInvokeCalliFrame) - { - sprintf_s(buff, ARRAY_SIZE(buff), "PInvoke CALLI target" FMT_ADDR, - DBG_ADDR(((PInvokeCalliFrame*)this)->GetPInvokeCalliTarget())); - frameType = buff; - } else if (GetFrameIdentifier() == FrameIdentifier::StubDispatchFrame) frameType = "StubDispatch"; else if (GetFrameIdentifier() == FrameIdentifier::ExternalMethodFrame) @@ -1706,37 +1699,6 @@ void TransitionFrame::PromoteCallerStackUsingGCRefMap(promote_func* fn, ScanCont } } -void PInvokeCalliFrame::PromoteCallerStack(promote_func* fn, ScanContext* sc) -{ - WRAPPER_NO_CONTRACT; - - LOG((LF_GC, INFO3, " Promoting CALLI caller Arguments\n" )); - - // get the signature - VASigCookie *varArgSig = GetVASigCookie(); - if (varArgSig->signature.IsEmpty()) - { - return; - } - - SigTypeContext typeContext(varArgSig->classInst, varArgSig->methodInst); - MetaSig msig(varArgSig->signature, - varArgSig->pModule, - &typeContext); - PromoteCallerStackHelper(fn, sc, NULL, &msig); -} - -#ifndef DACCESS_COMPILE -PInvokeCalliFrame::PInvokeCalliFrame(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget) - : FramedMethodFrame(FrameIdentifier::PInvokeCalliFrame, pTransitionBlock, NULL) -{ - LIMITED_METHOD_CONTRACT; - - m_pVASigCookie = pVASigCookie; - m_pUnmanagedTarget = pUnmanagedTarget; -} -#endif // #ifndef DACCESS_COMPILE - #if defined (_DEBUG) && !defined (DACCESS_COMPILE) // For IsProtectedByGCFrame, we need to know whether a given object ref is protected // by a TransitionFrame. Since GCScanRoots for those frames are diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index 856a9270d0fffd..7dfd2fd1ac6dee 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -64,9 +64,6 @@ // | | that generates a full-fledged frame. // | | // | | -// | +-PInvokeCalliFrame - protects arguments when a call to GetILStubForCalli is made -// | | to get or create IL stub for an unmanaged CALLI -// | | // | +-PrestubMethodFrame - represents a call to a prestub // | | // | +-StubDispatchFrame - represents a call into the virtual call stub manager @@ -114,10 +111,9 @@ Delegate over a native function pointer: goes through an IL stub). Calli: - The same as P/Invoke. - PInvokeCalliFrame is erected in stub generated by GenerateGetStubForPInvokeCalli - before calling to GetILStubForCalli which generates the IL stub. This happens only - the first time a call via the corresponding VASigCookie is made. + The same as P/Invoke. The IL stub is created when the caller is JIT-compiled + (see code:CEEInfo::convertPInvokeCalliToCall) and receives the unmanaged target + as its last argument. ClrToCom: Eventing: The stub does not erect any frames explicitly and calls back into managed code. @@ -1303,76 +1299,6 @@ struct cdac_data static constexpr size_t MethodDescPtr = offsetof(FramedMethodFrame, m_pMD); }; -//------------------------------------------------------------------------ -// This represents a call from a helper to GetILStubForCalli -//------------------------------------------------------------------------ - -typedef DPTR(class PInvokeCalliFrame) PTR_PInvokeCalliFrame; - -class PInvokeCalliFrame : public FramedMethodFrame -{ - PTR_VASigCookie m_pVASigCookie; - PCODE m_pUnmanagedTarget; - -public: - PInvokeCalliFrame(TransitionBlock * pTransitionBlock, VASigCookie * pVASigCookie, PCODE pUnmanagedTarget); - - void GcScanRoots_Impl(promote_func *fn, ScanContext* sc) - { - WRAPPER_NO_CONTRACT; - FramedMethodFrame::GcScanRoots_Impl(fn, sc); - PromoteCallerStack(fn, sc); - } - - void PromoteCallerStack(promote_func* fn, ScanContext* sc); - - // not a method - MethodDesc *GetFunction_Impl() - { - LIMITED_METHOD_DAC_CONTRACT; - return NULL; - } - - int GetFrameType_Impl() - { - LIMITED_METHOD_DAC_CONTRACT; - return TYPE_INTERCEPTION; - } - - PCODE GetPInvokeCalliTarget() - { - LIMITED_METHOD_CONTRACT; - return m_pUnmanagedTarget; - } - - PTR_VASigCookie GetVASigCookie() - { - LIMITED_METHOD_CONTRACT; - return m_pVASigCookie; - } - -#ifdef TARGET_X86 - void UpdateRegDisplay_Impl(const PREGDISPLAY, bool updateFloats = false); -#endif // TARGET_X86 - - BOOL TraceFrame_Impl(Thread *thread, BOOL fromPatch, - TraceDestination *trace, REGDISPLAY *regs) - { - WRAPPER_NO_CONTRACT; - - trace->InitForUnmanaged(GetPInvokeCalliTarget()); - return TRUE; - } - - friend struct ::cdac_data; -}; - -template <> -struct cdac_data -{ - static constexpr size_t VASigCookiePtr = offsetof(PInvokeCalliFrame, m_pVASigCookie); -}; - // Some context-related forwards. #ifdef FEATURE_HIJACK //------------------------------------------------------------------------ @@ -2101,7 +2027,8 @@ class InlinedCallFrame : public Frame WRAPPER_NO_CONTRACT; #ifdef HOST_64BIT - // See code:GenericPInvokeCalliHelper + // m_Datum is a MethodDesc* when it is set. It is NULL for indirect calls that do not + // have a stub secret argument. return ((m_Datum != NULL) && !(dac_cast(m_Datum) & 0x1)); #else // HOST_64BIT return ((dac_cast(m_Datum) & ~0xffff) != 0); diff --git a/src/coreclr/vm/i386/asmhelpers.S b/src/coreclr/vm/i386/asmhelpers.S index 29b76b1f220ffb..b2284ad1c7cdf2 100644 --- a/src/coreclr/vm/i386/asmhelpers.S +++ b/src/coreclr/vm/i386/asmhelpers.S @@ -399,53 +399,6 @@ LOCAL_LABEL(GoCallVarargWorker): jmp C_FUNC(VarargPInvokeStub) NESTED_END VarargPInvokeStub, _TEXT -// ========================================================================== -// Invoked for marshaling-required unmanaged CALLI calls as a stub. -// EAX - the unmanaged target -// ECX, EDX - arguments -// EBX - the VASigCookie -// -LEAF_ENTRY GenericPInvokeCalliHelper, _TEXT - - cmp dword ptr [ebx + VASigCookie__StubOffset], 0 - jz LOCAL_LABEL(GoCallCalliWorker) - - // Stub is already prepared, just jump to it - jmp dword ptr [ebx + VASigCookie__StubOffset] - -LOCAL_LABEL(GoCallCalliWorker): - // - // call the stub generating worker - // target ptr in EAX, VASigCookie ptr in EBX - // - - STUB_PROLOG - - mov esi, esp - - // save target - push eax - - #define STACK_ALIGN_PADDING 4 - sub esp, STACK_ALIGN_PADDING // pass stack aligned to 0x10 - push eax // unmanaged target - push ebx // pVaSigCookie (first stack argument) - push esi // pTransitionBlock - - CHECK_STACK_ALIGNMENT - call C_FUNC(GenericPInvokeCalliStubWorker) - add esp, STACK_ALIGN_PADDING // restore alignment, callee pop args - #undef STACK_ALIGN_PADDING - - // restore target - pop eax - - STUB_EPILOG - - // jump back to the helper - this time it won't come back here as the stub already exists - jmp C_FUNC(GenericPInvokeCalliHelper) -LEAF_END GenericPInvokeCalliHelper, _TEXT - #ifdef FEATURE_READYTORUN NESTED_ENTRY DynamicHelperArgsStub, _TEXT, NoHandler .cfi_def_cfa_offset 16 diff --git a/src/coreclr/vm/i386/asmhelpers.asm b/src/coreclr/vm/i386/asmhelpers.asm index f160c43c27b485..3dd14e72f7dfe2 100644 --- a/src/coreclr/vm/i386/asmhelpers.asm +++ b/src/coreclr/vm/i386/asmhelpers.asm @@ -38,7 +38,6 @@ EXTERN __alloca_probe:PROC EXTERN _PInvokeImportWorker@4:PROC EXTERN _VarargPInvokeStubWorker@12:PROC -EXTERN _GenericPInvokeCalliStubWorker@12:PROC EXTERN _PreStubWorker@8:PROC EXTERN _TheUMEntryPrestubWorker@4:PROC @@ -701,49 +700,6 @@ GoCallVarargWorker: _VarargPInvokeStub@0 endp -;========================================================================== -; Invoked for marshaling-required unmanaged CALLI calls as a stub. -; EAX - the unmanaged target -; ECX, EDX - arguments -; EBX - the VASigCookie -; -_GenericPInvokeCalliHelper@0 proc public - - cmp dword ptr [ebx + VASigCookie__StubOffset], 0 - jz GoCallCalliWorker - - ; Stub is already prepared, just jump to it - jmp dword ptr [ebx + VASigCookie__StubOffset] - -GoCallCalliWorker: - ; - ; call the stub generating worker - ; target ptr in EAX, VASigCookie ptr in EBX - ; - - STUB_PROLOG - - mov esi, esp - - ; save target - push eax - - push eax ; unmanaged target - push ebx ; pVaSigCookie (first stack argument) - push esi ; pTransitionBlock - - call _GenericPInvokeCalliStubWorker@12 - - ; restore target - pop eax - - STUB_EPILOG - - ; jump back to the helper - this time it won't come back here as the stub already exists - jmp _GenericPInvokeCalliHelper@0 - -_GenericPInvokeCalliHelper@0 endp - ifdef FEATURE_READYTORUN ;========================================================================== _DelayLoad_MethodCall@0 proc public diff --git a/src/coreclr/vm/i386/cgenx86.cpp b/src/coreclr/vm/i386/cgenx86.cpp index 1500b80f90030f..bc2daec3b7cab1 100644 --- a/src/coreclr/vm/i386/cgenx86.cpp +++ b/src/coreclr/vm/i386/cgenx86.cpp @@ -372,23 +372,6 @@ void HijackFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats #endif // FEATURE_HIJACK -void PInvokeCalliFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END; - - VASigCookie *pVASigCookie = GetVASigCookie(); - UpdateRegDisplayHelper(pRD, pVASigCookie->sizeOfArgs); - - LOG((LF_GCROOTS, LL_INFO100000, "STACKWALK PInvokeCalliFrame::UpdateRegDisplay_Impl(ip:%p, sp:%p)\n", pRD->ControlPC, pRD->SP)); -} - #ifndef UNIX_X86_ABI void TailCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateFloats) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index c8ffc31b0d3583..873b9e95e3e8a6 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -6649,6 +6649,13 @@ DWORD CEEInfo::getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftn) /* Function marked as not inlineable */ result |= CORINFO_FLG_DONT_INLINE; } + else if (pMD->IsILStub()) + { + // IL stubs have no metadata and their IL is only materialized while the stub itself is + // being compiled, so they can never be inlined into their callers. Reporting this here + // keeps the JIT from asking for the stub's IL (see code:CEEInfo::canInline). + result |= CORINFO_FLG_DONT_INLINE; + } // AggressiveInlining only makes sense for IL methods. else if (pMD->IsIL() && IsMiAggressiveInlining(ilMethodImplAttribs)) { @@ -10194,17 +10201,6 @@ bool CEEInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method, CORINFO_SI return result; } -/*********************************************************************/ -// Generate a cookie based on the signature that would needs to be passed -// to CORINFO_HELP_PINVOKE_CALLI -LPVOID CEEInfo::GetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig, - void **ppIndirection) -{ - WRAPPER_NO_CONTRACT; - - return getVarArgsHandle(szMetaSig, NULL, ppIndirection); -} - // Check any constraints on method type arguments bool CEEInfo::satisfiesMethodConstraints( CORINFO_CLASS_HANDLE parent, @@ -15419,9 +15415,94 @@ CORINFO_METHOD_HANDLE CEEJitInfo::getAsyncResumptionStub(void** entryPoint) return CORINFO_METHOD_HANDLE(result); } +//--------------------------------------------------------------------------------------- +// +// Optionally converts an unmanaged calli call site into a call to an IL stub that performs +// the argument marshalling and the managed/native transition. +// +// The IL stub is created (and cached in the IL stub cache by signature) here, but it is only +// JIT-compiled the first time it is called - we cannot JIT it while we are jitting the caller. +// +// Arguments: +// pResolvedToken - the token of the calli call site. Only token, tokenScope and +// tokenContext are valid on entry. On success, hMethod is filled in +// with the IL stub. +// fMustConvert - true if the JIT cannot emit an inline P/Invoke at this call site and +// therefore requires the conversion. +// +// Return Value: +// true if the call site was converted to a call to an IL stub. +// bool CEEInfo::convertPInvokeCalliToCall(CORINFO_RESOLVED_TOKEN * pResolvedToken, bool fMustConvert) { - return false; + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + bool result = false; + + JIT_TO_EE_TRANSITION(); + + CORINFO_MODULE_HANDLE scopeHnd = pResolvedToken->tokenScope; + + SigPointer sig{}; + bool canConvert = true; + + if (IsDynamicScope(scopeHnd)) + { + // The calli that dispatches to the unmanaged target inside a marshalling stub is the + // P/Invoke itself and must stay inline. Those call sites always use + // TOKEN_ILSTUB_TARGET_SIG, and their IL is owned either by an IL stub MethodDesc or, + // for a plain P/Invoke, directly by the PInvokeMethodDesc. + if (pResolvedToken->token == (mdToken)TOKEN_ILSTUB_TARGET_SIG) + { + canConvert = false; + } + else + { + sig = GetDynamicResolver(scopeHnd)->ResolveSignature(pResolvedToken->token); + } + } + else + { + Module* pModule = (Module*)scopeHnd; + + PCCOR_SIGNATURE pSig = NULL; + uint32_t cbSig = 0; + IfFailThrow(pModule->GetMDImport()->GetSigFromToken( + (mdSignature)pResolvedToken->token, + (ULONG*)&cbSig, + &pSig)); + sig = SigPointer{ pSig, cbSig }; + } + + if (canConvert) + { + PCCOR_SIGNATURE pSig; + uint32_t cbSig; + sig.GetSignature(&pSig, &cbSig); + + SigTypeContext typeContext; + GetTypeContext(pResolvedToken->tokenContext, &typeContext); + + MethodDesc* pStubMD = PInvoke::CreateCalliILStub( + GetModule(scopeHnd), + Signature(pSig, cbSig), + &typeContext, + fMustConvert); + + if (pStubMD != NULL) + { + pResolvedToken->hMethod = (CORINFO_METHOD_HANDLE)pStubMD; + result = true; + } + } + + EE_TO_JIT_TRANSITION(); + + return result; } void CEEInfo::updateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint) diff --git a/src/coreclr/vm/loongarch64/pinvokestubs.S b/src/coreclr/vm/loongarch64/pinvokestubs.S index d1bb4e462481a9..8052571d1786a7 100644 --- a/src/coreclr/vm/loongarch64/pinvokestubs.S +++ b/src/coreclr/vm/loongarch64/pinvokestubs.S @@ -11,12 +11,12 @@ // // Params :- // $FuncPrefix : prefix of the function name for the stub -// Eg. VarargPinvoke, GenericPInvokeCalli +// Eg. VarargPinvoke // $VASigCookieReg : register which contains the VASigCookie // $SaveFPArgs : "Yes" or "No" . For varidic functions FP Args are not present in FP regs // So need not save FP Args registers for vararg Pinvoke -.macro PINVOKE_STUB __PInvokeStubFuncName,__PInvokeGenStubFuncName,__PInvokeStubWorkerName,VASigCookieReg,HiddenArg,SaveFPArgs,ShiftLeftAndOrSecret=0 +.macro PINVOKE_STUB __PInvokeStubFuncName,__PInvokeGenStubFuncName,__PInvokeStubWorkerName,VASigCookieReg,HiddenArg,SaveFPArgs NESTED_ENTRY \__PInvokeStubFuncName, _TEXT, NoHandler @@ -26,16 +26,6 @@ // if null goto stub generation beq $t0, $zero, \__PInvokeGenStubFuncName - .if (\ShiftLeftAndOrSecret == 1) - // - // We need to distinguish between a MethodDesc* and an unmanaged target. - // The way we do this is to shift the managed target to the left by one bit and then set the - // least significant bit to 1. This works because MethodDesc* are always 8-byte aligned. - // - slli.d \HiddenArg, \HiddenArg, 1 - ori \HiddenArg, \HiddenArg, 1 - .endif - jirl $r0, $t0, 0 NESTED_END \__PInvokeStubFuncName, _TEXT @@ -166,16 +156,6 @@ LEAF_END JIT_PInvokeEnd, _TEXT PINVOKE_STUB VarargPInvokeStub, VarargPInvokeGenILStub, VarargPInvokeStubWorker, $a0, $t2, 0 -// ------------------------------------------------------------------ -// GenericPInvokeCalliHelper & GenericPInvokeCalliGenILStub -// Helper for generic pinvoke calli instruction -// -// in: -// $t3 = VASigCookie* -// $t2 = Unmanaged target -// -PINVOKE_STUB GenericPInvokeCalliHelper, GenericPInvokeCalliGenILStub, GenericPInvokeCalliStubWorker, $t3, $t2, 1, 1 - //// ------------------------------------------------------------------ //// VarargPInvokeStub_RetBuffArg & VarargPInvokeGenILStub_RetBuffArg //// Vararg PInvoke Stub when the method has a hidden return buffer arg diff --git a/src/coreclr/vm/mlinfo.cpp b/src/coreclr/vm/mlinfo.cpp index b89c18524f1efc..80132ad83c1497 100644 --- a/src/coreclr/vm/mlinfo.cpp +++ b/src/coreclr/vm/mlinfo.cpp @@ -2084,6 +2084,14 @@ VOID MarshalInfo::EmitOrThrowInteropParamException(PInvokeStubLinker* psl, BOOL } #endif // FEATURE_COMINTEROP + // An unmanaged CALLI stub is created while the calli's caller is being jitted, so its failures + // have to be reported when the stub is called rather than failing that compilation. + if (SF_IsCALLIStub(psl->GetStubFlags())) + { + psl->SetInteropParamExceptionInfo(resID, paramIdx); + return; + } + ThrowInteropParamException(resID, paramIdx); } diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 41e7624c50466f..6f594713732591 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -500,6 +500,7 @@ static const Entry s_QCall[] = DllImportEntry(StubHelpers_CreateCustomMarshaler) DllImportEntry(StubHelpers_CreateLayoutClassMarshalStubs) DllImportEntry(StubHelpers_ThrowInteropParamException) + DllImportEntry(StubHelpers_ThrowInteropException) DllImportEntry(StubHelpers_MarshalToManagedVaList) DllImportEntry(StubHelpers_MarshalToUnmanagedVaList) DllImportEntry(StubHelpers_ValidateObject) diff --git a/src/coreclr/vm/riscv64/pinvokestubs.S b/src/coreclr/vm/riscv64/pinvokestubs.S index 85eb386154f905..1d99a5b1b6d932 100644 --- a/src/coreclr/vm/riscv64/pinvokestubs.S +++ b/src/coreclr/vm/riscv64/pinvokestubs.S @@ -11,11 +11,11 @@ // // Params :- // FuncPrefix : prefix of the function name for the stub -// Eg. VarargPinvoke, GenericPInvokeCalli +// Eg. VarargPinvoke // VASigCookieReg : register which contains the VASigCookie // SaveFPArgs : "Yes" or "No" . For varidic functions FP Args are not present in FP regs // So need not save FP Args registers for vararg Pinvoke -.macro PINVOKE_STUB __PInvokeStubFuncName,__PInvokeGenStubFuncName,__PInvokeStubWorkerName,VASigCookieReg,HiddenArg,SaveFPArgs,ShiftLeftAndOrSecret=0 +.macro PINVOKE_STUB __PInvokeStubFuncName,__PInvokeGenStubFuncName,__PInvokeStubWorkerName,VASigCookieReg,HiddenArg,SaveFPArgs NESTED_ENTRY \__PInvokeStubFuncName, _TEXT, NoHandler @@ -26,16 +26,6 @@ // if null goto stub generation beq t0, zero, \__PInvokeGenStubFuncName - .if (\ShiftLeftAndOrSecret == 1) - // - // We need to distinguish between a MethodDesc* and an unmanaged target. - // The way we do this is to shift the managed target to the left by one bit and then set the - // least significant bit to 1. This works because MethodDesc* are always 8-byte aligned. - // - slli \HiddenArg, \HiddenArg, 1 - ori \HiddenArg, \HiddenArg, 1 - .endif - jr t0 NESTED_END \__PInvokeStubFuncName, _TEXT @@ -160,16 +150,6 @@ LEAF_END JIT_PInvokeEnd, _TEXT PINVOKE_STUB VarargPInvokeStub, VarargPInvokeGenILStub, VarargPInvokeStubWorker, a0, t2, 0 -// ------------------------------------------------------------------ -// GenericPInvokeCalliHelper & GenericPInvokeCalliGenILStub -// Helper for generic pinvoke calli instruction -// -// in: -// t3 = VASigCookie* -// t2 = Unmanaged target -// -PINVOKE_STUB GenericPInvokeCalliHelper, GenericPInvokeCalliGenILStub, GenericPInvokeCalliStubWorker, t3, t2, 1, 1 - //// ------------------------------------------------------------------ //// VarargPInvokeStub_RetBuffArg & VarargPInvokeGenILStub_RetBuffArg //// Vararg PInvoke Stub when the method has a hidden return buffer arg diff --git a/src/coreclr/vm/stubhelpers.cpp b/src/coreclr/vm/stubhelpers.cpp index c0b51077fda7e5..83ea29ad8d6dfd 100644 --- a/src/coreclr/vm/stubhelpers.cpp +++ b/src/coreclr/vm/stubhelpers.cpp @@ -510,14 +510,6 @@ FCIMPL1(void*, StubHelpers::GetDelegateTarget, DelegateObject *pThisUNSAFE) DELEGATEREF orefThis = (DELEGATEREF)ObjectToOBJECTREF(pThisUNSAFE); -#if defined(HOST_64BIT) - UINT_PTR target = (UINT_PTR)orefThis->GetMethodPtrAux(); - - // See code:GenericPInvokeCalliHelper - // The lowest bit is used to distinguish between MD and target on 64-bit. - target = (target << 1) | 1; -#endif // HOST_64BIT - pEntryPoint = orefThis->GetMethodPtrAux(); return (PVOID)pEntryPoint; @@ -533,6 +525,18 @@ extern "C" void QCALLTYPE StubHelpers_ThrowInteropParamException(INT resID, INT END_QCALL; } +// Throws an interop failure that was detected while the stub was being generated. Stubs that are +// created while their caller is being jitted report their failures this way so that a call site +// that is never executed does not fail the compilation of the method containing it. +extern "C" void QCALLTYPE StubHelpers_ThrowInteropException(INT exceptionKind, INT resID) +{ + QCALL_CONTRACT; + + BEGIN_QCALL; + COMPlusThrow(static_cast(exceptionKind), static_cast(resID)); + END_QCALL; +} + #ifdef PROFILING_SUPPORTED extern "C" void* QCALLTYPE StubHelpers_ProfilerBeginTransitionCallback(MethodDesc* pTargetMD) { diff --git a/src/coreclr/vm/stubhelpers.h b/src/coreclr/vm/stubhelpers.h index 69da8a9c6c64d4..08bd8e4df4cb49 100644 --- a/src/coreclr/vm/stubhelpers.h +++ b/src/coreclr/vm/stubhelpers.h @@ -58,6 +58,7 @@ extern "C" void QCALLTYPE InterfaceMarshaler_ValidateComVisibilityForIUnknown(IU #endif extern "C" void QCALLTYPE StubHelpers_ThrowInteropParamException(INT resID, INT paramIdx); +extern "C" void QCALLTYPE StubHelpers_ThrowInteropException(INT exceptionKind, INT resID); extern "C" void QCALLTYPE StubHelpers_MarshalToManagedVaList(va_list va, VARARGS* pArgIterator); extern "C" void QCALLTYPE StubHelpers_MarshalToUnmanagedVaList(va_list va, DWORD cbVaListSize, const VARARGS* pArgIterator); diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index 258fb74f509658..1fbb0a42b4aed2 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1687,6 +1687,105 @@ static PCODE GetLateBoundCOMTarget(Object *pThis, CLRToCOMCallInfo *pCLRToCOMCal } #endif // FEATURE_COMINTEROP +// Reads the incoming value of the index-th integer argument register from a context captured at +// a managed method's entry point. The registers are indexed the way a TransitionBlock lays them +// out, which is the same order the ArgIterator reports. +static bool TryGetArgumentRegister(T_CONTEXT *pContext, unsigned index, TADDR *pValue) +{ + LIMITED_METHOD_CONTRACT; + +#if defined(TARGET_X86) || defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_ARM64) + if (index >= NUM_ARGUMENT_REGISTERS) + return false; + + ArgumentRegisters regs; +#if defined(TARGET_X86) + regs.ECX = (INT32)pContext->Ecx; + regs.EDX = (INT32)pContext->Edx; +#elif defined(TARGET_AMD64) +#ifdef UNIX_AMD64_ABI + regs.RDI = (INT_PTR)pContext->Rdi; + regs.RSI = (INT_PTR)pContext->Rsi; + regs.RDX = (INT_PTR)pContext->Rdx; + regs.RCX = (INT_PTR)pContext->Rcx; + regs.R8 = (INT_PTR)pContext->R8; + regs.R9 = (INT_PTR)pContext->R9; +#else + regs.RCX = (INT_PTR)pContext->Rcx; + regs.RDX = (INT_PTR)pContext->Rdx; + regs.R8 = (INT_PTR)pContext->R8; + regs.R9 = (INT_PTR)pContext->R9; +#endif // UNIX_AMD64_ABI +#elif defined(TARGET_ARM) + regs.r[0] = (INT32)pContext->R0; + regs.r[1] = (INT32)pContext->R1; + regs.r[2] = (INT32)pContext->R2; + regs.r[3] = (INT32)pContext->R3; +#elif defined(TARGET_ARM64) + for (unsigned i = 0; i < NUM_ARGUMENT_REGISTERS; i++) + regs.x[i] = (INT64)pContext->X[i]; +#endif + + static_assert(sizeof(ArgumentRegisters) == NUM_ARGUMENT_REGISTERS * sizeof(TADDR), + "Argument registers are expected to be a flat array of pointer sized values"); + + *pValue = ((TADDR*)®s)[index]; + return true; +#else + // Not implemented for this architecture. + return false; +#endif +} + +// Recovers the unmanaged target of an unmanaged CALLI stub from a context captured at the stub's +// entry point. The target is passed as the last argument of the stub - see +// code:BuildCalliILStubSignature. +static bool TryGetCalliStubTarget(MethodDesc *pStubMD, T_CONTEXT *pContext, PCODE *pTarget) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + PRECONDITION(pStubMD->AsDynamicMethodDesc()->IsPInvokeCalliStub()); + } + CONTRACTL_END; + + MetaSig msig(pStubMD); + ArgIterator argit(&msig); + + int targetOffset = TransitionBlock::InvalidOffset; + int argOffset; + while ((argOffset = argit.GetNextOffset()) != TransitionBlock::InvalidOffset) + { + targetOffset = argOffset; + } + + if (targetOffset == TransitionBlock::InvalidOffset) + return false; + + if (TransitionBlock::IsArgumentRegisterOffset(targetOffset)) + { + TADDR value; + if (!TryGetArgumentRegister(pContext, TransitionBlock::GetArgumentIndexFromOffset(targetOffset), &value)) + return false; + + *pTarget = (PCODE)value; + return true; + } + + // The incoming stack arguments start right past the return address when the call instruction + // pushes it on the stack, and at the stack pointer itself when it is passed in a link register. +#if defined(TARGET_X86) || defined(TARGET_AMD64) + TADDR stackArgs = GetSP(pContext) + sizeof(TADDR); +#else + TADDR stackArgs = GetSP(pContext); +#endif + + *pTarget = *(PCODE*)(stackArgs + (targetOffset - TransitionBlock::GetOffsetOfArgs())); + return true; +} + BOOL ILStubManager::TraceManager(Thread *thread, TraceDestination *trace, T_CONTEXT *pContext, @@ -1740,13 +1839,14 @@ BOOL ILStubManager::TraceManager(Thread *thread, } else if (pStubMD->IsPInvokeCalliStub()) { - // This is unmanaged CALLI stub, the argument is the target - target = (PCODE)arg; - - // The value is mangled on 64-bit -#ifdef TARGET_AMD64 - target = target >> 1; // call target is encoded as (addr << 1) | 1 -#endif // TARGET_AMD64 + // This is an unmanaged CALLI stub. The native target is passed as its last argument + // rather than in a hidden argument, so it has to be read out of the incoming argument + // location that the calling convention assigned to it. + if (!TryGetCalliStubTarget(pStubMD, pContext, &target)) + { + LOG((LF_CORDB, LL_INFO1000, "ILSM::TraceManager: Unmanaged CALLI stub - could not locate the target\n")); + return FALSE; + } LOG((LF_CORDB, LL_INFO10000, "ILSM::TraceManager: Unmanaged CALLI case %p\n", target)); trace->InitForUnmanaged(target); @@ -1894,7 +1994,7 @@ BOOL PInvokeStubManager::DoTraceStub(PCODE stubStartAddress, #endif // !DACCESS_COMPILE } -// This is used to recognize VarargPInvokeStub, and GenericPInvokeCalliHelper. +// This is used to recognize VarargPInvokeStub. #ifndef DACCESS_COMPILE @@ -1941,12 +2041,6 @@ BOOL InteropDispatchStubManager::CheckIsStub_Internal(PCODE stubStartAddress) { return true; } - - if (stubStartAddress == GetEEFuncEntryPoint(GenericPInvokeCalliHelper)) - { - return true; - } - #endif // !DACCESS_COMPILE return false; } @@ -2008,18 +2102,6 @@ BOOL InteropDispatchStubManager::TraceManager(Thread *thread, trace->InitForUnmanaged(target); #endif //defined(TARGET_ARM64) && defined(__APPLE__) } - else if (stubIP == GetEEFuncEntryPoint(GenericPInvokeCalliHelper)) - { -#if defined(TARGET_ARM64) && defined(__APPLE__) - //On ARM64 Mac, we cannot put a breakpoint inside of GenericPInvokeCalliHelper - LOG((LF_CORDB, LL_INFO10000, "IDSM::TraceManager: Skipping on arm64-macOS\n")); - return FALSE; -#else - PCODE target = (PCODE)arg; - LOG((LF_CORDB, LL_INFO10000, "IDSM::TraceManager: Unmanaged CALLI case %p\n", target)); - trace->InitForUnmanaged(target); -#endif //defined(TARGET_ARM64) && defined(__APPLE__) - } return TRUE; } diff --git a/src/coreclr/vm/stubmgr.h b/src/coreclr/vm/stubmgr.h index da04e1f11dbe63..9d61bd75bc34a5 100644 --- a/src/coreclr/vm/stubmgr.h +++ b/src/coreclr/vm/stubmgr.h @@ -653,7 +653,6 @@ class PInvokeStubManager : public StubManager // This is used to recognize // VarargPInvokeStub() -// GenericPInvokeCalliHelper() typedef VPTR(class InteropDispatchStubManager) PTR_InteropDispatchStubManager; class InteropDispatchStubManager : public StubManager diff --git a/src/coreclr/vm/wasm/helpers.cpp b/src/coreclr/vm/wasm/helpers.cpp index 3d6c96c5bb8ea7..709dd9040449d7 100644 --- a/src/coreclr/vm/wasm/helpers.cpp +++ b/src/coreclr/vm/wasm/helpers.cpp @@ -705,11 +705,6 @@ EXTERN_C VOID STDCALL ResetCurrentContext() { } -extern "C" void STDCALL GenericPInvokeCalliHelper(void) -{ - PORTABILITY_ASSERT("GenericPInvokeCalliHelper is not implemented on wasm"); -} - // Does the pinvoke frame transition; the naked wrappers below have already set the wasm // __stack_pointer global to sp so it is safe to run native code here. EXTERN_C void JIT_PInvokeBeginImpl(void* sp, InlinedCallFrame* pFrame)