-// System.MonoCustomAttrs.cs
-// Hooks into the runtime to get custom attributes for reflection handles
+//
+// MonoCustomAttrs.cs: Hooks into the runtime to get custom attributes for reflection handles
//
// Authors:
// Paolo Molaro (lupus@ximian.com)
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// Marek Safar (marek.safar@gmail.com)
//
// (c) 2002,2003 Ximian, Inc. (http://www.ximian.com)
-//
-
-//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2013 Xamarin, Inc (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
using System.Reflection;
using System.Collections;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+#if !FULL_AOT_RUNTIME
using System.Reflection.Emit;
+#endif
+
using System.Collections.Generic;
namespace System
{
- internal class MonoCustomAttrs
+ static class MonoCustomAttrs
{
static Assembly corlib;
+ [ThreadStatic]
+ static Dictionary<Type, AttributeUsageAttribute> usage_cache;
- /* Treat as user types all corlib types extending System.Type that are not MonoType and TypeBuilder */
+ /* Treat as user types all corlib types extending System.Type that are not RuntimeType and TypeBuilder */
static bool IsUserCattrProvider (object obj)
{
Type type = obj as Type;
- if ((type is MonoType) || (type is TypeBuilder))
+#if !FULL_AOT_RUNTIME
+ if ((type is RuntimeType) || (type is TypeBuilder))
+#else
+ if (type is RuntimeType)
+#endif
return false;
if ((obj is Type))
return true;
else if (obj is ParameterInfo)
pseudoAttrs = ((ParameterInfo)obj).GetPseudoCustomAttributes ();
else if (obj is Type)
- pseudoAttrs = ((Type)obj).GetPseudoCustomAttributes ();
+ pseudoAttrs = GetPseudoCustomAttributes (((Type)obj));
if ((attributeType != null) && (pseudoAttrs != null)) {
for (int i = 0; i < pseudoAttrs.Length; ++i)
return pseudoAttrs;
else
return new object [] { pseudoAttrs [i] };
- return new object [0];
+ return EmptyArray<object>.Value;
}
- else
- return pseudoAttrs;
+
+ return pseudoAttrs;
}
- internal static object[] GetCustomAttributesBase (ICustomAttributeProvider obj, Type attributeType)
+ static object[] GetPseudoCustomAttributes (Type type)
+ {
+ int count = 0;
+ var Attributes = type.Attributes;
+
+ /* IsSerializable returns true for delegates/enums as well */
+ if ((Attributes & TypeAttributes.Serializable) != 0)
+ count ++;
+ if ((Attributes & TypeAttributes.Import) != 0)
+ count ++;
+
+ if (count == 0)
+ return null;
+ object[] attrs = new object [count];
+ count = 0;
+
+ if ((Attributes & TypeAttributes.Serializable) != 0)
+ attrs [count ++] = new SerializableAttribute ();
+ if ((Attributes & TypeAttributes.Import) != 0)
+ attrs [count ++] = new ComImportAttribute ();
+
+ return attrs;
+ }
+
+ internal static object[] GetCustomAttributesBase (ICustomAttributeProvider obj, Type attributeType, bool inheritedOnly)
{
object[] attrs;
if (IsUserCattrProvider (obj))
else
attrs = GetCustomAttributesInternal (obj, attributeType, false);
- object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
- if (pseudoAttrs != null) {
- object[] res = new object [attrs.Length + pseudoAttrs.Length];
- System.Array.Copy (attrs, res, attrs.Length);
- System.Array.Copy (pseudoAttrs, 0, res, attrs.Length, pseudoAttrs.Length);
- return res;
- }
- else
- return attrs;
- }
-
- internal static Attribute GetCustomAttribute (ICustomAttributeProvider obj,
- Type attributeType,
- bool inherit)
- {
- object[] res = GetCustomAttributes (obj, attributeType, inherit);
- if (res.Length == 0)
- {
- return null;
- }
- else if (res.Length > 1)
- {
- string msg = "'{0}' has more than one attribute of type '{1}";
- msg = String.Format (msg, obj, attributeType);
- throw new AmbiguousMatchException (msg);
+ //
+ // All pseudo custom attributes are Inherited = false hence we can avoid
+ // building attributes array which would be discarded by inherited checks
+ //
+ if (!inheritedOnly) {
+ object[] pseudoAttrs = GetPseudoCustomAttributes (obj, attributeType);
+ if (pseudoAttrs != null) {
+ object[] res = new object [attrs.Length + pseudoAttrs.Length];
+ System.Array.Copy (attrs, res, attrs.Length);
+ System.Array.Copy (pseudoAttrs, 0, res, attrs.Length, pseudoAttrs.Length);
+ return res;
+ }
}
- return (Attribute) res[0];
+ return attrs;
}
internal static object[] GetCustomAttributes (ICustomAttributeProvider obj, Type attributeType, bool inherit)
attributeType = null;
object[] r;
- object[] res = GetCustomAttributesBase (obj, attributeType);
+ object[] res = GetCustomAttributesBase (obj, attributeType, false);
// shortcut
- if (!inherit && res.Length == 1)
- {
+ if (!inherit && res.Length == 1) {
if (res [0] == null)
throw new CustomAttributeFormatException ("Invalid custom attribute format");
- if (attributeType != null)
- {
- if (attributeType.IsAssignableFrom (res[0].GetType ()))
- {
+ if (attributeType != null) {
+ if (attributeType.IsAssignableFrom (res[0].GetType ())) {
r = (object[]) Array.CreateInstance (attributeType, 1);
r[0] = res[0];
- }
- else
- {
+ } else {
r = (object[]) Array.CreateInstance (attributeType, 0);
}
- }
- else
- {
+ } else {
r = (object[]) Array.CreateInstance (res[0].GetType (), 1);
r[0] = res[0];
}
return r;
}
+ if (inherit && GetBase (obj) == null)
+ inherit = false;
+
// if AttributeType is sealed, and Inherited is set to false, then
// there's no use in scanning base types
- if ((attributeType != null && attributeType.IsSealed) && inherit)
- {
+ if ((attributeType != null && attributeType.IsSealed) && inherit) {
AttributeUsageAttribute usageAttribute = RetrieveAttributeUsage (
attributeType);
if (!usageAttribute.Inherited)
- {
inherit = false;
- }
}
- int initialSize = res.Length < 16 ? res.Length : 16;
-
- Hashtable attributeInfos = new Hashtable (initialSize);
- ArrayList a = new ArrayList (initialSize);
+ var initialSize = Math.Max (res.Length, 16);
+ List<Object> a = null;
ICustomAttributeProvider btype = obj;
+ object[] array;
+
+ /* Non-inherit case */
+ if (!inherit) {
+ if (attributeType == null) {
+ foreach (object attr in res) {
+ if (attr == null)
+ throw new CustomAttributeFormatException ("Invalid custom attribute format");
+ }
+ var result = new Attribute [res.Length];
+ res.CopyTo (result, 0);
+ return result;
+ }
+
+ a = new List<object> (initialSize);
+ foreach (object attr in res) {
+ if (attr == null)
+ throw new CustomAttributeFormatException ("Invalid custom attribute format");
+
+ Type attrType = attr.GetType ();
+ if (attributeType != null && !attributeType.IsAssignableFrom (attrType))
+ continue;
+ a.Add (attr);
+ }
+
+ if (attributeType == null || attributeType.IsValueType)
+ array = new Attribute [a.Count];
+ else
+ array = Array.CreateInstance (attributeType, a.Count) as object[];
+ a.CopyTo (array, 0);
+ return array;
+ }
+ /* Inherit case */
+ var attributeInfos = new Dictionary<Type, AttributeInfo> (initialSize);
int inheritanceLevel = 0;
+ a = new List<object> (initialSize);
- do
- {
- foreach (object attr in res)
- {
+ do {
+ foreach (object attr in res) {
AttributeUsageAttribute usage;
if (attr == null)
throw new CustomAttributeFormatException ("Invalid custom attribute format");
Type attrType = attr.GetType ();
- if (attributeType != null)
- {
+ if (attributeType != null) {
if (!attributeType.IsAssignableFrom (attrType))
- {
continue;
- }
}
- AttributeInfo firstAttribute = (AttributeInfo) attributeInfos[attrType];
- if (firstAttribute != null)
- {
+ AttributeInfo firstAttribute;
+ if (attributeInfos.TryGetValue (attrType, out firstAttribute))
usage = firstAttribute.Usage;
- }
else
- {
usage = RetrieveAttributeUsage (attrType);
- }
// only add attribute to the list of attributes if
// - we are on the first inheritance level, or the attribute can be inherited anyway
if ((inheritanceLevel == 0 || usage.Inherited) && (usage.AllowMultiple ||
(firstAttribute == null || (firstAttribute != null
&& firstAttribute.InheritanceLevel == inheritanceLevel))))
- {
a.Add (attr);
- }
if (firstAttribute == null)
- {
attributeInfos.Add (attrType, new AttributeInfo (usage, inheritanceLevel));
- }
}
- if ((btype = GetBase (btype)) != null)
- {
+ if ((btype = GetBase (btype)) != null) {
inheritanceLevel++;
- res = GetCustomAttributesBase (btype, attributeType);
+ res = GetCustomAttributesBase (btype, attributeType, true);
}
} while (inherit && btype != null);
- object[] array = null;
if (attributeType == null || attributeType.IsValueType)
- {
- array = (object[]) Array.CreateInstance (typeof(Attribute), a.Count);
- }
+ array = new Attribute [a.Count];
else
- {
array = Array.CreateInstance (attributeType, a.Count) as object[];
- }
// copy attributes to array
a.CopyTo (array, 0);
throw new ArgumentNullException ("obj");
if (!inherit)
- return (object[]) GetCustomAttributesBase (obj, null).Clone ();
+ return (object[]) GetCustomAttributesBase (obj, null, false).Clone ();
return GetCustomAttributes (obj, typeof (MonoCustomAttrs), inherit);
}
[MethodImplAttribute (MethodImplOptions.InternalCall)]
internal static extern bool IsDefinedInternal (ICustomAttributeProvider obj, Type AttributeType);
- static PropertyInfo GetBasePropertyDefinition (PropertyInfo property)
+ static PropertyInfo GetBasePropertyDefinition (MonoProperty property)
{
MethodInfo method = property.GetGetMethod (true);
if (method == null || !method.IsVirtual)
}
- static EventInfo GetBaseEventDefinition (EventInfo evt)
+ static EventInfo GetBaseEventDefinition (MonoEvent evt)
{
MethodInfo method = evt.GetAddMethod (true);
if (method == null || !method.IsVirtual)
return baseMethod;
}
- private static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
+ private static AttributeUsageAttribute RetrieveAttributeUsageNoCache (Type attributeType)
{
if (attributeType == typeof (AttributeUsageAttribute))
/* Avoid endless recursion */
return ((AttributeUsageAttribute) attribs[0]);
}
+ static AttributeUsageAttribute RetrieveAttributeUsage (Type attributeType)
+ {
+ AttributeUsageAttribute usageAttribute = null;
+ /* Usage a thread-local cache to speed this up, since it is called a lot from GetCustomAttributes () */
+ if (usage_cache == null)
+ usage_cache = new Dictionary<Type, AttributeUsageAttribute> ();
+ if (usage_cache.TryGetValue (attributeType, out usageAttribute))
+ return usageAttribute;
+ usageAttribute = RetrieveAttributeUsageNoCache (attributeType);
+ usage_cache [attributeType] = usageAttribute;
+ return usageAttribute;
+ }
+
private static readonly AttributeUsageAttribute DefaultAttributeUsage =
new AttributeUsageAttribute (AttributeTargets.All);