2 // codegen.cs: The code generator
5 // Miguel de Icaza (miguel@ximian.com)
7 // Copyright 2001, 2002, 2003 Ximian, Inc.
8 // Copyright 2004 Novell, Inc.
12 // Please leave this defined on SVN: The idea is that when we ship the
13 // compiler to end users, if the compiler crashes, they have a chance
14 // to narrow down the problem.
16 // Only remove it if you need to debug locally on your tree.
22 using System.Collections.Generic;
23 using System.Globalization;
24 using System.Reflection;
25 using System.Reflection.Emit;
26 using System.Runtime.InteropServices;
27 using System.Security;
28 using System.Security.Cryptography;
29 using System.Security.Permissions;
31 using Mono.Security.Cryptography;
33 namespace Mono.CSharp {
36 /// Code generator class.
38 public class CodeGen {
39 static AppDomain current_domain;
41 // Breaks dynamic and repl
42 public static AssemblyClass Assembly;
49 public static void Reset ()
51 Assembly = new AssemblyClass ();
54 public static string Basename (string name)
56 int pos = name.LastIndexOf ('/');
59 return name.Substring (pos + 1);
61 pos = name.LastIndexOf ('\\');
63 return name.Substring (pos + 1);
68 public static string Dirname (string name)
70 int pos = name.LastIndexOf ('/');
73 return name.Substring (0, pos);
75 pos = name.LastIndexOf ('\\');
77 return name.Substring (0, pos);
82 static public string FileName;
85 // Initializes the code generator variables for interactive use (repl)
87 static public void InitDynamic (CompilerContext ctx, string name)
89 current_domain = AppDomain.CurrentDomain;
90 AssemblyName an = Assembly.GetAssemblyName (name, name);
92 Assembly.Builder = current_domain.DefineDynamicAssembly (an, AssemblyBuilderAccess.Run);
93 RootContext.ToplevelTypes = new ModuleCompiled (ctx, true);
94 RootContext.ToplevelTypes.Builder = Assembly.Builder.DefineDynamicModule (Basename (name), false);
95 Assembly.Name = Assembly.Builder.GetName ();
99 // Initializes the code generator variables
101 static public bool Init (string name, string output, bool want_debugging_support, CompilerContext ctx)
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 ctx.GlobalRootNamespace.Assemblies) {
112 AssemblyName ref_name = a.GetName ();
113 byte [] b = ref_name.GetPublicKeyToken ();
114 if (b == null || b.Length == 0) {
115 ctx.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.RunAndSave, Dirname (name));
130 catch (ArgumentException) {
131 // specified key may not be exportable outside it's container
132 if (RootContext.StrongNameKeyContainer != null) {
133 ctx.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 ctx.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.
160 RootContext.ToplevelTypes.Builder = Assembly.Builder.DefineDynamicModule (
161 Basename (name), Basename (output), want_debugging_support);
164 // TODO: We should use SymbolWriter from DefineDynamicModule
165 if (want_debugging_support && !SymbolWriter.Initialize (RootContext.ToplevelTypes.Builder, output)) {
166 ctx.Report.Error (40, "Unexpected debug information initialization error `{0}'",
167 "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll)");
171 } catch (ExecutionEngineException e) {
172 ctx.Report.Error (40, "Unexpected debug information initialization error `{0}'",
180 static public void Save (string name, bool saveDebugInfo, Report Report)
182 PortableExecutableKinds pekind;
183 ImageFileMachine machine;
185 switch (RootContext.Platform) {
187 pekind = PortableExecutableKinds.Required32Bit;
188 machine = ImageFileMachine.I386;
191 pekind = PortableExecutableKinds.PE32Plus;
192 machine = ImageFileMachine.AMD64;
195 pekind = PortableExecutableKinds.PE32Plus;
196 machine = ImageFileMachine.IA64;
198 case Platform.AnyCPU:
200 pekind = PortableExecutableKinds.ILOnly;
201 machine = ImageFileMachine.I386;
205 Assembly.Builder.Save (Basename (name), pekind, machine);
207 catch (COMException) {
208 if ((RootContext.StrongNameKeyFile == null) || (!RootContext.StrongNameDelaySign))
211 // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies
212 Report.Error (1548, "Couldn't delay-sign the assembly with the '" +
213 RootContext.StrongNameKeyFile +
214 "', Use MCS with the Mono runtime or CSC to compile this assembly.");
216 catch (System.IO.IOException io) {
217 Report.Error (16, "Could not write to file `"+name+"', cause: " + io.Message);
220 catch (System.UnauthorizedAccessException ua) {
221 Report.Error (16, "Could not write to file `"+name+"', cause: " + ua.Message);
224 catch (System.NotImplementedException nie) {
225 Report.RuntimeMissingSupport (Location.Null, nie.Message);
230 // Write debuger symbol file
233 SymbolWriter.WriteSymbolFile ();
238 /// An Emit Context is created for each body of code (from methods,
239 /// properties bodies, indexer bodies or constructor bodies)
241 public class EmitContext : BuilderContext
243 // TODO: Has to be private
244 public ILGenerator ig;
247 /// The value that is allowed to be returned or NULL if there is no
250 TypeSpec return_type;
253 /// Keeps track of the Type to LocalBuilder temporary storage created
254 /// to store structures (used to compute the address of the structure
255 /// value on structure method invocations)
257 Dictionary<TypeSpec, object> temporary_storage;
260 /// The location where we store the return value.
262 public LocalBuilder return_value;
265 /// The location where return has to jump to return the
268 public Label ReturnLabel;
271 /// If we already defined the ReturnLabel
273 public bool HasReturnLabel;
276 /// Current loop begin and end labels.
278 public Label LoopBegin, LoopEnd;
281 /// Default target in a switch statement. Only valid if
284 public Label DefaultTarget;
287 /// If this is non-null, points to the current switch statement
289 public Switch Switch;
292 /// Whether we are inside an anonymous method.
294 public AnonymousExpression CurrentAnonymousMethod;
296 public readonly IMemberContext MemberContext;
298 DynamicSiteClass dynamic_site_container;
300 public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type)
302 this.MemberContext = rc;
305 this.return_type = return_type;
310 public TypeSpec CurrentType {
311 get { return MemberContext.CurrentType; }
314 public TypeParameter[] CurrentTypeParameters {
315 get { return MemberContext.CurrentTypeParameters; }
318 public MemberCore CurrentTypeDefinition {
319 get { return MemberContext.CurrentMemberDefinition; }
322 public bool IsStatic {
323 get { return MemberContext.IsStatic; }
326 bool IsAnonymousStoreyMutateRequired {
328 return CurrentAnonymousMethod != null &&
329 CurrentAnonymousMethod.Storey != null &&
330 CurrentAnonymousMethod.Storey.Mutator != null;
334 // Has to be used for emitter errors only
335 public Report Report {
336 get { return MemberContext.Compiler.Report; }
339 public TypeSpec ReturnType {
347 /// This is called immediately before emitting an IL opcode to tell the symbol
348 /// writer to which source line this opcode belongs.
350 public void Mark (Location loc)
352 if (!SymbolWriter.HasSymbolWriter || HasSet (Options.OmitDebugInfo) || loc.IsNull)
355 SymbolWriter.MarkSequencePoint (ig, loc);
358 public void DefineLocalVariable (string name, LocalBuilder builder)
360 SymbolWriter.DefineLocalVariable (name, builder);
363 public void BeginCatchBlock (TypeSpec type)
365 ig.BeginCatchBlock (type.GetMetaInfo ());
368 public void BeginExceptionBlock ()
370 ig.BeginExceptionBlock ();
373 public void BeginFinallyBlock ()
375 ig.BeginFinallyBlock ();
378 public void BeginScope ()
381 SymbolWriter.OpenScope(ig);
384 public void EndExceptionBlock ()
386 ig.EndExceptionBlock ();
389 public void EndScope ()
392 SymbolWriter.CloseScope(ig);
396 // Creates a nested container in this context for all dynamic compiler generated stuff
398 public DynamicSiteClass CreateDynamicSite ()
400 if (dynamic_site_container == null) {
401 var mc = MemberContext.CurrentMemberDefinition as MemberBase;
402 dynamic_site_container = new DynamicSiteClass (CurrentTypeDefinition.Parent.PartialContainer, mc, CurrentTypeParameters);
404 RootContext.ToplevelTypes.AddCompilerGeneratedClass (dynamic_site_container);
405 dynamic_site_container.CreateType ();
406 dynamic_site_container.DefineType ();
407 dynamic_site_container.ResolveTypeParameters ();
408 dynamic_site_container.Define ();
411 return dynamic_site_container;
414 public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
416 if (IsAnonymousStoreyMutateRequired)
417 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
419 return ig.DeclareLocal (type.GetMetaInfo (), pinned);
422 public Label DefineLabel ()
424 return ig.DefineLabel ();
427 public void MarkLabel (Label label)
429 ig.MarkLabel (label);
432 public void Emit (OpCode opcode)
437 public void Emit (OpCode opcode, LocalBuilder local)
439 ig.Emit (opcode, local);
442 public void Emit (OpCode opcode, string arg)
444 ig.Emit (opcode, arg);
447 public void Emit (OpCode opcode, double arg)
449 ig.Emit (opcode, arg);
452 public void Emit (OpCode opcode, float arg)
454 ig.Emit (opcode, arg);
457 public void Emit (OpCode opcode, int arg)
459 ig.Emit (opcode, arg);
462 public void Emit (OpCode opcode, byte arg)
464 ig.Emit (opcode, arg);
467 public void Emit (OpCode opcode, Label label)
469 ig.Emit (opcode, label);
472 public void Emit (OpCode opcode, Label[] labels)
474 ig.Emit (opcode, labels);
477 public void Emit (OpCode opcode, TypeSpec type)
479 if (IsAnonymousStoreyMutateRequired)
480 type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
482 ig.Emit (opcode, type.GetMetaInfo ());
485 public void Emit (OpCode opcode, FieldSpec field)
487 if (IsAnonymousStoreyMutateRequired)
488 field = field.Mutate (CurrentAnonymousMethod.Storey.Mutator);
490 ig.Emit (opcode, field.GetMetaInfo ());
493 public void Emit (OpCode opcode, MethodSpec method)
495 if (IsAnonymousStoreyMutateRequired)
496 method = method.Mutate (CurrentAnonymousMethod.Storey.Mutator);
498 if (method.IsConstructor)
499 ig.Emit (opcode, (ConstructorInfo) method.GetMetaInfo ());
501 ig.Emit (opcode, (MethodInfo) method.GetMetaInfo ());
504 // TODO: REMOVE breaks mutator
505 public void Emit (OpCode opcode, MethodInfo method)
507 ig.Emit (opcode, method);
510 // TODO: REMOVE breaks mutator
511 public void Emit (OpCode opcode, FieldBuilder field)
513 ig.Emit (opcode, field);
516 public void Emit (OpCode opcode, MethodSpec method, Type[] vargs)
518 // TODO MemberCache: This should mutate too
519 ig.EmitCall (opcode, (MethodInfo) method.GetMetaInfo (), vargs);
522 public void EmitArrayNew (ArrayContainer ac)
525 Emit (OpCodes.Newarr, ac.Element);
527 if (IsAnonymousStoreyMutateRequired)
528 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
530 ig.Emit (OpCodes.Newobj, ac.GetConstructor ());
534 public void EmitArrayAddress (ArrayContainer ac)
536 if (ac.Element.IsGenericParameter)
537 ig.Emit (OpCodes.Readonly);
540 if (IsAnonymousStoreyMutateRequired)
541 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
543 ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
545 Emit (OpCodes.Ldelema, ac.Element);
550 // Emits the right opcode to load from an array
552 public void EmitArrayLoad (ArrayContainer ac)
555 if (IsAnonymousStoreyMutateRequired)
556 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
558 ig.Emit (OpCodes.Call, ac.GetGetMethod ());
562 var type = ac.Element;
563 if (TypeManager.IsEnumType (type))
564 type = EnumSpec.GetUnderlyingType (type);
566 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
567 Emit (OpCodes.Ldelem_U1);
568 else if (type == TypeManager.sbyte_type)
569 Emit (OpCodes.Ldelem_I1);
570 else if (type == TypeManager.short_type)
571 Emit (OpCodes.Ldelem_I2);
572 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
573 Emit (OpCodes.Ldelem_U2);
574 else if (type == TypeManager.int32_type)
575 Emit (OpCodes.Ldelem_I4);
576 else if (type == TypeManager.uint32_type)
577 Emit (OpCodes.Ldelem_U4);
578 else if (type == TypeManager.uint64_type)
579 Emit (OpCodes.Ldelem_I8);
580 else if (type == TypeManager.int64_type)
581 Emit (OpCodes.Ldelem_I8);
582 else if (type == TypeManager.float_type)
583 Emit (OpCodes.Ldelem_R4);
584 else if (type == TypeManager.double_type)
585 Emit (OpCodes.Ldelem_R8);
586 else if (type == TypeManager.intptr_type)
587 Emit (OpCodes.Ldelem_I);
588 else if (TypeManager.IsStruct (type)) {
589 Emit (OpCodes.Ldelema, type);
590 Emit (OpCodes.Ldobj, type);
591 } else if (type.IsGenericParameter) {
592 Emit (OpCodes.Ldelem, type);
593 } else if (type.IsPointer)
594 Emit (OpCodes.Ldelem_I);
596 Emit (OpCodes.Ldelem_Ref);
600 // Emits the right opcode to store to an array
602 public void EmitArrayStore (ArrayContainer ac)
605 if (IsAnonymousStoreyMutateRequired)
606 ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
608 ig.Emit (OpCodes.Call, ac.GetSetMethod ());
612 var type = ac.Element;
615 type = EnumSpec.GetUnderlyingType (type);
617 if (type == TypeManager.byte_type || type == TypeManager.sbyte_type || type == TypeManager.bool_type)
618 Emit (OpCodes.Stelem_I1);
619 else if (type == TypeManager.short_type || type == TypeManager.ushort_type || type == TypeManager.char_type)
620 Emit (OpCodes.Stelem_I2);
621 else if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
622 Emit (OpCodes.Stelem_I4);
623 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
624 Emit (OpCodes.Stelem_I8);
625 else if (type == TypeManager.float_type)
626 Emit (OpCodes.Stelem_R4);
627 else if (type == TypeManager.double_type)
628 Emit (OpCodes.Stelem_R8);
629 else if (type == TypeManager.intptr_type)
630 Emit (OpCodes.Stobj, type);
631 else if (TypeManager.IsStruct (type))
632 Emit (OpCodes.Stobj, type);
633 else if (type.IsGenericParameter)
634 Emit (OpCodes.Stelem, type);
635 else if (type.IsPointer)
636 Emit (OpCodes.Stelem_I);
638 Emit (OpCodes.Stelem_Ref);
641 public void EmitInt (int i)
645 ig.Emit (OpCodes.Ldc_I4_M1);
649 ig.Emit (OpCodes.Ldc_I4_0);
653 ig.Emit (OpCodes.Ldc_I4_1);
657 ig.Emit (OpCodes.Ldc_I4_2);
661 ig.Emit (OpCodes.Ldc_I4_3);
665 ig.Emit (OpCodes.Ldc_I4_4);
669 ig.Emit (OpCodes.Ldc_I4_5);
673 ig.Emit (OpCodes.Ldc_I4_6);
677 ig.Emit (OpCodes.Ldc_I4_7);
681 ig.Emit (OpCodes.Ldc_I4_8);
685 if (i >= -128 && i <= 127) {
686 ig.Emit (OpCodes.Ldc_I4_S, (sbyte) i);
688 ig.Emit (OpCodes.Ldc_I4, i);
693 public void EmitLong (long l)
695 if (l >= int.MinValue && l <= int.MaxValue) {
696 EmitInt (unchecked ((int) l));
697 ig.Emit (OpCodes.Conv_I8);
701 if (l >= 0 && l <= uint.MaxValue) {
702 EmitInt (unchecked ((int) l));
703 ig.Emit (OpCodes.Conv_U8);
707 ig.Emit (OpCodes.Ldc_I8, l);
711 // Load the object from the pointer.
713 public void EmitLoadFromPtr (TypeSpec t)
715 if (t == TypeManager.int32_type)
716 ig.Emit (OpCodes.Ldind_I4);
717 else if (t == TypeManager.uint32_type)
718 ig.Emit (OpCodes.Ldind_U4);
719 else if (t == TypeManager.short_type)
720 ig.Emit (OpCodes.Ldind_I2);
721 else if (t == TypeManager.ushort_type)
722 ig.Emit (OpCodes.Ldind_U2);
723 else if (t == TypeManager.char_type)
724 ig.Emit (OpCodes.Ldind_U2);
725 else if (t == TypeManager.byte_type)
726 ig.Emit (OpCodes.Ldind_U1);
727 else if (t == TypeManager.sbyte_type)
728 ig.Emit (OpCodes.Ldind_I1);
729 else if (t == TypeManager.uint64_type)
730 ig.Emit (OpCodes.Ldind_I8);
731 else if (t == TypeManager.int64_type)
732 ig.Emit (OpCodes.Ldind_I8);
733 else if (t == TypeManager.float_type)
734 ig.Emit (OpCodes.Ldind_R4);
735 else if (t == TypeManager.double_type)
736 ig.Emit (OpCodes.Ldind_R8);
737 else if (t == TypeManager.bool_type)
738 ig.Emit (OpCodes.Ldind_I1);
739 else if (t == TypeManager.intptr_type)
740 ig.Emit (OpCodes.Ldind_I);
742 if (t == TypeManager.enum_type)
743 ig.Emit (OpCodes.Ldind_Ref);
745 EmitLoadFromPtr (EnumSpec.GetUnderlyingType (t));
746 } else if (TypeManager.IsStruct (t) || TypeManager.IsGenericParameter (t))
747 Emit (OpCodes.Ldobj, t);
748 else if (t.IsPointer)
749 ig.Emit (OpCodes.Ldind_I);
751 ig.Emit (OpCodes.Ldind_Ref);
755 // The stack contains the pointer and the value of type `type'
757 public void EmitStoreFromPtr (TypeSpec type)
760 type = EnumSpec.GetUnderlyingType (type);
762 if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
763 ig.Emit (OpCodes.Stind_I4);
764 else if (type == TypeManager.int64_type || type == TypeManager.uint64_type)
765 ig.Emit (OpCodes.Stind_I8);
766 else if (type == TypeManager.char_type || type == TypeManager.short_type ||
767 type == TypeManager.ushort_type)
768 ig.Emit (OpCodes.Stind_I2);
769 else if (type == TypeManager.float_type)
770 ig.Emit (OpCodes.Stind_R4);
771 else if (type == TypeManager.double_type)
772 ig.Emit (OpCodes.Stind_R8);
773 else if (type == TypeManager.byte_type || type == TypeManager.sbyte_type ||
774 type == TypeManager.bool_type)
775 ig.Emit (OpCodes.Stind_I1);
776 else if (type == TypeManager.intptr_type)
777 ig.Emit (OpCodes.Stind_I);
778 else if (TypeManager.IsStruct (type) || TypeManager.IsGenericParameter (type))
779 ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
781 ig.Emit (OpCodes.Stind_Ref);
785 /// Returns a temporary storage for a variable of type t as
786 /// a local variable in the current body.
788 public LocalBuilder GetTemporaryLocal (TypeSpec t)
790 if (temporary_storage != null) {
792 if (temporary_storage.TryGetValue (t, out o)) {
793 if (o is Stack<LocalBuilder>) {
794 var s = (Stack<LocalBuilder>) o;
795 o = s.Count == 0 ? null : s.Pop ();
797 temporary_storage.Remove (t);
801 return (LocalBuilder) o;
803 return DeclareLocal (t, false);
806 public void FreeTemporaryLocal (LocalBuilder b, TypeSpec t)
808 if (temporary_storage == null) {
809 temporary_storage = new Dictionary<TypeSpec, object> (ReferenceEquality<TypeSpec>.Default);
810 temporary_storage.Add (t, b);
815 if (!temporary_storage.TryGetValue (t, out o)) {
816 temporary_storage.Add (t, b);
819 var s = o as Stack<LocalBuilder>;
821 s = new Stack<LocalBuilder> ();
822 s.Push ((LocalBuilder)o);
823 temporary_storage [t] = s;
829 /// ReturnValue creates on demand the LocalBuilder for the
830 /// return value from the function. By default this is not
831 /// used. This is only required when returns are found inside
832 /// Try or Catch statements.
834 /// This method is typically invoked from the Emit phase, so
835 /// we allow the creation of a return label if it was not
836 /// requested during the resolution phase. Could be cleaned
837 /// up, but it would replicate a lot of logic in the Emit phase
838 /// of the code that uses it.
840 public LocalBuilder TemporaryReturn ()
842 if (return_value == null){
843 return_value = DeclareLocal (return_type, false);
844 if (!HasReturnLabel){
845 ReturnLabel = DefineLabel ();
846 HasReturnLabel = true;
854 public abstract class CommonAssemblyModulClass : Attributable, IMemberContext
856 public void AddAttributes (List<Attribute> attrs, IMemberContext context)
858 foreach (Attribute a in attrs)
859 a.AttachTo (this, context);
861 if (attributes == null) {
862 attributes = new Attributes (attrs);
865 attributes.AddAttributes (attrs);
868 public virtual void Emit (TypeContainer tc)
870 if (OptAttributes == null)
873 OptAttributes.Emit ();
876 protected Attribute ResolveAttribute (PredefinedAttribute a_type)
878 Attribute a = OptAttributes.Search (a_type);
885 #region IMemberContext Members
887 public CompilerContext Compiler {
888 get { return RootContext.ToplevelTypes.Compiler; }
891 public TypeSpec CurrentType {
895 public TypeParameter[] CurrentTypeParameters {
899 public MemberCore CurrentMemberDefinition {
900 get { return RootContext.ToplevelTypes; }
903 public string GetSignatureForError ()
908 public bool HasUnresolvedConstraints {
909 get { return false; }
912 public bool IsObsolete {
913 get { return false; }
916 public bool IsUnsafe {
917 get { return false; }
920 public bool IsStatic {
921 get { return false; }
924 public IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope)
926 throw new NotImplementedException ();
929 public FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
931 return RootContext.ToplevelTypes.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
934 public FullNamedExpression LookupNamespaceAlias (string name)
942 public class AssemblyClass : CommonAssemblyModulClass {
943 // TODO: make it private and move all builder based methods here
944 public AssemblyBuilder Builder;
945 bool is_cls_compliant;
946 bool wrap_non_exception_throws;
948 public Attribute ClsCompliantAttribute;
950 Dictionary<SecurityAction, PermissionSet> declarative_security;
951 bool has_extension_method;
952 public AssemblyName Name;
953 MethodInfo add_type_forwarder;
954 Dictionary<ITypeDefinition, Attribute> emitted_forwarders;
956 // Module is here just because of error messages
957 static string[] attribute_targets = new string [] { "assembly", "module" };
959 public AssemblyClass ()
961 wrap_non_exception_throws = true;
964 public bool HasExtensionMethods {
966 has_extension_method = value;
970 public bool IsClsCompliant {
972 return is_cls_compliant;
976 public bool WrapNonExceptionThrows {
978 return wrap_non_exception_throws;
982 public override AttributeTargets AttributeTargets {
984 return AttributeTargets.Assembly;
988 public override bool IsClsComplianceRequired ()
990 return is_cls_compliant;
994 get { return Compiler.Report; }
997 public void Resolve ()
999 if (RootContext.Unsafe) {
1001 // Emits [assembly: SecurityPermissionAttribute (SecurityAction.RequestMinimum, SkipVerification = true)]
1002 // when -unsafe option was specified
1005 Location loc = Location.Null;
1007 MemberAccess system_security_permissions = new MemberAccess (new MemberAccess (
1008 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Security", loc), "Permissions", loc);
1010 Arguments pos = new Arguments (1);
1011 pos.Add (new Argument (new MemberAccess (new MemberAccess (system_security_permissions, "SecurityAction", loc), "RequestMinimum")));
1013 Arguments named = new Arguments (1);
1014 named.Add (new NamedArgument ("SkipVerification", loc, new BoolLiteral (true, loc)));
1016 GlobalAttribute g = new GlobalAttribute (new NamespaceEntry (Compiler, null, null, null), "assembly",
1017 new MemberAccess (system_security_permissions, "SecurityPermissionAttribute"),
1018 new Arguments[] { pos, named }, loc, false);
1019 g.AttachTo (this, this);
1021 if (g.Resolve () != null) {
1022 declarative_security = new Dictionary<SecurityAction, PermissionSet> ();
1023 g.ExtractSecurityPermissionSet (declarative_security);
1027 if (OptAttributes == null)
1030 // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
1031 if (!OptAttributes.CheckTargets())
1034 ClsCompliantAttribute = ResolveAttribute (Compiler.PredefinedAttributes.CLSCompliant);
1036 if (ClsCompliantAttribute != null) {
1037 is_cls_compliant = ClsCompliantAttribute.GetClsCompliantAttributeValue ();
1040 Attribute a = ResolveAttribute (Compiler.PredefinedAttributes.RuntimeCompatibility);
1042 var val = a.GetPropertyValue ("WrapNonExceptionThrows") as BoolConstant;
1044 wrap_non_exception_throws = val.Value;
1049 private void SetPublicKey (AssemblyName an, byte[] strongNameBlob)
1052 // check for possible ECMA key
1053 if (strongNameBlob.Length == 16) {
1054 // will be rejected if not "the" ECMA key
1055 an.SetPublicKey (strongNameBlob);
1058 // take it, with or without, a private key
1059 RSA rsa = CryptoConvert.FromCapiKeyBlob (strongNameBlob);
1060 // and make sure we only feed the public part to Sys.Ref
1061 byte[] publickey = CryptoConvert.ToCapiPublicKeyBlob (rsa);
1063 // AssemblyName.SetPublicKey requires an additional header
1064 byte[] publicKeyHeader = new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 };
1066 byte[] encodedPublicKey = new byte [12 + publickey.Length];
1067 Buffer.BlockCopy (publicKeyHeader, 0, encodedPublicKey, 0, 12);
1068 Buffer.BlockCopy (publickey, 0, encodedPublicKey, 12, publickey.Length);
1069 an.SetPublicKey (encodedPublicKey);
1073 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' is incorrectly encoded");
1074 Environment.Exit (1);
1078 void Error_ObsoleteSecurityAttribute (Attribute a, string option)
1080 Report.Warning (1699, 1, a.Location,
1081 "Use compiler option `{0}' or appropriate project settings instead of `{1}' attribute",
1085 // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
1086 public AssemblyName GetAssemblyName (string name, string output)
1088 if (OptAttributes != null) {
1089 foreach (Attribute a in OptAttributes.Attrs) {
1090 // cannot rely on any resolve-based members before you call Resolve
1091 if (a.ExplicitTarget == null || a.ExplicitTarget != "assembly")
1094 // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
1095 // However, this is invoked by CodeGen.Init, when none of the namespaces
1097 // TODO: Does not handle quoted attributes properly
1099 case "AssemblyKeyFile":
1100 case "AssemblyKeyFileAttribute":
1101 case "System.Reflection.AssemblyKeyFileAttribute":
1102 if (RootContext.StrongNameKeyFile != null) {
1103 Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
1104 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1105 "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
1107 string value = a.GetString ();
1108 if (!string.IsNullOrEmpty (value)) {
1109 Error_ObsoleteSecurityAttribute (a, "keyfile");
1110 RootContext.StrongNameKeyFile = value;
1114 case "AssemblyKeyName":
1115 case "AssemblyKeyNameAttribute":
1116 case "System.Reflection.AssemblyKeyNameAttribute":
1117 if (RootContext.StrongNameKeyContainer != null) {
1118 Report.SymbolRelatedToPreviousError (a.Location, a.GetSignatureForError ());
1119 Report.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1120 "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
1122 string value = a.GetString ();
1123 if (!string.IsNullOrEmpty (value)) {
1124 Error_ObsoleteSecurityAttribute (a, "keycontainer");
1125 RootContext.StrongNameKeyContainer = value;
1129 case "AssemblyDelaySign":
1130 case "AssemblyDelaySignAttribute":
1131 case "System.Reflection.AssemblyDelaySignAttribute":
1132 bool b = a.GetBoolean ();
1134 Error_ObsoleteSecurityAttribute (a, "delaysign");
1137 RootContext.StrongNameDelaySign = b;
1143 AssemblyName an = new AssemblyName ();
1144 an.Name = Path.GetFileNameWithoutExtension (name);
1146 // note: delay doesn't apply when using a key container
1147 if (RootContext.StrongNameKeyContainer != null) {
1148 an.KeyPair = new StrongNameKeyPair (RootContext.StrongNameKeyContainer);
1152 // strongname is optional
1153 if (RootContext.StrongNameKeyFile == null)
1156 string AssemblyDir = Path.GetDirectoryName (output);
1158 // the StrongName key file may be relative to (a) the compiled
1159 // file or (b) to the output assembly. See bugzilla #55320
1160 // http://bugzilla.ximian.com/show_bug.cgi?id=55320
1162 // (a) relative to the compiled file
1163 string filename = Path.GetFullPath (RootContext.StrongNameKeyFile);
1164 bool exist = File.Exists (filename);
1165 if ((!exist) && (AssemblyDir != null) && (AssemblyDir != String.Empty)) {
1166 // (b) relative to the outputed assembly
1167 filename = Path.GetFullPath (Path.Combine (AssemblyDir, RootContext.StrongNameKeyFile));
1168 exist = File.Exists (filename);
1172 using (FileStream fs = new FileStream (filename, FileMode.Open, FileAccess.Read)) {
1173 byte[] snkeypair = new byte [fs.Length];
1174 fs.Read (snkeypair, 0, snkeypair.Length);
1176 if (RootContext.StrongNameDelaySign) {
1177 // delayed signing - DO NOT include private key
1178 SetPublicKey (an, snkeypair);
1181 // no delay so we make sure we have the private key
1183 CryptoConvert.FromCapiPrivateKeyBlob (snkeypair);
1184 an.KeyPair = new StrongNameKeyPair (snkeypair);
1186 catch (CryptographicException) {
1187 if (snkeypair.Length == 16) {
1188 // error # is different for ECMA key
1189 Report.Error (1606, "Could not sign the assembly. " +
1190 "ECMA key can only be used to delay-sign assemblies");
1193 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not have a private key");
1201 Error_AssemblySigning ("The specified file `" + RootContext.StrongNameKeyFile + "' does not exist");
1207 void Error_AssemblySigning (string text)
1209 Report.Error (1548, "Error during assembly signing. " + text);
1212 bool CheckInternalsVisibleAttribute (Attribute a)
1214 string assembly_name = a.GetString ();
1215 if (assembly_name.Length == 0)
1218 AssemblyName aname = null;
1220 aname = new AssemblyName (assembly_name);
1221 } catch (FileLoadException) {
1222 } catch (ArgumentException) {
1225 // Bad assembly name format
1227 Report.Warning (1700, 3, a.Location, "Assembly reference `" + assembly_name + "' is invalid and cannot be resolved");
1228 // Report error if we have defined Version or Culture
1229 else if (aname.Version != null || aname.CultureInfo != null)
1230 throw new Exception ("Friend assembly `" + a.GetString () +
1231 "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
1232 else if (aname.GetPublicKey () == null && Name.GetPublicKey () != null && Name.GetPublicKey ().Length != 0) {
1233 Report.Error (1726, a.Location, "Friend assembly reference `" + aname.FullName + "' is invalid." +
1234 " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
1241 static string IsValidAssemblyVersion (string version)
1245 v = new Version (version);
1248 int major = int.Parse (version, CultureInfo.InvariantCulture);
1249 v = new Version (major, 0);
1255 foreach (int candidate in new int [] { v.Major, v.Minor, v.Build, v.Revision }) {
1256 if (candidate > ushort.MaxValue)
1260 return new Version (v.Major, System.Math.Max (0, v.Minor), System.Math.Max (0, v.Build), System.Math.Max (0, v.Revision)).ToString (4);
1263 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
1265 if (a.IsValidSecurityAttribute ()) {
1266 if (declarative_security == null)
1267 declarative_security = new Dictionary<SecurityAction, PermissionSet> ();
1269 a.ExtractSecurityPermissionSet (declarative_security);
1273 if (a.Type == pa.AssemblyCulture) {
1274 string value = a.GetString ();
1275 if (value == null || value.Length == 0)
1278 if (RootContext.Target == Target.Exe) {
1279 a.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
1284 var fi = typeof (AssemblyBuilder).GetField ("culture", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
1285 fi.SetValue (Builder, value == "neutral" ? "" : value);
1287 Report.RuntimeMissingSupport (a.Location, "AssemblyCultureAttribute setting");
1293 if (a.Type == pa.AssemblyVersion) {
1294 string value = a.GetString ();
1295 if (value == null || value.Length == 0)
1298 var vinfo = IsValidAssemblyVersion (value.Replace ('*', '0'));
1299 if (vinfo == null) {
1300 a.Error_AttributeEmitError (string.Format ("Specified version `{0}' is not valid", value));
1305 var fi = typeof (AssemblyBuilder).GetField ("version", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
1306 fi.SetValue (Builder, vinfo);
1308 Report.RuntimeMissingSupport (a.Location, "AssemblyVersionAttribute setting");
1314 if (a.Type == pa.AssemblyAlgorithmId) {
1315 const int pos = 2; // skip CA header
1316 uint alg = (uint) cdata [pos];
1317 alg |= ((uint) cdata [pos + 1]) << 8;
1318 alg |= ((uint) cdata [pos + 2]) << 16;
1319 alg |= ((uint) cdata [pos + 3]) << 24;
1322 var fi = typeof (AssemblyBuilder).GetField ("algid", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
1323 fi.SetValue (Builder, alg);
1325 Report.RuntimeMissingSupport (a.Location, "AssemblyAlgorithmIdAttribute setting");
1331 if (a.Type == pa.AssemblyFlags) {
1332 const int pos = 2; // skip CA header
1333 uint flags = (uint) cdata[pos];
1334 flags |= ((uint) cdata[pos + 1]) << 8;
1335 flags |= ((uint) cdata[pos + 2]) << 16;
1336 flags |= ((uint) cdata[pos + 3]) << 24;
1338 // Ignore set PublicKey flag if assembly is not strongnamed
1339 if ((flags & (uint) AssemblyNameFlags.PublicKey) != 0 && (Builder.GetName ().KeyPair == null))
1340 flags &= ~(uint)AssemblyNameFlags.PublicKey;
1343 var fi = typeof (AssemblyBuilder).GetField ("flags", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
1344 fi.SetValue (Builder, flags);
1346 Report.RuntimeMissingSupport (a.Location, "AssemblyFlagsAttribute setting");
1352 if (a.Type == pa.InternalsVisibleTo && !CheckInternalsVisibleAttribute (a))
1355 if (a.Type == pa.TypeForwarder) {
1356 TypeSpec t = a.GetArgumentType ();
1357 if (t == null || TypeManager.HasElementType (t)) {
1358 Report.Error (735, a.Location, "Invalid type specified as an argument for TypeForwardedTo attribute");
1362 if (emitted_forwarders == null) {
1363 emitted_forwarders = new Dictionary<ITypeDefinition, Attribute> ();
1364 } else if (emitted_forwarders.ContainsKey (t.MemberDefinition)) {
1365 Report.SymbolRelatedToPreviousError(emitted_forwarders[t.MemberDefinition].Location, null);
1366 Report.Error(739, a.Location, "A duplicate type forward of type `{0}'",
1367 TypeManager.CSharpName(t));
1371 emitted_forwarders.Add(t.MemberDefinition, a);
1373 if (t.Assembly == Builder) {
1374 Report.SymbolRelatedToPreviousError (t);
1375 Report.Error (729, a.Location, "Cannot forward type `{0}' because it is defined in this assembly",
1376 TypeManager.CSharpName (t));
1381 Report.Error (730, a.Location, "Cannot forward type `{0}' because it is a nested type",
1382 TypeManager.CSharpName (t));
1386 if (add_type_forwarder == null) {
1387 add_type_forwarder = typeof (AssemblyBuilder).GetMethod ("AddTypeForwarder",
1388 BindingFlags.NonPublic | BindingFlags.Instance);
1390 if (add_type_forwarder == null) {
1391 Report.RuntimeMissingSupport (a.Location, "TypeForwardedTo attribute");
1396 add_type_forwarder.Invoke (Builder, new object[] { t.GetMetaInfo () });
1400 if (a.Type == pa.Extension) {
1401 a.Error_MisusedExtensionAttribute ();
1405 Builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
1408 public override void Emit (TypeContainer tc)
1412 if (has_extension_method)
1413 Compiler.PredefinedAttributes.Extension.EmitAttribute (Builder);
1415 PredefinedAttribute pa = tc.Compiler.PredefinedAttributes.RuntimeCompatibility;
1416 if (pa.IsDefined && (OptAttributes == null || !OptAttributes.Contains (pa))) {
1417 var ci = TypeManager.GetPredefinedConstructor (pa.Type, Location.Null, TypeSpec.EmptyTypes);
1418 PropertyInfo [] pis = new PropertyInfo [1];
1420 pis [0] = TypeManager.GetPredefinedProperty (pa.Type,
1421 "WrapNonExceptionThrows", Location.Null, TypeManager.bool_type).MetaInfo;
1422 object [] pargs = new object [1];
1424 Builder.SetCustomAttribute (new CustomAttributeBuilder ((ConstructorInfo) ci.GetMetaInfo (), new object[0], pis, pargs));
1427 if (declarative_security != null) {
1429 MethodInfo add_permission = typeof (AssemblyBuilder).GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1430 object builder_instance = Builder;
1433 // Microsoft runtime hacking
1434 if (add_permission == null) {
1435 var assembly_builder = typeof (AssemblyBuilder).Assembly.GetType ("System.Reflection.Emit.AssemblyBuilderData");
1436 add_permission = assembly_builder.GetMethod ("AddPermissionRequests", BindingFlags.Instance | BindingFlags.NonPublic);
1438 FieldInfo fi = typeof (AssemblyBuilder).GetField ("m_assemblyData", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.GetField);
1439 builder_instance = fi.GetValue (Builder);
1442 var args = new PermissionSet [3];
1443 declarative_security.TryGetValue (SecurityAction.RequestMinimum, out args [0]);
1444 declarative_security.TryGetValue (SecurityAction.RequestOptional, out args [1]);
1445 declarative_security.TryGetValue (SecurityAction.RequestRefuse, out args [2]);
1446 add_permission.Invoke (builder_instance, args);
1449 Report.RuntimeMissingSupport (Location.Null, "assembly permission setting");
1454 public override string[] ValidAttributeTargets {
1456 return attribute_targets;
1460 // Wrapper for AssemblyBuilder.AddModule
1461 static MethodInfo adder_method;
1462 static public MethodInfo AddModule_Method {
1464 if (adder_method == null)
1465 adder_method = typeof (AssemblyBuilder).GetMethod ("AddModule", BindingFlags.Instance|BindingFlags.NonPublic);
1466 return adder_method;
1469 public Module AddModule (string module)
1471 MethodInfo m = AddModule_Method;
1473 Report.RuntimeMissingSupport (Location.Null, "/addmodule");
1474 Environment.Exit (1);
1478 return (Module) m.Invoke (Builder, new object [] { module });
1479 } catch (TargetInvocationException ex) {
1480 throw ex.InnerException;