2 // Mono.ILASM.CodeGen.cs
\r
5 // Sergey Chaban (serge@wildwestsoftware.com)
\r
6 // Jackson Harper (Jackson@LatitudeGeo.com)
\r
9 // (C) 2003 Jackson Harper, All rights reserved
\r
15 using System.Collections;
\r
16 using System.Reflection;
\r
17 using System.Reflection.Emit;
\r
19 using System.Security;
\r
22 namespace Mono.ILASM {
\r
24 public class CodeGen {
\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
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
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
60 private ArrayList defcont_list;
\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
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
73 private string module_name;
\r
75 public CodeGen (string output_file, bool is_dll, bool is_assembly,
\r
76 bool debugging_info, Report report)
\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
84 symwriter = new SymbolWriter (CreateDebugFile (output_file));
\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
93 data_list = new ArrayList ();
\r
95 defcont_list = new ArrayList ();
\r
100 stack_reserve = -1;
\r
101 entry_point = false;
\r
104 private string CreateDebugFile (string output_file)
\r
106 int ext_index = output_file.LastIndexOf ('.');
\r
108 if (ext_index == -1)
\r
109 ext_index = output_file.Length;
\r
111 return String.Format ("{0}.{1}", output_file.Substring (0, ext_index),
\r
115 public PEFile PEFile {
\r
116 get { return pefile; }
\r
119 public Report Report {
\r
120 get { return report; }
\r
123 public SymbolWriter SymbolWriter {
\r
124 get { return symwriter; }
\r
127 public string CurrentNameSpace {
\r
128 get { return current_namespace; }
\r
129 set { current_namespace = value; }
\r
132 public TypeDef CurrentTypeDef {
\r
133 get { return current_typedef; }
\r
136 public MethodDef CurrentMethodDef {
\r
137 get { return current_methoddef; }
\r
140 public ExternAssembly CurrentAssemblyRef {
\r
141 get { return current_assemblyref; }
\r
144 public ExternModule CurrentModuleRef {
\r
145 get { return current_moduleref; }
\r
148 public ICustomAttrTarget CurrentCustomAttrTarget {
\r
149 get { return current_customattrtarget; }
\r
150 set { current_customattrtarget = value; }
\r
153 public IDeclSecurityTarget CurrentDeclSecurityTarget {
\r
154 get { return current_declsectarget; }
\r
155 set { current_declsectarget = value; }
\r
158 public ExternTable ExternTable {
\r
159 get { return extern_table; }
\r
162 public TypeManager TypeManager {
\r
163 get { return type_manager; }
\r
166 public bool HasEntryPoint {
\r
167 get { return entry_point; }
\r
169 /* if (!value) error: unsetting entrypoint ? */
\r
171 throw new Exception ("Multiple .entrypoint declarations.");
\r
172 entry_point = value;
\r
176 public TypeRef GetTypeRef (string name)
\r
180 if (typeref_table == null)
\r
181 typeref_table = new Hashtable ();
\r
183 tr = typeref_table [name] as TypeRef;
\r
186 tr = new TypeRef (name, false, null);
\r
187 typeref_table [name] = tr;
\r
193 public void SetSubSystem (int sub_system)
\r
195 this.sub_system = sub_system;
\r
198 public void SetCorFlags (int cor_flags)
\r
200 this.cor_flags = cor_flags;
\r
203 public void SetImageBase (long image_base)
\r
205 this.image_base = image_base;
\r
208 public void SetStackReserve (long stack_reserve)
\r
210 this.stack_reserve = stack_reserve;
\r
213 public void SetAssemblyName (string name)
\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
223 public void SetModuleName (string module_name)
\r
225 this.module_name = module_name;
\r
228 public void SetFileRef (FileRef file_ref)
\r
230 this.file_ref = file_ref;
\r
233 public bool IsThisAssembly (string name)
\r
235 return (name == assembly_name);
\r
238 public bool IsThisModule (string name)
\r
240 return (name == module_name);
\r
243 public void BeginSourceFile (string name)
\r
245 if (symwriter != null)
\r
246 symwriter.BeginSourceFile (name);
\r
249 public void EndSourceFile ()
\r
251 if (symwriter != null)
\r
252 symwriter.EndSourceFile ();
\r
255 public void BeginTypeDef (TypeAttr attr, string name, IClassRef parent,
\r
256 ArrayList impl_list, Location location, GenericParameters gen_params)
\r
258 TypeDef outer = null;
\r
259 string cache_name = CacheName (name);
\r
261 if (typedef_stack_top > 0) {
\r
262 StringBuilder sb = new StringBuilder ();
\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
270 cache_name = CacheName (sb.ToString ());
\r
273 TypeDef typedef = type_manager[cache_name];
\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
284 typedef = new TypeDef (attr, current_namespace,
\r
285 name, parent, impl_list, location, gen_params);
\r
288 typedef.OuterType = outer;
\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
297 public void AddFieldMarshalInfo (PEAPI.NativeType native_type)
\r
299 current_field_native_type = native_type;
\r
302 public void AddFieldDef (FieldDef fielddef)
\r
304 if (current_field_native_type != null) {
\r
305 fielddef.AddMarshalInfo (current_field_native_type);
\r
306 current_field_native_type = null;
\r
309 if (current_typedef != null) {
\r
310 current_typedef.AddFieldDef (fielddef);
\r
312 global_field_table.Add (
\r
313 new DictionaryEntry (fielddef.Name, fielddef.Type.FullName),
\r
318 public void AddDataDef (DataDef datadef)
\r
320 data_list.Add (datadef);
\r
323 public void AddManifestResource (ManifestResource mr)
\r
325 if (manifestResources == null)
\r
326 manifestResources = new ArrayList ();
\r
327 manifestResources.Add (mr);
\r
330 public PEAPI.DataConstant GetDataConst (string name)
\r
332 foreach (DataDef def in data_list) {
\r
333 if (def.Name == name)
\r
334 return (DataConstant) def.PeapiConstant;
\r
340 public void BeginMethodDef (MethodDef methoddef)
\r
342 if (current_typedef != null) {
\r
343 current_typedef.AddMethodDef (methoddef);
\r
345 global_method_table.Add (methoddef.Signature,
\r
349 current_customattrtarget = current_methoddef = methoddef;
\r
350 current_declsectarget = methoddef;
\r
353 public void EndMethodDef (Location location)
\r
355 if (symwriter != null)
\r
356 symwriter.EndMethod (location);
\r
358 current_methoddef = null;
\r
361 public void EndTypeDef ()
\r
363 typedef_stack_top--;
\r
364 typedef_stack.RemoveAt (typedef_stack_top);
\r
366 if (typedef_stack_top > 0)
\r
367 current_typedef = (TypeDef) typedef_stack [typedef_stack_top-1];
\r
369 current_typedef = null;
\r
373 public void BeginAssemblyRef (string name, AssemblyName asmb_name)
\r
375 current_customattrtarget = current_assemblyref = ExternTable.AddAssembly (name, asmb_name);
\r
376 current_declsectarget = current_assemblyref;
\r
379 public void EndAssemblyRef ()
\r
381 current_assemblyref = null;
\r
382 current_customattrtarget = null;
\r
383 current_declsectarget = null;
\r
386 public void AddToDefineContentsList (TypeDef typedef)
\r
388 defcont_list.Add (typedef);
\r
391 public void SetAssemblyPublicKey (byte [] public_key)
\r
393 assembly_public_key = public_key;
\r
396 public void SetAssemblyVersion (int major, int minor, int build, int revision)
\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
404 public void SetAssemblyLocale (string locale)
\r
406 assembly_locale = locale;
\r
409 public void SetAssemblyHashAlgorithm (int algorithm)
\r
411 assembly_hash_algorithm = algorithm;
\r
414 public void AddAssemblyCustomAttribute (CustomAttr attribute)
\r
416 if (assembly_custom_attributes == null)
\r
417 assembly_custom_attributes = new ArrayList ();
\r
418 assembly_custom_attributes.Add (attribute);
\r
421 public void AddAssemblyPermission (PEAPI.SecurityAction sec_action, object perm)
\r
423 if (assembly_declsec == null)
\r
424 assembly_declsec = new DeclSecurity ();
\r
426 PermissionSet ps = perm as PermissionSet;
\r
428 assembly_declsec.AddPermission (sec_action, (IPermission) perm);
\r
430 assembly_declsec.AddPermissionSet (sec_action, ps);
\r
433 public void AddPermission (PEAPI.SecurityAction sec_action, object perm)
\r
435 if (CurrentDeclSecurityTarget == null)
\r
438 PermissionSet ps = perm as PermissionSet;
\r
440 CurrentDeclSecurityTarget.AddPermission (sec_action, (IPermission) perm);
\r
442 CurrentDeclSecurityTarget.AddPermissionSet (sec_action, ps);
\r
445 public void Write ()
\r
447 FileStream out_stream = null;
\r
450 if (!is_dll && !HasEntryPoint)
\r
451 throw new Exception ("No EntryPoint found.");
\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
457 if (file_ref != null)
\r
458 file_ref.Resolve (this);
\r
460 extern_table.Resolve (this);
\r
461 type_manager.DefineAll ();
\r
463 if (manifestResources != null) {
\r
464 foreach (ManifestResource mr in manifestResources)
\r
465 pefile.AddManifestResource (mr);
\r
468 foreach (FieldDef fielddef in global_field_table.Values) {
\r
469 fielddef.Define (this);
\r
472 foreach (MethodDef methoddef in global_method_table.Values) {
\r
473 methoddef.Define (this);
\r
476 foreach (TypeDef typedef in defcont_list) {
\r
477 typedef.DefineContents (this);
\r
480 if (assembly_custom_attributes != null) {
\r
481 foreach (CustomAttr cattr in assembly_custom_attributes)
\r
482 cattr.AddTo (this, asmb);
\r
485 if (assembly_declsec != null)
\r
486 assembly_declsec.AddTo (this, asmb);
\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
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
500 pefile.WritePEFile ();
\r
502 if (symwriter != null) {
\r
503 Guid guid = pefile.GetThisModule ().Guid;
\r
504 symwriter.Write (guid);
\r
509 if (out_stream != null)
\r
510 out_stream.Close ();
\r
514 public PEAPI.Method ResolveMethod (string signature)
\r
516 MethodDef methoddef = (MethodDef) global_method_table[signature];
\r
518 return methoddef.Resolve (this);
\r
521 public PEAPI.Method ResolveVarargMethod (string signature,
\r
522 CodeGen code_gen, PEAPI.Type[] opt)
\r
524 MethodDef methoddef = (MethodDef) global_method_table[signature];
\r
525 methoddef.Resolve (code_gen);
\r
527 return methoddef.GetVarargSig (opt);
\r
530 public PEAPI.Field ResolveField (string name, string type_name)
\r
532 FieldDef fielddef = (FieldDef) global_field_table[new DictionaryEntry (name, type_name)];
\r
534 return fielddef.Resolve (this);
\r
537 private string CacheName (string name)
\r
539 if (current_namespace == null ||
\r
540 current_namespace == String.Empty)
\r
543 return current_namespace + "." + name;
\r