2 Copyright (C) 2008-2010 Jeroen Frijters
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
25 using System.Collections.Generic;
27 using System.Diagnostics;
28 using System.Diagnostics.SymbolStore;
29 using System.Security.Cryptography;
30 using System.Runtime.CompilerServices;
31 using System.Runtime.InteropServices;
32 using IKVM.Reflection.Impl;
33 using IKVM.Reflection.Metadata;
34 using IKVM.Reflection.Writer;
36 namespace IKVM.Reflection.Emit
38 public sealed class ModuleBuilder : Module, ITypeOwner
40 private static readonly bool usePublicKeyAssemblyReference = false;
41 private readonly Guid mvid = Guid.NewGuid();
42 private long imageBaseAddress = 0x00400000;
43 private readonly AssemblyBuilder asm;
44 internal readonly string moduleName;
45 internal readonly string fileName;
46 internal readonly ISymbolWriterImpl symbolWriter;
47 private readonly TypeBuilder moduleType;
48 private readonly List<TypeBuilder> types = new List<TypeBuilder>();
49 private readonly Dictionary<Type, int> typeTokens = new Dictionary<Type, int>();
50 private readonly Dictionary<Type, int> memberRefTypeTokens = new Dictionary<Type, int>();
51 private readonly Dictionary<string, TypeBuilder> fullNameToType = new Dictionary<string, TypeBuilder>();
52 internal readonly ByteBuffer methodBodies = new ByteBuffer(128 * 1024);
53 internal readonly List<int> tokenFixupOffsets = new List<int>();
54 internal readonly ByteBuffer initializedData = new ByteBuffer(512);
55 internal readonly ByteBuffer manifestResources = new ByteBuffer(512);
56 internal ResourceSection unmanagedResources;
57 private readonly Dictionary<MemberInfo, int> importedMembers = new Dictionary<MemberInfo, int>();
58 private readonly Dictionary<MemberRefKey, int> importedMemberRefs = new Dictionary<MemberRefKey, int>();
59 private readonly Dictionary<Assembly, int> referencedAssemblies = new Dictionary<Assembly, int>();
60 private List<AssemblyName> referencedAssemblyNames;
61 private int nextPseudoToken = -1;
62 private readonly List<int> resolvedTokens = new List<int>();
63 internal readonly TableHeap Tables = new TableHeap();
64 internal readonly StringHeap Strings = new StringHeap();
65 internal readonly UserStringHeap UserStrings = new UserStringHeap();
66 internal readonly GuidHeap Guids = new GuidHeap();
67 internal readonly BlobHeap Blobs = new BlobHeap();
69 struct MemberRefKey : IEquatable<MemberRefKey>
71 private readonly Type type;
72 private readonly string name;
73 private readonly Signature signature;
75 internal MemberRefKey(Type type, string name, Signature signature)
79 this.signature = signature;
82 public bool Equals(MemberRefKey other)
84 return other.type.Equals(type)
86 && other.signature.Equals(signature);
89 public override bool Equals(object obj)
91 MemberRefKey? other = obj as MemberRefKey?;
92 return other != null && Equals(other);
95 public override int GetHashCode()
97 return type.GetHashCode() + name.GetHashCode() + signature.GetHashCode();
101 internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, bool emitSymbolInfo)
105 this.moduleName = moduleName;
106 this.fileName = fileName;
109 symbolWriter = SymbolSupport.CreateSymbolWriterFor(this);
111 // <Module> must be the first record in the TypeDef table
112 moduleType = new TypeBuilder(this, "<Module>", null, 0);
113 types.Add(moduleType);
116 internal void PopulatePropertyAndEventTables()
118 // LAMESPEC the PropertyMap and EventMap tables are not required to be sorted by the CLI spec,
119 // but .NET sorts them and Mono requires them to be sorted, so we have to populate the
120 // tables in the right order
121 foreach (TypeBuilder type in types)
123 type.PopulatePropertyAndEventTables();
127 internal void WriteTypeDefTable(MetadataWriter mw)
131 foreach (TypeBuilder type in types)
133 type.WriteTypeDefRecord(mw, ref fieldList, ref methodList);
137 internal void WriteMethodDefTable(int baseRVA, MetadataWriter mw)
140 foreach (TypeBuilder type in types)
142 type.WriteMethodDefRecords(baseRVA, mw, ref paramList);
146 internal void WriteParamTable(MetadataWriter mw)
148 foreach (TypeBuilder type in types)
150 type.WriteParamRecords(mw);
154 internal void WriteFieldTable(MetadataWriter mw)
156 foreach (TypeBuilder type in types)
158 type.WriteFieldRecords(mw);
162 internal int AllocPseudoToken()
164 return nextPseudoToken--;
167 public TypeBuilder DefineType(string name)
169 return DefineType(name, TypeAttributes.Class);
172 public TypeBuilder DefineType(string name, TypeAttributes attr)
174 return DefineType(name, attr, null);
177 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent)
179 return DefineType(name, attr, parent, PackingSize.Unspecified, 0);
182 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, int typesize)
184 return DefineType(name, attr, parent, PackingSize.Unspecified, typesize);
187 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, PackingSize packsize)
189 return DefineType(name, attr, parent, packsize, 0);
192 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, Type[] interfaces)
194 TypeBuilder tb = DefineType(name, attr, parent);
195 foreach (Type iface in interfaces)
197 tb.AddInterfaceImplementation(iface);
202 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, PackingSize packingSize, int typesize)
204 if (parent == null && (attr & TypeAttributes.Interface) == 0)
206 parent = universe.System_Object;
208 TypeBuilder typeBuilder = new TypeBuilder(this, name, parent, attr);
209 PostDefineType(typeBuilder, packingSize, typesize);
213 public EnumBuilder DefineEnum(string name, TypeAttributes visibility, Type underlyingType)
215 TypeBuilder tb = DefineType(name, (visibility & TypeAttributes.VisibilityMask) | TypeAttributes.Sealed, universe.System_Enum);
216 FieldBuilder fb = tb.DefineField("value__", underlyingType, FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
217 return new EnumBuilder(tb, fb);
220 internal TypeBuilder DefineNestedTypeHelper(TypeBuilder enclosingType, string name, TypeAttributes attr, Type parent, PackingSize packingSize, int typesize)
222 if (parent == null && (attr & TypeAttributes.Interface) == 0)
224 parent = universe.System_Object;
226 TypeBuilder typeBuilder = new TypeBuilder(enclosingType, name, parent, attr);
227 PostDefineType(typeBuilder, packingSize, typesize);
228 if (enclosingType != null)
230 NestedClassTable.Record rec = new NestedClassTable.Record();
231 rec.NestedClass = typeBuilder.MetadataToken;
232 rec.EnclosingClass = enclosingType.MetadataToken;
233 this.NestedClass.AddRecord(rec);
238 private void PostDefineType(TypeBuilder typeBuilder, PackingSize packingSize, int typesize)
240 types.Add(typeBuilder);
241 fullNameToType.Add(typeBuilder.FullName, typeBuilder);
242 if (packingSize != PackingSize.Unspecified || typesize != 0)
244 ClassLayoutTable.Record rec = new ClassLayoutTable.Record();
245 rec.PackingSize = (short)packingSize;
246 rec.ClassSize = typesize;
247 rec.Parent = typeBuilder.MetadataToken;
248 this.ClassLayout.AddRecord(rec);
252 public FieldBuilder __DefineField(string name, Type type, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers, FieldAttributes attributes)
254 return moduleType.DefineField(name, type, requiredCustomModifiers, optionalCustomModifiers, attributes);
257 public ConstructorBuilder __DefineModuleInitializer(MethodAttributes visibility)
259 return moduleType.DefineConstructor(visibility | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, Type.EmptyTypes);
262 public FieldBuilder DefineUninitializedData(string name, int size, FieldAttributes attributes)
264 return moduleType.DefineUninitializedData(name, size, attributes);
267 public FieldBuilder DefineInitializedData(string name, byte[] data, FieldAttributes attributes)
269 return moduleType.DefineInitializedData(name, data, attributes);
272 public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, Type returnType, Type[] parameterTypes)
274 return moduleType.DefineMethod(name, attributes, returnType, parameterTypes);
277 public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
279 return moduleType.DefineMethod(name, attributes, callingConvention, returnType, parameterTypes);
282 public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] requiredReturnTypeCustomModifiers, Type[] optionalReturnTypeCustomModifiers, Type[] parameterTypes, Type[][] requiredParameterTypeCustomModifiers, Type[][] optionalParameterTypeCustomModifiers)
284 return moduleType.DefineMethod(name, attributes, callingConvention, returnType, requiredReturnTypeCustomModifiers, optionalReturnTypeCustomModifiers, parameterTypes, requiredParameterTypeCustomModifiers, optionalParameterTypeCustomModifiers);
287 public MethodBuilder DefinePInvokeMethod(string name, string dllName, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, CallingConvention nativeCallConv, CharSet nativeCharSet)
289 return moduleType.DefinePInvokeMethod(name, dllName, attributes, callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet);
292 public MethodBuilder DefinePInvokeMethod(string name, string dllName, string entryName, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, CallingConvention nativeCallConv, CharSet nativeCharSet)
294 return moduleType.DefinePInvokeMethod(name, dllName, entryName, attributes, callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet);
297 public void CreateGlobalFunctions()
299 moduleType.CreateType();
302 internal void AddTypeForwarder(Type type)
305 foreach (Type nested in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
307 // we export all nested types (i.e. even the private ones)
308 // (this behavior is the same as the C# compiler)
309 AddTypeForwarder(nested);
313 private int ExportType(Type type)
315 ExportedTypeTable.Record rec = new ExportedTypeTable.Record();
316 rec.TypeDefId = type.MetadataToken;
317 rec.TypeName = this.Strings.Add(TypeNameParser.Unescape(type.Name));
321 rec.TypeNamespace = 0;
322 rec.Implementation = ExportType(type.DeclaringType);
326 rec.Flags = 0x00200000; // CorTypeAttr.tdForwarder
327 string ns = type.Namespace;
328 rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(TypeNameParser.Unescape(ns));
329 rec.Implementation = ImportAssemblyRef(type.Assembly);
331 return 0x27000000 | this.ExportedType.FindOrAddRecord(rec);
334 public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
336 SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
339 public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
341 SetCustomAttribute(0x00000001, customBuilder);
344 internal void SetCustomAttribute(int token, CustomAttributeBuilder customBuilder)
346 Debug.Assert(!customBuilder.IsPseudoCustomAttribute);
347 CustomAttributeTable.Record rec = new CustomAttributeTable.Record();
349 rec.Type = this.GetConstructorToken(customBuilder.Constructor).Token;
350 rec.Value = customBuilder.WriteBlob(this);
351 this.CustomAttribute.AddRecord(rec);
354 internal void AddDeclarativeSecurity(int token, System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet)
356 DeclSecurityTable.Record rec = new DeclSecurityTable.Record();
357 rec.Action = (short)securityAction;
359 // like Ref.Emit, we're using the .NET 1.x xml format
360 rec.PermissionSet = this.Blobs.Add(ByteBuffer.Wrap(System.Text.Encoding.Unicode.GetBytes(permissionSet.ToXml().ToString())));
361 this.DeclSecurity.AddRecord(rec);
364 internal void AddDeclarativeSecurity(int token, List<CustomAttributeBuilder> declarativeSecurity)
366 Dictionary<int, List<CustomAttributeBuilder>> ordered = new Dictionary<int, List<CustomAttributeBuilder>>();
367 foreach (CustomAttributeBuilder cab in declarativeSecurity)
370 // check for HostProtectionAttribute without SecurityAction
371 if (cab.ConstructorArgumentCount == 0)
373 action = (int)System.Security.Permissions.SecurityAction.LinkDemand;
377 action = (int)cab.GetConstructorArgument(0);
379 List<CustomAttributeBuilder> list;
380 if (!ordered.TryGetValue(action, out list))
382 list = new List<CustomAttributeBuilder>();
383 ordered.Add(action, list);
387 foreach (KeyValuePair<int, List<CustomAttributeBuilder>> kv in ordered)
389 DeclSecurityTable.Record rec = new DeclSecurityTable.Record();
390 rec.Action = (short)kv.Key;
392 rec.PermissionSet = WriteDeclSecurityBlob(kv.Value);
393 this.DeclSecurity.AddRecord(rec);
397 private int WriteDeclSecurityBlob(List<CustomAttributeBuilder> list)
399 ByteBuffer namedArgs = new ByteBuffer(100);
400 ByteBuffer bb = new ByteBuffer(list.Count * 100);
402 bb.WriteCompressedInt(list.Count);
403 foreach (CustomAttributeBuilder cab in list)
405 bb.Write(cab.Constructor.DeclaringType.AssemblyQualifiedName);
407 cab.WriteNamedArgumentsForDeclSecurity(this, namedArgs);
408 bb.WriteCompressedInt(namedArgs.Length);
411 return this.Blobs.Add(bb);
414 public void DefineManifestResource(string name, Stream stream, ResourceAttributes attribute)
416 ManifestResourceTable.Record rec = new ManifestResourceTable.Record();
417 rec.Offset = manifestResources.Position;
418 rec.Flags = (int)attribute;
419 rec.Name = this.Strings.Add(name);
420 rec.Implementation = 0;
421 this.ManifestResource.AddRecord(rec);
422 manifestResources.Write(0); // placeholder for the length
423 manifestResources.Write(stream);
424 int savePosition = manifestResources.Position;
425 manifestResources.Position = rec.Offset;
426 manifestResources.Write(savePosition - (manifestResources.Position + 4));
427 manifestResources.Position = savePosition;
430 public override Assembly Assembly
435 internal override Type GetTypeImpl(string typeName)
438 fullNameToType.TryGetValue(typeName, out type);
442 internal override void GetTypesImpl(List<Type> list)
444 foreach (Type type in types)
446 if (type != moduleType)
453 public ISymbolDocumentWriter DefineDocument(string url, Guid language, Guid languageVendor, Guid documentType)
455 return symbolWriter.DefineDocument(url, language, languageVendor, documentType);
458 public TypeToken GetTypeToken(string name)
460 return new TypeToken(GetType(name, true, false).MetadataToken);
463 public TypeToken GetTypeToken(Type type)
465 if (type.Module == this)
467 return new TypeToken(type.GetModuleBuilderToken());
471 return new TypeToken(ImportType(type));
475 internal int GetTypeTokenForMemberRef(Type type)
477 if (type.IsGenericTypeDefinition)
480 if (!memberRefTypeTokens.TryGetValue(type, out token))
482 ByteBuffer spec = new ByteBuffer(5);
483 Signature.WriteTypeSpec(this, spec, type);
484 token = 0x1B000000 | this.TypeSpec.AddRecord(this.Blobs.Add(spec));
485 memberRefTypeTokens.Add(type, token);
489 else if (type.IsModulePseudoType)
491 return 0x1A000000 | this.ModuleRef.FindOrAddRecord(this.Strings.Add(type.Module.ScopeName));
495 return GetTypeToken(type).Token;
499 private static bool IsFromGenericTypeDefinition(MemberInfo member)
501 Type decl = member.DeclaringType;
502 return decl != null && decl.IsGenericTypeDefinition;
505 public FieldToken GetFieldToken(FieldInfo field)
507 // NOTE for some reason, when TypeBuilder.GetFieldToken() is used on a field in a generic type definition,
508 // a memberref token is returned (confirmed on .NET) unlike for Get(Method|Constructor)Token which always
509 // simply returns the MethodDef token (if the method is from the same module).
510 FieldBuilder fb = field as FieldBuilder;
511 if (fb != null && fb.Module == this && !IsFromGenericTypeDefinition(fb))
513 return new FieldToken(fb.MetadataToken);
517 return new FieldToken(ImportMember(field));
521 public MethodToken GetMethodToken(MethodInfo method)
523 MethodBuilder mb = method as MethodBuilder;
524 if (mb != null && mb.ModuleBuilder == this)
526 return new MethodToken(mb.MetadataToken);
530 return new MethodToken(ImportMember(method));
534 // when we refer to a method on a generic type definition in the IL stream,
535 // we need to use a MemberRef (even if the method is in the same module)
536 internal MethodToken GetMethodTokenForIL(MethodInfo method)
538 if (method.IsGenericMethodDefinition)
540 method = method.MakeGenericMethod(method.GetGenericArguments());
542 if (IsFromGenericTypeDefinition(method))
544 return new MethodToken(ImportMember(method));
548 return GetMethodToken(method);
552 public MethodToken GetConstructorToken(ConstructorInfo constructor)
554 if (constructor.Module == this && constructor.GetMethodInfo() is MethodBuilder)
556 return new MethodToken(constructor.MetadataToken);
560 return new MethodToken(ImportMember(constructor));
564 internal int ImportMember(MethodBase member)
567 if (!importedMembers.TryGetValue(member, out token))
569 token = member.ImportTo(this);
570 importedMembers.Add(member, token);
575 internal int ImportMember(FieldInfo member)
578 if (!importedMembers.TryGetValue(member, out token))
580 token = member.ImportTo(this);
581 importedMembers.Add(member, token);
586 internal int ImportMethodOrField(Type declaringType, string name, Signature sig)
589 if (!importedMemberRefs.TryGetValue(new MemberRefKey(declaringType, name, sig), out token))
591 MemberRefTable.Record rec = new MemberRefTable.Record();
592 rec.Class = GetTypeTokenForMemberRef(declaringType);
593 rec.Name = this.Strings.Add(name);
594 ByteBuffer bb = new ByteBuffer(16);
595 sig.WriteSig(this, bb);
596 rec.Signature = this.Blobs.Add(bb);
597 token = 0x0A000000 | this.MemberRef.AddRecord(rec);
598 importedMemberRefs.Add(new MemberRefKey(declaringType, name, sig), token);
603 internal int ImportType(Type type)
606 if (!typeTokens.TryGetValue(type, out token))
608 if (type.HasElementType || (type.IsGenericType && !type.IsGenericTypeDefinition))
610 ByteBuffer spec = new ByteBuffer(5);
611 Signature.WriteTypeSpec(this, spec, type);
612 token = 0x1B000000 | this.TypeSpec.AddRecord(this.Blobs.Add(spec));
616 TypeRefTable.Record rec = new TypeRefTable.Record();
619 rec.ResolutionScope = GetTypeToken(type.DeclaringType).Token;
620 rec.TypeName = this.Strings.Add(TypeNameParser.Unescape(type.Name));
621 rec.TypeNameSpace = 0;
625 rec.ResolutionScope = ImportAssemblyRef(type.Assembly);
626 rec.TypeName = this.Strings.Add(TypeNameParser.Unescape(type.Name));
627 string ns = type.Namespace;
628 rec.TypeNameSpace = ns == null ? 0 : this.Strings.Add(TypeNameParser.Unescape(ns));
630 token = 0x01000000 | this.TypeRef.AddRecord(rec);
632 typeTokens.Add(type, token);
637 private int ImportAssemblyRef(Assembly asm)
640 if (!referencedAssemblies.TryGetValue(asm, out token))
642 // We can't write the AssemblyRef record here yet, because the identity of the assembly can still change
643 // (if it's an AssemblyBuilder).
644 // We set the high bit of rid in the token to make sure we emit obviously broken metadata,
645 // if we forget to patch up the token somewhere.
646 token = 0x23800001 + referencedAssemblies.Count;
647 referencedAssemblies.Add(asm, token);
652 internal void FillAssemblyRefTable()
654 int[] realtokens = new int[referencedAssemblies.Count];
655 foreach (KeyValuePair<Assembly, int> kv in referencedAssemblies)
657 realtokens[(kv.Value & 0x7FFFFF) - 1] = FindOrAddAssemblyRef(kv.Key.GetName());
659 // now fixup the resolution scopes in TypeRef
660 for (int i = 0; i < this.TypeRef.records.Length; i++)
662 int resolutionScope = this.TypeRef.records[i].ResolutionScope;
663 if ((resolutionScope >> 24) == AssemblyRefTable.Index)
665 this.TypeRef.records[i].ResolutionScope = realtokens[(resolutionScope & 0x7FFFFF) - 1];
668 // and implementation in ExportedType
669 for (int i = 0; i < this.ExportedType.records.Length; i++)
671 int implementation = this.ExportedType.records[i].Implementation;
672 if ((implementation >> 24) == AssemblyRefTable.Index)
674 this.ExportedType.records[i].Implementation = realtokens[(implementation & 0x7FFFFF) - 1];
679 private int FindOrAddAssemblyRef(AssemblyName name)
681 AssemblyRefTable.Record rec = new AssemblyRefTable.Record();
682 Version ver = name.Version;
683 rec.MajorVersion = (ushort)ver.Major;
684 rec.MinorVersion = (ushort)ver.Minor;
685 rec.BuildNumber = (ushort)ver.Build;
686 rec.RevisionNumber = (ushort)ver.Revision;
687 rec.Flags = (int)(name.Flags & AssemblyNameFlags.Retargetable);
688 byte[] publicKeyOrToken = null;
689 if (usePublicKeyAssemblyReference)
691 publicKeyOrToken = name.GetPublicKey();
693 if (publicKeyOrToken == null || publicKeyOrToken.Length == 0)
695 publicKeyOrToken = name.GetPublicKeyToken();
699 const int PublicKey = 0x0001;
700 rec.Flags |= PublicKey;
702 rec.PublicKeyOrToken = this.Blobs.Add(ByteBuffer.Wrap(publicKeyOrToken));
703 rec.Name = this.Strings.Add(name.Name);
704 if (name.CultureInfo != null)
706 rec.Culture = this.Strings.Add(name.CultureInfo.Name);
713 return 0x23000000 | this.AssemblyRef.FindOrAddRecord(rec);
716 internal void WriteSymbolTokenMap()
718 for (int i = 0; i < resolvedTokens.Count; i++)
720 int newToken = resolvedTokens[i];
721 // The symbol API doesn't support remapping arbitrary integers, the types have to be the same,
722 // so we copy the type from the newToken, because our pseudo tokens don't have a type.
723 // (see MethodToken.SymbolToken)
724 int oldToken = (i + 1) | (newToken & ~0xFFFFFF);
725 SymbolSupport.RemapToken(symbolWriter, oldToken, newToken);
729 internal void RegisterTokenFixup(int pseudoToken, int realToken)
731 int index = -(pseudoToken + 1);
732 while (resolvedTokens.Count <= index)
734 resolvedTokens.Add(0);
736 resolvedTokens[index] = realToken;
739 internal bool IsPseudoToken(int token)
744 internal int ResolvePseudoToken(int pseudoToken)
746 int index = -(pseudoToken + 1);
747 return resolvedTokens[index];
750 internal void FixupMethodBodyTokens()
752 int methodToken = 0x06000001;
753 int fieldToken = 0x04000001;
754 int parameterToken = 0x08000001;
755 foreach (TypeBuilder type in types)
757 type.ResolveMethodAndFieldTokens(ref methodToken, ref fieldToken, ref parameterToken);
759 foreach (int offset in tokenFixupOffsets)
761 methodBodies.Position = offset;
762 int pseudoToken = methodBodies.GetInt32AtCurrentPosition();
763 methodBodies.Write(ResolvePseudoToken(pseudoToken));
767 private int GetHeaderLength()
774 4 + // ImageRuntimeVersion Length
775 StringToPaddedUTF8Length(asm.ImageRuntimeVersion) +
780 4 + // StringToPaddedUTF8Length("#~")
781 4 + // #Strings Offset
783 12 + // StringToPaddedUTF8Length("#Strings")
786 4 + // StringToPaddedUTF8Length("#US")
789 8 + // StringToPaddedUTF8Length("#GUID")
794 8 // StringToPaddedUTF8Length("#Blob")
798 internal int MetadataLength
802 return GetHeaderLength() + (Blobs.IsEmpty ? 0 : Blobs.Length) + Tables.Length + Strings.Length + UserStrings.Length + Guids.Length;
806 internal void WriteMetadata(MetadataWriter mw)
808 mw.Write(0x424A5342); // Signature ("BSJB")
809 mw.Write((ushort)1); // MajorVersion
810 mw.Write((ushort)1); // MinorVersion
811 mw.Write(0); // Reserved
812 byte[] version = StringToPaddedUTF8(asm.ImageRuntimeVersion);
813 mw.Write(version.Length); // Length
815 mw.Write((ushort)0); // Flags
816 // #Blob is the only optional heap
819 mw.Write((ushort)4); // Streams
823 mw.Write((ushort)5); // Streams
826 int offset = GetHeaderLength();
829 mw.Write(offset); // Offset
830 mw.Write(Tables.Length); // Size
831 mw.Write(StringToPaddedUTF8("#~"));
832 offset += Tables.Length;
834 mw.Write(offset); // Offset
835 mw.Write(Strings.Length); // Size
836 mw.Write(StringToPaddedUTF8("#Strings"));
837 offset += Strings.Length;
839 mw.Write(offset); // Offset
840 mw.Write(UserStrings.Length); // Size
841 mw.Write(StringToPaddedUTF8("#US"));
842 offset += UserStrings.Length;
844 mw.Write(offset); // Offset
845 mw.Write(Guids.Length); // Size
846 mw.Write(StringToPaddedUTF8("#GUID"));
847 offset += Guids.Length;
851 mw.Write(offset); // Offset
852 mw.Write(Blobs.Length); // Size
853 mw.Write(StringToPaddedUTF8("#Blob"));
858 UserStrings.Write(mw);
866 private static int StringToPaddedUTF8Length(string str)
868 return (System.Text.Encoding.UTF8.GetByteCount(str) + 4) & ~3;
871 private static byte[] StringToPaddedUTF8(string str)
873 byte[] buf = new byte[(System.Text.Encoding.UTF8.GetByteCount(str) + 4) & ~3];
874 System.Text.Encoding.UTF8.GetBytes(str, 0, str.Length, buf, 0);
878 internal override void ExportTypes(int fileToken, ModuleBuilder manifestModule)
880 manifestModule.ExportTypes(types.ToArray(), fileToken);
883 internal void ExportTypes(Type[] types, int fileToken)
885 Dictionary<Type, int> declaringTypes = new Dictionary<Type, int>();
886 foreach (Type type in types)
888 if (!type.IsModulePseudoType && IsVisible(type))
890 ExportedTypeTable.Record rec = new ExportedTypeTable.Record();
891 rec.Flags = (int)type.Attributes;
892 rec.TypeDefId = type.MetadataToken & 0xFFFFFF;
893 rec.TypeName = this.Strings.Add(TypeNameParser.Unescape(type.Name));
894 string ns = type.Namespace;
895 rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(TypeNameParser.Unescape(ns));
898 rec.Implementation = declaringTypes[type.DeclaringType];
902 rec.Implementation = fileToken;
904 int exportTypeToken = 0x27000000 | this.ExportedType.AddRecord(rec);
905 declaringTypes.Add(type, exportTypeToken);
910 private static bool IsVisible(Type type)
912 // NOTE this is not the same as Type.IsVisible, because that doesn't take into account family access
913 return type.IsPublic || ((type.IsNestedFamily || type.IsNestedFamORAssem || type.IsNestedPublic) && IsVisible(type.DeclaringType));
916 internal void AddConstant(int parentToken, object defaultValue)
918 ConstantTable.Record rec = new ConstantTable.Record();
919 rec.Parent = parentToken;
920 ByteBuffer val = new ByteBuffer(16);
921 if (defaultValue == null)
923 rec.Type = Signature.ELEMENT_TYPE_CLASS;
926 else if (defaultValue is bool)
928 rec.Type = Signature.ELEMENT_TYPE_BOOLEAN;
929 val.Write((bool)defaultValue ? (byte)1 : (byte)0);
931 else if (defaultValue is char)
933 rec.Type = Signature.ELEMENT_TYPE_CHAR;
934 val.Write((char)defaultValue);
936 else if (defaultValue is sbyte)
938 rec.Type = Signature.ELEMENT_TYPE_I1;
939 val.Write((sbyte)defaultValue);
941 else if (defaultValue is byte)
943 rec.Type = Signature.ELEMENT_TYPE_U1;
944 val.Write((byte)defaultValue);
946 else if (defaultValue is short)
948 rec.Type = Signature.ELEMENT_TYPE_I2;
949 val.Write((short)defaultValue);
951 else if (defaultValue is ushort)
953 rec.Type = Signature.ELEMENT_TYPE_U2;
954 val.Write((ushort)defaultValue);
956 else if (defaultValue is int)
958 rec.Type = Signature.ELEMENT_TYPE_I4;
959 val.Write((int)defaultValue);
961 else if (defaultValue is uint)
963 rec.Type = Signature.ELEMENT_TYPE_U4;
964 val.Write((uint)defaultValue);
966 else if (defaultValue is long)
968 rec.Type = Signature.ELEMENT_TYPE_I8;
969 val.Write((long)defaultValue);
971 else if (defaultValue is ulong)
973 rec.Type = Signature.ELEMENT_TYPE_U8;
974 val.Write((ulong)defaultValue);
976 else if (defaultValue is float)
978 rec.Type = Signature.ELEMENT_TYPE_R4;
979 val.Write((float)defaultValue);
981 else if (defaultValue is double)
983 rec.Type = Signature.ELEMENT_TYPE_R8;
984 val.Write((double)defaultValue);
986 else if (defaultValue is string)
988 rec.Type = Signature.ELEMENT_TYPE_STRING;
989 foreach (char c in (string)defaultValue)
994 else if (defaultValue is DateTime)
996 rec.Type = Signature.ELEMENT_TYPE_I8;
997 val.Write(((DateTime)defaultValue).Ticks);
1001 throw new ArgumentException();
1003 rec.Value = this.Blobs.Add(val);
1004 this.Constant.AddRecord(rec);
1007 ModuleBuilder ITypeOwner.ModuleBuilder
1009 get { return this; }
1012 public override Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1014 if (genericTypeArguments != null || genericMethodArguments != null)
1016 throw new NotImplementedException();
1018 return types[(metadataToken & 0xFFFFFF) - 1];
1021 public override MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1023 if (genericTypeArguments != null || genericMethodArguments != null)
1025 throw new NotImplementedException();
1027 // this method is inefficient, but since it isn't used we don't care
1028 if ((metadataToken >> 24) == MemberRefTable.Index)
1030 foreach (KeyValuePair<MemberInfo, int> kv in importedMembers)
1032 if (kv.Value == metadataToken)
1034 return (MethodBase)kv.Key;
1038 // HACK if we're given a SymbolToken, we need to convert back
1039 if ((metadataToken & 0xFF000000) == 0x06000000)
1041 metadataToken = -(metadataToken & 0x00FFFFFF);
1043 foreach (Type type in types)
1045 MethodBase method = ((TypeBuilder)type).LookupMethod(metadataToken);
1051 return ((TypeBuilder)moduleType).LookupMethod(metadataToken);
1054 public override FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1056 throw new NotImplementedException();
1059 public override MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1061 throw new NotImplementedException();
1064 public override string ResolveString(int metadataToken)
1066 throw new NotImplementedException();
1069 public override string FullyQualifiedName
1071 get { return Path.GetFullPath(Path.Combine(asm.dir, fileName)); }
1074 public override string Name
1076 get { return fileName; }
1079 public override Guid ModuleVersionId
1081 get { return mvid; }
1084 public override Type[] __ResolveOptionalParameterTypes(int metadataToken)
1086 throw new NotImplementedException();
1089 public override string ScopeName
1091 get { return moduleName; }
1094 public ISymbolWriter GetSymWriter()
1096 return symbolWriter;
1099 public void DefineUnmanagedResource(string resourceFileName)
1101 // This method reads the specified resource file (Win32 .res file) and converts it into the appropriate format and embeds it in the .rsrc section,
1102 // also setting the Resource Directory entry.
1103 unmanagedResources = new ResourceSection();
1104 unmanagedResources.ExtractResources(System.IO.File.ReadAllBytes(resourceFileName));
1107 public bool IsTransient()
1112 public void SetUserEntryPoint(MethodInfo entryPoint)
1114 int token = entryPoint.MetadataToken;
1117 token = -token | 0x06000000;
1119 if (symbolWriter != null)
1121 symbolWriter.SetUserEntryPoint(new SymbolToken(token));
1125 public StringToken GetStringConstant(string str)
1127 return new StringToken(this.UserStrings.Add(str) | (0x70 << 24));
1130 public SignatureToken GetSignatureToken(SignatureHelper sigHelper)
1132 return new SignatureToken(this.StandAloneSig.FindOrAddRecord(this.Blobs.Add(sigHelper.GetSignature(this))) | (StandAloneSigTable.Index << 24));
1135 public SignatureToken GetSignatureToken(byte[] sigBytes, int sigLength)
1137 return new SignatureToken(this.StandAloneSig.FindOrAddRecord(this.Blobs.Add(ByteBuffer.Wrap(sigBytes, sigLength))) | (StandAloneSigTable.Index << 24));
1140 public MethodInfo GetArrayMethod(Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
1142 return new ArrayMethod(this, arrayClass, methodName, callingConvention, returnType, parameterTypes);
1145 public MethodToken GetArrayMethodToken(Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
1147 return GetMethodToken(GetArrayMethod(arrayClass, methodName, callingConvention, returnType, parameterTypes));
1150 internal override Type GetModuleType()
1155 internal override IKVM.Reflection.Reader.ByteReader GetBlob(int blobIndex)
1157 return Blobs.GetBlob(blobIndex);
1160 internal int GetSignatureBlobIndex(Signature sig)
1162 ByteBuffer bb = new ByteBuffer(16);
1163 sig.WriteSig(this, bb);
1164 return this.Blobs.Add(bb);
1168 public long __ImageBase
1170 get { return imageBaseAddress; }
1171 set { imageBaseAddress = value; }
1174 public override int MDStreamVersion
1176 get { return asm.mdStreamVersion; }
1179 private int AddTypeRefByName(int resolutionScope, string ns, string name)
1181 TypeRefTable.Record rec = new TypeRefTable.Record();
1182 rec.ResolutionScope = resolutionScope;
1183 rec.TypeName = this.Strings.Add(name);
1184 rec.TypeNameSpace = ns == null ? 0 : this.Strings.Add(ns);
1185 return 0x01000000 | this.TypeRef.AddRecord(rec);
1188 public void __Save(PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
1190 PopulatePropertyAndEventTables();
1191 IList<CustomAttributeData> attributes = asm.GetCustomAttributesData(null);
1192 if (attributes.Count > 0)
1194 int mscorlib = ImportAssemblyRef(universe.Mscorlib);
1195 int[] placeholderTokens = new int[4];
1196 string[] placeholderTypeNames = new string[] { "AssemblyAttributesGoHere", "AssemblyAttributesGoHereM", "AssemblyAttributesGoHereS", "AssemblyAttributesGoHereSM" };
1197 foreach (CustomAttributeData cad in attributes)
1200 if (cad.Constructor.DeclaringType.BaseType == universe.System_Security_Permissions_CodeAccessSecurityAttribute)
1202 if (cad.Constructor.DeclaringType.IsAllowMultipleCustomAttribute)
1211 else if (cad.Constructor.DeclaringType.IsAllowMultipleCustomAttribute)
1219 if (placeholderTokens[index] == 0)
1221 // we manually add a TypeRef without looking it up in mscorlib, because Mono and Silverlight's mscorlib don't have these types
1222 placeholderTokens[index] = AddTypeRefByName(mscorlib, "System.Runtime.CompilerServices", placeholderTypeNames[index]);
1224 SetCustomAttribute(placeholderTokens[index], cad.__ToBuilder());
1227 FillAssemblyRefTable();
1228 ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, unmanagedResources, 0);
1231 public void __AddAssemblyReference(AssemblyName assemblyName)
1233 if (referencedAssemblyNames == null)
1235 referencedAssemblyNames = new List<AssemblyName>();
1237 FindOrAddAssemblyRef(assemblyName);
1238 referencedAssemblyNames.Add((AssemblyName)assemblyName.Clone());
1241 public override AssemblyName[] __GetReferencedAssemblies()
1243 List<AssemblyName> list = new List<AssemblyName>();
1244 if (referencedAssemblyNames != null)
1246 foreach (AssemblyName name in referencedAssemblyNames)
1248 if (!list.Contains(name))
1254 foreach (Assembly asm in referencedAssemblies.Keys)
1256 AssemblyName name = asm.GetName();
1257 if (!list.Contains(name))
1262 return list.ToArray();
1266 class ArrayMethod : MethodInfo
1268 private readonly Module module;
1269 private readonly Type arrayClass;
1270 private readonly string methodName;
1271 private readonly CallingConventions callingConvention;
1272 private readonly Type returnType;
1273 protected readonly Type[] parameterTypes;
1274 private MethodSignature methodSignature;
1276 internal ArrayMethod(Module module, Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
1278 this.module = module;
1279 this.arrayClass = arrayClass;
1280 this.methodName = methodName;
1281 this.callingConvention = callingConvention;
1282 this.returnType = returnType ?? module.universe.System_Void;
1283 this.parameterTypes = Util.Copy(parameterTypes);
1286 public override MethodBody GetMethodBody()
1288 throw new InvalidOperationException();
1291 public override MethodImplAttributes GetMethodImplementationFlags()
1293 throw new NotSupportedException();
1296 public override ParameterInfo[] GetParameters()
1298 throw new NotSupportedException();
1301 internal override int ImportTo(ModuleBuilder module)
1303 return module.ImportMethodOrField(arrayClass, methodName, MethodSignature);
1306 public override MethodAttributes Attributes
1308 get { throw new NotSupportedException(); }
1311 public override CallingConventions CallingConvention
1313 get { return callingConvention; }
1316 public override Type DeclaringType
1318 get { return arrayClass; }
1321 internal override MethodSignature MethodSignature
1325 if (methodSignature == null)
1327 methodSignature = MethodSignature.MakeFromBuilder(returnType, parameterTypes, null, callingConvention, 0);
1329 return methodSignature;
1333 public override Module Module
1335 // like .NET, we return the module that GetArrayMethod was called on, not the module associated with the array type
1336 get { return module; }
1339 public override string Name
1341 get { return methodName; }
1344 internal override int ParameterCount
1346 get { return parameterTypes.Length; }
1349 public override ParameterInfo ReturnParameter
1351 get { throw new NotImplementedException(); }
1354 public override Type ReturnType
1356 get { return returnType; }
1359 internal override bool HasThis
1361 get { return (callingConvention & (CallingConventions.HasThis | CallingConventions.ExplicitThis)) == CallingConventions.HasThis; }