2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / codegen.cs
blob96bfe1642351850ae25f47a1f246b1621db95a7e
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 //
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.
16 // Only remove it if you need to debug locally on your tree.
18 //#define PRODUCTION
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;
31 using Mono.Security.Cryptography;
33 namespace Mono.CSharp {
35 /// <summary>
36 /// Code generator class.
37 /// </summary>
38 public class CodeGen {
39 static AppDomain current_domain;
41 public static AssemblyClass Assembly;
43 static CodeGen ()
45 Reset ();
48 public static void Reset ()
50 Assembly = new AssemblyClass ();
53 public static string Basename (string name)
55 int pos = name.LastIndexOf ('/');
57 if (pos != -1)
58 return name.Substring (pos + 1);
60 pos = name.LastIndexOf ('\\');
61 if (pos != -1)
62 return name.Substring (pos + 1);
64 return name;
67 public static string Dirname (string name)
69 int pos = name.LastIndexOf ('/');
71 if (pos != -1)
72 return name.Substring (0, pos);
74 pos = name.LastIndexOf ('\\');
75 if (pos != -1)
76 return name.Substring (0, pos);
78 return ".";
81 static public string FileName;
83 #if MS_COMPATIBLE
84 const AssemblyBuilderAccess COMPILER_ACCESS = 0;
85 #else
86 /* Keep this in sync with System.Reflection.Emit.AssemblyBuilder */
87 const AssemblyBuilderAccess COMPILER_ACCESS = (AssemblyBuilderAccess) 0x800;
88 #endif
91 // Initializes the code generator variables for interactive use (repl)
93 static public void InitDynamic (CompilerContext ctx, string name)
95 current_domain = AppDomain.CurrentDomain;
96 AssemblyName an = Assembly.GetAssemblyName (name, name);
98 Assembly.Builder = current_domain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run | COMPILER_ACCESS);
99 RootContext.ToplevelTypes = new ModuleCompiled (ctx, true);
100 RootContext.ToplevelTypes.Builder = Assembly.Builder.DefineDynamicModule (Basename (name), false);
101 Assembly.Name = Assembly.Builder.GetName ();
105 // Initializes the code generator variables
107 static public bool Init (string name, string output, bool want_debugging_support, CompilerContext ctx)
109 FileName = output;
110 AssemblyName an = Assembly.GetAssemblyName (name, output);
111 if (an == null)
112 return false;
114 if (an.KeyPair != null) {
115 // If we are going to strong name our assembly make
116 // sure all its refs are strong named
117 foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) {
118 AssemblyName ref_name = a.GetName ();
119 byte [] b = ref_name.GetPublicKeyToken ();
120 if (b == null || b.Length == 0) {
121 ctx.Report.Error (1577, "Assembly generation failed " +
122 "-- Referenced assembly '" +
123 ref_name.Name +
124 "' does not have a strong name.");
125 //Environment.Exit (1);
130 current_domain = AppDomain.CurrentDomain;
132 try {
133 Assembly.Builder = current_domain.DefineDynamicAssembly (an,
134 AssemblyBuilderAccess.RunAndSave | COMPILER_ACCESS, Dirname (name));
136 catch (ArgumentException) {
137 // specified key may not be exportable outside it's container
138 if (RootContext.StrongNameKeyContainer != null) {
139 ctx.Report.Error (1548, "Could not access the key inside the container `" +
140 RootContext.StrongNameKeyContainer + "'.");
141 Environment.Exit (1);
143 throw;
145 catch (CryptographicException) {
146 if ((RootContext.StrongNameKeyContainer != null) || (RootContext.StrongNameKeyFile != null)) {
147 ctx.Report.Error (1548, "Could not use the specified key to strongname the assembly.");
148 Environment.Exit (1);
150 return false;
153 // Get the complete AssemblyName from the builder
154 // (We need to get the public key and token)
155 Assembly.Name = Assembly.Builder.GetName ();
158 // Pass a path-less name to DefineDynamicModule. Wonder how
159 // this copes with output in different directories then.
160 // FIXME: figure out how this copes with --output /tmp/blah
162 // If the third argument is true, the ModuleBuilder will dynamically
163 // load the default symbol writer.
165 try {
166 RootContext.ToplevelTypes.Builder = Assembly.Builder.DefineDynamicModule (
167 Basename (name), Basename (output), want_debugging_support);
169 #if !MS_COMPATIBLE
170 // TODO: We should use SymbolWriter from DefineDynamicModule
171 if (want_debugging_support && !SymbolWriter.Initialize (RootContext.ToplevelTypes.Builder, output)) {
172 ctx.Report.Error (40, "Unexpected debug information initialization error `{0}'",
173 "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll)");
174 return false;
176 #endif
177 } catch (ExecutionEngineException e) {
178 ctx.Report.Error (40, "Unexpected debug information initialization error `{0}'",
179 e.Message);
180 return false;
183 return true;
186 static public void Save (string name, bool saveDebugInfo, Report Report)
188 PortableExecutableKinds pekind;
189 ImageFileMachine machine;
191 switch (RootContext.Platform) {
192 case Platform.X86:
193 pekind = PortableExecutableKinds.Required32Bit;
194 machine = ImageFileMachine.I386;
195 break;
196 case Platform.X64:
197 pekind = PortableExecutableKinds.PE32Plus;
198 machine = ImageFileMachine.AMD64;
199 break;
200 case Platform.IA64:
201 pekind = PortableExecutableKinds.PE32Plus;
202 machine = ImageFileMachine.IA64;
203 break;
204 case Platform.AnyCPU:
205 default:
206 pekind = PortableExecutableKinds.ILOnly;
207 machine = ImageFileMachine.I386;
208 break;
210 try {
211 Assembly.Builder.Save (Basename (name), pekind, machine);
213 catch (COMException) {
214 if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
215 throw;
217 // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies
218 Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
219 RootContext.StrongNameKeyFile +
220 "', Use MCS with the Mono runtime or CSC to compile this assembly.");
222 catch (System.IO.IOException io) {
223 Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
224 return;
226 catch (System.UnauthorizedAccessException ua) {
227 Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message);
228 return;
230 catch (System.NotImplementedException nie) {
231 Report.RuntimeMissingSupport (Location.Null, nie.Message);
232 return;
236 // Write debuger symbol file
238 if (saveDebugInfo)
239 SymbolWriter.WriteSymbolFile ();
243 /// <summary>
244 /// An Emit Context is created for each body of code (from methods,
245 /// properties bodies, indexer bodies or constructor bodies)
246 /// </summary>
247 public class EmitContext : BuilderContext
249 public ILGenerator ig;
251 /// <summary>
252 /// The value that is allowed to be returned or NULL if there is no
253 /// return type.
254 /// </summary>
255 Type return_type;
257 /// <summary>
258 /// Keeps track of the Type to LocalBuilder temporary storage created
259 /// to store structures (used to compute the address of the structure
260 /// value on structure method invocations)
261 /// </summary>
262 Dictionary<Type, object> temporary_storage;
264 /// <summary>
265 /// The location where we store the return value.
266 /// </summary>
267 public LocalBuilder return_value;
269 /// <summary>
270 /// The location where return has to jump to return the
271 /// value
272 /// </summary>
273 public Label ReturnLabel;
275 /// <summary>
276 /// If we already defined the ReturnLabel
277 /// </summary>
278 public bool HasReturnLabel;
280 /// <summary>
281 /// Whether we are inside an anonymous method.
282 /// </summary>
283 public AnonymousExpression CurrentAnonymousMethod;
285 public readonly IMemberContext MemberContext;
287 public EmitContext (IMemberContext rc, ILGenerator ig, Type return_type)
289 this.MemberContext = rc;
290 this.ig = ig;
292 this.return_type = return_type;
295 public Type CurrentType {
296 get { return MemberContext.CurrentType; }
299 public TypeParameter[] CurrentTypeParameters {
300 get { return MemberContext.CurrentTypeParameters; }
303 public TypeContainer CurrentTypeDefinition {
304 get { return MemberContext.CurrentTypeDefinition; }
307 public bool IsStatic {
308 get { return MemberContext.IsStatic; }
311 // Has to be used for emitter errors only
312 public Report Report {
313 get { return MemberContext.Compiler.Report; }
316 public Type ReturnType {
317 get {
318 return return_type;
322 /// <summary>
323 /// This is called immediately before emitting an IL opcode to tell the symbol
324 /// writer to which source line this opcode belongs.
325 /// </summary>
326 public void Mark (Location loc)
328 if (!SymbolWriter.HasSymbolWriter || HasSet (Options.OmitDebugInfo) || loc.IsNull)
329 return;
331 SymbolWriter.MarkSequencePoint (ig, loc);
334 public void DefineLocalVariable (string name, LocalBuilder builder)
336 SymbolWriter.DefineLocalVariable (name, builder);
339 public void BeginScope ()
341 ig.BeginScope();
342 SymbolWriter.OpenScope(ig);
345 public void EndScope ()
347 ig.EndScope();
348 SymbolWriter.CloseScope(ig);
351 /// <summary>
352 /// Returns a temporary storage for a variable of type t as
353 /// a local variable in the current body.
354 /// </summary>
355 public LocalBuilder GetTemporaryLocal (Type t)
357 if (temporary_storage != null) {
358 object o;
359 if (temporary_storage.TryGetValue (t, out o)) {
360 if (o is Stack<LocalBuilder>) {
361 var s = (Stack<LocalBuilder>) o;
362 o = s.Count == 0 ? null : s.Pop ();
363 } else {
364 temporary_storage.Remove (t);
367 if (o != null)
368 return (LocalBuilder) o;
370 return ig.DeclareLocal (TypeManager.TypeToReflectionType (t));
373 public void FreeTemporaryLocal (LocalBuilder b, Type t)
375 if (temporary_storage == null) {
376 temporary_storage = new Dictionary<Type, object> (ReferenceEquality<Type>.Default);
377 temporary_storage.Add (t, b);
378 return;
380 object o;
382 if (!temporary_storage.TryGetValue (t, out o)) {
383 temporary_storage.Add (t, b);
384 return;
386 var s = o as Stack<LocalBuilder>;
387 if (s == null) {
388 s = new Stack<LocalBuilder> ();
389 s.Push ((LocalBuilder)o);
390 temporary_storage [t] = s;
392 s.Push (b);
395 /// <summary>
396 /// Current loop begin and end labels.
397 /// </summary>
398 public Label LoopBegin, LoopEnd;
400 /// <summary>
401 /// Default target in a switch statement. Only valid if
402 /// InSwitch is true
403 /// </summary>
404 public Label DefaultTarget;
406 /// <summary>
407 /// If this is non-null, points to the current switch statement
408 /// </summary>
409 public Switch Switch;
411 /// <summary>
412 /// ReturnValue creates on demand the LocalBuilder for the
413 /// return value from the function. By default this is not
414 /// used. This is only required when returns are found inside
415 /// Try or Catch statements.
417 /// This method is typically invoked from the Emit phase, so
418 /// we allow the creation of a return label if it was not
419 /// requested during the resolution phase. Could be cleaned
420 /// up, but it would replicate a lot of logic in the Emit phase
421 /// of the code that uses it.
422 /// </summary>
423 public LocalBuilder TemporaryReturn ()
425 if (return_value == null){
426 return_value = ig.DeclareLocal (return_type);
427 if (!HasReturnLabel){
428 ReturnLabel = ig.DefineLabel ();
429 HasReturnLabel = true;
433 return return_value;
437 public abstract class CommonAssemblyModulClass : Attributable, IMemberContext
439 public void AddAttributes (List<Attribute> attrs, IMemberContext context)
441 foreach (Attribute a in attrs)
442 a.AttachTo (this, context);
444 if (attributes == null) {
445 attributes = new Attributes (attrs);
446 return;
448 attributes.AddAttributes (attrs);
451 public virtual void Emit (TypeContainer tc)
453 if (OptAttributes == null)
454 return;
456 OptAttributes.Emit ();
459 protected Attribute ResolveAttribute (PredefinedAttribute a_type)
461 Attribute a = OptAttributes.Search (a_type);
462 if (a != null) {
463 a.Resolve ();
465 return a;
468 #region IMemberContext Members
470 public CompilerContext Compiler {
471 get { return RootContext.ToplevelTypes.Compiler; }
474 public Type CurrentType {
475 get { return null; }
478 public TypeParameter[] CurrentTypeParameters {
479 get { return null; }
482 public TypeContainer CurrentTypeDefinition {
483 get { return RootContext.ToplevelTypes; }
486 public string GetSignatureForError ()
488 return "<module>";
491 public bool IsObsolete {
492 get { return false; }
495 public bool IsUnsafe {
496 get { return false; }
499 public bool IsStatic {
500 get { return false; }
503 public ExtensionMethodGroupExpr LookupExtensionMethod (Type extensionType, string name, Location loc)
505 throw new NotImplementedException ();
508 public FullNamedExpression LookupNamespaceOrType (string name, Location loc, bool ignore_cs0104)
510 return RootContext.ToplevelTypes.LookupNamespaceOrType (name, loc, ignore_cs0104);
513 public FullNamedExpression LookupNamespaceAlias (string name)
515 return null;
518 #endregion
521 public class AssemblyClass : CommonAssemblyModulClass {
522 // TODO: make it private and move all builder based methods here
523 public AssemblyBuilder Builder;
524 bool is_cls_compliant;
525 bool wrap_non_exception_throws;
527 public Attribute ClsCompliantAttribute;
529 Dictionary<SecurityAction, PermissionSet> declarative_security;
530 bool has_extension_method;
531 public AssemblyName Name;
532 MethodInfo add_type_forwarder;
533 Dictionary<Type, Attribute> emitted_forwarders;
535 // Module is here just because of error messages
536 static string[] attribute_targets = new string [] { "assembly", "module" };
538 public AssemblyClass ()
540 wrap_non_exception_throws = true;
543 public bool HasExtensionMethods {
544 set {
545 has_extension_method = value;
549 public bool IsClsCompliant {
550 get {
551 return is_cls_compliant;
555 public bool WrapNonExceptionThrows {
556 get {
557 return wrap_non_exception_throws;
561 public override AttributeTargets AttributeTargets {
562 get {
563 return AttributeTargets.Assembly;
567 public override bool IsClsComplianceRequired ()
569 return is_cls_compliant;
572 Report Report {
573 get { return Compiler.Report; }
576 public void Resolve ()
578 if (RootContext.Unsafe) {
580 // Emits [assembly: SecurityPermissionAttribute (SecurityAction.RequestMinimum, SkipVerification = true)]
581 // when -unsafe option was specified
584 Location loc = Location.Null;
586 MemberAccess system_security_permissions = new MemberAccess (new MemberAccess (
587 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Security", loc), "Permissions", loc);
589 Arguments pos = new Arguments (1);
590 pos.Add (new Argument (new MemberAccess (new MemberAccess (system_security_permissions, "SecurityAction", loc), "RequestMinimum")));
592 Arguments named = new Arguments (1);
593 named.Add (new NamedArgument ("SkipVerification", loc, new BoolLiteral (true, loc)));
595 GlobalAttribute g = new GlobalAttribute (new NamespaceEntry (null, null, null), "assembly",
596 new MemberAccess (system_security_permissions, "SecurityPermissionAttribute"),
597 new Arguments[] { pos, named }, loc, false);
598 g.AttachTo (this, this);
600 if (g.Resolve () != null) {
601 declarative_security = new Dictionary<SecurityAction, PermissionSet> ();
602 g.ExtractSecurityPermissionSet (declarative_security);
606 if (OptAttributes == null)
607 return;
609 // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
610 if (!OptAttributes.CheckTargets())
611 return;
613 ClsCompliantAttribute = ResolveAttribute (PredefinedAttributes.Get.CLSCompliant);
615 if (ClsCompliantAttribute != null) {
616 is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue ();
619 Attribute a = ResolveAttribute (PredefinedAttributes.Get.RuntimeCompatibility);
620 if (a != null) {
621 object val = a.GetPropertyValue ("WrapNonExceptionThrows");
622 if (val != null)
623 wrap_non_exception_throws = (bool) val;
627 // fix bug #56621
628 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob)
630 try {
631 // check for possible ECMA key
632 if (strongNameBlob.Length == 16) {
633 // will be rejected if not "the" ECMA key
634 an.SetPublicKey (strongNameBlob);
636 else {
637 // take it, with or without, a private key
638 RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
639 // and make sure we only feed the public part to Sys.Ref
640 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
642 // AssemblyName.SetPublicKey requires an additional header
643 byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
645 byte[] encodedPublicKey = new byte [12 + publickey.Length];
646 Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
647 Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
648 an.SetPublicKey (encodedPublicKey);
651 catch (Exception) {
652 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded");
653 Environment.Exit (1);
657 // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
658 public AssemblyName GetAssemblyName (string name, string output)
660 if (OptAttributes != null) {
661 foreach (Attribute a in OptAttributes.Attrs) {
662 // cannot rely on any resolve-based members before you call Resolve
663 if (a.ExplicitTarget == null || a.ExplicitTarget != "assembly")
664 continue;
666 // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
667 // However, this is invoked by CodeGen.Init, when none of the namespaces
668 // are loaded yet.
669 // TODO: Does not handle quoted attributes properly
670 switch (a.Name) {
671 case "AssemblyKeyFile":
672 case "AssemblyKeyFileAttribute":
673 case "System.Reflection.AssemblyKeyFileAttribute":
674 if (RootContext.StrongNameKeyFile != null) {
675 Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
676 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
677 "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
678 } else {
679 string value = a.GetString ();
680 if (value != null && value.Length != 0)
681 RootContext.StrongNameKeyFile = value;
683 break;
684 case "AssemblyKeyName":
685 case "AssemblyKeyNameAttribute":
686 case "System.Reflection.AssemblyKeyNameAttribute":
687 if (RootContext.StrongNameKeyContainer != null) {
688 Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
689 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
690 "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
691 } else {
692 string value = a.GetString ();
693 if (value != null && value.Length != 0)
694 RootContext.StrongNameKeyContainer = value;
696 break;
697 case "AssemblyDelaySign":
698 case "AssemblyDelaySignAttribute":
699 case "System.Reflection.AssemblyDelaySignAttribute":
700 RootContext.StrongNameDelaySign = a.GetBoolean ();
701 break;
706 AssemblyName an = new AssemblyName ();
707 an.Name = Path.GetFileNameWithoutExtension (name);
709 // note: delay doesn't apply when using a key container
710 if (RootContext.StrongNameKeyContainer != null) {
711 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
712 return an;
715 // strongname is optional
716 if (RootContext.StrongNameKeyFile == null)
717 return an;
719 string AssemblyDir = Path.GetDirectoryName (output);
721 // the StrongName key file may be relative to (a) the compiled
722 // file or (b) to the output assembly. See bugzilla #55320
723 // http://bugzilla.ximian.com/show_bug.cgi?id=55320
725 // (a) relative to the compiled file
726 string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
727 bool exist = File.Exists (filename);
728 if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
729 // (b) relative to the outputed assembly
730 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
731 exist = File.Exists (filename);
734 if (exist) {
735 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
736 byte[] snkeypair = new byte [fs.Length];
737 fs.Read (snkeypair, 0, snkeypair.Length);
739 if (RootContext.StrongNameDelaySign) {
740 // delayed signing - DO NOT include private key
741 SetPublicKey (an, snkeypair);
743 else {
744 // no delay so we make sure we have the private key
745 try {
746 CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
747 an.KeyPair = new StrongNameKeyPair (snkeypair);
749 catch (CryptographicException) {
750 if (snkeypair.Length == 16) {
751 // error # is different for ECMA key
752 Report.Error (1606, "Could not sign the assembly. " +
753 "ECMA key can only be used to delay-sign assemblies");
755 else {
756 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not have a private key");
758 return null;
763 else {
764 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not exist");
765 return null;
767 return an;
770 void Error_AssemblySigning (string text)
772 Report.Error (1548, "Error during assembly signing. " + text);
775 bool CheckInternalsVisibleAttribute (Attribute a)
777 string assembly_name = a.GetString ();
778 if (assembly_name.Length == 0)
779 return false;
781 AssemblyName aname = null;
782 try {
783 aname = new AssemblyName (assembly_name);
784 } catch (FileLoadException) {
785 } catch (ArgumentException) {
788 // Bad assembly name format
789 if (aname == null)
790 Report.Warning (1700, 3, a.Location, "Assembly reference `" + assembly_name + "' is invalid and cannot be resolved");
791 // Report error if we have defined Version or Culture
792 else if (aname.Version != null || aname.CultureInfo != null)
793 throw new Exception ("Friend assembly `" + a.GetString () +
794 "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
795 else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null && Name.GetPublicKey ().Length != 0) {
796 Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." +
797 " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
798 return false;
801 return true;
804 static bool IsValidAssemblyVersion (string version)
806 Version v;
807 try {
808 v = new Version (version);
809 } catch {
810 try {
811 int major = int.Parse (version, CultureInfo.InvariantCulture);
812 v = new Version (major, 0);
813 } catch {
814 return false;
818 foreach (int candidate in new int [] { v.Major, v.Minor, v.Build, v.Revision }) {
819 if (candidate > ushort.MaxValue)
820 return false;
823 return true;
826 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
828 if (a.IsValidSecurityAttribute ()) {
829 if (declarative_security == null)
830 declarative_security = new Dictionary<SecurityAction, PermissionSet> ();
832 a.ExtractSecurityPermissionSet (declarative_security);
833 return;
836 if (a.Type == pa.AssemblyCulture) {
837 string value = a.GetString ();
838 if (value == null || value.Length == 0)
839 return;
841 if (RootContext.Target == Target.Exe) {
842 a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
843 return;
847 if (a.Type == pa.AssemblyVersion) {
848 string value = a.GetString ();
849 if (value == null || value.Length == 0)
850 return;
852 value = value.Replace ('*', '0');
854 if (!IsValidAssemblyVersion (value)) {
855 a.Error_AttributeEmitError (string.Format ("Specified version `{0}' is not valid", value));
856 return;
860 if (a.Type == pa.InternalsVisibleTo && !CheckInternalsVisibleAttribute (a))
861 return;
863 if (a.Type == pa.TypeForwarder) {
864 Type t = a.GetArgumentType ();
865 if (t == null || TypeManager.HasElementType (t)) {
866 Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
867 return;
870 t = TypeManager.DropGenericTypeArguments (t);
871 if (emitted_forwarders == null) {
872 emitted_forwarders = new Dictionary<Type, Attribute> ();
873 } else if (emitted_forwarders.ContainsKey (t)) {
874 Report.SymbolRelatedToPreviousError(emitted_forwarders[t].Location, null);
875 Report.Error(739, a.Location, "A duplicate type forward of type `{0}'",
876 TypeManager.CSharpName(t));
877 return;
880 emitted_forwarders.Add(t, a);
882 if (TypeManager.LookupDeclSpace (t) != null) {
883 Report.SymbolRelatedToPreviousError (t);
884 Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
885 TypeManager.CSharpName (t));
886 return;
889 if (t.DeclaringType != null) {
890 Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
891 TypeManager.CSharpName (t));
892 return;
895 if (add_type_forwarder == null) {
896 add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder",
897 BindingFlags.NonPublic | BindingFlags.Instance);
899 if (add_type_forwarder == null) {
900 Report.RuntimeMissingSupport (a.Location, "TypeForwardedTo attribute");
901 return;
905 add_type_forwarder.Invoke (Builder, new object[] { t });
906 return;
909 if (a.Type == pa.Extension) {
910 a.Error_MisusedExtensionAttribute ();
911 return;
914 Builder.SetCustomAttribute (cb);
917 public override void Emit (TypeContainer tc)
919 base.Emit (tc);
921 if (has_extension_method)
922 PredefinedAttributes.Get.Extension.EmitAttribute (Builder);
924 // FIXME: Does this belong inside SRE.AssemblyBuilder instead?
925 PredefinedAttribute pa = PredefinedAttributes.Get.RuntimeCompatibility;
926 if (pa.IsDefined && (OptAttributes == null || !OptAttributes.Contains (pa))) {
927 ConstructorInfo ci = TypeManager.GetPredefinedConstructor (
928 pa.Type, Location.Null, Type.EmptyTypes);
929 PropertyInfo [] pis = new PropertyInfo [1];
930 pis [0] = TypeManager.GetPredefinedProperty (pa.Type,
931 "WrapNonExceptionThrows", Location.Null, TypeManager.bool_type).MetaInfo;
932 object [] pargs = new object [1];
933 pargs [0] = true;
934 Builder.SetCustomAttribute (new CustomAttributeBuilder (ci, new object [0], pis, pargs));
937 if (declarative_security != null) {
939 MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
940 object builder_instance = Builder;
942 try {
943 // Microsoft runtime hacking
944 if (add_permission == null) {
945 Type assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData");
946 add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
948 FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
949 builder_instance = fi.GetValue (Builder);
952 var args = new PermissionSet [3];
953 declarative_security.TryGetValue (SecurityAction.RequestMinimum, out args [0]);
954 declarative_security.TryGetValue (SecurityAction.RequestOptional, out args [1]);
955 declarative_security.TryGetValue (SecurityAction.RequestRefuse, out args [2]);
956 add_permission.Invoke (builder_instance, args);
958 catch {
959 Report.RuntimeMissingSupport (Location.Null, "assembly permission setting");
964 public override string[] ValidAttributeTargets {
965 get {
966 return attribute_targets;
970 // Wrapper for AssemblyBuilder.AddModule
971 static MethodInfo adder_method;
972 static public MethodInfo AddModule_Method {
973 get {
974 if (adder_method == null)
975 adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
976 return adder_method;
979 public Module AddModule (string module)
981 MethodInfo m = AddModule_Method;
982 if (m == null) {
983 Report.RuntimeMissingSupport (Location.Null, "/addmodule");
984 Environment.Exit (1);
987 try {
988 return (Module) m.Invoke (Builder, new object [] { module });
989 } catch (TargetInvocationException ex) {
990 throw ex.InnerException;