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);
148 // Get the complete AssemblyName from the builder
149 // (We need to get the public key and token)
150 Assembly.Name = Assembly.Builder.GetName ();
154 // Pass a path-less name to DefineDynamicModule. Wonder how
155 // this copes with output in different directories then.
156 // FIXME: figure out how this copes with --output /tmp/blah
158 // If the third argument is true, the ModuleBuilder will dynamically
159 // load the default symbol writer.
161 Module.Builder = Assembly.Builder.DefineDynamicModule (
162 Basename (name), Basename (output), false);
164 if (want_debugging_support)
165 InitializeSymbolWriter (output);
170 static public void Save (string name)
173 Assembly.Builder.Save (Basename (name));
175 if (SymbolWriter != null)
176 SymbolWriter.WriteSymbolFile ();
178 catch (COMException) {
179 if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
182 // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies
183 Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
184 RootContext.StrongNameKeyFile +
185 "', Use MCS with the Mono runtime or CSC to compile this assembly.");
187 catch (System.IO.IOException io) {
188 Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
190 catch (System.UnauthorizedAccessException ua) {
191 Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message);
197 public interface IResolveContext
199 DeclSpace DeclContainer { get; }
200 bool IsInObsoleteScope { get; }
201 bool IsInUnsafeScope { get; }
203 // the declcontainer to lookup for type-parameters. Should only use LookupGeneric on it.
205 // FIXME: This is somewhat of a hack. We don't need a full DeclSpace for this. We just need the
206 // current type parameters in scope. IUIC, that will require us to rewrite GenericMethod.
207 // Maybe we can replace this with a 'LookupGeneric (string)' instead, but we'll have to
208 // handle generic method overrides differently
209 DeclSpace GenericDeclContainer { get; }
213 /// An Emit Context is created for each body of code (from methods,
214 /// properties bodies, indexer bodies or constructor bodies)
216 public class EmitContext : IResolveContext {
219 public DeclSpace TypeContainer;
220 public ILGenerator ig;
223 public enum Flags : byte {
225 /// This flag tracks the `checked' state of the compilation,
226 /// it controls whether we should generate code that does overflow
227 /// checking, or if we generate code that ignores overflows.
229 /// The default setting comes from the command line option to generate
230 /// checked or unchecked code plus any source code changes using the
231 /// checked/unchecked statements or expressions. Contrast this with
232 /// the ConstantCheckState flag.
237 /// The constant check state is always set to `true' and cant be changed
238 /// from the command line. The source code can change this setting with
239 /// the `checked' and `unchecked' statements and expressions.
241 ConstantCheckState = 1 << 1,
243 AllCheckStateFlags = CheckState | ConstantCheckState,
246 /// Whether we are inside an unsafe block
254 /// Whether control flow analysis is enabled
256 DoFlowAnalysis = 1 << 5,
259 /// Whether control flow analysis is disabled on structs
260 /// (only meaningful when DoFlowAnalysis is set)
262 OmitStructFlowAnalysis = 1 << 6
268 /// Whether we are emitting code inside a static or instance method
270 public bool IsStatic;
273 /// Whether the actual created method is static or instance method.
274 /// Althoug the method might be declared as `static', if an anonymous
275 /// method is involved, we might turn this into an instance method.
277 /// So this reflects the low-level staticness of the method, while
278 /// IsStatic represents the semantic, high-level staticness.
280 public bool MethodIsStatic;
283 /// Whether we are emitting a field initializer
285 public bool IsFieldInitializer;
288 /// The value that is allowed to be returned or NULL if there is no
291 public Type ReturnType;
294 /// Points to the Type (extracted from the TypeContainer) that
295 /// declares this body of code
297 public Type ContainerType;
300 /// Whether this is generating code for a constructor
302 public bool IsConstructor;
305 /// Keeps track of the Type to LocalBuilder temporary storage created
306 /// to store structures (used to compute the address of the structure
307 /// value on structure method invocations)
309 public Hashtable temporary_storage;
311 public Block CurrentBlock;
313 public int CurrentFile;
316 /// The location where we store the return value.
318 LocalBuilder return_value;
321 /// The location where return has to jump to return the
324 public Label ReturnLabel;
327 /// If we already defined the ReturnLabel
329 public bool HasReturnLabel;
332 /// Whether we are inside an iterator block.
334 public bool InIterator;
336 public bool IsLastStatement;
339 /// Whether we are in a `fixed' initialization
341 public bool InFixedInitializer;
344 /// Whether we are inside an anonymous method.
346 public AnonymousContainer CurrentAnonymousMethod;
349 /// Location for this EmitContext
354 /// Inside an enum definition, we do not resolve enumeration values
355 /// to their enumerations, but rather to the underlying type/value
356 /// This is so EnumVal + EnumValB can be evaluated.
358 /// There is no "E operator + (E x, E y)", so during an enum evaluation
359 /// we relax the rules
361 public bool InEnumContext;
364 /// Anonymous methods can capture local variables and fields,
365 /// this object tracks it. It is copied from the TopLevelBlock
368 public CaptureContext capture_context;
370 public readonly IResolveContext ResolveContext;
373 /// The current iterator
376 public Iterator CurrentIterator {
378 if (CurrentAnonymousMethod != null)
379 return CurrentAnonymousMethod.Iterator;
385 public Iterator CurrentIterator;
389 /// Whether we are in the resolving stage or not
397 bool isAnonymousMethodAllowed = true;
400 FlowBranching current_flow_branching;
402 static int next_id = 0;
405 public override string ToString ()
407 return String.Format ("EmitContext ({0}:{1}:{2})", id,
408 CurrentIterator, capture_context, loc);
411 public EmitContext (IResolveContext rc, DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig,
412 Type return_type, int code_flags, bool is_constructor)
414 this.ResolveContext = rc;
417 TypeContainer = parent;
419 if (RootContext.Checked)
420 flags |= Flags.CheckState;
421 flags |= Flags.ConstantCheckState;
424 if ((return_type is TypeBuilder) && return_type.IsGenericTypeDefinition)
425 throw new InternalErrorException ();
428 IsStatic = (code_flags & Modifiers.STATIC) != 0;
429 MethodIsStatic = IsStatic;
430 InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0;
431 ReturnType = return_type;
432 IsConstructor = is_constructor;
435 current_phase = Phase.Created;
438 // Can only be null for the ResolveType contexts.
439 ContainerType = parent.TypeBuilder;
440 if (rc.IsInUnsafeScope)
441 flags |= Flags.InUnsafe;
445 if (ReturnType == TypeManager.void_type)
449 public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
450 Type return_type, int code_flags, bool is_constructor)
451 : this (rc, ds, ds, l, ig, return_type, code_flags, is_constructor)
455 public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
456 Type return_type, int code_flags)
457 : this (rc, ds, ds, l, ig, return_type, code_flags, false)
461 public DeclSpace DeclContainer {
462 get { return declSpace; }
463 set { declSpace = value; }
466 public DeclSpace GenericDeclContainer {
467 get { return DeclContainer; }
470 public bool CheckState {
471 get { return (flags & Flags.CheckState) != 0; }
474 public bool ConstantCheckState {
475 get { return (flags & Flags.ConstantCheckState) != 0; }
478 public bool InUnsafe {
479 get { return (flags & Flags.InUnsafe) != 0; }
482 public bool InCatch {
483 get { return (flags & Flags.InCatch) != 0; }
486 public bool InFinally {
487 get { return (flags & Flags.InFinally) != 0; }
490 public bool DoFlowAnalysis {
491 get { return (flags & Flags.DoFlowAnalysis) != 0; }
494 public bool OmitStructFlowAnalysis {
495 get { return (flags & Flags.OmitStructFlowAnalysis) != 0; }
498 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
499 // it's public so that we can use a struct at the callsite
500 public struct FlagsHandle : IDisposable
503 Flags invmask, oldval;
504 internal FlagsHandle (EmitContext ec, Flags mask, Flags val)
508 oldval = ec.flags & mask;
509 ec.flags = (ec.flags & invmask) | (val & mask);
511 public void Dispose ()
513 ec.flags = (ec.flags & invmask) | oldval;
517 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
518 public FlagsHandle With (Flags bits, bool enable)
520 return new FlagsHandle (this, bits, enable ? bits : 0);
523 public FlagsHandle WithFlowAnalysis (bool do_flow_analysis, bool omit_struct_analysis)
526 (do_flow_analysis ? Flags.DoFlowAnalysis : 0) |
527 (omit_struct_analysis ? Flags.OmitStructFlowAnalysis : 0);
528 return new FlagsHandle (this, Flags.DoFlowAnalysis | Flags.OmitStructFlowAnalysis, newflags);
531 public bool IsInObsoleteScope {
532 get { return ResolveContext.IsInObsoleteScope; }
535 public bool IsInUnsafeScope {
536 get { return InUnsafe || ResolveContext.IsInUnsafeScope; }
539 public bool IsAnonymousMethodAllowed {
540 get { return isAnonymousMethodAllowed; }
541 set { isAnonymousMethodAllowed = value; }
544 public FlowBranching CurrentBranching {
545 get { return current_flow_branching; }
548 public bool HaveCaptureInfo {
549 get { return capture_context != null; }
552 public void EmitScopeInitFromBlock (Block b)
554 if (capture_context != null)
555 capture_context.EmitScopeInitFromBlock (this, b);
559 // Starts a new code branching. This inherits the state of all local
560 // variables and parameters from the current branching.
562 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
564 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
565 return current_flow_branching;
569 // Starts a new code branching for block `block'.
571 public FlowBranching StartFlowBranching (Block block)
573 FlowBranching.BranchingType type;
575 if ((CurrentBranching != null) &&
576 (CurrentBranching.Type == FlowBranching.BranchingType.Switch))
577 type = FlowBranching.BranchingType.SwitchSection;
579 type = FlowBranching.BranchingType.Block;
581 flags |= Flags.DoFlowAnalysis;
583 current_flow_branching = FlowBranching.CreateBranching (
584 CurrentBranching, type, block, block.StartLocation);
585 return current_flow_branching;
588 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
590 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
591 current_flow_branching = branching;
595 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
597 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
598 current_flow_branching = branching;
602 public FlowBranchingToplevel StartFlowBranching (ToplevelBlock stmt)
604 FlowBranchingToplevel branching = new FlowBranchingToplevel (CurrentBranching, stmt);
605 current_flow_branching = branching;
610 // Ends a code branching. Merges the state of locals and parameters
611 // from all the children of the ending branching.
613 public FlowBranching.UsageVector DoEndFlowBranching ()
615 FlowBranching old = current_flow_branching;
616 current_flow_branching = current_flow_branching.Parent;
618 return current_flow_branching.MergeChild (old);
622 // Ends a code branching. Merges the state of locals and parameters
623 // from all the children of the ending branching.
625 public FlowBranching.Reachability EndFlowBranching ()
627 FlowBranching.UsageVector vector = DoEndFlowBranching ();
629 return vector.Reachability;
633 // Kills the current code branching. This throws away any changed state
634 // information and should only be used in case of an error.
636 public void KillFlowBranching ()
638 current_flow_branching = current_flow_branching.Parent;
641 public void CaptureVariable (LocalInfo li)
643 capture_context.AddLocal (CurrentAnonymousMethod, li);
644 li.IsCaptured = true;
647 public void CaptureParameter (string name, Type t, int idx)
649 capture_context.AddParameter (this, CurrentAnonymousMethod, name, t, idx);
652 public void CaptureThis ()
654 capture_context.CaptureThis (CurrentAnonymousMethod);
659 // Use to register a field as captured
661 public void CaptureField (FieldExpr fe)
663 capture_context.AddField (this, CurrentAnonymousMethod, fe);
667 // Whether anonymous methods have captured variables
669 public bool HaveCapturedVariables ()
671 if (capture_context != null)
672 return capture_context.HaveCapturedVariables;
677 // Whether anonymous methods have captured fields or this.
679 public bool HaveCapturedFields ()
681 if (capture_context != null)
682 return capture_context.HaveCapturedFields;
687 // Emits the instance pointer for the host method
689 public void EmitMethodHostInstance (EmitContext target, AnonymousMethod am)
691 if (capture_context != null)
692 capture_context.EmitMethodHostInstance (target, am);
694 target.ig.Emit (OpCodes.Ldnull);
696 target.ig.Emit (OpCodes.Ldarg_0);
700 // Returns whether the `local' variable has been captured by an anonymous
703 public bool IsCaptured (LocalInfo local)
705 return capture_context.IsCaptured (local);
708 public bool IsParameterCaptured (string name)
710 if (capture_context != null)
711 return capture_context.IsParameterCaptured (name);
715 public void EmitMeta (ToplevelBlock b)
717 if (capture_context != null)
718 capture_context.EmitAnonymousHelperClasses (this);
722 ReturnLabel = ig.DefineLabel ();
726 // Here until we can fix the problem with Mono.CSharp.Switch, which
727 // currently can not cope with ig == null during resolve (which must
728 // be fixed for switch statements to work on anonymous methods).
730 public void EmitTopBlock (IMethodData md, ToplevelBlock block)
737 if (ResolveTopBlock (null, block, md.ParameterInfo, md, out unreachable)){
740 current_phase = Phase.Emitting;
741 EmitResolvedTopBlock (block, unreachable);
747 public bool ResolveTopBlock (EmitContext anonymous_method_host, ToplevelBlock block,
748 Parameters ip, IMethodData md, out bool unreachable)
750 current_phase = Phase.Resolving;
757 capture_context = block.CaptureContext;
760 CurrentFile = loc.File;
765 if (!block.ResolveMeta (this, ip))
768 using (this.With (EmitContext.Flags.DoFlowAnalysis, true)) {
769 FlowBranchingToplevel top_level;
770 if (anonymous_method_host != null)
771 top_level = new FlowBranchingToplevel (anonymous_method_host.CurrentBranching, block);
773 top_level = block.TopLevelBranching;
775 current_flow_branching = top_level;
776 bool ok = block.Resolve (this);
777 current_flow_branching = null;
782 FlowBranching.Reachability reachability = top_level.End ();
783 if (reachability.IsUnreachable)
787 } catch (Exception e) {
788 Console.WriteLine ("Exception caught by the compiler while compiling:");
789 Console.WriteLine (" Block that caused the problem begin at: " + loc);
791 if (CurrentBlock != null){
792 Console.WriteLine (" Block being compiled: [{0},{1}]",
793 CurrentBlock.StartLocation, CurrentBlock.EndLocation);
795 Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
800 if (ReturnType != null && !unreachable) {
801 if (CurrentAnonymousMethod == null) {
802 Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
804 } else if (!CurrentAnonymousMethod.IsIterator) {
805 Report.Error (1643, CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
806 CurrentAnonymousMethod.GetSignatureForError ());
811 block.CompleteContexts ();
816 public void EmitResolvedTopBlock (ToplevelBlock block, bool unreachable)
822 ig.MarkLabel (ReturnLabel);
824 if (return_value != null){
825 ig.Emit (OpCodes.Ldloc, return_value);
826 ig.Emit (OpCodes.Ret);
829 // If `HasReturnLabel' is set, then we already emitted a
830 // jump to the end of the method, so we must emit a `ret'
833 // Unfortunately, System.Reflection.Emit automatically emits
834 // a leave to the end of a finally block. This is a problem
835 // if no code is following the try/finally block since we may
836 // jump to a point after the end of the method.
837 // As a workaround, we're always creating a return label in
841 bool in_iterator = (CurrentAnonymousMethod != null) &&
842 CurrentAnonymousMethod.IsIterator && InIterator;
844 if ((block != null) && block.IsDestructor) {
845 // Nothing to do; S.R.E automatically emits a leave.
846 } else if (HasReturnLabel || (!unreachable && !in_iterator)) {
847 if (ReturnType != null)
848 ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
849 ig.Emit (OpCodes.Ret);
854 // Close pending helper classes if we are the toplevel
856 if (capture_context != null && capture_context.ParentToplevel == null)
857 capture_context.CloseAnonymousHelperClasses ();
861 /// This is called immediately before emitting an IL opcode to tell the symbol
862 /// writer to which source line this opcode belongs.
864 public void Mark (Location loc, bool check_file)
866 if ((CodeGen.SymbolWriter == null) || loc.IsNull)
869 if (check_file && (CurrentFile != loc.File))
872 CodeGen.SymbolWriter.MarkSequencePoint (ig, loc.Row, loc.Column);
875 public void DefineLocalVariable (string name, LocalBuilder builder)
877 if (CodeGen.SymbolWriter == null)
880 CodeGen.SymbolWriter.DefineLocalVariable (name, builder);
883 public void BeginScope ()
887 if (CodeGen.SymbolWriter != null)
888 CodeGen.SymbolWriter.OpenScope(ig);
891 public void EndScope ()
895 if (CodeGen.SymbolWriter != null)
896 CodeGen.SymbolWriter.CloseScope(ig);
900 /// Returns a temporary storage for a variable of type t as
901 /// a local variable in the current body.
903 public LocalBuilder GetTemporaryLocal (Type t)
905 if (temporary_storage != null) {
906 object o = temporary_storage [t];
910 o = s.Count == 0 ? null : s.Pop ();
912 temporary_storage.Remove (t);
916 return (LocalBuilder) o;
918 return ig.DeclareLocal (t);
921 public void FreeTemporaryLocal (LocalBuilder b, Type t)
925 if (temporary_storage == null) {
926 temporary_storage = new Hashtable ();
927 temporary_storage [t] = b;
930 object o = temporary_storage [t];
932 temporary_storage [t] = b;
940 temporary_storage [t] = s;
946 /// Current loop begin and end labels.
948 public Label LoopBegin, LoopEnd;
951 /// Default target in a switch statement. Only valid if
954 public Label DefaultTarget;
957 /// If this is non-null, points to the current switch statement
959 public Switch Switch;
962 /// ReturnValue creates on demand the LocalBuilder for the
963 /// return value from the function. By default this is not
964 /// used. This is only required when returns are found inside
965 /// Try or Catch statements.
967 /// This method is typically invoked from the Emit phase, so
968 /// we allow the creation of a return label if it was not
969 /// requested during the resolution phase. Could be cleaned
970 /// up, but it would replicate a lot of logic in the Emit phase
971 /// of the code that uses it.
973 public LocalBuilder TemporaryReturn ()
975 if (return_value == null){
976 return_value = ig.DeclareLocal (ReturnType);
977 if (!HasReturnLabel){
978 ReturnLabel = ig.DefineLabel ();
979 HasReturnLabel = true;
987 /// This method is used during the Resolution phase to flag the
988 /// need to define the ReturnLabel
990 public void NeedReturnLabel ()
992 if (current_phase != Phase.Resolving){
994 // The reason is that the `ReturnLabel' is declared between
995 // resolution and emission
997 throw new Exception ("NeedReturnLabel called from Emit phase, should only be called during Resolve");
1000 if (!InIterator && !HasReturnLabel)
1001 HasReturnLabel = true;
1005 // Emits the proper object to address fields on a remapped
1006 // variable/parameter to field in anonymous-method/iterator proxy classes.
1008 public void EmitThis (bool need_address)
1010 ig.Emit (OpCodes.Ldarg_0);
1011 if (capture_context != null && CurrentAnonymousMethod != null){
1012 ScopeInfo si = CurrentAnonymousMethod.Scope;
1014 if (si.ParentLink != null)
1015 ig.Emit (OpCodes.Ldfld, si.ParentLink);
1016 if (si.THIS != null){
1017 if (need_address && TypeManager.IsValueType (si.THIS.FieldType))
1018 ig.Emit (OpCodes.Ldflda, si.THIS);
1020 ig.Emit (OpCodes.Ldfld, si.THIS);
1023 si = si.ParentScope;
1029 // Emits the code necessary to load the instance required
1030 // to access the captured LocalInfo
1032 public void EmitCapturedVariableInstance (LocalInfo li)
1034 if (capture_context == null)
1035 throw new Exception ("Calling EmitCapturedContext when there is no capture_context");
1037 capture_context.EmitCapturedVariableInstance (this, li, CurrentAnonymousMethod);
1040 public void EmitParameter (string name, bool leave_copy, bool prepared, ref LocalTemporary temp)
1042 capture_context.EmitParameter (this, name, leave_copy, prepared, ref temp);
1045 public void EmitAssignParameter (string name, Expression source, bool leave_copy, bool prepare_for_load, ref LocalTemporary temp)
1047 capture_context.EmitAssignParameter (this, name, source, leave_copy, prepare_for_load, ref temp);
1050 public void EmitAddressOfParameter (string name)
1052 capture_context.EmitAddressOfParameter (this, name);
1055 public Expression GetThis (Location loc)
1058 if (CurrentBlock != null)
1059 my_this = new This (CurrentBlock, loc);
1061 my_this = new This (loc);
1063 if (!my_this.ResolveBase (this))
1071 public abstract class CommonAssemblyModulClass : Attributable, IResolveContext {
1073 protected CommonAssemblyModulClass ():
1078 public void AddAttributes (ArrayList attrs)
1080 foreach (Attribute a in attrs)
1083 if (attributes == null) {
1084 attributes = new Attributes (attrs);
1087 attributes.AddAttributes (attrs);
1090 public virtual void Emit (TypeContainer tc)
1092 if (OptAttributes == null)
1095 OptAttributes.Emit ();
1098 protected Attribute ResolveAttribute (Type a_type)
1100 Attribute a = OptAttributes.Search (a_type);
1107 public override IResolveContext ResolveContext {
1108 get { return this; }
1111 #region IResolveContext Members
1113 public DeclSpace DeclContainer {
1114 get { return RootContext.ToplevelTypes; }
1117 public DeclSpace GenericDeclContainer {
1118 get { return DeclContainer; }
1121 public bool IsInObsoleteScope {
1122 get { return false; }
1125 public bool IsInUnsafeScope {
1126 get { return false; }
1132 public class AssemblyClass : CommonAssemblyModulClass {
1133 // TODO: make it private and move all builder based methods here
1134 public AssemblyBuilder Builder;
1135 bool is_cls_compliant;
1136 bool wrap_non_exception_throws;
1138 public Attribute ClsCompliantAttribute;
1140 ListDictionary declarative_security;
1142 public AssemblyName Name;
1143 MethodInfo add_type_forwarder;
1146 // Module is here just because of error messages
1147 static string[] attribute_targets = new string [] { "assembly", "module" };
1149 public AssemblyClass (): base ()
1151 wrap_non_exception_throws = true;
1154 public bool IsClsCompliant {
1156 return is_cls_compliant;
1160 public bool WrapNonExceptionThrows {
1162 return wrap_non_exception_throws;
1166 public override AttributeTargets AttributeTargets {
1168 return AttributeTargets.Assembly;
1172 public override bool IsClsComplianceRequired ()
1174 return is_cls_compliant;
1177 public void Resolve ()
1179 if (OptAttributes == null)
1182 // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
1183 if (!OptAttributes.CheckTargets())
1186 ClsCompliantAttribute = ResolveAttribute (TypeManager.cls_compliant_attribute_type);
1187 if (ClsCompliantAttribute != null) {
1188 is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue ();
1192 Attribute a = ResolveAttribute (TypeManager.runtime_compatibility_attr_type);
1194 object val = a.GetPropertyValue ("WrapNonExceptionThrows");
1196 wrap_non_exception_throws = (bool)val;
1202 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob)
1205 // check for possible ECMA key
1206 if (strongNameBlob.Length == 16) {
1207 // will be rejected if not "the" ECMA key
1208 an.SetPublicKey (strongNameBlob);
1211 // take it, with or without, a private key
1212 RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
1213 // and make sure we only feed the public part to Sys.Ref
1214 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
1216 // AssemblyName.SetPublicKey requires an additional header
1217 byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
1219 byte[] encodedPublicKey = new byte [12 + publickey.Length];
1220 Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
1221 Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
1222 an.SetPublicKey (encodedPublicKey);
1226 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded");
1227 Environment.Exit (1);
1231 // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
1232 public AssemblyName GetAssemblyName (string name, string output)
1234 if (OptAttributes != null) {
1235 foreach (Attribute a in OptAttributes.Attrs) {
1236 // cannot rely on any resolve-based members before you call Resolve
1237 if (a.ExplicitTarget == null || a.ExplicitTarget != "assembly")
1240 // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
1241 // However, this is invoked by CodeGen.Init, when none of the namespaces
1243 // TODO: Does not handle quoted attributes properly
1245 case "AssemblyKeyFile":
1246 case "AssemblyKeyFileAttribute":
1247 case "System.Reflection.AssemblyKeyFileAttribute":
1248 if (RootContext.StrongNameKeyFile != null) {
1249 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1250 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1251 "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
1254 string value = a.GetString ();
1255 if (value.Length != 0)
1256 RootContext.StrongNameKeyFile = value;
1259 case "AssemblyKeyName":
1260 case "AssemblyKeyNameAttribute":
1261 case "System.Reflection.AssemblyKeyNameAttribute":
1262 if (RootContext.StrongNameKeyContainer != null) {
1263 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1264 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1265 "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
1268 string value = a.GetString ();
1269 if (value.Length != 0)
1270 RootContext.StrongNameKeyContainer = value;
1273 case "AssemblyDelaySign":
1274 case "AssemblyDelaySignAttribute":
1275 case "System.Reflection.AssemblyDelaySignAttribute":
1276 RootContext.StrongNameDelaySign = a.GetBoolean ();
1282 AssemblyName an = new AssemblyName ();
1283 an.Name = Path.GetFileNameWithoutExtension (name);
1285 // note: delay doesn't apply when using a key container
1286 if (RootContext.StrongNameKeyContainer != null) {
1287 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
1291 // strongname is optional
1292 if (RootContext.StrongNameKeyFile == null)
1295 string AssemblyDir = Path.GetDirectoryName (output);
1297 // the StrongName key file may be relative to (a) the compiled
1298 // file or (b) to the output assembly. See bugzilla #55320
1299 // http://bugzilla.ximian.com/show_bug.cgi?id=55320
1301 // (a) relative to the compiled file
1302 string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
1303 bool exist = File.Exists (filename);
1304 if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
1305 // (b) relative to the outputed assembly
1306 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
1307 exist = File.Exists (filename);
1311 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
1312 byte[] snkeypair = new byte [fs.Length];
1313 fs.Read (snkeypair, 0, snkeypair.Length);
1315 if (RootContext.StrongNameDelaySign) {
1316 // delayed signing - DO NOT include private key
1317 SetPublicKey (an, snkeypair);
1320 // no delay so we make sure we have the private key
1322 CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
1323 an.KeyPair = new StrongNameKeyPair (snkeypair);
1325 catch (CryptographicException) {
1326 if (snkeypair.Length == 16) {
1327 // error # is different for ECMA key
1328 Report.Error (1606, "Could not sign the assembly. " +
1329 "ECMA key can only be used to delay-sign assemblies");
1332 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not have a private key");
1340 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not exist");
1346 void Error_AssemblySigning (string text)
1348 Report.Error (1548, "Error during assembly signing. " + text);
1352 bool CheckInternalsVisibleAttribute (Attribute a)
1354 string assembly_name = a.GetString ();
1355 if (assembly_name.Length == 0)
1358 AssemblyName aname = null;
1360 aname = new AssemblyName (assembly_name);
1361 } catch (FileLoadException) {
1362 } catch (ArgumentException) {
1365 // Bad assembly name format
1367 Report.Warning (1700, 3, a.Location, "Assembly reference `" + assembly_name + "' is invalid and cannot be resolved");
1368 // Report error if we have defined Version or Culture
1369 else if (aname.Version != null || aname.CultureInfo != null)
1370 throw new Exception ("Friend assembly `" + a.GetString () +
1371 "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
1372 else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null) {
1373 Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." +
1374 " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
1382 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1384 if (a.Type.IsSubclassOf (TypeManager.security_attr_type) && a.CheckSecurityActionValidity (true)) {
1385 if (declarative_security == null)
1386 declarative_security = new ListDictionary ();
1388 a.ExtractSecurityPermissionSet (declarative_security);
1392 if (a.Type == TypeManager.assembly_culture_attribute_type) {
1393 string value = a.GetString ();
1394 if (value == null || value.Length == 0)
1397 if (RootContext.Target == Target.Exe) {
1398 a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
1404 if (a.Type == TypeManager.internals_visible_attr_type && !CheckInternalsVisibleAttribute (a))
1407 if (a.Type == TypeManager.type_forwarder_attr_type) {
1408 Type t = a.GetArgumentType ();
1409 if (t == null || TypeManager.HasElementType (t)) {
1410 Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
1414 if (TypeManager.LookupDeclSpace (t) != null) {
1415 Report.SymbolRelatedToPreviousError (t);
1416 Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
1417 TypeManager.CSharpName (t));
1422 Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
1423 TypeManager.CSharpName (t));
1427 if (t.IsGenericType) {
1428 Report.Error (733, a.Location, "Cannot forward generic type `{0}'", TypeManager.CSharpName (t));
1432 if (add_type_forwarder == null) {
1433 add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder",
1434 BindingFlags.NonPublic | BindingFlags.Instance);
1436 if (add_type_forwarder == null) {
1437 Report.RuntimeMissingSupport (a.Location, "TypeForwardedTo attribute");
1442 add_type_forwarder.Invoke (Builder, new object[] { t });
1447 Builder.SetCustomAttribute (customBuilder);
1450 public override void Emit (TypeContainer tc)
1455 // FIXME: Does this belong inside SRE.AssemblyBuilder instead?
1456 if (OptAttributes == null || !OptAttributes.Contains (TypeManager.runtime_compatibility_attr_type)) {
1457 ConstructorInfo ci = TypeManager.GetConstructor (
1458 TypeManager.runtime_compatibility_attr_type, Type.EmptyTypes);
1459 PropertyInfo [] pis = new PropertyInfo [1];
1460 pis [0] = TypeManager.GetProperty (
1461 TypeManager.runtime_compatibility_attr_type, "WrapNonExceptionThrows");
1462 object [] pargs = new object [1];
1464 Builder.SetCustomAttribute (new CustomAttributeBuilder (ci, new object [0], pis, pargs));
1468 if (declarative_security != null) {
1470 MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1471 object builder_instance = Builder;
1474 // Microsoft runtime hacking
1475 if (add_permission == null) {
1476 Type assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData");
1477 add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1479 FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
1480 builder_instance = fi.GetValue (Builder);
1483 object[] args = new object [] { declarative_security [SecurityAction.RequestMinimum],
1484 declarative_security [SecurityAction.RequestOptional],
1485 declarative_security [SecurityAction.RequestRefuse] };
1486 add_permission.Invoke (builder_instance, args);
1489 Report.RuntimeMissingSupport (Location.Null, "assembly permission setting");
1494 public override string[] ValidAttributeTargets {
1496 return attribute_targets;
1501 public class ModuleClass : CommonAssemblyModulClass {
1502 // TODO: make it private and move all builder based methods here
1503 public ModuleBuilder Builder;
1504 bool m_module_is_unsafe;
1506 public CharSet DefaultCharSet = CharSet.Ansi;
1507 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
1509 static string[] attribute_targets = new string [] { "module" };
1511 public ModuleClass (bool is_unsafe)
1513 m_module_is_unsafe = is_unsafe;
1516 public override AttributeTargets AttributeTargets {
1518 return AttributeTargets.Module;
1522 public override bool IsClsComplianceRequired ()
1524 return CodeGen.Assembly.IsClsCompliant;
1527 public override void Emit (TypeContainer tc)
1531 if (!m_module_is_unsafe)
1534 if (TypeManager.unverifiable_code_ctor == null) {
1535 Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute.");
1539 Builder.SetCustomAttribute (new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
1542 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1544 if (a.Type == TypeManager.cls_compliant_attribute_type) {
1545 if (CodeGen.Assembly.ClsCompliantAttribute == null) {
1546 Report.Warning (3012, 1, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
1548 else if (CodeGen.Assembly.IsClsCompliant != a.GetBoolean ()) {
1549 Report.SymbolRelatedToPreviousError (CodeGen.Assembly.ClsCompliantAttribute.Location, CodeGen.Assembly.ClsCompliantAttribute.GetSignatureForError ());
1550 Report.Error (3017, a.Location, "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
1555 Builder.SetCustomAttribute (customBuilder);
1559 /// It is called very early therefore can resolve only predefined attributes
1561 public void Resolve ()
1564 if (OptAttributes == null)
1567 if (!OptAttributes.CheckTargets())
1570 Attribute a = ResolveAttribute (TypeManager.default_charset_type);
1572 DefaultCharSet = a.GetCharSetValue ();
1573 switch (DefaultCharSet) {
1578 DefaultCharSetType = TypeAttributes.AutoClass;
1580 case CharSet.Unicode:
1581 DefaultCharSetType = TypeAttributes.UnicodeClass;
1584 Report.Error (1724, a.Location, "Value specified for the argument to 'System.Runtime.InteropServices.DefaultCharSetAttribute' is not valid");
1591 public override string[] ValidAttributeTargets {
1593 return attribute_targets;