2 Copyright (C) 2008-2011 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 Guid mvid = Guid.NewGuid();
42 private long imageBaseAddress = 0x00400000;
43 private long stackReserve = -1;
44 private readonly AssemblyBuilder asm;
45 internal readonly string moduleName;
46 internal readonly string fileName;
47 internal readonly ISymbolWriterImpl symbolWriter;
48 private readonly TypeBuilder moduleType;
49 private readonly List<TypeBuilder> types = new List<TypeBuilder>();
50 private readonly Dictionary<Type, int> typeTokens = new Dictionary<Type, int>();
51 private readonly Dictionary<Type, int> memberRefTypeTokens = new Dictionary<Type, int>();
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, null, "<Module>");
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)
205 int lastdot = name.LastIndexOf('.');
208 ns = name.Substring(0, lastdot);
209 name = name.Substring(lastdot + 1);
211 TypeBuilder typeBuilder = __DefineType(ns, name);
212 typeBuilder.__SetAttributes(attr);
213 typeBuilder.SetParent(parent);
214 if (packingSize != PackingSize.Unspecified || typesize != 0)
216 typeBuilder.__SetLayout((int)packingSize, typesize);
221 public TypeBuilder __DefineType(string ns, string name)
223 return DefineType(this, ns, name);
226 internal TypeBuilder DefineType(ITypeOwner owner, string ns, string name)
228 TypeBuilder typeBuilder = new TypeBuilder(owner, ns, name);
229 types.Add(typeBuilder);
233 public EnumBuilder DefineEnum(string name, TypeAttributes visibility, Type underlyingType)
235 TypeBuilder tb = DefineType(name, (visibility & TypeAttributes.VisibilityMask) | TypeAttributes.Sealed, universe.System_Enum);
236 FieldBuilder fb = tb.DefineField("value__", underlyingType, FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
237 return new EnumBuilder(tb, fb);
240 public FieldBuilder __DefineField(string name, Type type, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers, FieldAttributes attributes)
242 return moduleType.DefineField(name, type, requiredCustomModifiers, optionalCustomModifiers, attributes);
245 public ConstructorBuilder __DefineModuleInitializer(MethodAttributes visibility)
247 return moduleType.DefineConstructor(visibility | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, Type.EmptyTypes);
250 public FieldBuilder DefineUninitializedData(string name, int size, FieldAttributes attributes)
252 return moduleType.DefineUninitializedData(name, size, attributes);
255 public FieldBuilder DefineInitializedData(string name, byte[] data, FieldAttributes attributes)
257 return moduleType.DefineInitializedData(name, data, attributes);
260 public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, Type returnType, Type[] parameterTypes)
262 return moduleType.DefineMethod(name, attributes, returnType, parameterTypes);
265 public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
267 return moduleType.DefineMethod(name, attributes, callingConvention, returnType, parameterTypes);
270 public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] requiredReturnTypeCustomModifiers, Type[] optionalReturnTypeCustomModifiers, Type[] parameterTypes, Type[][] requiredParameterTypeCustomModifiers, Type[][] optionalParameterTypeCustomModifiers)
272 return moduleType.DefineMethod(name, attributes, callingConvention, returnType, requiredReturnTypeCustomModifiers, optionalReturnTypeCustomModifiers, parameterTypes, requiredParameterTypeCustomModifiers, optionalParameterTypeCustomModifiers);
275 public MethodBuilder DefinePInvokeMethod(string name, string dllName, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, CallingConvention nativeCallConv, CharSet nativeCharSet)
277 return moduleType.DefinePInvokeMethod(name, dllName, attributes, callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet);
280 public MethodBuilder DefinePInvokeMethod(string name, string dllName, string entryName, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, CallingConvention nativeCallConv, CharSet nativeCharSet)
282 return moduleType.DefinePInvokeMethod(name, dllName, entryName, attributes, callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet);
285 public void CreateGlobalFunctions()
287 moduleType.CreateType();
290 internal void AddTypeForwarder(Type type)
293 if (!type.__IsMissing)
295 foreach (Type nested in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
297 // we export all nested types (i.e. even the private ones)
298 // (this behavior is the same as the C# compiler)
299 AddTypeForwarder(nested);
304 private int ExportType(Type type)
306 ExportedTypeTable.Record rec = new ExportedTypeTable.Record();
307 MissingType missing = type as MissingType;
310 rec.TypeDefId = missing.GetMetadataTokenForMissing();
314 rec.TypeDefId = type.MetadataToken;
316 rec.TypeName = this.Strings.Add(type.__Name);
320 rec.TypeNamespace = 0;
321 rec.Implementation = ExportType(type.DeclaringType);
325 rec.Flags = 0x00200000; // CorTypeAttr.tdForwarder
326 string ns = type.__Namespace;
327 rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(ns);
328 rec.Implementation = ImportAssemblyRef(type.Assembly);
330 return 0x27000000 | this.ExportedType.FindOrAddRecord(rec);
333 public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
335 SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
338 public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
340 SetCustomAttribute(0x00000001, customBuilder);
343 internal void SetCustomAttribute(int token, CustomAttributeBuilder customBuilder)
345 Debug.Assert(!customBuilder.IsPseudoCustomAttribute);
346 CustomAttributeTable.Record rec = new CustomAttributeTable.Record();
348 rec.Type = this.GetConstructorToken(customBuilder.Constructor).Token;
349 rec.Value = customBuilder.WriteBlob(this);
350 this.CustomAttribute.AddRecord(rec);
353 internal void AddDeclarativeSecurity(int token, System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet)
355 DeclSecurityTable.Record rec = new DeclSecurityTable.Record();
356 rec.Action = (short)securityAction;
358 // like Ref.Emit, we're using the .NET 1.x xml format
359 rec.PermissionSet = this.Blobs.Add(ByteBuffer.Wrap(System.Text.Encoding.Unicode.GetBytes(permissionSet.ToXml().ToString())));
360 this.DeclSecurity.AddRecord(rec);
363 internal void AddDeclarativeSecurity(int token, List<CustomAttributeBuilder> declarativeSecurity)
365 Dictionary<int, List<CustomAttributeBuilder>> ordered = new Dictionary<int, List<CustomAttributeBuilder>>();
366 foreach (CustomAttributeBuilder cab in declarativeSecurity)
369 // check for HostProtectionAttribute without SecurityAction
370 if (cab.ConstructorArgumentCount == 0)
372 action = (int)System.Security.Permissions.SecurityAction.LinkDemand;
376 action = (int)cab.GetConstructorArgument(0);
378 List<CustomAttributeBuilder> list;
379 if (!ordered.TryGetValue(action, out list))
381 list = new List<CustomAttributeBuilder>();
382 ordered.Add(action, list);
386 foreach (KeyValuePair<int, List<CustomAttributeBuilder>> kv in ordered)
388 DeclSecurityTable.Record rec = new DeclSecurityTable.Record();
389 rec.Action = (short)kv.Key;
391 rec.PermissionSet = WriteDeclSecurityBlob(kv.Value);
392 this.DeclSecurity.AddRecord(rec);
396 private int WriteDeclSecurityBlob(List<CustomAttributeBuilder> list)
399 if (list.Count == 1 && (xml = list[0].GetLegacyDeclSecurity()) != null)
401 // write .NET 1.1 format
402 return this.Blobs.Add(ByteBuffer.Wrap(System.Text.Encoding.Unicode.GetBytes(xml)));
404 ByteBuffer namedArgs = new ByteBuffer(100);
405 ByteBuffer bb = new ByteBuffer(list.Count * 100);
407 bb.WriteCompressedInt(list.Count);
408 foreach (CustomAttributeBuilder cab in list)
410 bb.Write(cab.Constructor.DeclaringType.AssemblyQualifiedName);
412 cab.WriteNamedArgumentsForDeclSecurity(this, namedArgs);
413 bb.WriteCompressedInt(namedArgs.Length);
416 return this.Blobs.Add(bb);
419 public void DefineManifestResource(string name, Stream stream, ResourceAttributes attribute)
421 manifestResources.Align(8);
422 ManifestResourceTable.Record rec = new ManifestResourceTable.Record();
423 rec.Offset = manifestResources.Position;
424 rec.Flags = (int)attribute;
425 rec.Name = this.Strings.Add(name);
426 rec.Implementation = 0;
427 this.ManifestResource.AddRecord(rec);
428 manifestResources.Write(0); // placeholder for the length
429 manifestResources.Write(stream);
430 int savePosition = manifestResources.Position;
431 manifestResources.Position = rec.Offset;
432 manifestResources.Write(savePosition - (manifestResources.Position + 4));
433 manifestResources.Position = savePosition;
436 public override Assembly Assembly
441 internal override Type FindType(TypeName name)
443 foreach (Type type in types)
445 if (type.__Namespace == name.Namespace && type.__Name == name.Name)
453 internal override void GetTypesImpl(List<Type> list)
455 foreach (Type type in types)
457 if (type != moduleType)
464 public ISymbolDocumentWriter DefineDocument(string url, Guid language, Guid languageVendor, Guid documentType)
466 return symbolWriter.DefineDocument(url, language, languageVendor, documentType);
469 public TypeToken GetTypeToken(string name)
471 return new TypeToken(GetType(name, true, false).MetadataToken);
474 public TypeToken GetTypeToken(Type type)
476 if (type.Module == this)
478 return new TypeToken(type.GetModuleBuilderToken());
482 return new TypeToken(ImportType(type));
486 internal int GetTypeTokenForMemberRef(Type type)
488 if (type.__IsMissing)
490 return ImportType(type);
492 else if (type.IsGenericTypeDefinition)
495 if (!memberRefTypeTokens.TryGetValue(type, out token))
497 ByteBuffer spec = new ByteBuffer(5);
498 Signature.WriteTypeSpec(this, spec, type);
499 token = 0x1B000000 | this.TypeSpec.AddRecord(this.Blobs.Add(spec));
500 memberRefTypeTokens.Add(type, token);
504 else if (type.IsModulePseudoType)
506 return 0x1A000000 | this.ModuleRef.FindOrAddRecord(this.Strings.Add(type.Module.ScopeName));
510 return GetTypeToken(type).Token;
514 private static bool IsFromGenericTypeDefinition(MemberInfo member)
516 Type decl = member.DeclaringType;
517 return decl != null && !decl.__IsMissing && decl.IsGenericTypeDefinition;
520 public FieldToken GetFieldToken(FieldInfo field)
522 // NOTE for some reason, when TypeBuilder.GetFieldToken() is used on a field in a generic type definition,
523 // a memberref token is returned (confirmed on .NET) unlike for Get(Method|Constructor)Token which always
524 // simply returns the MethodDef token (if the method is from the same module).
525 FieldBuilder fb = field as FieldBuilder;
526 if (fb != null && fb.Module == this && !IsFromGenericTypeDefinition(fb))
528 return new FieldToken(fb.MetadataToken);
532 return new FieldToken(ImportMember(field));
536 public MethodToken GetMethodToken(MethodInfo method)
538 MethodBuilder mb = method as MethodBuilder;
539 if (mb != null && mb.ModuleBuilder == this)
541 return new MethodToken(mb.MetadataToken);
545 return new MethodToken(ImportMember(method));
549 // when we refer to a method on a generic type definition in the IL stream,
550 // we need to use a MemberRef (even if the method is in the same module)
551 internal MethodToken GetMethodTokenForIL(MethodInfo method)
553 if (method.IsGenericMethodDefinition)
555 method = method.MakeGenericMethod(method.GetGenericArguments());
557 if (IsFromGenericTypeDefinition(method))
559 return new MethodToken(ImportMember(method));
563 return GetMethodToken(method);
567 public MethodToken GetConstructorToken(ConstructorInfo constructor)
569 if (constructor.Module == this && constructor.GetMethodInfo() is MethodBuilder)
571 return new MethodToken(constructor.MetadataToken);
575 return new MethodToken(ImportMember(constructor));
579 internal int ImportMember(MethodBase member)
582 if (!importedMembers.TryGetValue(member, out token))
584 token = member.ImportTo(this);
585 importedMembers.Add(member, token);
590 internal int ImportMember(FieldInfo member)
593 if (!importedMembers.TryGetValue(member, out token))
595 token = member.ImportTo(this);
596 importedMembers.Add(member, token);
601 internal int ImportMethodOrField(Type declaringType, string name, Signature sig)
604 if (!importedMemberRefs.TryGetValue(new MemberRefKey(declaringType, name, sig), out token))
606 MemberRefTable.Record rec = new MemberRefTable.Record();
607 rec.Class = GetTypeTokenForMemberRef(declaringType);
608 rec.Name = this.Strings.Add(name);
609 ByteBuffer bb = new ByteBuffer(16);
610 sig.WriteSig(this, bb);
611 rec.Signature = this.Blobs.Add(bb);
612 token = 0x0A000000 | this.MemberRef.AddRecord(rec);
613 importedMemberRefs.Add(new MemberRefKey(declaringType, name, sig), token);
618 internal int ImportType(Type type)
621 if (!typeTokens.TryGetValue(type, out token))
623 if (type.HasElementType || type.IsGenericTypeInstance)
625 ByteBuffer spec = new ByteBuffer(5);
626 Signature.WriteTypeSpec(this, spec, type);
627 token = 0x1B000000 | this.TypeSpec.AddRecord(this.Blobs.Add(spec));
631 TypeRefTable.Record rec = new TypeRefTable.Record();
634 rec.ResolutionScope = GetTypeToken(type.DeclaringType).Token;
638 rec.ResolutionScope = ImportAssemblyRef(type.Assembly);
640 rec.TypeName = this.Strings.Add(type.__Name);
641 string ns = type.__Namespace;
642 rec.TypeNameSpace = ns == null ? 0 : this.Strings.Add(ns);
643 token = 0x01000000 | this.TypeRef.AddRecord(rec);
645 typeTokens.Add(type, token);
650 private int ImportAssemblyRef(Assembly asm)
653 if (!referencedAssemblies.TryGetValue(asm, out token))
655 // We can't write the AssemblyRef record here yet, because the identity of the assembly can still change
656 // (if it's an AssemblyBuilder).
657 // We set the high bit of rid in the token to make sure we emit obviously broken metadata,
658 // if we forget to patch up the token somewhere.
659 token = 0x23800001 + referencedAssemblies.Count;
660 referencedAssemblies.Add(asm, token);
665 internal void FillAssemblyRefTable()
667 int[] realtokens = new int[referencedAssemblies.Count];
668 foreach (KeyValuePair<Assembly, int> kv in referencedAssemblies)
670 realtokens[(kv.Value & 0x7FFFFF) - 1] = FindOrAddAssemblyRef(kv.Key.GetName());
672 // now fixup the resolution scopes in TypeRef
673 for (int i = 0; i < this.TypeRef.records.Length; i++)
675 int resolutionScope = this.TypeRef.records[i].ResolutionScope;
676 if ((resolutionScope >> 24) == AssemblyRefTable.Index)
678 this.TypeRef.records[i].ResolutionScope = realtokens[(resolutionScope & 0x7FFFFF) - 1];
681 // and implementation in ExportedType
682 for (int i = 0; i < this.ExportedType.records.Length; i++)
684 int implementation = this.ExportedType.records[i].Implementation;
685 if ((implementation >> 24) == AssemblyRefTable.Index)
687 this.ExportedType.records[i].Implementation = realtokens[(implementation & 0x7FFFFF) - 1];
692 private int FindOrAddAssemblyRef(AssemblyName name)
694 AssemblyRefTable.Record rec = new AssemblyRefTable.Record();
695 Version ver = name.Version ?? new Version(0, 0, 0, 0);
696 rec.MajorVersion = (ushort)ver.Major;
697 rec.MinorVersion = (ushort)ver.Minor;
698 rec.BuildNumber = (ushort)ver.Build;
699 rec.RevisionNumber = (ushort)ver.Revision;
700 rec.Flags = (int)(name.Flags & AssemblyNameFlags.Retargetable);
701 byte[] publicKeyOrToken = null;
702 if (usePublicKeyAssemblyReference)
704 publicKeyOrToken = name.GetPublicKey();
706 if (publicKeyOrToken == null || publicKeyOrToken.Length == 0)
708 publicKeyOrToken = name.GetPublicKeyToken() ?? Empty<byte>.Array;
712 const int PublicKey = 0x0001;
713 rec.Flags |= PublicKey;
715 rec.PublicKeyOrToken = this.Blobs.Add(ByteBuffer.Wrap(publicKeyOrToken));
716 rec.Name = this.Strings.Add(name.Name);
717 if (name.CultureInfo != null)
719 rec.Culture = this.Strings.Add(name.CultureInfo.Name);
725 if (name.hash != null)
727 rec.HashValue = this.Blobs.Add(ByteBuffer.Wrap(name.hash));
733 return 0x23000000 | this.AssemblyRef.FindOrAddRecord(rec);
736 internal void WriteSymbolTokenMap()
738 for (int i = 0; i < resolvedTokens.Count; i++)
740 int newToken = resolvedTokens[i];
741 // The symbol API doesn't support remapping arbitrary integers, the types have to be the same,
742 // so we copy the type from the newToken, because our pseudo tokens don't have a type.
743 // (see MethodToken.SymbolToken)
744 int oldToken = (i + 1) | (newToken & ~0xFFFFFF);
745 SymbolSupport.RemapToken(symbolWriter, oldToken, newToken);
749 internal void RegisterTokenFixup(int pseudoToken, int realToken)
751 int index = -(pseudoToken + 1);
752 while (resolvedTokens.Count <= index)
754 resolvedTokens.Add(0);
756 resolvedTokens[index] = realToken;
759 internal bool IsPseudoToken(int token)
764 internal int ResolvePseudoToken(int pseudoToken)
766 int index = -(pseudoToken + 1);
767 return resolvedTokens[index];
770 internal void FixupMethodBodyTokens()
772 int methodToken = 0x06000001;
773 int fieldToken = 0x04000001;
774 int parameterToken = 0x08000001;
775 foreach (TypeBuilder type in types)
777 type.ResolveMethodAndFieldTokens(ref methodToken, ref fieldToken, ref parameterToken);
779 foreach (int offset in tokenFixupOffsets)
781 methodBodies.Position = offset;
782 int pseudoToken = methodBodies.GetInt32AtCurrentPosition();
783 methodBodies.Write(ResolvePseudoToken(pseudoToken));
787 private int GetHeaderLength()
794 4 + // ImageRuntimeVersion Length
795 StringToPaddedUTF8Length(asm.ImageRuntimeVersion) +
800 4 + // StringToPaddedUTF8Length("#~")
801 4 + // #Strings Offset
803 12 + // StringToPaddedUTF8Length("#Strings")
806 4 + // StringToPaddedUTF8Length("#US")
809 8 + // StringToPaddedUTF8Length("#GUID")
814 8 // StringToPaddedUTF8Length("#Blob")
818 internal int MetadataLength
822 return GetHeaderLength() + (Blobs.IsEmpty ? 0 : Blobs.Length) + Tables.Length + Strings.Length + UserStrings.Length + Guids.Length;
826 internal void WriteMetadata(MetadataWriter mw)
828 mw.Write(0x424A5342); // Signature ("BSJB")
829 mw.Write((ushort)1); // MajorVersion
830 mw.Write((ushort)1); // MinorVersion
831 mw.Write(0); // Reserved
832 byte[] version = StringToPaddedUTF8(asm.ImageRuntimeVersion);
833 mw.Write(version.Length); // Length
835 mw.Write((ushort)0); // Flags
836 // #Blob is the only optional heap
839 mw.Write((ushort)4); // Streams
843 mw.Write((ushort)5); // Streams
846 int offset = GetHeaderLength();
849 mw.Write(offset); // Offset
850 mw.Write(Tables.Length); // Size
851 mw.Write(StringToPaddedUTF8("#~"));
852 offset += Tables.Length;
854 mw.Write(offset); // Offset
855 mw.Write(Strings.Length); // Size
856 mw.Write(StringToPaddedUTF8("#Strings"));
857 offset += Strings.Length;
859 mw.Write(offset); // Offset
860 mw.Write(UserStrings.Length); // Size
861 mw.Write(StringToPaddedUTF8("#US"));
862 offset += UserStrings.Length;
864 mw.Write(offset); // Offset
865 mw.Write(Guids.Length); // Size
866 mw.Write(StringToPaddedUTF8("#GUID"));
867 offset += Guids.Length;
871 mw.Write(offset); // Offset
872 mw.Write(Blobs.Length); // Size
873 mw.Write(StringToPaddedUTF8("#Blob"));
878 UserStrings.Write(mw);
886 private static int StringToPaddedUTF8Length(string str)
888 return (System.Text.Encoding.UTF8.GetByteCount(str) + 4) & ~3;
891 private static byte[] StringToPaddedUTF8(string str)
893 byte[] buf = new byte[(System.Text.Encoding.UTF8.GetByteCount(str) + 4) & ~3];
894 System.Text.Encoding.UTF8.GetBytes(str, 0, str.Length, buf, 0);
898 internal override void ExportTypes(int fileToken, ModuleBuilder manifestModule)
900 manifestModule.ExportTypes(types.ToArray(), fileToken);
903 internal void ExportTypes(Type[] types, int fileToken)
905 Dictionary<Type, int> declaringTypes = new Dictionary<Type, int>();
906 foreach (Type type in types)
908 if (!type.IsModulePseudoType && IsVisible(type))
910 ExportedTypeTable.Record rec = new ExportedTypeTable.Record();
911 rec.Flags = (int)type.Attributes;
912 rec.TypeDefId = type.MetadataToken & 0xFFFFFF;
913 rec.TypeName = this.Strings.Add(type.__Name);
914 string ns = type.__Namespace;
915 rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(ns);
918 rec.Implementation = declaringTypes[type.DeclaringType];
922 rec.Implementation = fileToken;
924 int exportTypeToken = 0x27000000 | this.ExportedType.AddRecord(rec);
925 declaringTypes.Add(type, exportTypeToken);
930 private static bool IsVisible(Type type)
932 // NOTE this is not the same as Type.IsVisible, because that doesn't take into account family access
933 return type.IsPublic || ((type.IsNestedFamily || type.IsNestedFamORAssem || type.IsNestedPublic) && IsVisible(type.DeclaringType));
936 internal void AddConstant(int parentToken, object defaultValue)
938 ConstantTable.Record rec = new ConstantTable.Record();
939 rec.Parent = parentToken;
940 ByteBuffer val = new ByteBuffer(16);
941 if (defaultValue == null)
943 rec.Type = Signature.ELEMENT_TYPE_CLASS;
946 else if (defaultValue is bool)
948 rec.Type = Signature.ELEMENT_TYPE_BOOLEAN;
949 val.Write((bool)defaultValue ? (byte)1 : (byte)0);
951 else if (defaultValue is char)
953 rec.Type = Signature.ELEMENT_TYPE_CHAR;
954 val.Write((char)defaultValue);
956 else if (defaultValue is sbyte)
958 rec.Type = Signature.ELEMENT_TYPE_I1;
959 val.Write((sbyte)defaultValue);
961 else if (defaultValue is byte)
963 rec.Type = Signature.ELEMENT_TYPE_U1;
964 val.Write((byte)defaultValue);
966 else if (defaultValue is short)
968 rec.Type = Signature.ELEMENT_TYPE_I2;
969 val.Write((short)defaultValue);
971 else if (defaultValue is ushort)
973 rec.Type = Signature.ELEMENT_TYPE_U2;
974 val.Write((ushort)defaultValue);
976 else if (defaultValue is int)
978 rec.Type = Signature.ELEMENT_TYPE_I4;
979 val.Write((int)defaultValue);
981 else if (defaultValue is uint)
983 rec.Type = Signature.ELEMENT_TYPE_U4;
984 val.Write((uint)defaultValue);
986 else if (defaultValue is long)
988 rec.Type = Signature.ELEMENT_TYPE_I8;
989 val.Write((long)defaultValue);
991 else if (defaultValue is ulong)
993 rec.Type = Signature.ELEMENT_TYPE_U8;
994 val.Write((ulong)defaultValue);
996 else if (defaultValue is float)
998 rec.Type = Signature.ELEMENT_TYPE_R4;
999 val.Write((float)defaultValue);
1001 else if (defaultValue is double)
1003 rec.Type = Signature.ELEMENT_TYPE_R8;
1004 val.Write((double)defaultValue);
1006 else if (defaultValue is string)
1008 rec.Type = Signature.ELEMENT_TYPE_STRING;
1009 foreach (char c in (string)defaultValue)
1014 else if (defaultValue is DateTime)
1016 rec.Type = Signature.ELEMENT_TYPE_I8;
1017 val.Write(((DateTime)defaultValue).Ticks);
1021 throw new ArgumentException();
1023 rec.Value = this.Blobs.Add(val);
1024 this.Constant.AddRecord(rec);
1027 ModuleBuilder ITypeOwner.ModuleBuilder
1029 get { return this; }
1032 public override Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1034 if (genericTypeArguments != null || genericMethodArguments != null)
1036 throw new NotImplementedException();
1038 return types[(metadataToken & 0xFFFFFF) - 1];
1041 public override MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1043 if (genericTypeArguments != null || genericMethodArguments != null)
1045 throw new NotImplementedException();
1047 // this method is inefficient, but since it isn't used we don't care
1048 if ((metadataToken >> 24) == MemberRefTable.Index)
1050 foreach (KeyValuePair<MemberInfo, int> kv in importedMembers)
1052 if (kv.Value == metadataToken)
1054 return (MethodBase)kv.Key;
1058 // HACK if we're given a SymbolToken, we need to convert back
1059 if ((metadataToken & 0xFF000000) == 0x06000000)
1061 metadataToken = -(metadataToken & 0x00FFFFFF);
1063 foreach (Type type in types)
1065 MethodBase method = ((TypeBuilder)type).LookupMethod(metadataToken);
1071 return ((TypeBuilder)moduleType).LookupMethod(metadataToken);
1074 public override FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1076 throw new NotImplementedException();
1079 public override MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1081 throw new NotImplementedException();
1084 public override string ResolveString(int metadataToken)
1086 throw new NotImplementedException();
1089 public override string FullyQualifiedName
1091 get { return Path.GetFullPath(Path.Combine(asm.dir, fileName)); }
1094 public override string Name
1096 get { return fileName; }
1099 public override Guid ModuleVersionId
1101 get { return mvid; }
1104 public void __SetModuleVersionId(Guid guid)
1109 public override Type[] __ResolveOptionalParameterTypes(int metadataToken)
1111 throw new NotImplementedException();
1114 public override string ScopeName
1116 get { return moduleName; }
1119 public ISymbolWriter GetSymWriter()
1121 return symbolWriter;
1124 public void DefineUnmanagedResource(string resourceFileName)
1126 // This method reads the specified resource file (Win32 .res file) and converts it into the appropriate format and embeds it in the .rsrc section,
1127 // also setting the Resource Directory entry.
1128 unmanagedResources = new ResourceSection();
1129 unmanagedResources.ExtractResources(System.IO.File.ReadAllBytes(resourceFileName));
1132 public bool IsTransient()
1137 public void SetUserEntryPoint(MethodInfo entryPoint)
1139 int token = entryPoint.MetadataToken;
1142 token = -token | 0x06000000;
1144 if (symbolWriter != null)
1146 symbolWriter.SetUserEntryPoint(new SymbolToken(token));
1150 public StringToken GetStringConstant(string str)
1152 return new StringToken(this.UserStrings.Add(str) | (0x70 << 24));
1155 public SignatureToken GetSignatureToken(SignatureHelper sigHelper)
1157 return new SignatureToken(this.StandAloneSig.FindOrAddRecord(this.Blobs.Add(sigHelper.GetSignature(this))) | (StandAloneSigTable.Index << 24));
1160 public SignatureToken GetSignatureToken(byte[] sigBytes, int sigLength)
1162 return new SignatureToken(this.StandAloneSig.FindOrAddRecord(this.Blobs.Add(ByteBuffer.Wrap(sigBytes, sigLength))) | (StandAloneSigTable.Index << 24));
1165 public MethodInfo GetArrayMethod(Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
1167 return new ArrayMethod(this, arrayClass, methodName, callingConvention, returnType, parameterTypes);
1170 public MethodToken GetArrayMethodToken(Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
1172 return GetMethodToken(GetArrayMethod(arrayClass, methodName, callingConvention, returnType, parameterTypes));
1175 internal override Type GetModuleType()
1180 internal override IKVM.Reflection.Reader.ByteReader GetBlob(int blobIndex)
1182 return Blobs.GetBlob(blobIndex);
1185 internal int GetSignatureBlobIndex(Signature sig)
1187 ByteBuffer bb = new ByteBuffer(16);
1188 sig.WriteSig(this, bb);
1189 return this.Blobs.Add(bb);
1193 public new long __ImageBase
1195 get { return imageBaseAddress; }
1196 set { imageBaseAddress = value; }
1199 protected override long GetImageBaseImpl()
1201 return imageBaseAddress;
1204 public override long __StackReserve
1206 get { return stackReserve; }
1209 public void __SetStackReserve(long stackReserve)
1211 this.stackReserve = stackReserve;
1214 internal ulong GetStackReserve(ulong defaultValue)
1216 return stackReserve == -1 ? defaultValue : (ulong)stackReserve;
1219 public override int MDStreamVersion
1221 get { return asm.mdStreamVersion; }
1224 private int AddTypeRefByName(int resolutionScope, string ns, string name)
1226 TypeRefTable.Record rec = new TypeRefTable.Record();
1227 rec.ResolutionScope = resolutionScope;
1228 rec.TypeName = this.Strings.Add(name);
1229 rec.TypeNameSpace = ns == null ? 0 : this.Strings.Add(ns);
1230 return 0x01000000 | this.TypeRef.AddRecord(rec);
1233 public void __Save(PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
1235 SaveImpl(null, portableExecutableKind, imageFileMachine);
1238 public void __Save(Stream stream, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
1240 if (!stream.CanRead || !stream.CanWrite || !stream.CanSeek || stream.Position != 0)
1242 throw new ArgumentException("Stream must support read/write/seek and current position must be zero.", "stream");
1244 SaveImpl(stream, portableExecutableKind, imageFileMachine);
1247 private void SaveImpl(Stream streamOrNull, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
1249 PopulatePropertyAndEventTables();
1250 IList<CustomAttributeData> attributes = asm.GetCustomAttributesData(null);
1251 if (attributes.Count > 0)
1253 int mscorlib = ImportAssemblyRef(universe.Mscorlib);
1254 int[] placeholderTokens = new int[4];
1255 string[] placeholderTypeNames = new string[] { "AssemblyAttributesGoHere", "AssemblyAttributesGoHereM", "AssemblyAttributesGoHereS", "AssemblyAttributesGoHereSM" };
1256 foreach (CustomAttributeData cad in attributes)
1259 if (cad.Constructor.DeclaringType.BaseType == universe.System_Security_Permissions_CodeAccessSecurityAttribute)
1261 if (cad.Constructor.DeclaringType.IsAllowMultipleCustomAttribute)
1270 else if (cad.Constructor.DeclaringType.IsAllowMultipleCustomAttribute)
1278 if (placeholderTokens[index] == 0)
1280 // we manually add a TypeRef without looking it up in mscorlib, because Mono and Silverlight's mscorlib don't have these types
1281 placeholderTokens[index] = AddTypeRefByName(mscorlib, "System.Runtime.CompilerServices", placeholderTypeNames[index]);
1283 SetCustomAttribute(placeholderTokens[index], cad.__ToBuilder());
1286 FillAssemblyRefTable();
1287 ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, unmanagedResources, 0, streamOrNull);
1290 public void __AddAssemblyReference(AssemblyName assemblyName)
1292 if (referencedAssemblyNames == null)
1294 referencedAssemblyNames = new List<AssemblyName>();
1296 FindOrAddAssemblyRef(assemblyName);
1297 referencedAssemblyNames.Add((AssemblyName)assemblyName.Clone());
1300 public override AssemblyName[] __GetReferencedAssemblies()
1302 List<AssemblyName> list = new List<AssemblyName>();
1303 if (referencedAssemblyNames != null)
1305 foreach (AssemblyName name in referencedAssemblyNames)
1307 if (!list.Contains(name))
1313 foreach (Assembly asm in referencedAssemblies.Keys)
1315 AssemblyName name = asm.GetName();
1316 if (!list.Contains(name))
1321 return list.ToArray();
1324 public void __AddModuleReference(string module)
1326 this.ModuleRef.FindOrAddRecord(module == null ? 0 : this.Strings.Add(module));
1329 public override string[] __GetReferencedModules()
1331 string[] arr = new string[this.ModuleRef.RowCount];
1332 for (int i = 0; i < arr.Length; i++)
1334 arr[i] = this.Strings.Find(this.ModuleRef.records[i]);
1339 public override Type[] __GetReferencedTypes()
1341 List<Type> list = new List<Type>();
1342 foreach (KeyValuePair<Type, int> kv in typeTokens)
1344 if (kv.Value >> 24 == TypeRefTable.Index)
1349 return list.ToArray();
1352 public override Type[] __GetExportedTypes()
1354 throw new NotImplementedException();
1357 public int __AddModule(int flags, string name, byte[] hash)
1359 FileTable.Record file = new FileTable.Record();
1361 file.Name = this.Strings.Add(name);
1362 file.HashValue = this.Blobs.Add(ByteBuffer.Wrap(hash));
1363 return 0x26000000 + this.File.AddRecord(file);
1366 public int __AddManifestResource(int offset, ResourceAttributes flags, string name, int implementation)
1368 ManifestResourceTable.Record res = new ManifestResourceTable.Record();
1369 res.Offset = offset;
1370 res.Flags = (int)flags;
1371 res.Name = this.Strings.Add(name);
1372 res.Implementation = implementation;
1373 return 0x28000000 + this.ManifestResource.AddRecord(res);
1376 public void __SetCustomAttributeFor(int token, CustomAttributeBuilder customBuilder)
1378 SetCustomAttribute(token, customBuilder);
1382 class ArrayMethod : MethodInfo
1384 private readonly Module module;
1385 private readonly Type arrayClass;
1386 private readonly string methodName;
1387 private readonly CallingConventions callingConvention;
1388 private readonly Type returnType;
1389 protected readonly Type[] parameterTypes;
1390 private MethodSignature methodSignature;
1392 internal ArrayMethod(Module module, Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
1394 this.module = module;
1395 this.arrayClass = arrayClass;
1396 this.methodName = methodName;
1397 this.callingConvention = callingConvention;
1398 this.returnType = returnType ?? module.universe.System_Void;
1399 this.parameterTypes = Util.Copy(parameterTypes);
1402 public override MethodBody GetMethodBody()
1404 throw new InvalidOperationException();
1407 public override MethodImplAttributes GetMethodImplementationFlags()
1409 throw new NotSupportedException();
1412 public override ParameterInfo[] GetParameters()
1414 throw new NotSupportedException();
1417 internal override int ImportTo(ModuleBuilder module)
1419 return module.ImportMethodOrField(arrayClass, methodName, MethodSignature);
1422 public override MethodAttributes Attributes
1424 get { throw new NotSupportedException(); }
1427 public override CallingConventions CallingConvention
1429 get { return callingConvention; }
1432 public override Type DeclaringType
1434 get { return arrayClass; }
1437 internal override MethodSignature MethodSignature
1441 if (methodSignature == null)
1443 methodSignature = MethodSignature.MakeFromBuilder(returnType, parameterTypes, null, callingConvention, 0);
1445 return methodSignature;
1449 public override Module Module
1451 // like .NET, we return the module that GetArrayMethod was called on, not the module associated with the array type
1452 get { return module; }
1455 public override string Name
1457 get { return methodName; }
1460 internal override int ParameterCount
1462 get { return parameterTypes.Length; }
1465 public override ParameterInfo ReturnParameter
1467 get { throw new NotImplementedException(); }
1470 public override Type ReturnType
1472 get { return returnType; }
1475 internal override bool HasThis
1477 get { return (callingConvention & (CallingConventions.HasThis | CallingConventions.ExplicitThis)) == CallingConventions.HasThis; }