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();
68 internal readonly List<VTableFixups> vtablefixups = new List<VTableFixups>();
69 internal readonly List<UnmanagedExport> unmanagedExports = new List<UnmanagedExport>();
71 internal struct VTableFixups
73 internal uint initializedDataOffset;
74 internal ushort count;
77 internal int SlotWidth
79 get { return (type & 0x02) == 0 ? 4 : 8; }
83 struct MemberRefKey : IEquatable<MemberRefKey>
85 private readonly Type type;
86 private readonly string name;
87 private readonly Signature signature;
89 internal MemberRefKey(Type type, string name, Signature signature)
93 this.signature = signature;
96 public bool Equals(MemberRefKey other)
98 return other.type.Equals(type)
100 && other.signature.Equals(signature);
103 public override bool Equals(object obj)
105 MemberRefKey? other = obj as MemberRefKey?;
106 return other != null && Equals(other);
109 public override int GetHashCode()
111 return type.GetHashCode() + name.GetHashCode() + signature.GetHashCode();
115 internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, bool emitSymbolInfo)
119 this.moduleName = moduleName;
120 this.fileName = fileName;
123 symbolWriter = SymbolSupport.CreateSymbolWriterFor(this);
125 // <Module> must be the first record in the TypeDef table
126 moduleType = new TypeBuilder(this, null, "<Module>");
127 types.Add(moduleType);
130 internal void PopulatePropertyAndEventTables()
132 // LAMESPEC the PropertyMap and EventMap tables are not required to be sorted by the CLI spec,
133 // but .NET sorts them and Mono requires them to be sorted, so we have to populate the
134 // tables in the right order
135 foreach (TypeBuilder type in types)
137 type.PopulatePropertyAndEventTables();
141 internal void WriteTypeDefTable(MetadataWriter mw)
145 foreach (TypeBuilder type in types)
147 type.WriteTypeDefRecord(mw, ref fieldList, ref methodList);
151 internal void WriteMethodDefTable(int baseRVA, MetadataWriter mw)
154 foreach (TypeBuilder type in types)
156 type.WriteMethodDefRecords(baseRVA, mw, ref paramList);
160 internal void WriteParamTable(MetadataWriter mw)
162 foreach (TypeBuilder type in types)
164 type.WriteParamRecords(mw);
168 internal void WriteFieldTable(MetadataWriter mw)
170 foreach (TypeBuilder type in types)
172 type.WriteFieldRecords(mw);
176 internal int AllocPseudoToken()
178 return nextPseudoToken--;
181 public TypeBuilder DefineType(string name)
183 return DefineType(name, TypeAttributes.Class);
186 public TypeBuilder DefineType(string name, TypeAttributes attr)
188 return DefineType(name, attr, null);
191 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent)
193 return DefineType(name, attr, parent, PackingSize.Unspecified, 0);
196 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, int typesize)
198 return DefineType(name, attr, parent, PackingSize.Unspecified, typesize);
201 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, PackingSize packsize)
203 return DefineType(name, attr, parent, packsize, 0);
206 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, Type[] interfaces)
208 TypeBuilder tb = DefineType(name, attr, parent);
209 foreach (Type iface in interfaces)
211 tb.AddInterfaceImplementation(iface);
216 public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, PackingSize packingSize, int typesize)
219 int lastdot = name.LastIndexOf('.');
222 ns = name.Substring(0, lastdot);
223 name = name.Substring(lastdot + 1);
225 TypeBuilder typeBuilder = __DefineType(ns, name);
226 typeBuilder.__SetAttributes(attr);
227 typeBuilder.SetParent(parent);
228 if (packingSize != PackingSize.Unspecified || typesize != 0)
230 typeBuilder.__SetLayout((int)packingSize, typesize);
235 public TypeBuilder __DefineType(string ns, string name)
237 return DefineType(this, ns, name);
240 internal TypeBuilder DefineType(ITypeOwner owner, string ns, string name)
242 TypeBuilder typeBuilder = new TypeBuilder(owner, ns, name);
243 types.Add(typeBuilder);
247 public EnumBuilder DefineEnum(string name, TypeAttributes visibility, Type underlyingType)
249 TypeBuilder tb = DefineType(name, (visibility & TypeAttributes.VisibilityMask) | TypeAttributes.Sealed, universe.System_Enum);
250 FieldBuilder fb = tb.DefineField("value__", underlyingType, FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
251 return new EnumBuilder(tb, fb);
254 public FieldBuilder __DefineField(string name, Type type, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers, FieldAttributes attributes)
256 return moduleType.DefineField(name, type, requiredCustomModifiers, optionalCustomModifiers, attributes);
259 public ConstructorBuilder __DefineModuleInitializer(MethodAttributes visibility)
261 return moduleType.DefineConstructor(visibility | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, Type.EmptyTypes);
264 public FieldBuilder DefineUninitializedData(string name, int size, FieldAttributes attributes)
266 return moduleType.DefineUninitializedData(name, size, attributes);
269 public FieldBuilder DefineInitializedData(string name, byte[] data, FieldAttributes attributes)
271 return moduleType.DefineInitializedData(name, data, attributes);
274 public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, Type returnType, Type[] parameterTypes)
276 return moduleType.DefineMethod(name, attributes, returnType, parameterTypes);
279 public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
281 return moduleType.DefineMethod(name, attributes, callingConvention, returnType, parameterTypes);
284 public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] requiredReturnTypeCustomModifiers, Type[] optionalReturnTypeCustomModifiers, Type[] parameterTypes, Type[][] requiredParameterTypeCustomModifiers, Type[][] optionalParameterTypeCustomModifiers)
286 return moduleType.DefineMethod(name, attributes, callingConvention, returnType, requiredReturnTypeCustomModifiers, optionalReturnTypeCustomModifiers, parameterTypes, requiredParameterTypeCustomModifiers, optionalParameterTypeCustomModifiers);
289 public MethodBuilder DefinePInvokeMethod(string name, string dllName, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, CallingConvention nativeCallConv, CharSet nativeCharSet)
291 return moduleType.DefinePInvokeMethod(name, dllName, attributes, callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet);
294 public MethodBuilder DefinePInvokeMethod(string name, string dllName, string entryName, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, CallingConvention nativeCallConv, CharSet nativeCharSet)
296 return moduleType.DefinePInvokeMethod(name, dllName, entryName, attributes, callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet);
299 public void CreateGlobalFunctions()
301 moduleType.CreateType();
304 internal void AddTypeForwarder(Type type)
307 if (!type.__IsMissing)
309 foreach (Type nested in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
311 // we export all nested types (i.e. even the private ones)
312 // (this behavior is the same as the C# compiler)
313 AddTypeForwarder(nested);
318 private int ExportType(Type type)
320 ExportedTypeTable.Record rec = new ExportedTypeTable.Record();
321 MissingType missing = type as MissingType;
324 rec.TypeDefId = missing.GetMetadataTokenForMissing();
328 rec.TypeDefId = type.MetadataToken;
330 rec.TypeName = this.Strings.Add(type.__Name);
334 rec.TypeNamespace = 0;
335 rec.Implementation = ExportType(type.DeclaringType);
339 rec.Flags = 0x00200000; // CorTypeAttr.tdForwarder
340 string ns = type.__Namespace;
341 rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(ns);
342 rec.Implementation = ImportAssemblyRef(type.Assembly);
344 return 0x27000000 | this.ExportedType.FindOrAddRecord(rec);
347 public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
349 SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
352 public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
354 SetCustomAttribute(0x00000001, customBuilder);
357 internal void SetCustomAttribute(int token, CustomAttributeBuilder customBuilder)
359 Debug.Assert(!customBuilder.IsPseudoCustomAttribute);
360 CustomAttributeTable.Record rec = new CustomAttributeTable.Record();
362 rec.Type = this.GetConstructorToken(customBuilder.Constructor).Token;
363 rec.Value = customBuilder.WriteBlob(this);
364 this.CustomAttribute.AddRecord(rec);
367 internal void AddDeclarativeSecurity(int token, System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet)
369 DeclSecurityTable.Record rec = new DeclSecurityTable.Record();
370 rec.Action = (short)securityAction;
372 // like Ref.Emit, we're using the .NET 1.x xml format
373 rec.PermissionSet = this.Blobs.Add(ByteBuffer.Wrap(System.Text.Encoding.Unicode.GetBytes(permissionSet.ToXml().ToString())));
374 this.DeclSecurity.AddRecord(rec);
377 internal void AddDeclarativeSecurity(int token, List<CustomAttributeBuilder> declarativeSecurity)
379 Dictionary<int, List<CustomAttributeBuilder>> ordered = new Dictionary<int, List<CustomAttributeBuilder>>();
380 foreach (CustomAttributeBuilder cab in declarativeSecurity)
383 // check for HostProtectionAttribute without SecurityAction
384 if (cab.ConstructorArgumentCount == 0)
386 action = (int)System.Security.Permissions.SecurityAction.LinkDemand;
390 action = (int)cab.GetConstructorArgument(0);
392 List<CustomAttributeBuilder> list;
393 if (!ordered.TryGetValue(action, out list))
395 list = new List<CustomAttributeBuilder>();
396 ordered.Add(action, list);
400 foreach (KeyValuePair<int, List<CustomAttributeBuilder>> kv in ordered)
402 DeclSecurityTable.Record rec = new DeclSecurityTable.Record();
403 rec.Action = (short)kv.Key;
405 rec.PermissionSet = WriteDeclSecurityBlob(kv.Value);
406 this.DeclSecurity.AddRecord(rec);
410 private int WriteDeclSecurityBlob(List<CustomAttributeBuilder> list)
413 if (list.Count == 1 && (xml = list[0].GetLegacyDeclSecurity()) != null)
415 // write .NET 1.1 format
416 return this.Blobs.Add(ByteBuffer.Wrap(System.Text.Encoding.Unicode.GetBytes(xml)));
418 ByteBuffer namedArgs = new ByteBuffer(100);
419 ByteBuffer bb = new ByteBuffer(list.Count * 100);
421 bb.WriteCompressedInt(list.Count);
422 foreach (CustomAttributeBuilder cab in list)
424 bb.Write(cab.Constructor.DeclaringType.AssemblyQualifiedName);
426 cab.WriteNamedArgumentsForDeclSecurity(this, namedArgs);
427 bb.WriteCompressedInt(namedArgs.Length);
430 return this.Blobs.Add(bb);
433 public void DefineManifestResource(string name, Stream stream, ResourceAttributes attribute)
435 manifestResources.Align(8);
436 ManifestResourceTable.Record rec = new ManifestResourceTable.Record();
437 rec.Offset = manifestResources.Position;
438 rec.Flags = (int)attribute;
439 rec.Name = this.Strings.Add(name);
440 rec.Implementation = 0;
441 this.ManifestResource.AddRecord(rec);
442 manifestResources.Write(0); // placeholder for the length
443 manifestResources.Write(stream);
444 int savePosition = manifestResources.Position;
445 manifestResources.Position = rec.Offset;
446 manifestResources.Write(savePosition - (manifestResources.Position + 4));
447 manifestResources.Position = savePosition;
450 public override Assembly Assembly
455 internal override Type FindType(TypeName name)
457 foreach (Type type in types)
459 if (type.__Namespace == name.Namespace && type.__Name == name.Name)
467 internal override void GetTypesImpl(List<Type> list)
469 foreach (Type type in types)
471 if (type != moduleType)
478 public ISymbolDocumentWriter DefineDocument(string url, Guid language, Guid languageVendor, Guid documentType)
480 return symbolWriter.DefineDocument(url, language, languageVendor, documentType);
483 public TypeToken GetTypeToken(string name)
485 return new TypeToken(GetType(name, true, false).MetadataToken);
488 public TypeToken GetTypeToken(Type type)
490 if (type.Module == this)
492 return new TypeToken(type.GetModuleBuilderToken());
496 return new TypeToken(ImportType(type));
500 internal int GetTypeTokenForMemberRef(Type type)
502 if (type.__IsMissing)
504 return ImportType(type);
506 else if (type.IsGenericTypeDefinition)
509 if (!memberRefTypeTokens.TryGetValue(type, out token))
511 ByteBuffer spec = new ByteBuffer(5);
512 Signature.WriteTypeSpec(this, spec, type);
513 token = 0x1B000000 | this.TypeSpec.AddRecord(this.Blobs.Add(spec));
514 memberRefTypeTokens.Add(type, token);
518 else if (type.IsModulePseudoType)
520 return 0x1A000000 | this.ModuleRef.FindOrAddRecord(this.Strings.Add(type.Module.ScopeName));
524 return GetTypeToken(type).Token;
528 private static bool IsFromGenericTypeDefinition(MemberInfo member)
530 Type decl = member.DeclaringType;
531 return decl != null && !decl.__IsMissing && decl.IsGenericTypeDefinition;
534 public FieldToken GetFieldToken(FieldInfo field)
536 // NOTE for some reason, when TypeBuilder.GetFieldToken() is used on a field in a generic type definition,
537 // a memberref token is returned (confirmed on .NET) unlike for Get(Method|Constructor)Token which always
538 // simply returns the MethodDef token (if the method is from the same module).
539 FieldBuilder fb = field as FieldBuilder;
540 if (fb != null && fb.Module == this && !IsFromGenericTypeDefinition(fb))
542 return new FieldToken(fb.MetadataToken);
546 return new FieldToken(ImportMember(field));
550 public MethodToken GetMethodToken(MethodInfo method)
552 MethodBuilder mb = method as MethodBuilder;
553 if (mb != null && mb.ModuleBuilder == this)
555 return new MethodToken(mb.MetadataToken);
559 return new MethodToken(ImportMember(method));
563 // when we refer to a method on a generic type definition in the IL stream,
564 // we need to use a MemberRef (even if the method is in the same module)
565 internal MethodToken GetMethodTokenForIL(MethodInfo method)
567 if (method.IsGenericMethodDefinition)
569 method = method.MakeGenericMethod(method.GetGenericArguments());
571 if (IsFromGenericTypeDefinition(method))
573 return new MethodToken(ImportMember(method));
577 return GetMethodToken(method);
581 public MethodToken GetConstructorToken(ConstructorInfo constructor)
583 if (constructor.Module == this && constructor.GetMethodInfo() is MethodBuilder)
585 return new MethodToken(constructor.MetadataToken);
589 return new MethodToken(ImportMember(constructor));
593 internal int ImportMember(MethodBase member)
596 if (!importedMembers.TryGetValue(member, out token))
598 token = member.ImportTo(this);
599 importedMembers.Add(member, token);
604 internal int ImportMember(FieldInfo member)
607 if (!importedMembers.TryGetValue(member, out token))
609 token = member.ImportTo(this);
610 importedMembers.Add(member, token);
615 internal int ImportMethodOrField(Type declaringType, string name, Signature sig)
618 if (!importedMemberRefs.TryGetValue(new MemberRefKey(declaringType, name, sig), out token))
620 MemberRefTable.Record rec = new MemberRefTable.Record();
621 rec.Class = GetTypeTokenForMemberRef(declaringType);
622 rec.Name = this.Strings.Add(name);
623 ByteBuffer bb = new ByteBuffer(16);
624 sig.WriteSig(this, bb);
625 rec.Signature = this.Blobs.Add(bb);
626 token = 0x0A000000 | this.MemberRef.AddRecord(rec);
627 importedMemberRefs.Add(new MemberRefKey(declaringType, name, sig), token);
632 internal int ImportType(Type type)
635 if (!typeTokens.TryGetValue(type, out token))
637 if (type.HasElementType || type.IsGenericTypeInstance)
639 ByteBuffer spec = new ByteBuffer(5);
640 Signature.WriteTypeSpec(this, spec, type);
641 token = 0x1B000000 | this.TypeSpec.AddRecord(this.Blobs.Add(spec));
645 TypeRefTable.Record rec = new TypeRefTable.Record();
648 rec.ResolutionScope = GetTypeToken(type.DeclaringType).Token;
652 rec.ResolutionScope = ImportAssemblyRef(type.Assembly);
654 rec.TypeName = this.Strings.Add(type.__Name);
655 string ns = type.__Namespace;
656 rec.TypeNameSpace = ns == null ? 0 : this.Strings.Add(ns);
657 token = 0x01000000 | this.TypeRef.AddRecord(rec);
659 typeTokens.Add(type, token);
664 private int ImportAssemblyRef(Assembly asm)
667 if (!referencedAssemblies.TryGetValue(asm, out token))
669 // We can't write the AssemblyRef record here yet, because the identity of the assembly can still change
670 // (if it's an AssemblyBuilder).
671 // We set the high bit of rid in the token to make sure we emit obviously broken metadata,
672 // if we forget to patch up the token somewhere.
673 token = 0x23800001 + referencedAssemblies.Count;
674 referencedAssemblies.Add(asm, token);
679 internal void FillAssemblyRefTable()
681 int[] realtokens = new int[referencedAssemblies.Count];
682 foreach (KeyValuePair<Assembly, int> kv in referencedAssemblies)
684 if ((kv.Value & 0x7F800000) == 0x23800000)
686 realtokens[(kv.Value & 0x7FFFFF) - 1] = FindOrAddAssemblyRef(kv.Key.GetName(), false);
689 // now fixup the resolution scopes in TypeRef
690 for (int i = 0; i < this.TypeRef.records.Length; i++)
692 int resolutionScope = this.TypeRef.records[i].ResolutionScope;
693 if ((resolutionScope & 0x7F800000) == 0x23800000)
695 this.TypeRef.records[i].ResolutionScope = realtokens[(resolutionScope & 0x7FFFFF) - 1];
698 // and implementation in ExportedType
699 for (int i = 0; i < this.ExportedType.records.Length; i++)
701 int implementation = this.ExportedType.records[i].Implementation;
702 if ((implementation & 0x7F800000) == 0x23800000)
704 this.ExportedType.records[i].Implementation = realtokens[(implementation & 0x7FFFFF) - 1];
709 private int FindOrAddAssemblyRef(AssemblyName name, bool alwaysAdd)
711 AssemblyRefTable.Record rec = new AssemblyRefTable.Record();
712 Version ver = name.Version ?? new Version(0, 0, 0, 0);
713 rec.MajorVersion = (ushort)ver.Major;
714 rec.MinorVersion = (ushort)ver.Minor;
715 rec.BuildNumber = (ushort)ver.Build;
716 rec.RevisionNumber = (ushort)ver.Revision;
717 rec.Flags = (int)(name.Flags & AssemblyNameFlags.Retargetable);
718 byte[] publicKeyOrToken = null;
719 if (usePublicKeyAssemblyReference)
721 publicKeyOrToken = name.GetPublicKey();
723 if (publicKeyOrToken == null || publicKeyOrToken.Length == 0)
725 publicKeyOrToken = name.GetPublicKeyToken() ?? Empty<byte>.Array;
729 const int PublicKey = 0x0001;
730 rec.Flags |= PublicKey;
732 rec.PublicKeyOrToken = this.Blobs.Add(ByteBuffer.Wrap(publicKeyOrToken));
733 rec.Name = this.Strings.Add(name.Name);
734 if (name.CultureInfo != null)
736 rec.Culture = this.Strings.Add(name.CultureInfo.Name);
742 if (name.hash != null)
744 rec.HashValue = this.Blobs.Add(ByteBuffer.Wrap(name.hash));
750 return 0x23000000 | (alwaysAdd ? this.AssemblyRef.AddRecord(rec) : this.AssemblyRef.FindOrAddRecord(rec));
753 internal void WriteSymbolTokenMap()
755 for (int i = 0; i < resolvedTokens.Count; i++)
757 int newToken = resolvedTokens[i];
758 // The symbol API doesn't support remapping arbitrary integers, the types have to be the same,
759 // so we copy the type from the newToken, because our pseudo tokens don't have a type.
760 // (see MethodToken.SymbolToken)
761 int oldToken = (i + 1) | (newToken & ~0xFFFFFF);
762 SymbolSupport.RemapToken(symbolWriter, oldToken, newToken);
766 internal void RegisterTokenFixup(int pseudoToken, int realToken)
768 int index = -(pseudoToken + 1);
769 while (resolvedTokens.Count <= index)
771 resolvedTokens.Add(0);
773 resolvedTokens[index] = realToken;
776 internal bool IsPseudoToken(int token)
781 internal int ResolvePseudoToken(int pseudoToken)
783 int index = -(pseudoToken + 1);
784 return resolvedTokens[index];
787 internal void ApplyUnmanagedExports(ImageFileMachine imageFileMachine)
789 if (unmanagedExports.Count != 0)
793 if (imageFileMachine == ImageFileMachine.I386)
803 List<MethodBuilder> methods = new List<MethodBuilder>();
804 for (int i = 0; i < unmanagedExports.Count; i++)
806 if (unmanagedExports[i].mb != null)
808 methods.Add(unmanagedExports[i].mb);
811 if (methods.Count != 0)
813 RelativeVirtualAddress rva = __AddVTableFixups(methods.ToArray(), type);
814 for (int i = 0; i < unmanagedExports.Count; i++)
816 if (unmanagedExports[i].mb != null)
818 UnmanagedExport exp = unmanagedExports[i];
819 exp.rva = new RelativeVirtualAddress(rva.initializedDataOffset + (uint)(methods.IndexOf(unmanagedExports[i].mb) * size));
820 unmanagedExports[i] = exp;
827 internal void FixupMethodBodyTokens()
829 int methodToken = 0x06000001;
830 int fieldToken = 0x04000001;
831 int parameterToken = 0x08000001;
832 foreach (TypeBuilder type in types)
834 type.ResolveMethodAndFieldTokens(ref methodToken, ref fieldToken, ref parameterToken);
836 foreach (int offset in tokenFixupOffsets)
838 methodBodies.Position = offset;
839 int pseudoToken = methodBodies.GetInt32AtCurrentPosition();
840 methodBodies.Write(ResolvePseudoToken(pseudoToken));
842 foreach (VTableFixups fixup in vtablefixups)
844 for (int i = 0; i < fixup.count; i++)
846 initializedData.Position = (int)fixup.initializedDataOffset + i * fixup.SlotWidth;
847 initializedData.Write(ResolvePseudoToken(initializedData.GetInt32AtCurrentPosition()));
852 private int GetHeaderLength()
859 4 + // ImageRuntimeVersion Length
860 StringToPaddedUTF8Length(asm.ImageRuntimeVersion) +
865 4 + // StringToPaddedUTF8Length("#~")
866 4 + // #Strings Offset
868 12 + // StringToPaddedUTF8Length("#Strings")
871 4 + // StringToPaddedUTF8Length("#US")
874 8 + // StringToPaddedUTF8Length("#GUID")
879 8 // StringToPaddedUTF8Length("#Blob")
883 internal int MetadataLength
887 return GetHeaderLength() + (Blobs.IsEmpty ? 0 : Blobs.Length) + Tables.Length + Strings.Length + UserStrings.Length + Guids.Length;
891 internal void WriteMetadata(MetadataWriter mw)
893 mw.Write(0x424A5342); // Signature ("BSJB")
894 mw.Write((ushort)1); // MajorVersion
895 mw.Write((ushort)1); // MinorVersion
896 mw.Write(0); // Reserved
897 byte[] version = StringToPaddedUTF8(asm.ImageRuntimeVersion);
898 mw.Write(version.Length); // Length
900 mw.Write((ushort)0); // Flags
901 // #Blob is the only optional heap
904 mw.Write((ushort)4); // Streams
908 mw.Write((ushort)5); // Streams
911 int offset = GetHeaderLength();
914 mw.Write(offset); // Offset
915 mw.Write(Tables.Length); // Size
916 mw.Write(StringToPaddedUTF8("#~"));
917 offset += Tables.Length;
919 mw.Write(offset); // Offset
920 mw.Write(Strings.Length); // Size
921 mw.Write(StringToPaddedUTF8("#Strings"));
922 offset += Strings.Length;
924 mw.Write(offset); // Offset
925 mw.Write(UserStrings.Length); // Size
926 mw.Write(StringToPaddedUTF8("#US"));
927 offset += UserStrings.Length;
929 mw.Write(offset); // Offset
930 mw.Write(Guids.Length); // Size
931 mw.Write(StringToPaddedUTF8("#GUID"));
932 offset += Guids.Length;
936 mw.Write(offset); // Offset
937 mw.Write(Blobs.Length); // Size
938 mw.Write(StringToPaddedUTF8("#Blob"));
943 UserStrings.Write(mw);
951 private static int StringToPaddedUTF8Length(string str)
953 return (System.Text.Encoding.UTF8.GetByteCount(str) + 4) & ~3;
956 private static byte[] StringToPaddedUTF8(string str)
958 byte[] buf = new byte[(System.Text.Encoding.UTF8.GetByteCount(str) + 4) & ~3];
959 System.Text.Encoding.UTF8.GetBytes(str, 0, str.Length, buf, 0);
963 internal override void ExportTypes(int fileToken, ModuleBuilder manifestModule)
965 manifestModule.ExportTypes(types.ToArray(), fileToken);
968 internal void ExportTypes(Type[] types, int fileToken)
970 Dictionary<Type, int> declaringTypes = new Dictionary<Type, int>();
971 foreach (Type type in types)
973 if (!type.IsModulePseudoType && IsVisible(type))
975 ExportedTypeTable.Record rec = new ExportedTypeTable.Record();
976 rec.Flags = (int)type.Attributes;
977 rec.TypeDefId = type.MetadataToken & 0xFFFFFF;
978 rec.TypeName = this.Strings.Add(type.__Name);
979 string ns = type.__Namespace;
980 rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(ns);
983 rec.Implementation = declaringTypes[type.DeclaringType];
987 rec.Implementation = fileToken;
989 int exportTypeToken = 0x27000000 | this.ExportedType.AddRecord(rec);
990 declaringTypes.Add(type, exportTypeToken);
995 private static bool IsVisible(Type type)
997 // NOTE this is not the same as Type.IsVisible, because that doesn't take into account family access
998 return type.IsPublic || ((type.IsNestedFamily || type.IsNestedFamORAssem || type.IsNestedPublic) && IsVisible(type.DeclaringType));
1001 internal void AddConstant(int parentToken, object defaultValue)
1003 ConstantTable.Record rec = new ConstantTable.Record();
1004 rec.Parent = parentToken;
1005 ByteBuffer val = new ByteBuffer(16);
1006 if (defaultValue == null)
1008 rec.Type = Signature.ELEMENT_TYPE_CLASS;
1011 else if (defaultValue is bool)
1013 rec.Type = Signature.ELEMENT_TYPE_BOOLEAN;
1014 val.Write((bool)defaultValue ? (byte)1 : (byte)0);
1016 else if (defaultValue is char)
1018 rec.Type = Signature.ELEMENT_TYPE_CHAR;
1019 val.Write((char)defaultValue);
1021 else if (defaultValue is sbyte)
1023 rec.Type = Signature.ELEMENT_TYPE_I1;
1024 val.Write((sbyte)defaultValue);
1026 else if (defaultValue is byte)
1028 rec.Type = Signature.ELEMENT_TYPE_U1;
1029 val.Write((byte)defaultValue);
1031 else if (defaultValue is short)
1033 rec.Type = Signature.ELEMENT_TYPE_I2;
1034 val.Write((short)defaultValue);
1036 else if (defaultValue is ushort)
1038 rec.Type = Signature.ELEMENT_TYPE_U2;
1039 val.Write((ushort)defaultValue);
1041 else if (defaultValue is int)
1043 rec.Type = Signature.ELEMENT_TYPE_I4;
1044 val.Write((int)defaultValue);
1046 else if (defaultValue is uint)
1048 rec.Type = Signature.ELEMENT_TYPE_U4;
1049 val.Write((uint)defaultValue);
1051 else if (defaultValue is long)
1053 rec.Type = Signature.ELEMENT_TYPE_I8;
1054 val.Write((long)defaultValue);
1056 else if (defaultValue is ulong)
1058 rec.Type = Signature.ELEMENT_TYPE_U8;
1059 val.Write((ulong)defaultValue);
1061 else if (defaultValue is float)
1063 rec.Type = Signature.ELEMENT_TYPE_R4;
1064 val.Write((float)defaultValue);
1066 else if (defaultValue is double)
1068 rec.Type = Signature.ELEMENT_TYPE_R8;
1069 val.Write((double)defaultValue);
1071 else if (defaultValue is string)
1073 rec.Type = Signature.ELEMENT_TYPE_STRING;
1074 foreach (char c in (string)defaultValue)
1079 else if (defaultValue is DateTime)
1081 rec.Type = Signature.ELEMENT_TYPE_I8;
1082 val.Write(((DateTime)defaultValue).Ticks);
1086 throw new ArgumentException();
1088 rec.Value = this.Blobs.Add(val);
1089 this.Constant.AddRecord(rec);
1092 ModuleBuilder ITypeOwner.ModuleBuilder
1094 get { return this; }
1097 public override Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1099 if (genericTypeArguments != null || genericMethodArguments != null)
1101 throw new NotImplementedException();
1103 return types[(metadataToken & 0xFFFFFF) - 1];
1106 public override MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1108 if (genericTypeArguments != null || genericMethodArguments != null)
1110 throw new NotImplementedException();
1112 // this method is inefficient, but since it isn't used we don't care
1113 if ((metadataToken >> 24) == MemberRefTable.Index)
1115 foreach (KeyValuePair<MemberInfo, int> kv in importedMembers)
1117 if (kv.Value == metadataToken)
1119 return (MethodBase)kv.Key;
1123 // HACK if we're given a SymbolToken, we need to convert back
1124 if ((metadataToken & 0xFF000000) == 0x06000000)
1126 metadataToken = -(metadataToken & 0x00FFFFFF);
1128 foreach (Type type in types)
1130 MethodBase method = ((TypeBuilder)type).LookupMethod(metadataToken);
1136 return ((TypeBuilder)moduleType).LookupMethod(metadataToken);
1139 public override FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1141 throw new NotImplementedException();
1144 public override MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
1146 throw new NotImplementedException();
1149 public override string ResolveString(int metadataToken)
1151 throw new NotImplementedException();
1154 public override string FullyQualifiedName
1156 get { return Path.GetFullPath(Path.Combine(asm.dir, fileName)); }
1159 public override string Name
1161 get { return fileName; }
1164 public override Guid ModuleVersionId
1166 get { return mvid; }
1169 public void __SetModuleVersionId(Guid guid)
1174 public override Type[] __ResolveOptionalParameterTypes(int metadataToken)
1176 throw new NotImplementedException();
1179 public override string ScopeName
1181 get { return moduleName; }
1184 public ISymbolWriter GetSymWriter()
1186 return symbolWriter;
1189 public void DefineUnmanagedResource(string resourceFileName)
1191 // This method reads the specified resource file (Win32 .res file) and converts it into the appropriate format and embeds it in the .rsrc section,
1192 // also setting the Resource Directory entry.
1193 unmanagedResources = new ResourceSection();
1194 unmanagedResources.ExtractResources(System.IO.File.ReadAllBytes(resourceFileName));
1197 public bool IsTransient()
1202 public void SetUserEntryPoint(MethodInfo entryPoint)
1204 int token = entryPoint.MetadataToken;
1207 token = -token | 0x06000000;
1209 if (symbolWriter != null)
1211 symbolWriter.SetUserEntryPoint(new SymbolToken(token));
1215 public StringToken GetStringConstant(string str)
1217 return new StringToken(this.UserStrings.Add(str) | (0x70 << 24));
1220 public SignatureToken GetSignatureToken(SignatureHelper sigHelper)
1222 return new SignatureToken(this.StandAloneSig.FindOrAddRecord(this.Blobs.Add(sigHelper.GetSignature(this))) | (StandAloneSigTable.Index << 24));
1225 public SignatureToken GetSignatureToken(byte[] sigBytes, int sigLength)
1227 return new SignatureToken(this.StandAloneSig.FindOrAddRecord(this.Blobs.Add(ByteBuffer.Wrap(sigBytes, sigLength))) | (StandAloneSigTable.Index << 24));
1230 public MethodInfo GetArrayMethod(Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
1232 return new ArrayMethod(this, arrayClass, methodName, callingConvention, returnType, parameterTypes);
1235 public MethodToken GetArrayMethodToken(Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
1237 return GetMethodToken(GetArrayMethod(arrayClass, methodName, callingConvention, returnType, parameterTypes));
1240 internal override Type GetModuleType()
1245 internal override IKVM.Reflection.Reader.ByteReader GetBlob(int blobIndex)
1247 return Blobs.GetBlob(blobIndex);
1250 internal int GetSignatureBlobIndex(Signature sig)
1252 ByteBuffer bb = new ByteBuffer(16);
1253 sig.WriteSig(this, bb);
1254 return this.Blobs.Add(bb);
1258 public new long __ImageBase
1260 get { return imageBaseAddress; }
1261 set { imageBaseAddress = value; }
1264 protected override long GetImageBaseImpl()
1266 return imageBaseAddress;
1269 public override long __StackReserve
1271 get { return stackReserve; }
1274 public void __SetStackReserve(long stackReserve)
1276 this.stackReserve = stackReserve;
1279 internal ulong GetStackReserve(ulong defaultValue)
1281 return stackReserve == -1 ? defaultValue : (ulong)stackReserve;
1284 public override int MDStreamVersion
1286 get { return asm.mdStreamVersion; }
1289 private int AddTypeRefByName(int resolutionScope, string ns, string name)
1291 TypeRefTable.Record rec = new TypeRefTable.Record();
1292 rec.ResolutionScope = resolutionScope;
1293 rec.TypeName = this.Strings.Add(name);
1294 rec.TypeNameSpace = ns == null ? 0 : this.Strings.Add(ns);
1295 return 0x01000000 | this.TypeRef.AddRecord(rec);
1298 public void __Save(PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
1300 SaveImpl(null, portableExecutableKind, imageFileMachine);
1303 public void __Save(Stream stream, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
1305 if (!stream.CanRead || !stream.CanWrite || !stream.CanSeek || stream.Position != 0)
1307 throw new ArgumentException("Stream must support read/write/seek and current position must be zero.", "stream");
1309 SaveImpl(stream, portableExecutableKind, imageFileMachine);
1312 private void SaveImpl(Stream streamOrNull, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
1314 PopulatePropertyAndEventTables();
1315 IList<CustomAttributeData> attributes = asm.GetCustomAttributesData(null);
1316 if (attributes.Count > 0)
1318 int mscorlib = ImportAssemblyRef(universe.Mscorlib);
1319 int[] placeholderTokens = new int[4];
1320 string[] placeholderTypeNames = new string[] { "AssemblyAttributesGoHere", "AssemblyAttributesGoHereM", "AssemblyAttributesGoHereS", "AssemblyAttributesGoHereSM" };
1321 foreach (CustomAttributeData cad in attributes)
1324 if (cad.Constructor.DeclaringType.BaseType == universe.System_Security_Permissions_CodeAccessSecurityAttribute)
1326 if (cad.Constructor.DeclaringType.IsAllowMultipleCustomAttribute)
1335 else if (cad.Constructor.DeclaringType.IsAllowMultipleCustomAttribute)
1343 if (placeholderTokens[index] == 0)
1345 // we manually add a TypeRef without looking it up in mscorlib, because Mono and Silverlight's mscorlib don't have these types
1346 placeholderTokens[index] = AddTypeRefByName(mscorlib, "System.Runtime.CompilerServices", placeholderTypeNames[index]);
1348 SetCustomAttribute(placeholderTokens[index], cad.__ToBuilder());
1351 FillAssemblyRefTable();
1352 ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, unmanagedResources, 0, streamOrNull);
1355 public void __AddAssemblyReference(AssemblyName assemblyName)
1357 __AddAssemblyReference(assemblyName, null);
1360 public void __AddAssemblyReference(AssemblyName assemblyName, Assembly assembly)
1362 if (referencedAssemblyNames == null)
1364 referencedAssemblyNames = new List<AssemblyName>();
1366 referencedAssemblyNames.Add((AssemblyName)assemblyName.Clone());
1367 int token = FindOrAddAssemblyRef(assemblyName, true);
1368 if (assembly != null)
1370 referencedAssemblies.Add(assembly, token);
1374 public override AssemblyName[] __GetReferencedAssemblies()
1376 List<AssemblyName> list = new List<AssemblyName>();
1377 if (referencedAssemblyNames != null)
1379 foreach (AssemblyName name in referencedAssemblyNames)
1381 if (!list.Contains(name))
1387 foreach (Assembly asm in referencedAssemblies.Keys)
1389 AssemblyName name = asm.GetName();
1390 if (!list.Contains(name))
1395 return list.ToArray();
1398 public void __AddModuleReference(string module)
1400 this.ModuleRef.FindOrAddRecord(module == null ? 0 : this.Strings.Add(module));
1403 public override string[] __GetReferencedModules()
1405 string[] arr = new string[this.ModuleRef.RowCount];
1406 for (int i = 0; i < arr.Length; i++)
1408 arr[i] = this.Strings.Find(this.ModuleRef.records[i]);
1413 public override Type[] __GetReferencedTypes()
1415 List<Type> list = new List<Type>();
1416 foreach (KeyValuePair<Type, int> kv in typeTokens)
1418 if (kv.Value >> 24 == TypeRefTable.Index)
1423 return list.ToArray();
1426 public override Type[] __GetExportedTypes()
1428 throw new NotImplementedException();
1431 public int __AddModule(int flags, string name, byte[] hash)
1433 FileTable.Record file = new FileTable.Record();
1435 file.Name = this.Strings.Add(name);
1436 file.HashValue = this.Blobs.Add(ByteBuffer.Wrap(hash));
1437 return 0x26000000 + this.File.AddRecord(file);
1440 public int __AddManifestResource(int offset, ResourceAttributes flags, string name, int implementation)
1442 ManifestResourceTable.Record res = new ManifestResourceTable.Record();
1443 res.Offset = offset;
1444 res.Flags = (int)flags;
1445 res.Name = this.Strings.Add(name);
1446 res.Implementation = implementation;
1447 return 0x28000000 + this.ManifestResource.AddRecord(res);
1450 public void __SetCustomAttributeFor(int token, CustomAttributeBuilder customBuilder)
1452 SetCustomAttribute(token, customBuilder);
1455 public RelativeVirtualAddress __AddVTableFixups(MethodBuilder[] methods, int type)
1457 initializedData.Align(8);
1458 VTableFixups fixups;
1459 fixups.initializedDataOffset = (uint)initializedData.Position;
1460 fixups.count = (ushort)methods.Length;
1461 fixups.type = (ushort)type;
1462 foreach (MethodBuilder mb in methods)
1464 initializedData.Write(mb.MetadataToken);
1465 if (fixups.SlotWidth == 8)
1467 initializedData.Write(0);
1470 vtablefixups.Add(fixups);
1471 return new RelativeVirtualAddress(fixups.initializedDataOffset);
1474 public void __AddUnmanagedExportStub(string name, int ordinal, RelativeVirtualAddress rva)
1476 AddUnmanagedExport(name, ordinal, null, rva);
1479 internal void AddUnmanagedExport(string name, int ordinal, MethodBuilder methodBuilder, RelativeVirtualAddress rva)
1481 UnmanagedExport export;
1483 export.ordinal = ordinal;
1484 export.mb = methodBuilder;
1486 unmanagedExports.Add(export);
1490 struct UnmanagedExport
1492 internal string name;
1493 internal int ordinal;
1494 internal RelativeVirtualAddress rva;
1495 internal MethodBuilder mb;
1498 public struct RelativeVirtualAddress
1500 internal readonly uint initializedDataOffset;
1502 internal RelativeVirtualAddress(uint initializedDataOffset)
1504 this.initializedDataOffset = initializedDataOffset;
1507 public static RelativeVirtualAddress operator +(RelativeVirtualAddress rva, int offset)
1509 return new RelativeVirtualAddress(rva.initializedDataOffset + (uint)offset);
1513 class ArrayMethod : MethodInfo
1515 private readonly Module module;
1516 private readonly Type arrayClass;
1517 private readonly string methodName;
1518 private readonly CallingConventions callingConvention;
1519 private readonly Type returnType;
1520 protected readonly Type[] parameterTypes;
1521 private MethodSignature methodSignature;
1523 internal ArrayMethod(Module module, Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
1525 this.module = module;
1526 this.arrayClass = arrayClass;
1527 this.methodName = methodName;
1528 this.callingConvention = callingConvention;
1529 this.returnType = returnType ?? module.universe.System_Void;
1530 this.parameterTypes = Util.Copy(parameterTypes);
1533 public override MethodBody GetMethodBody()
1535 throw new InvalidOperationException();
1538 public override MethodImplAttributes GetMethodImplementationFlags()
1540 throw new NotSupportedException();
1543 public override ParameterInfo[] GetParameters()
1545 throw new NotSupportedException();
1548 internal override int ImportTo(ModuleBuilder module)
1550 return module.ImportMethodOrField(arrayClass, methodName, MethodSignature);
1553 public override MethodAttributes Attributes
1555 get { throw new NotSupportedException(); }
1558 public override CallingConventions CallingConvention
1560 get { return callingConvention; }
1563 public override Type DeclaringType
1565 get { return arrayClass; }
1568 internal override MethodSignature MethodSignature
1572 if (methodSignature == null)
1574 methodSignature = MethodSignature.MakeFromBuilder(returnType, parameterTypes, null, callingConvention, 0);
1576 return methodSignature;
1580 public override Module Module
1582 // like .NET, we return the module that GetArrayMethod was called on, not the module associated with the array type
1583 get { return module; }
1586 public override string Name
1588 get { return methodName; }
1591 internal override int ParameterCount
1593 get { return parameterTypes.Length; }
1596 public override ParameterInfo ReturnParameter
1598 get { throw new NotImplementedException(); }
1601 public override Type ReturnType
1603 get { return returnType; }
1606 internal override bool HasThis
1608 get { return (callingConvention & (CallingConventions.HasThis | CallingConventions.ExplicitThis)) == CallingConventions.HasThis; }