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 public static AssemblyClass Assembly
;
48 public static void Reset ()
50 Assembly
= new AssemblyClass ();
53 public static string Basename (string name
)
55 int pos
= name
.LastIndexOf ('/');
58 return name
.Substring (pos
+ 1);
60 pos
= name
.LastIndexOf ('\\');
62 return name
.Substring (pos
+ 1);
67 public static string Dirname (string name
)
69 int pos
= name
.LastIndexOf ('/');
72 return name
.Substring (0, pos
);
74 pos
= name
.LastIndexOf ('\\');
76 return name
.Substring (0, pos
);
81 static public string FileName
;
84 // Initializes the code generator variables for interactive use (repl)
86 static public void InitDynamic (CompilerContext ctx
, string name
)
88 current_domain
= AppDomain
.CurrentDomain
;
89 AssemblyName an
= Assembly
.GetAssemblyName (name
, name
);
91 Assembly
.Builder
= current_domain
.DefineDynamicAssembly (an
, AssemblyBuilderAccess
.Run
);
92 RootContext
.ToplevelTypes
= new ModuleCompiled (ctx
, true);
93 RootContext
.ToplevelTypes
.Builder
= Assembly
.Builder
.DefineDynamicModule (Basename (name
), false);
94 Assembly
.Name
= Assembly
.Builder
.GetName ();
98 // Initializes the code generator variables
100 static public bool Init (string name
, string output
, bool want_debugging_support
, CompilerContext ctx
)
103 AssemblyName an
= Assembly
.GetAssemblyName (name
, output
);
107 if (an
.KeyPair
!= null) {
108 // If we are going to strong name our assembly make
109 // sure all its refs are strong named
110 foreach (Assembly a
in GlobalRootNamespace
.Instance
.Assemblies
) {
111 AssemblyName ref_name
= a
.GetName ();
112 byte [] b
= ref_name
.GetPublicKeyToken ();
113 if (b
== null || b
.Length
== 0) {
114 ctx
.Report
.Error (1577, "Assembly generation failed " +
115 "-- Referenced assembly '" +
117 "' does not have a strong name.");
118 //Environment.Exit (1);
123 current_domain
= AppDomain
.CurrentDomain
;
126 Assembly
.Builder
= current_domain
.DefineDynamicAssembly (an
,
127 AssemblyBuilderAccess
.RunAndSave
, Dirname (name
));
129 catch (ArgumentException
) {
130 // specified key may not be exportable outside it's container
131 if (RootContext
.StrongNameKeyContainer
!= null) {
132 ctx
.Report
.Error (1548, "Could not access the key inside the container `" +
133 RootContext
.StrongNameKeyContainer
+ "'.");
134 Environment
.Exit (1);
138 catch (CryptographicException
) {
139 if ((RootContext
.StrongNameKeyContainer
!= null) || (RootContext
.StrongNameKeyFile
!= null)) {
140 ctx
.Report
.Error (1548, "Could not use the specified key to strongname the assembly.");
141 Environment
.Exit (1);
146 // Get the complete AssemblyName from the builder
147 // (We need to get the public key and token)
148 Assembly
.Name
= Assembly
.Builder
.GetName ();
151 // Pass a path-less name to DefineDynamicModule. Wonder how
152 // this copes with output in different directories then.
153 // FIXME: figure out how this copes with --output /tmp/blah
155 // If the third argument is true, the ModuleBuilder will dynamically
156 // load the default symbol writer.
159 RootContext
.ToplevelTypes
.Builder
= Assembly
.Builder
.DefineDynamicModule (
160 Basename (name
), Basename (output
), want_debugging_support
);
163 // TODO: We should use SymbolWriter from DefineDynamicModule
164 if (want_debugging_support
&& !SymbolWriter
.Initialize (RootContext
.ToplevelTypes
.Builder
, output
)) {
165 ctx
.Report
.Error (40, "Unexpected debug information initialization error `{0}'",
166 "Could not find the symbol writer assembly (Mono.CompilerServices.SymbolWriter.dll)");
170 } catch (ExecutionEngineException e
) {
171 ctx
.Report
.Error (40, "Unexpected debug information initialization error `{0}'",
179 static public void Save (string name
, bool saveDebugInfo
, Report Report
)
181 PortableExecutableKinds pekind
;
182 ImageFileMachine machine
;
184 switch (RootContext
.Platform
) {
186 pekind
= PortableExecutableKinds
.Required32Bit
;
187 machine
= ImageFileMachine
.I386
;
190 pekind
= PortableExecutableKinds
.PE32Plus
;
191 machine
= ImageFileMachine
.AMD64
;
194 pekind
= PortableExecutableKinds
.PE32Plus
;
195 machine
= ImageFileMachine
.IA64
;
197 case Platform
.AnyCPU
:
199 pekind
= PortableExecutableKinds
.ILOnly
;
200 machine
= ImageFileMachine
.I386
;
204 Assembly
.Builder
.Save (Basename (name
), pekind
, machine
);
206 catch (COMException
) {
207 if ((RootContext
.StrongNameKeyFile
== null) || (!RootContext
.StrongNameDelaySign
))
210 // FIXME: it seems Microsoft AssemblyBuilder doesn't like to delay sign assemblies
211 Report
.Error (1548, "Couldn't delay-sign the assembly with the '" +
212 RootContext
.StrongNameKeyFile
+
213 "', Use MCS with the Mono runtime or CSC to compile this assembly.");
215 catch (System
.IO
.IOException io
) {
216 Report
.Error (16, "Could not write to file `"+name
+"', cause: " + io
.Message
);
219 catch (System
.UnauthorizedAccessException ua
) {
220 Report
.Error (16, "Could not write to file `"+name
+"', cause: " + ua
.Message
);
223 catch (System
.NotImplementedException nie
) {
224 Report
.RuntimeMissingSupport (Location
.Null
, nie
.Message
);
229 // Write debuger symbol file
232 SymbolWriter
.WriteSymbolFile ();
237 /// An Emit Context is created for each body of code (from methods,
238 /// properties bodies, indexer bodies or constructor bodies)
240 public class EmitContext
: BuilderContext
242 // TODO: Has to be private
243 public ILGenerator ig
;
246 /// The value that is allowed to be returned or NULL if there is no
249 TypeSpec return_type
;
252 /// Keeps track of the Type to LocalBuilder temporary storage created
253 /// to store structures (used to compute the address of the structure
254 /// value on structure method invocations)
256 Dictionary
<TypeSpec
, object> temporary_storage
;
259 /// The location where we store the return value.
261 public LocalBuilder return_value
;
264 /// The location where return has to jump to return the
267 public Label ReturnLabel
;
270 /// If we already defined the ReturnLabel
272 public bool HasReturnLabel
;
275 /// Current loop begin and end labels.
277 public Label LoopBegin
, LoopEnd
;
280 /// Default target in a switch statement. Only valid if
283 public Label DefaultTarget
;
286 /// If this is non-null, points to the current switch statement
288 public Switch Switch
;
291 /// Whether we are inside an anonymous method.
293 public AnonymousExpression CurrentAnonymousMethod
;
295 public readonly IMemberContext MemberContext
;
297 public EmitContext (IMemberContext rc
, ILGenerator ig
, TypeSpec return_type
)
299 this.MemberContext
= rc
;
302 this.return_type
= return_type
;
307 public TypeSpec CurrentType
{
308 get { return MemberContext.CurrentType; }
311 public TypeParameter
[] CurrentTypeParameters
{
312 get { return MemberContext.CurrentTypeParameters; }
315 public MemberCore CurrentTypeDefinition
{
316 get { return MemberContext.CurrentMemberDefinition; }
319 public bool IsStatic
{
320 get { return MemberContext.IsStatic; }
323 bool IsAnonymousStoreyMutateRequired
{
325 return CurrentAnonymousMethod
!= null &&
326 CurrentAnonymousMethod
.Storey
!= null &&
327 CurrentAnonymousMethod
.Storey
.Mutator
!= null;
331 // Has to be used for emitter errors only
332 public Report Report
{
333 get { return MemberContext.Compiler.Report; }
336 public TypeSpec ReturnType
{
344 /// This is called immediately before emitting an IL opcode to tell the symbol
345 /// writer to which source line this opcode belongs.
347 public void Mark (Location loc
)
349 if (!SymbolWriter
.HasSymbolWriter
|| HasSet (Options
.OmitDebugInfo
) || loc
.IsNull
)
352 SymbolWriter
.MarkSequencePoint (ig
, loc
);
355 public void DefineLocalVariable (string name
, LocalBuilder builder
)
357 SymbolWriter
.DefineLocalVariable (name
, builder
);
360 public void BeginCatchBlock (TypeSpec type
)
362 ig
.BeginCatchBlock (type
.GetMetaInfo ());
365 public void BeginExceptionBlock ()
367 ig
.BeginExceptionBlock ();
370 public void BeginFinallyBlock ()
372 ig
.BeginFinallyBlock ();
375 public void BeginScope ()
378 SymbolWriter
.OpenScope(ig
);
381 public void EndExceptionBlock ()
383 ig
.EndExceptionBlock ();
386 public void EndScope ()
389 SymbolWriter
.CloseScope(ig
);
392 public LocalBuilder
DeclareLocal (TypeSpec type
, bool pinned
)
394 if (IsAnonymousStoreyMutateRequired
)
395 type
= CurrentAnonymousMethod
.Storey
.Mutator
.Mutate (type
);
397 return ig
.DeclareLocal (type
.GetMetaInfo (), pinned
);
400 public Label
DefineLabel ()
402 return ig
.DefineLabel ();
405 public void MarkLabel (Label label
)
407 ig
.MarkLabel (label
);
410 public void Emit (OpCode opcode
)
415 public void Emit (OpCode opcode
, LocalBuilder local
)
417 ig
.Emit (opcode
, local
);
420 public void Emit (OpCode opcode
, string arg
)
422 ig
.Emit (opcode
, arg
);
425 public void Emit (OpCode opcode
, double arg
)
427 ig
.Emit (opcode
, arg
);
430 public void Emit (OpCode opcode
, float arg
)
432 ig
.Emit (opcode
, arg
);
435 public void Emit (OpCode opcode
, int arg
)
437 ig
.Emit (opcode
, arg
);
440 public void Emit (OpCode opcode
, byte arg
)
442 ig
.Emit (opcode
, arg
);
445 public void Emit (OpCode opcode
, Label label
)
447 ig
.Emit (opcode
, label
);
450 public void Emit (OpCode opcode
, Label
[] labels
)
452 ig
.Emit (opcode
, labels
);
455 public void Emit (OpCode opcode
, TypeSpec type
)
457 if (IsAnonymousStoreyMutateRequired
)
458 type
= CurrentAnonymousMethod
.Storey
.Mutator
.Mutate (type
);
460 ig
.Emit (opcode
, type
.GetMetaInfo ());
463 public void Emit (OpCode opcode
, FieldSpec field
)
465 if (IsAnonymousStoreyMutateRequired
)
466 field
= field
.Mutate (CurrentAnonymousMethod
.Storey
.Mutator
);
468 ig
.Emit (opcode
, field
.GetMetaInfo ());
471 public void Emit (OpCode opcode
, MethodSpec method
)
473 if (IsAnonymousStoreyMutateRequired
)
474 method
= method
.Mutate (CurrentAnonymousMethod
.Storey
.Mutator
);
476 if (method
.IsConstructor
)
477 ig
.Emit (opcode
, (ConstructorInfo
) method
.GetMetaInfo ());
479 ig
.Emit (opcode
, (MethodInfo
) method
.GetMetaInfo ());
482 // TODO: REMOVE breaks mutator
483 public void Emit (OpCode opcode
, MethodInfo method
)
485 ig
.Emit (opcode
, method
);
488 // TODO: REMOVE breaks mutator
489 public void Emit (OpCode opcode
, FieldBuilder field
)
491 ig
.Emit (opcode
, field
);
494 public void Emit (OpCode opcode
, MethodSpec method
, Type
[] vargs
)
496 // TODO MemberCache: This should mutate too
497 ig
.EmitCall (opcode
, (MethodInfo
) method
.GetMetaInfo (), vargs
);
500 public void EmitArrayNew (ArrayContainer ac
)
503 Emit (OpCodes
.Newarr
, ac
.Element
);
505 if (IsAnonymousStoreyMutateRequired
)
506 ac
= (ArrayContainer
) ac
.Mutate (CurrentAnonymousMethod
.Storey
.Mutator
);
508 ig
.Emit (OpCodes
.Newobj
, ac
.GetConstructor ());
512 public void EmitArrayAddress (ArrayContainer ac
)
514 if (ac
.Element
.IsGenericParameter
)
515 ig
.Emit (OpCodes
.Readonly
);
518 if (IsAnonymousStoreyMutateRequired
)
519 ac
= (ArrayContainer
) ac
.Mutate (CurrentAnonymousMethod
.Storey
.Mutator
);
521 ig
.Emit (OpCodes
.Call
, ac
.GetAddressMethod ());
523 Emit (OpCodes
.Ldelema
, ac
.Element
);
528 // Emits the right opcode to load from an array
530 public void EmitArrayLoad (ArrayContainer ac
)
533 if (IsAnonymousStoreyMutateRequired
)
534 ac
= (ArrayContainer
) ac
.Mutate (CurrentAnonymousMethod
.Storey
.Mutator
);
536 ig
.Emit (OpCodes
.Call
, ac
.GetGetMethod ());
540 var type
= ac
.Element
;
541 if (TypeManager
.IsEnumType (type
))
542 type
= EnumSpec
.GetUnderlyingType (type
);
544 if (type
== TypeManager
.byte_type
|| type
== TypeManager
.bool_type
)
545 Emit (OpCodes
.Ldelem_U1
);
546 else if (type
== TypeManager
.sbyte_type
)
547 Emit (OpCodes
.Ldelem_I1
);
548 else if (type
== TypeManager
.short_type
)
549 Emit (OpCodes
.Ldelem_I2
);
550 else if (type
== TypeManager
.ushort_type
|| type
== TypeManager
.char_type
)
551 Emit (OpCodes
.Ldelem_U2
);
552 else if (type
== TypeManager
.int32_type
)
553 Emit (OpCodes
.Ldelem_I4
);
554 else if (type
== TypeManager
.uint32_type
)
555 Emit (OpCodes
.Ldelem_U4
);
556 else if (type
== TypeManager
.uint64_type
)
557 Emit (OpCodes
.Ldelem_I8
);
558 else if (type
== TypeManager
.int64_type
)
559 Emit (OpCodes
.Ldelem_I8
);
560 else if (type
== TypeManager
.float_type
)
561 Emit (OpCodes
.Ldelem_R4
);
562 else if (type
== TypeManager
.double_type
)
563 Emit (OpCodes
.Ldelem_R8
);
564 else if (type
== TypeManager
.intptr_type
)
565 Emit (OpCodes
.Ldelem_I
);
566 else if (TypeManager
.IsStruct (type
)) {
567 Emit (OpCodes
.Ldelema
, type
);
568 Emit (OpCodes
.Ldobj
, type
);
569 } else if (type
.IsGenericParameter
) {
570 Emit (OpCodes
.Ldelem
, type
);
571 } else if (type
.IsPointer
)
572 Emit (OpCodes
.Ldelem_I
);
574 Emit (OpCodes
.Ldelem_Ref
);
578 // Emits the right opcode to store to an array
580 public void EmitArrayStore (ArrayContainer ac
)
583 if (IsAnonymousStoreyMutateRequired
)
584 ac
= (ArrayContainer
) ac
.Mutate (CurrentAnonymousMethod
.Storey
.Mutator
);
586 ig
.Emit (OpCodes
.Call
, ac
.GetSetMethod ());
590 var type
= ac
.Element
;
593 type
= EnumSpec
.GetUnderlyingType (type
);
595 if (type
== TypeManager
.byte_type
|| type
== TypeManager
.sbyte_type
|| type
== TypeManager
.bool_type
)
596 Emit (OpCodes
.Stelem_I1
);
597 else if (type
== TypeManager
.short_type
|| type
== TypeManager
.ushort_type
|| type
== TypeManager
.char_type
)
598 Emit (OpCodes
.Stelem_I2
);
599 else if (type
== TypeManager
.int32_type
|| type
== TypeManager
.uint32_type
)
600 Emit (OpCodes
.Stelem_I4
);
601 else if (type
== TypeManager
.int64_type
|| type
== TypeManager
.uint64_type
)
602 Emit (OpCodes
.Stelem_I8
);
603 else if (type
== TypeManager
.float_type
)
604 Emit (OpCodes
.Stelem_R4
);
605 else if (type
== TypeManager
.double_type
)
606 Emit (OpCodes
.Stelem_R8
);
607 else if (type
== TypeManager
.intptr_type
)
608 Emit (OpCodes
.Stobj
, type
);
609 else if (TypeManager
.IsStruct (type
))
610 Emit (OpCodes
.Stobj
, type
);
611 else if (type
.IsGenericParameter
)
612 Emit (OpCodes
.Stelem
, type
);
613 else if (type
.IsPointer
)
614 Emit (OpCodes
.Stelem_I
);
616 Emit (OpCodes
.Stelem_Ref
);
619 public void EmitInt (int i
)
623 ig
.Emit (OpCodes
.Ldc_I4_M1
);
627 ig
.Emit (OpCodes
.Ldc_I4_0
);
631 ig
.Emit (OpCodes
.Ldc_I4_1
);
635 ig
.Emit (OpCodes
.Ldc_I4_2
);
639 ig
.Emit (OpCodes
.Ldc_I4_3
);
643 ig
.Emit (OpCodes
.Ldc_I4_4
);
647 ig
.Emit (OpCodes
.Ldc_I4_5
);
651 ig
.Emit (OpCodes
.Ldc_I4_6
);
655 ig
.Emit (OpCodes
.Ldc_I4_7
);
659 ig
.Emit (OpCodes
.Ldc_I4_8
);
663 if (i
>= -128 && i
<= 127) {
664 ig
.Emit (OpCodes
.Ldc_I4_S
, (sbyte) i
);
666 ig
.Emit (OpCodes
.Ldc_I4
, i
);
671 public void EmitLong (long l
)
673 if (l
>= int.MinValue
&& l
<= int.MaxValue
) {
674 EmitInt (unchecked ((int) l
));
675 ig
.Emit (OpCodes
.Conv_I8
);
679 if (l
>= 0 && l
<= uint.MaxValue
) {
680 EmitInt (unchecked ((int) l
));
681 ig
.Emit (OpCodes
.Conv_U8
);
685 ig
.Emit (OpCodes
.Ldc_I8
, l
);
689 // Load the object from the pointer.
691 public void EmitLoadFromPtr (TypeSpec t
)
693 if (t
== TypeManager
.int32_type
)
694 ig
.Emit (OpCodes
.Ldind_I4
);
695 else if (t
== TypeManager
.uint32_type
)
696 ig
.Emit (OpCodes
.Ldind_U4
);
697 else if (t
== TypeManager
.short_type
)
698 ig
.Emit (OpCodes
.Ldind_I2
);
699 else if (t
== TypeManager
.ushort_type
)
700 ig
.Emit (OpCodes
.Ldind_U2
);
701 else if (t
== TypeManager
.char_type
)
702 ig
.Emit (OpCodes
.Ldind_U2
);
703 else if (t
== TypeManager
.byte_type
)
704 ig
.Emit (OpCodes
.Ldind_U1
);
705 else if (t
== TypeManager
.sbyte_type
)
706 ig
.Emit (OpCodes
.Ldind_I1
);
707 else if (t
== TypeManager
.uint64_type
)
708 ig
.Emit (OpCodes
.Ldind_I8
);
709 else if (t
== TypeManager
.int64_type
)
710 ig
.Emit (OpCodes
.Ldind_I8
);
711 else if (t
== TypeManager
.float_type
)
712 ig
.Emit (OpCodes
.Ldind_R4
);
713 else if (t
== TypeManager
.double_type
)
714 ig
.Emit (OpCodes
.Ldind_R8
);
715 else if (t
== TypeManager
.bool_type
)
716 ig
.Emit (OpCodes
.Ldind_I1
);
717 else if (t
== TypeManager
.intptr_type
)
718 ig
.Emit (OpCodes
.Ldind_I
);
720 if (t
== TypeManager
.enum_type
)
721 ig
.Emit (OpCodes
.Ldind_Ref
);
723 EmitLoadFromPtr (EnumSpec
.GetUnderlyingType (t
));
724 } else if (TypeManager
.IsStruct (t
) || TypeManager
.IsGenericParameter (t
))
725 Emit (OpCodes
.Ldobj
, t
);
726 else if (t
.IsPointer
)
727 ig
.Emit (OpCodes
.Ldind_I
);
729 ig
.Emit (OpCodes
.Ldind_Ref
);
733 // The stack contains the pointer and the value of type `type'
735 public void EmitStoreFromPtr (TypeSpec type
)
738 type
= EnumSpec
.GetUnderlyingType (type
);
740 if (type
== TypeManager
.int32_type
|| type
== TypeManager
.uint32_type
)
741 ig
.Emit (OpCodes
.Stind_I4
);
742 else if (type
== TypeManager
.int64_type
|| type
== TypeManager
.uint64_type
)
743 ig
.Emit (OpCodes
.Stind_I8
);
744 else if (type
== TypeManager
.char_type
|| type
== TypeManager
.short_type
||
745 type
== TypeManager
.ushort_type
)
746 ig
.Emit (OpCodes
.Stind_I2
);
747 else if (type
== TypeManager
.float_type
)
748 ig
.Emit (OpCodes
.Stind_R4
);
749 else if (type
== TypeManager
.double_type
)
750 ig
.Emit (OpCodes
.Stind_R8
);
751 else if (type
== TypeManager
.byte_type
|| type
== TypeManager
.sbyte_type
||
752 type
== TypeManager
.bool_type
)
753 ig
.Emit (OpCodes
.Stind_I1
);
754 else if (type
== TypeManager
.intptr_type
)
755 ig
.Emit (OpCodes
.Stind_I
);
756 else if (TypeManager
.IsStruct (type
) || TypeManager
.IsGenericParameter (type
))
757 ig
.Emit (OpCodes
.Stobj
, type
.GetMetaInfo ());
759 ig
.Emit (OpCodes
.Stind_Ref
);
763 /// Returns a temporary storage for a variable of type t as
764 /// a local variable in the current body.
766 public LocalBuilder
GetTemporaryLocal (TypeSpec t
)
768 if (temporary_storage
!= null) {
770 if (temporary_storage
.TryGetValue (t
, out o
)) {
771 if (o
is Stack
<LocalBuilder
>) {
772 var s
= (Stack
<LocalBuilder
>) o
;
773 o
= s
.Count
== 0 ? null : s
.Pop ();
775 temporary_storage
.Remove (t
);
779 return (LocalBuilder
) o
;
781 return DeclareLocal (t
, false);
784 public void FreeTemporaryLocal (LocalBuilder b
, TypeSpec t
)
786 if (temporary_storage
== null) {
787 temporary_storage
= new Dictionary
<TypeSpec
, object> (ReferenceEquality
<TypeSpec
>.Default
);
788 temporary_storage
.Add (t
, b
);
793 if (!temporary_storage
.TryGetValue (t
, out o
)) {
794 temporary_storage
.Add (t
, b
);
797 var s
= o
as Stack
<LocalBuilder
>;
799 s
= new Stack
<LocalBuilder
> ();
800 s
.Push ((LocalBuilder
)o
);
801 temporary_storage
[t
] = s
;
807 /// ReturnValue creates on demand the LocalBuilder for the
808 /// return value from the function. By default this is not
809 /// used. This is only required when returns are found inside
810 /// Try or Catch statements.
812 /// This method is typically invoked from the Emit phase, so
813 /// we allow the creation of a return label if it was not
814 /// requested during the resolution phase. Could be cleaned
815 /// up, but it would replicate a lot of logic in the Emit phase
816 /// of the code that uses it.
818 public LocalBuilder
TemporaryReturn ()
820 if (return_value
== null){
821 return_value
= DeclareLocal (return_type
, false);
822 if (!HasReturnLabel
){
823 ReturnLabel
= DefineLabel ();
824 HasReturnLabel
= true;
832 public abstract class CommonAssemblyModulClass
: Attributable
, IMemberContext
834 public void AddAttributes (List
<Attribute
> attrs
, IMemberContext context
)
836 foreach (Attribute a
in attrs
)
837 a
.AttachTo (this, context
);
839 if (attributes
== null) {
840 attributes
= new Attributes (attrs
);
843 attributes
.AddAttributes (attrs
);
846 public virtual void Emit (TypeContainer tc
)
848 if (OptAttributes
== null)
851 OptAttributes
.Emit ();
854 protected Attribute
ResolveAttribute (PredefinedAttribute a_type
)
856 Attribute a
= OptAttributes
.Search (a_type
);
863 #region IMemberContext Members
865 public CompilerContext Compiler
{
866 get { return RootContext.ToplevelTypes.Compiler; }
869 public TypeSpec CurrentType
{
873 public TypeParameter
[] CurrentTypeParameters
{
877 public MemberCore CurrentMemberDefinition
{
878 get { return RootContext.ToplevelTypes; }
881 public string GetSignatureForError ()
886 public bool HasUnresolvedConstraints
{
887 get { return false; }
890 public bool IsObsolete
{
891 get { return false; }
894 public bool IsUnsafe
{
895 get { return false; }
898 public bool IsStatic
{
899 get { return false; }
902 public ExtensionMethodGroupExpr
LookupExtensionMethod (TypeSpec extensionType
, string name
, int arity
, Location loc
)
904 throw new NotImplementedException ();
907 public FullNamedExpression
LookupNamespaceOrType (string name
, int arity
, Location loc
, bool ignore_cs0104
)
909 return RootContext
.ToplevelTypes
.LookupNamespaceOrType (name
, arity
, loc
, ignore_cs0104
);
912 public FullNamedExpression
LookupNamespaceAlias (string name
)
920 public class AssemblyClass
: CommonAssemblyModulClass
{
921 // TODO: make it private and move all builder based methods here
922 public AssemblyBuilder Builder
;
923 bool is_cls_compliant
;
924 bool wrap_non_exception_throws
;
926 public Attribute ClsCompliantAttribute
;
928 Dictionary
<SecurityAction
, PermissionSet
> declarative_security
;
929 bool has_extension_method
;
930 public AssemblyName Name
;
931 MethodInfo add_type_forwarder
;
932 Dictionary
<ITypeDefinition
, Attribute
> emitted_forwarders
;
934 // Module is here just because of error messages
935 static string[] attribute_targets
= new string [] { "assembly", "module" }
;
937 public AssemblyClass ()
939 wrap_non_exception_throws
= true;
942 public bool HasExtensionMethods
{
944 has_extension_method
= value;
948 public bool IsClsCompliant
{
950 return is_cls_compliant
;
954 public bool WrapNonExceptionThrows
{
956 return wrap_non_exception_throws
;
960 public override AttributeTargets AttributeTargets
{
962 return AttributeTargets
.Assembly
;
966 public override bool IsClsComplianceRequired ()
968 return is_cls_compliant
;
972 get { return Compiler.Report; }
975 public void Resolve ()
977 if (RootContext
.Unsafe
) {
979 // Emits [assembly: SecurityPermissionAttribute (SecurityAction.RequestMinimum, SkipVerification = true)]
980 // when -unsafe option was specified
983 Location loc
= Location
.Null
;
985 MemberAccess system_security_permissions
= new MemberAccess (new MemberAccess (
986 new QualifiedAliasMember (QualifiedAliasMember
.GlobalAlias
, "System", loc
), "Security", loc
), "Permissions", loc
);
988 Arguments pos
= new Arguments (1);
989 pos
.Add (new Argument (new MemberAccess (new MemberAccess (system_security_permissions
, "SecurityAction", loc
), "RequestMinimum")));
991 Arguments named
= new Arguments (1);
992 named
.Add (new NamedArgument ("SkipVerification", loc
, new BoolLiteral (true, loc
)));
994 GlobalAttribute g
= new GlobalAttribute (new NamespaceEntry (null, null, null), "assembly",
995 new MemberAccess (system_security_permissions
, "SecurityPermissionAttribute"),
996 new Arguments
[] { pos, named }
, loc
, false);
997 g
.AttachTo (this, this);
999 if (g
.Resolve () != null) {
1000 declarative_security
= new Dictionary
<SecurityAction
, PermissionSet
> ();
1001 g
.ExtractSecurityPermissionSet (declarative_security
);
1005 if (OptAttributes
== null)
1008 // Ensure that we only have GlobalAttributes, since the Search isn't safe with other types.
1009 if (!OptAttributes
.CheckTargets())
1012 ClsCompliantAttribute
= ResolveAttribute (PredefinedAttributes
.Get
.CLSCompliant
);
1014 if (ClsCompliantAttribute
!= null) {
1015 is_cls_compliant
= ClsCompliantAttribute
.GetClsCompliantAttributeValue ();
1018 Attribute a
= ResolveAttribute (PredefinedAttributes
.Get
.RuntimeCompatibility
);
1020 var val
= a
.GetPropertyValue ("WrapNonExceptionThrows") as BoolConstant
;
1022 wrap_non_exception_throws
= val
.Value
;
1027 private void SetPublicKey (AssemblyName an
, byte[] strongNameBlob
)
1030 // check for possible ECMA key
1031 if (strongNameBlob
.Length
== 16) {
1032 // will be rejected if not "the" ECMA key
1033 an
.SetPublicKey (strongNameBlob
);
1036 // take it, with or without, a private key
1037 RSA rsa
= CryptoConvert
.FromCapiKeyBlob (strongNameBlob
);
1038 // and make sure we only feed the public part to Sys.Ref
1039 byte[] publickey
= CryptoConvert
.ToCapiPublicKeyBlob (rsa
);
1041 // AssemblyName.SetPublicKey requires an additional header
1042 byte[] publicKeyHeader
= new byte [12] { 0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00 }
;
1044 byte[] encodedPublicKey
= new byte [12 + publickey
.Length
];
1045 Buffer
.BlockCopy (publicKeyHeader
, 0, encodedPublicKey
, 0, 12);
1046 Buffer
.BlockCopy (publickey
, 0, encodedPublicKey
, 12, publickey
.Length
);
1047 an
.SetPublicKey (encodedPublicKey
);
1051 Error_AssemblySigning ("The specified file `" + RootContext
.StrongNameKeyFile
+ "' is incorrectly encoded");
1052 Environment
.Exit (1);
1056 // TODO: rewrite this code (to kill N bugs and make it faster) and use standard ApplyAttribute way.
1057 public AssemblyName
GetAssemblyName (string name
, string output
)
1059 if (OptAttributes
!= null) {
1060 foreach (Attribute a
in OptAttributes
.Attrs
) {
1061 // cannot rely on any resolve-based members before you call Resolve
1062 if (a
.ExplicitTarget
== null || a
.ExplicitTarget
!= "assembly")
1065 // TODO: This code is buggy: comparing Attribute name without resolving is wrong.
1066 // However, this is invoked by CodeGen.Init, when none of the namespaces
1068 // TODO: Does not handle quoted attributes properly
1070 case "AssemblyKeyFile":
1071 case "AssemblyKeyFileAttribute":
1072 case "System.Reflection.AssemblyKeyFileAttribute":
1073 if (RootContext
.StrongNameKeyFile
!= null) {
1074 Report
.SymbolRelatedToPreviousError (a
.Location
, a
.GetSignatureForError ());
1075 Report
.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1076 "keyfile", "System.Reflection.AssemblyKeyFileAttribute");
1078 string value = a
.GetString ();
1079 if (value != null && value.Length
!= 0)
1080 RootContext
.StrongNameKeyFile
= value;
1083 case "AssemblyKeyName":
1084 case "AssemblyKeyNameAttribute":
1085 case "System.Reflection.AssemblyKeyNameAttribute":
1086 if (RootContext
.StrongNameKeyContainer
!= null) {
1087 Report
.SymbolRelatedToPreviousError (a
.Location
, a
.GetSignatureForError ());
1088 Report
.Warning (1616, 1, "Option `{0}' overrides attribute `{1}' given in a source file or added module",
1089 "keycontainer", "System.Reflection.AssemblyKeyNameAttribute");
1091 string value = a
.GetString ();
1092 if (value != null && value.Length
!= 0)
1093 RootContext
.StrongNameKeyContainer
= value;
1096 case "AssemblyDelaySign":
1097 case "AssemblyDelaySignAttribute":
1098 case "System.Reflection.AssemblyDelaySignAttribute":
1099 RootContext
.StrongNameDelaySign
= a
.GetBoolean ();
1105 AssemblyName an
= new AssemblyName ();
1106 an
.Name
= Path
.GetFileNameWithoutExtension (name
);
1108 // note: delay doesn't apply when using a key container
1109 if (RootContext
.StrongNameKeyContainer
!= null) {
1110 an
.KeyPair
= new StrongNameKeyPair (RootContext
.StrongNameKeyContainer
);
1114 // strongname is optional
1115 if (RootContext
.StrongNameKeyFile
== null)
1118 string AssemblyDir
= Path
.GetDirectoryName (output
);
1120 // the StrongName key file may be relative to (a) the compiled
1121 // file or (b) to the output assembly. See bugzilla #55320
1122 // http://bugzilla.ximian.com/show_bug.cgi?id=55320
1124 // (a) relative to the compiled file
1125 string filename
= Path
.GetFullPath (RootContext
.StrongNameKeyFile
);
1126 bool exist
= File
.Exists (filename
);
1127 if ((!exist
) && (AssemblyDir
!= null) && (AssemblyDir
!= String
.Empty
)) {
1128 // (b) relative to the outputed assembly
1129 filename
= Path
.GetFullPath (Path
.Combine (AssemblyDir
, RootContext
.StrongNameKeyFile
));
1130 exist
= File
.Exists (filename
);
1134 using (FileStream fs
= new FileStream (filename
, FileMode
.Open
, FileAccess
.Read
)) {
1135 byte[] snkeypair
= new byte [fs
.Length
];
1136 fs
.Read (snkeypair
, 0, snkeypair
.Length
);
1138 if (RootContext
.StrongNameDelaySign
) {
1139 // delayed signing - DO NOT include private key
1140 SetPublicKey (an
, snkeypair
);
1143 // no delay so we make sure we have the private key
1145 CryptoConvert
.FromCapiPrivateKeyBlob (snkeypair
);
1146 an
.KeyPair
= new StrongNameKeyPair (snkeypair
);
1148 catch (CryptographicException
) {
1149 if (snkeypair
.Length
== 16) {
1150 // error # is different for ECMA key
1151 Report
.Error (1606, "Could not sign the assembly. " +
1152 "ECMA key can only be used to delay-sign assemblies");
1155 Error_AssemblySigning ("The specified file `" + RootContext
.StrongNameKeyFile
+ "' does not have a private key");
1163 Error_AssemblySigning ("The specified file `" + RootContext
.StrongNameKeyFile
+ "' does not exist");
1169 void Error_AssemblySigning (string text
)
1171 Report
.Error (1548, "Error during assembly signing. " + text
);
1174 bool CheckInternalsVisibleAttribute (Attribute a
)
1176 string assembly_name
= a
.GetString ();
1177 if (assembly_name
.Length
== 0)
1180 AssemblyName aname
= null;
1182 aname
= new AssemblyName (assembly_name
);
1183 } catch (FileLoadException
) {
1184 } catch (ArgumentException
) {
1187 // Bad assembly name format
1189 Report
.Warning (1700, 3, a
.Location
, "Assembly reference `" + assembly_name
+ "' is invalid and cannot be resolved");
1190 // Report error if we have defined Version or Culture
1191 else if (aname
.Version
!= null || aname
.CultureInfo
!= null)
1192 throw new Exception ("Friend assembly `" + a
.GetString () +
1193 "' is invalid. InternalsVisibleTo cannot have version or culture specified.");
1194 else if (aname
.GetPublicKey () == null && Name
.GetPublicKey () != null && Name
.GetPublicKey ().Length
!= 0) {
1195 Report
.Error (1726, a
.Location
, "Friend assembly reference `" + aname
.FullName
+ "' is invalid." +
1196 " Strong named assemblies must specify a public key in their InternalsVisibleTo declarations");
1203 static string IsValidAssemblyVersion (string version
)
1207 v
= new Version (version
);
1210 int major
= int.Parse (version
, CultureInfo
.InvariantCulture
);
1211 v
= new Version (major
, 0);
1217 foreach (int candidate
in new int [] { v.Major, v.Minor, v.Build, v.Revision }
) {
1218 if (candidate
> ushort.MaxValue
)
1222 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);
1225 public override void ApplyAttributeBuilder (Attribute a
, MethodSpec ctor
, byte[] cdata
, PredefinedAttributes pa
)
1227 if (a
.IsValidSecurityAttribute ()) {
1228 if (declarative_security
== null)
1229 declarative_security
= new Dictionary
<SecurityAction
, PermissionSet
> ();
1231 a
.ExtractSecurityPermissionSet (declarative_security
);
1235 if (a
.Type
== pa
.AssemblyCulture
) {
1236 string value = a
.GetString ();
1237 if (value == null || value.Length
== 0)
1240 if (RootContext
.Target
== Target
.Exe
) {
1241 a
.Error_AttributeEmitError ("The executables cannot be satelite assemblies, remove the attribute or keep it empty");
1246 var fi
= typeof (AssemblyBuilder
).GetField ("culture", BindingFlags
.Instance
| BindingFlags
.NonPublic
| BindingFlags
.SetField
);
1247 fi
.SetValue (CodeGen
.Assembly
.Builder
, value == "neutral" ? "" : value);
1249 Report
.RuntimeMissingSupport (a
.Location
, "AssemblyCultureAttribute setting");
1255 if (a
.Type
== pa
.AssemblyVersion
) {
1256 string value = a
.GetString ();
1257 if (value == null || value.Length
== 0)
1260 var vinfo
= IsValidAssemblyVersion (value.Replace ('*', '0'));
1261 if (vinfo
== null) {
1262 a
.Error_AttributeEmitError (string.Format ("Specified version `{0}' is not valid", value));
1267 var fi
= typeof (AssemblyBuilder
).GetField ("version", BindingFlags
.Instance
| BindingFlags
.NonPublic
| BindingFlags
.SetField
);
1268 fi
.SetValue (CodeGen
.Assembly
.Builder
, vinfo
);
1270 Report
.RuntimeMissingSupport (a
.Location
, "AssemblyVersionAttribute setting");
1276 if (a
.Type
== pa
.AssemblyAlgorithmId
) {
1277 const int pos
= 2; // skip CA header
1278 uint alg
= (uint) cdata
[pos
];
1279 alg
|= ((uint) cdata
[pos
+ 1]) << 8;
1280 alg
|= ((uint) cdata
[pos
+ 2]) << 16;
1281 alg
|= ((uint) cdata
[pos
+ 3]) << 24;
1284 var fi
= typeof (AssemblyBuilder
).GetField ("algid", BindingFlags
.Instance
| BindingFlags
.NonPublic
| BindingFlags
.SetField
);
1285 fi
.SetValue (CodeGen
.Assembly
.Builder
, alg
);
1287 Report
.RuntimeMissingSupport (a
.Location
, "AssemblyAlgorithmIdAttribute setting");
1293 if (a
.Type
== pa
.AssemblyFlags
) {
1294 const int pos
= 2; // skip CA header
1295 uint flags
= (uint) cdata
[pos
];
1296 flags
|= ((uint) cdata
[pos
+ 1]) << 8;
1297 flags
|= ((uint) cdata
[pos
+ 2]) << 16;
1298 flags
|= ((uint) cdata
[pos
+ 3]) << 24;
1300 // Ignore set PublicKey flag if assembly is not strongnamed
1301 if ((flags
& (uint) AssemblyNameFlags
.PublicKey
) != 0 && (CodeGen
.Assembly
.Builder
.GetName ().KeyPair
== null))
1302 flags
&= ~
(uint)AssemblyNameFlags
.PublicKey
;
1305 var fi
= typeof (AssemblyBuilder
).GetField ("flags", BindingFlags
.Instance
| BindingFlags
.NonPublic
| BindingFlags
.SetField
);
1306 fi
.SetValue (CodeGen
.Assembly
.Builder
, flags
);
1308 Report
.RuntimeMissingSupport (a
.Location
, "AssemblyFlagsAttribute setting");
1314 if (a
.Type
== pa
.InternalsVisibleTo
&& !CheckInternalsVisibleAttribute (a
))
1317 if (a
.Type
== pa
.TypeForwarder
) {
1318 TypeSpec t
= a
.GetArgumentType ();
1319 if (t
== null || TypeManager
.HasElementType (t
)) {
1320 Report
.Error (735, a
.Location
, "Invalid type specified as an argument for TypeForwardedTo attribute");
1324 if (emitted_forwarders
== null) {
1325 emitted_forwarders
= new Dictionary
<ITypeDefinition
, Attribute
> ();
1326 } else if (emitted_forwarders
.ContainsKey (t
.MemberDefinition
)) {
1327 Report
.SymbolRelatedToPreviousError(emitted_forwarders
[t
.MemberDefinition
].Location
, null);
1328 Report
.Error(739, a
.Location
, "A duplicate type forward of type `{0}'",
1329 TypeManager
.CSharpName(t
));
1333 emitted_forwarders
.Add(t
.MemberDefinition
, a
);
1335 if (t
.Assembly
== Builder
) {
1336 Report
.SymbolRelatedToPreviousError (t
);
1337 Report
.Error (729, a
.Location
, "Cannot forward type `{0}' because it is defined in this assembly",
1338 TypeManager
.CSharpName (t
));
1343 Report
.Error (730, a
.Location
, "Cannot forward type `{0}' because it is a nested type",
1344 TypeManager
.CSharpName (t
));
1348 if (add_type_forwarder
== null) {
1349 add_type_forwarder
= typeof (AssemblyBuilder
).GetMethod ("AddTypeForwarder",
1350 BindingFlags
.NonPublic
| BindingFlags
.Instance
);
1352 if (add_type_forwarder
== null) {
1353 Report
.RuntimeMissingSupport (a
.Location
, "TypeForwardedTo attribute");
1358 add_type_forwarder
.Invoke (Builder
, new object[] { t.GetMetaInfo () }
);
1362 if (a
.Type
== pa
.Extension
) {
1363 a
.Error_MisusedExtensionAttribute ();
1367 Builder
.SetCustomAttribute ((ConstructorInfo
) ctor
.GetMetaInfo (), cdata
);
1370 public override void Emit (TypeContainer tc
)
1374 if (has_extension_method
)
1375 PredefinedAttributes
.Get
.Extension
.EmitAttribute (Builder
);
1377 // FIXME: Does this belong inside SRE.AssemblyBuilder instead?
1378 PredefinedAttribute pa
= PredefinedAttributes
.Get
.RuntimeCompatibility
;
1379 if (pa
.IsDefined
&& (OptAttributes
== null || !OptAttributes
.Contains (pa
))) {
1380 var ci
= TypeManager
.GetPredefinedConstructor (pa
.Type
, Location
.Null
, TypeSpec
.EmptyTypes
);
1381 PropertyInfo
[] pis
= new PropertyInfo
[1];
1382 pis
[0] = TypeManager
.GetPredefinedProperty (pa
.Type
,
1383 "WrapNonExceptionThrows", Location
.Null
, TypeManager
.bool_type
).MetaInfo
;
1384 object [] pargs
= new object [1];
1386 Builder
.SetCustomAttribute (new CustomAttributeBuilder ((ConstructorInfo
) ci
.GetMetaInfo (), new object[0], pis
, pargs
));
1389 if (declarative_security
!= null) {
1391 MethodInfo add_permission
= typeof (AssemblyBuilder
).GetMethod ("AddPermissionRequests", BindingFlags
.Instance
| BindingFlags
.NonPublic
);
1392 object builder_instance
= Builder
;
1395 // Microsoft runtime hacking
1396 if (add_permission
== null) {
1397 var assembly_builder
= typeof (AssemblyBuilder
).Assembly
.GetType ("System.Reflection.Emit.AssemblyBuilderData");
1398 add_permission
= assembly_builder
.GetMethod ("AddPermissionRequests", BindingFlags
.Instance
| BindingFlags
.NonPublic
);
1400 FieldInfo fi
= typeof (AssemblyBuilder
).GetField ("m_assemblyData", BindingFlags
.Instance
| BindingFlags
.NonPublic
| BindingFlags
.GetField
);
1401 builder_instance
= fi
.GetValue (Builder
);
1404 var args
= new PermissionSet
[3];
1405 declarative_security
.TryGetValue (SecurityAction
.RequestMinimum
, out args
[0]);
1406 declarative_security
.TryGetValue (SecurityAction
.RequestOptional
, out args
[1]);
1407 declarative_security
.TryGetValue (SecurityAction
.RequestRefuse
, out args
[2]);
1408 add_permission
.Invoke (builder_instance
, args
);
1411 Report
.RuntimeMissingSupport (Location
.Null
, "assembly permission setting");
1416 public override string[] ValidAttributeTargets
{
1418 return attribute_targets
;
1422 // Wrapper for AssemblyBuilder.AddModule
1423 static MethodInfo adder_method
;
1424 static public MethodInfo AddModule_Method
{
1426 if (adder_method
== null)
1427 adder_method
= typeof (AssemblyBuilder
).GetMethod ("AddModule", BindingFlags
.Instance
|BindingFlags
.NonPublic
);
1428 return adder_method
;
1431 public Module
AddModule (string module
)
1433 MethodInfo m
= AddModule_Method
;
1435 Report
.RuntimeMissingSupport (Location
.Null
, "/addmodule");
1436 Environment
.Exit (1);
1440 return (Module
) m
.Invoke (Builder
, new object [] { module }
);
1441 } catch (TargetInvocationException ex
) {
1442 throw ex
.InnerException
;