2006-11-14 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / ilasm / codegen / MethodDef.cs
index 7d4e98474a061d908f26708e3f2756902a6f9160..152113cc418fa2f5e484a7c15f8c88e0551120b5 100644 (file)
 using System;
 using System.Text;
 using System.Collections;
-
+using System.Security;
 
 namespace Mono.ILASM {
 
         public class MethodDef : ICustomAttrTarget, IDeclSecurityTarget {
 
-                protected class GenericInfo {
-                        public string Id;
-                        public ArrayList ConstraintList;
-                }
-
                 private PEAPI.MethAttr meth_attr;
                 private PEAPI.CallConv call_conv;
                 private PEAPI.ImplAttr impl_attr;
                 private string name;
                 private string signature;
                 private Hashtable vararg_sig_table;
-                private ITypeRef ret_type;
-                private ArrayList typar_list;
+                private ParamDef ret_param;
                 private ArrayList param_list;
                 private ArrayList inst_list;
                 private ArrayList customattr_list;
-                private ArrayList declsecurity_list;
+                private DeclSecurity decl_sec;
                 private Hashtable label_table;
                 private Hashtable labelref_table;
                 private ArrayList label_list;
@@ -51,19 +45,24 @@ namespace Mono.ILASM {
                 private string pinvoke_name;
                 private PEAPI.PInvokeAttr pinvoke_attr;
                private SourceMethod source;
-                private PEAPI.NativeType ret_native_type;
+                private TypeDef type_def;
+                private GenericParameters gen_params;
+                private Location start;
 
                 public MethodDef (CodeGen codegen, PEAPI.MethAttr meth_attr,
                                  PEAPI.CallConv call_conv, PEAPI.ImplAttr impl_attr,
-                                 string name, ITypeRef ret_type, ArrayList param_list,
-                                 Location start)
+                                 string name, BaseTypeRef ret_type, ArrayList param_list,
+                                 Location start, GenericParameters gen_params, TypeDef type_def)
                 {
                         this.meth_attr = meth_attr;
                         this.call_conv = call_conv;
                         this.impl_attr = impl_attr;
                         this.name = name;
-                        this.ret_type = ret_type;
                         this.param_list = param_list;
+                        this.type_def = type_def;
+                        this.gen_params = gen_params;
+                        this.ret_param = new ParamDef (PEAPI.ParamAttr.Default, "", ret_type);
+                        this.start = (Location) start.Clone ();
 
                         inst_list = new ArrayList ();
                         label_table = new Hashtable ();
@@ -80,6 +79,7 @@ namespace Mono.ILASM {
 
                         is_defined = false;
                         is_resolved = false;
+                        ResolveGenParams ();
                         CreateSignature ();
 
                        codegen.BeginMethodDef (this);
@@ -96,8 +96,8 @@ namespace Mono.ILASM {
                         get { return signature; }
                 }
 
-                public ITypeRef RetType {
-                        get { return ret_type; }
+                public BaseTypeRef RetType {
+                        get { return ret_param.Type; }
                 }
 
                 public PEAPI.CallConv CallConv {
@@ -129,12 +129,32 @@ namespace Mono.ILASM {
                         get { return (meth_attr & PEAPI.MethAttr.Abstract) != 0; }
                 }
 
-                public ITypeRef[] ParamTypeList () {
+                public Location StartLocation {
+                        get { return start; }
+                }
+
+                public DeclSecurity DeclSecurity {
+                        get {
+                                if (decl_sec == null)
+                                        decl_sec = new DeclSecurity ();
+                                return decl_sec;
+                        }
+                }
+
+                public string FullName { 
+                        get {
+                                if (type_def == null)
+                                        return Name;
+                                return type_def.FullName + "." + Name;
+                        }
+                }
+
+                public BaseTypeRef[] ParamTypeList () {
 
                         if (param_list == null)
-                                return new ITypeRef[0];
+                                return new BaseTypeRef[0];
                         int count = 0;
-                        ITypeRef[] type_list = new ITypeRef[param_list.Count];
+                        BaseTypeRef[] type_list = new BaseTypeRef[param_list.Count];
                         foreach (ParamDef param in param_list) {
                                 type_list[count++] = param.Type;
                         }
@@ -150,31 +170,32 @@ namespace Mono.ILASM {
                         pinvoke_info = true;
                 }
 
-                public void AddGenericParam (string id)
-                {
-                        if (typar_list == null)
-                                typar_list = new ArrayList ();
-
-                        GenericInfo gi = new GenericInfo ();
-                        gi.Id = id;
-
-                        typar_list.Add (gi);
+                public int GenParamCount {
+                        get { return (gen_params != null ? gen_params.Count : 0); }
                 }
 
-                public void AddGenericConstraint (int index, ITypeRef constraint)
+                public GenericParameter GetGenericParam (string id)
                 {
-                        GenericInfo gi = (GenericInfo) typar_list[index];
+                        if (gen_params == null)
+                                return null;
+                        
+                        return gen_params.GetGenericParam (id);
+                }
 
-                        if (gi.ConstraintList == null)
-                                gi.ConstraintList = new ArrayList ();
-                        gi.ConstraintList.Add (constraint);
+                public GenericParameter GetGenericParam (int index)
+                {
+                        if (gen_params == null || index < 0 || index >= gen_params.Count)
+                                return null;
+                        
+                        return gen_params [index];
                 }
 
-                public void AddParamDefaultValue (int index, PEAPI.Constant defval)
+                public int GetGenericParamNum (string id)
                 {
-                        if (param_list [index] != null) {
-                                ((ParamDef)param_list [index]).AddDefaultValue (defval);
-                        }
+                        if (gen_params == null)
+                                return -1;
+                        
+                        return gen_params.GetGenericParamNum (id);
                 }
 
                 public void AddCustomAttribute (CustomAttr customattr)
@@ -185,17 +206,9 @@ namespace Mono.ILASM {
                         customattr_list.Add (customattr);
                 }
 
-                public void AddDeclSecurity (DeclSecurity declsecurity)
-                {
-                        if (declsecurity_list == null)
-                                declsecurity_list = new ArrayList ();
-
-                        declsecurity_list.Add (declsecurity);
-                }
-
                 public void AddRetTypeMarshalInfo (PEAPI.NativeType native_type)
                 {
-                        this.ret_native_type = native_type;
+                        this.ret_param.AddMarshalInfo (native_type);
                 }
 
                 public void AddLocals (ArrayList local_list)
@@ -231,6 +244,9 @@ namespace Mono.ILASM {
                 public int GetNamedParamPos (string name)
                 {
                         int pos = -1;
+                        if (param_list == null)
+                                return -1;
+
                         if (!IsStatic)
                                 pos ++;
                         foreach (ParamDef param in param_list) {
@@ -242,8 +258,19 @@ namespace Mono.ILASM {
                         return pos;
                 }
 
+                /* index - 0: return type
+                 *         1: params start from this
+                 */
                 public ParamDef GetParam (int index)
                 {
+                        if (index == 0)
+                                return ret_param;
+
+                        if ((param_list == null) || (index < 0) || (index > param_list.Count))
+                                return null;
+
+                        index --; /* param_list has params zero-based */
+
                         if (param_list [index] != null)
                                 return (ParamDef)param_list [index];
                         else
@@ -258,7 +285,7 @@ namespace Mono.ILASM {
                 public void EntryPoint ()
                 {
                         if (!IsStatic)
-                                throw new Exception ("Non-static method as entrypoint.");
+                                Report.Error ("Non-static method as entrypoint.");
                         entry_point = true;
                 }
 
@@ -272,6 +299,46 @@ namespace Mono.ILASM {
                         this.max_stack = max_stack;
                 }
 
+               public void ResolveGenParam (PEAPI.GenParam gpar)
+               {
+                       if (gpar.Index != -1)
+                               return;
+       
+                       if (gpar.Type == PEAPI.GenParamType.MVar)
+                               gpar.Index = GetGenericParamNum (gpar.Name); 
+                       else
+                               gpar.Index = type_def.GetGenericParamNum (gpar.Name);
+
+                       if (gpar.Index < 0)
+                               Report.Error (String.Format ("Invalid {0}type parameter '{1}'", 
+                                                       (gpar.Type == PEAPI.GenParamType.MVar ? "method " : ""),
+                                                        gpar.Name));
+               }
+
+                public void ResolveGenParams ()
+                {
+                       GenericParameters type_params = (type_def != null) ? type_def.TypeParameters : null;
+
+                       if (gen_params == null && type_params == null)
+                               return;
+
+                       if (gen_params != null)
+                               gen_params.ResolveConstraints (type_params, gen_params);
+                       
+                       BaseGenericTypeRef gtr = RetType as BaseGenericTypeRef;
+                       if (gtr != null)
+                               gtr.Resolve (type_params, gen_params);
+
+                       if (param_list == null)
+                               return;
+
+                       foreach (ParamDef param in param_list) {
+                               gtr = param.Type as BaseGenericTypeRef;
+                               if (gtr != null)
+                                       gtr.Resolve (type_params, gen_params);
+                        }        
+                }
+
                 public PEAPI.MethodDef Resolve (CodeGen code_gen)
                 {
                         return Resolve (code_gen, null);
@@ -284,20 +351,17 @@ namespace Mono.ILASM {
 
                         PEAPI.Param [] param_array = GenerateParams (code_gen);
                         FixAttributes ();
-                        ret_type.Resolve (code_gen);
+                        ret_param.Define (code_gen);
 
                         if (classdef == null)
                                 methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
-                                                name, ret_type.PeapiType, param_array);
+                                                name, ret_param.PeapiParam, param_array);
                         else                   
                                 methoddef = classdef.AddMethod (meth_attr, impl_attr,
-                                                name, ret_type.PeapiType, param_array);
+                                                name, ret_param.PeapiParam, param_array);
 
                         methoddef.AddCallConv (call_conv);
 
-                        if (ret_native_type != null)
-                                methoddef.AddRetTypeMarshallInfo (ret_native_type);
-
                         is_resolved = true;
 
                         return methoddef;
@@ -333,7 +397,7 @@ namespace Mono.ILASM {
                 public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
                 {
                         if (!is_resolved)
-                                throw new Exception ("Methods must be resolved before a vararg sig can be created.");
+                                throw new InternalErrorException ("Methods must be resolved before a vararg sig can be created.");
 
                         PEAPI.MethodRef methref = null;
                         StringBuilder sigbuilder = new StringBuilder ();
@@ -356,34 +420,24 @@ namespace Mono.ILASM {
                         return methref;
                 }
 
-                /// <summary>
-                ///  Define a global method
-                /// </summary>
-                public void Define (CodeGen code_gen)
-                {
-                        if (is_defined)
-                                return;
-
-                        Resolve (code_gen);
-
-                        WriteCode (code_gen, methoddef);
-
-                        //code_gen.Report.Message (String.Format ("Assembled method '<Module>'::{0}", name));
-                        is_defined = true;
-                }
-
                 /// <summary>
                 ///  Define a member method
                 /// </summary>
-                public void Define (CodeGen code_gen, TypeDef typedef)
+                public void Define (CodeGen code_gen)
                 {
                         if (is_defined)
                                 return;
 
-                        Resolve (code_gen, (PEAPI.ClassDef) typedef.ClassDef);
+                        if (type_def == null)
+                                /* Global method */
+                                Resolve (code_gen, null);
+                        else
+                                Resolve (code_gen, (PEAPI.ClassDef) type_def.ClassDef);
+                                
                         WriteCode (code_gen, methoddef);
 
-                        //code_gen.Report.Message (String.Format ("Assembled method {0}::{1}", typedef.FullName, name));                        is_defined = true;
+                        //code_gen.Report.Message (String.Format ("Assembled method {0}::{1}", typedef.FullName, name));
+                       is_defined = true;
                 }
 
                 public void AddInstr (IInstr instr)
@@ -402,28 +456,44 @@ namespace Mono.ILASM {
                                }
 
                         /// Add declarative security to this method
-                        if (declsecurity_list != null) {
-                                foreach (DeclSecurity declsecurity in declsecurity_list)
-                                        declsecurity.AddTo (code_gen, methoddef);
-
+                       if (decl_sec != null) {
+                               decl_sec.AddTo (code_gen, methoddef);
                                 methoddef.AddMethAttribute (PEAPI.MethAttr.HasSecurity);
                         }        
 
-                        if (IsAbstract)
-                                return;
+                        // Generic type parameters
+                        if (gen_params != null)
+                                gen_params.Resolve (code_gen, methoddef);
+
+                        if (type_def == null) {
+                                //Global method
+                                meth_attr &= ~PEAPI.MethAttr.Abstract;
+                                meth_attr |= PEAPI.MethAttr.Static;
+                        } else {
+                                if ((inst_list.Count > 0) && type_def.IsInterface && !IsStatic)
+                                        Report.Error (start, "Method cannot have body if it is non-static declared in an interface");
+                                
+                                if (IsAbstract) {
+                                        if (!type_def.IsAbstract)
+                                                Report.Error (start, String.Format ("Abstract method '{0}' in non-abstract class '{1}'", 
+                                                                        Name, type_def.FullName));
+                                        if (inst_list.Count > 0)
+                                                Report.Error (start, "Method cannot have body if it is abstract.");
+                                        return;
+                                }
+                        }
 
                         if (entry_point)
                                 methoddef.DeclareEntryPoint ();
 
                         if (local_list.Count > 0) {
-                                int ec = code_gen.Report.ErrorCount;
+                                int ec = Report.ErrorCount;
                                 PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
-                                int i = 0;
 
                                 foreach (Local local in local_list)
                                         local_array[local.Slot]  = local.GetPeapiLocal (code_gen);
 
-                                if (code_gen.Report.ErrorCount > ec)
+                                if (Report.ErrorCount > ec)
                                         return;
 
                                 if (zero_init)
@@ -444,8 +514,36 @@ namespace Mono.ILASM {
                                                 (pinvoke_name != null ? pinvoke_name : name), pinvoke_attr);
                         }
 
-                        if (inst_list.Count < 1)
-                                return;
+                        if ((impl_attr & PEAPI.ImplAttr.Runtime) == PEAPI.ImplAttr.Runtime) {
+                                if (inst_list.Count > 0)
+                                        Report.Error (start, String.Format ("Method cannot have body if it is non-IL runtime-supplied, '{0}'", 
+                                                                FullName));
+                        } else {
+                                if (((impl_attr & PEAPI.ImplAttr.Native) != 0) ||
+                                        ((impl_attr & PEAPI.ImplAttr.Unmanaged) != 0))
+                                        Report.Error (start, String.Format ("Cannot compile native/unmanaged method, '{0}'", 
+                                                                FullName));
+                        }
+
+                        if (inst_list.Count > 0) {
+                                /* Has body */
+                                if ((impl_attr & PEAPI.ImplAttr.InternalCall) != 0)
+                                        Report.Error (start, String.Format ("Method cannot have body if it is an internal call, '{0}'", 
+                                                                FullName));
+
+                                if (pinvoke_info)
+                                        Report.Error (start, String.Format ("Method cannot have body if it is pinvoke, '{0}'",
+                                                                FullName));
+                        } else {
+                                if (pinvoke_info ||
+                                        ((impl_attr & PEAPI.ImplAttr.Runtime) != 0) ||
+                                        ((impl_attr & PEAPI.ImplAttr.InternalCall) != 0))
+                                        /* No body required */
+                                        return;
+
+                                Report.Warning (start, "Method has no body, 'ret' emitted.");
+                                AddInstr (new SimpInstr (PEAPI.Op.ret, start));
+                        }
 
                         PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
                         /// Create all the labels
@@ -476,7 +574,7 @@ namespace Mono.ILASM {
                         foreach (LabelInfo label in labelref_table.Values) {
                                 LabelInfo def = (LabelInfo) label_table[label.Name];
                                 if (def == null) {
-                                        code_gen.Report.Error ("Undefined Label:  " + label);
+                                        Report.Error ("Undefined Label:  " + label);
                                         return;
                                 }
                                 label.Label = def.Label;
@@ -506,29 +604,16 @@ namespace Mono.ILASM {
 
                        if (source != null)
                                source.MarkLocation (source.EndLine, cil.Offset);
-
-                        // Generic type parameters
-                        if (typar_list != null) {
-                                short index = 0;
-                                foreach (GenericInfo gi in typar_list) {
-                                        PEAPI.GenericParameter gp = methoddef.AddGenericParameter (index++, gi.Id);
-                                        if (gi.ConstraintList != null) {
-                                                foreach (ITypeRef cnst in gi.ConstraintList) {
-                                                        cnst.Resolve (code_gen);
-                                                        gp.AddConstraint (cnst.PeapiType);
-                                                }
-                                        }
-                                }
-                        }
                 }
 
                 public LabelInfo AddLabel (string name)
                 {
                         LabelInfo label_info = (LabelInfo) label_table[name];
                         if (label_info != null)
-                                return label_info;
+                                Report.Error ("Duplicate label '" + name + "'");
+
                         label_info = new LabelInfo (name, inst_list.Count);
-                        label_table.Add (name, label_info);
+                        label_table [name] = label_info;
                         return label_info;
                 }
 
@@ -555,7 +640,6 @@ namespace Mono.ILASM {
 
                 public LabelInfo AddLabel ()
                 {
-                        int pos = inst_list.Count;
                         LabelInfo label_info = new LabelInfo (null, inst_list.Count);
                         label_list.Add (label_info);
                         return label_info;
@@ -582,16 +666,18 @@ namespace Mono.ILASM {
                         if (IsVararg)
                                 signature = CreateVarargSignature (RetType, name, param_list);
                         else
-                                signature = CreateSignature (RetType, name, param_list);
+                                signature = CreateSignature (RetType, name, param_list, GenParamCount);
                 }
 
-                public static string CreateSignature (ITypeRef RetType, string name, IList param_list)
+                public static string CreateSignature (BaseTypeRef RetType, string name, IList param_list, int gen_param_count)
                 {
                         StringBuilder builder = new StringBuilder ();
 
                        builder.Append (RetType.FullName);
                        builder.Append (" ");
                         builder.Append (name);
+                        if (gen_param_count > 0)
+                                builder.AppendFormat ("`{0}", gen_param_count);
                         builder.Append ('(');
 
                         if (param_list != null) {
@@ -608,7 +694,7 @@ namespace Mono.ILASM {
                         return builder.ToString ();
                 }
 
-                public static string CreateVarargSignature (ITypeRef RetType, string name, IList param_list)
+                public static string CreateVarargSignature (BaseTypeRef RetType, string name, IList param_list)
                 {
                         StringBuilder builder = new StringBuilder ();
                         ParamDef last = null;
@@ -641,10 +727,10 @@ namespace Mono.ILASM {
                         return builder.ToString ();
                 }
 
-                public static string CreateVarargSignature (ITypeRef RetType, string name, ITypeRef [] param_list)
+                public static string CreateVarargSignature (BaseTypeRef RetType, string name, BaseTypeRef [] param_list)
                 {
                         StringBuilder builder = new StringBuilder ();
-                        ITypeRef last = null;
+                        BaseTypeRef last = null;
 
                        builder.Append (RetType.FullName);
                        builder.Append (" ");
@@ -653,7 +739,7 @@ namespace Mono.ILASM {
 
                         bool first = true;
                         if (param_list != null && param_list.Length > 0) {
-                                foreach (ITypeRef param in param_list) {
+                                foreach (BaseTypeRef param in param_list) {
                                         if (!first)
                                                 builder.Append (',');
                                         builder.Append (param.FullName);
@@ -676,18 +762,20 @@ namespace Mono.ILASM {
                         return builder.ToString ();
                 }
 
-                public static string CreateSignature (ITypeRef RetType, string name, ITypeRef[] param_list)
+                public static string CreateSignature (BaseTypeRef RetType, string name, BaseTypeRef[] param_list, int gen_param_count)
                 {
                         StringBuilder builder = new StringBuilder ();
 
                        builder.Append (RetType.FullName);
                        builder.Append (" ");
                         builder.Append (name);
+                        if (gen_param_count > 0)
+                                builder.AppendFormat ("`{0}", gen_param_count);
                         builder.Append ('(');
 
                         if (param_list != null) {
                                 bool first = true;
-                                foreach (ITypeRef param in param_list) {
+                                foreach (BaseTypeRef param in param_list) {
                                         if (!first)
                                                 builder.Append (',');
                                         builder.Append (param.FullName);