This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / gmcs / codegen.cs
1 //
2 // codegen.cs: The code generator
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.
8 //
9
10 using System;
11 using System.IO;
12 using System.Collections;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Runtime.InteropServices;
16 using System.Security.Cryptography;
17
18 using Mono.Security.Cryptography;
19
20 namespace Mono.CSharp {
21
22         /// <summary>
23         ///    Code generator class.
24         /// </summary>
25         public class CodeGen {
26                 static AppDomain current_domain;
27                 static public SymbolWriter SymbolWriter;
28
29                 public static AssemblyClass Assembly;
30                 public static ModuleClass Module;
31
32                 static CodeGen ()
33                 {
34                         Assembly = new AssemblyClass ();
35                         Module = new ModuleClass (RootContext.Unsafe);
36                 }
37
38                 public static string Basename (string name)
39                 {
40                         int pos = name.LastIndexOf ('/');
41
42                         if (pos != -1)
43                                 return name.Substring (pos + 1);
44
45                         pos = name.LastIndexOf ('\\');
46                         if (pos != -1)
47                                 return name.Substring (pos + 1);
48
49                         return name;
50                 }
51
52                 public static string Dirname (string name)
53                 {
54                         int pos = name.LastIndexOf ('/');
55
56                         if (pos != -1)
57                                 return name.Substring (0, pos);
58
59                         pos = name.LastIndexOf ('\\');
60                         if (pos != -1)
61                                 return name.Substring (0, pos);
62
63                         return ".";
64                 }
65
66                 static string TrimExt (string name)
67                 {
68                         int pos = name.LastIndexOf ('.');
69
70                         return name.Substring (0, pos);
71                 }
72
73                 static public string FileName;
74
75                 //
76                 // Initializes the symbol writer
77                 //
78                 static void InitializeSymbolWriter ()
79                 {
80                         SymbolWriter = SymbolWriter.GetSymbolWriter (Module.Builder);
81
82                         //
83                         // If we got an ISymbolWriter instance, initialize it.
84                         //
85                         if (SymbolWriter == null) {
86                                 Report.Warning (
87                                         -18, "Could not find the symbol writer assembly (Mono.CSharp.Debugger.dll). This is normally an installation problem. Please make sure to compile and install the mcs/class/Mono.CSharp.Debugger directory.");
88                                 return;
89                         }
90                 }
91
92                 //
93                 // Initializes the code generator variables
94                 //
95                 static public void Init (string name, string output, bool want_debugging_support)
96                 {
97                         FileName = output;
98                         AssemblyName an = Assembly.GetAssemblyName (name, output);
99
100                         if (an.KeyPair != null) {
101                                 // If we are going to strong name our assembly make
102                                 // sure all its refs are strong named
103                                 foreach (Assembly a in TypeManager.GetAssemblies ()) {
104                                         AssemblyName ref_name = a.GetName ();
105                                         byte [] b = ref_name.GetPublicKeyToken ();
106                                         if (b == null || b.Length == 0) {
107                                                 Report.Warning (1577, "Assembly generation failed " +
108                                                                 "-- Referenced assembly '" +
109                                                                 ref_name.Name +
110                                                                 "' does not have a strong name.");
111                                                 //Environment.Exit (1);
112                                         }
113                                 }
114                         }
115                         
116                         current_domain = AppDomain.CurrentDomain;
117
118                         try {
119                                 Assembly.Builder = current_domain.DefineDynamicAssembly (an,
120                                         AssemblyBuilderAccess.Save, Dirname (name));
121                         }
122                         catch (ArgumentException) {
123                                 // specified key may not be exportable outside it's container
124                                 if (RootContext.StrongNameKeyContainer != null) {
125                                         Report.Error (1548, "Could not access the key inside the container `" +
126                                                 RootContext.StrongNameKeyContainer + "'.");
127                                         Environment.Exit (1);
128                                 }
129                                 throw;
130                         }
131                         catch (CryptographicException) {
132                                 if ((RootContext.StrongNameKeyContainer != null) || (RootContext.StrongNameKeyFile != null)) {
133                                         Report.Error (1548, "Could not use the specified key to strongname the assembly.");
134                                         Environment.Exit (1);
135                                 }
136                                 throw;
137                         }
138
139                         //
140                         // Pass a path-less name to DefineDynamicModule.  Wonder how
141                         // this copes with output in different directories then.
142                         // FIXME: figure out how this copes with --output /tmp/blah
143                         //
144                         // If the third argument is true, the ModuleBuilder will dynamically
145                         // load the default symbol writer.
146                         //
147                         Module.Builder = Assembly.Builder.DefineDynamicModule (
148                                 Basename (name), Basename (output), want_debugging_support);
149
150                         if (want_debugging_support)
151                                 InitializeSymbolWriter ();
152                 }
153
154                 static public void Save (string name)
155                 {
156                         try {
157                                 Assembly.Builder.Save (Basename (name));
158                         }
159                         catch (COMException) {
160                                 if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
161                                         throw;
162
163                                 // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies 
164                                 Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
165                                         RootContext.StrongNameKeyFile +
166                                         "', Use MCS with the Mono runtime or CSC to compile this assembly.");
167                         }
168                         catch (System.IO.IOException io) {
169                                 Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
170                         }
171                 }
172         }
173
174         //
175         // Provides "local" store across code that can yield: locals
176         // or fields, notice that this should not be used by anonymous
177         // methods to create local storage, those only require
178         // variable mapping.
179         //
180         public class VariableStorage {
181                 ILGenerator ig;
182                 FieldBuilder fb;
183                 LocalBuilder local;
184                 
185                 static int count;
186                 
187                 public VariableStorage (EmitContext ec, Type t)
188                 {
189                         count++;
190                         if (ec.InIterator)
191                                 fb = IteratorHandler.Current.MapVariable ("s_", count.ToString (), t);
192                         else
193                                 local = ec.ig.DeclareLocal (t);
194                         ig = ec.ig;
195                 }
196
197                 public void EmitThis ()
198                 {
199                         if (fb != null)
200                                 ig.Emit (OpCodes.Ldarg_0);
201                 }
202
203                 public void EmitStore ()
204                 {
205                         if (fb == null)
206                                 ig.Emit (OpCodes.Stloc, local);
207                         else
208                                 ig.Emit (OpCodes.Stfld, fb);
209                 }
210
211                 public void EmitLoad ()
212                 {
213                         if (fb == null)
214                                 ig.Emit (OpCodes.Ldloc, local);
215                         else 
216                                 ig.Emit (OpCodes.Ldfld, fb);
217                 }
218                 
219                 public void EmitCall (MethodInfo mi)
220                 {
221                         // FIXME : we should handle a call like tostring
222                         // here, where boxing is needed. However, we will
223                         // never encounter that with the current usage.
224                         
225                         bool value_type_call;
226                         EmitThis ();
227                         if (fb == null) {
228                                 value_type_call = local.LocalType.IsValueType;
229                                 
230                                 if (value_type_call)
231                                         ig.Emit (OpCodes.Ldloca, local);
232                                 else
233                                         ig.Emit (OpCodes.Ldloc, local);
234                         } else {
235                                 value_type_call = fb.FieldType.IsValueType;
236                                 
237                                 if (value_type_call)
238                                         ig.Emit (OpCodes.Ldflda, fb);
239                                 else
240                                         ig.Emit (OpCodes.Ldfld, fb);
241                         }
242                         
243                         ig.Emit (value_type_call ? OpCodes.Call : OpCodes.Callvirt, mi);
244                 }
245         }
246         
247         /// <summary>
248         ///   An Emit Context is created for each body of code (from methods,
249         ///   properties bodies, indexer bodies or constructor bodies)
250         /// </summary>
251         public class EmitContext {
252                 public DeclSpace DeclSpace;
253                 public DeclSpace TypeContainer;
254                 public ILGenerator   ig;
255
256                 /// <summary>
257                 ///   This variable tracks the `checked' state of the compilation,
258                 ///   it controls whether we should generate code that does overflow
259                 ///   checking, or if we generate code that ignores overflows.
260                 ///
261                 ///   The default setting comes from the command line option to generate
262                 ///   checked or unchecked code plus any source code changes using the
263                 ///   checked/unchecked statements or expressions.   Contrast this with
264                 ///   the ConstantCheckState flag.
265                 /// </summary>
266                 
267                 public bool CheckState;
268
269                 /// <summary>
270                 ///   The constant check state is always set to `true' and cant be changed
271                 ///   from the command line.  The source code can change this setting with
272                 ///   the `checked' and `unchecked' statements and expressions. 
273                 /// </summary>
274                 public bool ConstantCheckState;
275
276                 /// <summary>
277                 ///   Whether we are emitting code inside a static or instance method
278                 /// </summary>
279                 public bool IsStatic;
280
281                 /// <summary>
282                 ///   Whether we are emitting a field initializer
283                 /// </summary>
284                 public bool IsFieldInitializer;
285
286                 /// <summary>
287                 ///   The value that is allowed to be returned or NULL if there is no
288                 ///   return type.
289                 /// </summary>
290                 public Type ReturnType;
291
292                 /// <summary>
293                 ///   Points to the Type (extracted from the TypeContainer) that
294                 ///   declares this body of code
295                 /// </summary>
296                 public Type ContainerType;
297                 
298                 /// <summary>
299                 ///   Whether this is generating code for a constructor
300                 /// </summary>
301                 public bool IsConstructor;
302
303                 /// <summary>
304                 ///   Whether we're control flow analysis enabled
305                 /// </summary>
306                 public bool DoFlowAnalysis;
307                 
308                 /// <summary>
309                 ///   Keeps track of the Type to LocalBuilder temporary storage created
310                 ///   to store structures (used to compute the address of the structure
311                 ///   value on structure method invocations)
312                 /// </summary>
313                 public Hashtable temporary_storage;
314
315                 public Block CurrentBlock;
316
317                 public int CurrentFile;
318
319                 /// <summary>
320                 ///   The location where we store the return value.
321                 /// </summary>
322                 LocalBuilder return_value;
323
324                 /// <summary>
325                 ///   The location where return has to jump to return the
326                 ///   value
327                 /// </summary>
328                 public Label ReturnLabel;
329
330                 /// <summary>
331                 ///   If we already defined the ReturnLabel
332                 /// </summary>
333                 public bool HasReturnLabel;
334
335                 /// <summary>
336                 ///   Whether we are inside an iterator block.
337                 /// </summary>
338                 public bool InIterator;
339
340                 public bool IsLastStatement;
341                 
342                 /// <summary>
343                 ///   Whether remapping of locals, parameters and fields is turned on.
344                 ///   Used by iterators and anonymous methods.
345                 /// </summary>
346                 public bool RemapToProxy;
347
348                 /// <summary>
349                 ///  Whether we are inside an unsafe block
350                 /// </summary>
351                 public bool InUnsafe;
352
353                 /// <summary>
354                 ///  Whether we are in a `fixed' initialization
355                 /// </summary>
356                 public bool InFixedInitializer;
357
358                 /// <summary>
359                 ///  Whether we are inside an anonymous method.
360                 /// </summary>
361                 public bool InAnonymousMethod;
362                 
363                 /// <summary>
364                 ///   Location for this EmitContext
365                 /// </summary>
366                 public Location loc;
367
368                 /// <summary>
369                 ///   Used to flag that it is ok to define types recursively, as the
370                 ///   expressions are being evaluated as part of the type lookup
371                 ///   during the type resolution process
372                 /// </summary>
373                 public bool ResolvingTypeTree;
374                 
375                 /// <summary>
376                 ///   Inside an enum definition, we do not resolve enumeration values
377                 ///   to their enumerations, but rather to the underlying type/value
378                 ///   This is so EnumVal + EnumValB can be evaluated.
379                 ///
380                 ///   There is no "E operator + (E x, E y)", so during an enum evaluation
381                 ///   we relax the rules
382                 /// </summary>
383                 public bool InEnumContext;
384
385                 FlowBranching current_flow_branching;
386                 
387                 public EmitContext (DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig,
388                                     Type return_type, int code_flags, bool is_constructor)
389                 {
390                         this.ig = ig;
391
392                         TypeContainer = parent;
393                         DeclSpace = ds;
394                         CheckState = RootContext.Checked;
395                         ConstantCheckState = true;
396                         
397                         IsStatic = (code_flags & Modifiers.STATIC) != 0;
398                         InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0;
399                         RemapToProxy = InIterator;
400                         ReturnType = return_type;
401                         IsConstructor = is_constructor;
402                         CurrentBlock = null;
403                         CurrentFile = 0;
404                         
405                         if (parent != null){
406                                 // Can only be null for the ResolveType contexts.
407                                 ContainerType = parent.TypeBuilder;
408                                 if (parent.UnsafeContext)
409                                         InUnsafe = true;
410                                 else
411                                         InUnsafe = (code_flags & Modifiers.UNSAFE) != 0;
412                         }
413                         loc = l;
414
415                         if (ReturnType == TypeManager.void_type)
416                                 ReturnType = null;
417                 }
418
419                 public EmitContext (TypeContainer tc, Location l, ILGenerator ig,
420                                     Type return_type, int code_flags, bool is_constructor)
421                         : this (tc, tc, l, ig, return_type, code_flags, is_constructor)
422                 {
423                 }
424
425                 public EmitContext (TypeContainer tc, Location l, ILGenerator ig,
426                                     Type return_type, int code_flags)
427                         : this (tc, tc, l, ig, return_type, code_flags, false)
428                 {
429                 }
430
431                 public FlowBranching CurrentBranching {
432                         get {
433                                 return current_flow_branching;
434                         }
435                 }
436
437                 // <summary>
438                 //   Starts a new code branching.  This inherits the state of all local
439                 //   variables and parameters from the current branching.
440                 // </summary>
441                 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
442                 {
443                         current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
444                         return current_flow_branching;
445                 }
446
447                 // <summary>
448                 //   Starts a new code branching for block `block'.
449                 // </summary>
450                 public FlowBranching StartFlowBranching (Block block)
451                 {
452                         FlowBranching.BranchingType type;
453
454                         if (CurrentBranching.Type == FlowBranching.BranchingType.Switch)
455                                 type = FlowBranching.BranchingType.SwitchSection;
456                         else
457                                 type = FlowBranching.BranchingType.Block;
458
459                         current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, block, block.StartLocation);
460                         return current_flow_branching;
461                 }
462
463                 // <summary>
464                 //   Ends a code branching.  Merges the state of locals and parameters
465                 //   from all the children of the ending branching.
466                 // </summary>
467                 public FlowBranching.UsageVector DoEndFlowBranching ()
468                 {
469                         FlowBranching old = current_flow_branching;
470                         current_flow_branching = current_flow_branching.Parent;
471
472                         return current_flow_branching.MergeChild (old);
473                 }
474
475                 // <summary>
476                 //   Ends a code branching.  Merges the state of locals and parameters
477                 //   from all the children of the ending branching.
478                 // </summary>
479                 public FlowBranching.Reachability EndFlowBranching ()
480                 {
481                         FlowBranching.UsageVector vector = DoEndFlowBranching ();
482
483                         return vector.Reachability;
484                 }
485
486                 // <summary>
487                 //   Kills the current code branching.  This throws away any changed state
488                 //   information and should only be used in case of an error.
489                 // </summary>
490                 public void KillFlowBranching ()
491                 {
492                         current_flow_branching = current_flow_branching.Parent;
493                 }
494
495                 public void EmitTopBlock (Block block, InternalParameters ip, Location loc)
496                 {
497                         bool unreachable = false;
498
499                         if (!Location.IsNull (loc))
500                                 CurrentFile = loc.File;
501
502                         if (block != null){
503                             try {
504                                 int errors = Report.Errors;
505
506                                 block.EmitMeta (this, ip);
507
508                                 if (Report.Errors == errors){
509                                         bool old_do_flow_analysis = DoFlowAnalysis;
510                                         DoFlowAnalysis = true;
511
512                                         current_flow_branching = FlowBranching.CreateBranching (
513                                                 null, FlowBranching.BranchingType.Block, block, loc);
514
515                                         if (!block.Resolve (this)) {
516                                                 current_flow_branching = null;
517                                                 DoFlowAnalysis = old_do_flow_analysis;
518                                                 return;
519                                         }
520
521                                         FlowBranching.Reachability reachability = current_flow_branching.MergeTopBlock ();
522                                         current_flow_branching = null;
523
524                                         DoFlowAnalysis = old_do_flow_analysis;
525
526                                         block.Emit (this);
527
528                                         if (reachability.AlwaysReturns ||
529                                             reachability.AlwaysThrows ||
530                                             reachability.IsUnreachable)
531                                                 unreachable = true;
532                                         }
533 #if FIXME
534                             } catch (Exception e) {
535                                         Console.WriteLine ("Exception caught by the compiler while compiling:");
536                                         Console.WriteLine ("   Block that caused the problem begin at: " + loc);
537                                         
538                                         if (CurrentBlock != null){
539                                                 Console.WriteLine ("                     Block being compiled: [{0},{1}]",
540                                                                    CurrentBlock.StartLocation, CurrentBlock.EndLocation);
541                                         }
542                                         Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
543                                         Console.WriteLine (Report.FriendlyStackTrace (e));
544                                         
545                                         Environment.Exit (1);
546 #else
547                             } finally {
548 #endif
549                             }
550                         }
551
552                         if (ReturnType != null && !unreachable){
553                                 if (!InIterator){
554                                         Report.Error (161, loc, "Not all code paths return a value");
555                                         return;
556                                 }
557                         }
558
559                         if (HasReturnLabel)
560                                 ig.MarkLabel (ReturnLabel);
561                         if (return_value != null){
562                                 ig.Emit (OpCodes.Ldloc, return_value);
563                                 ig.Emit (OpCodes.Ret);
564                         } else {
565                                 //
566                                 // If `HasReturnLabel' is set, then we already emitted a
567                                 // jump to the end of the method, so we must emit a `ret'
568                                 // there.
569                                 //
570                                 // Unfortunately, System.Reflection.Emit automatically emits
571                                 // a leave to the end of a finally block.  This is a problem
572                                 // if no code is following the try/finally block since we may
573                                 // jump to a point after the end of the method.
574                                 // As a workaround, we're always creating a return label in
575                                 // this case.
576                                 //
577
578                                 if ((block != null) && block.IsDestructor) {
579                                         // Nothing to do; S.R.E automatically emits a leave.
580                                 } else if (HasReturnLabel || (!unreachable && !InIterator)) {
581                                         if (ReturnType != null)
582                                                 ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
583                                         ig.Emit (OpCodes.Ret);
584                                 }
585                         }
586                 }
587
588                 /// <summary>
589                 ///   This is called immediately before emitting an IL opcode to tell the symbol
590                 ///   writer to which source line this opcode belongs.
591                 /// </summary>
592                 public void Mark (Location loc, bool check_file)
593                 {
594                         if ((CodeGen.SymbolWriter == null) || Location.IsNull (loc))
595                                 return;
596
597                         if (check_file && (CurrentFile != loc.File))
598                                 return;
599
600                         ig.MarkSequencePoint (null, loc.Row, 0, 0, 0);
601                 }
602
603                 /// <summary>
604                 ///   Returns a temporary storage for a variable of type t as 
605                 ///   a local variable in the current body.
606                 /// </summary>
607                 public LocalBuilder GetTemporaryLocal (Type t)
608                 {
609                         LocalBuilder location = null;
610                         
611                         if (temporary_storage != null){
612                                 object o = temporary_storage [t];
613                                 if (o != null){
614                                         if (o is ArrayList){
615                                                 ArrayList al = (ArrayList) o;
616                                                 
617                                                 for (int i = 0; i < al.Count; i++){
618                                                         if (al [i] != null){
619                                                                 location = (LocalBuilder) al [i];
620                                                                 al [i] = null;
621                                                                 break;
622                                                         }
623                                                 }
624                                         } else
625                                                 location = (LocalBuilder) o;
626                                         if (location != null)
627                                                 return location;
628                                 }
629                         }
630                         
631                         return ig.DeclareLocal (t);
632                 }
633
634                 public void FreeTemporaryLocal (LocalBuilder b, Type t)
635                 {
636                         if (temporary_storage == null){
637                                 temporary_storage = new Hashtable ();
638                                 temporary_storage [t] = b;
639                                 return;
640                         }
641                         object o = temporary_storage [t];
642                         if (o == null){
643                                 temporary_storage [t] = b;
644                                 return;
645                         }
646                         if (o is ArrayList){
647                                 ArrayList al = (ArrayList) o;
648                                 for (int i = 0; i < al.Count; i++){
649                                         if (al [i] == null){
650                                                 al [i] = b;
651                                                 return;
652                                         }
653                                 }
654                                 al.Add (b);
655                                 return;
656                         }
657                         ArrayList replacement = new ArrayList ();
658                         replacement.Add (o);
659                         temporary_storage.Remove (t);
660                         temporary_storage [t] = replacement;
661                 }
662
663                 /// <summary>
664                 ///   Current loop begin and end labels.
665                 /// </summary>
666                 public Label LoopBegin, LoopEnd;
667
668                 /// <summary>
669                 ///   Default target in a switch statement.   Only valid if
670                 ///   InSwitch is true
671                 /// </summary>
672                 public Label DefaultTarget;
673
674                 /// <summary>
675                 ///   If this is non-null, points to the current switch statement
676                 /// </summary>
677                 public Switch Switch;
678
679                 /// <summary>
680                 ///   ReturnValue creates on demand the LocalBuilder for the
681                 ///   return value from the function.  By default this is not
682                 ///   used.  This is only required when returns are found inside
683                 ///   Try or Catch statements.
684                 /// </summary>
685                 public LocalBuilder TemporaryReturn ()
686                 {
687                         if (return_value == null){
688                                 return_value = ig.DeclareLocal (ReturnType);
689                                 ReturnLabel = ig.DefineLabel ();
690                                 HasReturnLabel = true;
691                         }
692
693                         return return_value;
694                 }
695
696                 public void NeedReturnLabel ()
697                 {
698                         if (!HasReturnLabel) {
699                                 ReturnLabel = ig.DefineLabel ();
700                                 HasReturnLabel = true;
701                         }
702                 }
703
704                 //
705                 // Creates a field `name' with the type `t' on the proxy class
706                 //
707                 public FieldBuilder MapVariable (string name, Type t)
708                 {
709                         if (InIterator){
710                                 return IteratorHandler.Current.MapVariable ("v_", name, t);
711                         }
712
713                         throw new Exception ("MapVariable for an unknown state");
714                 }
715
716                 //
717                 // Invoke this routine to remap a VariableInfo into the
718                 // proper MemberAccess expression
719                 //
720                 public Expression RemapLocal (LocalInfo local_info)
721                 {
722                         FieldExpr fe = new FieldExpr (local_info.FieldBuilder, loc);
723                         fe.InstanceExpression = new ProxyInstance ();
724                         return fe.DoResolve (this);
725                 }
726
727                 public Expression RemapLocalLValue (LocalInfo local_info, Expression right_side)
728                 {
729                         FieldExpr fe = new FieldExpr (local_info.FieldBuilder, loc);
730                         fe.InstanceExpression = new ProxyInstance ();
731                         return fe.DoResolveLValue (this, right_side);
732                 }
733
734                 public Expression RemapParameter (int idx)
735                 {
736                         FieldExpr fe = new FieldExprNoAddress (IteratorHandler.Current.parameter_fields [idx], loc);
737                         fe.InstanceExpression = new ProxyInstance ();
738                         return fe.DoResolve (this);
739                 }
740
741                 public Expression RemapParameterLValue (int idx, Expression right_side)
742                 {
743                         FieldExpr fe = new FieldExprNoAddress (IteratorHandler.Current.parameter_fields [idx], loc);
744                         fe.InstanceExpression = new ProxyInstance ();
745                         return fe.DoResolveLValue (this, right_side);
746                 }
747                 
748                 //
749                 // Emits the proper object to address fields on a remapped
750                 // variable/parameter to field in anonymous-method/iterator proxy classes.
751                 //
752                 public void EmitThis ()
753                 {
754                         if (InIterator){
755                                 ig.Emit (OpCodes.Ldarg_0);
756                                 if (!IsStatic){
757                                         FieldBuilder this_field = IteratorHandler.Current.this_field;
758                                         if (TypeManager.IsValueType (this_field.FieldType))
759                                                 ig.Emit (OpCodes.Ldflda, this_field);
760                                         else
761                                                 ig.Emit (OpCodes.Ldfld, this_field);
762                                 } 
763                         } else
764                                 ig.Emit (OpCodes.Ldarg_0);
765                 }
766
767                 public Expression GetThis (Location loc)
768                 {
769                         This my_this;
770                         if (CurrentBlock != null)
771                                 my_this = new This (CurrentBlock, loc);
772                         else
773                                 my_this = new This (loc);
774
775                         if (!my_this.ResolveBase (this))
776                                 my_this = null;
777
778                         return my_this;
779                 }
780         }
781
782
783         public abstract class CommonAssemblyModulClass: Attributable {
784                 static string[] attribute_targets = new string [] { "assembly", "module" };
785
786                 protected CommonAssemblyModulClass ():
787                         base (null)
788                 {
789                 }
790
791                 public void AddAttributes (ArrayList attrs)
792                 {
793                         if (OptAttributes == null) {
794                                 OptAttributes = new Attributes (attrs);
795                                 return;
796                         }
797                         OptAttributes.AddAttributes (attrs);
798                         OptAttributes.CheckTargets (ValidAttributeTargets);
799                 }
800
801                 public virtual void Emit (TypeContainer tc) 
802                 {
803                         if (OptAttributes == null)
804                                 return;
805
806                         EmitContext ec = new EmitContext (tc, Mono.CSharp.Location.Null, null, null, 0, false);
807                         OptAttributes.Emit (ec, this);
808                 }
809
810                 protected Attribute GetClsCompliantAttribute ()
811                 {
812                         if (OptAttributes == null)
813                                 return null;
814
815                         EmitContext temp_ec = new EmitContext (new TypeContainer (), Mono.CSharp.Location.Null, null, null, 0, false);
816                         Attribute a = OptAttributes.Search (TypeManager.cls_compliant_attribute_type, temp_ec);
817                         if (a != null) {
818                                 a.Resolve (temp_ec);
819                         }
820                         return a;
821                 }
822
823                 protected override string[] ValidAttributeTargets {
824                         get {
825                                 return attribute_targets;
826                         }
827                 }
828         }
829
830         public class AssemblyClass: CommonAssemblyModulClass {
831                 // TODO: make it private and move all builder based methods here
832                 public AssemblyBuilder Builder;
833                     
834                 bool is_cls_compliant;
835
836                 public AssemblyClass (): base ()
837                 {
838                         is_cls_compliant = false;
839                 }
840
841                 public bool IsClsCompliant {
842                         get {
843                                 return is_cls_compliant;
844                         }
845                         }
846
847                 public override AttributeTargets AttributeTargets {
848                         get {
849                                 return AttributeTargets.Assembly;
850                         }
851                 }
852
853                 public override bool IsClsCompliaceRequired(DeclSpace ds)
854                 {
855                         return is_cls_compliant;
856                 }
857
858                 public void ResolveClsCompliance ()
859                 {
860                         Attribute a = GetClsCompliantAttribute ();
861                         if (a == null)
862                                 return;
863
864                         is_cls_compliant = a.GetClsCompliantAttributeValue (null);
865                 }
866
867                 public AssemblyName GetAssemblyName (string name, string output) 
868                 {
869                         if (OptAttributes != null) {
870                                foreach (Attribute a in OptAttributes.Attrs) {
871                                         if (a.Target != "assembly")
872                                                 continue;
873                                        // TODO: This code is buggy: comparing Attribute name without resolving it is wrong.
874                                        //       However, this is invoked by CodeGen.Init, at which time none of the namespaces
875                                        //       are loaded yet.
876                                         switch (a.Name) {
877                                                 case "AssemblyKeyFile":
878                                                case "AssemblyKeyFileAttribute":
879                                                case "System.Reflection.AssemblyKeyFileAttribute":
880                                                         if (RootContext.StrongNameKeyFile != null) {
881                                                                 Report.Warning (1616, "Compiler option -keyfile overrides " +
882                                                                         "AssemblyKeyFileAttribute");
883                                                         }
884                                                         else {
885                                                                 string value = a.GetString ();
886                                                                 if (value != String.Empty)
887                                                                         RootContext.StrongNameKeyFile = value;
888                                                         }
889                                                         break;
890                                                 case "AssemblyKeyName":
891                                                case "AssemblyKeyNameAttribute":
892                                                case "System.Reflection.AssemblyKeyNameAttribute":
893                                                         if (RootContext.StrongNameKeyContainer != null) {
894                                                                 Report.Warning (1616, "Compiler option -keycontainer overrides " +
895                                                                         "AssemblyKeyNameAttribute");
896                                                         }
897                                                         else {
898                                                                 string value = a.GetString ();
899                                                                 if (value != String.Empty)
900                                                                         RootContext.StrongNameKeyContainer = value;
901                                                         }
902                                                         break;
903                                                 case "AssemblyDelaySign":
904                                                case "AssemblyDelaySignAttribute":
905                                                case "System.Reflection.AssemblyDelaySignAttribute":
906                                                         RootContext.StrongNameDelaySign = a.GetBoolean ();
907                                                         break;
908                                         }
909                                 }
910                         }
911
912                         AssemblyName an = new AssemblyName ();
913                         an.Name = Path.GetFileNameWithoutExtension (name);
914
915                         // note: delay doesn't apply when using a key container
916                         if (RootContext.StrongNameKeyContainer != null) {
917                                 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
918                                 return an;
919                         }
920
921                         // strongname is optional
922                         if (RootContext.StrongNameKeyFile == null)
923                                 return an;
924
925                         string AssemblyDir = Path.GetDirectoryName (output);
926
927                         // the StrongName key file may be relative to (a) the compiled
928                         // file or (b) to the output assembly. See bugzilla #55320
929                         // http://bugzilla.ximian.com/show_bug.cgi?id=55320
930
931                         // (a) relative to the compiled file
932                         string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
933                         bool exist = File.Exists (filename);
934                         if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
935                                 // (b) relative to the outputed assembly
936                                 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
937                                 exist = File.Exists (filename);
938                         }
939
940                         if (exist) {
941                                 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
942                                         byte[] snkeypair = new byte [fs.Length];
943                                         fs.Read (snkeypair, 0, snkeypair.Length);
944
945                                         if (RootContext.StrongNameDelaySign) {
946                                                 // delayed signing - DO NOT include private key
947                                                 try {
948                                                         // check for possible ECMA key
949                                                         if (snkeypair.Length == 16) {
950                                                                 // will be rejected if not "the" ECMA key
951                                                                 an.KeyPair = new StrongNameKeyPair (snkeypair);
952                                                         }
953                                                         else {
954                                                                 // take it, with or without, a private key
955                                                                 RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair);
956                                                                 // and make sure we only feed the public part to Sys.Ref
957                                                                 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
958                                                                 an.KeyPair = new StrongNameKeyPair (publickey);
959                                                         }
960                                                 }
961                                                 catch (Exception) {
962                                                         Report.Error (1548, "Could not strongname the assembly. File `" +
963                                                                 RootContext.StrongNameKeyFile + "' incorrectly encoded.");
964                                                         Environment.Exit (1);
965                                                 }
966                                         }
967                                         else {
968                                                 // no delay so we make sure we have the private key
969                                                 try {
970                                                         CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
971                                                         an.KeyPair = new StrongNameKeyPair (snkeypair);
972                                                 }
973                                                 catch (CryptographicException) {
974                                                         if (snkeypair.Length == 16) {
975                                                                 // error # is different for ECMA key
976                                                                 Report.Error (1606, "Could not strongname the assembly. " + 
977                                                                         "ECMA key can only be used to delay-sign assemblies");
978                                                         }
979                                                         else {
980                                                                 Report.Error (1548, "Could not strongname the assembly. File `" +
981                                                                         RootContext.StrongNameKeyFile +
982                                                                         "' doesn't have a private key.");
983                                                         }
984                                                         Environment.Exit (1);
985                                                 }
986                                         }
987                                 }
988                         }
989                         else {
990                                 Report.Error (1548, "Could not strongname the assembly. File `" +
991                                         RootContext.StrongNameKeyFile + "' not found.");
992                                 Environment.Exit (1);
993                         }
994                         return an;
995                 }
996
997                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
998                 {
999                         Builder.SetCustomAttribute (customBuilder);
1000                 }
1001         }
1002
1003         public class ModuleClass: CommonAssemblyModulClass {
1004                 // TODO: make it private and move all builder based methods here
1005                 public ModuleBuilder Builder;
1006                 bool m_module_is_unsafe;
1007
1008                 public ModuleClass (bool is_unsafe)
1009                 {
1010                         m_module_is_unsafe = is_unsafe;
1011                 }
1012
1013                 public override AttributeTargets AttributeTargets {
1014                         get {
1015                                 return AttributeTargets.Module;
1016                         }
1017                 }
1018
1019                 public override bool IsClsCompliaceRequired(DeclSpace ds)
1020                 {
1021                         return CodeGen.Assembly.IsClsCompliant;
1022                         }
1023
1024                 public override void Emit (TypeContainer tc) 
1025                 {
1026                         base.Emit (tc);
1027
1028                         if (!m_module_is_unsafe)
1029                                 return;
1030
1031                         if (TypeManager.unverifiable_code_ctor == null) {
1032                                 Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute.");
1033                                 return;
1034                         }
1035                                 
1036                         ApplyAttributeBuilder (null, new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
1037                 }
1038                 
1039                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1040                 {
1041                         if (a != null && a.Type == TypeManager.cls_compliant_attribute_type) {
1042                                 Report.Warning_T (3012, a.Location);
1043                                 return;
1044                         }
1045
1046                         Builder.SetCustomAttribute (customBuilder);
1047                 }
1048         }
1049
1050 }