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