2 // codegen.cs: The code generator
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001, 2002, 2003 Ximian, Inc.
8 // (C) 2004 Novell, Inc.
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.
22 using System.Collections;
23 using System.Collections.Specialized;
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 {
36 /// Code generator class.
38 public class CodeGen {
39 static AppDomain current_domain;
40 static public SymbolWriter SymbolWriter;
42 public static AssemblyClass Assembly;
43 public static ModuleClass Module;
50 public static void Reset ()
52 Assembly = new AssemblyClass ();
53 Module = new ModuleClass (RootContext.Unsafe);
56 public static string Basename (string name)
58 int pos = name.LastIndexOf ('/');
61 return name.Substring (pos + 1);
63 pos = name.LastIndexOf ('\\');
65 return name.Substring (pos + 1);
70 public static string Dirname (string name)
72 int pos = name.LastIndexOf ('/');
75 return name.Substring (0, pos);
77 pos = name.LastIndexOf ('\\');
79 return name.Substring (0, pos);
84 static public string FileName;
87 // Initializes the symbol writer
89 static void InitializeSymbolWriter (string filename)
91 SymbolWriter = SymbolWriter.GetSymbolWriter (Module.Builder, filename);
94 // If we got an ISymbolWriter instance, initialize it.
96 if (SymbolWriter == null) {
98 -18, 1, "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll). This is normally an installation problem. Please make sure to compile and install the mcs/class/Mono.CompilerServices.SymbolWriter directory.");
104 // Initializes the code generator variables
106 static public bool Init (string name, string output, bool want_debugging_support)
109 AssemblyName an = Assembly.GetAssemblyName (name, output);
113 if (an.KeyPair != null) {
114 // If we are going to strong name our assembly make
115 // sure all its refs are strong named
116 foreach (Assembly a in RootNamespace.Global.Assemblies) {
117 AssemblyName ref_name = a.GetName ();
118 byte [] b = ref_name.GetPublicKeyToken ();
119 if (b == null || b.Length == 0) {
120 Report.Error (1577, "Assembly generation failed " +
121 "-- Referenced assembly '" +
123 "' does not have a strong name.");
124 //Environment.Exit (1);
129 current_domain = AppDomain.CurrentDomain;
132 Assembly.Builder = current_domain.DefineDynamicAssembly (an,
133 AssemblyBuilderAccess.Save, Dirname (name));
135 catch (ArgumentException) {
136 // specified key may not be exportable outside it's container
137 if (RootContext.StrongNameKeyContainer != null) {
138 Report.Error (1548, "Could not access the key inside the container `" +
139 RootContext.StrongNameKeyContainer + "'.");
140 Environment.Exit (1);
144 catch (CryptographicException) {
145 if ((RootContext.StrongNameKeyContainer != null) || (RootContext.StrongNameKeyFile != null)) {
146 Report.Error (1548, "Could not use the specified key to strongname the assembly.");
147 Environment.Exit (1);
153 // Get the complete AssemblyName from the builder
154 // (We need to get the public key and token)
155 Assembly.Name = Assembly.Builder.GetName ();
159 // Pass a path-less name to DefineDynamicModule. Wonder how
160 // this copes with output in different directories then.
161 // FIXME: figure out how this copes with --output /tmp/blah
163 // If the third argument is true, the ModuleBuilder will dynamically
164 // load the default symbol writer.
166 Module.Builder = Assembly.Builder.DefineDynamicModule (
167 Basename (name), Basename (output), false);
169 if (want_debugging_support)
170 InitializeSymbolWriter (output);
175 static public void Save (string name)
178 Assembly.Builder.Save (Basename (name));
180 if (SymbolWriter != null)
181 SymbolWriter.WriteSymbolFile ();
183 catch (COMException) {
184 if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
187 // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies
188 Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
189 RootContext.StrongNameKeyFile +
190 "', Use MCS with the Mono runtime or CSC to compile this assembly.");
192 catch (System.IO.IOException io) {
193 Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
195 catch (System.UnauthorizedAccessException ua) {
196 Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message);
202 public interface IResolveContext
204 DeclSpace DeclContainer { get; }
205 bool IsInObsoleteScope { get; }
206 bool IsInUnsafeScope { get; }
208 // the declcontainer to lookup for type-parameters. Should only use LookupGeneric on it.
210 // FIXME: This is somewhat of a hack. We don't need a full DeclSpace for this. We just need the
211 // current type parameters in scope. IUIC, that will require us to rewrite GenericMethod.
212 // Maybe we can replace this with a 'LookupGeneric (string)' instead, but we'll have to
213 // handle generic method overrides differently
214 DeclSpace GenericDeclContainer { get; }
218 /// An Emit Context is created for each body of code (from methods,
219 /// properties bodies, indexer bodies or constructor bodies)
221 public class EmitContext : IResolveContext {
224 public DeclSpace TypeContainer;
225 public ILGenerator ig;
228 public enum Flags : byte {
230 /// This flag tracks the `checked' state of the compilation,
231 /// it controls whether we should generate code that does overflow
232 /// checking, or if we generate code that ignores overflows.
234 /// The default setting comes from the command line option to generate
235 /// checked or unchecked code plus any source code changes using the
236 /// checked/unchecked statements or expressions. Contrast this with
237 /// the ConstantCheckState flag.
242 /// The constant check state is always set to `true' and cant be changed
243 /// from the command line. The source code can change this setting with
244 /// the `checked' and `unchecked' statements and expressions.
246 ConstantCheckState = 1 << 1,
248 AllCheckStateFlags = CheckState | ConstantCheckState,
251 /// Whether we are inside an unsafe block
259 /// Whether control flow analysis is enabled
261 DoFlowAnalysis = 1 << 5,
264 /// Whether control flow analysis is disabled on structs
265 /// (only meaningful when DoFlowAnalysis is set)
267 OmitStructFlowAnalysis = 1 << 6
273 /// Whether we are emitting code inside a static or instance method
275 public bool IsStatic;
278 /// Whether the actual created method is static or instance method.
279 /// Althoug the method might be declared as `static', if an anonymous
280 /// method is involved, we might turn this into an instance method.
282 /// So this reflects the low-level staticness of the method, while
283 /// IsStatic represents the semantic, high-level staticness.
285 public bool MethodIsStatic;
288 /// Whether we are emitting a field initializer
290 public bool IsFieldInitializer;
293 /// The value that is allowed to be returned or NULL if there is no
296 public readonly Type ReturnType;
299 /// Points to the Type (extracted from the TypeContainer) that
300 /// declares this body of code
302 public Type ContainerType;
305 /// Whether this is generating code for a constructor
307 public bool IsConstructor;
310 /// Keeps track of the Type to LocalBuilder temporary storage created
311 /// to store structures (used to compute the address of the structure
312 /// value on structure method invocations)
314 public Hashtable temporary_storage;
316 public Block CurrentBlock;
318 public int CurrentFile;
321 /// The location where we store the return value.
323 LocalBuilder return_value;
326 /// The location where return has to jump to return the
329 public Label ReturnLabel;
332 /// If we already defined the ReturnLabel
334 public bool HasReturnLabel;
337 /// Whether we are inside an iterator block.
339 public bool InIterator;
341 public bool IsLastStatement;
344 /// Whether we are in a `fixed' initialization
346 public bool InFixedInitializer;
349 /// Whether we are inside an anonymous method.
351 public AnonymousContainer CurrentAnonymousMethod;
354 /// Location for this EmitContext
359 /// Inside an enum definition, we do not resolve enumeration values
360 /// to their enumerations, but rather to the underlying type/value
361 /// This is so EnumVal + EnumValB can be evaluated.
363 /// There is no "E operator + (E x, E y)", so during an enum evaluation
364 /// we relax the rules
366 public bool InEnumContext;
368 public readonly IResolveContext ResolveContext;
371 /// The current iterator
373 public Iterator CurrentIterator {
374 get { return CurrentAnonymousMethod as Iterator; }
378 /// Whether we are in the resolving stage or not
386 public static EmitContext TempEc;
388 bool isAnonymousMethodAllowed = true;
391 FlowBranching current_flow_branching;
393 static int next_id = 0;
396 public override string ToString ()
398 return String.Format ("EmitContext ({0}:{1})", id,
399 CurrentAnonymousMethod, loc);
402 public EmitContext (IResolveContext rc, DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig,
403 Type return_type, int code_flags, bool is_constructor)
405 this.ResolveContext = rc;
408 TypeContainer = parent;
410 if (RootContext.Checked)
411 flags |= Flags.CheckState;
412 flags |= Flags.ConstantCheckState;
415 if ((return_type is TypeBuilder) && return_type.IsGenericTypeDefinition)
416 throw new InternalErrorException ();
419 IsStatic = (code_flags & Modifiers.STATIC) != 0;
420 MethodIsStatic = IsStatic;
421 InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0;
422 ReturnType = return_type;
423 IsConstructor = is_constructor;
426 current_phase = Phase.Created;
429 // Can only be null for the ResolveType contexts.
430 ContainerType = parent.TypeBuilder;
431 if (rc.IsInUnsafeScope)
432 flags |= Flags.InUnsafe;
436 if (ReturnType == TypeManager.void_type)
440 public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
441 Type return_type, int code_flags, bool is_constructor)
442 : this (rc, ds, ds, l, ig, return_type, code_flags, is_constructor)
446 public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
447 Type return_type, int code_flags)
448 : this (rc, ds, ds, l, ig, return_type, code_flags, false)
452 public DeclSpace DeclContainer {
453 get { return declSpace; }
454 set { declSpace = value; }
457 public DeclSpace GenericDeclContainer {
458 get { return DeclContainer; }
461 public bool CheckState {
462 get { return (flags & Flags.CheckState) != 0; }
465 public bool ConstantCheckState {
466 get { return (flags & Flags.ConstantCheckState) != 0; }
469 public bool InUnsafe {
470 get { return (flags & Flags.InUnsafe) != 0; }
473 public bool InCatch {
474 get { return (flags & Flags.InCatch) != 0; }
477 public bool InFinally {
478 get { return (flags & Flags.InFinally) != 0; }
481 public bool DoFlowAnalysis {
482 get { return (flags & Flags.DoFlowAnalysis) != 0; }
485 public bool OmitStructFlowAnalysis {
486 get { return (flags & Flags.OmitStructFlowAnalysis) != 0; }
489 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
490 // it's public so that we can use a struct at the callsite
491 public struct FlagsHandle : IDisposable
494 Flags invmask, oldval;
495 internal FlagsHandle (EmitContext ec, Flags mask, Flags val)
499 oldval = ec.flags & mask;
500 ec.flags = (ec.flags & invmask) | (val & mask);
502 public void Dispose ()
504 ec.flags = (ec.flags & invmask) | oldval;
508 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
509 public FlagsHandle With (Flags bits, bool enable)
511 return new FlagsHandle (this, bits, enable ? bits : 0);
514 public FlagsHandle WithFlowAnalysis (bool do_flow_analysis, bool omit_struct_analysis)
517 (do_flow_analysis ? Flags.DoFlowAnalysis : 0) |
518 (omit_struct_analysis ? Flags.OmitStructFlowAnalysis : 0);
519 return new FlagsHandle (this, Flags.DoFlowAnalysis | Flags.OmitStructFlowAnalysis, newflags);
522 public bool IsInObsoleteScope {
523 get { return ResolveContext.IsInObsoleteScope; }
526 public bool IsInUnsafeScope {
527 get { return InUnsafe || ResolveContext.IsInUnsafeScope; }
530 public bool IsAnonymousMethodAllowed {
531 get { return isAnonymousMethodAllowed; }
532 set { isAnonymousMethodAllowed = value; }
535 public FlowBranching CurrentBranching {
536 get { return current_flow_branching; }
540 // Starts a new code branching. This inherits the state of all local
541 // variables and parameters from the current branching.
543 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
545 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
546 return current_flow_branching;
550 // Starts a new code branching for block `block'.
552 public FlowBranching StartFlowBranching (Block block)
554 FlowBranching.BranchingType type;
556 if ((CurrentBranching != null) &&
557 (CurrentBranching.Type == FlowBranching.BranchingType.Switch))
558 type = FlowBranching.BranchingType.SwitchSection;
560 type = FlowBranching.BranchingType.Block;
562 flags |= Flags.DoFlowAnalysis;
564 current_flow_branching = FlowBranching.CreateBranching (
565 CurrentBranching, type, block, block.StartLocation);
566 return current_flow_branching;
569 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
571 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
572 current_flow_branching = branching;
576 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
578 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
579 current_flow_branching = branching;
583 public FlowBranchingToplevel StartFlowBranching (ToplevelBlock stmt)
585 FlowBranchingToplevel branching = new FlowBranchingToplevel (CurrentBranching, stmt);
586 current_flow_branching = branching;
591 // Ends a code branching. Merges the state of locals and parameters
592 // from all the children of the ending branching.
594 public FlowBranching.UsageVector DoEndFlowBranching ()
596 FlowBranching old = current_flow_branching;
597 current_flow_branching = current_flow_branching.Parent;
599 return current_flow_branching.MergeChild (old);
603 // Ends a code branching. Merges the state of locals and parameters
604 // from all the children of the ending branching.
606 public FlowBranching.Reachability EndFlowBranching ()
608 FlowBranching.UsageVector vector = DoEndFlowBranching ();
610 return vector.Reachability;
614 // Kills the current code branching. This throws away any changed state
615 // information and should only be used in case of an error.
617 public void KillFlowBranching ()
619 current_flow_branching = current_flow_branching.Parent;
622 public bool MustCaptureVariable (LocalInfo local)
624 if (CurrentAnonymousMethod == null)
626 if (CurrentAnonymousMethod.IsIterator)
628 return local.Block.Toplevel != CurrentBlock.Toplevel;
631 public void EmitMeta (ToplevelBlock b)
636 ReturnLabel = ig.DefineLabel ();
640 // Here until we can fix the problem with Mono.CSharp.Switch, which
641 // currently can not cope with ig == null during resolve (which must
642 // be fixed for switch statements to work on anonymous methods).
644 public void EmitTopBlock (IMethodData md, ToplevelBlock block)
651 if (ResolveTopBlock (null, block, md.ParameterInfo, md, out unreachable)){
654 current_phase = Phase.Emitting;
655 EmitResolvedTopBlock (block, unreachable);
661 public bool ResolveTopBlock (EmitContext anonymous_method_host, ToplevelBlock block,
662 Parameters ip, IMethodData md, out bool unreachable)
664 current_phase = Phase.Resolving;
672 CurrentFile = loc.File;
677 if (!block.ResolveMeta (this, ip))
680 if ((md != null) && (md.Iterator != null)) {
681 if (!md.Iterator.Resolve (this))
685 using (this.With (EmitContext.Flags.DoFlowAnalysis, true)) {
686 FlowBranchingToplevel top_level;
687 if (anonymous_method_host != null)
688 top_level = new FlowBranchingToplevel (anonymous_method_host.CurrentBranching, block);
690 top_level = block.TopLevelBranching;
692 current_flow_branching = top_level;
693 bool ok = block.Resolve (this);
694 current_flow_branching = null;
699 FlowBranching.Reachability reachability = top_level.End ();
700 if (reachability.IsUnreachable)
704 } catch (Exception e) {
705 Console.WriteLine ("Exception caught by the compiler while compiling:");
706 Console.WriteLine (" Block that caused the problem begin at: " + loc);
708 if (CurrentBlock != null){
709 Console.WriteLine (" Block being compiled: [{0},{1}]",
710 CurrentBlock.StartLocation, CurrentBlock.EndLocation);
712 Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
717 if (ReturnType != null && !unreachable) {
718 if (CurrentAnonymousMethod == null) {
719 Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
721 } else if (!CurrentAnonymousMethod.IsIterator) {
722 Report.Error (1643, CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
723 CurrentAnonymousMethod.GetSignatureForError ());
728 if (!block.CompleteContexts (this))
735 public void EmitResolvedTopBlock (ToplevelBlock block, bool unreachable)
741 ig.MarkLabel (ReturnLabel);
743 if (return_value != null){
744 ig.Emit (OpCodes.Ldloc, return_value);
745 ig.Emit (OpCodes.Ret);
748 // If `HasReturnLabel' is set, then we already emitted a
749 // jump to the end of the method, so we must emit a `ret'
752 // Unfortunately, System.Reflection.Emit automatically emits
753 // a leave to the end of a finally block. This is a problem
754 // if no code is following the try/finally block since we may
755 // jump to a point after the end of the method.
756 // As a workaround, we're always creating a return label in
760 bool in_iterator = (CurrentAnonymousMethod != null) &&
761 CurrentAnonymousMethod.IsIterator && InIterator;
763 if ((block != null) && block.IsDestructor) {
764 // Nothing to do; S.R.E automatically emits a leave.
765 } else if (HasReturnLabel || (!unreachable && !in_iterator)) {
766 if (ReturnType != null)
767 ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
768 ig.Emit (OpCodes.Ret);
774 /// This is called immediately before emitting an IL opcode to tell the symbol
775 /// writer to which source line this opcode belongs.
777 public void Mark (Location loc, bool check_file)
779 if ((CodeGen.SymbolWriter == null) || loc.IsNull)
782 if (check_file && (CurrentFile != loc.File))
785 CodeGen.SymbolWriter.MarkSequencePoint (ig, loc.Row, loc.Column);
788 public void DefineLocalVariable (string name, LocalBuilder builder)
790 if (CodeGen.SymbolWriter == null)
793 CodeGen.SymbolWriter.DefineLocalVariable (name, builder);
796 public void BeginScope ()
800 if (CodeGen.SymbolWriter != null)
801 CodeGen.SymbolWriter.OpenScope(ig);
804 public void EndScope ()
808 if (CodeGen.SymbolWriter != null)
809 CodeGen.SymbolWriter.CloseScope(ig);
813 /// Returns a temporary storage for a variable of type t as
814 /// a local variable in the current body.
816 public LocalBuilder GetTemporaryLocal (Type t)
818 if (temporary_storage != null) {
819 object o = temporary_storage [t];
823 o = s.Count == 0 ? null : s.Pop ();
825 temporary_storage.Remove (t);
829 return (LocalBuilder) o;
831 return ig.DeclareLocal (t);
834 public void FreeTemporaryLocal (LocalBuilder b, Type t)
838 if (temporary_storage == null) {
839 temporary_storage = new Hashtable ();
840 temporary_storage [t] = b;
843 object o = temporary_storage [t];
845 temporary_storage [t] = b;
853 temporary_storage [t] = s;
859 /// Current loop begin and end labels.
861 public Label LoopBegin, LoopEnd;
864 /// Default target in a switch statement. Only valid if
867 public Label DefaultTarget;
870 /// If this is non-null, points to the current switch statement
872 public Switch Switch;
875 /// ReturnValue creates on demand the LocalBuilder for the
876 /// return value from the function. By default this is not
877 /// used. This is only required when returns are found inside
878 /// Try or Catch statements.
880 /// This method is typically invoked from the Emit phase, so
881 /// we allow the creation of a return label if it was not
882 /// requested during the resolution phase. Could be cleaned
883 /// up, but it would replicate a lot of logic in the Emit phase
884 /// of the code that uses it.
886 public LocalBuilder TemporaryReturn ()
888 if (return_value == null){
889 return_value = ig.DeclareLocal (ReturnType);
890 if (!HasReturnLabel){
891 ReturnLabel = ig.DefineLabel ();
892 HasReturnLabel = true;
900 /// This method is used during the Resolution phase to flag the
901 /// need to define the ReturnLabel
903 public void NeedReturnLabel ()
905 if (current_phase != Phase.Resolving){
907 // The reason is that the `ReturnLabel' is declared between
908 // resolution and emission
910 throw new Exception ("NeedReturnLabel called from Emit phase, should only be called during Resolve");
913 if (!InIterator && !HasReturnLabel)
914 HasReturnLabel = true;
918 public Expression GetThis (Location loc)
921 if (CurrentBlock != null)
922 my_this = new This (CurrentBlock, loc);
924 my_this = new This (loc);
926 if (!my_this.ResolveBase (this))
934 public abstract class CommonAssemblyModulClass : Attributable, IResolveContext {
936 protected CommonAssemblyModulClass ():
941 public void AddAttributes (ArrayList attrs)
943 foreach (Attribute a in attrs)
946 if (attributes == null) {
947 attributes = new Attributes (attrs);
950 attributes.AddAttributes (attrs);
953 public virtual void Emit (TypeContainer tc)
955 if (OptAttributes == null)
958 OptAttributes.Emit ();
961 protected Attribute ResolveAttribute (Type a_type)
963 Attribute a = OptAttributes.Search (a_type);
970 public override IResolveContext ResolveContext {
974 #region IResolveContext Members
976 public DeclSpace DeclContainer {
977 get { return RootContext.ToplevelTypes; }
980 public DeclSpace GenericDeclContainer {
981 get { return DeclContainer; }
984 public bool IsInObsoleteScope {
985 get { return false; }
988 public bool IsInUnsafeScope {
989 get { return false; }
995 public class AssemblyClass : CommonAssemblyModulClass {
996 // TODO: make it private and move all builder based methods here
997 public AssemblyBuilder Builder;
998 bool is_cls_compliant;
999 bool wrap_non_exception_throws;
1000 bool has_extension_method;
1002 public Attribute ClsCompliantAttribute;
1004 ListDictionary declarative_security;
1006 public AssemblyName Name;
1007 MethodInfo add_type_forwarder;
1008 ListDictionary emitted_forwarders;
1011 // Module is here just because of error messages
1012 static string[] attribute_targets = new string [] { "assembly", "module" };
1014 public AssemblyClass (): base ()
1017 wrap_non_exception_throws = true;
1021 public bool HasExtensionMethods {
1022 set { has_extension_method = value; }
1025 public bool IsClsCompliant {
1027 return is_cls_compliant;
1031 public bool WrapNonExceptionThrows {
1033 return wrap_non_exception_throws;
1037 public override AttributeTargets AttributeTargets {
1039 return AttributeTargets.Assembly;
1043 public override bool IsClsComplianceRequired ()
1045 return is_cls_compliant;
1048 public void Resolve ()
1050 if (OptAttributes == null)
1053 // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
1054 if (!OptAttributes.CheckTargets())
1057 ClsCompliantAttribute = ResolveAttribute (TypeManager.cls_compliant_attribute_type);
1058 if (ClsCompliantAttribute != null) {
1059 is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue ();
1063 Attribute a = ResolveAttribute (TypeManager.runtime_compatibility_attr_type);
1065 object val = a.GetPropertyValue ("WrapNonExceptionThrows");
1067 wrap_non_exception_throws = (bool)val;
1073 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob)
1076 // check for possible ECMA key
1077 if (strongNameBlob.Length == 16) {
1078 // will be rejected if not "the" ECMA key
1079 an.SetPublicKey (strongNameBlob);
1082 // take it, with or without, a private key
1083 RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
1084 // and make sure we only feed the public part to Sys.Ref
1085 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
1087 // AssemblyName.SetPublicKey requires an additional header
1088 byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
1090 byte[] encodedPublicKey = new byte [12 + publickey.Length];
1091 Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
1092 Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
1093 an.SetPublicKey (encodedPublicKey);
1097 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded");
1098 Environment.Exit (1);
1102 // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
1103 public AssemblyName GetAssemblyName (string name, string output)
1105 if (OptAttributes != null) {
1106 foreach (Attribute a in OptAttributes.Attrs) {
1107 // cannot rely on any resolve-based members before you call Resolve
1108 if (a.ExplicitTarget == null || a.ExplicitTarget != "assembly")
1111 // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
1112 // However, this is invoked by CodeGen.Init, when none of the namespaces
1114 // TODO: Does not handle quoted attributes properly
1116 case "AssemblyKeyFile":
1117 case "AssemblyKeyFileAttribute":
1118 case "System.Reflection.AssemblyKeyFileAttribute":
1119 if (RootContext.StrongNameKeyFile != null) {
1120 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1121 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1122 "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
1125 string value = a.GetString ();
1126 if (value.Length != 0)
1127 RootContext.StrongNameKeyFile = value;
1130 case "AssemblyKeyName":
1131 case "AssemblyKeyNameAttribute":
1132 case "System.Reflection.AssemblyKeyNameAttribute":
1133 if (RootContext.StrongNameKeyContainer != null) {
1134 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1135 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1136 "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
1139 string value = a.GetString ();
1140 if (value.Length != 0)
1141 RootContext.StrongNameKeyContainer = value;
1144 case "AssemblyDelaySign":
1145 case "AssemblyDelaySignAttribute":
1146 case "System.Reflection.AssemblyDelaySignAttribute":
1147 RootContext.StrongNameDelaySign = a.GetBoolean ();
1153 AssemblyName an = new AssemblyName ();
1154 an.Name = Path.GetFileNameWithoutExtension (name);
1156 // note: delay doesn't apply when using a key container
1157 if (RootContext.StrongNameKeyContainer != null) {
1158 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
1162 // strongname is optional
1163 if (RootContext.StrongNameKeyFile == null)
1166 string AssemblyDir = Path.GetDirectoryName (output);
1168 // the StrongName key file may be relative to (a) the compiled
1169 // file or (b) to the output assembly. See bugzilla #55320
1170 // http://bugzilla.ximian.com/show_bug.cgi?id=55320
1172 // (a) relative to the compiled file
1173 string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
1174 bool exist = File.Exists (filename);
1175 if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
1176 // (b) relative to the outputed assembly
1177 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
1178 exist = File.Exists (filename);
1182 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
1183 byte[] snkeypair = new byte [fs.Length];
1184 fs.Read (snkeypair, 0, snkeypair.Length);
1186 if (RootContext.StrongNameDelaySign) {
1187 // delayed signing - DO NOT include private key
1188 SetPublicKey (an, snkeypair);
1191 // no delay so we make sure we have the private key
1193 CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
1194 an.KeyPair = new StrongNameKeyPair (snkeypair);
1196 catch (CryptographicException) {
1197 if (snkeypair.Length == 16) {
1198 // error # is different for ECMA key
1199 Report.Error (1606, "Could not sign the assembly. " +
1200 "ECMA key can only be used to delay-sign assemblies");
1203 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not have a private key");
1211 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not exist");
1217 void Error_AssemblySigning (string text)
1219 Report.Error (1548, "Error during assembly signing. " + text);
1223 bool CheckInternalsVisibleAttribute (Attribute a)
1225 string assembly_name = a.GetString ();
1226 if (assembly_name.Length == 0)
1229 AssemblyName aname = null;
1231 aname = new AssemblyName (assembly_name);
1232 } catch (FileLoadException) {
1233 } catch (ArgumentException) {
1236 // Bad assembly name format
1238 Report.Warning (1700, 3, a.Location, "Assembly reference `" + assembly_name + "' is invalid and cannot be resolved");
1239 // Report error if we have defined Version or Culture
1240 else if (aname.Version != null || aname.CultureInfo != null)
1241 throw new Exception ("Friend assembly `" + a.GetString () +
1242 "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
1243 else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null) {
1244 Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." +
1245 " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
1253 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1255 if (a.Type.IsSubclassOf (TypeManager.security_attr_type) && a.CheckSecurityActionValidity (true)) {
1256 if (declarative_security == null)
1257 declarative_security = new ListDictionary ();
1259 a.ExtractSecurityPermissionSet (declarative_security);
1263 if (a.Type == TypeManager.assembly_culture_attribute_type) {
1264 string value = a.GetString ();
1265 if (value == null || value.Length == 0)
1268 if (RootContext.Target == Target.Exe) {
1269 a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
1275 if (a.Type == TypeManager.internals_visible_attr_type && !CheckInternalsVisibleAttribute (a))
1278 if (a.Type == TypeManager.type_forwarder_attr_type) {
1279 Type t = a.GetArgumentType ();
1280 if (t == null || TypeManager.HasElementType (t)) {
1281 Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
1285 if (emitted_forwarders == null) {
1286 emitted_forwarders = new ListDictionary();
1287 } else if (emitted_forwarders.Contains(t)) {
1288 Report.SymbolRelatedToPreviousError(((Attribute)emitted_forwarders[t]).Location, null);
1289 Report.Error(739, a.Location, "A duplicate type forward of type `{0}'",
1290 TypeManager.CSharpName(t));
1294 emitted_forwarders.Add(t, a);
1296 if (TypeManager.LookupDeclSpace (t) != null) {
1297 Report.SymbolRelatedToPreviousError (t);
1298 Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
1299 TypeManager.CSharpName (t));
1304 Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
1305 TypeManager.CSharpName (t));
1309 if (t.IsGenericType) {
1310 Report.Error (733, a.Location, "Cannot forward generic type `{0}'", TypeManager.CSharpName (t));
1314 if (add_type_forwarder == null) {
1315 add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder",
1316 BindingFlags.NonPublic | BindingFlags.Instance);
1318 if (add_type_forwarder == null) {
1319 Report.RuntimeMissingSupport (a.Location, "TypeForwardedTo attribute");
1324 add_type_forwarder.Invoke (Builder, new object[] { t });
1328 if (a.Type == TypeManager.extension_attribute_type) {
1329 a.Error_MisusedExtensionAttribute ();
1333 Builder.SetCustomAttribute (customBuilder);
1336 public override void Emit (TypeContainer tc)
1341 if (has_extension_method)
1342 Builder.SetCustomAttribute (TypeManager.extension_attribute_attr);
1344 // FIXME: Does this belong inside SRE.AssemblyBuilder instead?
1345 if (OptAttributes == null || !OptAttributes.Contains (TypeManager.runtime_compatibility_attr_type)) {
1346 ConstructorInfo ci = TypeManager.GetConstructor (
1347 TypeManager.runtime_compatibility_attr_type, Type.EmptyTypes);
1348 PropertyInfo [] pis = new PropertyInfo [1];
1349 pis [0] = TypeManager.GetProperty (
1350 TypeManager.runtime_compatibility_attr_type, "WrapNonExceptionThrows");
1351 object [] pargs = new object [1];
1353 Builder.SetCustomAttribute (new CustomAttributeBuilder (ci, new object [0], pis, pargs));
1357 if (declarative_security != null) {
1359 MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1360 object builder_instance = Builder;
1363 // Microsoft runtime hacking
1364 if (add_permission == null) {
1365 Type assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData");
1366 add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1368 FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
1369 builder_instance = fi.GetValue (Builder);
1372 object[] args = new object [] { declarative_security [SecurityAction.RequestMinimum],
1373 declarative_security [SecurityAction.RequestOptional],
1374 declarative_security [SecurityAction.RequestRefuse] };
1375 add_permission.Invoke (builder_instance, args);
1378 Report.RuntimeMissingSupport (Location.Null, "assembly permission setting");
1383 public override string[] ValidAttributeTargets {
1385 return attribute_targets;
1389 // Wrapper for AssemblyBuilder.AddModule
1390 static MethodInfo adder_method;
1391 static public MethodInfo AddModule_Method {
1393 if (adder_method == null)
1394 adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
1395 return adder_method;
1398 public Module AddModule (string module)
1400 MethodInfo m = AddModule_Method;
1402 Report.RuntimeMissingSupport (Location.Null, "/addmodule");
1403 Environment.Exit (1);
1407 return (Module) m.Invoke (Builder, new object [] { module });
1408 } catch (TargetInvocationException ex) {
1409 throw ex.InnerException;
1414 public class ModuleClass : CommonAssemblyModulClass {
1415 // TODO: make it private and move all builder based methods here
1416 public ModuleBuilder Builder;
1417 bool m_module_is_unsafe;
1418 bool has_default_charset;
1420 public CharSet DefaultCharSet = CharSet.Ansi;
1421 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
1423 static string[] attribute_targets = new string [] { "module" };
1425 public ModuleClass (bool is_unsafe)
1427 m_module_is_unsafe = is_unsafe;
1430 public override AttributeTargets AttributeTargets {
1432 return AttributeTargets.Module;
1436 public override bool IsClsComplianceRequired ()
1438 return CodeGen.Assembly.IsClsCompliant;
1441 public override void Emit (TypeContainer tc)
1445 if (!m_module_is_unsafe)
1448 if (TypeManager.unverifiable_code_ctor == null) {
1449 Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute.");
1453 Builder.SetCustomAttribute (new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
1456 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1458 if (a.Type == TypeManager.cls_compliant_attribute_type) {
1459 if (CodeGen.Assembly.ClsCompliantAttribute == null) {
1460 Report.Warning (3012, 1, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
1462 else if (CodeGen.Assembly.IsClsCompliant != a.GetBoolean ()) {
1463 Report.SymbolRelatedToPreviousError (CodeGen.Assembly.ClsCompliantAttribute.Location, CodeGen.Assembly.ClsCompliantAttribute.GetSignatureForError ());
1464 Report.Error (3017, a.Location, "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
1469 Builder.SetCustomAttribute (customBuilder);
1472 public bool HasDefaultCharSet {
1474 return has_default_charset;
1479 /// It is called very early therefore can resolve only predefined attributes
1481 public void Resolve ()
1484 if (OptAttributes == null)
1487 if (!OptAttributes.CheckTargets())
1490 Attribute a = ResolveAttribute (TypeManager.default_charset_type);
1492 has_default_charset = true;
1493 DefaultCharSet = a.GetCharSetValue ();
1494 switch (DefaultCharSet) {
1499 DefaultCharSetType = TypeAttributes.AutoClass;
1501 case CharSet.Unicode:
1502 DefaultCharSetType = TypeAttributes.UnicodeClass;
1505 Report.Error (1724, a.Location, "Value specified for the argument to 'System.Runtime.InteropServices.DefaultCharSetAttribute' is not valid");
1512 public override string[] ValidAttributeTargets {
1514 return attribute_targets;