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 bool isAnonymousMethodAllowed = true;
389 FlowBranching current_flow_branching;
391 static int next_id = 0;
394 public override string ToString ()
396 return String.Format ("EmitContext ({0}:{1})", id,
397 CurrentAnonymousMethod, loc);
400 public EmitContext (IResolveContext rc, DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig,
401 Type return_type, int code_flags, bool is_constructor)
403 this.ResolveContext = rc;
406 TypeContainer = parent;
408 if (RootContext.Checked)
409 flags |= Flags.CheckState;
410 flags |= Flags.ConstantCheckState;
413 if ((return_type is TypeBuilder) && return_type.IsGenericTypeDefinition)
414 throw new InternalErrorException ();
417 IsStatic = (code_flags & Modifiers.STATIC) != 0;
418 MethodIsStatic = IsStatic;
419 InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0;
420 ReturnType = return_type;
421 IsConstructor = is_constructor;
424 current_phase = Phase.Created;
427 // Can only be null for the ResolveType contexts.
428 ContainerType = parent.TypeBuilder;
429 if (rc.IsInUnsafeScope)
430 flags |= Flags.InUnsafe;
434 if (ReturnType == TypeManager.void_type)
438 public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
439 Type return_type, int code_flags, bool is_constructor)
440 : this (rc, ds, ds, l, ig, return_type, code_flags, is_constructor)
444 public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
445 Type return_type, int code_flags)
446 : this (rc, ds, ds, l, ig, return_type, code_flags, false)
450 public DeclSpace DeclContainer {
451 get { return declSpace; }
452 set { declSpace = value; }
455 public DeclSpace GenericDeclContainer {
456 get { return DeclContainer; }
459 public bool CheckState {
460 get { return (flags & Flags.CheckState) != 0; }
463 public bool ConstantCheckState {
464 get { return (flags & Flags.ConstantCheckState) != 0; }
467 public bool InUnsafe {
468 get { return (flags & Flags.InUnsafe) != 0; }
471 public bool InCatch {
472 get { return (flags & Flags.InCatch) != 0; }
475 public bool InFinally {
476 get { return (flags & Flags.InFinally) != 0; }
479 public bool DoFlowAnalysis {
480 get { return (flags & Flags.DoFlowAnalysis) != 0; }
483 public bool OmitStructFlowAnalysis {
484 get { return (flags & Flags.OmitStructFlowAnalysis) != 0; }
487 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
488 // it's public so that we can use a struct at the callsite
489 public struct FlagsHandle : IDisposable
492 Flags invmask, oldval;
493 internal FlagsHandle (EmitContext ec, Flags mask, Flags val)
497 oldval = ec.flags & mask;
498 ec.flags = (ec.flags & invmask) | (val & mask);
500 public void Dispose ()
502 ec.flags = (ec.flags & invmask) | oldval;
506 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
507 public FlagsHandle With (Flags bits, bool enable)
509 return new FlagsHandle (this, bits, enable ? bits : 0);
512 public FlagsHandle WithFlowAnalysis (bool do_flow_analysis, bool omit_struct_analysis)
515 (do_flow_analysis ? Flags.DoFlowAnalysis : 0) |
516 (omit_struct_analysis ? Flags.OmitStructFlowAnalysis : 0);
517 return new FlagsHandle (this, Flags.DoFlowAnalysis | Flags.OmitStructFlowAnalysis, newflags);
520 public bool IsInObsoleteScope {
521 get { return ResolveContext.IsInObsoleteScope; }
524 public bool IsInUnsafeScope {
525 get { return InUnsafe || ResolveContext.IsInUnsafeScope; }
528 public bool IsAnonymousMethodAllowed {
529 get { return isAnonymousMethodAllowed; }
530 set { isAnonymousMethodAllowed = value; }
533 public FlowBranching CurrentBranching {
534 get { return current_flow_branching; }
538 // Starts a new code branching. This inherits the state of all local
539 // variables and parameters from the current branching.
541 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
543 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
544 return current_flow_branching;
548 // Starts a new code branching for block `block'.
550 public FlowBranching StartFlowBranching (Block block)
552 FlowBranching.BranchingType type;
554 if ((CurrentBranching != null) &&
555 (CurrentBranching.Type == FlowBranching.BranchingType.Switch))
556 type = FlowBranching.BranchingType.SwitchSection;
558 type = FlowBranching.BranchingType.Block;
560 flags |= Flags.DoFlowAnalysis;
562 current_flow_branching = FlowBranching.CreateBranching (
563 CurrentBranching, type, block, block.StartLocation);
564 return current_flow_branching;
567 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
569 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
570 current_flow_branching = branching;
574 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
576 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
577 current_flow_branching = branching;
581 public FlowBranchingToplevel StartFlowBranching (ToplevelBlock stmt)
583 FlowBranchingToplevel branching = new FlowBranchingToplevel (CurrentBranching, stmt);
584 current_flow_branching = branching;
589 // Ends a code branching. Merges the state of locals and parameters
590 // from all the children of the ending branching.
592 public FlowBranching.UsageVector DoEndFlowBranching ()
594 FlowBranching old = current_flow_branching;
595 current_flow_branching = current_flow_branching.Parent;
597 return current_flow_branching.MergeChild (old);
601 // Ends a code branching. Merges the state of locals and parameters
602 // from all the children of the ending branching.
604 public FlowBranching.Reachability EndFlowBranching ()
606 FlowBranching.UsageVector vector = DoEndFlowBranching ();
608 return vector.Reachability;
612 // Kills the current code branching. This throws away any changed state
613 // information and should only be used in case of an error.
615 public void KillFlowBranching ()
617 current_flow_branching = current_flow_branching.Parent;
620 public bool MustCaptureVariable (LocalInfo local)
622 if (CurrentAnonymousMethod == null)
624 if (CurrentAnonymousMethod.IsIterator)
626 return local.Block.Toplevel != CurrentBlock.Toplevel;
629 public void EmitMeta (ToplevelBlock b)
634 ReturnLabel = ig.DefineLabel ();
638 // Here until we can fix the problem with Mono.CSharp.Switch, which
639 // currently can not cope with ig == null during resolve (which must
640 // be fixed for switch statements to work on anonymous methods).
642 public void EmitTopBlock (IMethodData md, ToplevelBlock block)
649 if (ResolveTopBlock (null, block, md.ParameterInfo, md, out unreachable)){
652 current_phase = Phase.Emitting;
653 EmitResolvedTopBlock (block, unreachable);
659 public bool ResolveTopBlock (EmitContext anonymous_method_host, ToplevelBlock block,
660 Parameters ip, IMethodData md, out bool unreachable)
662 current_phase = Phase.Resolving;
670 CurrentFile = loc.File;
675 if (!block.ResolveMeta (this, ip))
678 if ((md != null) && (md.Iterator != null)) {
679 if (!md.Iterator.Resolve (this))
683 using (this.With (EmitContext.Flags.DoFlowAnalysis, true)) {
684 FlowBranchingToplevel top_level;
685 if (anonymous_method_host != null)
686 top_level = new FlowBranchingToplevel (anonymous_method_host.CurrentBranching, block);
688 top_level = block.TopLevelBranching;
690 current_flow_branching = top_level;
691 bool ok = block.Resolve (this);
692 current_flow_branching = null;
697 FlowBranching.Reachability reachability = top_level.End ();
698 if (reachability.IsUnreachable)
702 } catch (Exception e) {
703 Console.WriteLine ("Exception caught by the compiler while compiling:");
704 Console.WriteLine (" Block that caused the problem begin at: " + loc);
706 if (CurrentBlock != null){
707 Console.WriteLine (" Block being compiled: [{0},{1}]",
708 CurrentBlock.StartLocation, CurrentBlock.EndLocation);
710 Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
715 if (ReturnType != null && !unreachable) {
716 if (CurrentAnonymousMethod == null) {
717 Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
719 } else if (!CurrentAnonymousMethod.IsIterator) {
720 Report.Error (1643, CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
721 CurrentAnonymousMethod.GetSignatureForError ());
726 if (!block.CompleteContexts (this))
733 public void EmitResolvedTopBlock (ToplevelBlock block, bool unreachable)
739 ig.MarkLabel (ReturnLabel);
741 if (return_value != null){
742 ig.Emit (OpCodes.Ldloc, return_value);
743 ig.Emit (OpCodes.Ret);
746 // If `HasReturnLabel' is set, then we already emitted a
747 // jump to the end of the method, so we must emit a `ret'
750 // Unfortunately, System.Reflection.Emit automatically emits
751 // a leave to the end of a finally block. This is a problem
752 // if no code is following the try/finally block since we may
753 // jump to a point after the end of the method.
754 // As a workaround, we're always creating a return label in
758 bool in_iterator = (CurrentAnonymousMethod != null) &&
759 CurrentAnonymousMethod.IsIterator && InIterator;
761 if ((block != null) && block.IsDestructor) {
762 // Nothing to do; S.R.E automatically emits a leave.
763 } else if (HasReturnLabel || (!unreachable && !in_iterator)) {
764 if (ReturnType != null)
765 ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
766 ig.Emit (OpCodes.Ret);
772 /// This is called immediately before emitting an IL opcode to tell the symbol
773 /// writer to which source line this opcode belongs.
775 public void Mark (Location loc, bool check_file)
777 if ((CodeGen.SymbolWriter == null) || loc.IsNull)
780 if (check_file && (CurrentFile != loc.File))
783 CodeGen.SymbolWriter.MarkSequencePoint (ig, loc.Row, loc.Column);
786 public void DefineLocalVariable (string name, LocalBuilder builder)
788 if (CodeGen.SymbolWriter == null)
791 CodeGen.SymbolWriter.DefineLocalVariable (name, builder);
794 public void BeginScope ()
798 if (CodeGen.SymbolWriter != null)
799 CodeGen.SymbolWriter.OpenScope(ig);
802 public void EndScope ()
806 if (CodeGen.SymbolWriter != null)
807 CodeGen.SymbolWriter.CloseScope(ig);
811 /// Returns a temporary storage for a variable of type t as
812 /// a local variable in the current body.
814 public LocalBuilder GetTemporaryLocal (Type t)
816 if (temporary_storage != null) {
817 object o = temporary_storage [t];
821 o = s.Count == 0 ? null : s.Pop ();
823 temporary_storage.Remove (t);
827 return (LocalBuilder) o;
829 return ig.DeclareLocal (t);
832 public void FreeTemporaryLocal (LocalBuilder b, Type t)
836 if (temporary_storage == null) {
837 temporary_storage = new Hashtable ();
838 temporary_storage [t] = b;
841 object o = temporary_storage [t];
843 temporary_storage [t] = b;
851 temporary_storage [t] = s;
857 /// Current loop begin and end labels.
859 public Label LoopBegin, LoopEnd;
862 /// Default target in a switch statement. Only valid if
865 public Label DefaultTarget;
868 /// If this is non-null, points to the current switch statement
870 public Switch Switch;
873 /// ReturnValue creates on demand the LocalBuilder for the
874 /// return value from the function. By default this is not
875 /// used. This is only required when returns are found inside
876 /// Try or Catch statements.
878 /// This method is typically invoked from the Emit phase, so
879 /// we allow the creation of a return label if it was not
880 /// requested during the resolution phase. Could be cleaned
881 /// up, but it would replicate a lot of logic in the Emit phase
882 /// of the code that uses it.
884 public LocalBuilder TemporaryReturn ()
886 if (return_value == null){
887 return_value = ig.DeclareLocal (ReturnType);
888 if (!HasReturnLabel){
889 ReturnLabel = ig.DefineLabel ();
890 HasReturnLabel = true;
898 /// This method is used during the Resolution phase to flag the
899 /// need to define the ReturnLabel
901 public void NeedReturnLabel ()
903 if (current_phase != Phase.Resolving){
905 // The reason is that the `ReturnLabel' is declared between
906 // resolution and emission
908 throw new Exception ("NeedReturnLabel called from Emit phase, should only be called during Resolve");
911 if (!InIterator && !HasReturnLabel)
912 HasReturnLabel = true;
916 public Expression GetThis (Location loc)
919 if (CurrentBlock != null)
920 my_this = new This (CurrentBlock, loc);
922 my_this = new This (loc);
924 if (!my_this.ResolveBase (this))
932 public abstract class CommonAssemblyModulClass : Attributable, IResolveContext {
934 protected CommonAssemblyModulClass ():
939 public void AddAttributes (ArrayList attrs)
941 foreach (Attribute a in attrs)
944 if (attributes == null) {
945 attributes = new Attributes (attrs);
948 attributes.AddAttributes (attrs);
951 public virtual void Emit (TypeContainer tc)
953 if (OptAttributes == null)
956 OptAttributes.Emit ();
959 protected Attribute ResolveAttribute (Type a_type)
961 Attribute a = OptAttributes.Search (a_type);
968 public override IResolveContext ResolveContext {
972 #region IResolveContext Members
974 public DeclSpace DeclContainer {
975 get { return RootContext.ToplevelTypes; }
978 public DeclSpace GenericDeclContainer {
979 get { return DeclContainer; }
982 public bool IsInObsoleteScope {
983 get { return false; }
986 public bool IsInUnsafeScope {
987 get { return false; }
993 public class AssemblyClass : CommonAssemblyModulClass {
994 // TODO: make it private and move all builder based methods here
995 public AssemblyBuilder Builder;
996 bool is_cls_compliant;
997 bool wrap_non_exception_throws;
999 public Attribute ClsCompliantAttribute;
1001 ListDictionary declarative_security;
1003 public AssemblyName Name;
1004 MethodInfo add_type_forwarder;
1005 ListDictionary emitted_forwarders;
1008 // Module is here just because of error messages
1009 static string[] attribute_targets = new string [] { "assembly", "module" };
1011 public AssemblyClass (): base ()
1014 wrap_non_exception_throws = true;
1018 public bool IsClsCompliant {
1020 return is_cls_compliant;
1024 public bool WrapNonExceptionThrows {
1026 return wrap_non_exception_throws;
1030 public override AttributeTargets AttributeTargets {
1032 return AttributeTargets.Assembly;
1036 public override bool IsClsComplianceRequired ()
1038 return is_cls_compliant;
1041 public void Resolve ()
1043 if (OptAttributes == null)
1046 // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
1047 if (!OptAttributes.CheckTargets())
1050 ClsCompliantAttribute = ResolveAttribute (TypeManager.cls_compliant_attribute_type);
1051 if (ClsCompliantAttribute != null) {
1052 is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue ();
1056 Attribute a = ResolveAttribute (TypeManager.runtime_compatibility_attr_type);
1058 object val = a.GetPropertyValue ("WrapNonExceptionThrows");
1060 wrap_non_exception_throws = (bool)val;
1066 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob)
1069 // check for possible ECMA key
1070 if (strongNameBlob.Length == 16) {
1071 // will be rejected if not "the" ECMA key
1072 an.SetPublicKey (strongNameBlob);
1075 // take it, with or without, a private key
1076 RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
1077 // and make sure we only feed the public part to Sys.Ref
1078 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
1080 // AssemblyName.SetPublicKey requires an additional header
1081 byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
1083 byte[] encodedPublicKey = new byte [12 + publickey.Length];
1084 Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
1085 Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
1086 an.SetPublicKey (encodedPublicKey);
1090 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded");
1091 Environment.Exit (1);
1095 // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
1096 public AssemblyName GetAssemblyName (string name, string output)
1098 if (OptAttributes != null) {
1099 foreach (Attribute a in OptAttributes.Attrs) {
1100 // cannot rely on any resolve-based members before you call Resolve
1101 if (a.ExplicitTarget == null || a.ExplicitTarget != "assembly")
1104 // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
1105 // However, this is invoked by CodeGen.Init, when none of the namespaces
1107 // TODO: Does not handle quoted attributes properly
1109 case "AssemblyKeyFile":
1110 case "AssemblyKeyFileAttribute":
1111 case "System.Reflection.AssemblyKeyFileAttribute":
1112 if (RootContext.StrongNameKeyFile != null) {
1113 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1114 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1115 "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
1118 string value = a.GetString ();
1119 if (value.Length != 0)
1120 RootContext.StrongNameKeyFile = value;
1123 case "AssemblyKeyName":
1124 case "AssemblyKeyNameAttribute":
1125 case "System.Reflection.AssemblyKeyNameAttribute":
1126 if (RootContext.StrongNameKeyContainer != null) {
1127 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1128 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1129 "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
1132 string value = a.GetString ();
1133 if (value.Length != 0)
1134 RootContext.StrongNameKeyContainer = value;
1137 case "AssemblyDelaySign":
1138 case "AssemblyDelaySignAttribute":
1139 case "System.Reflection.AssemblyDelaySignAttribute":
1140 RootContext.StrongNameDelaySign = a.GetBoolean ();
1146 AssemblyName an = new AssemblyName ();
1147 an.Name = Path.GetFileNameWithoutExtension (name);
1149 // note: delay doesn't apply when using a key container
1150 if (RootContext.StrongNameKeyContainer != null) {
1151 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
1155 // strongname is optional
1156 if (RootContext.StrongNameKeyFile == null)
1159 string AssemblyDir = Path.GetDirectoryName (output);
1161 // the StrongName key file may be relative to (a) the compiled
1162 // file or (b) to the output assembly. See bugzilla #55320
1163 // http://bugzilla.ximian.com/show_bug.cgi?id=55320
1165 // (a) relative to the compiled file
1166 string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
1167 bool exist = File.Exists (filename);
1168 if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
1169 // (b) relative to the outputed assembly
1170 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
1171 exist = File.Exists (filename);
1175 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
1176 byte[] snkeypair = new byte [fs.Length];
1177 fs.Read (snkeypair, 0, snkeypair.Length);
1179 if (RootContext.StrongNameDelaySign) {
1180 // delayed signing - DO NOT include private key
1181 SetPublicKey (an, snkeypair);
1184 // no delay so we make sure we have the private key
1186 CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
1187 an.KeyPair = new StrongNameKeyPair (snkeypair);
1189 catch (CryptographicException) {
1190 if (snkeypair.Length == 16) {
1191 // error # is different for ECMA key
1192 Report.Error (1606, "Could not sign the assembly. " +
1193 "ECMA key can only be used to delay-sign assemblies");
1196 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not have a private key");
1204 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not exist");
1210 void Error_AssemblySigning (string text)
1212 Report.Error (1548, "Error during assembly signing. " + text);
1216 bool CheckInternalsVisibleAttribute (Attribute a)
1218 string assembly_name = a.GetString ();
1219 if (assembly_name.Length == 0)
1222 AssemblyName aname = null;
1224 aname = new AssemblyName (assembly_name);
1225 } catch (FileLoadException) {
1226 } catch (ArgumentException) {
1229 // Bad assembly name format
1231 Report.Warning (1700, 3, a.Location, "Assembly reference `" + assembly_name + "' is invalid and cannot be resolved");
1232 // Report error if we have defined Version or Culture
1233 else if (aname.Version != null || aname.CultureInfo != null)
1234 throw new Exception ("Friend assembly `" + a.GetString () +
1235 "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
1236 else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null) {
1237 Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." +
1238 " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
1246 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1248 if (a.Type.IsSubclassOf (TypeManager.security_attr_type) && a.CheckSecurityActionValidity (true)) {
1249 if (declarative_security == null)
1250 declarative_security = new ListDictionary ();
1252 a.ExtractSecurityPermissionSet (declarative_security);
1256 if (a.Type == TypeManager.assembly_culture_attribute_type) {
1257 string value = a.GetString ();
1258 if (value == null || value.Length == 0)
1261 if (RootContext.Target == Target.Exe) {
1262 a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
1268 if (a.Type == TypeManager.internals_visible_attr_type && !CheckInternalsVisibleAttribute (a))
1271 if (a.Type == TypeManager.type_forwarder_attr_type) {
1272 Type t = a.GetArgumentType ();
1273 if (t == null || TypeManager.HasElementType (t)) {
1274 Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
1278 if (emitted_forwarders == null) {
1279 emitted_forwarders = new ListDictionary();
1280 } else if (emitted_forwarders.Contains(t)) {
1281 Report.SymbolRelatedToPreviousError(((Attribute)emitted_forwarders[t]).Location, null);
1282 Report.Error(739, a.Location, "A duplicate type forward of type `{0}'",
1283 TypeManager.CSharpName(t));
1287 emitted_forwarders.Add(t, a);
1289 if (TypeManager.LookupDeclSpace (t) != null) {
1290 Report.SymbolRelatedToPreviousError (t);
1291 Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
1292 TypeManager.CSharpName (t));
1297 Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
1298 TypeManager.CSharpName (t));
1302 if (t.IsGenericType) {
1303 Report.Error (733, a.Location, "Cannot forward generic type `{0}'", TypeManager.CSharpName (t));
1307 if (add_type_forwarder == null) {
1308 add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder",
1309 BindingFlags.NonPublic | BindingFlags.Instance);
1311 if (add_type_forwarder == null) {
1312 Report.RuntimeMissingSupport (a.Location, "TypeForwardedTo attribute");
1317 add_type_forwarder.Invoke (Builder, new object[] { t });
1322 Builder.SetCustomAttribute (customBuilder);
1325 public override void Emit (TypeContainer tc)
1330 // FIXME: Does this belong inside SRE.AssemblyBuilder instead?
1331 if (OptAttributes == null || !OptAttributes.Contains (TypeManager.runtime_compatibility_attr_type)) {
1332 ConstructorInfo ci = TypeManager.GetConstructor (
1333 TypeManager.runtime_compatibility_attr_type, Type.EmptyTypes);
1334 PropertyInfo [] pis = new PropertyInfo [1];
1335 pis [0] = TypeManager.GetProperty (
1336 TypeManager.runtime_compatibility_attr_type, "WrapNonExceptionThrows");
1337 object [] pargs = new object [1];
1339 Builder.SetCustomAttribute (new CustomAttributeBuilder (ci, new object [0], pis, pargs));
1343 if (declarative_security != null) {
1345 MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1346 object builder_instance = Builder;
1349 // Microsoft runtime hacking
1350 if (add_permission == null) {
1351 Type assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData");
1352 add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1354 FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
1355 builder_instance = fi.GetValue (Builder);
1358 object[] args = new object [] { declarative_security [SecurityAction.RequestMinimum],
1359 declarative_security [SecurityAction.RequestOptional],
1360 declarative_security [SecurityAction.RequestRefuse] };
1361 add_permission.Invoke (builder_instance, args);
1364 Report.RuntimeMissingSupport (Location.Null, "assembly permission setting");
1369 public override string[] ValidAttributeTargets {
1371 return attribute_targets;
1375 // Wrapper for AssemblyBuilder.AddModule
1376 static MethodInfo adder_method;
1377 static public MethodInfo AddModule_Method {
1379 if (adder_method == null)
1380 adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
1381 return adder_method;
1384 public Module AddModule (string module)
1386 MethodInfo m = AddModule_Method;
1388 Report.RuntimeMissingSupport (Location.Null, "/addmodule");
1389 Environment.Exit (1);
1393 return (Module) m.Invoke (Builder, new object [] { module });
1394 } catch (TargetInvocationException ex) {
1395 throw ex.InnerException;
1400 public class ModuleClass : CommonAssemblyModulClass {
1401 // TODO: make it private and move all builder based methods here
1402 public ModuleBuilder Builder;
1403 bool m_module_is_unsafe;
1405 public CharSet DefaultCharSet = CharSet.Ansi;
1406 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
1408 static string[] attribute_targets = new string [] { "module" };
1410 public ModuleClass (bool is_unsafe)
1412 m_module_is_unsafe = is_unsafe;
1415 public override AttributeTargets AttributeTargets {
1417 return AttributeTargets.Module;
1421 public override bool IsClsComplianceRequired ()
1423 return CodeGen.Assembly.IsClsCompliant;
1426 public override void Emit (TypeContainer tc)
1430 if (!m_module_is_unsafe)
1433 if (TypeManager.unverifiable_code_ctor == null) {
1434 Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute.");
1438 Builder.SetCustomAttribute (new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
1441 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1443 if (a.Type == TypeManager.cls_compliant_attribute_type) {
1444 if (CodeGen.Assembly.ClsCompliantAttribute == null) {
1445 Report.Warning (3012, 1, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
1447 else if (CodeGen.Assembly.IsClsCompliant != a.GetBoolean ()) {
1448 Report.SymbolRelatedToPreviousError (CodeGen.Assembly.ClsCompliantAttribute.Location, CodeGen.Assembly.ClsCompliantAttribute.GetSignatureForError ());
1449 Report.Error (3017, a.Location, "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
1454 Builder.SetCustomAttribute (customBuilder);
1458 /// It is called very early therefore can resolve only predefined attributes
1460 public void Resolve ()
1463 if (OptAttributes == null)
1466 if (!OptAttributes.CheckTargets())
1469 Attribute a = ResolveAttribute (TypeManager.default_charset_type);
1471 DefaultCharSet = a.GetCharSetValue ();
1472 switch (DefaultCharSet) {
1477 DefaultCharSetType = TypeAttributes.AutoClass;
1479 case CharSet.Unicode:
1480 DefaultCharSetType = TypeAttributes.UnicodeClass;
1483 Report.Error (1724, a.Location, "Value specified for the argument to 'System.Runtime.InteropServices.DefaultCharSetAttribute' is not valid");
1490 public override string[] ValidAttributeTargets {
1492 return attribute_targets;