Skip to content

WIP: Svm diamond shape without mono exclusion #70045

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5a16ec5
Move the diamondshape test under StaticVirtualMethods
trylek Mar 17, 2022
07004ec
Modify the test to exercise static virtual methods
trylek Mar 17, 2022
d50b834
Fixes to svm_diamondshape to make it build; initial runtime changes
trylek Mar 18, 2022
b89edd7
One more fix to the new diamondshape test; more runtime fixes
trylek Mar 19, 2022
30eee66
Partial change for default interface implementations of SVMs
trylek Apr 27, 2022
21610bc
Additional JIT changes to make default impl's of SVM resolve properly
trylek Apr 27, 2022
7a2fbb9
Fix temporary instrumentation
trylek Apr 27, 2022
e402364
Address initial JanK's PR feedback
trylek Apr 28, 2022
c1e1483
Add struct variants for the svm_diamondshape tests
trylek Apr 28, 2022
32c3c9b
Add struct and ldftn testing per David's PR feedback
trylek Apr 29, 2022
3f0622e
Remove 'final' check; add reabstraction test cases
trylek May 11, 2022
32c3fa2
Fix a few syntax errors in the IL
trylek May 12, 2022
a36136b
Relax flag checking for reabstracted SVMs; runtime resolution test
trylek May 16, 2022
2bad146
More changes based on David Wrighton's feedback
trylek May 24, 2022
01b38a2
Additional changes for shared generic support
trylek May 26, 2022
7d0b7af
Fix calling convention flag setting in getCallInfo
trylek May 27, 2022
8a873a4
Fix test C# source code according to the IL; fix a few IL typos
trylek May 27, 2022
1d6d27f
Remove dummy 'else' block
trylek May 27, 2022
23ce9aa
Fix failures in several pre-existing SVM tests
trylek May 30, 2022
21c38da
Revert CORINFO_STATICVIRTUALCALL per Michal's PR feedback
trylek May 30, 2022
326dbec
Temporarily disable the SVM diamond shape test on mono with #70040
trylek May 31, 2022
915d5ce
Remove the issues.targets entry to see if Mono works now
trylek May 31, 2022
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: 2 additions & 0 deletions src/coreclr/inc/corinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,8 @@ enum CorInfoHelpFunc
CORINFO_HELP_VALIDATE_INDIRECT_CALL, // CFG: Validate function pointer
CORINFO_HELP_DISPATCH_INDIRECT_CALL, // CFG: Validate and dispatch to pointer

CORINFO_HELP_STATIC_VIRTUAL_AMBIGUOUS_RESOLUTION, // Throw AmbiguousResolutionException for failed static virtual method resolution

CORINFO_HELP_COUNT,
};

Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/inc/jithelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@
JITHELPER(CORINFO_HELP_DISPATCH_INDIRECT_CALL, NULL, CORINFO_HELP_SIG_REG_ONLY)
#endif

JITHELPER(CORINFO_HELP_STATIC_VIRTUAL_AMBIGUOUS_RESOLUTION, JIT_StaticVirtualAmbiguousResolution, CORINFO_HELP_SIG_REG_ONLY)

