2 // Mono.ILASM.MethodDef
5 // Jackson Harper (Jackson@LatitudeGeo.com)
7 // (C) 2003 Jackson Harper, All rights reserved
13 using System
.Collections
;
16 namespace Mono
.ILASM
{
18 public class MethodDef
{
20 protected class GenericInfo
{
22 public ArrayList ConstraintList
;
25 private PEAPI
.MethAttr meth_attr
;
26 private PEAPI
.CallConv call_conv
;
27 private PEAPI
.ImplAttr impl_attr
;
29 private string signature
;
30 private Hashtable vararg_sig_table
;
31 private ITypeRef ret_type
;
32 private ArrayList typar_list
;
33 private ArrayList param_list
;
34 private Hashtable named_param_table
;
35 private ArrayList inst_list
;
36 private ArrayList customattr_list
;
37 private Hashtable label_table
;
38 private Hashtable labelref_table
;
39 private ArrayList label_list
;
40 private PEAPI
.MethodDef methoddef
;
41 private bool entry_point
;
42 private bool zero_init
;
43 private bool is_resolved
;
44 private bool is_defined
;
45 private ArrayList local_list
;
46 private Hashtable named_local_table
;
47 private bool init_locals
;
48 private int max_stack
;
49 private bool pinvoke_info
;
50 private ExternModule pinvoke_mod
;
51 private string pinvoke_name
;
52 private PEAPI
.PInvokeAttr pinvoke_attr
;
53 private SourceMethod source
;
55 public MethodDef (CodeGen codegen
, PEAPI
.MethAttr meth_attr
,
56 PEAPI
.CallConv call_conv
, PEAPI
.ImplAttr impl_attr
,
57 string name
, ITypeRef ret_type
, ArrayList param_list
,
60 this.meth_attr
= meth_attr
;
61 this.call_conv
= call_conv
;
62 this.impl_attr
= impl_attr
;
64 this.ret_type
= ret_type
;
65 this.param_list
= param_list
;
67 inst_list
= new ArrayList ();
68 customattr_list
= new ArrayList ();
69 label_table
= new Hashtable ();
70 labelref_table
= new Hashtable ();
71 label_list
= new ArrayList ();
72 local_list
= new ArrayList ();
73 named_local_table
= new Hashtable ();
74 named_param_table
= new Hashtable ();
85 CreateNamedParamTable ();
87 codegen
.BeginMethodDef (this);
89 if (codegen
.SymbolWriter
!= null)
90 source
= codegen
.SymbolWriter
.BeginMethod (this, start
);
97 public string Signature
{
98 get { return signature; }
101 public ITypeRef RetType
{
102 get { return ret_type; }
105 public PEAPI
.CallConv CallConv
{
106 get { return call_conv; }
109 public PEAPI
.MethodDef PeapiMethodDef
{
110 get { return methoddef; }
113 public bool IsVararg
{
114 get { return (call_conv & PEAPI.CallConv.Vararg) != 0; }
117 public bool IsStatic
{
118 get { return (meth_attr & PEAPI.MethAttr.Static) != 0; }
121 public ITypeRef
[] ParamTypeList () {
123 if (param_list
== null)
124 return new ITypeRef
[0];
126 ITypeRef
[] type_list
= new ITypeRef
[param_list
.Count
];
127 foreach (ParamDef param
in param_list
) {
128 type_list
[count
++] = param
.Type
;
133 public void AddPInvokeInfo (PEAPI
.PInvokeAttr pinvoke_attr
, ExternModule pinvoke_mod
,
136 this.pinvoke_attr
= pinvoke_attr
;
137 this.pinvoke_mod
= pinvoke_mod
;
138 this.pinvoke_name
= pinvoke_name
;
142 public void AddGenericParam (string id
)
144 if (typar_list
== null)
145 typar_list
= new ArrayList ();
147 GenericInfo gi
= new GenericInfo ();
153 public void AddGenericConstraint (int index
, ITypeRef constraint
)
155 GenericInfo gi
= (GenericInfo
) typar_list
[index
];
157 if (gi
.ConstraintList
== null)
158 gi
.ConstraintList
= new ArrayList ();
159 gi
.ConstraintList
.Add (constraint
);
162 public void AddLocals (ArrayList local_list
)
164 int slot_pos
= this.local_list
.Count
;
166 foreach (Local local
in local_list
) {
167 if (local
.Slot
== -1) {
168 local
.Slot
= slot_pos
;
171 if (local
.Name
== null)
173 named_local_table
.Add (local
.Name
, local
);
176 this.local_list
.AddRange (local_list
);
179 public Local
GetNamedLocal (string name
)
181 return (Local
) named_local_table
[name
];
184 public int GetNamedLocalSlot (string name
)
186 Local local
= (Local
) named_local_table
[name
];
191 public int GetNamedParamPos (string name
)
193 int pos
= (int) named_param_table
[name
];
198 public void InitLocals ()
203 public void EntryPoint ()
208 public void ZeroInit ()
213 public void SetMaxStack (int max_stack
)
215 this.max_stack
= max_stack
;
218 public void AddCustomAttr (CustomAttr customattr
)
220 customattr_list
.Add (customattr
);
223 public PEAPI
.MethodDef
Resolve (CodeGen code_gen
)
228 PEAPI
.Param
[] param_array
= GenerateParams (code_gen
);
230 ret_type
.Resolve (code_gen
);
232 methoddef
= code_gen
.PEFile
.AddMethod (meth_attr
, impl_attr
,
233 name
, ret_type
.PeapiType
, param_array
);
235 methoddef
.AddCallConv (call_conv
);
241 public PEAPI
.MethodDef
Resolve (CodeGen code_gen
, PEAPI
.ClassDef classdef
)
246 PEAPI
.Param
[] param_array
= GenerateParams (code_gen
);
248 ret_type
.Resolve (code_gen
);
250 methoddef
= classdef
.AddMethod (meth_attr
, impl_attr
,
251 name
, ret_type
.PeapiType
, param_array
);
253 methoddef
.AddCallConv (call_conv
);
259 private PEAPI
.Param
[] GenerateParams (CodeGen code_gen
)
261 PEAPI
.Param
[] param_array
;
263 if (param_list
!= null && param_list
.Count
> 0) {
264 int param_count
= param_list
.Count
;
266 // Remove the last param if its the sentinel, not sure what
267 // should happen with more then one sentinel
268 ParamDef last
= (ParamDef
) param_list
[param_count
-1];
269 if (last
.IsSentinel ())
272 param_array
= new PEAPI
.Param
[param_count
];
273 for (int i
= 0; i
< param_count
; i
++) {
274 ParamDef paramdef
= (ParamDef
) param_list
[i
];
275 paramdef
.Define (code_gen
);
276 param_array
[i
] = paramdef
.PeapiParam
;
280 param_array
= new PEAPI
.Param
[0];
286 public PEAPI
.MethodRef
GetVarargSig (PEAPI
.Type
[] opt
)
289 throw new Exception ("Methods must be resolved before a vararg sig can be created.");
291 PEAPI
.MethodRef methref
= null;
292 StringBuilder sigbuilder
= new StringBuilder ();
294 foreach (PEAPI
.Type t
in opt
)
295 sigbuilder
.Append (opt
+ ", ");
296 sig
= sigbuilder
.ToString ();
298 if (vararg_sig_table
== null) {
299 vararg_sig_table
= new Hashtable ();
301 methref
= vararg_sig_table
[sig
] as PEAPI
.MethodRef
;
304 if (methref
== null) {
305 methref
= methoddef
.MakeVarArgSignature (opt
);
306 vararg_sig_table
[sig
] = methref
;
313 /// Define a global method
315 public void Define (CodeGen code_gen
)
322 WriteCode (code_gen
, methoddef
);
324 code_gen
.Report
.Message (String
.Format ("Assembled method '<Module>'::{0}", name
));
329 /// Define a member method
331 public void Define (CodeGen code_gen
, TypeDef typedef
)
336 Resolve (code_gen
, (PEAPI
.ClassDef
) typedef
.ClassDef
);
337 WriteCode (code_gen
, methoddef
);
339 code_gen
.Report
.Message (String
.Format ("Assembled method {0}::{1}", typedef
.FullName
, name
)); is_defined
= true;
342 public void AddInstr (IInstr instr
)
344 inst_list
.Add (instr
);
347 protected void WriteCode (CodeGen code_gen
, PEAPI
.MethodDef methoddef
)
350 methoddef
.DeclareEntryPoint ();
352 if (local_list
.Count
> 0) {
353 int ec
= code_gen
.Report
.ErrorCount
;
354 PEAPI
.Local
[] local_array
= new PEAPI
.Local
[local_list
.Count
];
357 foreach (Local local
in local_list
)
358 local_array
[local
.Slot
] = local
.GetPeapiLocal (code_gen
);
360 if (code_gen
.Report
.ErrorCount
> ec
)
366 methoddef
.AddLocals (local_array
, init_locals
);
369 /// Nothing seems to work if maxstack is not set,
370 /// i need to find out if this NEEDs to be set
371 /// and what its default value should be
374 methoddef
.SetMaxStack (max_stack
);
376 /// Add the custrom attributes to this method
377 foreach (CustomAttr customattr
in customattr_list
)
378 customattr
.AddTo (code_gen
, methoddef
);
381 methoddef
.AddPInvokeInfo (pinvoke_mod
.ModuleRef
,
382 (pinvoke_name
!= null ? pinvoke_name
: name
), pinvoke_attr
);
386 if (inst_list
.Count
< 1)
389 PEAPI
.CILInstructions cil
= methoddef
.CreateCodeBuffer ();
390 /// Create all the labels
391 /// TODO: Most labels don't actually need to be created so we could
392 /// probably only create the ones that need to be
393 LabelInfo
[] label_info
= new LabelInfo
[label_table
.Count
+ label_list
.Count
];
394 label_table
.Values
.CopyTo (label_info
, 0);
395 label_list
.CopyTo (label_info
, label_table
.Count
);
396 int previous_pos
= -1;
397 LabelInfo previous_label
= null;
398 Array
.Sort (label_info
);
400 foreach (LabelInfo label
in label_info
) {
401 if (label
.UseOffset
) {
402 label
.Define (new PEAPI
.CILLabel (label
.Offset
));
405 if (label
.Pos
== previous_pos
)
406 label
.Label
= previous_label
.Label
;
408 label
.Define (cil
.NewLabel ());
410 previous_label
= label
;
411 previous_pos
= label
.Pos
;
414 // Set all the label refs
415 foreach (LabelInfo label
in labelref_table
.Values
) {
416 LabelInfo def
= (LabelInfo
) label_table
[label
.Name
];
418 code_gen
.Report
.Error ("Undefined Label: " + label
);
421 label
.Label
= def
.Label
;
425 int next_label_pos
= (label_info
.Length
> 0 ? label_info
[0].Pos
: -1);
427 for (int i
=0; i
<inst_list
.Count
; i
++) {
428 IInstr instr
= (IInstr
) inst_list
[i
];
429 if (next_label_pos
== i
) {
430 cil
.CodeLabel (label_info
[label_pos
].Label
);
431 if (label_pos
< label_info
.Length
) {
432 while (next_label_pos
== i
&& ++label_pos
< label_info
.Length
) {
433 if (label_info
[label_pos
].UseOffset
)
434 cil
.CodeLabel (label_info
[label_pos
].Label
);
435 next_label_pos
= label_info
[label_pos
].Pos
;
438 if (label_pos
>= label_info
.Length
)
442 source
.MarkLocation (instr
.Location
.line
, cil
.Offset
);
443 instr
.Emit (code_gen
, this, cil
);
447 source
.MarkLocation (source
.EndLine
, cil
.Offset
);
449 // Generic type parameters
450 if (typar_list
!= null) {
452 foreach (GenericInfo gi
in typar_list
) {
453 PEAPI
.GenericParameter gp
= methoddef
.AddGenericParameter (index
++, gi
.Id
);
454 if (gi
.ConstraintList
!= null) {
455 foreach (ITypeRef cnst
in gi
.ConstraintList
) {
456 cnst
.Resolve (code_gen
);
457 gp
.AddConstraint (cnst
.PeapiType
);
464 public LabelInfo
AddLabel (string name
)
466 LabelInfo label_info
= (LabelInfo
) label_table
[name
];
467 if (label_info
!= null)
469 label_info
= new LabelInfo (name
, inst_list
.Count
);
470 label_table
.Add (name
, label_info
);
474 public LabelInfo
AddLabelRef (string name
)
476 LabelInfo label_info
= (LabelInfo
) label_table
[name
];
477 if (label_info
!= null)
479 label_info
= (LabelInfo
) labelref_table
[name
];
480 if (label_info
!= null)
482 label_info
= new LabelInfo (name
, -1);
483 labelref_table
.Add (name
, label_info
);
487 public LabelInfo
AddLabel (int offset
)
489 // We go pos + 1 so this line is not counted
490 LabelInfo label_info
= new LabelInfo (null, inst_list
.Count
+1, (uint) offset
);
491 label_list
.Add (label_info
);
495 public LabelInfo
AddLabel ()
497 int pos
= inst_list
.Count
;
498 LabelInfo label_info
= new LabelInfo (null, inst_list
.Count
);
499 label_list
.Add (label_info
);
503 public PEAPI
.CILLabel
GetLabelDef (string name
)
505 LabelInfo label_info
= (LabelInfo
) label_table
[name
];
507 return label_info
.Label
;
510 public PEAPI
.CILLabel
GetLabelDef (int pos
)
512 foreach (LabelInfo li
in label_list
) {
519 private void CreateSignature ()
522 signature
= CreateVarargSignature (name
, param_list
);
524 signature
= CreateSignature (name
, param_list
);
527 public static string CreateSignature (string name
, IList param_list
)
529 StringBuilder builder
= new StringBuilder ();
531 builder
.Append (name
);
532 builder
.Append ('(');
534 if (param_list
!= null) {
536 foreach (ParamDef paramdef
in param_list
) {
538 builder
.Append (',');
539 builder
.Append (paramdef
.TypeName
);
543 builder
.Append (')');
545 return builder
.ToString ();
548 public static string CreateVarargSignature (string name
, IList param_list
)
550 StringBuilder builder
= new StringBuilder ();
551 ParamDef last
= null;
553 builder
.Append (name
);
554 builder
.Append ('(');
557 if (param_list
!= null) {
558 foreach (ParamDef paramdef
in param_list
) {
560 builder
.Append (',');
561 builder
.Append (paramdef
.TypeName
);
564 last
= (ParamDef
) param_list
[param_list
.Count
- 1];
568 if (last
== null || !last
.IsSentinel ()) {
570 builder
.Append (',');
571 builder
.Append ("...");
574 builder
.Append (')');
576 return builder
.ToString ();
579 public static string CreateVarargSignature (string name
, ITypeRef
[] param_list
)
581 StringBuilder builder
= new StringBuilder ();
582 ITypeRef last
= null;
584 builder
.Append (name
);
585 builder
.Append ('(');
588 if (param_list
!= null && param_list
.Length
> 0) {
589 foreach (ITypeRef param
in param_list
) {
591 builder
.Append (',');
592 builder
.Append (param
.FullName
);
595 if (param
is SentinelTypeRef
)
601 if (last
== null || !(last
is SentinelTypeRef
)) {
603 builder
.Append (',');
604 builder
.Append ("...");
607 builder
.Append (')');
609 return builder
.ToString ();
612 public static string CreateSignature (string name
, ITypeRef
[] param_list
)
614 StringBuilder builder
= new StringBuilder ();
616 builder
.Append (name
);
617 builder
.Append ('(');
619 if (param_list
!= null) {
621 foreach (ITypeRef param
in param_list
) {
623 builder
.Append (',');
624 builder
.Append (param
.FullName
);
626 if (param
is SentinelTypeRef
)
630 builder
.Append (')');
632 return builder
.ToString ();
635 private void CreateNamedParamTable ()
637 if (param_list
== null)
640 int count
= (IsStatic
? 0 : 1);
642 foreach (ParamDef param
in param_list
) {
643 if (param
.Name
!= null)
644 named_param_table
.Add (param
.Name
, count
);
649 private void FixAttributes ()
651 if (name
== ".ctor" || name
== ".cctor")
652 meth_attr
|= PEAPI
.MethAttr
.SpecialName
| PEAPI
.MethAttr
.RTSpecialName
;
653 // If methods aren't flagged as static they are instance
654 if ((PEAPI
.MethAttr
.Static
& meth_attr
) == 0)
655 call_conv
|= PEAPI
.CallConv
.Instance
;