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