#undef JITHELPER
#undef DYNAMICJITHELPER
#undef JITHELPER
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9455,7 +9455,6 @@ var_types Compiler::impImportCall(OPCODE opcode,

switch (callInfo->kind)
{

case CORINFO_VIRTUALCALL_STUB:
{
assert(!(mflags & CORINFO_FLG_STATIC)); // can't call a static method
Expand Down
28 changes: 28 additions & 0 deletions src/coreclr/vm/jithelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3375,6 +3375,34 @@ NOINLINE HCIMPL3(CORINFO_MethodPtr, JIT_VirtualFunctionPointer_Framed, Object *
}
HCIMPLEND

HCIMPL3(void, JIT_StaticVirtualAmbiguousResolution,
MethodDesc *method,
MethodTable *interfaceType,
MethodTable *targetType)
{
FCALL_CONTRACT;

SString strMethodName;
SString strInterfaceName;
SString strTargetClassName;

HELPER_METHOD_FRAME_BEGIN_0(); // Set up a frame

TypeString::AppendMethod(strMethodName, method, method->GetMethodInstantiation());
TypeString::AppendType(strInterfaceName, TypeHandle(interfaceType));
TypeString::AppendType(strTargetClassName, targetType);

HELPER_METHOD_FRAME_END(); // Set up a frame

FCThrowExVoid(
kAmbiguousImplementationException,
IDS_CLASSLOAD_AMBIGUOUS_OVERRIDE,
strMethodName,
strInterfaceName,
strTargetClassName);
}
HCIMPLEND

HCIMPL1(Object*, JIT_GetRuntimeFieldStub, CORINFO_FIELD_HANDLE field)
{
FCALL_CONTRACT;
Expand Down
73 changes: 63 additions & 10 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2910,6 +2910,7 @@ void CEEInfo::ComputeRuntimeLookupForSharedGenericToken(DictionaryEntryKind entr

MethodDesc* pContextMD = GetMethodFromContext(pResolvedToken->tokenContext);
MethodTable* pContextMT = pContextMD->GetMethodTable();
bool isStaticVirtual = (pConstrainedResolvedToken != nullptr && pContextMD != nullptr && pContextMD->IsStatic());

// There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup.
if (!pContextMD->IsSharedByGenericInstantiations())
Expand Down Expand Up @@ -4842,6 +4843,8 @@ void CEEInfo::getCallInfo(
constrainedType = TypeHandle(pConstrainedResolvedToken->hClass);
}

BOOL fIsStaticVirtualMethod = (pConstrainedResolvedToken != NULL && pMD->IsInterface() && pMD->IsStatic());

BOOL fResolvedConstraint = FALSE;
BOOL fForceUseRuntimeLookup = FALSE;

Expand Down Expand Up @@ -4921,14 +4924,28 @@ void CEEInfo::getCallInfo(

exactType = constrainedType;
}
#ifdef FEATURE_DEFAULT_INTERFACES
else if (directMethod && pMD->IsStatic())
{
// Default interface implementation of static virtual method
pMDAfterConstraintResolution = directMethod;
fResolvedConstraint = TRUE;
pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
exactType = directMethod->GetMethodTable();
}
#endif
else if (constrainedType.IsValueType())
{
pResult->thisTransform = CORINFO_BOX_THIS;
}
else
else if (!fIsStaticVirtualMethod)
{
pResult->thisTransform = CORINFO_DEREF_THIS;
}
else
{
pResult->thisTransform = CORINFO_NO_THIS_TRANSFORM;
}
}

//
Expand All @@ -4938,10 +4955,15 @@ void CEEInfo::getCallInfo(
MethodDesc * pTargetMD = pMDAfterConstraintResolution;
DWORD dwTargetMethodAttrs = pTargetMD->GetAttrs();

pResult->exactContextNeedsRuntimeLookup = (!constrainedType.IsNull() && constrainedType.IsCanonicalSubtype());

if (pTargetMD->HasMethodInstantiation())
{
pResult->contextHandle = MAKE_METHODCONTEXT(pTargetMD);
pResult->exactContextNeedsRuntimeLookup = pTargetMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(pTargetMD->GetMethodInstantiation());
if (pTargetMD->GetMethodTable()->IsSharedByGenericInstantiations() || TypeHandle::IsCanonicalSubtypeInstantiation(pTargetMD->GetMethodInstantiation()))
{
pResult->exactContextNeedsRuntimeLookup = TRUE;
}
}
else
{
Expand All @@ -4955,7 +4977,10 @@ void CEEInfo::getCallInfo(
}

pResult->contextHandle = MAKE_CLASSCONTEXT(exactType.AsPtr());
pResult->exactContextNeedsRuntimeLookup = exactType.IsSharedByGenericInstantiations();
if (exactType.IsSharedByGenericInstantiations())
{
pResult->exactContextNeedsRuntimeLookup = TRUE;
}

// Use main method as the context as long as the methods are called on the same type
if (pResult->exactContextNeedsRuntimeLookup &&
Expand All @@ -4978,7 +5003,7 @@ void CEEInfo::getCallInfo(
bool directCall = false;
bool resolvedCallVirt = false;

if (flags & CORINFO_CALLINFO_LDFTN)
if ((flags & CORINFO_CALLINFO_LDFTN) && (!fIsStaticVirtualMethod || fResolvedConstraint))
{
// Since the ldvirtftn instruction resolves types
// at run-time we do this earlier than ldftn. The
Expand All @@ -5003,12 +5028,12 @@ void CEEInfo::getCallInfo(
}
else
// Static methods are always direct calls
if (pTargetMD->IsStatic())
if (pTargetMD->IsStatic() && (!fIsStaticVirtualMethod || fResolvedConstraint))
{
directCall = true;
}
else
if (!(flags & CORINFO_CALLINFO_CALLVIRT) || fResolvedConstraint)
if ((!fIsStaticVirtualMethod && !(flags & CORINFO_CALLINFO_CALLVIRT)) || fResolvedConstraint)
{
directCall = true;
}
Expand Down Expand Up @@ -5136,13 +5161,13 @@ void CEEInfo::getCallInfo(
// All virtual calls which take method instantiations must
// currently be implemented by an indirect call via a runtime-lookup
// function pointer
else if (pTargetMD->HasMethodInstantiation())
else if (pTargetMD->HasMethodInstantiation() && !fIsStaticVirtualMethod)
{
pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN; // stub dispatch can't handle generic method calls yet
pResult->nullInstanceCheck = TRUE;
}
// Non-interface dispatches go through the vtable.
else if (!pTargetMD->IsInterface())
else if (!pTargetMD->IsInterface() && !fIsStaticVirtualMethod)
{
pResult->kind = CORINFO_VIRTUALCALL_VTABLE;
pResult->nullInstanceCheck = TRUE;
Expand All @@ -5155,6 +5180,10 @@ void CEEInfo::getCallInfo(
pResult->kind = CORINFO_VIRTUALCALL_LDVIRTFTN;
#else // STUB_DISPATCH_PORTABLE
pResult->kind = CORINFO_VIRTUALCALL_STUB;
if (fIsStaticVirtualMethod)
{
pResult->kind = CORINFO_CALL_CODE_POINTER;
}

// We can't make stub calls when we need exact information
// for interface calls from shared code.
Expand All @@ -5163,9 +5192,9 @@ void CEEInfo::getCallInfo(
{
_ASSERTE(!m_pMethodBeingCompiled->IsDynamicMethod());

ComputeRuntimeLookupForSharedGenericToken(DispatchStubAddrSlot,
ComputeRuntimeLookupForSharedGenericToken(fIsStaticVirtualMethod ? ConstrainedMethodEntrySlot : DispatchStubAddrSlot,
pResolvedToken,
NULL,
pConstrainedResolvedToken,
pMD,
&pResult->stubLookup);
}
Expand Down Expand Up @@ -5390,6 +5419,30 @@ void CEEInfo::getCallInfo(
signatureKind = SK_CALLSITE;
}
getMethodSigInternal(pResult->hMethod, &pResult->sig, (pResult->hMethod == pResolvedToken->hMethod) ? pResolvedToken->hClass : NULL, signatureKind);
if (fIsStaticVirtualMethod && !fResolvedConstraint)
{
if (pResult->exactContextNeedsRuntimeLookup)
{
// Runtime lookup for static virtual methods always returns exact call addresses not requiring the instantiation argument
pResult->sig.callConv = (CorInfoCallConv)(pResult->sig.callConv & ~CORINFO_CALLCONV_PARAMTYPE);
}
else
{
// Unresolved static virtual method in the absence of shared generics means
// that the runtime needs to throw when reaching the call. SVM resolution within
// shared generics is covered by the ConstrainedMethodEntrySlot dictionary entry.
pResult->kind = CORINFO_CALL;
pResult->accessAllowed = CORINFO_ACCESS_ILLEGAL;
pResult->callsiteCalloutHelper.helperNum = CORINFO_HELP_STATIC_VIRTUAL_AMBIGUOUS_RESOLUTION;
pResult->callsiteCalloutHelper.numArgs = 3;
pResult->callsiteCalloutHelper.args[0].methodHandle = (CORINFO_METHOD_HANDLE)pMD;
pResult->callsiteCalloutHelper.args[0].argType = CORINFO_HELPER_ARG_TYPE_Method;
pResult->callsiteCalloutHelper.args[1].classHandle = (CORINFO_CLASS_HANDLE)th.AsMethodTable();
pResult->callsiteCalloutHelper.args[1].argType = CORINFO_HELPER_ARG_TYPE_Class;
pResult->callsiteCalloutHelper.args[2].classHandle = (CORINFO_CLASS_HANDLE)constrainedType.AsMethodTable();
pResult->callsiteCalloutHelper.args[2].argType = CORINFO_HELPER_ARG_TYPE_Class;
}
}

if (flags & CORINFO_CALLINFO_VERIFICATION)
{
Expand Down
Loading