Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Enable generic attributes #9189

Merged
merged 20 commits into from
Apr 17, 2018
Merged
Show file tree
Hide file tree
Changes from 19 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
10 changes: 5 additions & 5 deletions src/mscorlib/src/System/Reflection/CustomAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1557,7 +1557,7 @@ private unsafe static object[] GetCustomAttributes(
// Create custom attribute object
if (ctorHasParameters)
{
attribute = CreateCaObject(decoratedModule, ctor, ref blobStart, blobEnd, out cNamedArgs);
attribute = CreateCaObject(decoratedModule, attributeType, ctor, ref blobStart, blobEnd, out cNamedArgs);
}
else
{
Expand Down Expand Up @@ -1717,7 +1717,7 @@ private unsafe static bool FilterCustomAttributeRecord(
if (ctorHasParameters)
{
// Resolve method ctor token found in decorated decoratedModule scope
ctor = ModuleHandle.ResolveMethodHandleInternal(decoratedModule.GetNativeHandle(), caRecord.tkCtor);
ctor = decoratedModule.ResolveMethod(caRecord.tkCtor, attributeType.GenericTypeArguments, null).MethodHandle.GetMethodInfo();
}
else
{
Expand Down Expand Up @@ -1848,13 +1848,13 @@ private static void ParseAttributeUsageAttribute(
}

[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static unsafe extern Object _CreateCaObject(RuntimeModule pModule, IRuntimeMethodInfo pCtor, byte** ppBlob, byte* pEndBlob, int* pcNamedArgs);
private static unsafe Object CreateCaObject(RuntimeModule module, IRuntimeMethodInfo ctor, ref IntPtr blob, IntPtr blobEnd, out int namedArgs)
private static unsafe extern Object _CreateCaObject(RuntimeModule pModule, RuntimeType type, IRuntimeMethodInfo pCtor, byte** ppBlob, byte* pEndBlob, int* pcNamedArgs);
private static unsafe Object CreateCaObject(RuntimeModule module, RuntimeType type, IRuntimeMethodInfo ctor, ref IntPtr blob, IntPtr blobEnd, out int namedArgs)
{
byte* pBlob = (byte*)blob;
byte* pBlobEnd = (byte*)blobEnd;
int cNamedArgs;
object ca = _CreateCaObject(module, ctor, &pBlob, pBlobEnd, &cNamedArgs);
object ca = _CreateCaObject(module, type, ctor, &pBlob, pBlobEnd, &cNamedArgs);
blob = (IntPtr)pBlob;
namedArgs = cNamedArgs;
return ca;
Expand Down
34 changes: 34 additions & 0 deletions src/vm/callhelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,21 @@ class MethodDescCallSite
m_argIt.ForceSigWalk();
}

void DefaultInit(TypeHandle th)
{
CONTRACTL
{
MODE_ANY;
GC_TRIGGERS;
THROWS;
}
CONTRACTL_END;

m_pCallTarget = m_pMD->GetCallTarget(NULL, th);

m_argIt.ForceSigWalk();
}

#ifdef FEATURE_INTERPRETER
public:
void CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT *pReturnValue, int cbReturnValue, bool transitionToPreemptive = false);
Expand Down Expand Up @@ -234,6 +249,25 @@ class MethodDescCallSite
DefaultInit(porProtectedThis);
}

MethodDescCallSite(MethodDesc* pMD, TypeHandle th) :
m_pMD(pMD),
m_methodSig(pMD, th),
m_argIt(&m_methodSig)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_COOPERATIVE;
}
CONTRACTL_END;

// We don't have a "this" pointer - ensure that we have activated the containing module
m_pMD->EnsureActive();

DefaultInit(th);
}

//
// Only use this constructor if you're certain you know where
// you're going and it cannot be affected by generics/virtual
Expand Down
20 changes: 8 additions & 12 deletions src/vm/customattribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,7 @@ FCIMPL2(Object*, RuntimeTypeHandle::CreateCaInstance, ReflectClassBaseObject* pC
CONTRACTL {
FCALL_CHECK;
PRECONDITION(CheckPointer(pCaTypeUNSAFE));
PRECONDITION(!pCaTypeUNSAFE->GetType().IsGenericVariable());
PRECONDITION(!pCaTypeUNSAFE->GetType().IsGenericVariable());
Copy link

Choose a reason for hiding this comment

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

I believe this precondition is still valid. This is guarding against something like this:

 class G<T>
 {
      [T]   // <-- still disallowed, correct?
      class Inner {}
 }

Copy link
Author

Choose a reason for hiding this comment

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

@atsushikan You right sorry I revert this delete and validated it's still work

PRECONDITION(pCaTypeUNSAFE->GetType().IsValueType() || CheckPointer(pCtorUNSAFE));
}
CONTRACTL_END;
Expand All @@ -694,10 +694,6 @@ FCIMPL2(Object*, RuntimeTypeHandle::CreateCaInstance, ReflectClassBaseObject* pC
PRECONDITION(
(!pCtor && gc.refCaType->GetType().IsValueType() && !gc.refCaType->GetType().GetMethodTable()->HasDefaultConstructor()) ||
(pCtor == gc.refCaType->GetType().GetMethodTable()->GetDefaultConstructor()));

// If we relax this, we need to insure custom attributes construct properly for Nullable<T>
if (gc.refCaType->GetType().HasInstantiation())
COMPlusThrow(kNotSupportedException, W("Argument_GenericsInvalid"));

gc.o = pCaMT->Allocate();
Copy link
Member

Choose a reason for hiding this comment

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

How does this work for Nullable types that this comment is talking about?

Copy link
Author

Choose a reason for hiding this comment

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

If you mean that the generic argument is nullable so I tried with int? and it works great too


Expand Down Expand Up @@ -731,16 +727,20 @@ FCIMPL2(Object*, RuntimeTypeHandle::CreateCaInstance, ReflectClassBaseObject* pC
}
FCIMPLEND

FCIMPL5(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs)
FCIMPL6(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectClassBaseObject* pCaTypeUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs)
{
FCALL_CONTRACT;

struct
{
REFLECTCLASSBASEREF refCaType;
OBJECTREF ca;
REFLECTMETHODREF refCtor;
REFLECTMODULEBASEREF refAttributedModule;
} gc;
gc.refCaType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pCaTypeUNSAFE);
TypeHandle th = gc.refCaType->GetType();

gc.ca = NULL;
gc.refCtor = (REFLECTMETHODREF)ObjectToOBJECTREF(pMethodUNSAFE);
gc.refAttributedModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pAttributedModuleUNSAFE);
Expand All @@ -749,10 +749,10 @@ FCIMPL5(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAt
FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));

MethodDesc* pCtorMD = gc.refCtor->GetMethod();

HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
{
MethodDescCallSite ctorCallSite(pCtorMD);
MethodDescCallSite ctorCallSite(pCtorMD, th);
MetaSig* pSig = ctorCallSite.GetMetaSig();
BYTE* pBlob = *ppBlob;

Expand All @@ -767,10 +767,6 @@ FCIMPL5(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAt
OBJECTREF *argToProtect = (OBJECTREF*)_alloca(cArgs * sizeof(OBJECTREF));
memset((void*)argToProtect, 0, cArgs * sizeof(OBJECTREF));

// If we relax this, we need to insure custom attributes construct properly for Nullable<T>
if (pCtorMD->GetMethodTable()->HasInstantiation())
COMPlusThrow(kNotSupportedException, W("Argument_GenericsInvalid"));

// load the this pointer
argToProtect[0] = pCtorMD->GetMethodTable()->Allocate(); // this is the value to return after the ctor invocation

Expand Down
2 changes: 1 addition & 1 deletion src/vm/customattribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ class COMCustomAttribute

// custom attributes utility functions
static FCDECL5(VOID, ParseAttributeUsageAttribute, PVOID pData, ULONG cData, ULONG* pTargets, CLR_BOOL* pInherited, CLR_BOOL* pAllowMultiple);
static FCDECL5(LPVOID, CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs);
static FCDECL6(LPVOID, CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectClassBaseObject* pCaTypeUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs);
static FCDECL7(void, GetPropertyOrFieldData, ReflectModuleBaseObject *pModuleUNSAFE, BYTE** ppBlobStart, BYTE* pBlobEnd, STRINGREF* pName, CLR_BOOL* pbIsProperty, OBJECTREF* pType, OBJECTREF* value);
static FCDECL4(VOID, GetSecurityAttributes, ReflectModuleBaseObject *pModuleUNSAFE, DWORD tkToken, CLR_BOOL fAssembly, PTRARRAYREF* ppArray);

Expand Down
78 changes: 78 additions & 0 deletions tests/src/reflection/GenericAttribute/GenericAttributeMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

//

using System;
Copy link
Member

Choose a reason for hiding this comment

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

Could you please add license header?

using System.Reflection;
using System.Collections;
using System.Runtime.CompilerServices;

[assembly: SingleAttribute<int>()]
[assembly: SingleAttribute<bool>()]

[assembly: MultiAttribute<int>()]
[assembly: MultiAttribute<int>(1)]
[assembly: MultiAttribute<int>(Value = 2)]
[assembly: MultiAttribute<bool>()]
[assembly: MultiAttribute<bool>(true)]

[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = false)]
public class SingleAttribute<T> : Attribute
{

}

[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = true)]
public class MultiAttribute<T> : Attribute
{
public T Value { get; set; }

public MultiAttribute()
{
}

public MultiAttribute(T value)
{
Value = value;
}
}

public enum MyEnum
{
Ctor,
Property
}

[SingleAttribute<int>()]
[SingleAttribute<bool>()]
[MultiAttribute<int>()]
[MultiAttribute<int>(1)]
[MultiAttribute<int>(Value = 2)]
[MultiAttribute<bool>()]
[MultiAttribute<bool>(true)]
[MultiAttribute<bool>(Value = true)]
[MultiAttribute<bool?>()]
[MultiAttribute<string>("Ctor")]
[MultiAttribute<string>(Value = "Property")]
[MultiAttribute<Type>(typeof(Class))]
[MultiAttribute<Type>(Value = typeof(Class.Derive))]
[MultiAttribute<MyEnum>(MyEnum.Ctor)]
[MultiAttribute<MyEnum>(Value = MyEnum.Property)]
public class Class
{
public class Derive : Class
{

}

[SingleAttribute<int>()]
[SingleAttribute<bool>()]
[MultiAttribute<int>()]
[MultiAttribute<int>(1)]
[MultiAttribute<int>(Value = 2)]
[MultiAttribute<bool>()]
[MultiAttribute<bool>(true)]
public int Property { get; set; }
}
Loading