context: /*
    Copyright (C) 2008-2012 Jeroen Frijters
  
    This software is provided 'as-is', without any express or implied
    warranty.  In no event will the authors be held liable for any damages
    arising from the use of this software.
  
    Permission is granted to anyone to use this software for any purpose,
    including commercial applications, and to alter it and redistribute it
    freely, subject to the following restrictions:
  
    1. The origin of this software must not be misrepresented; you must not
       claim that you wrote the original software. If you use this software
       in a product, an acknowledgment in the product documentation would be
       appreciated but is not required.
    2. Altered source versions must be plainly marked as such, and must not be
       misrepresented as being the original software.
    3. This notice may not be removed or altered from any source distribution.
  
    Jeroen Frijters
    jeroen@frijters.net
    
  */
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Diagnostics;
  using System.Diagnostics.SymbolStore;
  using System.Security.Cryptography;
  using System.Runtime.CompilerServices;
  using System.Runtime.InteropServices;
  using IKVM.Reflection.Impl;
  using IKVM.Reflection.Metadata;
  using IKVM.Reflection.Writer;
  
  namespace IKVM.Reflection.Emit
  {
  	public sealed class ModuleBuilder : Module, ITypeOwner
  	{
  		private static readonly bool usePublicKeyAssemblyReference = false;
  		private Guid mvid = Guid.NewGuid();
  		private long imageBaseAddress = 0x00400000;
  		private long stackReserve = -1;
  		private int fileAlignment = 0x200;
  		private DllCharacteristics dllCharacteristics = DllCharacteristics.DynamicBase | DllCharacteristics.NoSEH | DllCharacteristics.NXCompat | DllCharacteristics.TerminalServerAware;
  		private readonly AssemblyBuilder asm;
  		internal readonly string moduleName;
  		internal readonly string fileName;
  		internal readonly ISymbolWriterImpl symbolWriter;
  		private readonly TypeBuilder moduleType;
  		private readonly List<TypeBuilder> types = new List<TypeBuilder>();
  		private readonly Dictionary<Type, int> typeTokens = new Dictionary<Type, int>();
  		private readonly Dictionary<Type, int> memberRefTypeTokens = new Dictionary<Type, int>();
  		internal readonly ByteBuffer methodBodies = new ByteBuffer(128 * 1024);
  		internal readonly List<int> tokenFixupOffsets = new List<int>();
  		internal readonly ByteBuffer initializedData = new ByteBuffer(512);
  		internal readonly ByteBuffer manifestResources = new ByteBuffer(512);
  		internal ResourceSection unmanagedResources;
  		private readonly Dictionary<MemberInfo, int> importedMembers = new Dictionary<MemberInfo, int>();
  		private readonly Dictionary<MemberRefKey, int> importedMemberRefs = new Dictionary<MemberRefKey, int>();
  		private readonly Dictionary<Assembly, int> referencedAssemblies = new Dictionary<Assembly, int>();
  		private List<AssemblyName> referencedAssemblyNames;
  		private int nextPseudoToken = -1;
  		private readonly List<int> resolvedTokens = new List<int>();
  		internal readonly TableHeap Tables = new TableHeap();
  		internal readonly StringHeap Strings = new StringHeap();
  		internal readonly UserStringHeap UserStrings = new UserStringHeap();
  		internal readonly GuidHeap Guids = new GuidHeap();
  		internal readonly BlobHeap Blobs = new BlobHeap();
  		internal readonly List<VTableFixups> vtablefixups = new List<VTableFixups>();
  		internal readonly List<UnmanagedExport> unmanagedExports = new List<UnmanagedExport>();
  		private List<InterfaceImplCustomAttribute> interfaceImplCustomAttributes;
  
  		internal struct VTableFixups
  		{
  			internal uint initializedDataOffset;
  			internal ushort count;
  			internal ushort type;
  
  			internal int SlotWidth
  			{
  				get { return (type & 0x02) == 0 ? 4 : 8; }
  			}
  		}
  
  		struct InterfaceImplCustomAttribute
  		{
  			internal int type;
  			internal int interfaceType;
  			internal int pseudoToken;
  		}
  
  		struct MemberRefKey : IEquatable<MemberRefKey>
  		{
  			private readonly Type type;
  			private readonly string name;
  			private readonly Signature signature;
  
  			internal MemberRefKey(Type type, string name, Signature signature)
  			{
  				this.type = type;
  				this.name = name;
  				this.signature = signature;
  			}
  
  			public bool Equals(MemberRefKey other)
  			{
  				return other.type.Equals(type)
  					&& other.name == name
  					&& other.signature.Equals(signature);
  			}
  
  			public override bool Equals(object obj)
  			{
  				MemberRefKey? other = obj as MemberRefKey?;
  				return other != null && Equals(other);
  			}
  
  			public override int GetHashCode()
  			{
  				return type.GetHashCode() + name.GetHashCode() + signature.GetHashCode();
  			}
  		}
  
  		internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, bool emitSymbolInfo)
  			: base(asm.universe)
  		{
  			this.asm = asm;
  			this.moduleName = moduleName;
  			this.fileName = fileName;
  			if (emitSymbolInfo)
  			{
  				symbolWriter = SymbolSupport.CreateSymbolWriterFor(this);
  			}
  			// <Module> must be the first record in the TypeDef table
  			moduleType = new TypeBuilder(this, null, "<Module>");
  			types.Add(moduleType);
  		}
  
  		internal void PopulatePropertyAndEventTables()
  		{
  			// LAMESPEC the PropertyMap and EventMap tables are not required to be sorted by the CLI spec,
  			// but .NET sorts them and Mono requires them to be sorted, so we have to populate the
  			// tables in the right order
  			foreach (TypeBuilder type in types)
  			{
  				type.PopulatePropertyAndEventTables();
  			}
  		}
  
  		internal void WriteTypeDefTable(MetadataWriter mw)
  		{
  			int fieldList = 1;
  			int methodList = 1;
  			foreach (TypeBuilder type in types)
  			{
  				type.WriteTypeDefRecord(mw, ref fieldList, ref methodList);
  			}
  		}
  
  		internal void WriteMethodDefTable(int baseRVA, MetadataWriter mw)
  		{
  			int paramList = 1;
  			foreach (TypeBuilder type in types)
  			{
  				type.WriteMethodDefRecords(baseRVA, mw, ref paramList);
  			}
  		}
  
  		internal void WriteParamTable(MetadataWriter mw)
  		{
  			foreach (TypeBuilder type in types)
  			{
  				type.WriteParamRecords(mw);
  			}
  		}
  
  		internal void WriteFieldTable(MetadataWriter mw)
  		{
  			foreach (TypeBuilder type in types)
  			{
  				type.WriteFieldRecords(mw);
  			}
  		}
  
  		internal int AllocPseudoToken()
  		{
  			return nextPseudoToken--;
  		}
  
  		public TypeBuilder DefineType(string name)
  		{
  			return DefineType(name, TypeAttributes.Class);
  		}
  
  		public TypeBuilder DefineType(string name, TypeAttributes attr)
  		{
  			return DefineType(name, attr, null);
  		}
  
  		public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent)
  		{
  			return DefineType(name, attr, parent, PackingSize.Unspecified, 0);
  		}
  
  		public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, int typesize)
  		{
  			return DefineType(name, attr, parent, PackingSize.Unspecified, typesize);
  		}
  
  		public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, PackingSize packsize)
  		{
  			return DefineType(name, attr, parent, packsize, 0);
  		}
  
  		public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, Type[] interfaces)
  		{
  			TypeBuilder tb = DefineType(name, attr, parent);
  			foreach (Type iface in interfaces)
  			{
  				tb.AddInterfaceImplementation(iface);
  			}
  			return tb;
  		}
  
  		public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, PackingSize packingSize, int typesize)
  		{
  			string ns = null;
  			int lastdot = name.LastIndexOf('.');
  			if (lastdot > 0)
  			{
  				ns = name.Substring(0, lastdot);
  				name = name.Substring(lastdot + 1);
  			}
  			TypeBuilder typeBuilder = __DefineType(ns, name);
  			typeBuilder.__SetAttributes(attr);
  			typeBuilder.SetParent(parent);
  			if (packingSize != PackingSize.Unspecified || typesize != 0)
  			{
  				typeBuilder.__SetLayout((int)packingSize, typesize);
  			}
  			return typeBuilder;
  		}
  
  		public TypeBuilder __DefineType(string ns, string name)
  		{
  			return DefineType(this, ns, name);
  		}
  
  		internal TypeBuilder DefineType(ITypeOwner owner, string ns, string name)
  		{
  			TypeBuilder typeBuilder = new TypeBuilder(owner, ns, name);
  			types.Add(typeBuilder);
  			return typeBuilder;
  		}
  
  		public EnumBuilder DefineEnum(string name, TypeAttributes visibility, Type underlyingType)
  		{
  			TypeBuilder tb = DefineType(name, (visibility & TypeAttributes.VisibilityMask) | TypeAttributes.Sealed, universe.System_Enum);
  			FieldBuilder fb = tb.DefineField("value__", underlyingType, FieldAttributes.Public | FieldAttributes.SpecialName | FieldAttributes.RTSpecialName);
  			return new EnumBuilder(tb, fb);
  		}
  
  		public FieldBuilder __DefineField(string name, Type type, CustomModifiers customModifiers, FieldAttributes attributes)
  		{
  			return moduleType.__DefineField(name, type, customModifiers, attributes);
  		}
  
  		[Obsolete("Please use __DefineField(string, Type, CustomModifiers, FieldAttributes) instead.")]
  		public FieldBuilder __DefineField(string name, Type type, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers, FieldAttributes attributes)
  		{
  			return moduleType.DefineField(name, type, requiredCustomModifiers, optionalCustomModifiers, attributes);
  		}
  
  		public ConstructorBuilder __DefineModuleInitializer(MethodAttributes visibility)
  		{
  			return moduleType.DefineConstructor(visibility | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, Type.EmptyTypes);
  		}
  
  		public FieldBuilder DefineUninitializedData(string name, int size, FieldAttributes attributes)
  		{
  			return moduleType.DefineUninitializedData(name, size, attributes);
  		}
  
  		public FieldBuilder DefineInitializedData(string name, byte[] data, FieldAttributes attributes)
  		{
  			return moduleType.DefineInitializedData(name, data, attributes);
  		}
  
  		public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, Type returnType, Type[] parameterTypes)
  		{
  			return moduleType.DefineMethod(name, attributes, returnType, parameterTypes);
  		}
  
  		public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
  		{
  			return moduleType.DefineMethod(name, attributes, callingConvention, returnType, parameterTypes);
  		}
  
  		public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] requiredReturnTypeCustomModifiers, Type[] optionalReturnTypeCustomModifiers, Type[] parameterTypes, Type[][] requiredParameterTypeCustomModifiers, Type[][] optionalParameterTypeCustomModifiers)
  		{
  			return moduleType.DefineMethod(name, attributes, callingConvention, returnType, requiredReturnTypeCustomModifiers, optionalReturnTypeCustomModifiers, parameterTypes, requiredParameterTypeCustomModifiers, optionalParameterTypeCustomModifiers);
  		}
  
  		public MethodBuilder DefinePInvokeMethod(string name, string dllName, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, CallingConvention nativeCallConv, CharSet nativeCharSet)
  		{
  			return moduleType.DefinePInvokeMethod(name, dllName, attributes, callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet);
  		}
  
  		public MethodBuilder DefinePInvokeMethod(string name, string dllName, string entryName, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, CallingConvention nativeCallConv, CharSet nativeCharSet)
  		{
  			return moduleType.DefinePInvokeMethod(name, dllName, entryName, attributes, callingConvention, returnType, parameterTypes, nativeCallConv, nativeCharSet);
  		}
  
  		public void CreateGlobalFunctions()
  		{
  			moduleType.CreateType();
  		}
  
  		internal void AddTypeForwarder(Type type)
  		{
  			ExportType(type);
  			if (!type.__IsMissing)
  			{
  				foreach (Type nested in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
  				{
  					// we export all nested types (i.e. even the private ones)
  					// (this behavior is the same as the C# compiler)
  					AddTypeForwarder(nested);
  				}
  			}
  		}
  
  		private int ExportType(Type type)
  		{
  			ExportedTypeTable.Record rec = new ExportedTypeTable.Record();
  			rec.TypeDefId = type.MetadataToken;
  			rec.TypeName = this.Strings.Add(type.__Name);
  			string ns = type.__Namespace;
  			rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(ns);
  			if (type.IsNested)
  			{
  				rec.Flags = 0;
  				rec.Implementation = ExportType(type.DeclaringType);
  			}
  			else
  			{
  				rec.Flags = 0x00200000;	// CorTypeAttr.tdForwarder
  				rec.Implementation = ImportAssemblyRef(type.Assembly);
  			}
  			return 0x27000000 | this.ExportedType.FindOrAddRecord(rec);
  		}
  
  		public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
  		{
  			SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
  		}
  
  		public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
  		{
  			SetCustomAttribute(0x00000001, customBuilder);
  		}
  
  		internal void SetCustomAttribute(int token, CustomAttributeBuilder customBuilder)
  		{
  			Debug.Assert(!customBuilder.IsPseudoCustomAttribute);
  			CustomAttributeTable.Record rec = new CustomAttributeTable.Record();
  			rec.Parent = token;
  			rec.Type = this.GetConstructorToken(customBuilder.Constructor).Token;
  			rec.Value = customBuilder.WriteBlob(this);
  			this.CustomAttribute.AddRecord(rec);
  		}
  
  		internal void AddDeclarativeSecurity(int token, System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet)
  		{
  			DeclSecurityTable.Record rec = new DeclSecurityTable.Record();
  			rec.Action = (short)securityAction;
  			rec.Parent = token;
  			// like Ref.Emit, we're using the .NET 1.x xml format
  			rec.PermissionSet = this.Blobs.Add(ByteBuffer.Wrap(System.Text.Encoding.Unicode.GetBytes(permissionSet.ToXml().ToString())));
  			this.DeclSecurity.AddRecord(rec);
  		}
  
  		internal void AddDeclarativeSecurity(int token, List<CustomAttributeBuilder> declarativeSecurity)
  		{
  			Dictionary<int, List<CustomAttributeBuilder>> ordered = new Dictionary<int, List<CustomAttributeBuilder>>();
  			foreach (CustomAttributeBuilder cab in declarativeSecurity)
  			{
  				int action;
  				// check for HostProtectionAttribute without SecurityAction
  				if (cab.ConstructorArgumentCount == 0)
  				{
  					action = (int)System.Security.Permissions.SecurityAction.LinkDemand;
  				}
  				else
  				{
  					action = (int)cab.GetConstructorArgument(0);
  				}
  				List<CustomAttributeBuilder> list;
  				if (!ordered.TryGetValue(action, out list))
  				{
  					list = new List<CustomAttributeBuilder>();
  					ordered.Add(action, list);
  				}
  				list.Add(cab);
  			}
  			foreach (KeyValuePair<int, List<CustomAttributeBuilder>> kv in ordered)
  			{
  				DeclSecurityTable.Record rec = new DeclSecurityTable.Record();
  				rec.Action = (short)kv.Key;
  				rec.Parent = token;
  				rec.PermissionSet = WriteDeclSecurityBlob(kv.Value);
  				this.DeclSecurity.AddRecord(rec);
  			}
  		}
  
  		private int WriteDeclSecurityBlob(List<CustomAttributeBuilder> list)
  		{
  			string xml;
  			if (list.Count == 1 && (xml = list[0].GetLegacyDeclSecurity()) != null)
  			{
  				// write .NET 1.1 format
  				return this.Blobs.Add(ByteBuffer.Wrap(System.Text.Encoding.Unicode.GetBytes(xml)));
  			}
  			ByteBuffer namedArgs = new ByteBuffer(100);
  			ByteBuffer bb = new ByteBuffer(list.Count * 100);
  			bb.Write((byte)'.');
  			bb.WriteCompressedInt(list.Count);
  			foreach (CustomAttributeBuilder cab in list)
  			{
  				bb.Write(cab.Constructor.DeclaringType.AssemblyQualifiedName);
  				namedArgs.Clear();
  				cab.WriteNamedArgumentsForDeclSecurity(this, namedArgs);
  				bb.WriteCompressedInt(namedArgs.Length);
  				bb.Write(namedArgs);
  			}
  			return this.Blobs.Add(bb);
  		}
  
  		public void DefineManifestResource(string name, Stream stream, ResourceAttributes attribute)
  		{
  			manifestResources.Align(8);
  			ManifestResourceTable.Record rec = new ManifestResourceTable.Record();
  			rec.Offset = manifestResources.Position;
  			rec.Flags = (int)attribute;
  			rec.Name = this.Strings.Add(name);
  			rec.Implementation = 0;
  			this.ManifestResource.AddRecord(rec);
  			manifestResources.Write(0);	// placeholder for the length
  			manifestResources.Write(stream);
  			int savePosition = manifestResources.Position;
  			manifestResources.Position = rec.Offset;
  			manifestResources.Write(savePosition - (manifestResources.Position + 4));
  			manifestResources.Position = savePosition;
  		}
  
  		public override Assembly Assembly
  		{
  			get { return asm; }
  		}
  
  		internal override Type FindType(TypeName name)
  		{
  			foreach (Type type in types)
  			{
  				if (type.__Namespace == name.Namespace && type.__Name == name.Name)
  				{
  					return type;
  				}
  			}
  			return null;
  		}
  
  		internal override Type FindTypeIgnoreCase(TypeName lowerCaseName)
  		{
  			foreach (Type type in types)
  			{
  				if (new TypeName(type.__Namespace, type.__Name).ToLowerInvariant() == lowerCaseName)
  				{
  					return type;
  				}
  			}
  			return null;
  		}
  
  		internal override void GetTypesImpl(List<Type> list)
  		{
  			foreach (Type type in types)
  			{
  				if (type != moduleType)
  				{
  					list.Add(type);
  				}
  			}
  		}
  
  		public ISymbolDocumentWriter DefineDocument(string url, Guid language, Guid languageVendor, Guid documentType)
  		{
  			return symbolWriter.DefineDocument(url, language, languageVendor, documentType);
  		}
  
  		public int __GetAssemblyToken(Assembly assembly)
  		{
  			return ImportAssemblyRef(assembly);
  		}
  
  		public TypeToken GetTypeToken(string name)
  		{
  			return new TypeToken(GetType(name, true, false).MetadataToken);
  		}
  
  		public TypeToken GetTypeToken(Type type)
  		{
  			if (type.Module == this)
  			{
  				return new TypeToken(type.GetModuleBuilderToken());
  			}
  			else
  			{
  				return new TypeToken(ImportType(type));
  			}
  		}
  
  		internal int GetTypeTokenForMemberRef(Type type)
  		{
  			if (type.__IsMissing)
  			{
  				return ImportType(type);
  			}
  			else if (type.IsGenericTypeDefinition)
  			{
  				int token;
  				if (!memberRefTypeTokens.TryGetValue(type, out token))
  				{
  					ByteBuffer spec = new ByteBuffer(5);
  					Signature.WriteTypeSpec(this, spec, type);
  					token = 0x1B000000 | this.TypeSpec.AddRecord(this.Blobs.Add(spec));
  					memberRefTypeTokens.Add(type, token);
  				}
  				return token;
  			}
  			else if (type.IsModulePseudoType)
  			{
  				return 0x1A000000 | this.ModuleRef.FindOrAddRecord(this.Strings.Add(type.Module.ScopeName));
  			}
  			else
  			{
  				return GetTypeToken(type).Token;
  			}
  		}
  
  		private static bool IsFromGenericTypeDefinition(MemberInfo member)
  		{
  			Type decl = member.DeclaringType;
  			return decl != null && !decl.__IsMissing && decl.IsGenericTypeDefinition;
  		}
  
  		public FieldToken GetFieldToken(FieldInfo field)
  		{
  			// NOTE for some reason, when TypeBuilder.GetFieldToken() is used on a field in a generic type definition,
  			// a memberref token is returned (confirmed on .NET) unlike for Get(Method|Constructor)Token which always
  			// simply returns the MethodDef token (if the method is from the same module).
  			FieldBuilder fb = field as FieldBuilder;
  			if (fb != null && fb.Module == this && !IsFromGenericTypeDefinition(fb))
  			{
  				return new FieldToken(fb.MetadataToken);
  			}
  			else
  			{
  				return new FieldToken(ImportMember(field));
  			}
  		}
  
  		public MethodToken GetMethodToken(MethodInfo method)
  		{
  			MethodBuilder mb = method as MethodBuilder;
  			if (mb != null && mb.ModuleBuilder == this)
  			{
  				return new MethodToken(mb.MetadataToken);
  			}
  			else
  			{
  				return new MethodToken(ImportMember(method));
  			}
  		}
  
  		// when we refer to a method on a generic type definition in the IL stream,
  		// we need to use a MemberRef (even if the method is in the same module)
  		internal MethodToken GetMethodTokenForIL(MethodInfo method)
  		{
  			if (method.IsGenericMethodDefinition)
  			{
  				method = method.MakeGenericMethod(method.GetGenericArguments());
  			}
  			if (IsFromGenericTypeDefinition(method))
  			{
  				return new MethodToken(ImportMember(method));
  			}
  			else
  			{
  				return GetMethodToken(method);
  			}
  		}
  
  		public MethodToken GetConstructorToken(ConstructorInfo constructor)
  		{
  			if (constructor.Module == this && constructor.GetMethodInfo() is MethodBuilder)
  			{
  				return new MethodToken(constructor.MetadataToken);
  			}
  			else
  			{
  				return new MethodToken(ImportMember(constructor));
  			}
  		}
  
  		internal int ImportMember(MethodBase member)
  		{
  			int token;
  			if (!importedMembers.TryGetValue(member, out token))
  			{
  				token = member.ImportTo(this);
  				importedMembers.Add(member, token);
  			}
  			return token;
  		}
  
  		internal int ImportMember(FieldInfo member)
  		{
  			int token;
  			if (!importedMembers.TryGetValue(member, out token))
  			{
  				token = member.ImportTo(this);
  				importedMembers.Add(member, token);
  			}
  			return token;
  		}
  
  		internal int ImportMethodOrField(Type declaringType, string name, Signature sig)
  		{
  			int token;
  			if (!importedMemberRefs.TryGetValue(new MemberRefKey(declaringType, name, sig), out token))
  			{
  				MemberRefTable.Record rec = new MemberRefTable.Record();
  				rec.Class = GetTypeTokenForMemberRef(declaringType);
  				rec.Name = this.Strings.Add(name);
  				ByteBuffer bb = new ByteBuffer(16);
  				sig.WriteSig(this, bb);
  				rec.Signature = this.Blobs.Add(bb);
  				token = 0x0A000000 | this.MemberRef.AddRecord(rec);
  				importedMemberRefs.Add(new MemberRefKey(declaringType, name, sig), token);
  			}
  			return token;
  		}
  
  		internal int ImportType(Type type)
  		{
  			int token;
  			if (!typeTokens.TryGetValue(type, out token))
  			{
  				if (type.HasElementType || type.IsGenericTypeInstance || type.__IsFunctionPointer)
  				{
  					ByteBuffer spec = new ByteBuffer(5);
  					Signature.WriteTypeSpec(this, spec, type);
  					token = 0x1B000000 | this.TypeSpec.AddRecord(this.Blobs.Add(spec));
  				}
  				else
  				{
  					TypeRefTable.Record rec = new TypeRefTable.Record();
  					if (type.IsNested)
  					{
  						rec.ResolutionScope = GetTypeToken(type.DeclaringType).Token;
  					}
  					else
  					{
  						rec.ResolutionScope = ImportAssemblyRef(type.Assembly);
  					}
  					rec.TypeName = this.Strings.Add(type.__Name);
  					string ns = type.__Namespace;
  					rec.TypeNameSpace = ns == null ? 0 : this.Strings.Add(ns);
  					token = 0x01000000 | this.TypeRef.AddRecord(rec);
  				}
  				typeTokens.Add(type, token);
  			}
  			return token;
  		}
  
  		private int ImportAssemblyRef(Assembly asm)
  		{
  			int token;
  			if (!referencedAssemblies.TryGetValue(asm, out token))
  			{
  				// We can't write the AssemblyRef record here yet, because the identity of the assembly can still change
  				// (if it's an AssemblyBuilder).
  				token = AllocPseudoToken();
  				referencedAssemblies.Add(asm, token);
  			}
  			return token;
  		}
  
  		internal void FillAssemblyRefTable()
  		{
  			foreach (KeyValuePair<Assembly, int> kv in referencedAssemblies)
  			{
  				if (IsPseudoToken(kv.Value))
  				{
  					RegisterTokenFixup(kv.Value, FindOrAddAssemblyRef(kv.Key.GetName(), false));
  				}
  			}
  		}
  
  		private int FindOrAddAssemblyRef(AssemblyName name, bool alwaysAdd)
  		{
  			AssemblyRefTable.Record rec = new AssemblyRefTable.Record();
  			Version ver = name.Version ?? new Version(0, 0, 0, 0);
  			rec.MajorVersion = (ushort)ver.Major;
  			rec.MinorVersion = (ushort)ver.Minor;
  			rec.BuildNumber = (ushort)ver.Build;
  			rec.RevisionNumber = (ushort)ver.Revision;
  			rec.Flags = (int)(name.Flags & ~AssemblyNameFlags.PublicKey);
  			const AssemblyNameFlags afPA_Specified = (AssemblyNameFlags)0x0080;
  			const AssemblyNameFlags afPA_Mask = (AssemblyNameFlags)0x0070;
  			if ((name.RawFlags & afPA_Specified) != 0)
  			{
  				rec.Flags |= (int)(name.RawFlags & afPA_Mask);
  			}
  			byte[] publicKeyOrToken = null;
  			if (usePublicKeyAssemblyReference)
  			{
  				publicKeyOrToken = name.GetPublicKey();
  			}
  			if (publicKeyOrToken == null || publicKeyOrToken.Length == 0)
  			{
  				publicKeyOrToken = name.GetPublicKeyToken() ?? Empty<byte>.Array;
  			}
  			else
  			{
  				const int PublicKey = 0x0001;
  				rec.Flags |= PublicKey;
  			}
  			rec.PublicKeyOrToken = this.Blobs.Add(ByteBuffer.Wrap(publicKeyOrToken));
  			rec.Name = this.Strings.Add(name.Name);
  			rec.Culture = name.Culture == null ? 0 : this.Strings.Add(name.Culture);
  			if (name.hash != null)
  			{
  				rec.HashValue = this.Blobs.Add(ByteBuffer.Wrap(name.hash));
  			}
  			else
  			{
  				rec.HashValue = 0;
  			}
  			return 0x23000000 | (alwaysAdd ? this.AssemblyRef.AddRecord(rec) : this.AssemblyRef.FindOrAddRecord(rec));
  		}
  
  		internal void WriteSymbolTokenMap()
  		{
  			for (int i = 0; i < resolvedTokens.Count; i++)
  			{
  				int newToken = resolvedTokens[i];
  				// The symbol API doesn't support remapping arbitrary integers, the types have to be the same,
  				// so we copy the type from the newToken, because our pseudo tokens don't have a type.
  				// (see MethodToken.SymbolToken)
  				int oldToken = (i + 1) | (newToken & ~0xFFFFFF);
  				SymbolSupport.RemapToken(symbolWriter, oldToken, newToken);
  			}
  		}
  
  		internal void RegisterTokenFixup(int pseudoToken, int realToken)
  		{
  			int index = -(pseudoToken + 1);
  			while (resolvedTokens.Count <= index)
  			{
  				resolvedTokens.Add(0);
  			}
  			resolvedTokens[index] = realToken;
  		}
  
  		internal bool IsPseudoToken(int token)
  		{
  			return token < 0;
  		}
  
  		internal int ResolvePseudoToken(int pseudoToken)
  		{
  			int index = -(pseudoToken + 1);
  			return resolvedTokens[index];
  		}
  
  		internal void ApplyUnmanagedExports(ImageFileMachine imageFileMachine)
  		{
  
gt: 			if (unmanagedExports.Count != 0)