This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / mcs / 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                             } catch (Exception e) {
534                                         Console.WriteLine ("Exception caught by the compiler while compiling:");
535                                         Console.WriteLine ("   Block that caused the problem begin at: " + loc);
536                                         
537                                         if (CurrentBlock != null){
538                                                 Console.WriteLine ("                     Block being compiled: [{0},{1}]",
539                                                                    CurrentBlock.StartLocation, CurrentBlock.EndLocation);
540                                         }
541                                         Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
542                                         Console.WriteLine (Report.FriendlyStackTrace (e));
543                                         
544                                         Environment.Exit (1);
545                             }
546                         }
547
548                         if (ReturnType != null && !unreachable){
549                                 if (!InIterator){
550                                         Report.Error (161, loc, "Not all code paths return a value");
551                                         return;
552                                 }
553                         }
554
555                         if (HasReturnLabel)
556                                 ig.MarkLabel (ReturnLabel);
557                         if (return_value != null){
558                                 ig.Emit (OpCodes.Ldloc, return_value);
559                                 ig.Emit (OpCodes.Ret);
560                         } else {
561                                 //
562                                 // If `HasReturnLabel' is set, then we already emitted a
563                                 // jump to the end of the method, so we must emit a `ret'
564                                 // there.
565                                 //
566                                 // Unfortunately, System.Reflection.Emit automatically emits
567                                 // a leave to the end of a finally block.  This is a problem
568                                 // if no code is following the try/finally block since we may
569                                 // jump to a point after the end of the method.
570                                 // As a workaround, we're always creating a return label in
571                                 // this case.
572                                 //
573
574                                 if ((block != null) && block.IsDestructor) {
575                                         // Nothing to do; S.R.E automatically emits a leave.
576                                 } else if (HasReturnLabel || (!unreachable && !InIterator)) {
577                                         if (ReturnType != null)
578                                                 ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
579                                         ig.Emit (OpCodes.Ret);
580                                 }
581                         }
582                 }
583
584                 /// <summary>
585                 ///   This is called immediately before emitting an IL opcode to tell the symbol
586                 ///   writer to which source line this opcode belongs.
587                 /// </summary>
588                 public void Mark (Location loc, bool check_file)
589                 {
590                         if ((CodeGen.SymbolWriter == null) || Location.IsNull (loc))
591                                 return;
592
593                         if (check_file && (CurrentFile != loc.File))
594                                 return;
595
596                         ig.MarkSequencePoint (null, loc.Row, 0, 0, 0);
597                 }
598
599                 /// <summary>
600                 ///   Returns a temporary storage for a variable of type t as 
601                 ///   a local variable in the current body.
602                 /// </summary>
603                 public LocalBuilder GetTemporaryLocal (Type t)
604                 {
605                         LocalBuilder location = null;
606                         
607                         if (temporary_storage != null){
608                                 object o = temporary_storage [t];
609                                 if (o != null){
610                                         if (o is ArrayList){
611                                                 ArrayList al = (ArrayList) o;
612                                                 
613                                                 for (int i = 0; i < al.Count; i++){
614                                                         if (al [i] != null){
615                                                                 location = (LocalBuilder) al [i];
616                                                                 al [i] = null;
617                                                                 break;
618                                                         }
619                                                 }
620                                         } else
621                                                 location = (LocalBuilder) o;
622                                         if (location != null)
623                                                 return location;
624                                 }
625                         }
626                         
627                         return ig.DeclareLocal (t);
628                 }
629
630                 public void FreeTemporaryLocal (LocalBuilder b, Type t)
631                 {
632                         if (temporary_storage == null){
633                                 temporary_storage = new Hashtable ();
634                                 temporary_storage [t] = b;
635                                 return;
636                         }
637                         object o = temporary_storage [t];
638                         if (o == null){
639                                 temporary_storage [t] = b;
640                                 return;
641                         }
642                         if (o is ArrayList){
643                                 ArrayList al = (ArrayList) o;
644                                 for (int i = 0; i < al.Count; i++){
645                                         if (al [i] == null){
646                                                 al [i] = b;
647                                                 return;
648                                         }
649                                 }
650                                 al.Add (b);
651                                 return;
652                         }
653                         ArrayList replacement = new ArrayList ();
654                         replacement.Add (o);
655                         temporary_storage.Remove (t);
656                         temporary_storage [t] = replacement;
657                 }
658
659                 /// <summary>
660                 ///   Current loop begin and end labels.
661                 /// </summary>
662                 public Label LoopBegin, LoopEnd;
663
664                 /// <summary>
665                 ///   Default target in a switch statement.   Only valid if
666                 ///   InSwitch is true
667                 /// </summary>
668                 public Label DefaultTarget;
669
670                 /// <summary>
671                 ///   If this is non-null, points to the current switch statement
672                 /// </summary>
673                 public Switch Switch;
674
675                 /// <summary>
676                 ///   ReturnValue creates on demand the LocalBuilder for the
677                 ///   return value from the function.  By default this is not
678                 ///   used.  This is only required when returns are found inside
679                 ///   Try or Catch statements.
680                 /// </summary>
681                 public LocalBuilder TemporaryReturn ()
682                 {
683                         if (return_value == null){
684                                 return_value = ig.DeclareLocal (ReturnType);
685                                 ReturnLabel = ig.DefineLabel ();
686                                 HasReturnLabel = true;
687                         }
688
689                         return return_value;
690                 }
691
692                 public void NeedReturnLabel ()
693                 {
694                         if (!HasReturnLabel) {
695                                 ReturnLabel = ig.DefineLabel ();
696                                 HasReturnLabel = true;
697                         }
698                 }
699
700                 //
701                 // Creates a field `name' with the type `t' on the proxy class
702                 //
703                 public FieldBuilder MapVariable (string name, Type t)
704                 {
705                         if (InIterator){
706                                 return IteratorHandler.Current.MapVariable ("v_", name, t);
707                         }
708
709                         throw new Exception ("MapVariable for an unknown state");
710                 }
711
712                 //
713                 // Invoke this routine to remap a VariableInfo into the
714                 // proper MemberAccess expression
715                 //
716                 public Expression RemapLocal (LocalInfo local_info)
717                 {
718                         FieldExpr fe = new FieldExpr (local_info.FieldBuilder, loc);
719                         fe.InstanceExpression = new ProxyInstance ();
720                         return fe.DoResolve (this);
721                 }
722
723                 public Expression RemapLocalLValue (LocalInfo local_info, Expression right_side)
724                 {
725                         FieldExpr fe = new FieldExpr (local_info.FieldBuilder, loc);
726                         fe.InstanceExpression = new ProxyInstance ();
727                         return fe.DoResolveLValue (this, right_side);
728                 }
729
730                 public Expression RemapParameter (int idx)
731                 {
732                         FieldExpr fe = new FieldExprNoAddress (IteratorHandler.Current.parameter_fields [idx], loc);
733                         fe.InstanceExpression = new ProxyInstance ();
734                         return fe.DoResolve (this);
735                 }
736
737                 public Expression RemapParameterLValue (int idx, Expression right_side)
738                 {
739                         FieldExpr fe = new FieldExprNoAddress (IteratorHandler.Current.parameter_fields [idx], loc);
740                         fe.InstanceExpression = new ProxyInstance ();
741                         return fe.DoResolveLValue (this, right_side);
742                 }
743                 
744                 //
745                 // Emits the proper object to address fields on a remapped
746                 // variable/parameter to field in anonymous-method/iterator proxy classes.
747                 //
748                 public void EmitThis ()
749                 {
750                         if (InIterator){
751                                 ig.Emit (OpCodes.Ldarg_0);
752                                 if (!IsStatic){
753                                         FieldBuilder this_field = IteratorHandler.Current.this_field;
754                                         if (TypeManager.IsValueType (this_field.FieldType))
755                                                 ig.Emit (OpCodes.Ldflda, this_field);
756                                         else
757                                                 ig.Emit (OpCodes.Ldfld, this_field);
758                                 } 
759                         } else
760                                 ig.Emit (OpCodes.Ldarg_0);
761                 }
762
763                 public Expression GetThis (Location loc)
764                 {
765                         This my_this;
766                         if (CurrentBlock != null)
767                                 my_this = new This (CurrentBlock, loc);
768                         else
769                                 my_this = new This (loc);
770
771                         if (!my_this.ResolveBase (this))
772                                 my_this = null;
773
774                         return my_this;
775                 }
776         }
777
778
779         public abstract class CommonAssemblyModulClass: Attributable {
780                 static string[] attribute_targets = new string [] { "assembly", "module" };
781
782                 protected CommonAssemblyModulClass ():
783                         base (null)
784                 {
785                 }
786
787                 public void AddAttributes (ArrayList attrs)
788                 {
789                         if (OptAttributes == null) {
790                                 OptAttributes = new Attributes (attrs);
791                                 return;
792                         }
793                         OptAttributes.AddAttributes (attrs);
794                         OptAttributes.CheckTargets (ValidAttributeTargets);
795                 }
796
797                 public virtual void Emit (TypeContainer tc) 
798                 {
799                         if (OptAttributes == null)
800                                 return;
801
802                         EmitContext ec = new EmitContext (tc, Mono.CSharp.Location.Null, null, null, 0, false);
803                         OptAttributes.Emit (ec, this);
804                 }
805                 
806                 protected Attribute GetClsCompliantAttribute ()
807                 {
808                         if (OptAttributes == null)
809                                 return null;
810
811                         EmitContext temp_ec = new EmitContext (new TypeContainer (), Mono.CSharp.Location.Null, null, null, 0, false);
812                         Attribute a = OptAttributes.Search (TypeManager.cls_compliant_attribute_type, temp_ec);
813                         if (a != null) {
814                                 a.Resolve (temp_ec);
815                         }
816                         return a;
817                 }
818
819                 protected override string[] ValidAttributeTargets {
820                         get {
821                                 return attribute_targets;
822                         }
823                 }
824
825         }
826                 
827         public class AssemblyClass: CommonAssemblyModulClass {
828                 // TODO: make it private and move all builder based methods here
829                 public AssemblyBuilder Builder;
830                 bool is_cls_compliant;
831
832                 public AssemblyClass (): base ()
833                 {
834                         is_cls_compliant = false;
835                 }
836
837                 public bool IsClsCompliant {
838                         get {
839                                 return is_cls_compliant;
840                         }
841                 }
842
843                 public override AttributeTargets AttributeTargets {
844                         get {
845                                 return AttributeTargets.Assembly;
846                         }
847                 }
848
849                 public override bool IsClsCompliaceRequired(DeclSpace ds)
850                 {
851                         return is_cls_compliant;
852                 }
853
854                 public void ResolveClsCompliance ()
855                 {
856                         Attribute a = GetClsCompliantAttribute ();
857                         if (a == null)
858                                 return;
859
860                         is_cls_compliant = a.GetClsCompliantAttributeValue (null);
861                 }
862
863                 public AssemblyName GetAssemblyName (string name, string output) 
864                 {
865                         if (OptAttributes != null) {
866                                 foreach (Attribute a in OptAttributes.Attrs) {
867                                         if (a.Target != "assembly")
868                                                 continue;
869                                         // TODO: This code is buggy: comparing Attribute name without resolving it is wrong.
870                                         //       However, this is invoked by CodeGen.Init, at which time none of the namespaces
871                                         //       are loaded yet.
872                                         switch (a.Name) {
873                                                 case "AssemblyKeyFile":
874                                                 case "AssemblyKeyFileAttribute":
875                                                 case "System.Reflection.AssemblyKeyFileAttribute":
876                                                         if (RootContext.StrongNameKeyFile != null) {
877                                                                 Report.Warning (1616, "Compiler option -keyfile overrides " +
878                                                                         "AssemblyKeyFileAttribute");
879                                                         }
880                                                         else {
881                                                                 string value = a.GetString ();
882                                                                 if (value != String.Empty)
883                                                                         RootContext.StrongNameKeyFile = value;
884                                                         }
885                                                         break;
886                                                 case "AssemblyKeyName":
887                                                 case "AssemblyKeyNameAttribute":
888                                                 case "System.Reflection.AssemblyKeyNameAttribute":
889                                                         if (RootContext.StrongNameKeyContainer != null) {
890                                                                 Report.Warning (1616, "Compiler option -keycontainer overrides " +
891                                                                         "AssemblyKeyNameAttribute");
892                                                         }
893                                                         else {
894                                                                 string value = a.GetString ();
895                                                                 if (value != String.Empty)
896                                                                         RootContext.StrongNameKeyContainer = value;
897                                                         }
898                                                         break;
899                                                 case "AssemblyDelaySign":
900                                                 case "AssemblyDelaySignAttribute":
901                                                 case "System.Reflection.AssemblyDelaySignAttribute":
902                                                         RootContext.StrongNameDelaySign = a.GetBoolean ();
903                                                         break;
904                                         }
905                                 }
906                         }
907
908                         AssemblyName an = new AssemblyName ();
909                         an.Name = Path.GetFileNameWithoutExtension (name);
910
911                         // note: delay doesn't apply when using a key container
912                         if (RootContext.StrongNameKeyContainer != null) {
913                                 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
914                                 return an;
915                         }
916
917                         // strongname is optional
918                         if (RootContext.StrongNameKeyFile == null)
919                                 return an;
920
921                         string AssemblyDir = Path.GetDirectoryName (output);
922
923                         // the StrongName key file may be relative to (a) the compiled
924                         // file or (b) to the output assembly. See bugzilla #55320
925                         // http://bugzilla.ximian.com/show_bug.cgi?id=55320
926
927                         // (a) relative to the compiled file
928                         string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
929                         bool exist = File.Exists (filename);
930                         if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
931                                 // (b) relative to the outputed assembly
932                                 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
933                                 exist = File.Exists (filename);
934                         }
935
936                         if (exist) {
937                                 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
938                                         byte[] snkeypair = new byte [fs.Length];
939                                         fs.Read (snkeypair, 0, snkeypair.Length);
940
941                                         if (RootContext.StrongNameDelaySign) {
942                                                 // delayed signing - DO NOT include private key
943                                                 try {
944                                                         // check for possible ECMA key
945                                                         if (snkeypair.Length == 16) {
946                                                                 // will be rejected if not "the" ECMA key
947                                                                 an.KeyPair = new StrongNameKeyPair (snkeypair);
948                                                         }
949                                                         else {
950                                                                 // take it, with or without, a private key
951                                                                 RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair);
952                                                                 // and make sure we only feed the public part to Sys.Ref
953                                                                 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
954                                                                 an.KeyPair = new StrongNameKeyPair (publickey);
955                                                         }
956                                                 }
957                                                 catch (Exception) {
958                                                         Report.Error (1548, "Could not strongname the assembly. File `" +
959                                                                 RootContext.StrongNameKeyFile + "' incorrectly encoded.");
960                                                         Environment.Exit (1);
961                                                 }
962                                         }
963                                         else {
964                                                 // no delay so we make sure we have the private key
965                                                 try {
966                                                         CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
967                                                         an.KeyPair = new StrongNameKeyPair (snkeypair);
968                                                 }
969                                                 catch (CryptographicException) {
970                                                         if (snkeypair.Length == 16) {
971                                                                 // error # is different for ECMA key
972                                                                 Report.Error (1606, "Could not strongname the assembly. " + 
973                                                                         "ECMA key can only be used to delay-sign assemblies");
974                                                         }
975                                                         else {
976                                                                 Report.Error (1548, "Could not strongname the assembly. File `" +
977                                                                         RootContext.StrongNameKeyFile +
978                                                                         "' doesn't have a private key.");
979                                                         }
980                                                         Environment.Exit (1);
981                                                 }
982                                         }
983                                 }
984                         }
985                         else {
986                                 Report.Error (1548, "Could not strongname the assembly. File `" +
987                                         RootContext.StrongNameKeyFile + "' not found.");
988                                 Environment.Exit (1);
989                         }
990                         return an;
991                 }
992
993                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
994                 {
995                         Builder.SetCustomAttribute (customBuilder);
996                 }
997         }
998
999         public class ModuleClass: CommonAssemblyModulClass {
1000                 // TODO: make it private and move all builder based methods here
1001                 public ModuleBuilder Builder;
1002                 bool m_module_is_unsafe;
1003
1004                 public ModuleClass (bool is_unsafe)
1005                 {
1006                         m_module_is_unsafe = is_unsafe;
1007                 }
1008
1009                 public override AttributeTargets AttributeTargets {
1010                         get {
1011                                 return AttributeTargets.Module;
1012                         }
1013                 }
1014
1015                 public override bool IsClsCompliaceRequired(DeclSpace ds)
1016                 {
1017                         return CodeGen.Assembly.IsClsCompliant;
1018                 }
1019
1020                 public override void Emit (TypeContainer tc) 
1021                 {
1022                         base.Emit (tc);
1023
1024                         if (!m_module_is_unsafe)
1025                                 return;
1026
1027                         if (TypeManager.unverifiable_code_ctor == null) {
1028                                 Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute.");
1029                                 return;
1030                         }
1031                                 
1032                         ApplyAttributeBuilder (null, new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
1033                 }
1034                 
1035                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1036                 {
1037                         if (a != null && a.Type == TypeManager.cls_compliant_attribute_type) {
1038                                 Report.Warning_T (3012, a.Location);
1039                                 return;
1040                         }
1041
1042                         Builder.SetCustomAttribute (customBuilder);
1043                 }
1044         }
1045 }