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 {
223 DeclSpace decl_space;
225 public DeclSpace TypeContainer;
226 public ILGenerator ig;
229 public enum Flags : byte {
231 /// This flag tracks the `checked' state of the compilation,
232 /// it controls whether we should generate code that does overflow
233 /// checking, or if we generate code that ignores overflows.
235 /// The default setting comes from the command line option to generate
236 /// checked or unchecked code plus any source code changes using the
237 /// checked/unchecked statements or expressions. Contrast this with
238 /// the ConstantCheckState flag.
243 /// The constant check state is always set to `true' and cant be changed
244 /// from the command line. The source code can change this setting with
245 /// the `checked' and `unchecked' statements and expressions.
247 ConstantCheckState = 1 << 1,
249 AllCheckStateFlags = CheckState | ConstantCheckState,
252 /// Whether we are inside an unsafe block
260 /// Whether control flow analysis is enabled
262 DoFlowAnalysis = 1 << 5,
265 /// Whether control flow analysis is disabled on structs
266 /// (only meaningful when DoFlowAnalysis is set)
268 OmitStructFlowAnalysis = 1 << 6
274 /// Whether we are emitting code inside a static or instance method
276 public bool IsStatic;
279 /// Whether the actual created method is static or instance method.
280 /// Althoug the method might be declared as `static', if an anonymous
281 /// method is involved, we might turn this into an instance method.
283 /// So this reflects the low-level staticness of the method, while
284 /// IsStatic represents the semantic, high-level staticness.
286 public bool MethodIsStatic;
289 /// Whether we are emitting a field initializer
291 public bool IsFieldInitializer;
294 /// If this is true, then Return and ContextualReturn statements
295 /// will set the ReturnType value based on the expression types
296 /// of each return statement instead of the method return type
297 /// (which is initially null).
299 public bool InferReturnType;
302 /// The value that is allowed to be returned or NULL if there is no
308 /// Points to the Type (extracted from the TypeContainer) that
309 /// declares this body of code
311 public Type ContainerType;
314 /// Whether this is generating code for a constructor
316 public bool IsConstructor;
319 /// Keeps track of the Type to LocalBuilder temporary storage created
320 /// to store structures (used to compute the address of the structure
321 /// value on structure method invocations)
323 public Hashtable temporary_storage;
325 public Block CurrentBlock;
327 public int CurrentFile;
330 /// The location where we store the return value.
332 LocalBuilder return_value;
335 /// The location where return has to jump to return the
338 public Label ReturnLabel;
341 /// If we already defined the ReturnLabel
343 public bool HasReturnLabel;
346 /// Whether we are inside an iterator block.
348 public bool InIterator;
351 /// Whether we are in a `fixed' initialization
353 public bool InFixedInitializer;
356 /// Whether we are inside an anonymous method.
358 public AnonymousContainer CurrentAnonymousMethod;
361 /// Location for this EmitContext
366 /// Inside an enum definition, we do not resolve enumeration values
367 /// to their enumerations, but rather to the underlying type/value
368 /// This is so EnumVal + EnumValB can be evaluated.
370 /// There is no "E operator + (E x, E y)", so during an enum evaluation
371 /// we relax the rules
373 public bool InEnumContext;
375 public readonly IResolveContext ResolveContext;
378 /// The current iterator
380 public Iterator CurrentIterator {
381 get { return CurrentAnonymousMethod as Iterator; }
385 /// Whether we are in the resolving stage or not
393 public static EmitContext TempEc;
395 bool isAnonymousMethodAllowed = true;
398 FlowBranching current_flow_branching;
400 static int next_id = 0;
403 public override string ToString ()
405 return String.Format ("EmitContext ({0}:{1})", id,
406 CurrentAnonymousMethod, loc);
409 public EmitContext (IResolveContext rc, DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig,
410 Type return_type, int code_flags, bool is_constructor)
412 this.ResolveContext = rc;
415 TypeContainer = parent;
416 this.decl_space = ds;
417 if (RootContext.Checked)
418 flags |= Flags.CheckState;
419 flags |= Flags.ConstantCheckState;
422 if ((return_type is TypeBuilder) && return_type.IsGenericTypeDefinition)
423 throw new InternalErrorException ();
426 IsStatic = (code_flags & Modifiers.STATIC) != 0;
427 MethodIsStatic = IsStatic;
428 InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0;
429 ReturnType = return_type;
430 IsConstructor = is_constructor;
433 current_phase = Phase.Created;
436 // Can only be null for the ResolveType contexts.
437 ContainerType = parent.TypeBuilder;
438 if (rc.IsInUnsafeScope)
439 flags |= Flags.InUnsafe;
444 public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
445 Type return_type, int code_flags, bool is_constructor)
446 : this (rc, ds, ds, l, ig, return_type, code_flags, is_constructor)
450 public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
451 Type return_type, int code_flags)
452 : this (rc, ds, ds, l, ig, return_type, code_flags, false)
456 public DeclSpace DeclContainer {
457 get { return decl_space; }
458 set { decl_space = value; }
461 public DeclSpace GenericDeclContainer {
462 get { return DeclContainer; }
465 public bool CheckState {
466 get { return (flags & Flags.CheckState) != 0; }
469 public bool ConstantCheckState {
470 get { return (flags & Flags.ConstantCheckState) != 0; }
473 public bool InUnsafe {
474 get { return (flags & Flags.InUnsafe) != 0; }
477 public bool InCatch {
478 get { return (flags & Flags.InCatch) != 0; }
481 public bool InFinally {
482 get { return (flags & Flags.InFinally) != 0; }
485 public bool DoFlowAnalysis {
486 get { return (flags & Flags.DoFlowAnalysis) != 0; }
489 public bool OmitStructFlowAnalysis {
490 get { return (flags & Flags.OmitStructFlowAnalysis) != 0; }
493 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
494 // it's public so that we can use a struct at the callsite
495 public struct FlagsHandle : IDisposable
498 Flags invmask, oldval;
499 internal FlagsHandle (EmitContext ec, Flags mask, Flags val)
503 oldval = ec.flags & mask;
504 ec.flags = (ec.flags & invmask) | (val & mask);
506 public void Dispose ()
508 ec.flags = (ec.flags & invmask) | oldval;
512 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
513 public FlagsHandle With (Flags bits, bool enable)
515 return new FlagsHandle (this, bits, enable ? bits : 0);
518 public FlagsHandle WithFlowAnalysis (bool do_flow_analysis, bool omit_struct_analysis)
521 (do_flow_analysis ? Flags.DoFlowAnalysis : 0) |
522 (omit_struct_analysis ? Flags.OmitStructFlowAnalysis : 0);
523 return new FlagsHandle (this, Flags.DoFlowAnalysis | Flags.OmitStructFlowAnalysis, newflags);
526 public bool IsInObsoleteScope {
527 get { return ResolveContext.IsInObsoleteScope; }
530 public bool IsInUnsafeScope {
531 get { return InUnsafe || ResolveContext.IsInUnsafeScope; }
534 public bool IsAnonymousMethodAllowed {
535 get { return isAnonymousMethodAllowed; }
536 set { isAnonymousMethodAllowed = value; }
539 public FlowBranching CurrentBranching {
540 get { return current_flow_branching; }
544 // Starts a new code branching. This inherits the state of all local
545 // variables and parameters from the current branching.
547 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
549 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
550 return current_flow_branching;
554 // Starts a new code branching for block `block'.
556 public FlowBranching StartFlowBranching (Block block)
558 FlowBranching.BranchingType type;
560 if ((CurrentBranching != null) &&
561 (CurrentBranching.Type == FlowBranching.BranchingType.Switch))
562 type = FlowBranching.BranchingType.SwitchSection;
564 type = FlowBranching.BranchingType.Block;
566 flags |= Flags.DoFlowAnalysis;
568 current_flow_branching = FlowBranching.CreateBranching (
569 CurrentBranching, type, block, block.StartLocation);
570 return current_flow_branching;
573 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
575 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
576 current_flow_branching = branching;
580 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
582 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
583 current_flow_branching = branching;
587 public FlowBranchingToplevel StartFlowBranching (ToplevelBlock stmt)
589 FlowBranchingToplevel branching = new FlowBranchingToplevel (CurrentBranching, stmt);
590 current_flow_branching = branching;
595 // Ends a code branching. Merges the state of locals and parameters
596 // from all the children of the ending branching.
598 public FlowBranching.UsageVector DoEndFlowBranching ()
600 FlowBranching old = current_flow_branching;
601 current_flow_branching = current_flow_branching.Parent;
603 return current_flow_branching.MergeChild (old);
607 // Ends a code branching. Merges the state of locals and parameters
608 // from all the children of the ending branching.
610 public bool EndFlowBranching ()
612 FlowBranching.UsageVector vector = DoEndFlowBranching ();
614 return vector.IsUnreachable;
618 // Kills the current code branching. This throws away any changed state
619 // information and should only be used in case of an error.
621 public void KillFlowBranching ()
623 current_flow_branching = current_flow_branching.Parent;
626 public bool MustCaptureVariable (LocalInfo local)
628 if (CurrentAnonymousMethod == null)
630 if (CurrentAnonymousMethod.IsIterator)
632 return local.Block.Toplevel != CurrentBlock.Toplevel;
635 public void EmitMeta (ToplevelBlock b)
640 ReturnLabel = ig.DefineLabel ();
644 // Here until we can fix the problem with Mono.CSharp.Switch, which
645 // currently can not cope with ig == null during resolve (which must
646 // be fixed for switch statements to work on anonymous methods).
648 public void EmitTopBlock (IMethodData md, ToplevelBlock block)
655 if (ResolveTopBlock (null, block, md.ParameterInfo, md, out unreachable)){
658 current_phase = Phase.Emitting;
659 EmitResolvedTopBlock (block, unreachable);
665 public bool ResolveTopBlock (EmitContext anonymous_method_host, ToplevelBlock block,
666 Parameters ip, IMethodData md, out bool unreachable)
668 current_phase = Phase.Resolving;
676 CurrentFile = loc.File;
681 if (!block.ResolveMeta (this, ip))
684 if ((md != null) && (md.Iterator != null)) {
685 if (!md.Iterator.Resolve (this))
689 using (this.With (EmitContext.Flags.DoFlowAnalysis, true)) {
690 FlowBranchingToplevel top_level;
691 if (anonymous_method_host != null)
692 top_level = new FlowBranchingToplevel (anonymous_method_host.CurrentBranching, block);
694 top_level = block.TopLevelBranching;
696 current_flow_branching = top_level;
697 bool ok = block.Resolve (this);
698 current_flow_branching = null;
703 bool flow_unreachable = top_level.End ();
704 if (flow_unreachable)
708 } catch (Exception e) {
709 Console.WriteLine ("Exception caught by the compiler while compiling:");
710 Console.WriteLine (" Block that caused the problem begin at: " + loc);
712 if (CurrentBlock != null){
713 Console.WriteLine (" Block being compiled: [{0},{1}]",
714 CurrentBlock.StartLocation, CurrentBlock.EndLocation);
716 Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
721 if (return_type != null && !unreachable) {
722 if (CurrentAnonymousMethod == null) {
723 Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
725 } else if (!CurrentAnonymousMethod.IsIterator) {
726 Report.Error (1643, CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
727 CurrentAnonymousMethod.GetSignatureForError ());
732 if (!block.CompleteContexts (this))
739 public Type ReturnType {
741 return_type = value == TypeManager.void_type ?
749 public void EmitResolvedTopBlock (ToplevelBlock block, bool unreachable)
755 ig.MarkLabel (ReturnLabel);
757 if (return_value != null){
758 ig.Emit (OpCodes.Ldloc, return_value);
759 ig.Emit (OpCodes.Ret);
762 // If `HasReturnLabel' is set, then we already emitted a
763 // jump to the end of the method, so we must emit a `ret'
766 // Unfortunately, System.Reflection.Emit automatically emits
767 // a leave to the end of a finally block. This is a problem
768 // if no code is following the try/finally block since we may
769 // jump to a point after the end of the method.
770 // As a workaround, we're always creating a return label in
774 bool in_iterator = (CurrentAnonymousMethod != null) &&
775 CurrentAnonymousMethod.IsIterator && InIterator;
777 if ((block != null) && block.IsDestructor) {
778 // Nothing to do; S.R.E automatically emits a leave.
779 } else if (HasReturnLabel || (!unreachable && !in_iterator)) {
780 if (return_type != null)
781 ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
782 ig.Emit (OpCodes.Ret);
788 /// This is called immediately before emitting an IL opcode to tell the symbol
789 /// writer to which source line this opcode belongs.
791 public void Mark (Location loc, bool check_file)
793 if ((CodeGen.SymbolWriter == null) || loc.IsNull)
796 if (check_file && (CurrentFile != loc.File))
799 CodeGen.SymbolWriter.MarkSequencePoint (ig, loc.Row, loc.Column);
802 public void DefineLocalVariable (string name, LocalBuilder builder)
804 if (CodeGen.SymbolWriter == null)
807 CodeGen.SymbolWriter.DefineLocalVariable (name, builder);
810 public void BeginScope ()
814 if (CodeGen.SymbolWriter != null)
815 CodeGen.SymbolWriter.OpenScope(ig);
818 public void EndScope ()
822 if (CodeGen.SymbolWriter != null)
823 CodeGen.SymbolWriter.CloseScope(ig);
827 /// Returns a temporary storage for a variable of type t as
828 /// a local variable in the current body.
830 public LocalBuilder GetTemporaryLocal (Type t)
832 if (temporary_storage != null) {
833 object o = temporary_storage [t];
837 o = s.Count == 0 ? null : s.Pop ();
839 temporary_storage.Remove (t);
843 return (LocalBuilder) o;
845 return ig.DeclareLocal (t);
848 public void FreeTemporaryLocal (LocalBuilder b, Type t)
852 if (temporary_storage == null) {
853 temporary_storage = new Hashtable ();
854 temporary_storage [t] = b;
857 object o = temporary_storage [t];
859 temporary_storage [t] = b;
867 temporary_storage [t] = s;
873 /// Current loop begin and end labels.
875 public Label LoopBegin, LoopEnd;
878 /// Default target in a switch statement. Only valid if
881 public Label DefaultTarget;
884 /// If this is non-null, points to the current switch statement
886 public Switch Switch;
889 /// ReturnValue creates on demand the LocalBuilder for the
890 /// return value from the function. By default this is not
891 /// used. This is only required when returns are found inside
892 /// Try or Catch statements.
894 /// This method is typically invoked from the Emit phase, so
895 /// we allow the creation of a return label if it was not
896 /// requested during the resolution phase. Could be cleaned
897 /// up, but it would replicate a lot of logic in the Emit phase
898 /// of the code that uses it.
900 public LocalBuilder TemporaryReturn ()
902 if (return_value == null){
903 return_value = ig.DeclareLocal (return_type);
904 if (!HasReturnLabel){
905 ReturnLabel = ig.DefineLabel ();
906 HasReturnLabel = true;
914 /// This method is used during the Resolution phase to flag the
915 /// need to define the ReturnLabel
917 public void NeedReturnLabel ()
919 if (current_phase != Phase.Resolving){
921 // The reason is that the `ReturnLabel' is declared between
922 // resolution and emission
924 throw new Exception ("NeedReturnLabel called from Emit phase, should only be called during Resolve");
927 if (!InIterator && !HasReturnLabel)
928 HasReturnLabel = true;
932 public Expression GetThis (Location loc)
935 if (CurrentBlock != null)
936 my_this = new This (CurrentBlock, loc);
938 my_this = new This (loc);
940 if (!my_this.ResolveBase (this))
948 public abstract class CommonAssemblyModulClass : Attributable, IResolveContext {
950 protected CommonAssemblyModulClass ():
955 public void AddAttributes (ArrayList attrs)
957 foreach (Attribute a in attrs)
960 if (attributes == null) {
961 attributes = new Attributes (attrs);
964 attributes.AddAttributes (attrs);
967 public virtual void Emit (TypeContainer tc)
969 if (OptAttributes == null)
972 OptAttributes.Emit ();
975 protected Attribute ResolveAttribute (Type a_type)
977 Attribute a = OptAttributes.Search (a_type);
984 public override IResolveContext ResolveContext {
988 #region IResolveContext Members
990 public DeclSpace DeclContainer {
991 get { return RootContext.ToplevelTypes; }
994 public DeclSpace GenericDeclContainer {
995 get { return DeclContainer; }
998 public bool IsInObsoleteScope {
999 get { return false; }
1002 public bool IsInUnsafeScope {
1003 get { return false; }
1009 public class AssemblyClass : CommonAssemblyModulClass {
1010 // TODO: make it private and move all builder based methods here
1011 public AssemblyBuilder Builder;
1012 bool is_cls_compliant;
1013 bool wrap_non_exception_throws;
1015 public Attribute ClsCompliantAttribute;
1017 ListDictionary declarative_security;
1019 bool has_extension_method;
1020 public AssemblyName Name;
1021 MethodInfo add_type_forwarder;
1022 ListDictionary emitted_forwarders;
1025 // Module is here just because of error messages
1026 static string[] attribute_targets = new string [] { "assembly", "module" };
1028 public AssemblyClass (): base ()
1031 wrap_non_exception_throws = true;
1035 public bool HasExtensionMethods {
1038 has_extension_method = value;
1043 public bool IsClsCompliant {
1045 return is_cls_compliant;
1049 public bool WrapNonExceptionThrows {
1051 return wrap_non_exception_throws;
1055 public override AttributeTargets AttributeTargets {
1057 return AttributeTargets.Assembly;
1061 public override bool IsClsComplianceRequired ()
1063 return is_cls_compliant;
1066 public void Resolve ()
1068 if (OptAttributes == null)
1071 // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
1072 if (!OptAttributes.CheckTargets())
1075 ClsCompliantAttribute = ResolveAttribute (TypeManager.cls_compliant_attribute_type);
1076 if (ClsCompliantAttribute != null) {
1077 is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue ();
1081 Attribute a = ResolveAttribute (TypeManager.runtime_compatibility_attr_type);
1083 object val = a.GetPropertyValue ("WrapNonExceptionThrows");
1085 wrap_non_exception_throws = (bool)val;
1091 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob)
1094 // check for possible ECMA key
1095 if (strongNameBlob.Length == 16) {
1096 // will be rejected if not "the" ECMA key
1097 an.SetPublicKey (strongNameBlob);
1100 // take it, with or without, a private key
1101 RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
1102 // and make sure we only feed the public part to Sys.Ref
1103 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
1105 // AssemblyName.SetPublicKey requires an additional header
1106 byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
1108 byte[] encodedPublicKey = new byte [12 + publickey.Length];
1109 Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
1110 Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
1111 an.SetPublicKey (encodedPublicKey);
1115 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded");
1116 Environment.Exit (1);
1120 // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
1121 public AssemblyName GetAssemblyName (string name, string output)
1123 if (OptAttributes != null) {
1124 foreach (Attribute a in OptAttributes.Attrs) {
1125 // cannot rely on any resolve-based members before you call Resolve
1126 if (a.ExplicitTarget == null || a.ExplicitTarget != "assembly")
1129 // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
1130 // However, this is invoked by CodeGen.Init, when none of the namespaces
1132 // TODO: Does not handle quoted attributes properly
1134 case "AssemblyKeyFile":
1135 case "AssemblyKeyFileAttribute":
1136 case "System.Reflection.AssemblyKeyFileAttribute":
1137 if (RootContext.StrongNameKeyFile != null) {
1138 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1139 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1140 "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
1143 string value = a.GetString ();
1144 if (value.Length != 0)
1145 RootContext.StrongNameKeyFile = value;
1148 case "AssemblyKeyName":
1149 case "AssemblyKeyNameAttribute":
1150 case "System.Reflection.AssemblyKeyNameAttribute":
1151 if (RootContext.StrongNameKeyContainer != null) {
1152 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1153 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1154 "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
1157 string value = a.GetString ();
1158 if (value.Length != 0)
1159 RootContext.StrongNameKeyContainer = value;
1162 case "AssemblyDelaySign":
1163 case "AssemblyDelaySignAttribute":
1164 case "System.Reflection.AssemblyDelaySignAttribute":
1165 RootContext.StrongNameDelaySign = a.GetBoolean ();
1171 AssemblyName an = new AssemblyName ();
1172 an.Name = Path.GetFileNameWithoutExtension (name);
1174 // note: delay doesn't apply when using a key container
1175 if (RootContext.StrongNameKeyContainer != null) {
1176 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
1180 // strongname is optional
1181 if (RootContext.StrongNameKeyFile == null)
1184 string AssemblyDir = Path.GetDirectoryName (output);
1186 // the StrongName key file may be relative to (a) the compiled
1187 // file or (b) to the output assembly. See bugzilla #55320
1188 // http://bugzilla.ximian.com/show_bug.cgi?id=55320
1190 // (a) relative to the compiled file
1191 string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
1192 bool exist = File.Exists (filename);
1193 if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
1194 // (b) relative to the outputed assembly
1195 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
1196 exist = File.Exists (filename);
1200 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
1201 byte[] snkeypair = new byte [fs.Length];
1202 fs.Read (snkeypair, 0, snkeypair.Length);
1204 if (RootContext.StrongNameDelaySign) {
1205 // delayed signing - DO NOT include private key
1206 SetPublicKey (an, snkeypair);
1209 // no delay so we make sure we have the private key
1211 CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
1212 an.KeyPair = new StrongNameKeyPair (snkeypair);
1214 catch (CryptographicException) {
1215 if (snkeypair.Length == 16) {
1216 // error # is different for ECMA key
1217 Report.Error (1606, "Could not sign the assembly. " +
1218 "ECMA key can only be used to delay-sign assemblies");
1221 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not have a private key");
1229 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not exist");
1235 void Error_AssemblySigning (string text)
1237 Report.Error (1548, "Error during assembly signing. " + text);
1241 bool CheckInternalsVisibleAttribute (Attribute a)
1243 string assembly_name = a.GetString ();
1244 if (assembly_name.Length == 0)
1247 AssemblyName aname = null;
1249 aname = new AssemblyName (assembly_name);
1250 } catch (FileLoadException) {
1251 } catch (ArgumentException) {
1254 // Bad assembly name format
1256 Report.Warning (1700, 3, a.Location, "Assembly reference `" + assembly_name + "' is invalid and cannot be resolved");
1257 // Report error if we have defined Version or Culture
1258 else if (aname.Version != null || aname.CultureInfo != null)
1259 throw new Exception ("Friend assembly `" + a.GetString () +
1260 "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
1261 else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null) {
1262 Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." +
1263 " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
1271 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1273 if (a.Type.IsSubclassOf (TypeManager.security_attr_type) && a.CheckSecurityActionValidity (true)) {
1274 if (declarative_security == null)
1275 declarative_security = new ListDictionary ();
1277 a.ExtractSecurityPermissionSet (declarative_security);
1281 if (a.Type == TypeManager.assembly_culture_attribute_type) {
1282 string value = a.GetString ();
1283 if (value == null || value.Length == 0)
1286 if (RootContext.Target == Target.Exe) {
1287 a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
1293 if (a.Type == TypeManager.internals_visible_attr_type && !CheckInternalsVisibleAttribute (a))
1296 if (a.Type == TypeManager.type_forwarder_attr_type) {
1297 Type t = a.GetArgumentType ();
1298 if (t == null || TypeManager.HasElementType (t)) {
1299 Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
1303 if (emitted_forwarders == null) {
1304 emitted_forwarders = new ListDictionary();
1305 } else if (emitted_forwarders.Contains(t)) {
1306 Report.SymbolRelatedToPreviousError(((Attribute)emitted_forwarders[t]).Location, null);
1307 Report.Error(739, a.Location, "A duplicate type forward of type `{0}'",
1308 TypeManager.CSharpName(t));
1312 emitted_forwarders.Add(t, a);
1314 if (TypeManager.LookupDeclSpace (t) != null) {
1315 Report.SymbolRelatedToPreviousError (t);
1316 Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
1317 TypeManager.CSharpName (t));
1322 Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
1323 TypeManager.CSharpName (t));
1327 if (t.IsGenericType) {
1328 Report.Error (733, a.Location, "Cannot forward generic type `{0}'", TypeManager.CSharpName (t));
1332 if (add_type_forwarder == null) {
1333 add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder",
1334 BindingFlags.NonPublic | BindingFlags.Instance);
1336 if (add_type_forwarder == null) {
1337 Report.RuntimeMissingSupport (a.Location, "TypeForwardedTo attribute");
1342 add_type_forwarder.Invoke (Builder, new object[] { t });
1346 if (a.Type == TypeManager.extension_attribute_type) {
1347 a.Error_MisusedExtensionAttribute ();
1351 Builder.SetCustomAttribute (customBuilder);
1354 public override void Emit (TypeContainer tc)
1359 if (has_extension_method)
1360 Builder.SetCustomAttribute (TypeManager.extension_attribute_attr);
1362 // FIXME: Does this belong inside SRE.AssemblyBuilder instead?
1363 if (OptAttributes == null || !OptAttributes.Contains (TypeManager.runtime_compatibility_attr_type)) {
1364 ConstructorInfo ci = TypeManager.GetConstructor (
1365 TypeManager.runtime_compatibility_attr_type, Type.EmptyTypes);
1366 PropertyInfo [] pis = new PropertyInfo [1];
1367 pis [0] = TypeManager.GetProperty (
1368 TypeManager.runtime_compatibility_attr_type, "WrapNonExceptionThrows");
1369 object [] pargs = new object [1];
1371 Builder.SetCustomAttribute (new CustomAttributeBuilder (ci, new object [0], pis, pargs));
1375 if (declarative_security != null) {
1377 MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1378 object builder_instance = Builder;
1381 // Microsoft runtime hacking
1382 if (add_permission == null) {
1383 Type assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData");
1384 add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1386 FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
1387 builder_instance = fi.GetValue (Builder);
1390 object[] args = new object [] { declarative_security [SecurityAction.RequestMinimum],
1391 declarative_security [SecurityAction.RequestOptional],
1392 declarative_security [SecurityAction.RequestRefuse] };
1393 add_permission.Invoke (builder_instance, args);
1396 Report.RuntimeMissingSupport (Location.Null, "assembly permission setting");
1401 public override string[] ValidAttributeTargets {
1403 return attribute_targets;
1407 // Wrapper for AssemblyBuilder.AddModule
1408 static MethodInfo adder_method;
1409 static public MethodInfo AddModule_Method {
1411 if (adder_method == null)
1412 adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
1413 return adder_method;
1416 public Module AddModule (string module)
1418 MethodInfo m = AddModule_Method;
1420 Report.RuntimeMissingSupport (Location.Null, "/addmodule");
1421 Environment.Exit (1);
1425 return (Module) m.Invoke (Builder, new object [] { module });
1426 } catch (TargetInvocationException ex) {
1427 throw ex.InnerException;
1432 public class ModuleClass : CommonAssemblyModulClass {
1433 // TODO: make it private and move all builder based methods here
1434 public ModuleBuilder Builder;
1435 bool m_module_is_unsafe;
1436 bool has_default_charset;
1438 public CharSet DefaultCharSet = CharSet.Ansi;
1439 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
1441 static string[] attribute_targets = new string [] { "module" };
1443 public ModuleClass (bool is_unsafe)
1445 m_module_is_unsafe = is_unsafe;
1448 public override AttributeTargets AttributeTargets {
1450 return AttributeTargets.Module;
1454 public override bool IsClsComplianceRequired ()
1456 return CodeGen.Assembly.IsClsCompliant;
1459 public override void Emit (TypeContainer tc)
1463 if (!m_module_is_unsafe)
1466 if (TypeManager.unverifiable_code_ctor == null) {
1467 Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute.");
1471 Builder.SetCustomAttribute (new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
1474 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1476 if (a.Type == TypeManager.cls_compliant_attribute_type) {
1477 if (CodeGen.Assembly.ClsCompliantAttribute == null) {
1478 Report.Warning (3012, 1, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
1480 else if (CodeGen.Assembly.IsClsCompliant != a.GetBoolean ()) {
1481 Report.SymbolRelatedToPreviousError (CodeGen.Assembly.ClsCompliantAttribute.Location, CodeGen.Assembly.ClsCompliantAttribute.GetSignatureForError ());
1482 Report.Error (3017, a.Location, "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
1487 Builder.SetCustomAttribute (customBuilder);
1490 public bool HasDefaultCharSet {
1492 return has_default_charset;
1497 /// It is called very early therefore can resolve only predefined attributes
1499 public void Resolve ()
1502 if (OptAttributes == null)
1505 if (!OptAttributes.CheckTargets())
1508 Attribute a = ResolveAttribute (TypeManager.default_charset_type);
1510 has_default_charset = true;
1511 DefaultCharSet = a.GetCharSetValue ();
1512 switch (DefaultCharSet) {
1517 DefaultCharSetType = TypeAttributes.AutoClass;
1519 case CharSet.Unicode:
1520 DefaultCharSetType = TypeAttributes.UnicodeClass;
1523 Report.Error (1724, a.Location, "Value specified for the argument to 'System.Runtime.InteropServices.DefaultCharSetAttribute' is not valid");
1530 public override string[] ValidAttributeTargets {
1532 return attribute_targets;