2010-04-01 Jb Evain <jbevain@novell.com>
[mcs.git] / ilasm / codegen / CodeGen.cs
blobb0b1803c18060a442523c60a46fda4794cb477ae
1 //
2 // Mono.ILASM.CodeGen.cs
3 //
4 // Author(s):
5 // Sergey Chaban (serge@wildwestsoftware.com)
6 // Jackson Harper (Jackson@LatitudeGeo.com)
7 //
8 // (C) Sergey Chaban
9 // (C) 2003 Jackson Harper, All rights reserved
12 using PEAPI;
13 using System;
14 using System.IO;
15 using System.Collections;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Text;
19 using System.Security;
21 using SSPermissionSet = System.Security.PermissionSet;
22 using MIPermissionSet = Mono.ILASM.PermissionSet;
24 using MIAssembly = Mono.ILASM.Assembly;
26 namespace Mono.ILASM {
28 public class CodeGen {
30 private PEFile pefile;
31 private ExternAssembly current_assemblyref;
32 private ExternModule current_moduleref;
33 private string current_namespace;
34 private TypeDef current_typedef;
35 private MethodDef current_methoddef;
36 private ArrayList typedef_stack;
37 private int typedef_stack_top;
38 private SymbolWriter symwriter;
39 private ICustomAttrTarget current_customattrtarget;
40 private IDeclSecurityTarget current_declsectarget;
41 private PEAPI.NativeType current_field_native_type;
43 private MIAssembly this_assembly;
45 private TypeManager type_manager;
46 private ExternTable extern_table;
47 private Hashtable global_field_table;
48 private Hashtable global_method_table;
49 private Hashtable global_methodref_table;
50 private Hashtable global_fieldref_table;
51 private Hashtable data_table;
52 private FileRef file_ref;
53 private ArrayList manifestResources;
54 private Hashtable typeref_table;
56 private ArrayList defcont_list;
58 private int sub_system;
59 private int cor_flags;
60 private long image_base;
61 private long stack_reserve;
63 private string output_file;
64 private string debug_file;
65 private bool is_dll;
66 private bool entry_point;
68 private Module this_module;
70 public CodeGen (string output_file, bool is_dll, bool debugging_info)
72 this.output_file = output_file;
73 this.is_dll = is_dll;
75 if (debugging_info)
76 symwriter = new SymbolWriter (output_file);
78 type_manager = new TypeManager (this);
79 extern_table = new ExternTable ();
80 typedef_stack = new ArrayList ();
81 typedef_stack_top = 0;
82 global_field_table = new Hashtable ();
83 global_method_table = new Hashtable ();
85 data_table = new Hashtable ();
87 defcont_list = new ArrayList ();
89 sub_system = -1;
90 cor_flags = -1;
91 image_base = -1;
92 stack_reserve = -1;
93 entry_point = false;
94 this_module = null;
97 public PEFile PEFile {
98 get { return pefile; }
101 public SymbolWriter SymbolWriter {
102 get { return symwriter; }
105 public string CurrentNameSpace {
106 get { return current_namespace; }
107 set { current_namespace = value; }
110 public TypeDef CurrentTypeDef {
111 get { return current_typedef; }
114 public MethodDef CurrentMethodDef {
115 get { return current_methoddef; }
118 public ExternAssembly CurrentAssemblyRef {
119 get { return current_assemblyref; }
122 public ExternModule CurrentModuleRef {
123 get { return current_moduleref; }
126 public ICustomAttrTarget CurrentCustomAttrTarget {
127 get { return current_customattrtarget; }
128 set { current_customattrtarget = value; }
131 public IDeclSecurityTarget CurrentDeclSecurityTarget {
132 get { return current_declsectarget; }
133 set { current_declsectarget = value; }
136 public ExternTable ExternTable {
137 get { return extern_table; }
140 public TypeManager TypeManager {
141 get { return type_manager; }
144 public bool HasEntryPoint {
145 get { return entry_point; }
146 set {
147 /* if (!value) error: unsetting entrypoint ? */
148 if (entry_point)
149 Report.Error ("Multiple .entrypoint declarations.");
150 entry_point = value;
154 public TypeRef GetTypeRef (string name)
156 TypeRef tr = null;
158 if (typeref_table == null)
159 typeref_table = new Hashtable ();
160 else
161 tr = typeref_table [name] as TypeRef;
163 if (tr == null) {
164 tr = new TypeRef (name, false, null);
165 typeref_table [name] = tr;
168 return tr;
171 public GlobalMethodRef GetGlobalMethodRef (BaseTypeRef ret_type, PEAPI.CallConv call_conv,
172 string name, BaseTypeRef[] param, int gen_param_count)
174 string key = MethodDef.CreateSignature (ret_type, call_conv, name, param, gen_param_count, true);
176 GlobalMethodRef methref = null;
178 if (global_methodref_table == null)
179 global_methodref_table = new Hashtable ();
180 else
181 methref = (GlobalMethodRef) global_methodref_table [key];
183 if (methref == null) {
184 methref = new GlobalMethodRef (ret_type, call_conv, name, param, gen_param_count);
185 global_methodref_table [key] = methref;
188 return methref;
191 public GlobalFieldRef GetGlobalFieldRef (BaseTypeRef ret_type, string name)
193 string key = ret_type.FullName + name;
195 GlobalFieldRef fieldref = null;
197 if (global_fieldref_table == null)
198 global_fieldref_table = new Hashtable ();
199 else
200 fieldref = (GlobalFieldRef) global_fieldref_table [key];
202 if (fieldref == null) {
203 fieldref = new GlobalFieldRef (ret_type, name);
204 global_fieldref_table [key] = fieldref;
207 return fieldref;
210 public void SetSubSystem (int sub_system)
212 this.sub_system = sub_system;
215 public void SetCorFlags (int cor_flags)
217 this.cor_flags = cor_flags;
220 public void SetImageBase (long image_base)
222 this.image_base = image_base;
225 public void SetStackReserve (long stack_reserve)
227 this.stack_reserve = stack_reserve;
230 public void SetThisAssembly (string name, PEAPI.AssemAttr attr)
232 if (this_assembly != null && this_assembly.Name != name)
233 Report.Error ("Multiple assembly declarations");
235 this_assembly = new Assembly (name);
236 this_assembly.SetAssemblyAttr (attr);
237 if (name != "mscorlib")
238 ExternTable.AddCorlib ();
241 public void SetModuleName (string module_name)
243 this_module = new Module (module_name);
244 CurrentCustomAttrTarget = this_module;
247 public void SetFileRef (FileRef file_ref)
249 this.file_ref = file_ref;
252 public MIAssembly ThisAssembly {
253 get { return this_assembly; }
256 public bool IsThisAssembly (string name)
258 return (this_assembly != null && name == this_assembly.Name);
261 public Module ThisModule {
262 get { return this_module; }
265 public bool IsThisModule (string name)
267 return (this_module != null && name == this_module.Name);
270 public void BeginSourceFile (string name)
272 if (symwriter != null)
273 symwriter.BeginSourceFile (name);
276 public void EndSourceFile ()
278 if (symwriter != null)
279 symwriter.EndSourceFile ();
282 public void BeginTypeDef (TypeAttr attr, string name, BaseClassRef parent,
283 ArrayList impl_list, Location location, GenericParameters gen_params)
285 TypeDef outer = null;
286 string cache_name = CacheName (name);
287 if (typedef_stack_top > 0) {
288 StringBuilder sb = new StringBuilder ();
290 for (int i = 0; i < typedef_stack_top; i++){
291 outer = (TypeDef) typedef_stack [i];
292 if (i == 0)
293 /* Use FullName for outermost class to get the
294 namespace also */
295 sb.Append (outer.FullName);
296 else
297 sb.Append (outer.Name);
298 sb.Append ("/");
300 sb.Append (name);
301 cache_name = sb.ToString ();
304 TypeDef typedef = type_manager[cache_name];
306 if (typedef != null) {
307 // Class head is allready defined, we are just reopening the class
308 current_customattrtarget = current_typedef = typedef;
309 current_declsectarget = typedef;
310 typedef_stack.Add (current_typedef);
311 typedef_stack_top++;
312 return;
315 typedef = new TypeDef (attr, current_namespace,
316 name, parent, impl_list, location, gen_params, outer);
318 type_manager[cache_name] = typedef;
319 current_customattrtarget = current_typedef = typedef;
320 current_declsectarget = typedef;
321 typedef_stack.Add (typedef);
322 typedef_stack_top++;
325 public void AddFieldMarshalInfo (PEAPI.NativeType native_type)
327 current_field_native_type = native_type;
330 public void AddFieldDef (FieldDef fielddef)
332 if (current_field_native_type != null) {
333 fielddef.AddMarshalInfo (current_field_native_type);
334 current_field_native_type = null;
337 if (current_typedef != null) {
338 current_typedef.AddFieldDef (fielddef);
339 } else {
340 global_field_table.Add (
341 new DictionaryEntry (fielddef.Name, fielddef.Type.FullName),
342 fielddef);
346 public void AddDataDef (DataDef datadef)
348 if (data_table [datadef.Name] != null)
349 Report.Error ("Duplicate global label '" + datadef.Name + "'");
350 data_table [datadef.Name] = datadef;
353 public void AddManifestResource (ManifestResource mr)
355 if (manifestResources == null)
356 manifestResources = new ArrayList ();
357 manifestResources.Add (mr);
360 public PEAPI.DataConstant GetDataConst (string name)
362 DataDef def = (DataDef) data_table [name];
363 if (def == null)
364 return null;
366 return (DataConstant) def.PeapiConstant;
369 public void BeginMethodDef (MethodDef methoddef)
371 if (current_typedef != null) {
372 current_typedef.AddMethodDef (methoddef);
373 } else {
374 global_method_table.Add (methoddef.Signature,
375 methoddef);
378 current_customattrtarget = current_methoddef = methoddef;
379 current_declsectarget = methoddef;
382 public void EndMethodDef (Location location)
384 if (symwriter != null)
385 symwriter.EndMethod (location);
387 current_methoddef = null;
390 public void EndTypeDef ()
392 typedef_stack_top--;
393 typedef_stack.RemoveAt (typedef_stack_top);
395 if (typedef_stack_top > 0)
396 current_typedef = (TypeDef) typedef_stack [typedef_stack_top-1];
397 else
398 current_typedef = null;
402 public void BeginAssemblyRef (string name, AssemblyName asmb_name, PEAPI.AssemAttr attr)
404 current_customattrtarget = current_assemblyref = ExternTable.AddAssembly (name, asmb_name, attr);
405 current_declsectarget = current_assemblyref;
408 public void EndAssemblyRef ()
410 current_assemblyref = null;
411 current_customattrtarget = null;
412 current_declsectarget = null;
415 public void AddToDefineContentsList (TypeDef typedef)
417 defcont_list.Add (typedef);
420 public void AddPermission (PEAPI.SecurityAction sec_action, object perm)
422 if (CurrentDeclSecurityTarget == null)
423 return;
425 AddPermission (sec_action, perm, CurrentDeclSecurityTarget.DeclSecurity);
428 private void AddPermission (PEAPI.SecurityAction sec_action, object perm, DeclSecurity decl_sec)
430 SSPermissionSet ps = perm as SSPermissionSet;
431 if (ps != null) {
432 decl_sec.AddPermissionSet (sec_action, ps);
433 return;
436 IPermission iper = perm as IPermission;
437 if (iper != null) {
438 decl_sec.AddPermission (sec_action, iper);
439 return;
442 MIPermissionSet ps20 = perm as MIPermissionSet;
443 if (ps20 != null) {
444 decl_sec.AddPermissionSet (sec_action, ps20);
445 return;
449 public void Write ()
451 FileStream out_stream = null;
453 try {
454 if (ThisModule == null)
455 this_module = new Module (Path.GetFileName (output_file));
457 out_stream = new FileStream (output_file, FileMode.Create, FileAccess.Write);
458 pefile = new PEFile (ThisAssembly != null ? ThisAssembly.Name : null, ThisModule.Name, is_dll, ThisAssembly != null, null, out_stream);
459 PEAPI.Assembly asmb = pefile.GetThisAssembly ();
461 ThisModule.PeapiModule = pefile.GetThisModule ();
463 if (file_ref != null)
464 file_ref.Resolve (this);
466 extern_table.Resolve (this);
467 type_manager.DefineAll ();
469 if (manifestResources != null) {
470 foreach (ManifestResource mr in manifestResources)
471 pefile.AddManifestResource (mr);
474 foreach (FieldDef fielddef in global_field_table.Values) {
475 fielddef.Define (this);
478 foreach (MethodDef methoddef in global_method_table.Values) {
479 methoddef.Define (this);
482 foreach (TypeDef typedef in defcont_list) {
483 typedef.DefineContents (this);
486 if (ThisAssembly != null)
487 ThisAssembly.Resolve (this, pefile.GetThisAssembly ());
488 ThisModule.Resolve (this, pefile.GetThisModule ());
490 if (sub_system != -1)
491 pefile.SetSubSystem ((PEAPI.SubSystem) sub_system);
492 if (cor_flags != -1)
493 pefile.SetCorFlags (cor_flags);
494 if (stack_reserve != -1)
495 pefile.SetStackReserve (stack_reserve);
497 pefile.WritePEFile ();
499 if (symwriter != null) {
500 Guid guid = pefile.GetThisModule ().Guid;
501 symwriter.Write (guid);
503 } finally {
504 if (out_stream != null)
505 out_stream.Close ();
509 public PEAPI.Method ResolveMethod (string signature)
511 MethodDef methoddef = (MethodDef) global_method_table[signature];
512 if (methoddef == null)
513 Report.Error ("Unable to resolve global method : " + signature);
515 return methoddef.Resolve (this);
518 public PEAPI.Method ResolveVarargMethod (string sig_only_required_params, string sig_with_optional_params,
519 CodeGen code_gen, PEAPI.Type[] opt)
521 MethodDef methoddef = (MethodDef) global_method_table [sig_only_required_params];
522 if (methoddef == null)
523 Report.Error ("Unable to resolve global method : " + sig_only_required_params);
525 methoddef.Resolve (code_gen);
526 return methoddef.GetVarargSig (opt, sig_with_optional_params);
529 public PEAPI.Field ResolveField (string name, string type_name)
531 FieldDef fielddef = (FieldDef) global_field_table[new DictionaryEntry (name, type_name)];
532 if (fielddef == null)
533 Report.Error (String.Format ("Unable to resolve global field : {0} {1}", type_name, name));
535 return fielddef.Resolve (this);
538 private string CacheName (string name)
540 if (current_namespace == null ||
541 current_namespace == String.Empty)
542 return name;
544 return current_namespace + "." + name;