Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
789055d
Support for shared GVM devirt that doesn't require a runtime lookup
hez2010 Jan 18, 2026
555ba83
Update src/coreclr/vm/jitinterface.cpp
hez2010 Jan 18, 2026
25c0967
A better way to check runtime lookup
hez2010 Jan 18, 2026
65a61bb
Add a TODO
hez2010 Jan 18, 2026
8d74fdb
Merge branch 'main' into gvm-devirt-shared
hez2010 Jan 29, 2026
c8b7f69
Add support for runtime lookup as well
hez2010 Feb 1, 2026
0aea180
Try another approach
hez2010 Feb 1, 2026
5fbd527
Nit
hez2010 Feb 1, 2026
a3d71c0
Merge branch 'main' into gvm-devirt-shared
hez2010 Feb 3, 2026
eb692c5
Introduce a new kind of dictionary entry and switch to instParamLookup
hez2010 Feb 7, 2026
abd5db2
Save resolved token
hez2010 Feb 7, 2026
2eff218
Merge branch 'main' into gvm-devirt-shared
hez2010 Feb 7, 2026
2178332
Also assert isArrayInterface
hez2010 Feb 7, 2026
d4c9f91
Always use impRuntimeLookupToTree
hez2010 Feb 7, 2026
e96d509
Nit
hez2010 Feb 7, 2026
21623ad
Fix inlining in case of runtime lookup not available (R2R)
hez2010 Feb 7, 2026
bc7d210
Address a potential AV
hez2010 Feb 8, 2026
aeca172
Always call getInstantiatedEntry
hez2010 Feb 8, 2026
aa460d5
Include instantiation in the method name
hez2010 Feb 8, 2026
263a6ae
Add more information to the dump
hez2010 Feb 8, 2026
eaf4493
Remove duplicated class name
hez2010 Feb 8, 2026
264058e
Merge branch 'main' into gvm-devirt-shared
hez2010 Feb 9, 2026
19da409
Use getLookupTree
hez2010 Feb 9, 2026
9c5faa7
Disable runtime lookup support in R2R
hez2010 Feb 9, 2026
ecdf97f
Merge branch 'main' into gvm-devirt-shared
hez2010 Feb 9, 2026
2fb9e79
Remove unused ctxTree
hez2010 Feb 9, 2026
53a52d4
Get rid of getInstantiatedEntry and prevent computing a runtime looku…
hez2010 Feb 10, 2026
264dc62
Merge branch 'gvm-devirt-shared' of github.com:hez2010/runtime into g…
hez2010 Feb 10, 2026
d994cb1
Guard lookupToken
hez2010 Feb 10, 2026
3994537
More fixes
hez2010 Feb 10, 2026
014fb46
Fix
hez2010 Feb 10, 2026
fc995e5
Bail NativeAOT
hez2010 Feb 10, 2026
583277b
Make runtime lookup tests really do runtime lookup
hez2010 Feb 10, 2026
1aea555
Fix R2R const lookup
hez2010 Feb 10, 2026
d5e3485
Bail on runtime lookup for R2R
hez2010 Feb 10, 2026
267e187
R2R runtime lookup support
hez2010 Feb 10, 2026
ca8f876
Merge branch 'main' into gvm-devirt-shared
hez2010 Feb 11, 2026
757043d
Use the correct impl method token
hez2010 Feb 12, 2026
2906173
Remove the no longer necessary assertion
hez2010 Feb 12, 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
8 changes: 3 additions & 5 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1591,17 +1591,15 @@ struct CORINFO_DEVIRTUALIZATION_INFO
// - details on the computation done by the jit host
// - If pResolvedTokenDevirtualizedMethod is not set to NULL and targeting an R2R image
// use it as the parameter to getCallInfo
// - isInstantiatingStub is set to TRUE if the devirtualized method is a generic method instantiating stub
// - needsMethodContext is set TRUE if the devirtualized method may require a method context
// (in which case the method handle and context will be a generic method)
// - instParamLookup contains all the information necessary to pass the instantiation parameter for
// the devirtualized method.
//
CORINFO_METHOD_HANDLE devirtualizedMethod;
CORINFO_CONTEXT_HANDLE exactContext;
CORINFO_DEVIRTUALIZATION_DETAIL detail;
CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedMethod;
CORINFO_RESOLVED_TOKEN resolvedTokenDevirtualizedUnboxedMethod;
bool isInstantiatingStub;
bool needsMethodContext;
CORINFO_LOOKUP instParamLookup;
};

