2 // Mono.ILASM.CodeGen.cs
5 // Sergey Chaban (serge@wildwestsoftware.com)
6 // Jackson Harper (Jackson@LatitudeGeo.com)
9 // (C) 2003 Jackson Harper, All rights reserved
15 using System
.Collections
;
16 using System
.Reflection
;
17 using System
.Reflection
.Emit
;
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
;
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
;
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 ();
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; }
147 /* if (!value) error: unsetting entrypoint ? */
149 Report
.Error ("Multiple .entrypoint declarations.");
154 public TypeRef
GetTypeRef (string name
)
158 if (typeref_table
== null)
159 typeref_table
= new Hashtable ();
161 tr
= typeref_table
[name
] as TypeRef
;
164 tr
= new TypeRef (name
, false, null);
165 typeref_table
[name
] = 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 ();
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
;
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 ();
200 fieldref
= (GlobalFieldRef
) global_fieldref_table
[key
];
202 if (fieldref
== null) {
203 fieldref
= new GlobalFieldRef (ret_type
, name
);
204 global_fieldref_table
[key
] = 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
];
293 /* Use FullName for outermost class to get the
295 sb
.Append (outer
.FullName
);
297 sb
.Append (outer
.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
);
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
);
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
);
340 global_field_table
.Add (
341 new DictionaryEntry (fielddef
.Name
, fielddef
.Type
.FullName
),
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
];
366 return (DataConstant
) def
.PeapiConstant
;
369 public void BeginMethodDef (MethodDef methoddef
)
371 if (current_typedef
!= null) {
372 current_typedef
.AddMethodDef (methoddef
);
374 global_method_table
.Add (methoddef
.Signature
,
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 ()
393 typedef_stack
.RemoveAt (typedef_stack_top
);
395 if (typedef_stack_top
> 0)
396 current_typedef
= (TypeDef
) typedef_stack
[typedef_stack_top
-1];
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)
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
;
432 decl_sec
.AddPermissionSet (sec_action
, ps
);
436 IPermission iper
= perm
as IPermission
;
438 decl_sec
.AddPermission (sec_action
, iper
);
442 MIPermissionSet ps20
= perm
as MIPermissionSet
;
444 decl_sec
.AddPermissionSet (sec_action
, ps20
);
451 FileStream out_stream
= null;
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
);
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
);
504 if (out_stream
!= null)
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
)
544 return current_namespace
+ "." + name
;