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 if (SymbolWriter != null)
174 SymbolWriter.WriteSymbolFile ();
176 catch (COMException) {
177 if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
180 // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies
181 Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
182 RootContext.StrongNameKeyFile +
183 "', Use MCS with the Mono runtime or CSC to compile this assembly.");
185 catch (System.IO.IOException io) {
186 Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
188 catch (System.UnauthorizedAccessException ua) {
189 Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message);
195 public interface IResolveContext
197 DeclSpace DeclContainer { get; }
198 bool IsInObsoleteScope { get; }
199 bool IsInUnsafeScope { get; }
201 // the declcontainer to lookup for type-parameters. Should only use LookupGeneric on it.
203 // FIXME: This is somewhat of a hack. We don't need a full DeclSpace for this. We just need the
204 // current type parameters in scope. IUIC, that will require us to rewrite GenericMethod.
205 // Maybe we can replace this with a 'LookupGeneric (string)' instead, but we'll have to
206 // handle generic method overrides differently
207 DeclSpace GenericDeclContainer { get; }
211 /// An Emit Context is created for each body of code (from methods,
212 /// properties bodies, indexer bodies or constructor bodies)
214 public class EmitContext : IResolveContext {
217 public DeclSpace TypeContainer;
218 public ILGenerator ig;
221 public enum Flags : byte {
223 /// This flag tracks the `checked' state of the compilation,
224 /// it controls whether we should generate code that does overflow
225 /// checking, or if we generate code that ignores overflows.
227 /// The default setting comes from the command line option to generate
228 /// checked or unchecked code plus any source code changes using the
229 /// checked/unchecked statements or expressions. Contrast this with
230 /// the ConstantCheckState flag.
235 /// The constant check state is always set to `true' and cant be changed
236 /// from the command line. The source code can change this setting with
237 /// the `checked' and `unchecked' statements and expressions.
239 ConstantCheckState = 1 << 1,
241 AllCheckStateFlags = CheckState | ConstantCheckState,
244 /// Whether we are inside an unsafe block
252 /// Whether control flow analysis is enabled
254 DoFlowAnalysis = 1 << 5,
257 /// Whether control flow analysis is disabled on structs
258 /// (only meaningful when DoFlowAnalysis is set)
260 OmitStructFlowAnalysis = 1 << 6
266 /// Whether we are emitting code inside a static or instance method
268 public bool IsStatic;
271 /// Whether the actual created method is static or instance method.
272 /// Althoug the method might be declared as `static', if an anonymous
273 /// method is involved, we might turn this into an instance method.
275 /// So this reflects the low-level staticness of the method, while
276 /// IsStatic represents the semantic, high-level staticness.
278 public bool MethodIsStatic;
281 /// Whether we are emitting a field initializer
283 public bool IsFieldInitializer;
286 /// The value that is allowed to be returned or NULL if there is no
289 public Type ReturnType;
292 /// Points to the Type (extracted from the TypeContainer) that
293 /// declares this body of code
295 public Type ContainerType;
298 /// Whether this is generating code for a constructor
300 public bool IsConstructor;
303 /// Keeps track of the Type to LocalBuilder temporary storage created
304 /// to store structures (used to compute the address of the structure
305 /// value on structure method invocations)
307 public Hashtable temporary_storage;
309 public Block CurrentBlock;
311 public int CurrentFile;
314 /// The location where we store the return value.
316 LocalBuilder return_value;
319 /// The location where return has to jump to return the
322 public Label ReturnLabel;
325 /// If we already defined the ReturnLabel
327 public bool HasReturnLabel;
330 /// Whether we are inside an iterator block.
332 public bool InIterator;
334 public bool IsLastStatement;
337 /// Whether we are in a `fixed' initialization
339 public bool InFixedInitializer;
342 /// Whether we are inside an anonymous method.
344 public AnonymousContainer CurrentAnonymousMethod;
347 /// Location for this EmitContext
352 /// Inside an enum definition, we do not resolve enumeration values
353 /// to their enumerations, but rather to the underlying type/value
354 /// This is so EnumVal + EnumValB can be evaluated.
356 /// There is no "E operator + (E x, E y)", so during an enum evaluation
357 /// we relax the rules
359 public bool InEnumContext;
362 /// Anonymous methods can capture local variables and fields,
363 /// this object tracks it. It is copied from the TopLevelBlock
366 public CaptureContext capture_context;
368 public readonly IResolveContext ResolveContext;
371 /// The current iterator
373 public Iterator CurrentIterator {
375 if (CurrentAnonymousMethod != null)
376 return CurrentAnonymousMethod.Iterator;
383 /// Whether we are in the resolving stage or not
391 bool isAnonymousMethodAllowed = true;
394 FlowBranching current_flow_branching;
396 static int next_id = 0;
399 public override string ToString ()
401 return String.Format ("EmitContext ({0}:{1}:{2})", id,
402 CurrentIterator, capture_context, loc);
405 public EmitContext (IResolveContext rc, DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig,
406 Type return_type, int code_flags, bool is_constructor)
408 this.ResolveContext = rc;
411 TypeContainer = parent;
413 if (RootContext.Checked)
414 flags |= Flags.CheckState;
415 flags |= Flags.ConstantCheckState;
417 if ((return_type is TypeBuilder) && return_type.IsGenericTypeDefinition)
418 throw new InternalErrorException ();
420 IsStatic = (code_flags & Modifiers.STATIC) != 0;
421 MethodIsStatic = IsStatic;
422 InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0;
423 ReturnType = return_type;
424 IsConstructor = is_constructor;
427 current_phase = Phase.Created;
430 // Can only be null for the ResolveType contexts.
431 ContainerType = parent.TypeBuilder;
432 if (rc.IsInUnsafeScope)
433 flags |= Flags.InUnsafe;
437 if (ReturnType == TypeManager.void_type)
441 public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
442 Type return_type, int code_flags, bool is_constructor)
443 : this (rc, ds, ds, l, ig, return_type, code_flags, is_constructor)
447 public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
448 Type return_type, int code_flags)
449 : this (rc, ds, ds, l, ig, return_type, code_flags, false)
453 public DeclSpace DeclContainer {
454 get { return declSpace; }
455 set { declSpace = value; }
458 public DeclSpace GenericDeclContainer {
459 get { return DeclContainer; }
462 public bool CheckState {
463 get { return (flags & Flags.CheckState) != 0; }
466 public bool ConstantCheckState {
467 get { return (flags & Flags.ConstantCheckState) != 0; }
470 public bool InUnsafe {
471 get { return (flags & Flags.InUnsafe) != 0; }
474 public bool InCatch {
475 get { return (flags & Flags.InCatch) != 0; }
478 public bool InFinally {
479 get { return (flags & Flags.InFinally) != 0; }
482 public bool DoFlowAnalysis {
483 get { return (flags & Flags.DoFlowAnalysis) != 0; }
486 public bool OmitStructFlowAnalysis {
487 get { return (flags & Flags.OmitStructFlowAnalysis) != 0; }
490 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
491 // it's public so that we can use a struct at the callsite
492 public struct FlagsHandle : IDisposable
495 Flags invmask, oldval;
496 internal FlagsHandle (EmitContext ec, Flags mask, Flags val)
500 oldval = ec.flags & mask;
501 ec.flags = (ec.flags & invmask) | (val & mask);
503 public void Dispose ()
505 ec.flags = (ec.flags & invmask) | oldval;
509 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
510 public FlagsHandle With (Flags bits, bool enable)
512 return new FlagsHandle (this, bits, enable ? bits : 0);
515 public FlagsHandle WithFlowAnalysis (bool do_flow_analysis, bool omit_struct_analysis)
518 (do_flow_analysis ? Flags.DoFlowAnalysis : 0) |
519 (omit_struct_analysis ? Flags.OmitStructFlowAnalysis : 0);
520 return new FlagsHandle (this, Flags.DoFlowAnalysis | Flags.OmitStructFlowAnalysis, newflags);
523 public bool IsInObsoleteScope {
524 get { return ResolveContext.IsInObsoleteScope; }
527 public bool IsInUnsafeScope {
528 get { return InUnsafe || ResolveContext.IsInUnsafeScope; }
531 public bool IsAnonymousMethodAllowed {
532 get { return isAnonymousMethodAllowed; }
533 set { isAnonymousMethodAllowed = value; }
536 public FlowBranching CurrentBranching {
537 get { return current_flow_branching; }
540 public bool HaveCaptureInfo {
541 get { return capture_context != null; }
544 public void EmitScopeInitFromBlock (Block b)
546 if (capture_context != null)
547 capture_context.EmitScopeInitFromBlock (this, b);
551 // Starts a new code branching. This inherits the state of all local
552 // variables and parameters from the current branching.
554 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
556 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
557 return current_flow_branching;
561 // Starts a new code branching for block `block'.
563 public FlowBranching StartFlowBranching (Block block)
565 FlowBranching.BranchingType type;
567 if ((CurrentBranching != null) &&
568 (CurrentBranching.Type == FlowBranching.BranchingType.Switch))
569 type = FlowBranching.BranchingType.SwitchSection;
571 type = FlowBranching.BranchingType.Block;
573 flags |= Flags.DoFlowAnalysis;
575 current_flow_branching = FlowBranching.CreateBranching (
576 CurrentBranching, type, block, block.StartLocation);
577 return current_flow_branching;
580 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
582 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
583 current_flow_branching = branching;
587 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
589 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
590 current_flow_branching = branching;
594 public FlowBranchingToplevel StartFlowBranching (ToplevelBlock stmt)
596 FlowBranchingToplevel branching = new FlowBranchingToplevel (CurrentBranching, stmt);
597 current_flow_branching = branching;
602 // Ends a code branching. Merges the state of locals and parameters
603 // from all the children of the ending branching.
605 public FlowBranching.UsageVector DoEndFlowBranching ()
607 FlowBranching old = current_flow_branching;
608 current_flow_branching = current_flow_branching.Parent;
610 return current_flow_branching.MergeChild (old);
614 // Ends a code branching. Merges the state of locals and parameters
615 // from all the children of the ending branching.
617 public FlowBranching.Reachability EndFlowBranching ()
619 FlowBranching.UsageVector vector = DoEndFlowBranching ();
621 return vector.Reachability;
625 // Kills the current code branching. This throws away any changed state
626 // information and should only be used in case of an error.
628 public void KillFlowBranching ()
630 current_flow_branching = current_flow_branching.Parent;
633 public void CaptureVariable (LocalInfo li)
635 capture_context.AddLocal (CurrentAnonymousMethod, li);
636 li.IsCaptured = true;
639 public void CaptureParameter (string name, Type t, int idx)
641 capture_context.AddParameter (this, CurrentAnonymousMethod, name, t, idx);
644 public void CaptureThis ()
646 capture_context.CaptureThis (CurrentAnonymousMethod);
651 // Use to register a field as captured
653 public void CaptureField (FieldExpr fe)
655 capture_context.AddField (this, CurrentAnonymousMethod, fe);
659 // Whether anonymous methods have captured variables
661 public bool HaveCapturedVariables ()
663 if (capture_context != null)
664 return capture_context.HaveCapturedVariables;
669 // Whether anonymous methods have captured fields or this.
671 public bool HaveCapturedFields ()
673 if (capture_context != null)
674 return capture_context.HaveCapturedFields;
679 // Emits the instance pointer for the host method
681 public void EmitMethodHostInstance (EmitContext target, AnonymousMethod am)
683 if (capture_context != null)
684 capture_context.EmitMethodHostInstance (target, am);
686 target.ig.Emit (OpCodes.Ldnull);
688 target.ig.Emit (OpCodes.Ldarg_0);
692 // Returns whether the `local' variable has been captured by an anonymous
695 public bool IsCaptured (LocalInfo local)
697 return capture_context.IsCaptured (local);
700 public bool IsParameterCaptured (string name)
702 if (capture_context != null)
703 return capture_context.IsParameterCaptured (name);
707 public void EmitMeta (ToplevelBlock b)
709 if (capture_context != null)
710 capture_context.EmitAnonymousHelperClasses (this);
714 ReturnLabel = ig.DefineLabel ();
718 // Here until we can fix the problem with Mono.CSharp.Switch, which
719 // currently can not cope with ig == null during resolve (which must
720 // be fixed for switch statements to work on anonymous methods).
722 public void EmitTopBlock (IMethodData md, ToplevelBlock block)
729 if (ResolveTopBlock (null, block, md.ParameterInfo, md, out unreachable)){
732 current_phase = Phase.Emitting;
733 EmitResolvedTopBlock (block, unreachable);
739 public bool ResolveTopBlock (EmitContext anonymous_method_host, ToplevelBlock block,
740 Parameters ip, IMethodData md, out bool unreachable)
742 current_phase = Phase.Resolving;
749 capture_context = block.CaptureContext;
752 CurrentFile = loc.File;
757 if (!block.ResolveMeta (this, ip))
760 using (this.With (EmitContext.Flags.DoFlowAnalysis, true)) {
761 FlowBranchingToplevel top_level;
762 if (anonymous_method_host != null)
763 top_level = new FlowBranchingToplevel (anonymous_method_host.CurrentBranching, block);
765 top_level = block.TopLevelBranching;
767 current_flow_branching = top_level;
768 bool ok = block.Resolve (this);
769 current_flow_branching = null;
774 FlowBranching.Reachability reachability = top_level.End ();
775 if (reachability.IsUnreachable)
779 } catch (Exception e) {
780 Console.WriteLine ("Exception caught by the compiler while compiling:");
781 Console.WriteLine (" Block that caused the problem begin at: " + loc);
783 if (CurrentBlock != null){
784 Console.WriteLine (" Block being compiled: [{0},{1}]",
785 CurrentBlock.StartLocation, CurrentBlock.EndLocation);
787 Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
792 if (ReturnType != null && !unreachable) {
793 if (CurrentAnonymousMethod == null) {
794 Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
796 } else if (!CurrentAnonymousMethod.IsIterator) {
797 Report.Error (1643, CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
798 CurrentAnonymousMethod.GetSignatureForError ());
803 block.CompleteContexts ();
808 public void EmitResolvedTopBlock (ToplevelBlock block, bool unreachable)
814 ig.MarkLabel (ReturnLabel);
816 if (return_value != null){
817 ig.Emit (OpCodes.Ldloc, return_value);
818 ig.Emit (OpCodes.Ret);
821 // If `HasReturnLabel' is set, then we already emitted a
822 // jump to the end of the method, so we must emit a `ret'
825 // Unfortunately, System.Reflection.Emit automatically emits
826 // a leave to the end of a finally block. This is a problem
827 // if no code is following the try/finally block since we may
828 // jump to a point after the end of the method.
829 // As a workaround, we're always creating a return label in
833 bool in_iterator = (CurrentAnonymousMethod != null) &&
834 CurrentAnonymousMethod.IsIterator && InIterator;
836 if ((block != null) && block.IsDestructor) {
837 // Nothing to do; S.R.E automatically emits a leave.
838 } else if (HasReturnLabel || (!unreachable && !in_iterator)) {
839 if (ReturnType != null)
840 ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
841 ig.Emit (OpCodes.Ret);
846 // Close pending helper classes if we are the toplevel
848 if (capture_context != null && capture_context.ParentToplevel == null)
849 capture_context.CloseAnonymousHelperClasses ();
853 /// This is called immediately before emitting an IL opcode to tell the symbol
854 /// writer to which source line this opcode belongs.
856 public void Mark (Location loc, bool check_file)
858 if ((CodeGen.SymbolWriter == null) || loc.IsNull)
861 if (check_file && (CurrentFile != loc.File))
864 CodeGen.SymbolWriter.MarkSequencePoint (ig, loc.Row, loc.Column);
867 public void DefineLocalVariable (string name, LocalBuilder builder)
869 if (CodeGen.SymbolWriter == null)
872 CodeGen.SymbolWriter.DefineLocalVariable (name, builder);
875 public void BeginScope ()
879 if (CodeGen.SymbolWriter != null)
880 CodeGen.SymbolWriter.OpenScope(ig);
883 public void EndScope ()
887 if (CodeGen.SymbolWriter != null)
888 CodeGen.SymbolWriter.CloseScope(ig);
892 /// Returns a temporary storage for a variable of type t as
893 /// a local variable in the current body.
895 public LocalBuilder GetTemporaryLocal (Type t)
897 if (temporary_storage != null) {
898 object o = temporary_storage [t];
902 o = s.Count == 0 ? null : s.Pop ();
904 temporary_storage.Remove (t);
908 return (LocalBuilder) o;
910 return ig.DeclareLocal (t);
913 public void FreeTemporaryLocal (LocalBuilder b, Type t)
917 if (temporary_storage == null) {
918 temporary_storage = new Hashtable ();
919 temporary_storage [t] = b;
922 object o = temporary_storage [t];
924 temporary_storage [t] = b;
932 temporary_storage [t] = s;
938 /// Current loop begin and end labels.
940 public Label LoopBegin, LoopEnd;
943 /// Default target in a switch statement. Only valid if
946 public Label DefaultTarget;
949 /// If this is non-null, points to the current switch statement
951 public Switch Switch;
954 /// ReturnValue creates on demand the LocalBuilder for the
955 /// return value from the function. By default this is not
956 /// used. This is only required when returns are found inside
957 /// Try or Catch statements.
959 /// This method is typically invoked from the Emit phase, so
960 /// we allow the creation of a return label if it was not
961 /// requested during the resolution phase. Could be cleaned
962 /// up, but it would replicate a lot of logic in the Emit phase
963 /// of the code that uses it.
965 public LocalBuilder TemporaryReturn ()
967 if (return_value == null){
968 return_value = ig.DeclareLocal (ReturnType);
969 if (!HasReturnLabel){
970 ReturnLabel = ig.DefineLabel ();
971 HasReturnLabel = true;
979 /// This method is used during the Resolution phase to flag the
980 /// need to define the ReturnLabel
982 public void NeedReturnLabel ()
984 if (current_phase != Phase.Resolving){
986 // The reason is that the `ReturnLabel' is declared between
987 // resolution and emission
989 throw new Exception ("NeedReturnLabel called from Emit phase, should only be called during Resolve");
992 if (!InIterator && !HasReturnLabel)
993 HasReturnLabel = true;
997 // Emits the proper object to address fields on a remapped
998 // variable/parameter to field in anonymous-method/iterator proxy classes.
1000 public void EmitThis (bool need_address)
1002 ig.Emit (OpCodes.Ldarg_0);
1003 if (capture_context != null && CurrentAnonymousMethod != null){
1004 ScopeInfo si = CurrentAnonymousMethod.Scope;
1006 if (si.ParentLink != null)
1007 ig.Emit (OpCodes.Ldfld, si.ParentLink);
1008 if (si.THIS != null){
1009 if (need_address && TypeManager.IsValueType (si.THIS.FieldType))
1010 ig.Emit (OpCodes.Ldflda, si.THIS);
1012 ig.Emit (OpCodes.Ldfld, si.THIS);
1015 si = si.ParentScope;
1021 // Emits the code necessary to load the instance required
1022 // to access the captured LocalInfo
1024 public void EmitCapturedVariableInstance (LocalInfo li)
1026 if (capture_context == null)
1027 throw new Exception ("Calling EmitCapturedContext when there is no capture_context");
1029 capture_context.EmitCapturedVariableInstance (this, li, CurrentAnonymousMethod);
1032 public void EmitParameter (string name, bool leave_copy, bool prepared, ref LocalTemporary temp)
1034 capture_context.EmitParameter (this, name, leave_copy, prepared, ref temp);
1037 public void EmitAssignParameter (string name, Expression source, bool leave_copy, bool prepare_for_load, ref LocalTemporary temp)
1039 capture_context.EmitAssignParameter (this, name, source, leave_copy, prepare_for_load, ref temp);
1042 public void EmitAddressOfParameter (string name)
1044 capture_context.EmitAddressOfParameter (this, name);
1047 public Expression GetThis (Location loc)
1050 if (CurrentBlock != null)
1051 my_this = new This (CurrentBlock, loc);
1053 my_this = new This (loc);
1055 if (!my_this.ResolveBase (this))
1063 public abstract class CommonAssemblyModulClass : Attributable, IResolveContext {
1065 protected CommonAssemblyModulClass ():
1070 public void AddAttributes (ArrayList attrs)
1072 foreach (Attribute a in attrs)
1075 if (attributes == null) {
1076 attributes = new Attributes (attrs);
1079 attributes.AddAttributes (attrs);
1082 public virtual void Emit (TypeContainer tc)
1084 if (OptAttributes == null)
1087 OptAttributes.Emit ();
1090 protected Attribute ResolveAttribute (Type a_type)
1092 if (OptAttributes == null)
1095 // Ensure that we only have GlobalAttributes, since the Search below isn't safe with other types.
1096 if (!OptAttributes.CheckTargets ())
1099 Attribute a = OptAttributes.Search (a_type);
1106 public override IResolveContext ResolveContext {
1107 get { return this; }
1110 #region IResolveContext Members
1112 public DeclSpace DeclContainer {
1113 get { return RootContext.ToplevelTypes; }
1116 public DeclSpace GenericDeclContainer {
1117 get { return DeclContainer; }
1120 public bool IsInObsoleteScope {
1121 get { return false; }
1124 public bool IsInUnsafeScope {
1125 get { return false; }
1131 public class AssemblyClass : CommonAssemblyModulClass {
1132 // TODO: make it private and move all builder based methods here
1133 public AssemblyBuilder Builder;
1134 public AssemblyName Name;
1136 bool is_cls_compliant;
1137 bool wrap_non_exception_throws;
1139 public Attribute ClsCompliantAttribute;
1141 ListDictionary declarative_security;
1142 MethodInfo add_type_forwarder;
1144 // Module is here just because of error messages
1145 static string[] attribute_targets = new string [] { "assembly", "module" };
1147 public AssemblyClass (): base ()
1149 wrap_non_exception_throws = true;
1152 public bool IsClsCompliant {
1154 return is_cls_compliant;
1158 public bool WrapNonExceptionThrows {
1160 return wrap_non_exception_throws;
1164 public override AttributeTargets AttributeTargets {
1166 return AttributeTargets.Assembly;
1170 public override bool IsClsComplianceRequired ()
1172 return is_cls_compliant;
1175 public void Resolve ()
1177 ClsCompliantAttribute = ResolveAttribute (TypeManager.cls_compliant_attribute_type);
1178 if (ClsCompliantAttribute != null) {
1179 is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue ();
1183 Attribute a = ResolveAttribute (TypeManager.runtime_compatibility_attr_type);
1185 object val = a.GetPropertyValue ("WrapNonExceptionThrows");
1187 wrap_non_exception_throws = (bool)val;
1193 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob)
1196 // check for possible ECMA key
1197 if (strongNameBlob.Length == 16) {
1198 // will be rejected if not "the" ECMA key
1199 an.SetPublicKey (strongNameBlob);
1202 // take it, with or without, a private key
1203 RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
1204 // and make sure we only feed the public part to Sys.Ref
1205 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
1207 // AssemblyName.SetPublicKey requires an additional header
1208 byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
1210 byte[] encodedPublicKey = new byte [12 + publickey.Length];
1211 Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
1212 Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
1213 an.SetPublicKey (encodedPublicKey);
1217 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded");
1218 Environment.Exit (1);
1222 // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
1223 public AssemblyName GetAssemblyName (string name, string output)
1225 if (OptAttributes != null) {
1226 foreach (Attribute a in OptAttributes.Attrs) {
1227 // cannot rely on any resolve-based members before you call Resolve
1228 if (a.ExplicitTarget == null || a.ExplicitTarget != "assembly")
1231 // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
1232 // However, this is invoked by CodeGen.Init, when none of the namespaces
1234 // TODO: Does not handle quoted attributes properly
1236 case "AssemblyKeyFile":
1237 case "AssemblyKeyFileAttribute":
1238 case "System.Reflection.AssemblyKeyFileAttribute":
1239 if (RootContext.StrongNameKeyFile != null) {
1240 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1241 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1242 "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
1245 string value = a.GetString ();
1246 if (value.Length != 0)
1247 RootContext.StrongNameKeyFile = value;
1250 case "AssemblyKeyName":
1251 case "AssemblyKeyNameAttribute":
1252 case "System.Reflection.AssemblyKeyNameAttribute":
1253 if (RootContext.StrongNameKeyContainer != null) {
1254 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1255 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1256 "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
1259 string value = a.GetString ();
1260 if (value.Length != 0)
1261 RootContext.StrongNameKeyContainer = value;
1264 case "AssemblyDelaySign":
1265 case "AssemblyDelaySignAttribute":
1266 case "System.Reflection.AssemblyDelaySignAttribute":
1267 RootContext.StrongNameDelaySign = a.GetBoolean ();
1273 AssemblyName an = new AssemblyName ();
1274 an.Name = Path.GetFileNameWithoutExtension (name);
1276 // note: delay doesn't apply when using a key container
1277 if (RootContext.StrongNameKeyContainer != null) {
1278 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
1282 // strongname is optional
1283 if (RootContext.StrongNameKeyFile == null)
1286 string AssemblyDir = Path.GetDirectoryName (output);
1288 // the StrongName key file may be relative to (a) the compiled
1289 // file or (b) to the output assembly. See bugzilla #55320
1290 // http://bugzilla.ximian.com/show_bug.cgi?id=55320
1292 // (a) relative to the compiled file
1293 string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
1294 bool exist = File.Exists (filename);
1295 if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
1296 // (b) relative to the outputed assembly
1297 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
1298 exist = File.Exists (filename);
1302 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
1303 byte[] snkeypair = new byte [fs.Length];
1304 fs.Read (snkeypair, 0, snkeypair.Length);
1306 if (RootContext.StrongNameDelaySign) {
1307 // delayed signing - DO NOT include private key
1308 SetPublicKey (an, snkeypair);
1311 // no delay so we make sure we have the private key
1313 CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
1314 an.KeyPair = new StrongNameKeyPair (snkeypair);
1316 catch (CryptographicException) {
1317 if (snkeypair.Length == 16) {
1318 // error # is different for ECMA key
1319 Report.Error (1606, "Could not sign the assembly. " +
1320 "ECMA key can only be used to delay-sign assemblies");
1323 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not have a private key");
1331 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not exist");
1337 void Error_AssemblySigning (string text)
1339 Report.Error (1548, "Error during assembly signing. " + text);
1342 bool CheckInternalsVisibleAttribute (Attribute a)
1344 string assembly_name = a.GetString ();
1345 if (assembly_name.Length == 0)
1348 AssemblyName aname = null;
1350 aname = new AssemblyName (assembly_name);
1351 } catch (FileLoadException) {
1352 } catch (ArgumentException) {
1355 // Bad assembly name format
1357 Report.Warning (1700, 3, a.Location, "Assembly reference `" + assembly_name + "' is invalid and cannot be resolved");
1358 // Report error if we have defined Version or Culture
1359 else if (aname.Version != null || aname.CultureInfo != null)
1360 throw new Exception ("Friend assembly `" + a.GetString () +
1361 "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
1362 else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null) {
1363 Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." +
1364 " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
1371 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1373 if (a.Type.IsSubclassOf (TypeManager.security_attr_type) && a.CheckSecurityActionValidity (true)) {
1374 if (declarative_security == null)
1375 declarative_security = new ListDictionary ();
1377 a.ExtractSecurityPermissionSet (declarative_security);
1381 if (a.Type == TypeManager.assembly_culture_attribute_type) {
1382 string value = a.GetString ();
1383 if (value == null || value.Length == 0)
1386 if (RootContext.Target == Target.Exe) {
1387 a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
1392 if (a.Type == TypeManager.internals_visible_attr_type && !CheckInternalsVisibleAttribute (a))
1395 if (a.Type == TypeManager.type_forwarder_attr_type) {
1396 Type t = a.GetArgumentType ();
1397 if (t == null || TypeManager.HasElementType (t)) {
1398 Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
1402 if (TypeManager.LookupDeclSpace (t) != null) {
1403 Report.SymbolRelatedToPreviousError (t);
1404 Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
1405 TypeManager.CSharpName (t));
1410 Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
1411 TypeManager.CSharpName (t));
1415 if (t.IsGenericType) {
1416 Report.Error (733, a.Location, "Cannot forward generic type `{0}'", TypeManager.CSharpName (t));
1420 if (add_type_forwarder == null) {
1421 add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder",
1422 BindingFlags.NonPublic | BindingFlags.Instance);
1424 if (add_type_forwarder == null) {
1425 Report.RuntimeMissingSupport (a.Location, "TypeForwardedTo attribute");
1430 add_type_forwarder.Invoke (Builder, new object[] { t });
1434 Builder.SetCustomAttribute (customBuilder);
1437 public override void Emit (TypeContainer tc)
1441 // FIXME: Does this belong inside SRE.AssemblyBuilder instead?
1442 if (OptAttributes == null || !OptAttributes.Contains (TypeManager.runtime_compatibility_attr_type)) {
1443 ConstructorInfo ci = TypeManager.GetConstructor (
1444 TypeManager.runtime_compatibility_attr_type, Type.EmptyTypes);
1445 PropertyInfo [] pis = new PropertyInfo [1];
1446 pis [0] = TypeManager.GetProperty (
1447 TypeManager.runtime_compatibility_attr_type, "WrapNonExceptionThrows");
1448 object [] pargs = new object [1];
1450 Builder.SetCustomAttribute (new CustomAttributeBuilder (ci, new object [0], pis, pargs));
1453 if (declarative_security != null) {
1455 MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1456 object builder_instance = Builder;
1459 // Microsoft runtime hacking
1460 if (add_permission == null) {
1461 Type assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData");
1462 add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1464 FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
1465 builder_instance = fi.GetValue (Builder);
1468 object[] args = new object [] { declarative_security [SecurityAction.RequestMinimum],
1469 declarative_security [SecurityAction.RequestOptional],
1470 declarative_security [SecurityAction.RequestRefuse] };
1471 add_permission.Invoke (builder_instance, args);
1474 Report.RuntimeMissingSupport (Location.Null, "assembly permission setting");
1479 public override string[] ValidAttributeTargets {
1481 return attribute_targets;
1486 public class ModuleClass : CommonAssemblyModulClass {
1487 // TODO: make it private and move all builder based methods here
1488 public ModuleBuilder Builder;
1489 bool m_module_is_unsafe;
1491 public CharSet DefaultCharSet = CharSet.Ansi;
1492 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
1494 static string[] attribute_targets = new string [] { "module" };
1496 public ModuleClass (bool is_unsafe)
1498 m_module_is_unsafe = is_unsafe;
1501 public override AttributeTargets AttributeTargets {
1503 return AttributeTargets.Module;
1507 public override bool IsClsComplianceRequired ()
1509 return CodeGen.Assembly.IsClsCompliant;
1512 public override void Emit (TypeContainer tc)
1516 if (!m_module_is_unsafe)
1519 if (TypeManager.unverifiable_code_ctor == null) {
1520 Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute.");
1524 Builder.SetCustomAttribute (new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
1527 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1529 if (a.Type == TypeManager.cls_compliant_attribute_type) {
1530 if (CodeGen.Assembly.ClsCompliantAttribute == null) {
1531 Report.Warning (3012, 1, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
1533 else if (CodeGen.Assembly.IsClsCompliant != a.GetBoolean ()) {
1534 Report.SymbolRelatedToPreviousError (CodeGen.Assembly.ClsCompliantAttribute.Location, CodeGen.Assembly.ClsCompliantAttribute.GetSignatureForError ());
1535 Report.Error (3017, a.Location, "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
1540 Builder.SetCustomAttribute (customBuilder);
1544 /// It is called very early therefore can resolve only predefined attributes
1546 public void ResolveAttributes ()
1549 Attribute a = ResolveAttribute (TypeManager.default_charset_type);
1551 DefaultCharSet = a.GetCharSetValue ();
1552 switch (DefaultCharSet) {
1557 DefaultCharSetType = TypeAttributes.AutoClass;
1559 case CharSet.Unicode:
1560 DefaultCharSetType = TypeAttributes.UnicodeClass;
1563 Report.Error (1724, a.Location, "Value specified for the argument to 'System.Runtime.InteropServices.DefaultCharSetAttribute' is not valid");
1570 public override string[] ValidAttributeTargets {
1572 return attribute_targets;