//----------------------------------------------------------------------------
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 = { /* 868b8ae2-0000-410b-a9dc-38d9eda37d66 */
0x868b8ae2,
0x0000,
0x410b,
{0xa9, 0xdc, 0x38, 0xd9, 0xed, 0xa3, 0x7d, 0x66}
constexpr GUID JITEEVersionIdentifier = { /* fc5f63e7-921b-4091-b920-8df8d7b872c1 */
0xfc5f63e7,
0x921b,
0x4091,
{0xb9, 0x20, 0x8d, 0xf8, 0xd7, 0xb8, 0x72, 0xc1}
};

#endif // JIT_EE_VERSIONING_GUID_H
2 changes: 2 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -5204,6 +5204,8 @@ class Compiler

methodPointerInfo* impAllocateMethodPointerInfo(const CORINFO_RESOLVED_TOKEN& token, mdToken tokenConstrained);

static bool impDevirtualizedCallHasConstInstParam(const CORINFO_DEVIRTUALIZATION_INFO& dvInfo);

/*
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Expand Down
15 changes: 8 additions & 7 deletions src/coreclr/jit/fginline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,16 +603,17 @@ class SubstitutePlaceholdersAndDevirtualizeWalker : public GenTreeVisitor<Substi
}
#endif // DEBUG

CORINFO_METHOD_HANDLE method = call->gtLateDevirtualizationInfo->methodHnd;
CORINFO_CONTEXT_HANDLE context = call->gtLateDevirtualizationInfo->exactContextHnd;
InlineContext* inlinersContext = call->gtLateDevirtualizationInfo->inlinersContext;
unsigned methodFlags = 0;
const bool isLateDevirtualization = true;
const bool explicitTailCall = call->IsTailPrefixedCall();
CORINFO_METHOD_HANDLE method = call->gtLateDevirtualizationInfo->methodHnd;
CORINFO_CONTEXT_HANDLE context = call->gtLateDevirtualizationInfo->exactContextHnd;
InlineContext* inlinersContext = call->gtLateDevirtualizationInfo->inlinersContext;
CORINFO_RESOLVED_TOKEN* pResolvedToken = &call->gtLateDevirtualizationInfo->resolvedToken;
unsigned methodFlags = 0;
const bool isLateDevirtualization = true;
const bool explicitTailCall = call->IsTailPrefixedCall();

CORINFO_CONTEXT_HANDLE contextInput = context;
context = nullptr;
m_compiler->impDevirtualizeCall(call, nullptr, &method, &methodFlags, &contextInput, &context,
m_compiler->impDevirtualizeCall(call, pResolvedToken, &method, &methodFlags, &contextInput, &context,
isLateDevirtualization, explicitTailCall);

if (!call->IsDevirtualizationCandidate(m_compiler))
Expand Down
182 changes: 104 additions & 78 deletions src/coreclr/jit/importercalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
info->methodHnd = callInfo->hMethod;
info->exactContextHnd = exactContextHnd;
info->inlinersContext = compInlineContext;
info->resolvedToken = *pResolvedToken;
call->AsCall()->gtLateDevirtualizationInfo = info;
}
}
Expand Down Expand Up @@ -7510,6 +7511,29 @@ bool Compiler::isCompatibleMethodGDV(GenTreeCall* call, CORINFO_METHOD_HANDLE gd
return true;
}

//------------------------------------------------------------------------
// impDevirtualizedCallHasConstInstParam: check if the instantiation argument
// is a compile-time lookup.
//
// Arguments:
// dvInfo - Devirtualization information returned by resolveVirtualMethod.
//
// Returns:
// true if instParamLookup describes a valid constant handle/address lookup.
//
bool Compiler::impDevirtualizedCallHasConstInstParam(const CORINFO_DEVIRTUALIZATION_INFO& dvInfo)
{
if (dvInfo.instParamLookup.lookupKind.needsRuntimeLookup)
{
return false;
}

return ((dvInfo.instParamLookup.constLookup.accessType == IAT_VALUE &&
dvInfo.instParamLookup.constLookup.handle != nullptr) ||
(dvInfo.instParamLookup.constLookup.accessType == IAT_PVALUE &&
dvInfo.instParamLookup.constLookup.addr != nullptr));
}

//------------------------------------------------------------------------
// considerGuardedDevirtualization: see if we can profitably guess at the
// class involved in an interface or virtual call.
Expand Down Expand Up @@ -7629,6 +7653,8 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call,
CORINFO_CONTEXT_HANDLE exactContext = dvInfo.exactContext;
CORINFO_METHOD_HANDLE exactMethod = dvInfo.devirtualizedMethod;
uint32_t exactMethodAttrs = info.compCompHnd->getMethodAttribs(exactMethod);
const bool exactNeedsMethodContext =
((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD;

// NOTE: This is currently used only with NativeAOT. In theory, we could also check if we
// have static PGO data to decide which class to guess first. Presumably, this is a rare case.
Expand All @@ -7643,8 +7669,9 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call,
}

addGuardedDevirtualizationCandidate(call, exactMethod, exactCls, exactContext, exactMethodAttrs,
clsAttrs, likelyHood, dvInfo.needsMethodContext,
dvInfo.isInstantiatingStub, baseMethod, originalContext);
clsAttrs, likelyHood, exactNeedsMethodContext,
impDevirtualizedCallHasConstInstParam(dvInfo), baseMethod,
originalContext);
}

if (call->GetInlineCandidatesCount() == numExactClasses)
Expand Down Expand Up @@ -7716,8 +7743,8 @@ void Compiler::considerGuardedDevirtualization(GenTreeCall* call,

likelyContext = dvInfo.exactContext;
likelyMethod = dvInfo.devirtualizedMethod;
needsMethodContext = dvInfo.needsMethodContext;
instantiatingStub = dvInfo.isInstantiatingStub;
needsMethodContext = ((size_t)likelyContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD;
instantiatingStub = impDevirtualizedCallHasConstInstParam(dvInfo);
}
else
{
Expand Down Expand Up @@ -8721,25 +8748,23 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
const bool objClassIsFinal = (objClassAttribs & CORINFO_FLG_FINAL) != 0;

#if defined(DEBUG)
const char* callKind = isInterface ? "interface" : "virtual";
const char* objClassNote = "[?]";
const char* objClassName = "?objClass";
const char* baseClassName = "?baseClass";
const char* baseMethodName = "?baseMethod";
const char* callKind = isInterface ? "interface" : "virtual";
const char* objClassNote = "[?]";
const char* objClassName = "?objClass";
const char* baseMethodFullName = "?baseMethod";

if (verbose || doPrint)
{
objClassNote = isExact ? " [exact]" : objClassIsFinal ? " [final]" : "";
objClassName = eeGetClassName(objClass);
baseClassName = eeGetClassName(baseClass);
baseMethodName = eeGetMethodName(baseMethod);
objClassNote = isExact ? " [exact]" : objClassIsFinal ? " [final]" : "";
objClassName = eeGetClassName(objClass);
baseMethodFullName = eeGetMethodFullName(baseMethod);

if (verbose)
{
printf("\nimpDevirtualizeCall: Trying to devirtualize %s call:\n"
" class for 'this' is %s%s (attrib %08x)\n"
" base method is %s::%s\n",
callKind, objClassName, objClassNote, objClassAttribs, baseClassName, baseMethodName);
" base method is %s\n",
callKind, objClassName, objClassNote, objClassAttribs, baseMethodFullName);
}
}
#endif // defined(DEBUG)
Expand Down Expand Up @@ -8788,26 +8813,29 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,

info.compCompHnd->resolveVirtualMethod(&dvInfo);

CORINFO_METHOD_HANDLE derivedMethod = dvInfo.devirtualizedMethod;
CORINFO_CONTEXT_HANDLE exactContext = dvInfo.exactContext;
CORINFO_CLASS_HANDLE derivedClass = NO_CLASS_HANDLE;
CORINFO_RESOLVED_TOKEN* pDerivedResolvedToken = &dvInfo.resolvedTokenDevirtualizedMethod;
CORINFO_METHOD_HANDLE derivedMethod = dvInfo.devirtualizedMethod;
CORINFO_CONTEXT_HANDLE exactContext = dvInfo.exactContext;
CORINFO_CLASS_HANDLE derivedClass = NO_CLASS_HANDLE;
CORINFO_RESOLVED_TOKEN* pDerivedResolvedToken = &dvInfo.resolvedTokenDevirtualizedMethod;
const bool needsRuntimeLookup = dvInfo.instParamLookup.lookupKind.needsRuntimeLookup;
const bool needsCompileTimeLookup = impDevirtualizedCallHasConstInstParam(dvInfo);
const bool needsInstParam = needsRuntimeLookup || needsCompileTimeLookup;

if (derivedMethod != nullptr)
{
assert(exactContext != nullptr);

if (((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_CLASS)
{
assert(!dvInfo.needsMethodContext);
assert(!needsInstParam);
derivedClass = (CORINFO_CLASS_HANDLE)((size_t)exactContext & ~CORINFO_CONTEXTFLAGS_MASK);
}
else
{
// Array interface devirt can return a nonvirtual generic method of the non-generic SZArrayHelper class.
// Generic virtual method devirt also returns a generic method.
//
assert(call->IsGenericVirtual(this) || dvInfo.needsMethodContext);
assert(call->IsGenericVirtual(this) || needsInstParam || ((objClassAttribs & CORINFO_FLG_ARRAY) != 0));
assert(((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD);
derivedClass = info.compCompHnd->getMethodClass(derivedMethod);
}
Expand All @@ -8818,54 +8846,30 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
bool canDevirtualize = false;

#if defined(DEBUG)
const char* derivedClassName = "?derivedClass";
const char* derivedMethodName = "?derivedMethod";
const char* note = "inexact or not final";
const char* instArg = "";
const char* derivedMethodFullName = "?derivedMethod";
const char* note = "inexact or not final";
const char* instArg = "";
#endif

CORINFO_METHOD_HANDLE instantiatingStub = NO_METHOD_HANDLE;

if (dvInfo.isInstantiatingStub)
if (derivedMethod != nullptr && needsInstParam)
{
// We should only end up with generic methods that needs a method context (eg. array interface, GVM).
//
assert(dvInfo.needsMethodContext);

// We don't expect NAOT to end up here, since it has Array<T>
// and normal devirtualization.
//
assert(!IsTargetAbi(CORINFO_NATIVEAOT_ABI));

// We don't expect R2R to end up here, since it does not (yet) support
// array interface devirtualization.
//
assert(!IsAot());

// We don't expect there to be an existing inst param arg.
//
CallArg* const instParam = call->gtArgs.FindWellKnownArg(WellKnownArg::InstParam);
if (instParam != nullptr)
if (needsCompileTimeLookup)
{
assert(!"unexpected inst param in virtual/interface call");
return;
}
// We should only end up with generic methods that need a method context (eg. array interface, GVM).
//
assert(((size_t)exactContext & CORINFO_CONTEXTFLAGS_MASK) == CORINFO_CONTEXTFLAGS_METHOD);

// If we don't know the array type exactly we may have the wrong interface type here.
// Bail out.
//
if (!isExact)
{
JITDUMP("Array interface devirt: array type is inexact, sorry.\n");
return;
// We don't expect R2R/NAOT to end up here for array interface devirtualization.
// For NAOT, it has Array<T> and normal devirtualization.
// For R2R, we don't (yet) support array interface devirtualization.
assert(call->IsGenericVirtual(this) || !IsAot());

instantiatingStub = (CORINFO_METHOD_HANDLE)((size_t)exactContext & ~CORINFO_CONTEXTFLAGS_MASK);
}

// We want to inline the instantiating stub. Fetch the relevant info.
//
CORINFO_CLASS_HANDLE ignored = NO_CLASS_HANDLE;
derivedMethod = info.compCompHnd->getInstantiatedEntry(derivedMethod, &instantiatingStub, &ignored);
assert(ignored == NO_CLASS_HANDLE);
assert((derivedMethod == NO_METHOD_HANDLE) || (instantiatingStub != NO_METHOD_HANDLE));
assert(!needsCompileTimeLookup || (instantiatingStub != NO_METHOD_HANDLE));
}

// If we failed to get a method handle, we can't directly devirtualize.
Expand Down Expand Up @@ -8896,18 +8900,18 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
{
note = "final method";
}
if (dvInfo.isInstantiatingStub)
if (needsInstParam)
{
instArg = " [instantiating stub]";
instArg = needsCompileTimeLookup ? eeGetMethodFullName(instantiatingStub) : "runtime lookup";
}

if (verbose || doPrint)
{
derivedMethodName = eeGetMethodName(derivedMethod);
derivedClassName = eeGetClassName(derivedClass);
derivedMethodFullName = eeGetMethodFullName(derivedMethod);
if (verbose)
{
printf(" devirt to %s::%s -- %s%s\n", derivedClassName, derivedMethodName, note, instArg);
printf(" devirt to %s -- %s%s%s\n", derivedMethodFullName, note,
needsInstParam ? ", instantiating stub: " : "", instArg);
gtDispTree(call);
}
}
Expand Down Expand Up @@ -8946,24 +8950,46 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
return;
}

// Insert the instantiation argument when necessary.
if (needsInstParam)
{
assert(call->gtArgs.FindWellKnownArg(WellKnownArg::InstParam) == nullptr);

CORINFO_METHOD_HANDLE compileTimeHandle = derivedMethod;
if (needsCompileTimeLookup)
{
compileTimeHandle = instantiatingStub;
}

CORINFO_RESOLVED_TOKEN* lookupToken =
(pDerivedResolvedToken->tokenScope != nullptr) ? pDerivedResolvedToken : pResolvedToken;
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instParam insertion chooses lookupToken as (resolvedTokenDevirtualizedMethod.tokenScope != nullptr) ? ... : pResolvedToken, but pResolvedToken is allowed to be nullptr in some callers (e.g., indirectcalltransformer). If needsInstParam is true and tokenScope is null (common for non-R2R), this will dereference a null pointer. Add a null check and bail out (or ensure callers always supply a resolved token when instParamLookup may be used).

Suggested change
(pDerivedResolvedToken->tokenScope != nullptr) ? pDerivedResolvedToken : pResolvedToken;
(pDerivedResolvedToken->tokenScope != nullptr) ? pDerivedResolvedToken : pResolvedToken;
if (lookupToken == nullptr)
{
JITDUMP("Failed to materialize instantiation argument for devirtualized call: no resolved token.\n");
return;
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GVMs are not being profiled yet so they won't hit the GDV code path.


if ((lookupToken == nullptr) && dvInfo.instParamLookup.lookupKind.needsRuntimeLookup)
{
JITDUMP("Cannot perform runtime instantiation lookup without a resolved token, sorry.\n");
return;
}

GenTree* instParam =
getLookupTree(lookupToken, &dvInfo.instParamLookup, GTF_ICON_METHOD_HDL, compileTimeHandle);

if (instParam == nullptr)
{
// If we're inlining, impLookupToTree can return nullptr after recording a fatal observation.
JITDUMP("Failed to materialize instantiation argument for devirtualized call, sorry.\n");
return;
}

call->gtArgs.InsertInstParam(this, instParam);
}
Comment on lines 8953 to 8984
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR enables devirtualization of shared generic virtual method targets by introducing instParamLookup and new runtime lookup kinds. There are many existing JIT tests for generic virtual methods/devirtualization, but none updated here to cover the new shared-target + instantiation-arg lookup behavior (including late devirtualization). Please add/extend a JIT regression test that exercises this scenario (ideally with late devirt enabled) to guard against future regressions in instParamLookup materialization and the new DevirtualizedMethodDescSlot runtime lookup encoding.

Copilot uses AI. Check for mistakes.
Comment on lines 8953 to 8984
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR introduces new behavior for shared GVM devirtualization (including new instantiation-parameter runtime lookup handling). Please add a focused JIT regression test (e.g., under src/tests/JIT) that exercises both interface and virtual-call cases where the devirtualized target is a shared generic method requiring an instantiation argument, to prevent future regressions (especially for late devirtualization / post-import phases).

Copilot uses AI. Check for mistakes.

// All checks done. Time to transform the call.
//
assert(canDevirtualize);
Metrics.DevirtualizedCall++;

JITDUMP(" %s; can devirtualize\n", note);

if (dvInfo.isInstantiatingStub)
{
// Pass the instantiating stub method desc as the inst param arg.
//
// Note different embedding would be needed for NAOT/R2R,
// but we have ruled those out above.
//
GenTree* const instParam = gtNewIconEmbMethHndNode(instantiatingStub);
call->gtArgs.InsertInstParam(this, instParam);
}

// Make the updates.
call->gtFlags &= ~GTF_CALL_VIRT_VTABLE;
call->gtFlags &= ~GTF_CALL_VIRT_STUB;
Expand Down Expand Up @@ -8993,8 +9019,8 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,

if (doPrint)
{
printf("Devirtualized %s call to %s:%s; now direct call to %s:%s [%s]\n", callKind, baseClassName,
baseMethodName, derivedClassName, derivedMethodName, note);
printf("Devirtualized %s call to %s; now direct call to %s [%s]%s%s\n", callKind, baseMethodFullName,
derivedMethodFullName, note, needsInstParam ? ", instantiating stub: " : "", instArg);
}

// If we successfully devirtualized based on an exact or final class,
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/jit/inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@ struct LateDevirtualizationInfo
CORINFO_METHOD_HANDLE methodHnd;
CORINFO_CONTEXT_HANDLE exactContextHnd;
InlineContext* inlinersContext;
CORINFO_RESOLVED_TOKEN resolvedToken;
};

// InlArgInfo describes inline candidate argument properties.
Expand Down
Loading
Loading