5 // Marek Safar <marek.safar@gmail.com>
7 // Copyright (C) 2015 Xamarin Inc (http://www.xamarin.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Reflection;
30 using System.Runtime.CompilerServices;
31 using System.Threading;
32 using System.Collections.Generic;
33 using System.Runtime.InteropServices;
34 using System.Globalization;
36 using System.Reflection.Emit;
38 using System.Diagnostics.Contracts;
39 using System.Security;
40 using System.Runtime.Serialization;
44 // Contains information about the type which is expensive to compute
45 [StructLayout (LayoutKind.Sequential)]
46 internal class MonoTypeInfo {
47 // this is the displayed form: special characters
48 // ,+*&*[]\ in the identifier portions of the names
49 // have been escaped with a leading backslash (\)
50 public string full_name;
51 public MonoCMethod default_ctor;
54 [StructLayout (LayoutKind.Sequential)]
55 partial class RuntimeType
58 MonoTypeInfo type_info;
60 internal Object GenericCache;
62 internal RuntimeType (Object obj)
64 throw new NotImplementedException ();
67 internal MonoCMethod GetDefaultConstructor ()
69 MonoCMethod ctor = null;
71 if (type_info == null)
72 type_info = new MonoTypeInfo ();
74 ctor = type_info.default_ctor;
77 var ctors = GetConstructors (BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
79 for (int i = 0; i < ctors.Length; ++i) {
80 if (ctors [i].GetParametersCount () == 0) {
81 type_info.default_ctor = ctor = (MonoCMethod) ctors [i];
90 [MethodImplAttribute(MethodImplOptions.InternalCall)]
91 extern MethodInfo GetCorrespondingInflatedMethod (MethodInfo generic);
93 [MethodImplAttribute(MethodImplOptions.InternalCall)]
94 extern ConstructorInfo GetCorrespondingInflatedConstructor (ConstructorInfo generic);
96 internal override MethodInfo GetMethod (MethodInfo fromNoninstanciated)
98 if (fromNoninstanciated == null)
99 throw new ArgumentNullException ("fromNoninstanciated");
100 return GetCorrespondingInflatedMethod (fromNoninstanciated);
103 internal override ConstructorInfo GetConstructor (ConstructorInfo fromNoninstanciated)
105 if (fromNoninstanciated == null)
106 throw new ArgumentNullException ("fromNoninstanciated");
107 return GetCorrespondingInflatedConstructor (fromNoninstanciated);
110 internal override FieldInfo GetField (FieldInfo fromNoninstanciated)
112 /* create sensible flags from given FieldInfo */
113 BindingFlags flags = fromNoninstanciated.IsStatic ? BindingFlags.Static : BindingFlags.Instance;
114 flags |= fromNoninstanciated.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic;
115 return GetField (fromNoninstanciated.Name, flags);
118 string GetDefaultMemberName ()
120 object [] att = GetCustomAttributes (typeof (DefaultMemberAttribute), true);
121 return att.Length != 0 ? ((DefaultMemberAttribute) att [0]).MemberName : null;
124 RuntimeConstructorInfo m_serializationCtor;
125 internal RuntimeConstructorInfo GetSerializationCtor()
127 if (m_serializationCtor == null) {
128 var s_SICtorParamTypes = new Type[] { typeof(SerializationInfo), typeof(StreamingContext) };
130 m_serializationCtor = GetConstructor(
131 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
133 CallingConventions.Any,
135 null) as RuntimeConstructorInfo;
138 return m_serializationCtor;
141 internal Object CreateInstanceSlow(bool publicOnly, bool skipCheckThis, bool fillCache, ref StackCrawlMark stackMark)
143 bool bNeedSecurityCheck = true;
144 bool bCanBeCached = false;
145 bool bSecurityCheckOff = false;
148 CreateInstanceCheckThis();
151 bSecurityCheckOff = true;
153 return CreateInstanceMono (!publicOnly);
156 object CreateInstanceMono (bool nonPublic)
158 var ctor = GetDefaultConstructor ();
159 if (!nonPublic && ctor != null && !ctor.IsPublic) {
164 Type elementType = this.GetRootElementType();
165 if (ReferenceEquals (elementType, typeof (TypedReference)) || ReferenceEquals (elementType, typeof (RuntimeArgumentHandle)))
166 throw new NotSupportedException (Environment.GetResourceString ("NotSupported_ContainsStackPtr"));
169 return CreateInstanceInternal (this);
171 throw new MissingMethodException (Locale.GetText ("Default constructor not found for type " + FullName));
174 // TODO: .net does more checks in unmanaged land in RuntimeTypeHandle::CreateInstance
176 throw new MissingMethodException (Locale.GetText ("Cannot create an abstract class '{0}'.", FullName));
179 return ctor.InternalInvoke (null, null);
182 internal Object CheckValue (Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
185 var res = TryConvertToType (value, ref failed);
189 if ((invokeAttr & BindingFlags.ExactBinding) == BindingFlags.ExactBinding)
190 throw new ArgumentException(String.Format(CultureInfo.CurrentUICulture, Environment.GetResourceString("Arg_ObjObjEx"), value.GetType(), this));
192 if (binder != null && binder != Type.DefaultBinder)
193 return binder.ChangeType (value, this, culture);
195 throw new ArgumentException(String.Format(CultureInfo.CurrentUICulture, Environment.GetResourceString("Arg_ObjObjEx"), value.GetType(), this));
198 object TryConvertToType (object value, ref bool failed)
200 if (IsInstanceOfType (value)) {
205 var elementType = GetElementType ();
206 if (value == null || elementType.IsInstanceOfType (value)) {
215 var type = Enum.GetUnderlyingType (this);
216 if (type == value.GetType ())
218 var res = IsConvertibleToPrimitiveType (value, this);
221 } else if (IsPrimitive) {
222 var res = IsConvertibleToPrimitiveType (value, this);
225 } else if (IsPointer) {
226 var vtype = value.GetType ();
227 if (vtype == typeof (IntPtr) || vtype == typeof (UIntPtr))
235 // Binder uses some incompatible conversion rules. For example
236 // int value cannot be used with decimal parameter but in other
237 // ways it's more flexible than normal convertor, for example
238 // long value can be used with int based enum
239 static object IsConvertibleToPrimitiveType (object value, Type targetType)
241 var type = value.GetType ();
243 type = Enum.GetUnderlyingType (type);
244 if (type == targetType)
248 var from = Type.GetTypeCode (type);
249 var to = Type.GetTypeCode (targetType);
255 return (Char) (Byte) value;
256 case TypeCode.UInt16:
263 return (Int16) (Byte) value;
265 return (Int16) (SByte) value;
268 case TypeCode.UInt16:
271 return (UInt16) (Byte) value;
279 return (Int32) (Byte) value;
281 return (Int32) (SByte) value;
283 return (Int32) (Char) value;
285 return (Int32) (Int16) value;
286 case TypeCode.UInt16:
287 return (Int32) (UInt16) value;
290 case TypeCode.UInt32:
293 return (UInt32) (Byte) value;
295 return (UInt32) (Char) value;
296 case TypeCode.UInt16:
297 return (UInt32) (UInt16) value;
303 return (Int64) (Byte) value;
305 return (Int64) (SByte) value;
307 return (Int64) (Int16) value;
309 return (Int64) (Char) value;
310 case TypeCode.UInt16:
311 return (Int64) (UInt16) value;
313 return (Int64) (Int32) value;
314 case TypeCode.UInt32:
315 return (Int64) (UInt32) value;
318 case TypeCode.UInt64:
321 return (UInt64) (Byte) value;
323 return (UInt64) (Char) value;
324 case TypeCode.UInt16:
325 return (UInt64) (UInt16) value;
326 case TypeCode.UInt32:
327 return (UInt64) (UInt32) value;
330 case TypeCode.Single:
333 return (Single) (Byte) value;
335 return (Single) (SByte) value;
337 return (Single) (Int16) value;
339 return (Single) (Char) value;
340 case TypeCode.UInt16:
341 return (Single) (UInt16) value;
343 return (Single) (Int32) value;
344 case TypeCode.UInt32:
345 return (Single) (UInt32) value;
347 return (Single) (Int64) value;
348 case TypeCode.UInt64:
349 return (Single) (UInt64) value;
352 case TypeCode.Double:
355 return (Double) (Byte) value;
357 return (Double) (SByte) value;
359 return (Double) (Char) value;
361 return (Double) (Int16) value;
362 case TypeCode.UInt16:
363 return (Double) (UInt16) value;
365 return (Double) (Int32) value;
366 case TypeCode.UInt32:
367 return (Double) (UInt32) value;
369 return (Double) (Int64) value;
370 case TypeCode.UInt64:
371 return (Double) (UInt64) value;
372 case TypeCode.Single:
373 return (Double) (Single) value;
378 // Everything else is rejected
382 string GetCachedName (TypeNameKind kind)
385 case TypeNameKind.SerializationName:
388 throw new NotImplementedException ();
392 [MethodImplAttribute(MethodImplOptions.InternalCall)]
393 extern Type make_array_type (int rank);
395 public override Type MakeArrayType ()
397 return make_array_type (0);
400 public override Type MakeArrayType (int rank)
402 if (rank < 1 || rank > 255)
403 throw new IndexOutOfRangeException ();
404 return make_array_type (rank);
407 [MethodImplAttribute(MethodImplOptions.InternalCall)]
408 extern Type make_byref_type ();
410 public override Type MakeByRefType ()
413 throw new TypeLoadException ("Can not call MakeByRefType on a ByRef type");
414 return make_byref_type ();
417 [MethodImplAttribute(MethodImplOptions.InternalCall)]
418 static extern Type MakePointerType (Type type);
420 public override Type MakePointerType ()
422 return MakePointerType (this);
425 public override StructLayoutAttribute StructLayoutAttribute {
427 return StructLayoutAttribute.GetCustomAttribute (this);
431 public override bool ContainsGenericParameters {
433 if (IsGenericParameter)
437 foreach (Type arg in GetGenericArguments ())
438 if (arg.ContainsGenericParameters)
443 return GetElementType ().ContainsGenericParameters;
449 public override Type[] GetGenericParameterConstraints()
451 if (!IsGenericParameter)
452 throw new InvalidOperationException(Environment.GetResourceString("Arg_NotGenericParameter"));
453 Contract.EndContractBlock();
455 var paramInfo = new Mono.RuntimeGenericParamInfoHandle (RuntimeTypeHandle.GetGenericParameterInfo (this));
456 Type[] constraints = paramInfo.Constraints;
458 if (constraints == null)
459 constraints = EmptyArray<Type>.Value;
464 internal static object CreateInstanceForAnotherGenericParameter (Type genericType, RuntimeType genericArgument)
466 var gt = (RuntimeType) MakeGenericType (genericType, new Type [] { genericArgument });
467 var ctor = gt.GetDefaultConstructor ();
468 return ctor.InternalInvoke (null, null);
471 [MethodImplAttribute(MethodImplOptions.InternalCall)]
472 static extern Type MakeGenericType (Type gt, Type [] types);
474 [MethodImplAttribute(MethodImplOptions.InternalCall)]
475 internal extern IntPtr GetMethodsByName_native (string name, BindingFlags bindingAttr, bool ignoreCase);
477 internal RuntimeMethodInfo[] GetMethodsByName (string name, BindingFlags bindingAttr, bool ignoreCase, RuntimeType reflectedType)
479 var refh = new RuntimeTypeHandle (reflectedType);
480 using (var h = new Mono.SafeGPtrArrayHandle (GetMethodsByName_native (name, bindingAttr, ignoreCase), false)) {
482 var a = new RuntimeMethodInfo [n];
483 for (int i = 0; i < n; i++) {
484 var mh = new RuntimeMethodHandle (h[i]);
485 a[i] = (RuntimeMethodInfo) MethodBase.GetMethodFromHandleNoGenericCheck (mh, refh);
491 [MethodImplAttribute(MethodImplOptions.InternalCall)]
492 extern RuntimePropertyInfo[] GetPropertiesByName (string name, BindingFlags bindingAttr, bool icase, Type reflected_type);
494 [MethodImplAttribute(MethodImplOptions.InternalCall)]
495 extern IntPtr GetConstructors_native (BindingFlags bindingAttr);
497 RuntimeConstructorInfo[] GetConstructors_internal (BindingFlags bindingAttr, RuntimeType reflectedType)
499 var refh = new RuntimeTypeHandle (reflectedType);
500 using (var h = new Mono.SafeGPtrArrayHandle (GetConstructors_native (bindingAttr), false)) {
502 var a = new RuntimeConstructorInfo [n];
503 for (int i = 0; i < n; i++) {
504 var mh = new RuntimeMethodHandle (h[i]);
505 a[i] = (RuntimeConstructorInfo) MethodBase.GetMethodFromHandleNoGenericCheck (mh, refh);
512 public override InterfaceMapping GetInterfaceMap (Type ifaceType)
514 if (IsGenericParameter)
515 throw new InvalidOperationException(Environment.GetResourceString("Arg_GenericParameter"));
517 if ((object)ifaceType == null)
518 throw new ArgumentNullException("ifaceType");
519 Contract.EndContractBlock();
521 RuntimeType ifaceRtType = ifaceType as RuntimeType;
523 if (ifaceRtType == null)
524 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "ifaceType");
526 InterfaceMapping res;
527 if (!ifaceType.IsInterface)
528 throw new ArgumentException (Locale.GetText ("Argument must be an interface."), "ifaceType");
530 throw new ArgumentException ("'this' type cannot be an interface itself");
531 res.TargetType = this;
532 res.InterfaceType = ifaceType;
533 GetInterfaceMapData (this, ifaceType, out res.TargetMethods, out res.InterfaceMethods);
534 if (res.TargetMethods == null)
535 throw new ArgumentException (Locale.GetText ("Interface not found"), "ifaceType");
540 [MethodImplAttribute(MethodImplOptions.InternalCall)]
541 static extern void GetInterfaceMapData (Type t, Type iface, out MethodInfo[] targets, out MethodInfo[] methods);
543 public override Guid GUID {
545 object[] att = GetCustomAttributes(typeof(System.Runtime.InteropServices.GuidAttribute), true);
548 return new Guid(((System.Runtime.InteropServices.GuidAttribute)att[0]).Value);
552 [MethodImplAttribute(MethodImplOptions.InternalCall)]
553 internal extern void GetPacking (out int packing, out int size);
556 private static Dictionary<Guid, Type> clsid_types;
557 private static AssemblyBuilder clsid_assemblybuilder;
560 internal static Type GetTypeFromCLSIDImpl(Guid clsid, String server, bool throwOnError)
565 if (clsid_types == null)
567 Dictionary<Guid, Type> new_clsid_types = new Dictionary<Guid, Type> ();
568 Interlocked.CompareExchange<Dictionary<Guid, Type>>(
569 ref clsid_types, new_clsid_types, null);
573 if (clsid_types.TryGetValue(clsid, out result))
576 if (clsid_assemblybuilder == null)
578 AssemblyName assemblyname = new AssemblyName ();
579 assemblyname.Name = "GetTypeFromCLSIDDummyAssembly";
580 clsid_assemblybuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (
581 assemblyname, AssemblyBuilderAccess.Run);
583 ModuleBuilder modulebuilder = clsid_assemblybuilder.DefineDynamicModule (
586 TypeBuilder typebuilder = modulebuilder.DefineType ("System.__ComObject",
587 TypeAttributes.Public | TypeAttributes.Class, typeof(System.__ComObject));
589 Type[] guidattrtypes = new Type[] { typeof(string) };
591 CustomAttributeBuilder customattr = new CustomAttributeBuilder (
592 typeof(GuidAttribute).GetConstructor (guidattrtypes),
593 new object[] { clsid.ToString () });
595 typebuilder.SetCustomAttribute (customattr);
597 customattr = new CustomAttributeBuilder (
598 typeof(ComImportAttribute).GetConstructor (EmptyTypes),
601 typebuilder.SetCustomAttribute (customattr);
603 result = typebuilder.CreateType ();
605 clsid_types.Add(clsid, result);
610 throw new NotImplementedException ("Unmanaged activation removed");
614 protected override TypeCode GetTypeCodeImpl ()
616 return GetTypeCodeImplInternal (this);
619 [MethodImplAttribute(MethodImplOptions.InternalCall)]
620 extern static TypeCode GetTypeCodeImplInternal (Type type);
622 internal static Type GetTypeFromProgIDImpl(String progID, String server, bool throwOnError)
624 throw new NotImplementedException ("Unmanaged activation is not supported");
627 public override string ToString()
629 return getFullName (false, false);
632 bool IsGenericCOMObjectImpl ()
637 [MethodImplAttribute (MethodImplOptions.InternalCall)]
638 static extern object CreateInstanceInternal (Type type);
640 public extern override MethodBase DeclaringMethod {
641 [MethodImplAttribute(MethodImplOptions.InternalCall)]
645 [MethodImplAttribute(MethodImplOptions.InternalCall)]
646 internal extern string getFullName(bool full_name, bool assembly_qualified);
648 [MethodImplAttribute(MethodImplOptions.InternalCall)]
649 extern Type[] GetGenericArgumentsInternal (bool runtimeArray);
651 GenericParameterAttributes GetGenericParameterAttributes () {
652 return (new Mono.RuntimeGenericParamInfoHandle (RuntimeTypeHandle.GetGenericParameterInfo (this))).Attributes;
655 [MethodImplAttribute(MethodImplOptions.InternalCall)]
656 extern int GetGenericParameterPosition ();
658 [MethodImplAttribute(MethodImplOptions.InternalCall)]
659 extern RuntimeEventInfo[] GetEvents_internal (string name, BindingFlags bindingAttr, Type reflected_type);
661 [MethodImplAttribute(MethodImplOptions.InternalCall)]
662 extern IntPtr GetFields_native (string name, BindingFlags bindingAttr);
664 RuntimeFieldInfo[] GetFields_internal (string name, BindingFlags bindingAttr, RuntimeType reflectedType)
666 var refh = new RuntimeTypeHandle (reflectedType);
667 using (var h = new Mono.SafeGPtrArrayHandle (GetFields_native (name, bindingAttr), false)) {
669 var a = new RuntimeFieldInfo[n];
670 for (int i = 0; i < n; i++) {
671 var fh = new RuntimeFieldHandle (h[i]);
672 a[i] = (RuntimeFieldInfo) FieldInfo.GetFieldFromHandle (fh, refh);
678 [MethodImplAttribute(MethodImplOptions.InternalCall)]
679 public extern override Type[] GetInterfaces();
681 [MethodImplAttribute(MethodImplOptions.InternalCall)]
682 extern RuntimeType[] GetNestedTypes_internal (string name, BindingFlags bindingAttr);
684 public override string AssemblyQualifiedName {
686 return getFullName (true, true);
690 public extern override Type DeclaringType {
691 [MethodImplAttribute(MethodImplOptions.InternalCall)]
695 public extern override string Name {
696 [MethodImplAttribute(MethodImplOptions.InternalCall)]
700 public extern override string Namespace {
701 [MethodImplAttribute(MethodImplOptions.InternalCall)]
706 static int get_core_clr_security_level ()
711 //seclevel { transparent = 0, safe-critical = 1, critical = 2}
712 [MethodImplAttribute(MethodImplOptions.InternalCall)]
713 public extern int get_core_clr_security_level ();
715 public override bool IsSecurityTransparent {
716 get { return get_core_clr_security_level () == 0; }
719 public override bool IsSecurityCritical {
720 get { return get_core_clr_security_level () > 0; }
723 public override bool IsSecuritySafeCritical {
724 get { return get_core_clr_security_level () == 1; }
728 public override int GetHashCode()
730 Type t = UnderlyingSystemType;
731 if (t != null && t != this)
732 return t.GetHashCode ();
733 return (int)_impl.Value;
736 public override string FullName {
739 // This doesn't need locking
740 if (type_info == null)
741 type_info = new MonoTypeInfo ();
742 if ((fullName = type_info.full_name) == null)
743 fullName = type_info.full_name = getFullName (true, false);
749 internal override bool IsUserType {