2 // roottypes.cs: keeps a tree representation of the generated code
4 // Authors: Miguel de Icaza (miguel@gnu.org)
5 // Marek Safar (marek.safar@gmail.com)
7 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 // Copyright 2003-2008 Novell, Inc.
14 using System.Collections.Generic;
15 using System.Runtime.InteropServices;
16 using Mono.CompilerServices.SymbolWriter;
19 using IKVM.Reflection;
20 using IKVM.Reflection.Emit;
22 using System.Reflection;
23 using System.Reflection.Emit;
29 // Module (top-level type) container
31 public class ModuleContainer : TypeContainer
34 // Compiler generated container for static data
36 sealed class StaticDataContainer : CompilerGeneratedClass
38 Dictionary<int, Struct> size_types;
41 static MethodInfo set_data;
44 public StaticDataContainer (ModuleContainer module)
45 : base (module, new MemberName ("<PrivateImplementationDetails>" + module.builder.ModuleVersionId.ToString ("B"), Location.Null), Modifiers.STATIC)
47 size_types = new Dictionary<int, Struct> ();
50 public override void CloseType ()
54 foreach (var entry in size_types) {
55 entry.Value.CloseType ();
59 public FieldSpec DefineInitializedData (byte[] data, Location loc)
62 if (!size_types.TryGetValue (data.Length, out size_type)) {
64 // Build common type for this data length. We cannot use
65 // DefineInitializedData because it creates public type,
66 // and its name is not unique among modules
68 size_type = new Struct (null, this, new MemberName ("$ArrayType=" + data.Length, Location), Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED, null);
69 size_type.CreateType ();
70 size_type.DefineType ();
72 size_types.Add (data.Length, size_type);
74 var pa = Module.PredefinedAttributes.StructLayout;
75 if (pa.Constructor != null || pa.ResolveConstructor (Location, TypeManager.short_type)) {
76 var argsEncoded = new AttributeEncoder (false);
77 argsEncoded.Encode ((short) LayoutKind.Explicit);
79 var field_size = pa.GetField ("Size", TypeManager.int32_type, Location);
80 var pack = pa.GetField ("Pack", TypeManager.int32_type, Location);
81 if (field_size != null) {
82 argsEncoded.EncodeNamedArguments (
83 new[] { field_size, pack },
84 new[] { new IntConstant ((int) data.Length, Location), new IntConstant (1, Location) }
88 pa.EmitAttribute (size_type.TypeBuilder, argsEncoded);
92 var name = "$field-" + fields.ToString ("X");
94 const Modifiers fmod = Modifiers.STATIC | Modifiers.INTERNAL;
95 var fbuilder = TypeBuilder.DefineField (name, size_type.CurrentType.GetMetaInfo (), ModifiersExtensions.FieldAttr (fmod) | FieldAttributes.HasFieldRVA);
97 fbuilder.__SetDataAndRVA (data);
100 set_data = typeof (FieldBuilder).GetMethod ("SetRVAData", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
103 set_data.Invoke (fbuilder, new object[] { data });
105 Report.RuntimeMissingSupport (loc, "SetRVAData");
109 return new FieldSpec (CurrentType, null, size_type.CurrentType, fbuilder, fmod);
113 public CharSet DefaultCharSet = CharSet.Ansi;
114 public TypeAttributes DefaultCharSetType = TypeAttributes.AnsiClass;
116 Dictionary<int, List<AnonymousTypeClass>> anonymous_types;
117 StaticDataContainer static_data;
119 AssemblyDefinition assembly;
120 readonly CompilerContext context;
121 readonly RootNamespace global_ns;
122 Dictionary<string, RootNamespace> alias_ns;
124 ModuleBuilder builder;
127 public List<Enum> hack_corlib_enums = new List<Enum> ();
129 bool has_default_charset;
130 bool has_extenstion_method;
132 PredefinedAttributes predefined_attributes;
133 PredefinedTypes predefined_types;
135 static readonly string[] attribute_targets = new string[] { "assembly", "module" };
137 public ModuleContainer (CompilerContext context)
138 : base (null, null, MemberName.Null, null, 0)
140 this.context = context;
142 caching_flags &= ~(Flags.Obsolete_Undetected | Flags.Excluded_Undetected);
144 types = new List<TypeContainer> ();
145 anonymous_types = new Dictionary<int, List<AnonymousTypeClass>> ();
146 global_ns = new GlobalRootNamespace ();
147 alias_ns = new Dictionary<string, RootNamespace> ();
152 public override AttributeTargets AttributeTargets {
154 return AttributeTargets.Assembly;
158 public ModuleBuilder Builder {
164 public override CompilerContext Compiler {
170 public override AssemblyDefinition DeclaringAssembly {
176 public bool HasDefaultCharSet {
178 return has_default_charset;
182 public bool HasExtensionMethod {
184 return has_extenstion_method;
187 has_extenstion_method = value;
192 // Returns module global:: namespace
194 public RootNamespace GlobalRootNamespace {
200 public override ModuleContainer Module {
206 internal PredefinedAttributes PredefinedAttributes {
208 return predefined_attributes;
212 internal PredefinedTypes PredefinedTypes {
214 return predefined_types;
218 public override string[] ValidAttributeTargets {
220 return attribute_targets;
226 public void AddAnonymousType (AnonymousTypeClass type)
228 List<AnonymousTypeClass> existing;
229 if (!anonymous_types.TryGetValue (type.Parameters.Count, out existing))
230 if (existing == null) {
231 existing = new List<AnonymousTypeClass> ();
232 anonymous_types.Add (type.Parameters.Count, existing);
238 public void AddAttributes (List<Attribute> attrs)
240 AddAttributes (attrs, this);
243 public void AddAttributes (List<Attribute> attrs, IMemberContext context)
245 foreach (Attribute a in attrs)
246 a.AttachTo (this, context);
248 if (attributes == null) {
249 attributes = new Attributes (attrs);
252 attributes.AddAttributes (attrs);
255 public override TypeContainer AddPartial (TypeContainer nextPart)
257 return AddPartial (nextPart, nextPart.Name);
260 public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
262 if (a.Target == AttributeTargets.Assembly) {
263 assembly.ApplyAttributeBuilder (a, ctor, cdata, pa);
267 if (a.Type == pa.CLSCompliant) {
268 Attribute cls = DeclaringAssembly.CLSCompliantAttribute;
270 Report.Warning (3012, 1, a.Location,
271 "You must specify the CLSCompliant attribute on the assembly, not the module, to enable CLS compliance checking");
272 } else if (DeclaringAssembly.IsCLSCompliant != a.GetBoolean ()) {
273 Report.SymbolRelatedToPreviousError (cls.Location, cls.GetSignatureForError ());
274 Report.Warning (3017, 1, a.Location,
275 "You cannot specify the CLSCompliant attribute on a module that differs from the CLSCompliant attribute on the assembly");
280 builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
283 public override void CloseType ()
287 foreach (TypeContainer tc in types) {
291 if (compiler_generated != null)
292 foreach (CompilerGeneratedClass c in compiler_generated)
296 public TypeBuilder CreateBuilder (string name, TypeAttributes attr, int typeSize)
298 return builder.DefineType (name, attr, null, typeSize);
302 // Creates alias global namespace
304 public RootNamespace CreateRootNamespace (string alias)
306 if (alias == global_ns.Alias) {
307 NamespaceEntry.Error_GlobalNamespaceRedefined (Location.Null, Report);
312 if (!alias_ns.TryGetValue (alias, out rn)) {
313 rn = new RootNamespace (alias);
314 alias_ns.Add (alias, rn);
320 public new void Define ()
322 builder = assembly.CreateModuleBuilder ();
324 // FIXME: Temporary hack for repl to reset
327 // TODO: It should be done much later when the types are resolved
328 // but that require DefineType clean-up
329 ResolveGlobalAttributes ();
331 foreach (TypeContainer tc in types)
334 InitializePredefinedTypes ();
336 foreach (TypeContainer tc in types)
339 foreach (TypeContainer tc in types)
340 tc.ResolveTypeParameters ();
342 foreach (TypeContainer tc in types) {
345 } catch (Exception e) {
346 throw new InternalErrorException (tc, e);
351 public override void Emit ()
353 if (OptAttributes != null)
354 OptAttributes.Emit ();
356 if (RootContext.Unsafe) {
357 var pa = PredefinedAttributes.UnverifiableCode;
359 pa.EmitAttribute (builder);
362 foreach (var tc in types)
363 tc.DefineConstants ();
367 foreach (TypeContainer tc in types)
370 if (Compiler.Report.Errors > 0)
373 foreach (TypeContainer tc in types)
376 if (compiler_generated != null)
377 foreach (var c in compiler_generated)
381 public AnonymousTypeClass GetAnonymousType (IList<AnonymousTypeParameter> parameters)
383 List<AnonymousTypeClass> candidates;
384 if (!anonymous_types.TryGetValue (parameters.Count, out candidates))
388 foreach (AnonymousTypeClass at in candidates) {
389 for (i = 0; i < parameters.Count; ++i) {
390 if (!parameters [i].Equals (at.Parameters [i]))
394 if (i == parameters.Count)
401 public RootNamespace GetRootNamespace (string name)
404 alias_ns.TryGetValue (name, out rn);
408 public override string GetSignatureForError ()
416 if (RootContext.StdLib)
420 // HACK: When building corlib mcs uses loaded mscorlib which
421 // has different predefined types and this method sets mscorlib types
422 // to be same to avoid type check errors in CreateType.
424 var type = typeof (Type);
425 var system_4_type_arg = new[] { type, type, type, type };
427 MethodInfo set_corlib_type_builders =
428 typeof (System.Reflection.Emit.AssemblyBuilder).GetMethod (
429 "SetCorlibTypeBuilders", BindingFlags.NonPublic | BindingFlags.Instance, null,
430 system_4_type_arg, null);
432 if (set_corlib_type_builders == null) {
433 Compiler.Report.Warning (-26, 3,
434 "The compilation may fail due to missing `System.Reflection.Emit.AssemblyBuilder.SetCorlibTypeBuilders(...)' method");
438 object[] args = new object[4];
439 args[0] = TypeManager.object_type.GetMetaInfo ();
440 args[1] = TypeManager.value_type.GetMetaInfo ();
441 args[2] = TypeManager.enum_type.GetMetaInfo ();
442 args[3] = TypeManager.void_type.GetMetaInfo ();
443 set_corlib_type_builders.Invoke (assembly.Builder, args);
447 void HackCorlibEnums ()
449 if (RootContext.StdLib)
452 // Another Mono corlib HACK
453 // mono_class_layout_fields requires to have enums created
454 // before creating a class which used the enum for any of its fields
455 foreach (var e in hack_corlib_enums)
459 public void InitializePredefinedTypes ()
461 predefined_attributes = new PredefinedAttributes (this);
462 predefined_types = new PredefinedTypes (this);
465 public override bool IsClsComplianceRequired ()
467 return DeclaringAssembly.IsCLSCompliant;
471 // Makes const data field inside internal type container
473 public FieldSpec MakeStaticData (byte[] data, Location loc)
475 if (static_data == null) {
476 static_data = new StaticDataContainer (this);
477 static_data.CreateType ();
478 static_data.DefineType ();
480 AddCompilerGeneratedClass (static_data);
483 return static_data.DefineInitializedData (data, loc);
486 protected override bool AddMemberType (TypeContainer ds)
488 if (!AddToContainer (ds, ds.Name))
490 ds.NamespaceEntry.NS.AddType (ds.Definition);
494 protected override void RemoveMemberType (DeclSpace ds)
496 ds.NamespaceEntry.NS.RemoveDeclSpace (ds.Basename);
497 base.RemoveMemberType (ds);
501 /// It is called very early therefore can resolve only predefined attributes
503 void ResolveGlobalAttributes ()
505 if (OptAttributes == null)
508 if (!OptAttributes.CheckTargets ())
511 // FIXME: Define is wrong as the type may not exist yet
512 var DefaultCharSet_attr = new PredefinedAttribute (this, "System.Runtime.InteropServices", "DefaultCharSetAttribute");
513 DefaultCharSet_attr.Define ();
514 Attribute a = ResolveModuleAttribute (DefaultCharSet_attr);
516 has_default_charset = true;
517 DefaultCharSet = a.GetCharSetValue ();
518 switch (DefaultCharSet) {
523 DefaultCharSetType = TypeAttributes.AutoClass;
525 case CharSet.Unicode:
526 DefaultCharSetType = TypeAttributes.UnicodeClass;
529 Report.Error (1724, a.Location, "Value specified for the argument to `{0}' is not valid",
530 DefaultCharSet_attr.GetSignatureForError ());
536 public Attribute ResolveAssemblyAttribute (PredefinedAttribute a_type)
538 Attribute a = OptAttributes.Search ("assembly", a_type);
545 Attribute ResolveModuleAttribute (PredefinedAttribute a_type)
547 Attribute a = OptAttributes.Search ("module", a_type);
554 public void SetDeclaringAssembly (AssemblyDefinition assembly)
556 // TODO: This setter is quite ugly but I have not found a way around it yet
557 this.assembly = assembly;
561 class RootDeclSpace : TypeContainer {
562 public RootDeclSpace (NamespaceEntry ns)
563 : base (ns, null, MemberName.Null, null, 0)
565 PartialContainer = RootContext.ToplevelTypes;
568 public override AttributeTargets AttributeTargets {
569 get { throw new InternalErrorException ("should not be called"); }
572 public override CompilerContext Compiler {
574 return PartialContainer.Compiler;
578 public override string DocCommentHeader {
579 get { throw new InternalErrorException ("should not be called"); }
582 public override void DefineType ()
584 throw new InternalErrorException ("should not be called");
587 public override ModuleContainer Module {
589 return PartialContainer.Module;
593 public override bool IsClsComplianceRequired ()
595 return PartialContainer.IsClsComplianceRequired ();
598 public override FullNamedExpression LookupNamespaceAlias (string name)
600 return NamespaceEntry.LookupNamespaceAlias (name);