Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'mcs/ilasm/codegen/MethodDef.cs')
-rw-r--r--mcs/ilasm/codegen/MethodDef.cs751
1 files changed, 751 insertions, 0 deletions
diff --git a/mcs/ilasm/codegen/MethodDef.cs b/mcs/ilasm/codegen/MethodDef.cs
new file mode 100644
index 00000000000..8ed1268534e
--- /dev/null
+++ b/mcs/ilasm/codegen/MethodDef.cs
@@ -0,0 +1,751 @@
+//
+// Mono.ILASM.MethodDef
+//
+// Author(s):
+// Jackson Harper (Jackson@LatitudeGeo.com)
+//
+// (C) 2003 Jackson Harper, All rights reserved
+//
+
+
+using System;
+using System.Text;
+using System.Collections;
+using System.Security;
+
+namespace Mono.ILASM {
+
+ public class MethodDef : ICustomAttrTarget, IDeclSecurityTarget {
+
+ 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 BaseTypeRef ret_type;
+ private ArrayList param_list;
+ private ArrayList inst_list;
+ private ArrayList customattr_list;
+ private DeclSecurity decl_sec;
+ private Hashtable label_table;
+ private Hashtable labelref_table;
+ private ArrayList label_list;
+ private PEAPI.MethodDef methoddef;
+ private bool entry_point;
+ private bool zero_init;
+ private bool is_resolved;
+ private bool is_defined;
+ private ArrayList local_list;
+ private Hashtable named_local_table;
+ private bool init_locals;
+ private int max_stack;
+ private bool pinvoke_info;
+ private ExternModule pinvoke_mod;
+ 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;
+
+ public MethodDef (CodeGen codegen, PEAPI.MethAttr meth_attr,
+ PEAPI.CallConv call_conv, PEAPI.ImplAttr impl_attr,
+ 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;
+
+ inst_list = new ArrayList ();
+ label_table = new Hashtable ();
+ labelref_table = new Hashtable ();
+ label_list = new ArrayList ();
+ local_list = new ArrayList ();
+ named_local_table = new Hashtable ();
+
+ entry_point = false;
+ zero_init = false;
+ init_locals = false;
+ max_stack = -1;
+ pinvoke_info = false;
+
+ is_defined = false;
+ is_resolved = false;
+ ResolveGenParams ();
+ CreateSignature ();
+
+ codegen.BeginMethodDef (this);
+
+ if (codegen.SymbolWriter != null)
+ source = codegen.SymbolWriter.BeginMethod (this, start);
+ }
+
+ public string Name {
+ get { return name; }
+ }
+
+ public string Signature {
+ get { return signature; }
+ }
+
+ public BaseTypeRef RetType {
+ get { return ret_type; }
+ }
+
+ public PEAPI.CallConv CallConv {
+ get { return call_conv; }
+ }
+
+ public PEAPI.MethodDef PeapiMethodDef {
+ get { return methoddef; }
+ }
+
+ public PEAPI.MethAttr Attributes {
+ get { return meth_attr; }
+ set { meth_attr = value; }
+ }
+
+ public bool IsVararg {
+ get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
+ }
+
+ public bool IsStatic {
+ get { return (meth_attr & PEAPI.MethAttr.Static) != 0; }
+ }
+
+ public bool IsVirtual {
+ get { return (meth_attr & PEAPI.MethAttr.Virtual) != 0; }
+ }
+
+ public bool IsAbstract {
+ get { return (meth_attr & PEAPI.MethAttr.Abstract) != 0; }
+ }
+
+ public BaseTypeRef[] ParamTypeList () {
+
+ if (param_list == null)
+ return new BaseTypeRef[0];
+ int count = 0;
+ BaseTypeRef[] type_list = new BaseTypeRef[param_list.Count];
+ foreach (ParamDef param in param_list) {
+ type_list[count++] = param.Type;
+ }
+ return type_list;
+ }
+
+ public void AddPInvokeInfo (PEAPI.PInvokeAttr pinvoke_attr, ExternModule pinvoke_mod,
+ string pinvoke_name)
+ {
+ this.pinvoke_attr = pinvoke_attr;
+ this.pinvoke_mod = pinvoke_mod;
+ this.pinvoke_name = pinvoke_name;
+ pinvoke_info = true;
+ }
+
+ public int GenParamCount {
+ get { return (gen_params != null ? gen_params.Count : 0); }
+ }
+
+ public GenericParameter GetGenericParam (string id)
+ {
+ if (gen_params == null)
+ return null;
+
+ return gen_params.GetGenericParam (id);
+ }
+
+ public GenericParameter GetGenericParam (int index)
+ {
+ if (gen_params == null || index < 0 || index >= gen_params.Count)
+ return null;
+
+ return gen_params [index];
+ }
+
+ public int GetGenericParamNum (string id)
+ {
+ if (gen_params == null)
+ return -1;
+
+ return gen_params.GetGenericParamNum (id);
+ }
+
+ public void AddParamDefaultValue (int index, PEAPI.Constant defval)
+ {
+ if (param_list [index] != null) {
+ ((ParamDef)param_list [index]).AddDefaultValue (defval);
+ }
+ }
+
+ public void AddCustomAttribute (CustomAttr customattr)
+ {
+ if (customattr_list == null)
+ customattr_list = new ArrayList ();
+
+ customattr_list.Add (customattr);
+ }
+
+ public void AddPermissionSet (PEAPI.SecurityAction sec_action, PermissionSet ps)
+ {
+ if (decl_sec == null)
+ decl_sec = new DeclSecurity ();
+
+ decl_sec.AddPermissionSet (sec_action, ps);
+ }
+
+ public void AddPermission (PEAPI.SecurityAction sec_action, IPermission iper)
+ {
+ if (decl_sec == null)
+ decl_sec = new DeclSecurity ();
+
+ decl_sec.AddPermission (sec_action, iper);
+ }
+
+ public void AddRetTypeMarshalInfo (PEAPI.NativeType native_type)
+ {
+ this.ret_native_type = native_type;
+ }
+
+ public void AddLocals (ArrayList local_list)
+ {
+ int slot_pos = this.local_list.Count;
+
+ foreach (Local local in local_list) {
+ if (local.Slot == -1) {
+ local.Slot = slot_pos;
+ }
+ slot_pos++;
+ if (local.Name == null)
+ continue;
+ if(!named_local_table.Contains(local.Name))
+ named_local_table.Add (local.Name, local);
+ }
+
+ this.local_list.AddRange (local_list);
+ }
+
+ public Local GetNamedLocal (string name)
+ {
+ return (Local) named_local_table[name];
+ }
+
+ public int GetNamedLocalSlot (string name)
+ {
+ Local local = (Local) named_local_table[name];
+
+ return local.Slot;
+ }
+
+ public int GetNamedParamPos (string name)
+ {
+ int pos = -1;
+ if (!IsStatic)
+ pos ++;
+ foreach (ParamDef param in param_list) {
+ pos ++;
+ if (param.Name.CompareTo (name) == 0)
+ return pos;
+ }
+
+ return pos;
+ }
+
+ public ParamDef GetParam (int index)
+ {
+ if (param_list [index] != null)
+ return (ParamDef)param_list [index];
+ else
+ return null;
+ }
+
+ public void InitLocals ()
+ {
+ init_locals = true;
+ }
+
+ public void EntryPoint ()
+ {
+ if (!IsStatic)
+ Report.Error ("Non-static method as entrypoint.");
+ entry_point = true;
+ }
+
+ public void ZeroInit ()
+ {
+ zero_init = true;
+ }
+
+ public void SetMaxStack (int max_stack)
+ {
+ 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 = ret_type 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);
+ }
+
+ public PEAPI.MethodDef Resolve (CodeGen code_gen, PEAPI.ClassDef classdef)
+ {
+ if (is_resolved)
+ return methoddef;
+
+ PEAPI.Param [] param_array = GenerateParams (code_gen);
+ FixAttributes ();
+ ret_type.Resolve (code_gen);
+
+ if (classdef == null)
+ methoddef = code_gen.PEFile.AddMethod (meth_attr, impl_attr,
+ name, ret_type.PeapiType, param_array);
+ else
+ methoddef = classdef.AddMethod (meth_attr, impl_attr,
+ name, ret_type.PeapiType, param_array);
+
+ methoddef.AddCallConv (call_conv);
+
+ if (ret_native_type != null)
+ methoddef.AddRetTypeMarshallInfo (ret_native_type);
+
+ is_resolved = true;
+
+ return methoddef;
+ }
+
+ private PEAPI.Param [] GenerateParams (CodeGen code_gen)
+ {
+ PEAPI.Param[] param_array;
+
+ if (param_list != null && param_list.Count > 0) {
+ int param_count = param_list.Count;
+
+ // Remove the last param if its the sentinel, not sure what
+ // should happen with more then one sentinel
+ ParamDef last = (ParamDef) param_list [param_count-1];
+ if (last.IsSentinel ())
+ param_count--;
+
+ param_array = new PEAPI.Param [param_count];
+ for (int i = 0; i < param_count; i++) {
+ ParamDef paramdef = (ParamDef) param_list [i];
+ paramdef.Define (code_gen);
+ param_array [i] = paramdef.PeapiParam;
+ }
+
+ } else {
+ param_array = new PEAPI.Param [0];
+ }
+
+ return param_array;
+ }
+
+ public PEAPI.MethodRef GetVarargSig (PEAPI.Type[] opt)
+ {
+ if (!is_resolved)
+ throw new InternalErrorException ("Methods must be resolved before a vararg sig can be created.");
+
+ PEAPI.MethodRef methref = null;
+ StringBuilder sigbuilder = new StringBuilder ();
+ string sig;
+ foreach (PEAPI.Type t in opt)
+ sigbuilder.Append (opt + ", ");
+ sig = sigbuilder.ToString ();
+
+ if (vararg_sig_table == null) {
+ vararg_sig_table = new Hashtable ();
+ } else {
+ methref = vararg_sig_table [sig] as PEAPI.MethodRef;
+ }
+
+ if (methref == null) {
+ methref = methoddef.MakeVarArgSignature (opt);
+ vararg_sig_table [sig] = methref;
+ }
+
+ return methref;
+ }
+
+ /// <summary>
+ /// Define a member method
+ /// </summary>
+ public void Define (CodeGen code_gen)
+ {
+ if (is_defined)
+ return;
+
+ 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;
+ }
+
+ public void AddInstr (IInstr instr)
+ {
+ inst_list.Add (instr);
+ }
+
+ protected void WriteCode (CodeGen code_gen, PEAPI.MethodDef methoddef)
+ {
+ /// Add the custrom attributes to this method
+ if (customattr_list != null)
+ foreach (CustomAttr customattr in customattr_list) {
+ customattr.AddTo (code_gen, methoddef);
+ if (customattr.IsSuppressUnmanaged (code_gen))
+ methoddef.AddMethAttribute (PEAPI.MethAttr.HasSecurity);
+ }
+
+ /// Add declarative security to this method
+ if (decl_sec != null) {
+ decl_sec.AddTo (code_gen, methoddef);
+ methoddef.AddMethAttribute (PEAPI.MethAttr.HasSecurity);
+ }
+
+ // Generic type parameters
+ if (gen_params != null)
+ gen_params.Resolve (code_gen, methoddef);
+
+ if (IsAbstract)
+ return;
+
+ if (entry_point)
+ methoddef.DeclareEntryPoint ();
+
+ if (local_list.Count > 0) {
+ int ec = Report.ErrorCount;
+ PEAPI.Local[] local_array = new PEAPI.Local[local_list.Count];
+
+ foreach (Local local in local_list)
+ local_array[local.Slot] = local.GetPeapiLocal (code_gen);
+
+ if (Report.ErrorCount > ec)
+ return;
+
+ if (zero_init)
+ init_locals = true;
+
+ methoddef.AddLocals (local_array, init_locals);
+ }
+
+ /// Nothing seems to work if maxstack is not set,
+ /// i need to find out if this NEEDs to be set
+ /// and what its default value should be
+ if (max_stack < 0)
+ max_stack = 8;
+ methoddef.SetMaxStack (max_stack);
+
+ if (pinvoke_info) {
+ methoddef.AddPInvokeInfo (pinvoke_mod.ModuleRef,
+ (pinvoke_name != null ? pinvoke_name : name), pinvoke_attr);
+ }
+
+ if (inst_list.Count < 1)
+ return;
+
+ PEAPI.CILInstructions cil = methoddef.CreateCodeBuffer ();
+ /// Create all the labels
+ /// TODO: Most labels don't actually need to be created so we could
+ /// probably only create the ones that need to be
+ LabelInfo[] label_info = new LabelInfo[label_table.Count + label_list.Count];
+ label_table.Values.CopyTo (label_info, 0);
+ label_list.CopyTo (label_info, label_table.Count);
+ int previous_pos = -1;
+ LabelInfo previous_label = null;
+ Array.Sort (label_info);
+
+ foreach (LabelInfo label in label_info) {
+ if (label.UseOffset) {
+ label.Define (new PEAPI.CILLabel (label.Offset));
+ continue;
+ }
+ if (label.Pos == previous_pos)
+ label.Label = previous_label.Label;
+ else
+ label.Define (cil.NewLabel ());
+
+ previous_label = label;
+ previous_pos = label.Pos;
+ }
+
+ // Set all the label refs
+ foreach (LabelInfo label in labelref_table.Values) {
+ LabelInfo def = (LabelInfo) label_table[label.Name];
+ if (def == null) {
+ Report.Error ("Undefined Label: " + label);
+ return;
+ }
+ label.Label = def.Label;
+ }
+
+ int label_pos = 0;
+ int next_label_pos = (label_info.Length > 0 ? label_info[0].Pos : -1);
+
+ for (int i=0; i<inst_list.Count; i++) {
+ IInstr instr = (IInstr) inst_list[i];
+ if (next_label_pos == i) {
+ cil.CodeLabel (label_info[label_pos].Label);
+ if (label_pos < label_info.Length) {
+ while (next_label_pos == i && ++label_pos < label_info.Length) {
+ if (label_info[label_pos].UseOffset)
+ cil.CodeLabel (label_info[label_pos].Label);
+ next_label_pos = label_info[label_pos].Pos;
+ }
+ }
+ if (label_pos >= label_info.Length)
+ next_label_pos = -1;
+ }
+ if (source != null)
+ source.MarkLocation (instr.Location.line, cil.Offset);
+ instr.Emit (code_gen, this, cil);
+ }
+
+ if (source != null)
+ source.MarkLocation (source.EndLine, cil.Offset);
+ }
+
+ public LabelInfo AddLabel (string name)
+ {
+ LabelInfo label_info = (LabelInfo) label_table[name];
+ if (label_info != null)
+ return label_info;
+ label_info = new LabelInfo (name, inst_list.Count);
+ label_table.Add (name, label_info);
+ return label_info;
+ }
+
+ public LabelInfo AddLabelRef (string name)
+ {
+ LabelInfo label_info = (LabelInfo) label_table[name];
+ if (label_info != null)
+ return label_info;
+ label_info = (LabelInfo) labelref_table[name];
+ if (label_info != null)
+ return label_info;
+ label_info = new LabelInfo (name, -1);
+ labelref_table.Add (name, label_info);
+ return label_info;
+ }
+
+ public LabelInfo AddLabel (int offset)
+ {
+ // We go pos + 1 so this line is not counted
+ LabelInfo label_info = new LabelInfo (null, inst_list.Count+1, (uint) offset);
+ label_list.Add (label_info);
+ return label_info;
+ }
+
+ public LabelInfo AddLabel ()
+ {
+ LabelInfo label_info = new LabelInfo (null, inst_list.Count);
+ label_list.Add (label_info);
+ return label_info;
+ }
+
+ public PEAPI.CILLabel GetLabelDef (string name)
+ {
+ LabelInfo label_info = (LabelInfo) label_table[name];
+
+ return label_info.Label;
+ }
+
+ public PEAPI.CILLabel GetLabelDef (int pos)
+ {
+ foreach (LabelInfo li in label_list) {
+ if (li.Pos == pos)
+ return li.Label;
+ }
+ return null;
+ }
+
+ private void CreateSignature ()
+ {
+ if (IsVararg)
+ signature = CreateVarargSignature (RetType, name, param_list);
+ else
+ signature = CreateSignature (RetType, name, param_list, GenParamCount);
+ }
+
+ 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) {
+ bool first = true;
+ foreach (ParamDef paramdef in param_list) {
+ if (!first)
+ builder.Append (',');
+ builder.Append (paramdef.TypeName);
+ first = false;
+ }
+ }
+ builder.Append (')');
+
+ return builder.ToString ();
+ }
+
+ public static string CreateVarargSignature (BaseTypeRef RetType, string name, IList param_list)
+ {
+ StringBuilder builder = new StringBuilder ();
+ ParamDef last = null;
+
+ builder.Append (RetType.FullName);
+ builder.Append (" ");
+ builder.Append (name);
+ builder.Append ('(');
+
+ bool first = true;
+ if (param_list != null) {
+ foreach (ParamDef paramdef in param_list) {
+ if (!first)
+ builder.Append (',');
+ builder.Append (paramdef.TypeName);
+ first = false;
+ }
+ last = (ParamDef) param_list[param_list.Count - 1];
+ }
+
+
+ if (last == null || !last.IsSentinel ()) {
+ if (!first)
+ builder.Append (',');
+ builder.Append ("...");
+ }
+
+ builder.Append (')');
+
+ return builder.ToString ();
+ }
+
+ public static string CreateVarargSignature (BaseTypeRef RetType, string name, BaseTypeRef [] param_list)
+ {
+ StringBuilder builder = new StringBuilder ();
+ BaseTypeRef last = null;
+
+ builder.Append (RetType.FullName);
+ builder.Append (" ");
+ builder.Append (name);
+ builder.Append ('(');
+
+ bool first = true;
+ if (param_list != null && param_list.Length > 0) {
+ foreach (BaseTypeRef param in param_list) {
+ if (!first)
+ builder.Append (',');
+ builder.Append (param.FullName);
+ first = false;
+ last = param;
+ if (param is SentinelTypeRef)
+ break;
+ }
+
+ }
+
+ if (last == null || !(last is SentinelTypeRef)) {
+ if (!first)
+ builder.Append (',');
+ builder.Append ("...");
+ }
+
+ builder.Append (')');
+
+ return builder.ToString ();
+ }
+
+ 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 (BaseTypeRef param in param_list) {
+ if (!first)
+ builder.Append (',');
+ builder.Append (param.FullName);
+ first = false;
+ if (param is SentinelTypeRef)
+ break;
+ }
+ }
+ builder.Append (')');
+
+ return builder.ToString ();
+ }
+
+ private void FixAttributes ()
+ {
+ if (name == ".ctor" || name == ".cctor")
+ meth_attr |= PEAPI.MethAttr.SpecialName | PEAPI.MethAttr.RTSpecialName;
+ // If methods aren't flagged as static they are instance
+ if ((PEAPI.MethAttr.Static & meth_attr) == 0)
+ call_conv |= PEAPI.CallConv.Instance;
+ }
+
+ }
+
+}
+