Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions src/coreclr/jit/fgbasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1143,9 +1143,9 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, Fixed
{
OPCODE actualOpcode = impGetNonPrefixOpcode(codeAddr, codeEndp);

if (actualOpcode != CEE_CALLVIRT)
if (actualOpcode != CEE_CALLVIRT && actualOpcode != CEE_CALL && actualOpcode != CEE_LDFTN)
{
BADCODE("constrained. has to be followed by callvirt");
BADCODE("constrained. has to be followed by callvirt, call or ldftn");
}
}
goto OBSERVE_OPCODE;
Expand Down
7 changes: 4 additions & 3 deletions src/coreclr/jit/importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13862,7 +13862,8 @@ void Compiler::impImportBlockCode(BasicBlock* block)

JITDUMP(" %08X", resolvedToken.token);

eeGetCallInfo(&resolvedToken, nullptr /* constraint typeRef*/,
eeGetCallInfo(&resolvedToken,
(prefixFlags & PREFIX_CONSTRAINED) ? &constrainedResolvedToken : nullptr,
addVerifyFlag(combine(CORINFO_CALLINFO_SECURITYCHECKS, CORINFO_CALLINFO_LDFTN)),
&callInfo);

Expand Down Expand Up @@ -14033,9 +14034,9 @@ void Compiler::impImportBlockCode(BasicBlock* block)

{
OPCODE actualOpcode = impGetNonPrefixOpcode(codeAddr, codeEndp);
if (actualOpcode != CEE_CALLVIRT)
if (actualOpcode != CEE_CALLVIRT && actualOpcode != CEE_CALL && actualOpcode != CEE_LDFTN)
{
BADCODE("constrained. has to be followed by callvirt");
BADCODE("constrained. has to be followed by callvirt, call or ldftn");
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5118,7 +5118,7 @@ void CEEInfo::getCallInfo(
TypeHandle exactType = TypeHandle(pResolvedToken->hClass);

TypeHandle constrainedType;
if ((flags & CORINFO_CALLINFO_CALLVIRT) && (pConstrainedResolvedToken != NULL))
if (pConstrainedResolvedToken != NULL)
{
constrainedType = TypeHandle(pConstrainedResolvedToken->hClass);
}
Expand Down
14 changes: 14 additions & 0 deletions src/coreclr/vm/methodtable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9170,6 +9170,15 @@ MethodDesc *MethodTable::GetDefaultConstructor(BOOL forceBoxedEntryPoint /* = FA
FALSE /* no allowInstParam */);
}

//==========================================================================================
// Finds the (non-unboxing) MethodDesc that implements the interface virtual static method pInterfaceMD.
MethodDesc *
MethodTable::ResolveVirtualStaticMethod(MethodDesc* pInterfaceMD)
{
// TODO
COMPlusThrow(kTypeLoadException, E_NOTIMPL);
}

//==========================================================================================
// Finds the (non-unboxing) MethodDesc that implements the interface method pInterfaceMD.
//
Expand All @@ -9189,6 +9198,11 @@ MethodTable::TryResolveConstraintMethodApprox(
GC_TRIGGERS;
} CONTRACTL_END;

if (pInterfaceMD->IsStatic())
{
return ResolveVirtualStaticMethod(pInterfaceMD);
}

// We can't resolve constraint calls effectively for reference types, and there's
// not a lot of perf. benefit in doing it anyway.
//
Expand Down
8 changes: 7 additions & 1 deletion src/coreclr/vm/methodtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -1557,6 +1557,9 @@ class MethodTable

inline WORD GetNumNonVirtualSlots();

inline BOOL HasVirtualStaticMethods() const;
inline void SetHasVirtualStaticMethods();

inline WORD GetNumVirtuals()
{
LIMITED_METHOD_DAC_CONTRACT;
Expand Down Expand Up @@ -2276,6 +2279,9 @@ class MethodTable
#endif // FEATURE_COMINTEROP


// Resolve virtual static interface method pInterfaceMD on this type.
MethodDesc *ResolveVirtualStaticMethod(MethodDesc* pInterfaceMD);

// Try a partial resolve of the constraint call, up to generic code sharing.
//
// Note that this will not necessarily resolve the call exactly, since we might be compiling
Expand Down Expand Up @@ -3655,7 +3661,7 @@ public :
enum_flag_RequiresDispatchTokenFat = 0x0200,

enum_flag_HasCctor = 0x0400,
// enum_flag_unused = 0x0800,
enum_flag_HasVirtualStaticMethods = 0x0800,

#ifdef FEATURE_64BIT_ALIGNMENT
enum_flag_RequiresAlign8 = 0x1000, // Type requires 8-byte alignment (only set on platforms that require this and don't get it implicitly)
Expand Down
14 changes: 14 additions & 0 deletions src/coreclr/vm/methodtable.inl
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,20 @@ inline INT32 MethodTable::MethodIterator::GetNumMethods() const
return m_iMethods;
}

//==========================================================================================
inline BOOL MethodTable::HasVirtualStaticMethods() const
{
WRAPPER_NO_CONTRACT;
return GetFlag(enum_flag_HasVirtualStaticMethods);
}

//==========================================================================================
inline void MethodTable::SetHasVirtualStaticMethods()
{
WRAPPER_NO_CONTRACT;
return SetFlag(enum_flag_HasVirtualStaticMethods);
}

//==========================================================================================
// Returns TRUE if it's valid to request data from the current position
inline BOOL MethodTable::MethodIterator::IsValid() const
Expand Down
158 changes: 89 additions & 69 deletions src/coreclr/vm/methodtablebuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2945,7 +2945,15 @@ MethodTableBuilder::EnumerateClassMethods()
}
if(IsMdStatic(dwMemberAttrs))
{
BuildMethodTableThrowException(BFA_VIRTUAL_STATIC_METHOD);
if (fIsClassInterface)
{
bmtProp->fHasVirtualStaticMethods = TRUE;
}
else
{
// Static virtual methods are only allowed to exist in interfaces
BuildMethodTableThrowException(BFA_VIRTUAL_STATIC_METHOD);
}
}
if(strMethodName && (0==strcmp(strMethodName, COR_CTOR_METHOD_NAME)))
{
Expand Down Expand Up @@ -5021,14 +5029,16 @@ MethodTableBuilder::ValidateMethods()

if (it.IsMethodImpl())
{
if (!IsMdVirtual(it.Attrs()))
{ // Non-virtual methods cannot participate in a methodImpl pair.
if (!IsMdVirtual(it.Attrs()) && !IsMdStatic(it.Attrs()))
{
// Non-virtual methods may only participate in a methodImpl pair when
// they are static and they implement a virtual static interface method.
BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MUSTBEVIRTUAL, it.Token());
}
}

// Virtual static methods are not allowed.
if (IsMdStatic(it.Attrs()) && IsMdVirtual(it.Attrs()))
if (IsMdStatic(it.Attrs()) && IsMdVirtual(it.Attrs()) && !IsInterface())
{
BuildMethodTableThrowException(IDS_CLASSLOAD_STATICVIRTUAL, it.Token());
}
Expand Down Expand Up @@ -5297,8 +5307,8 @@ MethodTableBuilder::PlaceVirtualMethods()
DeclaredMethodIterator it(*this);
while (it.Next())
{
if (!IsMdVirtual(it.Attrs()))
{ // Only processing declared virtual methods
if (!IsMdVirtual(it.Attrs()) || IsMdStatic(it.Attrs()))
{ // Only processing declared virtual instance methods
continue;
}

Expand Down Expand Up @@ -5613,12 +5623,11 @@ MethodTableBuilder::ProcessMethodImpls()
DeclaredMethodIterator it(*this);
while (it.Next())
{
// Non-virtual methods cannot be classified as methodImpl - we should have thrown an
// error before reaching this point.
CONSISTENCY_CHECK(!(!IsMdVirtual(it.Attrs()) && it.IsMethodImpl()));

if (!IsMdVirtual(it.Attrs()))
{ // Only virtual methods can participate in methodImpls
if (!IsMdVirtual(it.Attrs()) && it.IsMethodImpl())
{
// Non-virtual methods can only be classified as methodImpl when implementing
// static virtual methods.
CONSISTENCY_CHECK(IsMdStatic(it.Attrs()));
continue;
}

Expand Down Expand Up @@ -6263,75 +6272,80 @@ MethodTableBuilder::PlaceMethodImpls()
// Get the declaration part of the method impl. It will either be a token
// (declaration is on this type) or a method desc.
bmtMethodHandle hDeclMethod = bmtMethodImpl->GetDeclarationMethod(iEntry);
if(hDeclMethod.IsMDMethod())
{
// The declaration is on the type being built
bmtMDMethod * pCurDeclMethod = hDeclMethod.AsMDMethod();

mdToken mdef = pCurDeclMethod->GetMethodSignature().GetToken();
if (bmtMethodImpl->IsBody(mdef))
{ // A method declared on this class cannot be both a decl and an impl
BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES, mdef);
}

if (IsInterface())
{
// Throws
PlaceInterfaceDeclarationOnInterface(
hDeclMethod,
pCurImplMethod,
slots, // Adds override to the slot and replaced arrays.
replaced,
&slotIndex,
dwMaxSlotSize); // Increments count
}
else
{
// Throws
PlaceLocalDeclarationOnClass(
pCurDeclMethod,
pCurImplMethod,
slots, // Adds override to the slot and replaced arrays.
replaced,
&slotIndex,
dwMaxSlotSize); // Increments count
}
}
else
// Don't place static virtual method overrides in the vtable
if (!IsMdStatic(hDeclMethod.GetDeclAttrs()))
{
bmtRTMethod * pCurDeclMethod = hDeclMethod.AsRTMethod();

if (IsInterface())
{
// Throws
PlaceInterfaceDeclarationOnInterface(
hDeclMethod,
pCurImplMethod,
slots, // Adds override to the slot and replaced arrays.
replaced,
&slotIndex,
dwMaxSlotSize); // Increments count
}
else
if(hDeclMethod.IsMDMethod())
{
// Do not use pDecl->IsInterface here as that asks the method table and the MT may not yet be set up.
if (pCurDeclMethod->GetOwningType()->IsInterface())
// The declaration is on the type being built
bmtMDMethod * pCurDeclMethod = hDeclMethod.AsMDMethod();

mdToken mdef = pCurDeclMethod->GetMethodSignature().GetToken();
if (bmtMethodImpl->IsBody(mdef))
{ // A method declared on this class cannot be both a decl and an impl
BuildMethodTableThrowException(IDS_CLASSLOAD_MI_MULTIPLEOVERRIDES, mdef);
}

if (IsInterface())
{
// Throws
PlaceInterfaceDeclarationOnClass(
pCurDeclMethod,
pCurImplMethod);
PlaceInterfaceDeclarationOnInterface(
hDeclMethod,
pCurImplMethod,
slots, // Adds override to the slot and replaced arrays.
replaced,
&slotIndex,
dwMaxSlotSize); // Increments count
}
else
{
// Throws
PlaceParentDeclarationOnClass(
PlaceLocalDeclarationOnClass(
pCurDeclMethod,
pCurImplMethod,
slots,
slots, // Adds override to the slot and replaced arrays.
replaced,
&slotIndex,
dwMaxSlotSize); // Increments count
}
}
else
{
bmtRTMethod * pCurDeclMethod = hDeclMethod.AsRTMethod();

if (IsInterface())
{
// Throws
PlaceInterfaceDeclarationOnInterface(
hDeclMethod,
pCurImplMethod,
slots, // Adds override to the slot and replaced arrays.
replaced,
&slotIndex,
dwMaxSlotSize); // Increments count
dwMaxSlotSize); // Increments count
}
else
{
// Do not use pDecl->IsInterface here as that asks the method table and the MT may not yet be set up.
if (pCurDeclMethod->GetOwningType()->IsInterface())
{
// Throws
PlaceInterfaceDeclarationOnClass(
pCurDeclMethod,
pCurImplMethod);
}
else
{
// Throws
PlaceParentDeclarationOnClass(
pCurDeclMethod,
pCurImplMethod,
slots,
replaced,
&slotIndex,
dwMaxSlotSize); // Increments count
}
}
}
}
Expand Down Expand Up @@ -9783,7 +9797,8 @@ MethodTable * MethodTableBuilder::AllocateNewMT(
LoaderAllocator *pAllocator,
BOOL isInterface,
BOOL fDynamicStatics,
BOOL fHasGenericsStaticsInfo
BOOL fHasGenericsStaticsInfo,
BOOL fHasVirtualStaticMethods
#ifdef FEATURE_COMINTEROP
, BOOL fHasDynamicInterfaceMap
#endif
Expand Down Expand Up @@ -9926,6 +9941,10 @@ MethodTable * MethodTableBuilder::AllocateNewMT(

// initialize the total number of slots
pMT->SetNumVirtuals(static_cast<WORD>(dwVirtuals));
if (fHasVirtualStaticMethods)
{
pMT->SetHasVirtualStaticMethods();
}

pMT->SetParentMethodTable(pMTParent);

Expand Down Expand Up @@ -10103,6 +10122,7 @@ MethodTableBuilder::SetupMethodTable2(
IsInterface(),
bmtProp->fDynamicStatics,
bmtProp->fGenericsStatics,
bmtProp->fHasVirtualStaticMethods,
#ifdef FEATURE_COMINTEROP
fHasDynamicInterfaceMap,
#endif
Expand Down
6 changes: 4 additions & 2 deletions src/coreclr/vm/methodtablebuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1325,6 +1325,7 @@ class MethodTableBuilder
bool fIsEnum;
bool fNoSanityChecks;
bool fSparse; // Set to true if a sparse interface is being used.
bool fHasVirtualStaticMethods; // Set to true if the interface type declares virtual static methods.

// Com Interop, ComWrapper classes extend from ComObject
bool fIsComObjectType; // whether this class is an instance of ComObject class
Expand Down Expand Up @@ -1496,7 +1497,7 @@ class MethodTableBuilder
AddNonVirtualMethod(bmtMDMethod * pMethod)
{
INDEBUG(SealVirtualSlotSection());
CONSISTENCY_CHECK(!IsMdVirtual(pMethod->GetDeclAttrs()));
CONSISTENCY_CHECK(!IsMdVirtual(pMethod->GetDeclAttrs()) || IsMdStatic(pMethod->GetDeclAttrs()));
pMethod->SetSlotIndex(pSlotTable->GetSlotCount());
if (!pSlotTable->AddMethodSlot(bmtMethodSlot(pMethod, pMethod)))
return false;
Expand Down Expand Up @@ -2984,7 +2985,8 @@ class MethodTableBuilder
LoaderAllocator *pAllocator,
BOOL isIFace,
BOOL fDynamicStatics,
BOOL fHasGenericsStaticsInfo
BOOL fHasGenericsStaticsInfo,
BOOL fHasVirtualStaticMethods
#ifdef FEATURE_COMINTEROP
, BOOL bHasDynamicInterfaceMap
#endif
Expand Down