Normalize line endings.
[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 // Copyright 2001, 2002, 2003 Ximian, Inc.
8 // Copyright 2004 Novell, Inc.
9 //
10
11 //
12 // Please leave this defined on SVN: The idea is that when we ship the
13 // compiler to end users, if the compiler crashes, they have a chance
14 // to narrow down the problem.   
15 //
16 // Only remove it if you need to debug locally on your tree.
17 //
18 //#define PRODUCTION
19
20 using System;
21 using System.IO;
22 using System.Collections.Generic;
23 using System.Globalization;
24 using System.Reflection;
25 using System.Reflection.Emit;
26 using System.Runtime.InteropServices;
27 using System.Security;
28 using System.Security.Cryptography;
29 using System.Security.Permissions;
30
31 using Mono.Security.Cryptography;
32
33 namespace Mono.CSharp {
34
35         /// <summary>
36         ///    Code generator class.
37         /// </summary>
38         public class CodeGen {
39                 static AppDomain current_domain;
40
41                 public static AssemblyClass Assembly;
42
43                 static CodeGen ()
44                 {
45                         Reset ();
46                 }
47
48                 public static void Reset ()
49                 {
50                         Assembly = new AssemblyClass ();
51                 }
52
53                 public static string Basename (string name)
54                 {
55                         int pos = name.LastIndexOf ('/');
56
57                         if (pos != -1)
58                                 return name.Substring (pos + 1);
59
60                         pos = name.LastIndexOf ('\\');
61                         if (pos != -1)
62                                 return name.Substring (pos + 1);
63
64                         return name;
65                 }
66
67                 public static string Dirname (string name)
68                 {
69                         int pos = name.LastIndexOf ('/');
70
71                         if (pos != -1)
72                                 return name.Substring (0, pos);
73
74                         pos = name.LastIndexOf ('\\');
75                         if (pos != -1)
76                                 return name.Substring (0, pos);
77
78                         return ".";
79                 }
80
81                 static public string FileName;
82                                 
83                 //
84                 // Initializes the code generator variables for interactive use (repl)
85                 //
86                 static public void InitDynamic (CompilerContext ctx, string name)
87                 {
88                         current_domain = AppDomain.CurrentDomain;
89                         AssemblyName an = Assembly.GetAssemblyName (name, name);
90                         
91                         Assembly.Builder = current_domain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
92                         RootContext.ToplevelTypes = new ModuleCompiled (ctx, true);
93                         RootContext.ToplevelTypes.Builder = Assembly.Builder.DefineDynamicModule (Basename (name), false);
94                         Assembly.Name = Assembly.Builder.GetName ();
95                 }
96
97                 //
98                 // Initializes the code generator variables
99                 //
100                 static public bool Init (string name, string output, bool want_debugging_support, CompilerContext ctx)
101                 {
102                         FileName = output;
103                         AssemblyName an = Assembly.GetAssemblyName (name, output);
104                         if (an == null)
105                                 return false;
106
107                         if (an.KeyPair != null) {
108                                 // If we are going to strong name our assembly make
109                                 // sure all its refs are strong named
110                                 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
111                                         AssemblyName ref_name = a.GetName ();
112                                         byte [] b = ref_name.GetPublicKeyToken ();
113                                         if (b == null || b.Length == 0) {
114                                                 ctx.Report.Error (1577, "Assembly generation failed " +
115                                                                 "-- Referenced assembly '" +
116                                                                 ref_name.Name +
117                                                                 "' does not have a strong name.");
118                                                 //Environment.Exit (1);
119                                         }
120                                 }
121                         }
122                         
123                         current_domain = AppDomain.CurrentDomain;
124
125                         try {
126                                 Assembly.Builder = current_domain.DefineDynamicAssembly (an,
127                                         AssemblyBuilderAccess.RunAndSave, Dirname (name));
128                         }
129                         catch (ArgumentException) {
130                                 // specified key may not be exportable outside it's container
131                                 if (RootContext.StrongNameKeyContainer != null) {
132                                         ctx.Report.Error (1548, "Could not access the key inside the container `" +
133                                                 RootContext.StrongNameKeyContainer + "'.");
134                                         Environment.Exit (1);
135                                 }
136                                 throw;
137                         }
138                         catch (CryptographicException) {
139                                 if ((RootContext.StrongNameKeyContainer != null) || (RootContext.StrongNameKeyFile != null)) {
140                                         ctx.Report.Error (1548, "Could not use the specified key to strongname the assembly.");
141                                         Environment.Exit (1);
142                                 }
143                                 return false;
144                         }
145
146                         // Get the complete AssemblyName from the builder
147                         // (We need to get the public key and token)
148                         Assembly.Name = Assembly.Builder.GetName ();
149
150                         //
151                         // Pass a path-less name to DefineDynamicModule.  Wonder how
152                         // this copes with output in different directories then.
153                         // FIXME: figure out how this copes with --output /tmp/blah
154                         //
155                         // If the third argument is true, the ModuleBuilder will dynamically
156                         // load the default symbol writer.
157                         //
158                         try {
159                                 RootContext.ToplevelTypes.Builder = Assembly.Builder.DefineDynamicModule (
160                                         Basename (name), Basename (output), want_debugging_support);
161
162 #if !MS_COMPATIBLE
163                                 // TODO: We should use SymbolWriter from DefineDynamicModule
164                                 if (want_debugging_support && !SymbolWriter.Initialize (RootContext.ToplevelTypes.Builder, output)) {
165                                         ctx.Report.Error (40, "Unexpected debug information initialization error `{0}'",
166                                                 "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll)");
167                                         return false;
168                                 }
169 #endif
170                         } catch (ExecutionEngineException e) {
171                                 ctx.Report.Error (40, "Unexpected debug information initialization error `{0}'",
172                                         e.Message);
173                                 return false;
174                         }
175
176                         return true;
177                 }
178
179                 static public void Save (string name, bool saveDebugInfo, Report Report)
180                 {
181                         PortableExecutableKinds pekind;
182                         ImageFileMachine machine;
183
184                         switch (RootContext.Platform) {
185                         case Platform.X86:
186                                 pekind = PortableExecutableKinds.Required32Bit;
187                                 machine = ImageFileMachine.I386;
188                                 break;
189                         case Platform.X64:
190                                 pekind = PortableExecutableKinds.PE32Plus;
191                                 machine = ImageFileMachine.AMD64;
192                                 break;
193                         case Platform.IA64:
194                                 pekind = PortableExecutableKinds.PE32Plus;
195                                 machine = ImageFileMachine.IA64;
196                                 break;
197                         case Platform.AnyCPU:
198                         default:
199                                 pekind = PortableExecutableKinds.ILOnly;
200                                 machine = ImageFileMachine.I386;
201                                 break;
202                         }
203                         try {
204                                 Assembly.Builder.Save (Basename (name), pekind, machine);
205                         }
206                         catch (COMException) {
207                                 if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
208                                         throw;
209
210                                 // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies 
211                                 Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
212                                         RootContext.StrongNameKeyFile +
213                                         "', Use MCS with the Mono runtime or CSC to compile this assembly.");
214                         }
215                         catch (System.IO.IOException io) {
216                                 Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
217                                 return;
218                         }
219                         catch (System.UnauthorizedAccessException ua) {
220                                 Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message);
221                                 return;
222                         }
223                         catch (System.NotImplementedException nie) {
224                                 Report.RuntimeMissingSupport (Location.Null, nie.Message);
225                                 return;
226                         }
227
228                         //
229                         // Write debuger symbol file
230                         //
231                         if (saveDebugInfo)
232                                 SymbolWriter.WriteSymbolFile ();
233                         }
234         }
235
236         /// <summary>
237         ///   An Emit Context is created for each body of code (from methods,
238         ///   properties bodies, indexer bodies or constructor bodies)
239         /// </summary>
240         public class EmitContext : BuilderContext
241         {
242                 // TODO: Has to be private
243                 public ILGenerator ig;
244
245                 /// <summary>
246                 ///   The value that is allowed to be returned or NULL if there is no
247                 ///   return type.
248                 /// </summary>
249                 TypeSpec return_type;
250
251                 /// <summary>
252                 ///   Keeps track of the Type to LocalBuilder temporary storage created
253                 ///   to store structures (used to compute the address of the structure
254                 ///   value on structure method invocations)
255                 /// </summary>
256                 Dictionary<TypeSpec, object> temporary_storage;
257
258                 /// <summary>
259                 ///   The location where we store the return value.
260                 /// </summary>
261                 public LocalBuilder return_value;
262
263                 /// <summary>
264                 ///   The location where return has to jump to return the
265                 ///   value
266                 /// </summary>
267                 public Label ReturnLabel;
268
269                 /// <summary>
270                 ///   If we already defined the ReturnLabel
271                 /// </summary>
272                 public bool HasReturnLabel;
273
274                 /// <summary>
275                 ///   Current loop begin and end labels.
276                 /// </summary>
277                 public Label LoopBegin, LoopEnd;
278
279                 /// <summary>
280                 ///   Default target in a switch statement.   Only valid if
281                 ///   InSwitch is true
282                 /// </summary>
283                 public Label DefaultTarget;
284
285                 /// <summary>
286                 ///   If this is non-null, points to the current switch statement
287                 /// </summary>
288                 public Switch Switch;
289
290                 /// <summary>
291                 ///  Whether we are inside an anonymous method.
292                 /// </summary>
293                 public AnonymousExpression CurrentAnonymousMethod;
294                 
295                 public readonly IMemberContext MemberContext;
296
297                 public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type)
298                 {
299                         this.MemberContext = rc;
300                         this.ig = ig;
301
302                         this.return_type = return_type;
303                 }
304
305 #region Properties
306
307                 public TypeSpec CurrentType {
308                         get { return MemberContext.CurrentType; }
309                 }
310
311                 public TypeParameter[] CurrentTypeParameters {
312                         get { return MemberContext.CurrentTypeParameters; }
313                 }
314
315                 public MemberCore CurrentTypeDefinition {
316                         get { return MemberContext.CurrentMemberDefinition; }
317                 }
318
319                 public bool IsStatic {
320                         get { return MemberContext.IsStatic; }
321                 }
322
323                 bool IsAnonymousStoreyMutateRequired {
324                         get {
325                                 return CurrentAnonymousMethod != null &&
326                                         CurrentAnonymousMethod.Storey != null &&
327                                         CurrentAnonymousMethod.Storey.Mutator != null;
328                         }
329                 }
330
331                 // Has to be used for emitter errors only
332                 public Report Report {
333                         get { return MemberContext.Compiler.Report; }
334                 }
335
336                 public TypeSpec ReturnType {
337                         get {
338                                 return return_type;
339                         }
340                 }
341 #endregion
342
343                 /// <summary>
344                 ///   This is called immediately before emitting an IL opcode to tell the symbol
345                 ///   writer to which source line this opcode belongs.
346                 /// </summary>
347                 public void Mark (Location loc)
348                 {
349                         if (!SymbolWriter.HasSymbolWriter || HasSet (Options.OmitDebugInfo) || loc.IsNull)
350                                 return;
351
352                         SymbolWriter.MarkSequencePoint (ig, loc);
353                 }
354
355                 public void DefineLocalVariable (string name, LocalBuilder builder)
356                 {
357                         SymbolWriter.DefineLocalVariable (name, builder);
358                 }
359
360                 public void BeginCatchBlock (TypeSpec type)
361                 {
362                         ig.BeginCatchBlock (type.GetMetaInfo ());
363                 }
364
365                 public void BeginExceptionBlock ()
366                 {
367                         ig.BeginExceptionBlock ();
368                 }
369
370                 public void BeginFinallyBlock ()
371                 {
372                         ig.BeginFinallyBlock ();
373                 }
374
375                 public void BeginScope ()
376                 {
377                         ig.BeginScope();
378                         SymbolWriter.OpenScope(ig);
379                 }
380
381                 public void EndExceptionBlock ()
382                 {
383                         ig.EndExceptionBlock ();
384                 }
385
386                 public void EndScope ()
387                 {
388                         ig.EndScope();
389                         SymbolWriter.CloseScope(ig);
390                 }
391
392                 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
393                 {
394                         if (IsAnonymousStoreyMutateRequired)
395                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
396
397                         return ig.DeclareLocal (type.GetMetaInfo (), pinned);
398                 }
399
400                 public Label DefineLabel ()
401                 {
402                         return ig.DefineLabel ();
403                 }
404
405                 public void MarkLabel (Label label)
406                 {
407                         ig.MarkLabel (label);
408                 }
409
410                 public void Emit (OpCode opcode)
411                 {
412                         ig.Emit (opcode);
413                 }
414
415                 public void Emit (OpCode opcode, LocalBuilder local)
416                 {
417                         ig.Emit (opcode, local);
418                 }
419
420                 public void Emit (OpCode opcode, string arg)
421                 {
422                         ig.Emit (opcode, arg);
423                 }
424
425                 public void Emit (OpCode opcode, double arg)
426                 {
427                         ig.Emit (opcode, arg);
428                 }
429
430                 public void Emit (OpCode opcode, float arg)
431                 {
432                         ig.Emit (opcode, arg);
433                 }
434
435                 public void Emit (OpCode opcode, int arg)
436                 {
437                         ig.Emit (opcode, arg);
438                 }
439
440                 public void Emit (OpCode opcode, byte arg)
441                 {
442                         ig.Emit (opcode, arg);
443                 }
444
445                 public void Emit (OpCode opcode, Label label)
446                 {
447                         ig.Emit (opcode, label);
448                 }
449
450                 public void Emit (OpCode opcode, Label[] labels)
451                 {
452                         ig.Emit (opcode, labels);
453                 }
454
455                 public void Emit (OpCode opcode, TypeSpec type)
456                 {
457                         if (IsAnonymousStoreyMutateRequired)
458                                 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
459
460                         ig.Emit (opcode, type.GetMetaInfo ());
461                 }
462
463                 public void Emit (OpCode opcode, FieldSpec field)
464                 {
465                         if (IsAnonymousStoreyMutateRequired)
466                                 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
467
468                         ig.Emit (opcode, field.GetMetaInfo ());
469                 }
470
471                 public void Emit (OpCode opcode, MethodSpec method)
472                 {
473                         if (IsAnonymousStoreyMutateRequired)
474                                 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
475
476                         if (method.IsConstructor)
477                                 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
478                         else
479                                 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
480                 }
481
482                 // TODO: REMOVE breaks mutator
483                 public void Emit (OpCode opcode, MethodInfo method)
484                 {
485                         ig.Emit (opcode, method);
486                 }
487
488                 // TODO: REMOVE breaks mutator
489                 public void Emit (OpCode opcode, FieldBuilder field)
490                 {
491                         ig.Emit (opcode, field);
492                 }
493
494                 public void Emit (OpCode opcode, MethodSpec method, Type[] vargs)
495                 {
496                         // TODO MemberCache: This should mutate too
497                         ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
498                 }
499
500                 public void EmitArrayNew (ArrayContainer ac)
501                 {
502                         if (ac.Rank == 1) {
503                                 Emit (OpCodes.Newarr, ac.Element);
504                         } else {
505                                 if (IsAnonymousStoreyMutateRequired)
506                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
507
508                                 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
509                         }
510                 }
511
512                 public void EmitArrayAddress (ArrayContainer ac)
513                 {
514                         if (ac.Element.IsGenericParameter)
515                                 ig.Emit (OpCodes.Readonly);
516
517                         if (ac.Rank > 1) {
518                                 if (IsAnonymousStoreyMutateRequired)
519                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
520
521                                 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
522                         } else {
523                                 Emit (OpCodes.Ldelema, ac.Element);
524                         }
525                 }
526
527                 //
528                 // Emits the right opcode to load from an array
529                 //
530                 public void EmitArrayLoad (ArrayContainer ac)
531                 {
532                         if (ac.Rank > 1) {
533                                 if (IsAnonymousStoreyMutateRequired)
534                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
535
536                                 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
537                                 return;
538                         }
539
540                         var type = ac.Element;
541                         if (TypeManager.IsEnumType (type))
542                                 type = EnumSpec.GetUnderlyingType (type);
543
544                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
545                                 Emit (OpCodes.Ldelem_U1);
546                         else if (type == TypeManager.sbyte_type)
547                                 Emit (OpCodes.Ldelem_I1);
548                         else if (type == TypeManager.short_type)
549                                 Emit (OpCodes.Ldelem_I2);
550                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
551                                 Emit (OpCodes.Ldelem_U2);
552                         else if (type == TypeManager.int32_type)
553                                 Emit (OpCodes.Ldelem_I4);
554                         else if (type == TypeManager.uint32_type)
555                                 Emit (OpCodes.Ldelem_U4);
556                         else if (type == TypeManager.uint64_type)
557                                 Emit (OpCodes.Ldelem_I8);
558                         else if (type == TypeManager.int64_type)
559                                 Emit (OpCodes.Ldelem_I8);
560                         else if (type == TypeManager.float_type)
561                                 Emit (OpCodes.Ldelem_R4);
562                         else if (type == TypeManager.double_type)
563                                 Emit (OpCodes.Ldelem_R8);
564                         else if (type == TypeManager.intptr_type)
565                                 Emit (OpCodes.Ldelem_I);
566                         else if (TypeManager.IsStruct (type)) {
567                                 Emit (OpCodes.Ldelema, type);
568                                 Emit (OpCodes.Ldobj, type);
569                         } else if (type.IsGenericParameter) {
570                                 Emit (OpCodes.Ldelem, type);
571                         } else if (type.IsPointer)
572                                 Emit (OpCodes.Ldelem_I);
573                         else
574                                 Emit (OpCodes.Ldelem_Ref);
575                 }
576
577                 //
578                 // Emits the right opcode to store to an array
579                 //
580                 public void EmitArrayStore (ArrayContainer ac)
581                 {
582                         if (ac.Rank > 1) {
583                                 if (IsAnonymousStoreyMutateRequired)
584                                         ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
585
586                                 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
587                                 return;
588                         }
589
590                         var type = ac.Element;
591
592                         if (type.IsEnum)
593                                 type = EnumSpec.GetUnderlyingType (type);
594
595                         if (type == TypeManager.byte_type || type == TypeManager.sbyte_type || type == TypeManager.bool_type)
596                                 Emit (OpCodes.Stelem_I1);
597                         else if (type == TypeManager.short_type || type == TypeManager.ushort_type || type == TypeManager.char_type)
598                                 Emit (OpCodes.Stelem_I2);
599                         else if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
600                                 Emit (OpCodes.Stelem_I4);
601                         else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
602                                 Emit (OpCodes.Stelem_I8);
603                         else if (type == TypeManager.float_type)
604                                 Emit (OpCodes.Stelem_R4);
605                         else if (type == TypeManager.double_type)
606                                 Emit (OpCodes.Stelem_R8);
607                         else if (type == TypeManager.intptr_type)
608                                 Emit (OpCodes.Stobj, type);
609                         else if (TypeManager.IsStruct (type))
610                                 Emit (OpCodes.Stobj, type);
611                         else if (type.IsGenericParameter)
612                                 Emit (OpCodes.Stelem, type);
613                         else if (type.IsPointer)
614                                 Emit (OpCodes.Stelem_I);
615                         else
616                                 Emit (OpCodes.Stelem_Ref);
617                 }
618
619                 public void EmitInt (int i)
620                 {
621                         switch (i) {
622                         case -1:
623                                 ig.Emit (OpCodes.Ldc_I4_M1);
624                                 break;
625
626                         case 0:
627                                 ig.Emit (OpCodes.Ldc_I4_0);
628                                 break;
629
630                         case 1:
631                                 ig.Emit (OpCodes.Ldc_I4_1);
632                                 break;
633
634                         case 2:
635                                 ig.Emit (OpCodes.Ldc_I4_2);
636                                 break;
637
638                         case 3:
639                                 ig.Emit (OpCodes.Ldc_I4_3);
640                                 break;
641
642                         case 4:
643                                 ig.Emit (OpCodes.Ldc_I4_4);
644                                 break;
645
646                         case 5:
647                                 ig.Emit (OpCodes.Ldc_I4_5);
648                                 break;
649
650                         case 6:
651                                 ig.Emit (OpCodes.Ldc_I4_6);
652                                 break;
653
654                         case 7:
655                                 ig.Emit (OpCodes.Ldc_I4_7);
656                                 break;
657
658                         case 8:
659                                 ig.Emit (OpCodes.Ldc_I4_8);
660                                 break;
661
662                         default:
663                                 if (i >= -128 && i <= 127) {
664                                         ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
665                                 } else
666                                         ig.Emit (OpCodes.Ldc_I4, i);
667                                 break;
668                         }
669                 }
670
671                 public void EmitLong (long l)
672                 {
673                         if (l >= int.MinValue && l <= int.MaxValue) {
674                                 EmitInt (unchecked ((int) l));
675                                 ig.Emit (OpCodes.Conv_I8);
676                                 return;
677                         }
678
679                         if (l >= 0 && l <= uint.MaxValue) {
680                                 EmitInt (unchecked ((int) l));
681                                 ig.Emit (OpCodes.Conv_U8);
682                                 return;
683                         }
684
685                         ig.Emit (OpCodes.Ldc_I8, l);
686                 }
687
688                 //
689                 // Load the object from the pointer.  
690                 //
691                 public void EmitLoadFromPtr (TypeSpec t)
692                 {
693                         if (t == TypeManager.int32_type)
694                                 ig.Emit (OpCodes.Ldind_I4);
695                         else if (t == TypeManager.uint32_type)
696                                 ig.Emit (OpCodes.Ldind_U4);
697                         else if (t == TypeManager.short_type)
698                                 ig.Emit (OpCodes.Ldind_I2);
699                         else if (t == TypeManager.ushort_type)
700                                 ig.Emit (OpCodes.Ldind_U2);
701                         else if (t == TypeManager.char_type)
702                                 ig.Emit (OpCodes.Ldind_U2);
703                         else if (t == TypeManager.byte_type)
704                                 ig.Emit (OpCodes.Ldind_U1);
705                         else if (t == TypeManager.sbyte_type)
706                                 ig.Emit (OpCodes.Ldind_I1);
707                         else if (t == TypeManager.uint64_type)
708                                 ig.Emit (OpCodes.Ldind_I8);
709                         else if (t == TypeManager.int64_type)
710                                 ig.Emit (OpCodes.Ldind_I8);
711                         else if (t == TypeManager.float_type)
712                                 ig.Emit (OpCodes.Ldind_R4);
713                         else if (t == TypeManager.double_type)
714                                 ig.Emit (OpCodes.Ldind_R8);
715                         else if (t == TypeManager.bool_type)
716                                 ig.Emit (OpCodes.Ldind_I1);
717                         else if (t == TypeManager.intptr_type)
718                                 ig.Emit (OpCodes.Ldind_I);
719                         else if (t.IsEnum) {
720                                 if (t == TypeManager.enum_type)
721                                         ig.Emit (OpCodes.Ldind_Ref);
722                                 else
723                                         EmitLoadFromPtr (EnumSpec.GetUnderlyingType (t));
724                         } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
725                                 Emit (OpCodes.Ldobj, t);
726                         else if (t.IsPointer)
727                                 ig.Emit (OpCodes.Ldind_I);
728                         else
729                                 ig.Emit (OpCodes.Ldind_Ref);
730                 }
731
732                 //
733                 // The stack contains the pointer and the value of type `type'
734                 //
735                 public void EmitStoreFromPtr (TypeSpec type)
736                 {
737                         if (type.IsEnum)
738                                 type = EnumSpec.GetUnderlyingType (type);
739
740                         if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
741                                 ig.Emit (OpCodes.Stind_I4);
742                         else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
743                                 ig.Emit (OpCodes.Stind_I8);
744                         else if (type == TypeManager.char_type || type == TypeManager.short_type ||
745                                  type == TypeManager.ushort_type)
746                                 ig.Emit (OpCodes.Stind_I2);
747                         else if (type == TypeManager.float_type)
748                                 ig.Emit (OpCodes.Stind_R4);
749                         else if (type == TypeManager.double_type)
750                                 ig.Emit (OpCodes.Stind_R8);
751                         else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
752                                  type == TypeManager.bool_type)
753                                 ig.Emit (OpCodes.Stind_I1);
754                         else if (type == TypeManager.intptr_type)
755                                 ig.Emit (OpCodes.Stind_I);
756                         else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
757                                 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
758                         else
759                                 ig.Emit (OpCodes.Stind_Ref);
760                 }
761
762                 /// <summary>
763                 ///   Returns a temporary storage for a variable of type t as 
764                 ///   a local variable in the current body.
765                 /// </summary>
766                 public LocalBuilder GetTemporaryLocal (TypeSpec t)
767                 {
768                         if (temporary_storage != null) {
769                                 object o;
770                                 if (temporary_storage.TryGetValue (t, out o)) {
771                                         if (o is Stack<LocalBuilder>) {
772                                                 var s = (Stack<LocalBuilder>) o;
773                                                 o = s.Count == 0 ? null : s.Pop ();
774                                         } else {
775                                                 temporary_storage.Remove (t);
776                                         }
777                                 }
778                                 if (o != null)
779                                         return (LocalBuilder) o;
780                         }
781                         return DeclareLocal (t, false);
782                 }
783
784                 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
785                 {
786                         if (temporary_storage == null) {
787                                 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
788                                 temporary_storage.Add (t, b);
789                                 return;
790                         }
791                         object o;
792                         
793                         if (!temporary_storage.TryGetValue (t, out o)) {
794                                 temporary_storage.Add (t, b);
795                                 return;
796                         }
797                         var s = o as Stack<LocalBuilder>;
798                         if (s == null) {
799                                 s = new Stack<LocalBuilder> ();
800                                 s.Push ((LocalBuilder)o);
801                                 temporary_storage [t] = s;
802                         }
803                         s.Push (b);
804                 }
805
806                 /// <summary>
807                 ///   ReturnValue creates on demand the LocalBuilder for the
808                 ///   return value from the function.  By default this is not
809                 ///   used.  This is only required when returns are found inside
810                 ///   Try or Catch statements.
811                 ///
812                 ///   This method is typically invoked from the Emit phase, so
813                 ///   we allow the creation of a return label if it was not
814                 ///   requested during the resolution phase.   Could be cleaned
815                 ///   up, but it would replicate a lot of logic in the Emit phase
816                 ///   of the code that uses it.
817                 /// </summary>
818                 public LocalBuilder TemporaryReturn ()
819                 {
820                         if (return_value == null){
821                                 return_value = DeclareLocal (return_type, false);
822                                 if (!HasReturnLabel){
823                                         ReturnLabel = DefineLabel ();
824                                         HasReturnLabel = true;
825                                 }
826                         }
827
828                         return return_value;
829                 }
830         }
831
832         public abstract class CommonAssemblyModulClass : Attributable, IMemberContext
833         {
834                 public void AddAttributes (List<Attribute> attrs, IMemberContext context)
835                 {
836                         foreach (Attribute a in attrs)
837                                 a.AttachTo (this, context);
838
839                         if (attributes == null) {
840                                 attributes = new Attributes (attrs);
841                                 return;
842                         }
843                         attributes.AddAttributes (attrs);
844                 }
845
846                 public virtual void Emit (TypeContainer tc) 
847                 {
848                         if (OptAttributes == null)
849                                 return;
850
851                         OptAttributes.Emit ();
852                 }
853
854                 protected Attribute ResolveAttribute (PredefinedAttribute a_type)
855                 {
856                         Attribute a = OptAttributes.Search (a_type);
857                         if (a != null) {
858                                 a.Resolve ();
859                         }
860                         return a;
861                 }
862
863                 #region IMemberContext Members
864
865                 public CompilerContext Compiler {
866                         get { return RootContext.ToplevelTypes.Compiler; }
867                 }
868
869                 public TypeSpec CurrentType {
870                         get { return null; }
871                 }
872
873                 public TypeParameter[] CurrentTypeParameters {
874                         get { return null; }
875                 }
876
877                 public MemberCore CurrentMemberDefinition {
878                         get { return RootContext.ToplevelTypes; }
879                 }
880
881                 public string GetSignatureForError ()
882                 {
883                         return "<module>";
884                 }
885
886                 public bool HasUnresolvedConstraints {
887                         get { return false; }
888                 }
889
890                 public bool IsObsolete {
891                         get { return false; }
892                 }
893
894                 public bool IsUnsafe {
895                         get { return false; }
896                 }
897
898                 public bool IsStatic {
899                         get { return false; }
900                 }
901
902                 public ExtensionMethodGroupExpr LookupExtensionMethod (TypeSpec extensionType, string name, int arity, Location loc)
903                 {
904                         throw new NotImplementedException ();
905                 }
906
907                 public FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
908                 {
909                         return RootContext.ToplevelTypes.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
910                 }
911
912                 public FullNamedExpression LookupNamespaceAlias (string name)
913                 {
914                         return null;
915                 }
916
917                 #endregion
918         }
919                 
920         public class AssemblyClass : CommonAssemblyModulClass {
921                 // TODO: make it private and move all builder based methods here
922                 public AssemblyBuilder Builder;
923                 bool is_cls_compliant;
924                 bool wrap_non_exception_throws;
925
926                 public Attribute ClsCompliantAttribute;
927
928                 Dictionary<SecurityAction, PermissionSet> declarative_security;
929                 bool has_extension_method;              
930                 public AssemblyName Name;
931                 MethodInfo add_type_forwarder;
932                 Dictionary<ITypeDefinition, Attribute> emitted_forwarders;
933
934                 // Module is here just because of error messages
935                 static string[] attribute_targets = new string [] { "assembly", "module" };
936
937                 public AssemblyClass ()
938                 {
939                         wrap_non_exception_throws = true;
940                 }
941
942                 public bool HasExtensionMethods {
943                         set {
944                                 has_extension_method = value;
945                         }
946                 }
947
948                 public bool IsClsCompliant {
949                         get {
950                                 return is_cls_compliant;
951                         }
952                 }
953
954                 public bool WrapNonExceptionThrows {
955                         get {
956                                 return wrap_non_exception_throws;
957                         }
958                 }
959
960                 public override AttributeTargets AttributeTargets {
961                         get {
962                                 return AttributeTargets.Assembly;
963                         }
964                 }
965
966                 public override bool IsClsComplianceRequired ()
967                 {
968                         return is_cls_compliant;
969                 }
970
971                 Report Report {
972                         get { return Compiler.Report; }
973                 }
974
975                 public void Resolve ()
976                 {
977                         if (RootContext.Unsafe) {
978                                 //
979                                 // Emits [assembly: SecurityPermissionAttribute (SecurityAction.RequestMinimum, SkipVerification = true)]
980                                 // when -unsafe option was specified
981                                 //
982                                 
983                                 Location loc = Location.Null;
984
985                                 MemberAccess system_security_permissions = new MemberAccess (new MemberAccess (
986                                         new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Security", loc), "Permissions", loc);
987
988                                 Arguments pos = new Arguments (1);
989                                 pos.Add (new Argument (new MemberAccess (new MemberAccess (system_security_permissions, "SecurityAction", loc), "RequestMinimum")));
990
991                                 Arguments named = new Arguments (1);
992                                 named.Add (new NamedArgument ("SkipVerification", loc, new BoolLiteral (true, loc)));
993
994                                 GlobalAttribute g = new GlobalAttribute (new NamespaceEntry (null, null, null), "assembly",
995                                         new MemberAccess (system_security_permissions, "SecurityPermissionAttribute"),
996                                         new Arguments[] { pos, named }, loc, false);
997                                 g.AttachTo (this, this);
998
999                                 if (g.Resolve () != null) {
1000                                         declarative_security = new Dictionary<SecurityAction, PermissionSet> ();
1001                                         g.ExtractSecurityPermissionSet (declarative_security);
1002                                 }
1003                         }
1004
1005                         if (OptAttributes == null)
1006                                 return;
1007
1008                         // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
1009                         if (!OptAttributes.CheckTargets())
1010                                 return;
1011
1012                         ClsCompliantAttribute = ResolveAttribute (PredefinedAttributes.Get.CLSCompliant);
1013
1014                         if (ClsCompliantAttribute != null) {
1015                                 is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue ();
1016                         }
1017
1018                         Attribute a = ResolveAttribute (PredefinedAttributes.Get.RuntimeCompatibility);
1019                         if (a != null) {
1020                                 var val = a.GetPropertyValue ("WrapNonExceptionThrows") as BoolConstant;
1021                                 if (val != null)
1022                                         wrap_non_exception_throws = val.Value;
1023                         }
1024                 }
1025
1026                 // fix bug #56621
1027                 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob) 
1028                 {
1029                         try {
1030                                 // check for possible ECMA key
1031                                 if (strongNameBlob.Length == 16) {
1032                                         // will be rejected if not "the" ECMA key
1033                                         an.SetPublicKey (strongNameBlob);
1034                                 }
1035                                 else {
1036                                         // take it, with or without, a private key
1037                                         RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
1038                                         // and make sure we only feed the public part to Sys.Ref
1039                                         byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
1040                                         
1041                                         // AssemblyName.SetPublicKey requires an additional header
1042                                         byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
1043
1044                                         byte[] encodedPublicKey = new byte [12 + publickey.Length];
1045                                         Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
1046                                         Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
1047                                         an.SetPublicKey (encodedPublicKey);
1048                                 }
1049                         }
1050                         catch (Exception) {
1051                                 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded");
1052                                 Environment.Exit (1);
1053                         }
1054                 }
1055
1056                 // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
1057                 public AssemblyName GetAssemblyName (string name, string output) 
1058                 {
1059                         if (OptAttributes != null) {
1060                                 foreach (Attribute a in OptAttributes.Attrs) {
1061                                         // cannot rely on any resolve-based members before you call Resolve
1062                                         if (a.ExplicitTarget == null || a.ExplicitTarget != "assembly")
1063                                                 continue;
1064
1065                                         // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
1066                                         //       However, this is invoked by CodeGen.Init, when none of the namespaces
1067                                         //       are loaded yet.
1068                                         // TODO: Does not handle quoted attributes properly
1069                                         switch (a.Name) {
1070                                         case "AssemblyKeyFile":
1071                                         case "AssemblyKeyFileAttribute":
1072                                         case "System.Reflection.AssemblyKeyFileAttribute":
1073                                                 if (RootContext.StrongNameKeyFile != null) {
1074                                                         Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
1075                                                         Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1076                                                                         "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
1077                                                 } else {
1078                                                         string value = a.GetString ();
1079                                                         if (value != null && value.Length != 0)
1080                                                                 RootContext.StrongNameKeyFile = value;
1081                                                 }
1082                                                 break;
1083                                         case "AssemblyKeyName":
1084                                         case "AssemblyKeyNameAttribute":
1085                                         case "System.Reflection.AssemblyKeyNameAttribute":
1086                                                 if (RootContext.StrongNameKeyContainer != null) {
1087                                                         Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
1088                                                         Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1089                                                                         "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
1090                                                 } else {
1091                                                         string value = a.GetString ();
1092                                                         if (value != null && value.Length != 0)
1093                                                                 RootContext.StrongNameKeyContainer = value;
1094                                                 }
1095                                                 break;
1096                                         case "AssemblyDelaySign":
1097                                         case "AssemblyDelaySignAttribute":
1098                                         case "System.Reflection.AssemblyDelaySignAttribute":
1099                                                 RootContext.StrongNameDelaySign = a.GetBoolean ();
1100                                                 break;
1101                                         }
1102                                 }
1103                         }
1104                         
1105                         AssemblyName an = new AssemblyName ();
1106                         an.Name = Path.GetFileNameWithoutExtension (name);
1107
1108                         // note: delay doesn't apply when using a key container
1109                         if (RootContext.StrongNameKeyContainer != null) {
1110                                 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
1111                                 return an;
1112                         }
1113
1114                         // strongname is optional
1115                         if (RootContext.StrongNameKeyFile == null)
1116                                 return an;
1117
1118                         string AssemblyDir = Path.GetDirectoryName (output);
1119
1120                         // the StrongName key file may be relative to (a) the compiled
1121                         // file or (b) to the output assembly. See bugzilla #55320
1122                         // http://bugzilla.ximian.com/show_bug.cgi?id=55320
1123
1124                         // (a) relative to the compiled file
1125                         string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
1126                         bool exist = File.Exists (filename);
1127                         if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
1128                                 // (b) relative to the outputed assembly
1129                                 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
1130                                 exist = File.Exists (filename);
1131                         }
1132
1133                         if (exist) {
1134                                 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
1135                                         byte[] snkeypair = new byte [fs.Length];
1136                                         fs.Read (snkeypair, 0, snkeypair.Length);
1137
1138                                         if (RootContext.StrongNameDelaySign) {
1139                                                 // delayed signing - DO NOT include private key
1140                                                 SetPublicKey (an, snkeypair);
1141                                         }
1142                                         else {
1143                                                 // no delay so we make sure we have the private key
1144                                                 try {
1145                                                         CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
1146                                                         an.KeyPair = new StrongNameKeyPair (snkeypair);
1147                                                 }
1148                                                 catch (CryptographicException) {
1149                                                         if (snkeypair.Length == 16) {
1150                                                                 // error # is different for ECMA key
1151                                                                 Report.Error (1606, "Could not sign the assembly. " + 
1152                                                                         "ECMA key can only be used to delay-sign assemblies");
1153                                                         }
1154                                                         else {
1155                                                                 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not have a private key");
1156                                                         }
1157                                                         return null;
1158                                                 }
1159                                         }
1160                                 }
1161                         }
1162                         else {
1163                                 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not exist");
1164                                 return null;
1165                         }
1166                         return an;
1167                 }
1168
1169                 void Error_AssemblySigning (string text)
1170                 {
1171                         Report.Error (1548, "Error during assembly signing. " + text);
1172                 }
1173
1174                 bool CheckInternalsVisibleAttribute (Attribute a)
1175                 {
1176                         string assembly_name = a.GetString ();
1177                         if (assembly_name.Length == 0)
1178                                 return false;
1179                                 
1180                         AssemblyName aname = null;
1181                         try {
1182                                 aname = new AssemblyName (assembly_name);
1183                         } catch (FileLoadException) {
1184                         } catch (ArgumentException) {
1185                         }
1186                                 
1187                         // Bad assembly name format
1188                         if (aname == null)
1189                                 Report.Warning (1700, 3, a.Location, "Assembly reference `" + assembly_name + "' is invalid and cannot be resolved");
1190                         // Report error if we have defined Version or Culture
1191                         else if (aname.Version != null || aname.CultureInfo != null)
1192                                 throw new Exception ("Friend assembly `" + a.GetString () + 
1193                                                 "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
1194                         else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null && Name.GetPublicKey ().Length != 0) {
1195                                 Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." +
1196                                                 " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
1197                                 return false;
1198                         }
1199
1200                         return true;
1201                 }
1202
1203                 static string IsValidAssemblyVersion (string version)
1204                 {
1205                         Version v;
1206                         try {
1207                                 v = new Version (version);
1208                         } catch {
1209                                 try {
1210                                         int major = int.Parse (version, CultureInfo.InvariantCulture);
1211                                         v = new Version (major, 0);
1212                                 } catch {
1213                                         return null;
1214                                 }
1215                         }
1216
1217                         foreach (int candidate in new int [] { v.Major, v.Minor, v.Build, v.Revision }) {
1218                                 if (candidate > ushort.MaxValue)
1219                                         return null;
1220                         }
1221
1222                         return new Version (v.Major, System.Math.Max (0, v.Minor), System.Math.Max (0, v.Build), System.Math.Max (0, v.Revision)).ToString (4);
1223                 }
1224
1225                 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
1226                 {
1227                         if (a.IsValidSecurityAttribute ()) {
1228                                 if (declarative_security == null)
1229                                         declarative_security = new Dictionary<SecurityAction, PermissionSet> ();
1230
1231                                 a.ExtractSecurityPermissionSet (declarative_security);
1232                                 return;
1233                         }
1234
1235                         if (a.Type == pa.AssemblyCulture) {
1236                                 string value = a.GetString ();
1237                                 if (value == null || value.Length == 0)
1238                                         return;
1239
1240                                 if (RootContext.Target == Target.Exe) {
1241                                         a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
1242                                         return;
1243                                 }
1244
1245                                 try {
1246                                         var fi = typeof (AssemblyBuilder).GetField ("culture", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
1247                                         fi.SetValue (CodeGen.Assembly.Builder, value == "neutral" ? "" : value);
1248                                 } catch {
1249                                         Report.RuntimeMissingSupport (a.Location, "AssemblyCultureAttribute setting");
1250                                 }
1251
1252                                 return;
1253                         }
1254
1255                         if (a.Type == pa.AssemblyVersion) {
1256                                 string value = a.GetString ();
1257                                 if (value == null || value.Length == 0)
1258                                         return;
1259
1260                                 var vinfo = IsValidAssemblyVersion (value.Replace ('*', '0'));
1261                                 if (vinfo == null) {
1262                                         a.Error_AttributeEmitError (string.Format ("Specified version `{0}' is not valid", value));
1263                                         return;
1264                                 }
1265
1266                                 try {
1267                                         var fi = typeof (AssemblyBuilder).GetField ("version", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
1268                                         fi.SetValue (CodeGen.Assembly.Builder, vinfo);
1269                                 } catch {
1270                                         Report.RuntimeMissingSupport (a.Location, "AssemblyVersionAttribute setting");
1271                                 }
1272
1273                                 return;
1274                         }
1275
1276                         if (a.Type == pa.AssemblyAlgorithmId) {
1277                                 const int pos = 2; // skip CA header
1278                                 uint alg = (uint) cdata [pos];
1279                                 alg |= ((uint) cdata [pos + 1]) << 8;
1280                                 alg |= ((uint) cdata [pos + 2]) << 16;
1281                                 alg |= ((uint) cdata [pos + 3]) << 24;
1282
1283                                 try {
1284                                         var fi = typeof (AssemblyBuilder).GetField ("algid", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
1285                                         fi.SetValue (CodeGen.Assembly.Builder, alg);
1286                                 } catch {
1287                                         Report.RuntimeMissingSupport (a.Location, "AssemblyAlgorithmIdAttribute setting");
1288                                 }
1289
1290                                 return;
1291                         }
1292
1293                         if (a.Type == pa.AssemblyFlags) {
1294                                 const int pos = 2; // skip CA header
1295                                 uint flags = (uint) cdata[pos];
1296                                 flags |= ((uint) cdata[pos + 1]) << 8;
1297                                 flags |= ((uint) cdata[pos + 2]) << 16;
1298                                 flags |= ((uint) cdata[pos + 3]) << 24;
1299
1300                                 // Ignore set PublicKey flag if assembly is not strongnamed
1301                                 if ((flags & (uint) AssemblyNameFlags.PublicKey) != 0 && (CodeGen.Assembly.Builder.GetName ().KeyPair == null))
1302                                         flags &= ~(uint)AssemblyNameFlags.PublicKey;
1303
1304                                 try {
1305                                         var fi = typeof (AssemblyBuilder).GetField ("flags", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
1306                                         fi.SetValue (CodeGen.Assembly.Builder, flags);
1307                                 } catch {
1308                                         Report.RuntimeMissingSupport (a.Location, "AssemblyFlagsAttribute setting");
1309                                 }
1310
1311                                 return;
1312                         }
1313
1314                         if (a.Type == pa.InternalsVisibleTo && !CheckInternalsVisibleAttribute (a))
1315                                 return;
1316
1317                         if (a.Type == pa.TypeForwarder) {
1318                                 TypeSpec t = a.GetArgumentType ();
1319                                 if (t == null || TypeManager.HasElementType (t)) {
1320                                         Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
1321                                         return;
1322                                 }
1323
1324                                 if (emitted_forwarders == null) {
1325                                         emitted_forwarders = new Dictionary<ITypeDefinition, Attribute>  ();
1326                                 } else if (emitted_forwarders.ContainsKey (t.MemberDefinition)) {
1327                                         Report.SymbolRelatedToPreviousError(emitted_forwarders[t.MemberDefinition].Location, null);
1328                                         Report.Error(739, a.Location, "A duplicate type forward of type `{0}'",
1329                                                 TypeManager.CSharpName(t));
1330                                         return;
1331                                 }
1332
1333                                 emitted_forwarders.Add(t.MemberDefinition, a);
1334
1335                                 if (t.Assembly == Builder) {
1336                                         Report.SymbolRelatedToPreviousError (t);
1337                                         Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
1338                                                 TypeManager.CSharpName (t));
1339                                         return;
1340                                 }
1341
1342                                 if (t.IsNested) {
1343                                         Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
1344                                                 TypeManager.CSharpName (t));
1345                                         return;
1346                                 }
1347
1348                                 if (add_type_forwarder == null) {
1349                                         add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder",
1350                                                 BindingFlags.NonPublic | BindingFlags.Instance);
1351
1352                                         if (add_type_forwarder == null) {
1353                                                 Report.RuntimeMissingSupport (a.Location, "TypeForwardedTo attribute");
1354                                                 return;
1355                                         }
1356                                 }
1357
1358                                 add_type_forwarder.Invoke (Builder, new object[] { t.GetMetaInfo () });
1359                                 return;
1360                         }
1361                         
1362                         if (a.Type == pa.Extension) {
1363                                 a.Error_MisusedExtensionAttribute ();
1364                                 return;
1365                         }
1366
1367                         Builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
1368                 }
1369
1370                 public override void Emit (TypeContainer tc)
1371                 {
1372                         base.Emit (tc);
1373
1374                         if (has_extension_method)
1375                                 PredefinedAttributes.Get.Extension.EmitAttribute (Builder);
1376
1377                         // FIXME: Does this belong inside SRE.AssemblyBuilder instead?
1378                         PredefinedAttribute pa = PredefinedAttributes.Get.RuntimeCompatibility;
1379                         if (pa.IsDefined && (OptAttributes == null || !OptAttributes.Contains (pa))) {
1380                                 var ci = TypeManager.GetPredefinedConstructor (pa.Type, Location.Null, TypeSpec.EmptyTypes);
1381                                 PropertyInfo [] pis = new PropertyInfo [1];
1382                                 pis [0] = TypeManager.GetPredefinedProperty (pa.Type,
1383                                         "WrapNonExceptionThrows", Location.Null, TypeManager.bool_type).MetaInfo;
1384                                 object [] pargs = new object [1];
1385                                 pargs [0] = true;
1386                                 Builder.SetCustomAttribute (new CustomAttributeBuilder ((ConstructorInfo) ci.GetMetaInfo (), new object[0], pis, pargs));
1387                         }
1388
1389                         if (declarative_security != null) {
1390
1391                                 MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1392                                 object builder_instance = Builder;
1393
1394                                 try {
1395                                         // Microsoft runtime hacking
1396                                         if (add_permission == null) {
1397                                                 var assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData");
1398                                                 add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1399
1400                                                 FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
1401                                                 builder_instance = fi.GetValue (Builder);
1402                                         }
1403
1404                                         var args = new PermissionSet [3];
1405                                         declarative_security.TryGetValue (SecurityAction.RequestMinimum, out args [0]);
1406                                         declarative_security.TryGetValue (SecurityAction.RequestOptional, out args [1]);
1407                                         declarative_security.TryGetValue (SecurityAction.RequestRefuse, out args [2]);
1408                                         add_permission.Invoke (builder_instance, args);
1409                                 }
1410                                 catch {
1411                                         Report.RuntimeMissingSupport (Location.Null, "assembly permission setting");
1412                                 }
1413                         }
1414                 }
1415
1416                 public override string[] ValidAttributeTargets {
1417                         get {
1418                                 return attribute_targets;
1419                         }
1420                 }
1421
1422                 // Wrapper for AssemblyBuilder.AddModule
1423                 static MethodInfo adder_method;
1424                 static public MethodInfo AddModule_Method {
1425                         get {
1426                                 if (adder_method == null)
1427                                         adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
1428                                 return adder_method;
1429                         }
1430                 }
1431                 public Module AddModule (string module)
1432                 {
1433                         MethodInfo m = AddModule_Method;
1434                         if (m == null) {
1435                                 Report.RuntimeMissingSupport (Location.Null, "/addmodule");
1436                                 Environment.Exit (1);
1437                         }
1438
1439                         try {
1440                                 return (Module) m.Invoke (Builder, new object [] { module });
1441                         } catch (TargetInvocationException ex) {
1442                                 throw ex.InnerException;
1443                         }
1444                 }               
1445         }
1446 }