* DataGrid.cs: remove the XXX'ed check at the top of
[mcs.git] / mcs / codegen.cs
blob9668b92eef9099d98c1d7df19f1164c7c9782a87
1 //
2 // codegen.cs: The code generator
3 //
4 // Author:
5 // Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001, 2002, 2003 Ximian, Inc.
8 // (C) 2004 Novell, Inc.
9 //
12 // Please leave this defined on SVN: The idea is that when we ship the
13 // compiler to end users, if the compiler crashes, they have a chance
14 // to narrow down the problem.
16 // Only remove it if you need to debug locally on your tree.
18 //#define PRODUCTION
20 using System;
21 using System.IO;
22 using System.Collections;
23 using System.Collections.Specialized;
24 using System.Reflection;
25 using System.Reflection.Emit;
26 using System.Runtime.InteropServices;
27 using System.Security;
28 using System.Security.Cryptography;
29 using System.Security.Permissions;
31 using Mono.Security.Cryptography;
33 namespace Mono.CSharp {
35 /// <summary>
36 /// Code generator class.
37 /// </summary>
38 public class CodeGen {
39 static AppDomain current_domain;
40 static public SymbolWriter SymbolWriter;
42 public static AssemblyClass Assembly;
43 public static ModuleClass Module;
45 static CodeGen ()
47 Reset ();
50 public static void Reset ()
52 Assembly = new AssemblyClass ();
53 Module = new ModuleClass (RootContext.Unsafe);
56 public static string Basename (string name)
58 int pos = name.LastIndexOf ('/');
60 if (pos != -1)
61 return name.Substring (pos + 1);
63 pos = name.LastIndexOf ('\\');
64 if (pos != -1)
65 return name.Substring (pos + 1);
67 return name;
70 public static string Dirname (string name)
72 int pos = name.LastIndexOf ('/');
74 if (pos != -1)
75 return name.Substring (0, pos);
77 pos = name.LastIndexOf ('\\');
78 if (pos != -1)
79 return name.Substring (0, pos);
81 return ".";
84 static public string FileName;
87 // Initializes the symbol writer
89 static void InitializeSymbolWriter (string filename)
91 SymbolWriter = SymbolWriter.GetSymbolWriter (Module.Builder, filename);
94 // If we got an ISymbolWriter instance, initialize it.
96 if (SymbolWriter == null) {
97 Report.Warning (
98 -18, 1, "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll). This is normally an installation problem. Please make sure to compile and install the mcs/class/Mono.CompilerServices.SymbolWriter directory.");
99 return;
104 // Initializes the code generator variables
106 static public bool Init (string name, string output, bool want_debugging_support)
108 FileName = output;
109 AssemblyName an = Assembly.GetAssemblyName (name, output);
110 if (an == null)
111 return false;
113 if (an.KeyPair != null) {
114 // If we are going to strong name our assembly make
115 // sure all its refs are strong named
116 foreach (Assembly a in RootNamespace.Global.Assemblies) {
117 AssemblyName ref_name = a.GetName ();
118 byte [] b = ref_name.GetPublicKeyToken ();
119 if (b == null || b.Length == 0) {
120 Report.Error (1577, "Assembly generation failed " +
121 "-- Referenced assembly '" +
122 ref_name.Name +
123 "' does not have a strong name.");
124 //Environment.Exit (1);
129 current_domain = AppDomain.CurrentDomain;
131 try {
132 Assembly.Builder = current_domain.DefineDynamicAssembly (an,
133 AssemblyBuilderAccess.Save, Dirname (name));
135 catch (ArgumentException) {
136 // specified key may not be exportable outside it's container
137 if (RootContext.StrongNameKeyContainer != null) {
138 Report.Error (1548, "Could not access the key inside the container `" +
139 RootContext.StrongNameKeyContainer + "'.");
140 Environment.Exit (1);
142 return false;
144 catch (CryptographicException) {
145 if ((RootContext.StrongNameKeyContainer != null) || (RootContext.StrongNameKeyFile != null)) {
146 Report.Error (1548, "Could not use the specified key to strongname the assembly.");
147 Environment.Exit (1);
149 return false;
152 #if GMCS_SOURCE
153 // Get the complete AssemblyName from the builder
154 // (We need to get the public key and token)
155 Assembly.Name = Assembly.Builder.GetName ();
156 #endif
159 // Pass a path-less name to DefineDynamicModule. Wonder how
160 // this copes with output in different directories then.
161 // FIXME: figure out how this copes with --output /tmp/blah
163 // If the third argument is true, the ModuleBuilder will dynamically
164 // load the default symbol writer.
166 Module.Builder = Assembly.Builder.DefineDynamicModule (
167 Basename (name), Basename (output), false);
169 if (want_debugging_support)
170 InitializeSymbolWriter (output);
172 return true;
175 static public void Save (string name)
177 try {
178 Assembly.Builder.Save (Basename (name));
180 if (SymbolWriter != null)
181 SymbolWriter.WriteSymbolFile ();
183 catch (COMException) {
184 if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
185 throw;
187 // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies
188 Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
189 RootContext.StrongNameKeyFile +
190 "', Use MCS with the Mono runtime or CSC to compile this assembly.");
192 catch (System.IO.IOException io) {
193 Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
195 catch (System.UnauthorizedAccessException ua) {
196 Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message);
202 public interface IResolveContext
204 DeclSpace DeclContainer { get; }
205 bool IsInObsoleteScope { get; }
206 bool IsInUnsafeScope { get; }
208 // the declcontainer to lookup for type-parameters. Should only use LookupGeneric on it.
210 // FIXME: This is somewhat of a hack. We don't need a full DeclSpace for this. We just need the
211 // current type parameters in scope. IUIC, that will require us to rewrite GenericMethod.
212 // Maybe we can replace this with a 'LookupGeneric (string)' instead, but we'll have to
213 // handle generic method overrides differently
214 DeclSpace GenericDeclContainer { get; }
217 /// <summary>
218 /// An Emit Context is created for each body of code (from methods,
219 /// properties bodies, indexer bodies or constructor bodies)
220 /// </summary>
221 public class EmitContext : IResolveContext {
223 DeclSpace decl_space;
225 public DeclSpace TypeContainer;
226 public ILGenerator ig;
228 [Flags]
229 public enum Flags : byte {
230 /// <summary>
231 /// This flag tracks the `checked' state of the compilation,
232 /// it controls whether we should generate code that does overflow
233 /// checking, or if we generate code that ignores overflows.
235 /// The default setting comes from the command line option to generate
236 /// checked or unchecked code plus any source code changes using the
237 /// checked/unchecked statements or expressions. Contrast this with
238 /// the ConstantCheckState flag.
239 /// </summary>
240 CheckState = 1 << 0,
242 /// <summary>
243 /// The constant check state is always set to `true' and cant be changed
244 /// from the command line. The source code can change this setting with
245 /// the `checked' and `unchecked' statements and expressions.
246 /// </summary>
247 ConstantCheckState = 1 << 1,
249 AllCheckStateFlags = CheckState | ConstantCheckState,
251 /// <summary>
252 /// Whether we are inside an unsafe block
253 /// </summary>
254 InUnsafe = 1 << 2,
256 InCatch = 1 << 3,
257 InFinally = 1 << 4,
259 /// <summary>
260 /// Whether control flow analysis is enabled
261 /// </summary>
262 DoFlowAnalysis = 1 << 5,
264 /// <summary>
265 /// Whether control flow analysis is disabled on structs
266 /// (only meaningful when DoFlowAnalysis is set)
267 /// </summary>
268 OmitStructFlowAnalysis = 1 << 6
271 Flags flags;
273 /// <summary>
274 /// Whether we are emitting code inside a static or instance method
275 /// </summary>
276 public bool IsStatic;
278 /// <summary>
279 /// Whether the actual created method is static or instance method.
280 /// Althoug the method might be declared as `static', if an anonymous
281 /// method is involved, we might turn this into an instance method.
283 /// So this reflects the low-level staticness of the method, while
284 /// IsStatic represents the semantic, high-level staticness.
285 /// </summary>
286 public bool MethodIsStatic;
288 /// <summary>
289 /// Whether we are emitting a field initializer
290 /// </summary>
291 public bool IsFieldInitializer;
293 /// <summary>
294 /// If this is true, then Return and ContextualReturn statements
295 /// will set the ReturnType value based on the expression types
296 /// of each return statement instead of the method return type
297 /// (which is initially null).
298 /// </summary>
299 public bool InferReturnType;
301 /// <summary>
302 /// The value that is allowed to be returned or NULL if there is no
303 /// return type.
304 /// </summary>
305 Type return_type;
307 /// <summary>
308 /// Points to the Type (extracted from the TypeContainer) that
309 /// declares this body of code
310 /// </summary>
311 public Type ContainerType;
313 /// <summary>
314 /// Whether this is generating code for a constructor
315 /// </summary>
316 public bool IsConstructor;
318 /// <summary>
319 /// Keeps track of the Type to LocalBuilder temporary storage created
320 /// to store structures (used to compute the address of the structure
321 /// value on structure method invocations)
322 /// </summary>
323 public Hashtable temporary_storage;
325 public Block CurrentBlock;
327 public int CurrentFile;
329 /// <summary>
330 /// The location where we store the return value.
331 /// </summary>
332 LocalBuilder return_value;
334 /// <summary>
335 /// The location where return has to jump to return the
336 /// value
337 /// </summary>
338 public Label ReturnLabel;
340 /// <summary>
341 /// If we already defined the ReturnLabel
342 /// </summary>
343 public bool HasReturnLabel;
345 /// <summary>
346 /// Whether we are inside an iterator block.
347 /// </summary>
348 public bool InIterator;
350 /// <summary>
351 /// Whether we are in a `fixed' initialization
352 /// </summary>
353 public bool InFixedInitializer;
355 /// <summary>
356 /// Whether we are inside an anonymous method.
357 /// </summary>
358 public AnonymousContainer CurrentAnonymousMethod;
360 /// <summary>
361 /// Location for this EmitContext
362 /// </summary>
363 public Location loc;
365 /// <summary>
366 /// Inside an enum definition, we do not resolve enumeration values
367 /// to their enumerations, but rather to the underlying type/value
368 /// This is so EnumVal + EnumValB can be evaluated.
370 /// There is no "E operator + (E x, E y)", so during an enum evaluation
371 /// we relax the rules
372 /// </summary>
373 public bool InEnumContext;
375 public readonly IResolveContext ResolveContext;
377 /// <summary>
378 /// The current iterator
379 /// </summary>
380 public Iterator CurrentIterator {
381 get { return CurrentAnonymousMethod as Iterator; }
384 /// <summary>
385 /// Whether we are in the resolving stage or not
386 /// </summary>
387 enum Phase {
388 Created,
389 Resolving,
390 Emitting
393 public static EmitContext TempEc;
395 bool isAnonymousMethodAllowed = true;
397 Phase current_phase;
398 FlowBranching current_flow_branching;
400 static int next_id = 0;
401 int id = ++next_id;
403 public override string ToString ()
405 return String.Format ("EmitContext ({0}:{1})", id,
406 CurrentAnonymousMethod, loc);
409 public EmitContext (IResolveContext rc, DeclSpace parent, DeclSpace ds, Location l, ILGenerator ig,
410 Type return_type, int code_flags, bool is_constructor)
412 this.ResolveContext = rc;
413 this.ig = ig;
415 TypeContainer = parent;
416 this.decl_space = ds;
417 if (RootContext.Checked)
418 flags |= Flags.CheckState;
419 flags |= Flags.ConstantCheckState;
421 #if GMCS_SOURCE
422 if ((return_type is TypeBuilder) && return_type.IsGenericTypeDefinition)
423 throw new InternalErrorException ();
424 #endif
426 IsStatic = (code_flags & Modifiers.STATIC) != 0;
427 MethodIsStatic = IsStatic;
428 InIterator = (code_flags & Modifiers.METHOD_YIELDS) != 0;
429 ReturnType = return_type;
430 IsConstructor = is_constructor;
431 CurrentBlock = null;
432 CurrentFile = 0;
433 current_phase = Phase.Created;
435 if (parent != null){
436 // Can only be null for the ResolveType contexts.
437 ContainerType = parent.TypeBuilder;
438 if (rc.IsInUnsafeScope)
439 flags |= Flags.InUnsafe;
441 loc = l;
444 public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
445 Type return_type, int code_flags, bool is_constructor)
446 : this (rc, ds, ds, l, ig, return_type, code_flags, is_constructor)
450 public EmitContext (IResolveContext rc, DeclSpace ds, Location l, ILGenerator ig,
451 Type return_type, int code_flags)
452 : this (rc, ds, ds, l, ig, return_type, code_flags, false)
456 public DeclSpace DeclContainer {
457 get { return decl_space; }
458 set { decl_space = value; }
461 public DeclSpace GenericDeclContainer {
462 get { return DeclContainer; }
465 public bool CheckState {
466 get { return (flags & Flags.CheckState) != 0; }
469 public bool ConstantCheckState {
470 get { return (flags & Flags.ConstantCheckState) != 0; }
473 public bool InUnsafe {
474 get { return (flags & Flags.InUnsafe) != 0; }
477 public bool InCatch {
478 get { return (flags & Flags.InCatch) != 0; }
481 public bool InFinally {
482 get { return (flags & Flags.InFinally) != 0; }
485 public bool DoFlowAnalysis {
486 get { return (flags & Flags.DoFlowAnalysis) != 0; }
489 public bool OmitStructFlowAnalysis {
490 get { return (flags & Flags.OmitStructFlowAnalysis) != 0; }
493 // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
494 // it's public so that we can use a struct at the callsite
495 public struct FlagsHandle : IDisposable
497 EmitContext ec;
498 Flags invmask, oldval;
499 internal FlagsHandle (EmitContext ec, Flags mask, Flags val)
501 this.ec = ec;
502 invmask = ~mask;
503 oldval = ec.flags & mask;
504 ec.flags = (ec.flags & invmask) | (val & mask);
506 public void Dispose ()
508 ec.flags = (ec.flags & invmask) | oldval;
512 // Temporarily set all the given flags to the given value. Should be used in an 'using' statement
513 public FlagsHandle With (Flags bits, bool enable)
515 return new FlagsHandle (this, bits, enable ? bits : 0);
518 public FlagsHandle WithFlowAnalysis (bool do_flow_analysis, bool omit_struct_analysis)
520 Flags newflags =
521 (do_flow_analysis ? Flags.DoFlowAnalysis : 0) |
522 (omit_struct_analysis ? Flags.OmitStructFlowAnalysis : 0);
523 return new FlagsHandle (this, Flags.DoFlowAnalysis | Flags.OmitStructFlowAnalysis, newflags);
526 public bool IsInObsoleteScope {
527 get { return ResolveContext.IsInObsoleteScope; }
530 public bool IsInUnsafeScope {
531 get { return InUnsafe || ResolveContext.IsInUnsafeScope; }
534 public bool IsAnonymousMethodAllowed {
535 get { return isAnonymousMethodAllowed; }
536 set { isAnonymousMethodAllowed = value; }
539 public FlowBranching CurrentBranching {
540 get { return current_flow_branching; }
543 // <summary>
544 // Starts a new code branching. This inherits the state of all local
545 // variables and parameters from the current branching.
546 // </summary>
547 public FlowBranching StartFlowBranching (FlowBranching.BranchingType type, Location loc)
549 current_flow_branching = FlowBranching.CreateBranching (CurrentBranching, type, null, loc);
550 return current_flow_branching;
553 // <summary>
554 // Starts a new code branching for block `block'.
555 // </summary>
556 public FlowBranching StartFlowBranching (Block block)
558 FlowBranching.BranchingType type;
560 if ((CurrentBranching != null) &&
561 (CurrentBranching.Type == FlowBranching.BranchingType.Switch))
562 type = FlowBranching.BranchingType.SwitchSection;
563 else
564 type = FlowBranching.BranchingType.Block;
566 flags |= Flags.DoFlowAnalysis;
568 current_flow_branching = FlowBranching.CreateBranching (
569 CurrentBranching, type, block, block.StartLocation);
570 return current_flow_branching;
573 public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
575 FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
576 current_flow_branching = branching;
577 return branching;
580 public FlowBranchingLabeled StartFlowBranching (LabeledStatement stmt)
582 FlowBranchingLabeled branching = new FlowBranchingLabeled (CurrentBranching, stmt);
583 current_flow_branching = branching;
584 return branching;
587 public FlowBranchingToplevel StartFlowBranching (ToplevelBlock stmt)
589 FlowBranchingToplevel branching = new FlowBranchingToplevel (CurrentBranching, stmt);
590 current_flow_branching = branching;
591 return branching;
594 // <summary>
595 // Ends a code branching. Merges the state of locals and parameters
596 // from all the children of the ending branching.
597 // </summary>
598 public FlowBranching.UsageVector DoEndFlowBranching ()
600 FlowBranching old = current_flow_branching;
601 current_flow_branching = current_flow_branching.Parent;
603 return current_flow_branching.MergeChild (old);
606 // <summary>
607 // Ends a code branching. Merges the state of locals and parameters
608 // from all the children of the ending branching.
609 // </summary>
610 public bool EndFlowBranching ()
612 FlowBranching.UsageVector vector = DoEndFlowBranching ();
614 return vector.IsUnreachable;
617 // <summary>
618 // Kills the current code branching. This throws away any changed state
619 // information and should only be used in case of an error.
620 // </summary>
621 public void KillFlowBranching ()
623 current_flow_branching = current_flow_branching.Parent;
626 public bool MustCaptureVariable (LocalInfo local)
628 if (CurrentAnonymousMethod == null)
629 return false;
630 if (CurrentAnonymousMethod.IsIterator)
631 return true;
632 return local.Block.Toplevel != CurrentBlock.Toplevel;
635 public void EmitMeta (ToplevelBlock b)
637 b.EmitMeta (this);
639 if (HasReturnLabel)
640 ReturnLabel = ig.DefineLabel ();
644 // Here until we can fix the problem with Mono.CSharp.Switch, which
645 // currently can not cope with ig == null during resolve (which must
646 // be fixed for switch statements to work on anonymous methods).
648 public void EmitTopBlock (IMethodData md, ToplevelBlock block)
650 if (block == null)
651 return;
653 bool unreachable;
655 if (ResolveTopBlock (null, block, md.ParameterInfo, md, out unreachable)){
656 EmitMeta (block);
658 current_phase = Phase.Emitting;
659 EmitResolvedTopBlock (block, unreachable);
663 bool resolved;
665 public bool ResolveTopBlock (EmitContext anonymous_method_host, ToplevelBlock block,
666 Parameters ip, IMethodData md, out bool unreachable)
668 current_phase = Phase.Resolving;
670 unreachable = false;
672 if (resolved)
673 return true;
675 if (!loc.IsNull)
676 CurrentFile = loc.File;
678 #if PRODUCTION
679 try {
680 #endif
681 if (!block.ResolveMeta (this, ip))
682 return false;
684 if ((md != null) && (md.Iterator != null)) {
685 if (!md.Iterator.Resolve (this))
686 return false;
689 using (this.With (EmitContext.Flags.DoFlowAnalysis, true)) {
690 FlowBranchingToplevel top_level;
691 if (anonymous_method_host != null)
692 top_level = new FlowBranchingToplevel (anonymous_method_host.CurrentBranching, block);
693 else
694 top_level = block.TopLevelBranching;
696 current_flow_branching = top_level;
697 bool ok = block.Resolve (this);
698 current_flow_branching = null;
700 if (!ok)
701 return false;
703 bool flow_unreachable = top_level.End ();
704 if (flow_unreachable)
705 unreachable = true;
707 #if PRODUCTION
708 } catch (Exception e) {
709 Console.WriteLine ("Exception caught by the compiler while compiling:");
710 Console.WriteLine (" Block that caused the problem begin at: " + loc);
712 if (CurrentBlock != null){
713 Console.WriteLine (" Block being compiled: [{0},{1}]",
714 CurrentBlock.StartLocation, CurrentBlock.EndLocation);
716 Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
717 throw;
719 #endif
721 if (return_type != null && !unreachable) {
722 if (CurrentAnonymousMethod == null) {
723 Report.Error (161, md.Location, "`{0}': not all code paths return a value", md.GetSignatureForError ());
724 return false;
725 } else if (!CurrentAnonymousMethod.IsIterator) {
726 Report.Error (1643, CurrentAnonymousMethod.Location, "Not all code paths return a value in anonymous method of type `{0}'",
727 CurrentAnonymousMethod.GetSignatureForError ());
728 return false;
732 if (!block.CompleteContexts (this))
733 return false;
735 resolved = true;
736 return true;
739 public Type ReturnType {
740 set {
741 return_type = value == TypeManager.void_type ?
742 null : value;
744 get {
745 return return_type;
749 public void EmitResolvedTopBlock (ToplevelBlock block, bool unreachable)
751 if (block != null)
752 block.Emit (this);
754 if (HasReturnLabel)
755 ig.MarkLabel (ReturnLabel);
757 if (return_value != null){
758 ig.Emit (OpCodes.Ldloc, return_value);
759 ig.Emit (OpCodes.Ret);
760 } else {
762 // If `HasReturnLabel' is set, then we already emitted a
763 // jump to the end of the method, so we must emit a `ret'
764 // there.
766 // Unfortunately, System.Reflection.Emit automatically emits
767 // a leave to the end of a finally block. This is a problem
768 // if no code is following the try/finally block since we may
769 // jump to a point after the end of the method.
770 // As a workaround, we're always creating a return label in
771 // this case.
774 bool in_iterator = (CurrentAnonymousMethod != null) &&
775 CurrentAnonymousMethod.IsIterator && InIterator;
777 if ((block != null) && block.IsDestructor) {
778 // Nothing to do; S.R.E automatically emits a leave.
779 } else if (HasReturnLabel || (!unreachable && !in_iterator)) {
780 if (return_type != null)
781 ig.Emit (OpCodes.Ldloc, TemporaryReturn ());
782 ig.Emit (OpCodes.Ret);
787 /// <summary>
788 /// This is called immediately before emitting an IL opcode to tell the symbol
789 /// writer to which source line this opcode belongs.
790 /// </summary>
791 public void Mark (Location loc, bool check_file)
793 if ((CodeGen.SymbolWriter == null) || loc.IsNull)
794 return;
796 if (check_file && (CurrentFile != loc.File))
797 return;
799 CodeGen.SymbolWriter.MarkSequencePoint (ig, loc.Row, loc.Column);
802 public void DefineLocalVariable (string name, LocalBuilder builder)
804 if (CodeGen.SymbolWriter == null)
805 return;
807 CodeGen.SymbolWriter.DefineLocalVariable (name, builder);
810 public void BeginScope ()
812 ig.BeginScope();
814 if (CodeGen.SymbolWriter != null)
815 CodeGen.SymbolWriter.OpenScope(ig);
818 public void EndScope ()
820 ig.EndScope();
822 if (CodeGen.SymbolWriter != null)
823 CodeGen.SymbolWriter.CloseScope(ig);
826 /// <summary>
827 /// Returns a temporary storage for a variable of type t as
828 /// a local variable in the current body.
829 /// </summary>
830 public LocalBuilder GetTemporaryLocal (Type t)
832 if (temporary_storage != null) {
833 object o = temporary_storage [t];
834 if (o != null) {
835 if (o is Stack) {
836 Stack s = (Stack) o;
837 o = s.Count == 0 ? null : s.Pop ();
838 } else {
839 temporary_storage.Remove (t);
842 if (o != null)
843 return (LocalBuilder) o;
845 return ig.DeclareLocal (t);
848 public void FreeTemporaryLocal (LocalBuilder b, Type t)
850 Stack s;
852 if (temporary_storage == null) {
853 temporary_storage = new Hashtable ();
854 temporary_storage [t] = b;
855 return;
857 object o = temporary_storage [t];
858 if (o == null) {
859 temporary_storage [t] = b;
860 return;
862 if (o is Stack) {
863 s = (Stack) o;
864 } else {
865 s = new Stack ();
866 s.Push (o);
867 temporary_storage [t] = s;
869 s.Push (b);
872 /// <summary>
873 /// Current loop begin and end labels.
874 /// </summary>
875 public Label LoopBegin, LoopEnd;
877 /// <summary>
878 /// Default target in a switch statement. Only valid if
879 /// InSwitch is true
880 /// </summary>
881 public Label DefaultTarget;
883 /// <summary>
884 /// If this is non-null, points to the current switch statement
885 /// </summary>
886 public Switch Switch;
888 /// <summary>
889 /// ReturnValue creates on demand the LocalBuilder for the
890 /// return value from the function. By default this is not
891 /// used. This is only required when returns are found inside
892 /// Try or Catch statements.
894 /// This method is typically invoked from the Emit phase, so
895 /// we allow the creation of a return label if it was not
896 /// requested during the resolution phase. Could be cleaned
897 /// up, but it would replicate a lot of logic in the Emit phase
898 /// of the code that uses it.
899 /// </summary>
900 public LocalBuilder TemporaryReturn ()
902 if (return_value == null){
903 return_value = ig.DeclareLocal (return_type);
904 if (!HasReturnLabel){
905 ReturnLabel = ig.DefineLabel ();
906 HasReturnLabel = true;
910 return return_value;
913 /// <summary>
914 /// This method is used during the Resolution phase to flag the
915 /// need to define the ReturnLabel
916 /// </summary>
917 public void NeedReturnLabel ()
919 if (current_phase != Phase.Resolving){
921 // The reason is that the `ReturnLabel' is declared between
922 // resolution and emission
924 throw new Exception ("NeedReturnLabel called from Emit phase, should only be called during Resolve");
927 if (!InIterator && !HasReturnLabel)
928 HasReturnLabel = true;
932 public Expression GetThis (Location loc)
934 This my_this;
935 if (CurrentBlock != null)
936 my_this = new This (CurrentBlock, loc);
937 else
938 my_this = new This (loc);
940 if (!my_this.ResolveBase (this))
941 my_this = null;
943 return my_this;
948 public abstract class CommonAssemblyModulClass : Attributable, IResolveContext {
950 protected CommonAssemblyModulClass ():
951 base (null)
955 public void AddAttributes (ArrayList attrs)
957 foreach (Attribute a in attrs)
958 a.AttachTo (this);
960 if (attributes == null) {
961 attributes = new Attributes (attrs);
962 return;
964 attributes.AddAttributes (attrs);
967 public virtual void Emit (TypeContainer tc)
969 if (OptAttributes == null)
970 return;
972 OptAttributes.Emit ();
975 protected Attribute ResolveAttribute (Type a_type)
977 Attribute a = OptAttributes.Search (a_type);
978 if (a != null) {
979 a.Resolve ();
981 return a;
984 public override IResolveContext ResolveContext {
985 get { return this; }
988 #region IResolveContext Members
990 public DeclSpace DeclContainer {
991 get { return RootContext.ToplevelTypes; }
994 public DeclSpace GenericDeclContainer {
995 get { return DeclContainer; }
998 public bool IsInObsoleteScope {
999 get { return false; }
1002 public bool IsInUnsafeScope {
1003 get { return false; }
1006 #endregion
1009 public class AssemblyClass : CommonAssemblyModulClass {
1010 // TODO: make it private and move all builder based methods here
1011 public AssemblyBuilder Builder;
1012 bool is_cls_compliant;
1013 bool wrap_non_exception_throws;
1014 bool has_extension_method;
1016 public Attribute ClsCompliantAttribute;
1018 ListDictionary declarative_security;
1019 #if GMCS_SOURCE
1020 public AssemblyName Name;
1021 MethodInfo add_type_forwarder;
1022 ListDictionary emitted_forwarders;
1023 #endif
1025 // Module is here just because of error messages
1026 static string[] attribute_targets = new string [] { "assembly", "module" };
1028 public AssemblyClass (): base ()
1030 #if GMCS_SOURCE
1031 wrap_non_exception_throws = true;
1032 #endif
1035 public bool HasExtensionMethods {
1036 set { has_extension_method = value; }
1039 public bool IsClsCompliant {
1040 get {
1041 return is_cls_compliant;
1045 public bool WrapNonExceptionThrows {
1046 get {
1047 return wrap_non_exception_throws;
1051 public override AttributeTargets AttributeTargets {
1052 get {
1053 return AttributeTargets.Assembly;
1057 public override bool IsClsComplianceRequired ()
1059 return is_cls_compliant;
1062 public void Resolve ()
1064 if (OptAttributes == null)
1065 return;
1067 // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
1068 if (!OptAttributes.CheckTargets())
1069 return;
1071 ClsCompliantAttribute = ResolveAttribute (TypeManager.cls_compliant_attribute_type);
1072 if (ClsCompliantAttribute != null) {
1073 is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue ();
1076 #if GMCS_SOURCE
1077 Attribute a = ResolveAttribute (TypeManager.runtime_compatibility_attr_type);
1078 if (a != null) {
1079 object val = a.GetPropertyValue ("WrapNonExceptionThrows");
1080 if (val != null)
1081 wrap_non_exception_throws = (bool)val;
1083 #endif
1086 // fix bug #56621
1087 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob)
1089 try {
1090 // check for possible ECMA key
1091 if (strongNameBlob.Length == 16) {
1092 // will be rejected if not "the" ECMA key
1093 an.SetPublicKey (strongNameBlob);
1095 else {
1096 // take it, with or without, a private key
1097 RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
1098 // and make sure we only feed the public part to Sys.Ref
1099 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
1101 // AssemblyName.SetPublicKey requires an additional header
1102 byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
1104 byte[] encodedPublicKey = new byte [12 + publickey.Length];
1105 Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
1106 Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
1107 an.SetPublicKey (encodedPublicKey);
1110 catch (Exception) {
1111 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded");
1112 Environment.Exit (1);
1116 // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
1117 public AssemblyName GetAssemblyName (string name, string output)
1119 if (OptAttributes != null) {
1120 foreach (Attribute a in OptAttributes.Attrs) {
1121 // cannot rely on any resolve-based members before you call Resolve
1122 if (a.ExplicitTarget == null || a.ExplicitTarget != "assembly")
1123 continue;
1125 // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
1126 // However, this is invoked by CodeGen.Init, when none of the namespaces
1127 // are loaded yet.
1128 // TODO: Does not handle quoted attributes properly
1129 switch (a.Name) {
1130 case "AssemblyKeyFile":
1131 case "AssemblyKeyFileAttribute":
1132 case "System.Reflection.AssemblyKeyFileAttribute":
1133 if (RootContext.StrongNameKeyFile != null) {
1134 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1135 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1136 "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
1138 else {
1139 string value = a.GetString ();
1140 if (value.Length != 0)
1141 RootContext.StrongNameKeyFile = value;
1143 break;
1144 case "AssemblyKeyName":
1145 case "AssemblyKeyNameAttribute":
1146 case "System.Reflection.AssemblyKeyNameAttribute":
1147 if (RootContext.StrongNameKeyContainer != null) {
1148 Report.SymbolRelatedToPreviousError (a.Location, a.Name);
1149 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1150 "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
1152 else {
1153 string value = a.GetString ();
1154 if (value.Length != 0)
1155 RootContext.StrongNameKeyContainer = value;
1157 break;
1158 case "AssemblyDelaySign":
1159 case "AssemblyDelaySignAttribute":
1160 case "System.Reflection.AssemblyDelaySignAttribute":
1161 RootContext.StrongNameDelaySign = a.GetBoolean ();
1162 break;
1167 AssemblyName an = new AssemblyName ();
1168 an.Name = Path.GetFileNameWithoutExtension (name);
1170 // note: delay doesn't apply when using a key container
1171 if (RootContext.StrongNameKeyContainer != null) {
1172 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
1173 return an;
1176 // strongname is optional
1177 if (RootContext.StrongNameKeyFile == null)
1178 return an;
1180 string AssemblyDir = Path.GetDirectoryName (output);
1182 // the StrongName key file may be relative to (a) the compiled
1183 // file or (b) to the output assembly. See bugzilla #55320
1184 // http://bugzilla.ximian.com/show_bug.cgi?id=55320
1186 // (a) relative to the compiled file
1187 string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
1188 bool exist = File.Exists (filename);
1189 if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
1190 // (b) relative to the outputed assembly
1191 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
1192 exist = File.Exists (filename);
1195 if (exist) {
1196 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
1197 byte[] snkeypair = new byte [fs.Length];
1198 fs.Read (snkeypair, 0, snkeypair.Length);
1200 if (RootContext.StrongNameDelaySign) {
1201 // delayed signing - DO NOT include private key
1202 SetPublicKey (an, snkeypair);
1204 else {
1205 // no delay so we make sure we have the private key
1206 try {
1207 CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
1208 an.KeyPair = new StrongNameKeyPair (snkeypair);
1210 catch (CryptographicException) {
1211 if (snkeypair.Length == 16) {
1212 // error # is different for ECMA key
1213 Report.Error (1606, "Could not sign the assembly. " +
1214 "ECMA key can only be used to delay-sign assemblies");
1216 else {
1217 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not have a private key");
1219 return null;
1224 else {
1225 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not exist");
1226 return null;
1228 return an;
1231 void Error_AssemblySigning (string text)
1233 Report.Error (1548, "Error during assembly signing. " + text);
1236 #if GMCS_SOURCE
1237 bool CheckInternalsVisibleAttribute (Attribute a)
1239 string assembly_name = a.GetString ();
1240 if (assembly_name.Length == 0)
1241 return false;
1243 AssemblyName aname = null;
1244 try {
1245 aname = new AssemblyName (assembly_name);
1246 } catch (FileLoadException) {
1247 } catch (ArgumentException) {
1250 // Bad assembly name format
1251 if (aname == null)
1252 Report.Warning (1700, 3, a.Location, "Assembly reference `" + assembly_name + "' is invalid and cannot be resolved");
1253 // Report error if we have defined Version or Culture
1254 else if (aname.Version != null || aname.CultureInfo != null)
1255 throw new Exception ("Friend assembly `" + a.GetString () +
1256 "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
1257 else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null) {
1258 Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." +
1259 " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
1260 return false;
1263 return true;
1265 #endif
1267 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1269 if (a.Type.IsSubclassOf (TypeManager.security_attr_type) && a.CheckSecurityActionValidity (true)) {
1270 if (declarative_security == null)
1271 declarative_security = new ListDictionary ();
1273 a.ExtractSecurityPermissionSet (declarative_security);
1274 return;
1277 if (a.Type == TypeManager.assembly_culture_attribute_type) {
1278 string value = a.GetString ();
1279 if (value == null || value.Length == 0)
1280 return;
1282 if (RootContext.Target == Target.Exe) {
1283 a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
1284 return;
1288 #if GMCS_SOURCE
1289 if (a.Type == TypeManager.internals_visible_attr_type && !CheckInternalsVisibleAttribute (a))
1290 return;
1292 if (a.Type == TypeManager.type_forwarder_attr_type) {
1293 Type t = a.GetArgumentType ();
1294 if (t == null || TypeManager.HasElementType (t)) {
1295 Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
1296 return;
1299 if (emitted_forwarders == null) {
1300 emitted_forwarders = new ListDictionary();
1301 } else if (emitted_forwarders.Contains(t)) {
1302 Report.SymbolRelatedToPreviousError(((Attribute)emitted_forwarders[t]).Location, null);
1303 Report.Error(739, a.Location, "A duplicate type forward of type `{0}'",
1304 TypeManager.CSharpName(t));
1305 return;
1308 emitted_forwarders.Add(t, a);
1310 if (TypeManager.LookupDeclSpace (t) != null) {
1311 Report.SymbolRelatedToPreviousError (t);
1312 Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
1313 TypeManager.CSharpName (t));
1314 return;
1317 if (t.IsNested) {
1318 Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
1319 TypeManager.CSharpName (t));
1320 return;
1323 if (t.IsGenericType) {
1324 Report.Error (733, a.Location, "Cannot forward generic type `{0}'", TypeManager.CSharpName (t));
1325 return;
1328 if (add_type_forwarder == null) {
1329 add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder",
1330 BindingFlags.NonPublic | BindingFlags.Instance);
1332 if (add_type_forwarder == null) {
1333 Report.RuntimeMissingSupport (a.Location, "TypeForwardedTo attribute");
1334 return;
1338 add_type_forwarder.Invoke (Builder, new object[] { t });
1339 return;
1342 if (a.Type == TypeManager.extension_attribute_type) {
1343 a.Error_MisusedExtensionAttribute ();
1344 return;
1346 #endif
1347 Builder.SetCustomAttribute (customBuilder);
1350 public override void Emit (TypeContainer tc)
1352 base.Emit (tc);
1354 #if GMCS_SOURCE
1355 if (has_extension_method)
1356 Builder.SetCustomAttribute (TypeManager.extension_attribute_attr);
1358 // FIXME: Does this belong inside SRE.AssemblyBuilder instead?
1359 if (OptAttributes == null || !OptAttributes.Contains (TypeManager.runtime_compatibility_attr_type)) {
1360 ConstructorInfo ci = TypeManager.GetConstructor (
1361 TypeManager.runtime_compatibility_attr_type, Type.EmptyTypes);
1362 PropertyInfo [] pis = new PropertyInfo [1];
1363 pis [0] = TypeManager.GetProperty (
1364 TypeManager.runtime_compatibility_attr_type, "WrapNonExceptionThrows");
1365 object [] pargs = new object [1];
1366 pargs [0] = true;
1367 Builder.SetCustomAttribute (new CustomAttributeBuilder (ci, new object [0], pis, pargs));
1369 #endif
1371 if (declarative_security != null) {
1373 MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1374 object builder_instance = Builder;
1376 try {
1377 // Microsoft runtime hacking
1378 if (add_permission == null) {
1379 Type assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData");
1380 add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1382 FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
1383 builder_instance = fi.GetValue (Builder);
1386 object[] args = new object [] { declarative_security [SecurityAction.RequestMinimum],
1387 declarative_security [SecurityAction.RequestOptional],
1388 declarative_security [SecurityAction.RequestRefuse] };
1389 add_permission.Invoke (builder_instance, args);
1391 catch {
1392 Report.RuntimeMissingSupport (Location.Null, "assembly permission setting");
1397 public override string[] ValidAttributeTargets {
1398 get {
1399 return attribute_targets;
1403 // Wrapper for AssemblyBuilder.AddModule
1404 static MethodInfo adder_method;
1405 static public MethodInfo AddModule_Method {
1406 get {
1407 if (adder_method == null)
1408 adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
1409 return adder_method;
1412 public Module AddModule (string module)
1414 MethodInfo m = AddModule_Method;
1415 if (m == null) {
1416 Report.RuntimeMissingSupport (Location.Null, "/addmodule");
1417 Environment.Exit (1);
1420 try {
1421 return (Module) m.Invoke (Builder, new object [] { module });
1422 } catch (TargetInvocationException ex) {
1423 throw ex.InnerException;
1428 public class ModuleClass : CommonAssemblyModulClass {
1429 // TODO: make it private and move all builder based methods here
1430 public ModuleBuilder Builder;
1431 bool m_module_is_unsafe;
1432 bool has_default_charset;
1434 public CharSet DefaultCharSet = CharSet.Ansi;
1435 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
1437 static string[] attribute_targets = new string [] { "module" };
1439 public ModuleClass (bool is_unsafe)
1441 m_module_is_unsafe = is_unsafe;
1444 public override AttributeTargets AttributeTargets {
1445 get {
1446 return AttributeTargets.Module;
1450 public override bool IsClsComplianceRequired ()
1452 return CodeGen.Assembly.IsClsCompliant;
1455 public override void Emit (TypeContainer tc)
1457 base.Emit (tc);
1459 if (!m_module_is_unsafe)
1460 return;
1462 if (TypeManager.unverifiable_code_ctor == null) {
1463 Console.WriteLine ("Internal error ! Cannot set unverifiable code attribute.");
1464 return;
1467 Builder.SetCustomAttribute (new CustomAttributeBuilder (TypeManager.unverifiable_code_ctor, new object [0]));
1470 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder customBuilder)
1472 if (a.Type == TypeManager.cls_compliant_attribute_type) {
1473 if (CodeGen.Assembly.ClsCompliantAttribute == null) {
1474 Report.Warning (3012, 1, a.Location, "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
1476 else if (CodeGen.Assembly.IsClsCompliant != a.GetBoolean ()) {
1477 Report.SymbolRelatedToPreviousError (CodeGen.Assembly.ClsCompliantAttribute.Location, CodeGen.Assembly.ClsCompliantAttribute.GetSignatureForError ());
1478 Report.Error (3017, a.Location, "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
1479 return;
1483 Builder.SetCustomAttribute (customBuilder);
1486 public bool HasDefaultCharSet {
1487 get {
1488 return has_default_charset;
1492 /// <summary>
1493 /// It is called very early therefore can resolve only predefined attributes
1494 /// </summary>
1495 public void Resolve ()
1497 #if GMCS_SOURCE
1498 if (OptAttributes == null)
1499 return;
1501 if (!OptAttributes.CheckTargets())
1502 return;
1504 Attribute a = ResolveAttribute (TypeManager.default_charset_type);
1505 if (a != null) {
1506 has_default_charset = true;
1507 DefaultCharSet = a.GetCharSetValue ();
1508 switch (DefaultCharSet) {
1509 case CharSet.Ansi:
1510 case CharSet.None:
1511 break;
1512 case CharSet.Auto:
1513 DefaultCharSetType = TypeAttributes.AutoClass;
1514 break;
1515 case CharSet.Unicode:
1516 DefaultCharSetType = TypeAttributes.UnicodeClass;
1517 break;
1518 default:
1519 Report.Error (1724, a.Location, "Value specified for the argument to 'System.Runtime.InteropServices.DefaultCharSetAttribute' is not valid");
1520 break;
1523 #endif
1526 public override string[] ValidAttributeTargets {
1527 get {
1528 return attribute_targets;