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
21 using SSPermissionSet = System.Security.PermissionSet;
\r
22 using MIPermissionSet = Mono.ILASM.PermissionSet;
\r
24 using MIAssembly = Mono.ILASM.Assembly;
\r
26 namespace Mono.ILASM {
\r
28 public class CodeGen {
\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
43 private MIAssembly this_assembly;
\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
56 private ArrayList defcont_list;
\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
63 private string output_file;
\r
64 private bool is_dll;
\r
65 private bool entry_point;
\r
68 private Module this_module;
\r
70 public CodeGen (string output_file, bool is_dll, bool debugging_info, bool noautoinherit)
\r
72 this.output_file = output_file;
\r
73 this.is_dll = is_dll;
\r
74 this.noautoinherit = noautoinherit;
\r
77 symwriter = new SymbolWriter (output_file);
\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
86 data_table = new Hashtable ();
\r
88 defcont_list = new ArrayList ();
\r
94 entry_point = false;
\r
98 public PEFile PEFile {
\r
99 get { return pefile; }
\r
102 public SymbolWriter SymbolWriter {
\r
103 get { return symwriter; }
\r
106 public string CurrentNameSpace {
\r
107 get { return current_namespace; }
\r
108 set { current_namespace = value; }
\r
111 public TypeDef CurrentTypeDef {
\r
112 get { return current_typedef; }
\r
115 public MethodDef CurrentMethodDef {
\r
116 get { return current_methoddef; }
\r
119 public ExternAssembly CurrentAssemblyRef {
\r
120 get { return current_assemblyref; }
\r
123 // public ExternModule CurrentModuleRef {
\r
124 // get { return current_moduleref; }
\r
127 public ICustomAttrTarget CurrentCustomAttrTarget {
\r
128 get { return current_customattrtarget; }
\r
129 set { current_customattrtarget = value; }
\r
132 public IDeclSecurityTarget CurrentDeclSecurityTarget {
\r
133 get { return current_declsectarget; }
\r
134 set { current_declsectarget = value; }
\r
137 public ExternTable ExternTable {
\r
138 get { return extern_table; }
\r
141 public TypeManager TypeManager {
\r
142 get { return type_manager; }
\r
145 public bool HasEntryPoint {
\r
146 get { return entry_point; }
\r
148 /* if (!value) error: unsetting entrypoint ? */
\r
150 Report.Error ("Multiple .entrypoint declarations.");
\r
151 entry_point = value;
\r
155 public TypeRef GetTypeRef (string name)
\r
159 if (typeref_table == null)
\r
160 typeref_table = new Hashtable ();
\r
162 tr = typeref_table [name] as TypeRef;
\r
165 tr = new TypeRef (name, false, null);
\r
166 typeref_table [name] = tr;
\r
172 public GlobalMethodRef GetGlobalMethodRef (BaseTypeRef ret_type, PEAPI.CallConv call_conv,
\r
173 string name, BaseTypeRef[] param, int gen_param_count)
\r
175 string key = MethodDef.CreateSignature (ret_type, call_conv, name, param, gen_param_count, true);
\r
177 GlobalMethodRef methref = null;
\r
179 if (global_methodref_table == null)
\r
180 global_methodref_table = new Hashtable ();
\r
182 methref = (GlobalMethodRef) global_methodref_table [key];
\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
192 public GlobalFieldRef GetGlobalFieldRef (BaseTypeRef ret_type, string name)
\r
194 string key = ret_type.FullName + name;
\r
196 GlobalFieldRef fieldref = null;
\r
198 if (global_fieldref_table == null)
\r
199 global_fieldref_table = new Hashtable ();
\r
201 fieldref = (GlobalFieldRef) global_fieldref_table [key];
\r
203 if (fieldref == null) {
\r
204 fieldref = new GlobalFieldRef (ret_type, name);
\r
205 global_fieldref_table [key] = fieldref;
\r
211 public void SetSubSystem (int sub_system)
\r
213 this.sub_system = sub_system;
\r
216 public void SetCorFlags (int cor_flags)
\r
218 this.cor_flags = cor_flags;
\r
221 public void SetImageBase (long image_base)
\r
223 this.image_base = image_base;
\r
226 public void SetStackReserve (long stack_reserve)
\r
228 this.stack_reserve = stack_reserve;
\r
231 public void SetThisAssembly (string name, PEAPI.AssemAttr attr)
\r
233 if (this_assembly != null && this_assembly.Name != name)
\r
234 Report.Error ("Multiple assembly declarations");
\r
236 this_assembly = new Assembly (name);
\r
237 this_assembly.SetAssemblyAttr (attr);
\r
238 if (name != "mscorlib")
\r
239 ExternTable.AddCorlib ();
\r
242 public void SetModuleName (string module_name)
\r
244 this_module = new Module (module_name);
\r
245 CurrentCustomAttrTarget = this_module;
\r
248 public void SetFileRef (FileRef file_ref)
\r
250 this.file_ref = file_ref;
\r
253 public MIAssembly ThisAssembly {
\r
254 get { return this_assembly; }
\r
257 public bool IsThisAssembly (string name)
\r
259 return (this_assembly != null && name == this_assembly.Name);
\r
262 public Module ThisModule {
\r
263 get { return this_module; }
\r
266 public bool IsThisModule (string name)
\r
268 return (this_module != null && name == this_module.Name);
\r
271 public void BeginSourceFile (string name)
\r
273 if (symwriter != null)
\r
274 symwriter.BeginSourceFile (name);
\r
277 public void EndSourceFile ()
\r
279 if (symwriter != null)
\r
280 symwriter.EndSourceFile ();
\r
283 public void BeginTypeDef (TypeAttr attr, string name, BaseClassRef parent,
\r
284 ArrayList impl_list, Location location, GenericParameters gen_params)
\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
291 for (int i = 0; i < typedef_stack_top; i++){
\r
292 outer = (TypeDef) typedef_stack [i];
\r
294 /* Use FullName for outermost class to get the
\r
296 sb.Append (outer.FullName);
\r
298 sb.Append (outer.Name);
\r
302 cache_name = sb.ToString ();
\r
305 TypeDef typedef = type_manager[cache_name];
\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
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
326 public void AddFieldMarshalInfo (PEAPI.NativeType native_type)
\r
328 current_field_native_type = native_type;
\r
331 public void AddFieldDef (FieldDef fielddef)
\r
333 if (current_field_native_type != null) {
\r
334 fielddef.AddMarshalInfo (current_field_native_type);
\r
335 current_field_native_type = null;
\r
338 if (current_typedef != null) {
\r
339 current_typedef.AddFieldDef (fielddef);
\r
341 global_field_table.Add (
\r
342 new DictionaryEntry (fielddef.Name, fielddef.Type.FullName),
\r
347 public void AddDataDef (DataDef datadef)
\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
354 public void AddManifestResource (ManifestResource mr)
\r
356 if (manifestResources == null)
\r
357 manifestResources = new ArrayList ();
\r
358 manifestResources.Add (mr);
\r
361 public PEAPI.DataConstant GetDataConst (string name)
\r
363 DataDef def = (DataDef) data_table [name];
\r
367 return (DataConstant) def.PeapiConstant;
\r
370 public void BeginMethodDef (MethodDef methoddef)
\r
372 if (current_typedef != null) {
\r
373 current_typedef.AddMethodDef (methoddef);
\r
375 global_method_table.Add (methoddef.Signature,
\r
379 current_customattrtarget = current_methoddef = methoddef;
\r
380 current_declsectarget = methoddef;
\r
383 public void EndMethodDef (Location location)
\r
385 if (symwriter != null)
\r
386 symwriter.EndMethod (location);
\r
388 current_methoddef = null;
\r
391 public void EndTypeDef ()
\r
393 typedef_stack_top--;
\r
394 typedef_stack.RemoveAt (typedef_stack_top);
\r
396 if (typedef_stack_top > 0)
\r
397 current_typedef = (TypeDef) typedef_stack [typedef_stack_top-1];
\r
399 current_typedef = null;
\r
403 public void BeginAssemblyRef (string name, AssemblyName asmb_name, PEAPI.AssemAttr attr)
\r
405 current_customattrtarget = current_assemblyref = ExternTable.AddAssembly (name, asmb_name, attr);
\r
406 current_declsectarget = current_assemblyref;
\r
409 public void EndAssemblyRef ()
\r
411 current_assemblyref = null;
\r
412 current_customattrtarget = null;
\r
413 current_declsectarget = null;
\r
416 public void AddToDefineContentsList (TypeDef typedef)
\r
418 defcont_list.Add (typedef);
\r
421 public void AddPermission (PEAPI.SecurityAction sec_action, object perm)
\r
423 if (CurrentDeclSecurityTarget == null)
\r
426 AddPermission (sec_action, perm, CurrentDeclSecurityTarget.DeclSecurity);
\r
429 private void AddPermission (PEAPI.SecurityAction sec_action, object perm, DeclSecurity decl_sec)
\r
431 SSPermissionSet ps = perm as SSPermissionSet;
\r
433 decl_sec.AddPermissionSet (sec_action, ps);
\r
437 IPermission iper = perm as IPermission;
\r
438 if (iper != null) {
\r
439 decl_sec.AddPermission (sec_action, iper);
\r
443 MIPermissionSet ps20 = perm as MIPermissionSet;
\r
444 if (ps20 != null) {
\r
445 decl_sec.AddPermissionSet (sec_action, ps20);
\r
450 public void Write ()
\r
452 FileStream out_stream = null;
\r
455 if (ThisModule == null)
\r
456 this_module = new Module (Path.GetFileName (output_file));
\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
462 ThisModule.PeapiModule = pefile.GetThisModule ();
\r
464 if (file_ref != null)
\r
465 file_ref.Resolve (this);
\r
467 extern_table.Resolve (this);
\r
468 type_manager.DefineAll ();
\r
470 if (manifestResources != null) {
\r
471 foreach (ManifestResource mr in manifestResources)
\r
472 pefile.AddManifestResource (mr);
\r
475 foreach (FieldDef fielddef in global_field_table.Values) {
\r
476 fielddef.Define (this);
\r
479 foreach (MethodDef methoddef in global_method_table.Values) {
\r
480 methoddef.Define (this);
\r
483 foreach (TypeDef typedef in defcont_list) {
\r
484 typedef.DefineContents (this);
\r
487 if (ThisAssembly != null)
\r
488 ThisAssembly.Resolve (this, pefile.GetThisAssembly ());
\r
489 ThisModule.Resolve (this, pefile.GetThisModule ());
\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
498 pefile.WritePEFile ();
\r
500 if (symwriter != null) {
\r
501 Guid guid = pefile.GetThisModule ().Guid;
\r
502 symwriter.Write (guid);
\r
505 if (out_stream != null)
\r
506 out_stream.Close ();
\r
510 public PEAPI.Method ResolveMethod (string signature)
\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
516 return methoddef.Resolve (this);
\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
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
526 methoddef.Resolve (code_gen);
\r
527 return methoddef.GetVarargSig (opt, sig_with_optional_params);
\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
533 if (fielddef == null)
\r
534 Report.Error (String.Format ("Unable to resolve global field : {0} {1}", type_name, name));
\r
536 return fielddef.Resolve (this);
\r
539 private string CacheName (string name)
\r
541 if (current_namespace == null ||
\r
542 current_namespace == String.Empty)
\r
545 return current_namespace + "." + name;
\r