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