2 // typemanager.cs: C# type manager
4 // Author: Miguel de Icaza (miguel@gnu.org)
6 // Licensed under the terms of the GNU GPL
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
13 using System.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
17 namespace Mono.CSharp {
19 public class TypeManager {
21 // A list of core types that the compiler requires or uses
23 static public Type object_type;
24 static public Type value_type;
25 static public Type string_type;
26 static public Type int32_type;
27 static public Type uint32_type;
28 static public Type int64_type;
29 static public Type uint64_type;
30 static public Type float_type;
31 static public Type double_type;
32 static public Type char_type;
33 static public Type char_ptr_type;
34 static public Type short_type;
35 static public Type decimal_type;
36 static public Type bool_type;
37 static public Type sbyte_type;
38 static public Type byte_type;
39 static public Type ushort_type;
40 static public Type enum_type;
41 static public Type delegate_type;
42 static public Type multicast_delegate_type;
43 static public Type void_type;
44 static public Type enumeration_type;
45 static public Type array_type;
46 static public Type runtime_handle_type;
47 static public Type icloneable_type;
48 static public Type type_type;
49 static public Type ienumerator_type;
50 static public Type idisposable_type;
51 static public Type default_member_type;
52 static public Type iasyncresult_type;
53 static public Type asynccallback_type;
54 static public Type intptr_type;
55 static public Type monitor_type;
56 static public Type runtime_field_handle_type;
57 static public Type attribute_usage_type;
58 static public Type dllimport_type;
59 static public Type unverifiable_code_type;
60 static public Type methodimpl_attr_type;
61 static public Type param_array_type;
62 static public Type void_ptr_type;
64 static public Type [] NoTypes;
67 // Internal, not really used outside
69 Type runtime_helpers_type;
72 // These methods are called by code generated by the compiler
74 static public MethodInfo string_concat_string_string;
75 static public MethodInfo string_concat_object_object;
76 static public MethodInfo string_isinterneted_string;
77 static public MethodInfo system_type_get_type_from_handle;
78 static public MethodInfo object_getcurrent_void;
79 static public MethodInfo bool_movenext_void;
80 static public MethodInfo void_dispose_void;
81 static public MethodInfo void_monitor_enter_object;
82 static public MethodInfo void_monitor_exit_object;
83 static public MethodInfo void_initializearray_array_fieldhandle;
84 static public MethodInfo int_getlength_int;
85 static public MethodInfo delegate_combine_delegate_delegate;
86 static public MethodInfo delegate_remove_delegate_delegate;
87 static public MethodInfo int_get_offset_to_string_data;
90 // The attribute constructors.
92 static public ConstructorInfo cons_param_array_attribute;
95 // Holds the Array of Assemblies that have been loaded
96 // (either because it is the default or the user used the
97 // -r command line option)
99 Assembly [] assemblies;
102 // Keeps a list of module builders. We used this to do lookups
103 // on the modulebuilder using GetType -- needed for arrays
105 ModuleBuilder [] modules;
108 // This is the type_cache from the assemblies to avoid
109 // hitting System.Reflection on every lookup.
114 // This is used to hotld the corresponding TypeContainer objects
115 // since we need this in FindMembers
117 Hashtable typecontainers;
120 // Keeps track of those types that are defined by the
123 ArrayList user_types;
126 // Keeps a mapping between TypeBuilders and their TypeContainers
128 static PtrHashtable builder_to_container;
131 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
132 // the arguments to the method
134 static Hashtable method_arguments;
137 // Maybe `method_arguments' should be replaced and only
138 // method_internal_params should be kept?
140 static Hashtable method_internal_params;
142 static PtrHashtable builder_to_interface;
145 // Keeps track of delegate types
148 static Hashtable builder_to_delegate;
151 // Keeps track of enum types
154 static Hashtable builder_to_enum;
157 // Keeps track of attribute types
160 static Hashtable builder_to_attr;
162 public TypeManager ()
166 user_types = new ArrayList ();
167 types = new Hashtable ();
168 typecontainers = new Hashtable ();
169 builder_to_interface = new PtrHashtable ();
170 builder_to_delegate = new PtrHashtable ();
171 builder_to_enum = new PtrHashtable ();
172 builder_to_attr = new PtrHashtable ();
175 static TypeManager ()
177 method_arguments = new PtrHashtable ();
178 method_internal_params = new PtrHashtable ();
179 builder_to_container = new PtrHashtable ();
180 NoTypes = new Type [0];
183 public void AddUserType (string name, TypeBuilder t)
189 public void AddUserType (string name, TypeBuilder t, TypeContainer tc)
191 AddUserType (name, t);
192 builder_to_container.Add (t, tc);
193 typecontainers.Add (name, tc);
196 public void AddDelegateType (string name, TypeBuilder t, Delegate del)
199 builder_to_delegate.Add (t, del);
202 public void AddEnumType (string name, TypeBuilder t, Enum en)
205 builder_to_enum.Add (t, en);
208 public void AddUserInterface (string name, TypeBuilder t, Interface i)
210 AddUserType (name, t);
211 builder_to_interface.Add (t, i);
214 public void RegisterAttrType (Type t, TypeContainer tc)
216 builder_to_attr.Add (t, tc);
220 /// Returns the TypeContainer whose Type is `t' or null if there is no
221 /// TypeContainer for `t' (ie, the Type comes from a library)
223 public static TypeContainer LookupTypeContainer (Type t)
225 return (TypeContainer) builder_to_container [t];
228 public Interface LookupInterface (Type t)
230 return (Interface) builder_to_interface [t];
233 public static Delegate LookupDelegate (Type t)
235 return (Delegate) builder_to_delegate [t];
238 public static Enum LookupEnum (Type t)
240 return (Enum) builder_to_enum [t];
243 public static TypeContainer LookupAttr (Type t)
245 return (TypeContainer) builder_to_attr [t];
249 /// Registers an assembly to load types from.
251 public void AddAssembly (Assembly a)
253 int top = assemblies != null ? assemblies.Length : 0;
254 Assembly [] n = new Assembly [top + 1];
256 if (assemblies != null)
257 assemblies.CopyTo (n, 0);
263 /// Registers a module builder to lookup types from
265 public void AddModule (ModuleBuilder mb)
267 int top = modules != null ? modules.Length : 0;
268 ModuleBuilder [] n = new ModuleBuilder [top + 1];
271 modules.CopyTo (n, 0);
277 /// Returns the Type associated with @name
279 public Type LookupType (string name)
284 // First lookup in user defined and cached values
287 t = (Type) types [name];
291 foreach (Assembly a in assemblies){
292 t = a.GetType (name);
300 foreach (ModuleBuilder mb in modules) {
301 t = mb.GetType (name);
312 /// Returns the C# name of a type if possible, or the full type name otherwise
314 static public string CSharpName (Type t)
318 else if (t == uint32_type)
320 else if (t == int64_type)
322 else if (t == uint64_type)
324 else if (t == float_type)
326 else if (t == double_type)
328 else if (t == char_type)
330 else if (t == short_type)
332 else if (t == decimal_type)
334 else if (t == bool_type)
336 else if (t == sbyte_type)
338 else if (t == byte_type)
340 else if (t == short_type)
342 else if (t == ushort_type)
344 else if (t == string_type)
346 else if (t == object_type)
348 else if (t == void_type)
355 /// Looks up a type, and aborts if it is not found. This is used
356 /// by types required by the compiler
358 Type CoreLookupType (string name)
360 Type t = LookupType (name);
363 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
364 Environment.Exit (0);
371 /// Returns the MethodInfo for a method named `name' defined
372 /// in type `t' which takes arguments of types `args'
374 MethodInfo GetMethod (Type t, string name, Type [] args)
376 MethodInfo mi = t.GetMethod (name, args);
379 throw new Exception ("Can not find the core function `" + name + "'");
384 ConstructorInfo GetConstructor (Type t, Type [] args)
386 ConstructorInfo ci = t.GetConstructor (args);
389 throw new Exception ("Can not find the core constructor for `" + t.FullName + "'");
395 /// The types have to be initialized after the initial
396 /// population of the type has happened (for example, to
397 /// bootstrap the corlib.dll
399 public void InitCoreTypes ()
401 object_type = CoreLookupType ("System.Object");
402 value_type = CoreLookupType ("System.ValueType");
403 string_type = CoreLookupType ("System.String");
404 int32_type = CoreLookupType ("System.Int32");
405 int64_type = CoreLookupType ("System.Int64");
406 uint32_type = CoreLookupType ("System.UInt32");
407 uint64_type = CoreLookupType ("System.UInt64");
408 float_type = CoreLookupType ("System.Single");
409 double_type = CoreLookupType ("System.Double");
410 byte_type = CoreLookupType ("System.Byte");
411 sbyte_type = CoreLookupType ("System.SByte");
412 char_type = CoreLookupType ("System.Char");
413 char_ptr_type = CoreLookupType ("System.Char*");
414 short_type = CoreLookupType ("System.Int16");
415 ushort_type = CoreLookupType ("System.UInt16");
416 decimal_type = CoreLookupType ("System.Decimal");
417 bool_type = CoreLookupType ("System.Boolean");
418 enum_type = CoreLookupType ("System.Enum");
420 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
421 delegate_type = CoreLookupType ("System.Delegate");
423 array_type = CoreLookupType ("System.Array");
424 void_type = CoreLookupType ("System.Void");
425 type_type = CoreLookupType ("System.Type");
427 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
428 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
429 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
430 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
431 asynccallback_type = CoreLookupType ("System.AsyncCallback");
432 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
433 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
434 idisposable_type = CoreLookupType ("System.IDisposable");
435 icloneable_type = CoreLookupType ("System.ICloneable");
436 monitor_type = CoreLookupType ("System.Threading.Monitor");
437 intptr_type = CoreLookupType ("System.IntPtr");
439 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
440 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
441 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
442 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
444 unverifiable_code_type = CoreLookupType ("System.Security.UnverifiableCodeAttribute");
446 void_ptr_type = CoreLookupType ("System.Void*");
449 // Now load the default methods that we use.
451 Type [] string_string = { string_type, string_type };
452 string_concat_string_string = GetMethod (
453 string_type, "Concat", string_string);
455 Type [] object_object = { object_type, object_type };
456 string_concat_object_object = GetMethod (
457 string_type, "Concat", object_object);
459 Type [] string_ = { string_type };
460 string_isinterneted_string = GetMethod (
461 string_type, "IsInterned", string_);
463 Type [] runtime_type_handle = { runtime_handle_type };
464 system_type_get_type_from_handle = GetMethod (
465 type_type, "GetTypeFromHandle", runtime_type_handle);
467 Type [] delegate_delegate = { delegate_type, delegate_type };
468 delegate_combine_delegate_delegate = GetMethod (
469 delegate_type, "Combine", delegate_delegate);
471 delegate_remove_delegate_delegate = GetMethod (
472 delegate_type, "Remove", delegate_delegate);
477 Type [] void_arg = { };
478 object_getcurrent_void = GetMethod (
479 ienumerator_type, "get_Current", void_arg);
480 bool_movenext_void = GetMethod (
481 ienumerator_type, "MoveNext", void_arg);
482 void_dispose_void = GetMethod (
483 idisposable_type, "Dispose", void_arg);
484 int_get_offset_to_string_data = GetMethod (
485 runtime_helpers_type, "get_OffsetToStringData", void_arg);
490 Type [] object_arg = { object_type };
491 void_monitor_enter_object = GetMethod (
492 monitor_type, "Enter", object_arg);
493 void_monitor_exit_object = GetMethod (
494 monitor_type, "Exit", object_arg);
496 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
498 void_initializearray_array_fieldhandle = GetMethod (
499 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
504 Type [] int_arg = { int32_type };
505 int_getlength_int = GetMethod (
506 array_type, "GetLength", int_arg);
511 cons_param_array_attribute = GetConstructor (
512 param_array_type, void_arg);
516 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
518 public MemberInfo [] FindMembers (Type t, MemberTypes mt, BindingFlags bf,
519 MemberFilter filter, object criteria)
522 // We have to take care of arrays specially, because GetType on
523 // a TypeBuilder array will return a Type, not a TypeBuilder,
524 // and we can not call FindMembers on this type.
526 if (t.IsSubclassOf (TypeManager.array_type))
527 return TypeManager.array_type.FindMembers (mt, bf, filter, criteria);
529 if (!(t is TypeBuilder)){
531 // Since FindMembers will not lookup both static and instance
532 // members, we emulate this behaviour here.
534 if ((bf & instance_and_static) == instance_and_static){
535 MemberInfo [] i_members = t.FindMembers (
536 mt, bf & ~BindingFlags.Static, filter, criteria);
537 MemberInfo [] s_members = t.FindMembers (
538 mt, bf & ~BindingFlags.Instance, filter, criteria);
540 int i_len = i_members.Length;
541 int s_len = s_members.Length;
542 if (i_len > 0 || s_len > 0){
543 MemberInfo [] both = new MemberInfo [i_len + s_len];
545 i_members.CopyTo (both, 0);
546 s_members.CopyTo (both, i_len);
552 return t.FindMembers (mt, bf, filter, criteria);
556 // FIXME: We should not have builder_to_blah everywhere,
557 // we should just have a builder_to_findmemberizable
558 // and have them implement a new ICanFindMembers interface
560 Enum e = (Enum) builder_to_enum [t];
563 return e.FindMembers (mt, bf, filter, criteria);
565 Delegate del = (Delegate) builder_to_delegate [t];
568 return del.FindMembers (mt, bf, filter, criteria);
570 Interface iface = (Interface) builder_to_interface [t];
573 return iface.FindMembers (mt, bf, filter, criteria);
575 TypeContainer tc = (TypeContainer) builder_to_container [t];
578 return tc.FindMembers (mt, bf, filter, criteria);
583 public static bool IsBuiltinType (Type t)
585 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
586 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
587 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
588 t == sbyte_type || t == byte_type || t == ushort_type)
594 public static bool IsDelegateType (Type t)
596 if (t.IsSubclassOf (TypeManager.delegate_type))
602 public static bool IsEnumType (Type t)
604 if (t.IsSubclassOf (TypeManager.enum_type))
610 public static bool IsInterfaceType (Type t)
612 Interface iface = (Interface) builder_to_interface [t];
621 /// Returns the User Defined Types
623 public ArrayList UserTypes {
629 public Hashtable TypeContainers {
631 return typecontainers;
635 static Hashtable builder_to_constant;
637 public static void RegisterConstant (FieldBuilder fb, Const c)
639 if (builder_to_constant == null)
640 builder_to_constant = new PtrHashtable ();
642 if (builder_to_constant.Contains (fb))
645 builder_to_constant.Add (fb, c);
648 public static Const LookupConstant (FieldBuilder fb)
650 if (builder_to_constant == null)
653 return (Const) builder_to_constant [fb];
657 /// Gigantic work around for missing features in System.Reflection.Emit follows.
661 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
662 /// for anything which is dynamic, and we need this in a number of places,
663 /// we register this information here, and use it afterwards.
665 static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
670 method_arguments.Add (mb, args);
671 method_internal_params.Add (mb, ip);
676 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
678 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
681 if (method_internal_params.Contains (mb))
682 return (InternalParameters) method_internal_params [mb];
684 throw new Exception ("Argument for Method not registered" + mb);
688 /// Returns the argument types for a method based on its methodbase
690 /// For dynamic methods, we use the compiler provided types, for
691 /// methods from existing assemblies we load them from GetParameters,
692 /// and insert them into the cache
694 static public Type [] GetArgumentTypes (MethodBase mb)
696 if (method_arguments.Contains (mb))
697 return (Type []) method_arguments [mb];
699 ParameterInfo [] pi = mb.GetParameters ();
701 Type [] types = new Type [c];
703 for (int i = 0; i < c; i++)
704 types [i] = pi [i].ParameterType;
706 method_arguments.Add (mb, types);
712 // This is a workaround the fact that GetValue is not
713 // supported for dynamic types
715 static Hashtable fields = new Hashtable ();
716 static public bool RegisterFieldValue (FieldBuilder fb, object value)
718 if (fields.Contains (fb))
721 fields.Add (fb, value);
726 static public object GetValue (FieldBuilder fb)
731 static Hashtable fieldbuilders_to_fields = new Hashtable ();
732 static public bool RegisterField (FieldBuilder fb, Field f)
734 if (fieldbuilders_to_fields.Contains (fb))
737 fieldbuilders_to_fields.Add (fb, f);
741 static public Field GetField (FieldInfo fb)
743 return (Field) fieldbuilders_to_fields [fb];
746 static Hashtable events;
748 static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
751 events = new Hashtable ();
753 if (events.Contains (eb))
756 events.Add (eb, new Pair (add, remove));
761 static public MethodInfo GetAddMethod (EventInfo ei)
763 if (ei is MyEventBuilder) {
764 Pair pair = (Pair) events [ei];
766 return (MethodInfo) pair.First;
768 return ei.GetAddMethod ();
771 static public MethodInfo GetRemoveMethod (EventInfo ei)
773 if (ei is MyEventBuilder) {
774 Pair pair = (Pair) events [ei];
776 return (MethodInfo) pair.Second;
778 return ei.GetAddMethod ();
781 static Hashtable properties;
783 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
785 if (properties == null)
786 properties = new Hashtable ();
788 if (properties.Contains (pb))
791 properties.Add (pb, new Pair (get, set));
797 // FIXME: we need to return the accessors depending on whether
798 // they are visible or not.
800 static public MethodInfo [] GetAccessors (PropertyInfo pi)
804 if (pi is PropertyBuilder){
805 Pair pair = (Pair) properties [pi];
807 ret = new MethodInfo [2];
808 ret [0] = (MethodInfo) pair.First;
809 ret [1] = (MethodInfo) pair.Second;
813 MethodInfo [] mi = new MethodInfo [2];
816 // Why this and not pi.GetAccessors?
817 // Because sometimes index 0 is the getter
820 mi [0] = pi.GetGetMethod (true);
821 mi [1] = pi.GetSetMethod (true);
827 static public MethodInfo GetPropertyGetter (PropertyInfo pi)
829 if (pi is PropertyBuilder){
830 Pair de = (Pair) properties [pi];
832 return (MethodInfo) de.Second;
834 return pi.GetSetMethod ();
837 static public MethodInfo GetPropertySetter (PropertyInfo pi)
839 if (pi is PropertyBuilder){
840 Pair de = (Pair) properties [pi];
842 return (MethodInfo) de.First;
844 return pi.GetGetMethod ();
848 /// The following is used to check if a given type implements an interface.
849 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
851 public static bool ImplementsInterface (Type t, Type iface)
856 // FIXME OPTIMIZATION:
857 // as soon as we hit a non-TypeBuiler in the interface
858 // chain, we could return, as the `Type.GetInterfaces'
859 // will return all the interfaces implement by the type
863 interfaces = t.GetInterfaces ();
865 for (int i = interfaces.Length; i > 0; ){
867 if (interfaces [i] == iface)
877 // This is needed, because enumerations from assemblies
878 // do not report their underlyingtype, but they report
881 public static Type EnumToUnderlying (Type t)
883 t = t.UnderlyingSystemType;
884 if (!TypeManager.IsEnumType (t))
887 TypeCode tc = Type.GetTypeCode (t);
890 case TypeCode.Boolean:
891 return TypeManager.bool_type;
893 return TypeManager.byte_type;
895 return TypeManager.sbyte_type;
897 return TypeManager.char_type;
899 return TypeManager.short_type;
900 case TypeCode.UInt16:
901 return TypeManager.ushort_type;
903 return TypeManager.int32_type;
904 case TypeCode.UInt32:
905 return TypeManager.uint32_type;
907 return TypeManager.int64_type;
908 case TypeCode.UInt64:
909 return TypeManager.uint64_type;
911 throw new Exception ("Unhandled typecode in enum" + tc);
915 /// Utility function that can be used to probe whether a type
916 /// is managed or not.
918 public static bool VerifyUnManaged (Type t, Location loc)
922 // FIXME: this is more complex, we actually need to
923 // make sure that the type does not contain any
931 "Cannot take the address or size of a variable of a managed type ('" +
932 CSharpName (t) + "')");
937 /// Returns the name of the indexer in a given type.
940 /// The default is not always `Item'. The user can change this behaviour by
941 /// using the DefaultMemberAttribute in the class.
943 /// For example, the String class indexer is named `Chars' not `Item'
945 public static string IndexerPropertyName (Type t)
948 if (t is TypeBuilder) {
949 TypeContainer tc = (TypeContainer) builder_to_container [t];
951 Attributes attrs = tc.OptAttributes;
953 if (attrs == null || attrs.AttributeSections == null)
956 foreach (AttributeSection asec in attrs.AttributeSections) {
958 if (asec.Attributes == null)
961 foreach (Attribute a in asec.Attributes) {
962 if (a.Name.IndexOf ("DefaultMember") != -1) {
963 ArrayList pos_args = (ArrayList) a.Arguments [0];
964 Expression e = ((Argument) pos_args [0]).expr;
966 if (e is StringConstant)
967 return ((StringConstant) e).Value;
975 System.Attribute attr = System.Attribute.GetCustomAttribute (t, TypeManager.default_member_type);
979 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
981 return dma.MemberName;
987 public static void MakePinned (LocalBuilder builder)
990 // FIXME: Flag the "LocalBuilder" type as being
991 // pinned. Figure out API.