In ilasm/tests:
[mono.git] / mcs / ilasm / codegen / CodeGen.cs
1 //\r
2 // Mono.ILASM.CodeGen.cs\r
3 //\r
4 // Author(s):\r
5 //  Sergey Chaban (serge@wildwestsoftware.com)\r
6 //  Jackson Harper (Jackson@LatitudeGeo.com)\r
7 //\r
8 // (C) Sergey Chaban\r
9 // (C) 2003 Jackson Harper, All rights reserved\r
10 //\r
11 \r
12 using PEAPI;\r
13 using System;\r
14 using System.IO;\r
15 using System.Collections;\r
16 using System.Reflection;\r
17 using System.Reflection.Emit;\r
18 using System.Text;\r
19 \r
20 namespace Mono.ILASM {\r
21 \r
22         public class CodeGen {\r
23 \r
24                 private PEFile pefile;\r
25                 private string assembly_name;\r
26                 private Report report;\r
27                 private ExternAssembly current_assemblyref;\r
28                 private ExternModule current_moduleref;\r
29                 private string current_namespace;\r
30                 private TypeDef current_typedef;\r
31                 private MethodDef current_methoddef;\r
32                 private ArrayList typedef_stack;\r
33                 private int typedef_stack_top;\r
34                 private SymbolWriter symwriter;\r
35                 private ICustomAttrTarget current_customattrtarget;\r
36                 private IDeclSecurityTarget current_declsectarget;\r
37                 private PEAPI.NativeType current_field_native_type;\r
38 \r
39                 private byte [] assembly_public_key;\r
40                 private int assembly_major_version;\r
41                 private int assembly_minor_version;\r
42                 private int assembly_build_version;\r
43                 private int assembly_revision_version;\r
44                 private string assembly_locale;\r
45                 private int assembly_hash_algorithm;\r
46                 private ArrayList assembly_custom_attributes;\r
47                 private ArrayList assembly_declsec;\r
48                         \r
49                 private TypeManager type_manager;\r
50                 private ExternTable extern_table;\r
51                 private Hashtable global_field_table;\r
52                 private Hashtable global_method_table;\r
53                 private ArrayList data_list;\r
54                 private FileRef file_ref;\r
55                 private ArrayList manifestResources;\r
56                 \r
57                 private ArrayList defcont_list;\r
58 \r
59                 private int sub_system;\r
60                 private int cor_flags;\r
61                 private long image_base;\r
62 \r
63                 private string output_file;\r
64                 private string debug_file;\r
65                 private bool is_dll;\r
66                 private bool is_assembly;\r
67                 private bool entry_point;\r
68 \r
69                 private string module_name;\r
70 \r
71                 public CodeGen (string output_file, bool is_dll, bool is_assembly,\r
72                                 bool debugging_info, Report report)\r
73                 {\r
74                         this.output_file = output_file;\r
75                         this.is_dll = is_dll;\r
76                         this.is_assembly = is_assembly;\r
77                         this.report = report;\r
78 \r
79                         if (debugging_info)\r
80                                 symwriter = new SymbolWriter (CreateDebugFile (output_file));\r
81 \r
82                         type_manager = new TypeManager (this);\r
83                         extern_table = new ExternTable ();\r
84                         typedef_stack = new ArrayList ();\r
85                         typedef_stack_top = 0;\r
86                         global_field_table = new Hashtable ();\r
87                         global_method_table = new Hashtable ();\r
88 \r
89                         data_list = new ArrayList ();\r
90 \r
91                         defcont_list = new ArrayList ();\r
92 \r
93                         sub_system = -1;\r
94                         cor_flags = -1;\r
95                         image_base = -1;\r
96                         entry_point = false;\r
97                 }\r
98 \r
99                 private string CreateDebugFile (string output_file)\r
100                 {\r
101                         int ext_index = output_file.LastIndexOf ('.');\r
102 \r
103                         if (ext_index == -1)\r
104                                 ext_index = output_file.Length;\r
105 \r
106                         return String.Format ("{0}.{1}", output_file.Substring (0, ext_index),\r
107                                               "mdb");\r
108                 }\r
109 \r
110                 public PEFile PEFile {\r
111                         get { return pefile; }\r
112                 }\r
113 \r
114                 public Report Report {\r
115                         get { return report; }\r
116                 }\r
117 \r
118                 public SymbolWriter SymbolWriter {\r
119                         get { return symwriter; }\r
120                 }\r
121 \r
122                 public string CurrentNameSpace {\r
123                         get { return current_namespace; }\r
124                         set { current_namespace = value; }\r
125                 }\r
126 \r
127                 public TypeDef CurrentTypeDef {\r
128                         get { return current_typedef; }\r
129                 }\r
130 \r
131                 public MethodDef CurrentMethodDef {\r
132                         get { return current_methoddef; }\r
133                 }\r
134 \r
135                 public ExternAssembly CurrentAssemblyRef {\r
136                         get { return current_assemblyref; }\r
137                 }\r
138 \r
139                 public ExternModule CurrentModuleRef {\r
140                         get { return current_moduleref; }\r
141                 }\r
142 \r
143                 public ICustomAttrTarget CurrentCustomAttrTarget {\r
144                         get { return current_customattrtarget; }\r
145                         set { current_customattrtarget = value; }\r
146                 }\r
147 \r
148                 public IDeclSecurityTarget CurrentDeclSecurityTarget {\r
149                         get { return current_declsectarget; }\r
150                         set { current_declsectarget = value; }\r
151                 }\r
152 \r
153                 public ExternTable ExternTable {\r
154                         get { return extern_table; }\r
155                 }\r
156 \r
157                 public TypeManager TypeManager {\r
158                         get { return type_manager; }\r
159                 }\r
160 \r
161                 public bool HasEntryPoint {\r
162                         get { return entry_point; }\r
163                         set { \r
164                                 /* if (!value) error: unsetting entrypoint ? */\r
165                                 if (entry_point)\r
166                                         throw new Exception ("Multiple .entrypoint declarations.");\r
167                                 entry_point = value;\r
168                         }                \r
169                 }\r
170 \r
171                 public void SetSubSystem (int sub_system)\r
172                 {\r
173                         this.sub_system = sub_system;\r
174                 }\r
175 \r
176                 public void SetCorFlags (int cor_flags)\r
177                 {\r
178                         this.cor_flags = cor_flags;\r
179                 }\r
180 \r
181                 public void SetImageBase (long image_base)\r
182                 {\r
183                         this.image_base = image_base;\r
184                 }\r
185 \r
186                 public void SetAssemblyName (string name)\r
187                 {\r
188                         assembly_name = name;\r
189                 }\r
190 \r
191                 public void SetModuleName (string module_name)\r
192                 {\r
193                         this.module_name = module_name;\r
194                 }\r
195 \r
196                 public void SetFileRef (FileRef file_ref)\r
197                 {\r
198                         this.file_ref = file_ref;\r
199                 }\r
200 \r
201                 public bool IsThisAssembly (string name)\r
202                 {\r
203                         return (name == assembly_name);\r
204                 }\r
205 \r
206                 public bool IsThisModule (string name)\r
207                 {\r
208                         return (name == module_name);\r
209                 }\r
210 \r
211                 public void BeginSourceFile (string name)\r
212                 {\r
213                         if (symwriter != null)\r
214                                 symwriter.BeginSourceFile (name);\r
215                 }\r
216 \r
217                 public void EndSourceFile ()\r
218                 {\r
219                         if (symwriter != null)\r
220                                 symwriter.EndSourceFile ();\r
221                 }\r
222 \r
223                 public void BeginTypeDef (TypeAttr attr, string name, IClassRef parent,\r
224                                 ArrayList impl_list, Location location)\r
225                 {\r
226                         TypeDef outer = null;\r
227                         string cache_name = CacheName (name);\r
228 \r
229                         if (typedef_stack_top > 0) {\r
230                                 StringBuilder sb = new StringBuilder ();\r
231                                 \r
232                                 for (int i = 0; i < typedef_stack_top; i++){\r
233                                         outer = (TypeDef) typedef_stack [i];\r
234                                         sb.Append (outer.Name);\r
235                                         sb.Append ("/");\r
236                                 }\r
237                                 sb.Append (name);\r
238                                 cache_name = CacheName (sb.ToString ());\r
239                         }\r
240 \r
241                         TypeDef typedef = type_manager[cache_name];\r
242 \r
243                         if (typedef != null) {\r
244                                 // Class head is allready defined, we are just reopening the class\r
245                                 current_customattrtarget = current_typedef = typedef;\r
246                                 current_declsectarget = typedef;\r
247                                 typedef_stack.Add (current_typedef);\r
248                                 typedef_stack_top++;\r
249                                 return;\r
250                         }\r
251 \r
252                         typedef = new TypeDef (attr, current_namespace,\r
253                                         name, parent, impl_list, location);\r
254 \r
255                         if (outer != null)\r
256                                 typedef.OuterType = outer;\r
257 \r
258                         type_manager[cache_name] = typedef;\r
259                         current_customattrtarget = current_typedef = typedef;\r
260                         current_declsectarget = typedef;\r
261                         typedef_stack.Add (typedef);\r
262                         typedef_stack_top++;\r
263                 }\r
264 \r
265                 public void AddFieldMarshalInfo (PEAPI.NativeType native_type)\r
266                 {\r
267                         current_field_native_type = native_type;\r
268                 }\r
269 \r
270                 public void AddFieldDef (FieldDef fielddef)\r
271                 {\r
272                         if (current_field_native_type != null) {\r
273                                 fielddef.AddMarshalInfo (current_field_native_type);\r
274                                 current_field_native_type = null;\r
275                         }\r
276 \r
277                         if (current_typedef != null) {\r
278                                 current_typedef.AddFieldDef (fielddef);\r
279                         } else {\r
280                                 global_field_table.Add (fielddef.Name,\r
281                                                 fielddef);\r
282                         }\r
283                 }\r
284 \r
285                 public void AddDataDef (DataDef datadef)\r
286                 {\r
287                         data_list.Add (datadef);\r
288                 }\r
289 \r
290                 public void AddManifestResource (ManifestResource mr)\r
291                 {\r
292                         if (manifestResources == null)\r
293                                 manifestResources = new ArrayList ();\r
294                         manifestResources.Add (mr);\r
295                 }\r
296 \r
297                 public PEAPI.DataConstant GetDataConst (string name)\r
298                 {\r
299                         foreach (DataDef def in data_list) {\r
300                                 if (def.Name == name)\r
301                                         return (DataConstant) def.PeapiConstant;\r
302                         }\r
303                         return null;\r
304 \r
305                 }\r
306 \r
307                 public void BeginMethodDef (MethodDef methoddef)\r
308                 {\r
309                         if (current_typedef != null) {\r
310                                 current_typedef.AddMethodDef (methoddef);\r
311                         } else {\r
312                                 global_method_table.Add (methoddef.Signature,\r
313                                                 methoddef);\r
314                         }\r
315 \r
316                         current_customattrtarget = current_methoddef = methoddef;\r
317                         current_declsectarget = methoddef;\r
318                 }\r
319 \r
320                 public void EndMethodDef (Location location)\r
321                 {\r
322                         if (symwriter != null)\r
323                                 symwriter.EndMethod (location);\r
324 \r
325                         current_methoddef = null;\r
326                 }\r
327 \r
328                 public void EndTypeDef ()\r
329                 {\r
330                         typedef_stack_top--;\r
331                         typedef_stack.RemoveAt (typedef_stack_top);\r
332 \r
333                         if (typedef_stack_top > 0)\r
334                                 current_typedef = (TypeDef) typedef_stack [typedef_stack_top-1];\r
335                         else\r
336                                 current_typedef = null;\r
337 \r
338                 }\r
339 \r
340                 public void BeginAssemblyRef (string name, AssemblyName asmb_name)\r
341                 {\r
342                         current_customattrtarget = current_assemblyref = ExternTable.AddAssembly (name, asmb_name);\r
343                         current_declsectarget = current_assemblyref;\r
344                 }\r
345 \r
346                 public void EndAssemblyRef ()\r
347                 {\r
348                         current_assemblyref = null;\r
349                 }\r
350 \r
351                 public void AddToDefineContentsList (TypeDef typedef)\r
352                 {\r
353                         defcont_list.Add (typedef);\r
354                 }\r
355 \r
356                 public void SetAssemblyPublicKey (byte [] public_key)\r
357                 {\r
358                         assembly_public_key = public_key;\r
359                 }\r
360 \r
361                 public void SetAssemblyVersion (int major, int minor, int build, int revision)\r
362                 {\r
363                         assembly_major_version = major;\r
364                         assembly_minor_version = minor;\r
365                         assembly_build_version = build;\r
366                         assembly_revision_version = revision;\r
367                 }\r
368 \r
369                 public void SetAssemblyLocale (string locale)\r
370                 {\r
371                         assembly_locale = locale;\r
372                 }\r
373 \r
374                 public void SetAssemblyHashAlgorithm (int algorithm)\r
375                 {\r
376                         assembly_hash_algorithm = algorithm;\r
377                 }\r
378 \r
379                 public void AddAssemblyCustomAttribute (CustomAttr attribute)\r
380                 {\r
381                         if (assembly_custom_attributes == null)\r
382                                 assembly_custom_attributes = new ArrayList ();\r
383                         assembly_custom_attributes.Add (attribute);\r
384                 }\r
385 \r
386                 public void AddAssemblyDeclSecurity (DeclSecurity decl_sec)\r
387                 {\r
388                         if (assembly_declsec == null)\r
389                                 assembly_declsec = new ArrayList ();\r
390                         assembly_declsec.Add (decl_sec);\r
391                 }\r
392 \r
393                 public void Write ()\r
394                 {\r
395                         FileStream out_stream = null;\r
396 \r
397                         try {\r
398                                 if (!is_dll && !HasEntryPoint)\r
399                                         throw new Exception ("No EntryPoint found.");\r
400 \r
401                                 out_stream = new FileStream (output_file, FileMode.Create, FileAccess.Write);\r
402                                 pefile = new PEFile (assembly_name, module_name, is_dll, is_assembly, out_stream);\r
403                                 PEAPI.Assembly asmb = pefile.GetThisAssembly ();\r
404 \r
405                                 if (file_ref != null)\r
406                                         file_ref.Resolve (this);\r
407 \r
408                                 extern_table.Resolve (this);\r
409                                 type_manager.DefineAll ();\r
410 \r
411                                 if (manifestResources != null) {\r
412                                         foreach (ManifestResource mr in manifestResources)\r
413                                                 pefile.AddManifestResource (mr);\r
414                                 }\r
415 \r
416                                 foreach (FieldDef fielddef in global_field_table.Values) {\r
417                                         fielddef.Define (this);\r
418                                 }\r
419 \r
420                                 foreach (MethodDef methoddef in global_method_table.Values) {\r
421                                         methoddef.Define (this);\r
422                                 }\r
423 \r
424                                 foreach (TypeDef typedef in defcont_list) {\r
425                                         typedef.DefineContents (this);\r
426                                 }\r
427 \r
428                                 if (assembly_custom_attributes != null) {\r
429                                         foreach (CustomAttr cattr in assembly_custom_attributes)\r
430                                                 cattr.AddTo (this, asmb);\r
431                                 }\r
432                                 \r
433                                 if (assembly_declsec != null) {\r
434                                         foreach (DeclSecurity decl_sec in assembly_declsec)\r
435                                                 decl_sec.AddTo (this, asmb);\r
436                                 }\r
437 \r
438                                 if (sub_system != -1)\r
439                                         pefile.SetSubSystem ((PEAPI.SubSystem) sub_system);\r
440                                 if (cor_flags != -1)\r
441                                         pefile.SetCorFlags (cor_flags);\r
442 \r
443                                 asmb.AddAssemblyInfo(assembly_major_version,\r
444                                                 assembly_minor_version, assembly_build_version,\r
445                                                 assembly_revision_version, assembly_public_key,\r
446                                                 (uint) assembly_hash_algorithm, assembly_locale);\r
447 \r
448                                 pefile.WritePEFile ();\r
449 \r
450                                 if (symwriter != null) {\r
451                                         Guid guid = pefile.GetThisModule ().Guid;\r
452                                         symwriter.Write (guid);\r
453                                 }\r
454                         } catch {\r
455                                 throw;\r
456                         } finally {\r
457                                 if (out_stream != null)\r
458                                         out_stream.Close ();\r
459                         }\r
460                 }\r
461 \r
462                 public PEAPI.Method ResolveMethod (string signature)\r
463                 {\r
464                         MethodDef methoddef = (MethodDef) global_method_table[signature];\r
465 \r
466                         return methoddef.Resolve (this);\r
467                 }\r
468 \r
469                 public PEAPI.Method ResolveVarargMethod (string signature,\r
470                                 CodeGen code_gen, PEAPI.Type[] opt)\r
471                 {\r
472                         MethodDef methoddef = (MethodDef) global_method_table[signature];\r
473                         methoddef.Resolve (code_gen);\r
474 \r
475                         return methoddef.GetVarargSig (opt);\r
476                 }\r
477 \r
478                 public PEAPI.Field ResolveField (string name)\r
479                 {\r
480                         FieldDef fielddef = (FieldDef) global_field_table[name];\r
481 \r
482                         return fielddef.Resolve (this);\r
483                 }\r
484 \r
485                 private string CacheName (string name)\r
486                 {\r
487                         if (current_namespace == null ||\r
488                                         current_namespace == String.Empty)\r
489                                 return name;\r
490 \r
491                         return current_namespace + "." + name;\r
492                 }\r
493         }\r
494 \r
495 }\r
496 \r