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