Skip to content
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

[CoreCLR and native AOT] UnsafeAccessorAttribute supports generic parameters #99468

Merged
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -686,27 +686,27 @@ private ILToken NewToken(object value, int tokenType)

public ILToken NewToken(TypeDesc value)
{
return NewToken(value, 0x01000000);
return NewToken(value, 0x01000000); // mdtTypeRef
}

public ILToken NewToken(MethodDesc value)
{
return NewToken(value, 0x0a000000);
return NewToken(value, 0x0a000000); // mdtMemberRef
}

public ILToken NewToken(FieldDesc value)
{
return NewToken(value, 0x0a000000);
return NewToken(value, 0x0a000000); // mdtMemberRef
}

public ILToken NewToken(string value)
{
return NewToken(value, 0x70000000);
return NewToken(value, 0x70000000); // mdtString
}

public ILToken NewToken(MethodSignature value)
{
return NewToken(value, 0x11000000);
return NewToken(value, 0x11000000); // mdtSignature
}

public ILLocalVariable NewLocal(TypeDesc localType, bool isPinned = false)
Expand Down
59 changes: 47 additions & 12 deletions src/coreclr/tools/Common/TypeSystem/IL/UnsafeAccessors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ public static MethodIL TryGetIL(EcmaMethod method)
return GenerateAccessorBadImageFailure(method);
}

// Block generic support early
if (method.HasInstantiation || method.OwningType.HasInstantiation)
{
return GenerateAccessorBadImageFailure(method);
}

if (!TryParseUnsafeAccessorAttribute(method, decodedAttribute.Value, out UnsafeAccessorKind kind, out string name))
{
return GenerateAccessorBadImageFailure(method);
Expand Down Expand Up @@ -232,15 +226,22 @@ private static bool ValidateTargetType(TypeDesc targetTypeMaybe, out TypeDesc va
targetType = null;
}

// We do not support signature variables as a target (for example, VAR and MVAR).
if (targetType is SignatureVariable)
{
targetType = null;
}

validated = targetType;
return validated != null;
}

private static bool DoesMethodMatchUnsafeAccessorDeclaration(ref GenerationContext context, MethodDesc method, bool ignoreCustomModifiers)
private static bool DoesMethodMatchUnsafeAccessorDeclaration(
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
ref GenerationContext context,
MethodSignature declSig,
MethodSignature maybeSig,
bool ignoreCustomModifiers)
{
MethodSignature declSig = context.Declaration.Signature;
MethodSignature maybeSig = method.Signature;

// Check if we need to also validate custom modifiers.
// If we are, do it first.
if (!ignoreCustomModifiers)
Expand Down Expand Up @@ -366,10 +367,22 @@ private static bool DoesMethodMatchUnsafeAccessorDeclaration(ref GenerationConte
return true;
}

private static bool TrySetTargetMethod(ref GenerationContext context, string name, out bool isAmbiguous, bool ignoreCustomModifiers = true)
private static unsafe bool TrySetTargetMethod(ref GenerationContext context, string name, out bool isAmbiguous, bool ignoreCustomModifiers = true)
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
TypeDesc targetType = context.TargetType;

// Build up a substitution Instantiation to use when looking up methods involving generics.
Instantiation substitutionForSig = default;
if (targetType.Instantiation.Length > 0)
{
TypeDesc[] types = new TypeDesc[targetType.Instantiation.Length];
for (int i = 0; i < types.Length; ++i)
{
types[i] = targetType.Context.GetSignatureVariable(i, true);
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
}
substitutionForSig = new Instantiation(types);
}

MethodDesc targetMaybe = null;
foreach (MethodDesc md in targetType.GetMethods())
{
Expand All @@ -385,8 +398,18 @@ private static bool TrySetTargetMethod(ref GenerationContext context, string nam
continue;
}

// Create a substitution signature for the current signature if appropriate.
MethodSignature sigToCompare = md.Signature;
if (!substitutionForSig.IsNull)
{
sigToCompare = sigToCompare.ApplySubstitution(substitutionForSig);
}

// Check signature
if (!DoesMethodMatchUnsafeAccessorDeclaration(ref context, md, ignoreCustomModifiers))
if (!DoesMethodMatchUnsafeAccessorDeclaration(ref context,
context.Declaration.Signature,
sigToCompare,
ignoreCustomModifiers))
{
continue;
}
Expand All @@ -411,6 +434,18 @@ private static bool TrySetTargetMethod(ref GenerationContext context, string nam
}

isAmbiguous = false;

if (targetMaybe != null && targetMaybe.HasInstantiation)
{
TypeDesc[] methodInstantiation = new TypeDesc[targetMaybe.Instantiation.Length];
for (int i = 0; i < methodInstantiation.Length; ++i)
{
methodInstantiation[i] = targetMaybe.Context.GetSignatureVariable(i, true);
}

targetMaybe = targetMaybe.Context.GetInstantiatedMethod(targetMaybe, new Instantiation(methodInstantiation));
}

context.TargetMethod = targetMaybe;
return context.TargetMethod != null;
}
Expand Down
11 changes: 4 additions & 7 deletions src/coreclr/vm/callconvbuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,15 +298,12 @@ namespace
{
STANDARD_VM_CONTRACT;

TypeHandle type;
MethodDesc* pMD;
FieldDesc* pFD;
ResolvedToken resolved{};
pResolver->ResolveToken(token, &resolved);

pResolver->ResolveToken(token, &type, &pMD, &pFD);
_ASSERTE(!resolved.TypeHandle.IsNull());

_ASSERTE(!type.IsNull());

*nameOut = type.GetMethodTable()->GetFullyQualifiedNameInfo(namespaceOut);
*nameOut = resolved.TypeHandle.GetMethodTable()->GetFullyQualifiedNameInfo(namespaceOut);

return S_OK;
}
Expand Down
31 changes: 21 additions & 10 deletions src/coreclr/vm/dynamicmethod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1325,7 +1325,7 @@ void LCGMethodResolver::AddToUsedIndCellList(BYTE * indcell)

}

