Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
6968432
Implement convertPInvokeCalliToCall for CoreCLR
jkoritzinsky Jul 28, 2026
86a4ed1
Recover the unmanaged CALLI stub target for the debugger
jkoritzinsky Jul 28, 2026
5b241ba
Remove the dead PInvoke calli cookie path
jkoritzinsky Jul 28, 2026
900965c
Report unmanaged calli stub failures when the stub is called
jkoritzinsky Jul 30, 2026
a2057d2
Remove the unused PInvoke calli cookie from the JIT-EE interface
jkoritzinsky Jul 30, 2026
ba6179a
Fix unused target variable and EXPLICITTHIS handling in calli stub
Copilot Jul 31, 2026
eedd452
Preserve the exception kind when deferring a calli modopt failure
jkoritzinsky Jul 31, 2026
e4f63e6
Allow an unmanaged CALLI stub to have a trailing target argument on x86
jkoritzinsky Aug 1, 2026
76cf5c1
Keep resolved calli token handles in sync
jkoritzinsky Aug 11, 2026
77e20a9
Pass calli target in secret stub register
jkoritzinsky Aug 17, 2026
7ff76c5
Identify calli stub target with modreq
jkoritzinsky Aug 17, 2026
134299e
Lazily resolve secret stub argument type
jkoritzinsky Aug 18, 2026
e135084
Delay calli stub signature allocation
jkoritzinsky Aug 18, 2026
aa619ee
Retain calli stub signature on cache miss
jkoritzinsky Aug 19, 2026
ee3760b
Add a comment on how stub signature lifetimes work for CreateInteropI…
jkoritzinsky Aug 20, 2026
8dfc6f7
Clean up StubSigDesc overloads
jkoritzinsky Aug 21, 2026
5808681
Fix lifetime documentation for signatures to be accurate and clean up…
jkoritzinsky Aug 21, 2026
61498d9
Remove now unused method
jkoritzinsky Aug 22, 2026
9a716b5
Copy down register homing logic from #132534 for win-x64
jkoritzinsky Aug 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions docs/design/coreclr/botr/clr-abi.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 2 additions & 4 deletions docs/design/coreclr/botr/guide-for-porting.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2179,6 +2179,9 @@ internal static partial class StubHelpers
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "StubHelpers_ThrowInteropParamException")]
internal static safe 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);
Expand Down
16 changes: 6 additions & 10 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,6 @@ enum CorInfoHelpFunc

/* Miscellaneous */

CORINFO_HELP_PINVOKE_CALLI, // Indirect pinvoke call
CORINFO_HELP_TAILCALL, // Perform a tail call

CORINFO_HELP_GETCURRENTMANAGEDTHREADID,
Expand Down Expand Up @@ -633,9 +632,10 @@ enum CorInfoWasmType

enum CorInfoTypeWithMod
{
CORINFO_TYPE_MASK = 0x3F, // lower 6 bits are type mask
CORINFO_TYPE_MOD_PINNED = 0x40, // can be applied to CLASS, or BYREF to indicate pinned
CORINFO_TYPE_MOD_COPY_WITH_HELPER = 0x80 // can be applied to VALUECLASS to indicate 'needs helper to copy'
CORINFO_TYPE_MASK = 0x3F, // lower 6 bits are type mask
CORINFO_TYPE_MOD_PINNED = 0x40, // can be applied to CLASS, or BYREF to indicate pinned
CORINFO_TYPE_MOD_COPY_WITH_HELPER = 0x80, // can be applied to VALUECLASS to indicate 'needs helper to copy'
CORINFO_TYPE_MOD_SECRET_STUB_ARGUMENT = 0x100, // can be applied to NATIVEINT to indicate the secret stub argument
};

inline CorInfoType strip(CorInfoTypeWithMod val) {
Expand Down Expand Up @@ -3393,12 +3393,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;
Expand Down Expand Up @@ -3542,6 +3536,8 @@ class ICorDynamicInfo : public ICorStaticInfo
) = 0;

// Optionally, convert calli to regular method call. This is for PInvoke argument marshalling.
// On success, pResolvedToken->hMethod and pResolvedToken->hClass are set to the method
// and class that should be called instead.
virtual bool convertPInvokeCalliToCall(
CORINFO_RESOLVED_TOKEN * pResolvedToken,
bool fMustConvert
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/inc/icorjitinfoimpl_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -604,10 +604,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;

Expand Down
10 changes: 5 additions & 5 deletions src/coreclr/inc/jiteeversionguid.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@

#include <minipal/guid.h>

constexpr GUID JITEEVersionIdentifier = { /* daa88390-808f-4164-908c-8635f9c8282c */
0xdaa88390,
0x808f,
0x4164,
{0x90, 0x8c, 0x86, 0x35, 0xf9, 0xc8, 0x28, 0x2c}
constexpr GUID JITEEVersionIdentifier = { /* 0470bb0a-8e19-446c-a494-04f35ca0404c */
0x0470bb0a,
0x8e19,
0x446c,
{0xa4, 0x94, 0x04, 0xf3, 0x5c, 0xa0, 0x40, 0x4c}
};

#endif // JIT_EE_VERSIONING_GUID_H
2 changes: 0 additions & 2 deletions src/coreclr/inc/jithelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/jit/ICorJitInfo_names_generated.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,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)
Expand Down
10 changes: 0 additions & 10 deletions src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1426,16 +1426,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)
{
Expand Down
3 changes: 1 addition & 2 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4447,6 +4447,7 @@ class Compiler
// mechanism passes the address of the return address to a runtime helper
// where it is used to detect tail-call chains.
unsigned lvaRetAddrVar = BAD_VAR_NUM;
unsigned lvaSecretStubArg = BAD_VAR_NUM;
Comment thread
jkoritzinsky marked this conversation as resolved.

#ifdef SWIFT_SUPPORT
unsigned lvaSwiftSelfArg = BAD_VAR_NUM;
Expand Down Expand Up @@ -9625,8 +9626,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()
{
Expand Down
28 changes: 0 additions & 28 deletions src/coreclr/jit/ee_il_dll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
Expand Down
4 changes: 4 additions & 0 deletions src/coreclr/jit/eeinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ void AppendCorInfoTypeWithModModifiers(StringPrinter* printer, CorInfoTypeWithMo
{
printer->Append("COPY_WITH_HELPER__");
}
if ((corInfoTypeWithMod & CORINFO_TYPE_MOD_SECRET_STUB_ARGUMENT) == CORINFO_TYPE_MOD_SECRET_STUB_ARGUMENT)
{
printer->Append("SECRET_STUB_ARGUMENT__");
}
}

//------------------------------------------------------------------------
Expand Down
36 changes: 4 additions & 32 deletions src/coreclr/jit/gentree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1591,14 +1591,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;
Expand Down Expand Up @@ -2381,12 +2373,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;
}

Expand Down Expand Up @@ -2604,18 +2590,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()) &&
Expand Down Expand Up @@ -10119,19 +10093,17 @@ 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;
}
else
{
node->gtCallMethHnd = callHnd;
node->gtControlExpr = nullptr;
node->ClearInlineInfo();
}
node->gtReturnType = type;

Expand Down Expand Up @@ -11750,15 +11722,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;
Expand Down
3 changes: 0 additions & 3 deletions src/coreclr/jit/gentree.h
Original file line number Diff line number Diff line change
Expand Up @@ -5881,9 +5881,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
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/jit/handlekinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading