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.
17 using System.Collections;
18 using System.Collections.Specialized;
19 using System.Reflection;
20 using System.Reflection.Emit;
21 using System.Runtime.InteropServices;
22 using System.Security;
23 using System.Security.Cryptography;
24 using System.Security.Permissions;
26 using Mono.Security.Cryptography;
28 namespace Mono.CSharp {
31 /// Code generator class.
33 public class CodeGen {
34 static AppDomain current_domain;
35 static public SymbolWriter SymbolWriter;
37 public static AssemblyClass Assembly;
38 public static ModuleClass Module;
45 public static void Reset ()
47 Assembly = new AssemblyClass ();
48 Module = new ModuleClass (RootContext.Unsafe);
51 public static string Basename (string name)
53 int pos = name.LastIndexOf ('/');
56 return name.Substring (pos + 1);
58 pos = name.LastIndexOf ('\\');
60 return name.Substring (pos + 1);
65 public static string Dirname (string name)
67 int pos = name.LastIndexOf ('/');
70 return name.Substring (0, pos);
72 pos = name.LastIndexOf ('\\');
74 return name.Substring (0, pos);
79 static public string FileName;
82 // Initializes the symbol writer
84 static void InitializeSymbolWriter (string filename)
86 SymbolWriter = SymbolWriter.GetSymbolWriter (Module.Builder, filename);
89 // If we got an ISymbolWriter instance, initialize it.
91 if (SymbolWriter == null) {
93 -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.");
99 // Initializes the code generator variables
101 static public bool Init (string name, string output, bool want_debugging_support)
104 AssemblyName an = Assembly.GetAssemblyName (name, output);
108 if (an.KeyPair != null) {
109 // If we are going to strong name our assembly make
110 // sure all its refs are strong named
111 foreach (Assembly a in RootNamespace.Global.Assemblies) {
112 AssemblyName ref_name = a.GetName ();
113 byte [] b = ref_name.GetPublicKeyToken ();
114 if (b == null || b.Length == 0) {
115 Report.Error (1577, "Assembly generation failed " +
116 "-- Referenced assembly '" +
118 "' does not have a strong name.");
119 //Environment.Exit (1);
124 current_domain = AppDomain.CurrentDomain;
127 Assembly.Builder = current_domain.DefineDynamicAssembly (an,
128 AssemblyBuilderAccess.Save, Dirname (name));
130 catch (ArgumentException) {
131 // specified key may not be exportable outside it's container
132 if (RootContext.StrongNameKeyContainer != null) {
133 Report.Error (1548, "Could not access the key inside the container `" +
134 RootContext.StrongNameKeyContainer + "'.");
135 Environment.Exit (1);
139 catch (CryptographicException) {
140 if ((RootContext.StrongNameKeyContainer != null) || (RootContext.StrongNameKeyFile != null)) {
141 Report.Error (1548, "Could not use the specified key to strongname the assembly.");
142 Environment.Exit (1);
147 // Get the complete AssemblyName from the builder
148 // (We need to get the public key and token)
149 Assembly.Name = Assembly.Builder.GetName ();
152 // Pass a path-less name to DefineDynamicModule. Wonder how
153 // this copes with output in different directories then.
154 // FIXME: figure out how this copes with --output /tmp/blah
156 // If the third argument is true, the ModuleBuilder will dynamically
157 // load the default symbol writer.
159 Module.Builder = Assembly.Builder.DefineDynamicModule (
160 Basename (name), Basename (output), false);
162 if (want_debugging_support)
163 InitializeSymbolWriter (output);
168 static public void Save (string name)
171 Assembly.Builder.Save (Basename (name));
173 catch (COMException) {
174 if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
177 // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies
178 Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
179 RootContext.StrongNameKeyFile +
180 "', Use MCS with the Mono runtime or CSC to compile this assembly.");
182 catch (System.IO.IOException io) {
183 Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
185 catch (System.UnauthorizedAccessException ua) {
186 Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message);
189 if (SymbolWriter != null)
190 SymbolWriter.WriteSymbolFile ();
195 /// An Emit Context is created for each body of code (from methods,
196 /// properties bodies, indexer bodies or constructor bodies)
198 public class EmitContext {
199 public DeclSpace DeclSpace;
200 public DeclSpace TypeContainer;
201 public ILGenerator ig;
204 /// This variable tracks the `checked' state of the compilation,
205 /// it controls whether we should generate code that does overflow
206 /// checking, or if we generate code that ignores overflows.
208 /// The default setting comes from the command line option to generate
209 /// checked or unchecked code plus any source code changes using the
210 /// checked/unchecked statements or expressions. Contrast this with
211 /// the ConstantCheckState flag.
214 public bool CheckState;
217 /// The constant check state is always set to `true' and cant be changed
218 /// from the command line. The source code can change this setting with
219 /// the `checked' and `unchecked' statements and expressions.
221 public bool ConstantCheckState;
224 /// Whether we are emitting code inside a static or instance method
226 public bool IsStatic;
229 /// Whether the actual created method is static or instance method.
230 /// Althoug the method might be declared as `static', if an anonymous
231 /// method is involved, we might turn this into an instance method.
233 /// So this reflects the low-level staticness of the method, while
234 /// IsStatic represents the semantic, high-level staticness.
236 public bool MethodIsStatic;
239 /// Whether we are emitting a field initializer
241 public bool IsFieldInitializer;
244 /// We are resolving a class'es base class and interfaces.
246 public bool ResolvingTypeTree;
249 /// We are resolving a generic method's return type and parameters.
251 public bool ResolvingGenericMethod;
254 /// The value that is allowed to be returned or NULL if there is no
257 public Type ReturnType;
260 /// Points to the Type (extracted from the TypeContainer) that
261 /// declares this body of code
263 public Type ContainerType;
266 /// Whether this is generating code for a constructor
268 public bool IsConstructor;
271 /// Whether we're control flow analysis enabled
273 public bool DoFlowAnalysis;
276 /// Whether we're control flow analysis disabled on struct
278 public bool OmitStructFlowAnalysis;
281 /// Keeps track of the Type to LocalBuilder temporary storage created
282 /// to store structures (used to compute the address of the structure
283 /// value on structure method invocations)
285 public Hashtable temporary_storage;
287 public Block CurrentBlock;
289 public int CurrentFile;
292 /// The location where we store the return value.
294 LocalBuilder return_value;
297 /// The location where return has to jump to return the
300 public Label ReturnLabel;
303 /// If we already defined the ReturnLabel
305 public bool HasReturnLabel;
308 /// Whether we are inside an iterator block.
310 public bool InIterator;
312 public bool IsLastStatement;
315 /// Whether we are inside an unsafe block
317 public bool InUnsafe;
320 /// Whether we are in a `fixed' initialization
322 public bool InFixedInitializer;
324 public bool InRefOutArgumentResolving;
327 public bool InFinally;
330 /// Whether we are inside an anonymous method.
332 public AnonymousContainer CurrentAnonymousMethod;
335 /// Location for this EmitContext
340 /// Inside an enum definition, we do not resolve enumeration values
341 /// to their enumerations, but rather to the underlying type/value
342 /// This is so EnumVal + EnumValB can be evaluated.
344 /// There is no "E operator + (E x, E y)", so during an enum evaluation
345 /// we relax the rules
347 public bool InEnumContext;
350 /// Anonymous methods can capture local variables and fields,
351 /// this object tracks it. It is copied from the TopLevelBlock
354 public CaptureContext capture_context;
357 /// Trace when method is called and is obsolete then this member suppress message
358 /// when call is inside next [Obsolete] method or type.
360 public bool TestObsoleteMethodUsage = true;
363 /// The current iterator
365 public Iterator CurrentIterator {
367 if (CurrentAnonymousMethod != null)
368 return CurrentAnonymousMethod.Iterator;
375 /// Whether we are in the resolving stage or not
384 FlowBranching current_flow_branching;
386 static int next_id = 0;
389 public override string ToString ()
391 return String.Format ("EmitContext ({0}:{1}:{2})", id,
392 CurrentIterator, capture_context, loc);
395 public EmitContext (DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig,
396 Type return_type, int code_flags, bool is_constructor)
400 TypeContainer = parent;
402 CheckState = RootContext.Checked;
403 ConstantCheckState = true;
405 if ((return_type is TypeBuilder) && return_type.IsGenericTypeDefinition)
406 throw new InternalErrorException ();
408 IsStatic = (code_flags & Modifiers.STATIC) != 0;
409 MethodIsStatic = IsStatic;
410 InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0;
411 ReturnType = return_type;
412 IsConstructor = is_constructor;
415 current_phase = Phase.Created;
418 // Can only be null for the ResolveType contexts.
419 ContainerType = parent.TypeBuilder;
420 if (parent.UnsafeContext)
423 InUnsafe = (code_flags & Modifiers.UNSAFE) != 0;
427 if (ReturnType == TypeManager.void_type)
431 public EmitContext (TypeContainer tc, Location l, ILGenerator ig,
432 Type return_type, int code_flags, bool is_constructor)
433 : this (tc, tc, l, ig, return_type, code_flags, is_constructor)
437 public EmitContext (TypeContainer tc, Location l, ILGenerator ig,
438 Type return_type, int code_flags)
439 : this (tc, tc, l, ig, return_type, code_flags, false)
443 public FlowBranching CurrentBranching {
445 return current_flow_branching;
449 public bool HaveCaptureInfo {
451 return capture_context != null;
456 // Starts a new code branching. This inherits the state of all local
457 // variables and parameters from the current branching.
459 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
461 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
462 return current_flow_branching;
466 // Starts a new code branching for block `block'.
468 public FlowBranching StartFlowBranching (Block block)
470 FlowBranching.BranchingType type;
472 if ((CurrentBranching != null) &&
473 (CurrentBranching.Type == FlowBranching.BranchingType.Switch))
474 type = FlowBranching.BranchingType.SwitchSection;
476 type = FlowBranching.BranchingType.Block;
478 DoFlowAnalysis = true;
480 current_flow_branching = FlowBranching.CreateBranching (
481 CurrentBranching, type, block, block.StartLocation);
482 return current_flow_branching;
485 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
487 FlowBranchingException branching = new FlowBranchingException (
488 CurrentBranching, stmt);
489 current_flow_branching = branching;
494 // Ends a code branching. Merges the state of locals and parameters
495 // from all the children of the ending branching.
497 public FlowBranching.UsageVector DoEndFlowBranching ()
499 FlowBranching old = current_flow_branching;
500 current_flow_branching = current_flow_branching.Parent;
502 return current_flow_branching.MergeChild (old);
506 // Ends a code branching. Merges the state of locals and parameters
507 // from all the children of the ending branching.
509 public FlowBranching.Reachability EndFlowBranching ()
511 FlowBranching.UsageVector vector = DoEndFlowBranching ();
513 return vector.Reachability;
517 // Kills the current code branching. This throws away any changed state
518 // information and should only be used in case of an error.
520 public void KillFlowBranching ()
522 current_flow_branching = current_flow_branching.Parent;
525 public void CaptureVariable (LocalInfo li)
527 capture_context.AddLocal (CurrentAnonymousMethod, li);
528 li.IsCaptured = true;
531 public void CaptureParameter (string name, Type t, int idx)
533 capture_context.AddParameter (this, CurrentAnonymousMethod, name, t, idx);
536 public void CaptureThis ()
538 capture_context.CaptureThis (CurrentAnonymousMethod);
543 // Use to register a field as captured
545 public void CaptureField (FieldExpr fe)
547 capture_context.AddField (this, CurrentAnonymousMethod, fe);
551 // Whether anonymous methods have captured variables
553 public bool HaveCapturedVariables ()
555 if (capture_context != null)
556 return capture_context.HaveCapturedVariables;
561 // Whether anonymous methods have captured fields or this.
563 public bool HaveCapturedFields ()
565 if (capture_context != null)
566 return capture_context.HaveCapturedFields;
571 // Emits the instance pointer for the host method
573 public void EmitMethodHostInstance (EmitContext target, AnonymousMethod am)
575 if (capture_context != null)
576 capture_context.EmitMethodHostInstance (target, am);
578 target.ig.Emit (OpCodes.Ldnull);
580 target.ig.Emit (OpCodes.Ldarg_0);
584 // Returns whether the `local' variable has been captured by an anonymous
587 public bool IsCaptured (LocalInfo local)
589 return capture_context.IsCaptured (local);
592 public bool IsParameterCaptured (string name)
594 if (capture_context != null)
595 return capture_context.IsParameterCaptured (name);
599 public void EmitMeta (ToplevelBlock b)
601 if (capture_context != null)
602 capture_context.EmitAnonymousHelperClasses (this);
606 ReturnLabel = ig.DefineLabel ();
610 // Here until we can fix the problem with Mono.CSharp.Switch, which
611 // currently can not cope with ig == null during resolve (which must
612 // be fixed for switch statements to work on anonymous methods).
614 public void EmitTopBlock (IMethodData md, ToplevelBlock block)
621 if (ResolveTopBlock (null, block, md.ParameterInfo, md, out unreachable)){
624 current_phase = Phase.Emitting;
625 EmitResolvedTopBlock (block, unreachable);
631 public bool ResolveTopBlock (EmitContext anonymous_method_host, ToplevelBlock block,
632 Parameters ip, IMethodData md, out bool unreachable)
634 current_phase = Phase.Resolving;
641 capture_context = block.CaptureContext;
644 CurrentFile = loc.File;
649 if (!block.ResolveMeta (this, ip))
652 bool old_do_flow_analysis = DoFlowAnalysis;
653 DoFlowAnalysis = true;
655 if (anonymous_method_host != null)
656 current_flow_branching = FlowBranching.CreateBranching (
657 anonymous_method_host.CurrentBranching,
658 FlowBranching.BranchingType.Block, block, loc);
660 current_flow_branching = block.TopLevelBranching;
662 if (!block.Resolve (this)) {
663 current_flow_branching = null;
664 DoFlowAnalysis = old_do_flow_analysis;
668 FlowBranching.Reachability reachability = current_flow_branching.MergeTopBlock ();
669 current_flow_branching = null;
671 DoFlowAnalysis = old_do_flow_analysis;
673 if (reachability.AlwaysReturns ||
674 reachability.AlwaysThrows ||
675 reachability.IsUnreachable)
678 } catch (Exception e) {
679 Console.WriteLine ("Exception caught by the compiler while compiling:");
680 Console.WriteLine (" Block that caused the problem begin at: " + loc);
682 if (CurrentBlock != null){
683 Console.WriteLine (" Block being compiled: [{0},{1}]",
684 CurrentBlock.StartLocation, CurrentBlock.EndLocation);
686 Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
691 if (ReturnType != null && !unreachable) {
692 if (CurrentAnonymousMethod == null) {
693 Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
695 } else if (!CurrentAnonymousMethod.IsIterator) {
696 Report.Error (1643, CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
697 CurrentAnonymousMethod.GetSignatureForError ());
702 block.CompleteContexts ();
707 public void EmitResolvedTopBlock (ToplevelBlock block, bool unreachable)
713 ig.MarkLabel (ReturnLabel);
715 if (return_value != null){
716 ig.Emit (OpCodes.Ldloc, return_value);
717 ig.Emit (OpCodes.Ret);
720 // If `HasReturnLabel' is set, then we already emitted a
721 // jump to the end of the method, so we must emit a `ret'
724 // Unfortunately, System.Reflection.Emit automatically emits
725 // a leave to the end of a finally block. This is a problem
726 // if no code is following the try/finally block since we may
727 // jump to a point after the end of the method.
728 // As a workaround, we're always creating a return label in
732 bool in_iterator = (CurrentAnonymousMethod != null) &&
733 CurrentAnonymousMethod.IsIterator && InIterator;
735 if ((block != null) && block.IsDestructor) {
736 // Nothing to do; S.R.E automatically emits a leave.
737 } else if (HasReturnLabel || (!unreachable && !in_iterator)) {
738 if (ReturnType != null)
739 ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
740 ig.Emit (OpCodes.Ret);
745 // Close pending helper classes if we are the toplevel
747 if (capture_context != null && capture_context.ParentToplevel == null)
748 capture_context.CloseAnonymousHelperClasses ();
752 /// This is called immediately before emitting an IL opcode to tell the symbol
753 /// writer to which source line this opcode belongs.
755 public void Mark (Location loc, bool check_file)
757 if ((CodeGen.SymbolWriter == null) || loc.IsNull)
760 if (check_file && (CurrentFile != loc.File))
763 CodeGen.SymbolWriter.MarkSequencePoint (ig, loc.Row, loc.Column);
766 public void DefineLocalVariable (string name, LocalBuilder builder)
768 if (CodeGen.SymbolWriter == null)
771 CodeGen.SymbolWriter.DefineLocalVariable (name, builder);
774 public void BeginScope ()
778 if (CodeGen.SymbolWriter != null)
779 CodeGen.SymbolWriter.OpenScope(ig);
782 public void EndScope ()
786 if (CodeGen.SymbolWriter != null)
787 CodeGen.SymbolWriter.CloseScope(ig);
791 /// Returns a temporary storage for a variable of type t as
792 /// a local variable in the current body.
794 public LocalBuilder GetTemporaryLocal (Type t)
796 LocalBuilder location = null;
798 if (temporary_storage != null){
799 object o = temporary_storage [t];
802 ArrayList al = (ArrayList) o;
804 for (int i = 0; i < al.Count; i++){
806 location = (LocalBuilder) al [i];
812 location = (LocalBuilder) o;
813 if (location != null)
818 return ig.DeclareLocal (t);
821 public void FreeTemporaryLocal (LocalBuilder b, Type t)
823 if (temporary_storage == null){
824 temporary_storage = new Hashtable ();
825 temporary_storage [t] = b;
828 object o = temporary_storage [t];
830 temporary_storage [t] = b;
834 ArrayList al = (ArrayList) o;
835 for (int i = 0; i < al.Count; i++){
844 ArrayList replacement = new ArrayList ();
846 temporary_storage.Remove (t);
847 temporary_storage [t] = replacement;
851 /// Current loop begin and end labels.
853 public Label LoopBegin, LoopEnd;
856 /// Default target in a switch statement. Only valid if
859 public Label DefaultTarget;
862 /// If this is non-null, points to the current switch statement
864 public Switch Switch;
867 /// ReturnValue creates on demand the LocalBuilder for the
868 /// return value from the function. By default this is not
869 /// used. This is only required when returns are found inside
870 /// Try or Catch statements.
872 /// This method is typically invoked from the Emit phase, so
873 /// we allow the creation of a return label if it was not
874 /// requested during the resolution phase. Could be cleaned
875 /// up, but it would replicate a lot of logic in the Emit phase
876 /// of the code that uses it.
878 public LocalBuilder TemporaryReturn ()
880 if (return_value == null){
881 return_value = ig.DeclareLocal (ReturnType);
882 if (!HasReturnLabel){
883 ReturnLabel = ig.DefineLabel ();
884 HasReturnLabel = true;
892 /// This method is used during the Resolution phase to flag the
893 /// need to define the ReturnLabel
895 public void NeedReturnLabel ()
897 if (current_phase != Phase.Resolving){
899 // The reason is that the `ReturnLabel' is declared between
900 // resolution and emission
902 throw new Exception ("NeedReturnLabel called from Emit phase, should only be called during Resolve");
905 if (!InIterator && !HasReturnLabel)
906 HasReturnLabel = true;
910 // Emits the proper object to address fields on a remapped
911 // variable/parameter to field in anonymous-method/iterator proxy classes.
913 public void EmitThis (bool need_address)
915 ig.Emit (OpCodes.Ldarg_0);
916 if (capture_context != null && CurrentAnonymousMethod != null){
917 ScopeInfo si = CurrentAnonymousMethod.Scope;
919 if (si.ParentLink != null)
920 ig.Emit (OpCodes.Ldfld, si.ParentLink);
921 if (si.THIS != null){
922 if (need_address && TypeManager.IsValueType (si.THIS.FieldType))
923 ig.Emit (OpCodes.Ldflda, si.THIS);
925 ig.Emit (OpCodes.Ldfld, si.THIS);
934 // Emits the code necessary to load the instance required
935 // to access the captured LocalInfo
937 public void EmitCapturedVariableInstance (LocalInfo li)
939 if (capture_context == null)
940 throw new Exception ("Calling EmitCapturedContext when there is no capture_context");
942 capture_context.EmitCapturedVariableInstance (this, li, CurrentAnonymousMethod);
945 public void EmitParameter (string name, bool leave_copy, bool prepared, ref LocalTemporary temp)
947 capture_context.EmitParameter (this, name, leave_copy, prepared, ref temp);
950 public void EmitAssignParameter (string name, Expression source, bool leave_copy, bool prepare_for_load, ref LocalTemporary temp)
952 capture_context.EmitAssignParameter (this, name, source, leave_copy, prepare_for_load, ref temp);
955 public void EmitAddressOfParameter (string name)
957 capture_context.EmitAddressOfParameter (this, name);
960 public Expression GetThis (Location loc)
963 if (CurrentBlock != null)
964 my_this = new This (CurrentBlock, loc);
966 my_this = new This (loc);
968 if (!my_this.ResolveBase (this))
976 public abstract class CommonAssemblyModulClass : Attributable {
977 protected CommonAssemblyModulClass ():
982 public void AddAttributes (ArrayList attrs)
984 if (OptAttributes == null) {
985 OptAttributes = new Attributes (attrs);
988 OptAttributes.AddAttributes (attrs);
991 public virtual void Emit (TypeContainer tc)
993 if (OptAttributes == null)
996 EmitContext ec = new EmitContext (tc, Mono.CSharp.Location.Null, null, null, 0, false);
997 OptAttributes.Emit (ec, this);
1000 protected Attribute ResolveAttribute (Type a_type)
1002 if (OptAttributes == null)
1005 // Ensure that we only have GlobalAttributes, since the Search below isn't safe with other types.
1006 if (!OptAttributes.CheckTargets (this))
1009 EmitContext temp_ec = new EmitContext (RootContext.Tree.Types, Mono.CSharp.Location.Null, null, null, 0, false);
1010 Attribute a = OptAttributes.Search (a_type, temp_ec);
1012 a.Resolve (temp_ec);
1018 public class AssemblyClass : CommonAssemblyModulClass {
1019 // TODO: make it private and move all builder based methods here
1020 public AssemblyBuilder Builder;
1021 public AssemblyName Name;
1023 bool is_cls_compliant;
1024 bool wrap_non_exception_throws;
1026 public Attribute ClsCompliantAttribute;
1028 ListDictionary declarative_security;
1030 // Module is here just because of error messages
1031 static string[] attribute_targets = new string [] { "assembly", "module" };
1033 public AssemblyClass (): base ()
1035 wrap_non_exception_throws = true;
1038 public bool IsClsCompliant {
1040 return is_cls_compliant;
1044 public bool WrapNonExceptionThrows {
1046 return wrap_non_exception_throws;
1050 public override AttributeTargets AttributeTargets {
1052 return AttributeTargets.Assembly;
1056 public override bool IsClsComplianceRequired(DeclSpace ds)
1058 return is_cls_compliant;
1061 public void Resolve ()
1063 ClsCompliantAttribute = ResolveAttribute (TypeManager.cls_compliant_attribute_type);
1064 if (ClsCompliantAttribute != null) {
1065 is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue (null);
1069 Attribute a = ResolveAttribute (TypeManager.runtime_compatibility_attr_type);
1071 object val = a.GetPropertyValue ("WrapNonExceptionThrows");
1073 wrap_non_exception_throws = (bool)val;
1079 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob)
1082 // check for possible ECMA key
1083 if (strongNameBlob.Length == 16) {
1084 // will be rejected if not "the" ECMA key
1085 an.SetPublicKey (strongNameBlob);
1088 // take it, with or without, a private key
1089 RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
1090 // and make sure we only feed the public part to Sys.Ref
1091 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
1093 // AssemblyName.SetPublicKey requires an additional header
1094 byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
1096 byte[] encodedPublicKey = new byte [12 + publickey.Length];
1097 Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
1098 Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
1099 an.SetPublicKey (encodedPublicKey);
1103 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded");
1104 Environment.Exit (1);
1108 // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
1109 public AssemblyName GetAssemblyName (string name, string output)
1111 if (OptAttributes != null) {
1112 foreach (Attribute a in OptAttributes.Attrs) {
1113 // cannot rely on any resolve-based members before you call Resolve
1114 if (a.ExplicitTarget == null || a.ExplicitTarget != "assembly")
1117 // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
1118 // However, this is invoked by CodeGen.Init, when none of the namespaces
1120 // TODO: Does not handle quoted attributes properly
1122 case "AssemblyKeyFile":
1123 case "AssemblyKeyFileAttribute":
1124 case "System.Reflection.AssemblyKeyFileAttribute":
1125 if (RootContext.StrongNameKeyFile != null) {
1126 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1127 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1128 "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
1131 string value = a.GetString ();
1132 if (value != String.Empty)
1133 RootContext.StrongNameKeyFile = value;
1136 case "AssemblyKeyName":
1137 case "AssemblyKeyNameAttribute":
1138 case "System.Reflection.AssemblyKeyNameAttribute":
1139 if (RootContext.StrongNameKeyContainer != null) {
1140 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1141 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1142 "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
1145 string value = a.GetString ();
1146 if (value != String.Empty)
1147 RootContext.StrongNameKeyContainer = value;
1150 case "AssemblyDelaySign":
1151 case "AssemblyDelaySignAttribute":
1152 case "System.Reflection.AssemblyDelaySignAttribute":
1153 RootContext.StrongNameDelaySign = a.GetBoolean ();
1159 AssemblyName an = new AssemblyName ();
1160 an.Name = Path.GetFileNameWithoutExtension (name);
1162 // note: delay doesn't apply when using a key container
1163 if (RootContext.StrongNameKeyContainer != null) {
1164 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
1168 // strongname is optional
1169 if (RootContext.StrongNameKeyFile == null)
1172 string AssemblyDir = Path.GetDirectoryName (output);
1174 // the StrongName key file may be relative to (a) the compiled
1175 // file or (b) to the output assembly. See bugzilla #55320
1176 // http://bugzilla.ximian.com/show_bug.cgi?id=55320
1178 // (a) relative to the compiled file
1179 string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
1180 bool exist = File.Exists (filename);
1181 if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
1182 // (b) relative to the outputed assembly
1183 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
1184 exist = File.Exists (filename);
1188 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
1189 byte[] snkeypair = new byte [fs.Length];
1190 fs.Read (snkeypair, 0, snkeypair.Length);
1192 if (RootContext.StrongNameDelaySign) {
1193 // delayed signing - DO NOT include private key
1194 SetPublicKey (an, snkeypair);
1197 // no delay so we make sure we have the private key
1199 CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
1200 an.KeyPair = new StrongNameKeyPair (snkeypair);
1202 catch (CryptographicException) {
1203 if (snkeypair.Length == 16) {
1204 // error # is different for ECMA key
1205 Report.Error (1606, "Could not sign the assembly. " +
1206 "ECMA key can only be used to delay-sign assemblies");
1209 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not have a private key");
1217 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not exist");
1223 void Error_AssemblySigning (string text)
1225 Report.Error (1548, "Error during assembly signing. " + text);
1228 bool CheckInternalsVisibleAttribute (Attribute a)
1230 string assembly_name = a.GetString ();
1231 if (assembly_name.Length == 0)
1234 AssemblyName aname = null;
1236 aname = new AssemblyName (assembly_name);
1237 } catch (FileLoadException) {
1238 } catch (ArgumentException) {
1241 // Bad assembly name format
1243 Report.Warning (1700, 3, a.Location, "Assembly reference `" + assembly_name + "' is invalid and cannot be resolved");
1244 // Report error if we have defined Version or Culture
1245 else if (aname.Version != null || aname.CultureInfo != null)
1246 throw new Exception ("Friend assembly `" + a.GetString () +
1247 "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
1248 else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null) {
1249 Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." +
1250 " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
1257 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1259 if (a.Type.IsSubclassOf (TypeManager.security_attr_type) && a.CheckSecurityActionValidity (true)) {
1260 if (declarative_security == null)
1261 declarative_security = new ListDictionary ();
1263 a.ExtractSecurityPermissionSet (declarative_security);
1267 if (a.Type == TypeManager.assembly_culture_attribute_type) {
1268 string value = a.GetString ();
1269 if (value == null || value.Length == 0)
1272 if (RootContext.Target == Target.Exe) {
1273 a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
1278 if (a.Type == TypeManager.internals_visible_attr_type && !CheckInternalsVisibleAttribute (a))
1281 Builder.SetCustomAttribute (customBuilder);
1284 public override void Emit (TypeContainer tc)
1288 if (declarative_security != null) {
1290 MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1291 object builder_instance = Builder;
1294 // Microsoft runtime hacking
1295 if (add_permission == null) {
1296 Type assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData");
1297 add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1299 FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
1300 builder_instance = fi.GetValue (Builder);
1303 object[] args = new object [] { declarative_security [SecurityAction.RequestMinimum],
1304 declarative_security [SecurityAction.RequestOptional],
1305 declarative_security [SecurityAction.RequestRefuse] };
1306 add_permission.Invoke (builder_instance, args);
1309 Report.RuntimeMissingSupport (Location.Null, "assembly permission setting");
1313 // FIXME: Does this belong inside SRE.AssemblyBuilder instead?
1314 if (OptAttributes == null || !OptAttributes.Contains (TypeManager.runtime_compatibility_attr_type, null)) {
1315 if (RootContext.StdLib) {
1316 ConstructorInfo ci = TypeManager.runtime_compatibility_attr_type.GetConstructor (TypeManager.NoTypes);
1317 PropertyInfo pi = TypeManager.runtime_compatibility_attr_type.GetProperty ("WrapNonExceptionThrows");
1318 Builder.SetCustomAttribute (new CustomAttributeBuilder (ci, new object [0],
1319 new PropertyInfo [] { pi }, new object[] { true } ));
1321 // FIXME: Do something appropriate for 'mscorlib'
1322 Report.Warning (-31, 1, "FIXME: Did not emit 'RuntimeComatibilityAttribute' for mscorlib");
1327 public override string[] ValidAttributeTargets {
1329 return attribute_targets;
1334 public class ModuleClass : CommonAssemblyModulClass {
1335 // TODO: make it private and move all builder based methods here
1336 public ModuleBuilder Builder;
1337 bool m_module_is_unsafe;
1339 public CharSet DefaultCharSet = CharSet.Ansi;
1340 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
1342 static string[] attribute_targets = new string [] { "module" };
1344 public ModuleClass (bool is_unsafe)
1346 m_module_is_unsafe = is_unsafe;
1349 public override AttributeTargets AttributeTargets {
1351 return AttributeTargets.Module;
1355 public override bool IsClsComplianceRequired(DeclSpace ds)
1357 return CodeGen.Assembly.IsClsCompliant;
1360 public override void Emit (TypeContainer tc)
1364 if (!m_module_is_unsafe)
1367 if (TypeManager.unverifiable_code_ctor == null) {
1368 Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute.");
1372 Builder.SetCustomAttribute (new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
1375 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1377 if (a.Type == TypeManager.cls_compliant_attribute_type) {
1378 if (CodeGen.Assembly.ClsCompliantAttribute == null) {
1379 Report.Warning (3012, 1, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
1381 else if (CodeGen.Assembly.IsClsCompliant != a.GetBoolean ()) {
1382 Report.SymbolRelatedToPreviousError (CodeGen.Assembly.ClsCompliantAttribute.Location, CodeGen.Assembly.ClsCompliantAttribute.GetSignatureForError ());
1383 Report.Error (3017, a.Location, "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
1388 Builder.SetCustomAttribute (customBuilder);
1392 /// It is called very early therefore can resolve only predefined attributes
1394 public void ResolveAttributes ()
1396 Attribute a = ResolveAttribute (TypeManager.default_charset_type);
1398 DefaultCharSet = a.GetCharSetValue ();
1399 switch (DefaultCharSet) {
1404 DefaultCharSetType = TypeAttributes.AutoClass;
1406 case CharSet.Unicode:
1407 DefaultCharSetType = TypeAttributes.UnicodeClass;
1410 Report.Error (1724, a.Location, "Value specified for the argument to 'System.Runtime.InteropServices.DefaultCharSetAttribute' is not valid");
1416 public override string[] ValidAttributeTargets {
1418 return attribute_targets;