//
// typegen.cs: type generation
//
// Author: Miguel de Icaza (miguel@gnu.org)
//
// Licensed under the terms of the GNU GPL
//
// (C) 2001 Ximian, Inc (http://www.ximian.com)
//
//
using System;
using System.Collections;
using System.Reflection;
using System.Reflection.Emit;
namespace CIR {
public class TypeManager {
//
// A list of core types that the compiler requires or uses
//
static public Type object_type;
static public Type value_type;
static public Type string_type;
static public Type int32_type;
static public Type uint32_type;
static public Type int64_type;
static public Type uint64_type;
static public Type float_type;
static public Type double_type;
static public Type char_type;
static public Type short_type;
static public Type decimal_type;
static public Type bool_type;
static public Type sbyte_type;
static public Type byte_type;
static public Type ushort_type;
static public Type enum_type;
static public Type delegate_type;
static public Type void_type;
static public Type enumeration_type;
static public Type array_type;
static public Type runtime_handle_type;
static public Type icloneable_type;
static public Type type_type;
static public Type ienumerator_type;
static public Type idisposable_type;
static public Type default_member_type;
static public Type iasyncresult_type;
static public Type asynccallback_type;
static public Type intptr_type;
static public Type monitor_type;
static public Type runtime_field_handle_type;
//
// Internal, not really used outside
//
Type runtime_helpers_type;
//
// These methods are called by code generated by the compiler
//
static public MethodInfo string_concat_string_string;
static public MethodInfo string_concat_object_object;
static public MethodInfo system_type_get_type_from_handle;
static public MethodInfo object_getcurrent_void;
static public MethodInfo bool_movenext_void;
static public MethodInfo void_dispose_void;
static public MethodInfo void_monitor_enter_object;
static public MethodInfo void_monitor_exit_object;
static public MethodInfo void_initializearray_array_fieldhandle;
//
// Holds the Array of Assemblies that have been loaded
// (either because it is the default or the user used the
// -r command line option)
//
ArrayList assemblies;
//
// Keeps a list of module builders. We used this to do lookups
// on the modulebuilder using GetType -- needed for arrays
//
ArrayList modules;
//
// This is the type_cache from the assemblies to avoid
// hitting System.Reflection on every lookup.
//
Hashtable types;
//
// This is used to hotld the corresponding TypeContainer objects
// since we need this in FindMembers
//
Hashtable typecontainers;
//
// Keeps track of those types that are defined by the
// user's program
//
ArrayList user_types;
//
// Keeps a mapping between TypeBuilders and their TypeContainers
//
static Hashtable builder_to_container;
//
// Maps MethodBase.RuntimeTypeHandle to a Type array that contains
// the arguments to the method
//
static Hashtable method_arguments;
static Hashtable builder_to_interface;
//
// Keeps track of delegate types
//
static Hashtable builder_to_delegate;
//
// Keeps track of enum types
//
static Hashtable builder_to_enum;
public TypeManager ()
{
assemblies = new ArrayList ();
modules = new ArrayList ();
user_types = new ArrayList ();
types = new Hashtable ();
typecontainers = new Hashtable ();
builder_to_interface = new Hashtable ();
builder_to_delegate = new Hashtable ();
builder_to_enum = new Hashtable ();
}
static TypeManager ()
{
method_arguments = new Hashtable ();
builder_to_container = new Hashtable ();
type_interface_cache = new Hashtable ();
}
public void AddUserType (string name, TypeBuilder t)
{
types.Add (name, t);
user_types.Add (t);
}
public void AddUserType (string name, TypeBuilder t, TypeContainer tc)
{
AddUserType (name, t);
builder_to_container.Add (t, tc);
typecontainers.Add (name, tc);
}
public void AddDelegateType (string name, TypeBuilder t, Delegate del)
{
types.Add (name, t);
builder_to_delegate.Add (t, del);
}
public void AddEnumType (string name, TypeBuilder t, Enum en)
{
types.Add (name, t);
builder_to_enum.Add (t, en);
}
public void AddUserInterface (string name, TypeBuilder t, Interface i)
{
AddUserType (name, t);
builder_to_interface.Add (t, i);
}
//
// Returns the TypeContainer whose Type is `t' or null if there is no
// TypeContainer for `t' (ie, the Type comes from a library)
//
public static TypeContainer LookupTypeContainer (Type t)
{
return (TypeContainer) builder_to_container [t];
}
public Interface LookupInterface (Type t)
{
return (Interface) builder_to_interface [t];
}
public static Delegate LookupDelegate (Type t)
{
return (Delegate) builder_to_delegate [t];
}
//
// Registers an assembly to load types from.
//
public void AddAssembly (Assembly a)
{
assemblies.Add (a);
}
//
// Registers a module builder to lookup types from
//
public void AddModule (ModuleBuilder mb)
{
modules.Add (mb);
}
//
// Returns the Type associated with @name
//
public Type LookupType (string name)
{
Type t;
//
// First lookup in user defined and cached values
//
t = (Type) types [name];
if (t != null)
return t;
foreach (Assembly a in assemblies){
t = a.GetType (name);
if (t != null){
types [name] = t;
return t;
}
}
foreach (ModuleBuilder mb in modules) {
t = mb.GetType (name);
if (t != null) {
types [name] = t;
return t;
}
}
return null;
}
//
// Returns the C# name of a type if possible, or the full type name otherwise
//
static public string CSharpName (Type t)
{
if (t == int32_type)
return "int";
else if (t == uint32_type)
return "uint";
else if (t == int64_type)
return "long";
else if (t == uint64_type)
return "ulong";
else if (t == float_type)
return "float";
else if (t == double_type)
return "double";
else if (t == char_type)
return "char";
else if (t == short_type)
return "short";
else if (t == decimal_type)
return "decimal";
else if (t == bool_type)
return "bool";
else if (t == sbyte_type)
return "sbyte";
else if (t == byte_type)
return "byte";
else if (t == short_type)
return "short";
else if (t == ushort_type)
return "ushort";
else if (t == string_type)
return "string";
else if (t == object_type)
return "object";
else
return t.FullName;
}
//
// Looks up a type, and aborts if it is not found. This is used
// by types required by the compiler
//
Type CoreLookupType (string name)
{
Type t = LookupType (name);
if (t == null)
throw new Exception ("Can not find core type " + name);
return t;
}
//
// Returns the MethodInfo for a method named `name' defined
// in type `t' which takes arguments of types `args'
//
MethodInfo GetMethod (Type t, string name, Type [] args)
{
MethodInfo mi = t.GetMethod (name, args);
if (mi == null)
throw new Exception ("Can not find the core function `" + name + "'");
return mi;
}
//
// The types have to be initialized after the initial
// population of the type has happened (for example, to
// bootstrap the corlib.dll
//
public void InitCoreTypes ()
{
object_type = CoreLookupType ("System.Object");
value_type = CoreLookupType ("System.ValueType");
string_type = CoreLookupType ("System.String");
int32_type = CoreLookupType ("System.Int32");
int64_type = CoreLookupType ("System.Int64");
uint32_type = CoreLookupType ("System.UInt32");
uint64_type = CoreLookupType ("System.UInt64");
float_type = CoreLookupType ("System.Single");
double_type = CoreLookupType ("System.Double");
byte_type = CoreLookupType ("System.Byte");
sbyte_type = CoreLookupType ("System.SByte");
char_type = CoreLookupType ("System.Char");
short_type = CoreLookupType ("System.Int16");
ushort_type = CoreLookupType ("System.UInt16");
decimal_type = CoreLookupType ("System.Decimal");
bool_type = CoreLookupType ("System.Boolean");
enum_type = CoreLookupType ("System.Enum");
delegate_type = CoreLookupType ("System.MulticastDelegate");
array_type = CoreLookupType ("System.Array");
void_type = CoreLookupType ("System.Void");
type_type = CoreLookupType ("System.Type");
runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
asynccallback_type = CoreLookupType ("System.AsyncCallback");
iasyncresult_type = CoreLookupType ("System.IAsyncResult");
ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
idisposable_type = CoreLookupType ("System.IDisposable");
icloneable_type = CoreLookupType ("System.ICloneable");
monitor_type = CoreLookupType ("System.Threading.Monitor");
intptr_type = CoreLookupType ("System.IntPtr");
//
// Now load the default methods that we use.
//
Type [] string_string = { string_type, string_type };
string_concat_string_string = GetMethod (
string_type, "Concat", string_string);
Type [] object_object = { object_type, object_type };
string_concat_object_object = GetMethod (
string_type, "Concat", object_object);
Type [] runtime_type_handle = { runtime_handle_type };
system_type_get_type_from_handle = GetMethod (
type_type, "GetTypeFromHandle", runtime_type_handle);
//
// Void arguments
//
Type [] void_arg = { };
object_getcurrent_void = GetMethod (
ienumerator_type, "get_Current", void_arg);
bool_movenext_void = GetMethod (
ienumerator_type, "MoveNext", void_arg);
void_dispose_void = GetMethod (
idisposable_type, "Dispose", void_arg);
//
// object arguments
//
Type [] object_arg = { object_type };
void_monitor_enter_object = GetMethod (
monitor_type, "Enter", object_arg);
void_monitor_exit_object = GetMethod (
monitor_type, "Exit", object_arg);
Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
void_initializearray_array_fieldhandle = GetMethod (
runtime_helpers_type, "InitializeArray", array_field_handle_arg);
}
public MemberInfo [] FindMembers (Type t, MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria)
{
if (!(t is TypeBuilder))
return t.FindMembers (mt, bf, filter, criteria);
Enum e = (Enum) builder_to_enum [t];
if (e != null)
return e.FindMembers (mt, bf, filter, criteria);
Delegate del = (Delegate) builder_to_delegate [t];
if (del != null)
return del.FindMembers (mt, bf, filter, criteria);
Interface iface = (Interface) builder_to_interface [t];
if (iface != null)
return iface.FindMembers (mt, bf, filter, criteria);
TypeContainer tc = (TypeContainer) builder_to_container [t];
if (tc != null)
return tc.FindMembers (mt, bf, filter, criteria);
return null;
}
public static bool IsBuiltinType (Type t)
{
if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
t == int64_type || t == uint64_type || t == float_type || t == double_type ||
t == char_type || t == short_type || t == decimal_type || t == bool_type ||
t == sbyte_type || t == byte_type || t == ushort_type)
return true;
else
return false;
}
public static bool IsDelegateType (Type t)
{
Delegate del = (Delegate) builder_to_delegate [t];
if (del != null)
return true;
else
return false;
}
public static bool IsEnumType (Type t)
{
Enum en = (Enum) builder_to_enum [t];
if (en != null)
return true;
else
return false;
}
public static bool IsInterfaceType (Type t)
{
Interface iface = (Interface) builder_to_interface [t];
if (iface != null)
return true;
else
return false;
}
//
// Returns the User Defined Types
//
public ArrayList UserTypes {
get {
return user_types;
}
}
public Hashtable TypeContainers {
get {
return typecontainers;
}
}
static string GetSig (MethodBase mb)
{
if (mb is MethodBuilder || mb is ConstructorBuilder)
return mb.ReflectedType.FullName + ":" + mb;
else
return mb.MethodHandle.ToString ();
}
//
// Gigantic work around for stupidity in System.Reflection.Emit follows
//
// Since System.Reflection.Emit can not return MethodBase.GetParameters
// for anything which is dynamic, and we need this in a number of places,
// we register this information here, and use it afterwards.
//
static public bool RegisterMethod (MethodBase mb, Type [] args)
{
string s;
s = GetSig (mb);
if (method_arguments.Contains (s))
return false;
method_arguments.Add (s, args);
return true;
}
//
// Returns the argument types for a method based on its methodbase
//
// For dynamic methods, we use the compiler provided types, for
// methods from existing assemblies we load them from GetParameters,
// and insert them into the cache
//
static public Type [] GetArgumentTypes (MethodBase mb)
{
string sig = GetSig (mb);
object o = method_arguments [sig];
if (method_arguments.Contains (sig))
return (Type []) method_arguments [sig];
else {
ParameterInfo [] pi = mb.GetParameters ();
int c = pi.Length;
Type [] types = new Type [c];
for (int i = 0; i < c; i++)
types [i] = pi [i].ParameterType;
method_arguments.Add (sig, types);
return types;
}
}
//
// This is a workaround the fact that GetValue is not
// supported for dynamic types
//
static Hashtable fields;
static public bool RegisterField (FieldBuilder fb, object value)
{
if (fields == null)
fields = new Hashtable ();
if (fields.Contains (fb))
return false;
fields.Add (fb, value);
return true;
}
static public object GetValue (FieldBuilder fb)
{
return fields [fb];
}
static Hashtable properties;
static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
{
if (properties == null)
properties = new Hashtable ();
if (properties.Contains (pb))
return false;
properties.Add (pb, new DictionaryEntry (get, set));
return true;
}
static public MethodInfo [] GetAccessors (PropertyInfo pi)
{
MethodInfo [] ret;
if (pi is PropertyBuilder){
DictionaryEntry de = (DictionaryEntry) properties [pi];
ret = new MethodInfo [2];
ret [0] = (MethodInfo) de.Key;
ret [1] = (MethodInfo) de.Value;
return ret;
} else
return pi.GetAccessors ();
}
//
// The following is used to check if a given type implements an interface.
// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
//
static Hashtable type_interface_cache;
public static bool ImplementsInterface (Type t, Type iface)
{
Type [] interfaces = (Type []) type_interface_cache [t];
if (interfaces == null) {
if (type_interface_cache.Contains (t))
return false;
interfaces = t.GetInterfaces ();
type_interface_cache [t] = interfaces;
}
if (interfaces == null)
return false;
for (int i = interfaces.Length; i > 0; ) {
i--;
if (interfaces [i] == iface)
return true;
}
return false;
}
//
// Returns the name of the indexer in a given type. The default
// is not always `Item'. The user can change this behaviour by
// using the DefaultMemberAttribute in the class.
//
// For example, the String class indexer is named `Chars' not `Item'
//
public static string IndexerPropertyName (Type t)
{
//
// FIXME: Replace with something that works around S.R.E failure
//
#if FIXME
System.Attribute attr;
attr = System.Attribute.GetCustomAttribute (t, TypeManager.default_member_type);
if (attr != null)
{
DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
return dma.MemberName;
}
#endif
return "Item";
}
}
}