void LCGMethodResolver::ResolveToken(mdToken token, TypeHandle * pTH, MethodDesc ** ppMD, FieldDesc ** ppFD)
void LCGMethodResolver::ResolveToken(mdToken token, ResolvedToken* resolvedToken)
{
STANDARD_VM_CONTRACT;

Expand All @@ -1335,24 +1335,35 @@ void LCGMethodResolver::ResolveToken(mdToken token, TypeHandle * pTH, MethodDesc

DECLARE_ARGHOLDER_ARRAY(args, 5);

TypeHandle handle;
MethodDesc* pMD = NULL;
FieldDesc* pFD = NULL;
args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(ObjectFromHandle(m_managedResolver));
args[ARGNUM_1] = DWORD_TO_ARGHOLDER(token);
args[ARGNUM_2] = pTH;
args[ARGNUM_3] = ppMD;
args[ARGNUM_4] = ppFD;
args[ARGNUM_2] = &handle;
args[ARGNUM_3] = &pMD;
args[ARGNUM_4] = &pFD;

CALL_MANAGED_METHOD_NORET(args);

_ASSERTE(*ppMD == NULL || *ppFD == NULL);
_ASSERTE(pMD == NULL || pFD == NULL);

if (pTH->IsNull())
if (handle.IsNull())
{
if (*ppMD != NULL) *pTH = (*ppMD)->GetMethodTable();
else
if (*ppFD != NULL) *pTH = (*ppFD)->GetEnclosingMethodTable();
if (pMD != NULL)
{
handle = pMD->GetMethodTable();
}
else if (pFD != NULL)
{
handle = pFD->GetEnclosingMethodTable();
}
}

_ASSERTE(!pTH->IsNull());
_ASSERTE(!handle.IsNull());
resolvedToken->TypeHandle = handle;
resolvedToken->Method = pMD;
resolvedToken->Field = pFD;
}

//---------------------------------------------------------------------------------------
Expand Down
13 changes: 11 additions & 2 deletions src/coreclr/vm/dynamicmethod.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ class ChunkAllocator
void Delete();
};

struct ResolvedToken final
{
TypeHandle TypeHandle;
SigPointer TypeSignature;
SigPointer MethodSignature;
MethodDesc* Method;
FieldDesc* Field;
};

//---------------------------------------------------------------------------------------
//
class DynamicResolver
Expand Down Expand Up @@ -90,7 +99,7 @@ class DynamicResolver
virtual OBJECTHANDLE ConstructStringLiteral(mdToken metaTok) = 0;
virtual BOOL IsValidStringRef(mdToken metaTok) = 0;
virtual STRINGREF GetStringLiteral(mdToken metaTok) = 0;
virtual void ResolveToken(mdToken token, TypeHandle * pTH, MethodDesc ** ppMD, FieldDesc ** ppFD) = 0;
virtual void ResolveToken(mdToken token, ResolvedToken* resolvedToken) = 0;
virtual SigPointer ResolveSignature(mdToken token) = 0;
virtual SigPointer ResolveSignatureForVarArg(mdToken token) = 0;
virtual void GetEHInfo(unsigned EHnumber, CORINFO_EH_CLAUSE* clause) = 0;
Expand Down Expand Up @@ -141,7 +150,7 @@ class LCGMethodResolver : public DynamicResolver

OBJECTHANDLE ConstructStringLiteral(mdToken metaTok);
BOOL IsValidStringRef(mdToken metaTok);
void ResolveToken(mdToken token, TypeHandle * pTH, MethodDesc ** ppMD, FieldDesc ** ppFD);
void ResolveToken(mdToken token, ResolvedToken* resolvedToken);
SigPointer ResolveSignature(mdToken token);
SigPointer ResolveSignatureForVarArg(mdToken token);
void GetEHInfo(unsigned EHnumber, CORINFO_EH_CLAUSE* clause);
Expand Down
66 changes: 56 additions & 10 deletions src/coreclr/vm/ilstubresolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,41 +133,87 @@ STRINGREF ILStubResolver::GetStringLiteral(mdToken metaTok)
return NULL;
}

void ILStubResolver::ResolveToken(mdToken token, TypeHandle * pTH, MethodDesc ** ppMD, FieldDesc ** ppFD)
void ILStubResolver::ResolveToken(mdToken token, ResolvedToken* resolvedToken)
{
STANDARD_VM_CONTRACT;

*pTH = NULL;
*ppMD = NULL;
*ppFD = NULL;
_ASSERTE(resolvedToken != NULL);

switch (TypeFromToken(token))
{
case mdtMethodDef:
{
MethodDesc* pMD = m_pCompileTimeState->m_tokenLookupMap.LookupMethodDef(token);
_ASSERTE(pMD);
*ppMD = pMD;
*pTH = TypeHandle(pMD->GetMethodTable());
resolvedToken->Method = pMD;
resolvedToken->TypeHandle = TypeHandle(pMD->GetMethodTable());
}
break;

case mdtTypeDef:
{
TypeHandle typeHnd = m_pCompileTimeState->m_tokenLookupMap.LookupTypeDef(token);
_ASSERTE(!typeHnd.IsNull());
*pTH = typeHnd;
resolvedToken->TypeHandle = typeHnd;
}
break;

case mdtFieldDef:
{
FieldDesc* pFD = m_pCompileTimeState->m_tokenLookupMap.LookupFieldDef(token);
_ASSERTE(pFD);
*ppFD = pFD;
*pTH = TypeHandle(pFD->GetEnclosingMethodTable());
resolvedToken->Field = pFD;
resolvedToken->TypeHandle = TypeHandle(pFD->GetEnclosingMethodTable());
}
break;

#if !defined(DACCESS_COMPILE)
case mdtMemberRef:
{
TokenLookupMap::MemberRefEntry entry = m_pCompileTimeState->m_tokenLookupMap.LookupMemberRef(token);
if (entry.Type == mdtFieldDef)
{
_ASSERTE(entry.Entry.Field != NULL);

if (entry.ClassSignatureToken != mdTokenNil)
resolvedToken->TypeSignature = m_pCompileTimeState->m_tokenLookupMap.LookupSig(entry.ClassSignatureToken);

resolvedToken->Field = entry.Entry.Field;
resolvedToken->TypeHandle = TypeHandle(entry.Entry.Field->GetApproxEnclosingMethodTable());
}
else
{
_ASSERTE(entry.Type == mdtMethodDef);
_ASSERTE(entry.Entry.Method != NULL);

if (entry.ClassSignatureToken != mdTokenNil)
resolvedToken->TypeSignature = m_pCompileTimeState->m_tokenLookupMap.LookupSig(entry.ClassSignatureToken);

resolvedToken->Method = entry.Entry.Method;
MethodTable* pMT = entry.Entry.Method->GetMethodTable();
_ASSERTE(!pMT->ContainsGenericVariables());
resolvedToken->TypeHandle = TypeHandle(pMT);
}
}
break;

case mdtMethodSpec:
{
TokenLookupMap::MethodSpecEntry entry = m_pCompileTimeState->m_tokenLookupMap.LookupMethodSpec(token);
_ASSERTE(entry.Method != NULL);

if (entry.ClassSignatureToken != mdTokenNil)
resolvedToken->TypeSignature = m_pCompileTimeState->m_tokenLookupMap.LookupSig(entry.ClassSignatureToken);

if (entry.MethodSignatureToken != mdTokenNil)
resolvedToken->MethodSignature = m_pCompileTimeState->m_tokenLookupMap.LookupSig(entry.MethodSignatureToken);

resolvedToken->Method = entry.Method;
MethodTable* pMT = entry.Method->GetMethodTable();
_ASSERTE(!pMT->ContainsGenericVariables());
resolvedToken->TypeHandle = TypeHandle(pMT);
}
break;
#endif // !defined(DACCESS_COMPILE)

default:
UNREACHABLE_MSG("unexpected metadata token type");
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/ilstubresolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class ILStubResolver : DynamicResolver
OBJECTHANDLE ConstructStringLiteral(mdToken metaTok);
BOOL IsValidStringRef(mdToken metaTok);
STRINGREF GetStringLiteral(mdToken metaTok);
void ResolveToken(mdToken token, TypeHandle * pTH, MethodDesc ** ppMD, FieldDesc ** ppFD);
void ResolveToken(mdToken token, ResolvedToken* resolvedToken);
SigPointer ResolveSignature(mdToken token);
SigPointer ResolveSignatureForVarArg(mdToken token);
void GetEHInfo(unsigned EHnumber, CORINFO_EH_CLAUSE* clause);
Expand Down