зеркало из https://github.com/mono/ikvm-fork.git
1364 строки
40 KiB
C#
1364 строки
40 KiB
C#
/*
|
|
Copyright (C) 2008-2011 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 readonly Guid mvid = Guid.NewGuid();
|
|
private long imageBaseAddress = 0x00400000;
|
|
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>();
|
|
private readonly Dictionary<string, TypeBuilder> fullNameToType = new Dictionary<string, TypeBuilder>();
|
|
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();
|
|
|
|
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>", 0);
|
|
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, attr);
|
|
if (parent == null && (attr & TypeAttributes.Interface) == 0)
|
|
{
|
|
parent = universe.System_Object;
|
|
}
|
|
typeBuilder.SetParent(parent);
|
|
SetPackingSizeAndTypeSize(typeBuilder, packingSize, typesize);
|
|
return typeBuilder;
|
|
}
|
|
|
|
public TypeBuilder __DefineType(string ns, string name, TypeAttributes attr)
|
|
{
|
|
return DefineType(this, ns, name, attr);
|
|
}
|
|
|
|
internal TypeBuilder DefineType(ITypeOwner owner, string ns, string name, TypeAttributes attr)
|
|
{
|
|
TypeBuilder typeBuilder = new TypeBuilder(owner, ns, name, attr);
|
|
types.Add(typeBuilder);
|
|
fullNameToType.Add(typeBuilder.FullName, typeBuilder);
|
|
return typeBuilder;
|
|
}
|
|
|
|
internal void SetPackingSizeAndTypeSize(TypeBuilder typeBuilder, PackingSize packingSize, int typesize)
|
|
{
|
|
if (packingSize != PackingSize.Unspecified || typesize != 0)
|
|
{
|
|
ClassLayoutTable.Record rec = new ClassLayoutTable.Record();
|
|
rec.PackingSize = (short)packingSize;
|
|
rec.ClassSize = typesize;
|
|
rec.Parent = typeBuilder.MetadataToken;
|
|
this.ClassLayout.AddRecord(rec);
|
|
}
|
|
}
|
|
|
|
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, 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);
|
|
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);
|
|
if (type.IsNested)
|
|
{
|
|
rec.Flags = 0;
|
|
rec.TypeNamespace = 0;
|
|
rec.Implementation = ExportType(type.DeclaringType);
|
|
}
|
|
else
|
|
{
|
|
rec.Flags = 0x00200000; // CorTypeAttr.tdForwarder
|
|
string ns = type.__Namespace;
|
|
rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(ns);
|
|
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)
|
|
{
|
|
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)
|
|
{
|
|
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 GetTypeImpl(string typeName)
|
|
{
|
|
TypeBuilder type;
|
|
fullNameToType.TryGetValue(typeName, out type);
|
|
return type;
|
|
}
|
|
|
|
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 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.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.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.IsGenericType && !type.IsGenericTypeDefinition))
|
|
{
|
|
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).
|
|
// We set the high bit of rid in the token to make sure we emit obviously broken metadata,
|
|
// if we forget to patch up the token somewhere.
|
|
token = 0x23800001 + referencedAssemblies.Count;
|
|
referencedAssemblies.Add(asm, token);
|
|
}
|
|
return token;
|
|
}
|
|
|
|
internal void FillAssemblyRefTable()
|
|
{
|
|
int[] realtokens = new int[referencedAssemblies.Count];
|
|
foreach (KeyValuePair<Assembly, int> kv in referencedAssemblies)
|
|
{
|
|
realtokens[(kv.Value & 0x7FFFFF) - 1] = FindOrAddAssemblyRef(kv.Key.GetName());
|
|
}
|
|
// now fixup the resolution scopes in TypeRef
|
|
for (int i = 0; i < this.TypeRef.records.Length; i++)
|
|
{
|
|
int resolutionScope = this.TypeRef.records[i].ResolutionScope;
|
|
if ((resolutionScope >> 24) == AssemblyRefTable.Index)
|
|
{
|
|
this.TypeRef.records[i].ResolutionScope = realtokens[(resolutionScope & 0x7FFFFF) - 1];
|
|
}
|
|
}
|
|
// and implementation in ExportedType
|
|
for (int i = 0; i < this.ExportedType.records.Length; i++)
|
|
{
|
|
int implementation = this.ExportedType.records[i].Implementation;
|
|
if ((implementation >> 24) == AssemblyRefTable.Index)
|
|
{
|
|
this.ExportedType.records[i].Implementation = realtokens[(implementation & 0x7FFFFF) - 1];
|
|
}
|
|
}
|
|
}
|
|
|
|
private int FindOrAddAssemblyRef(AssemblyName name)
|
|
{
|
|
AssemblyRefTable.Record rec = new AssemblyRefTable.Record();
|
|
Version ver = name.Version;
|
|
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.Retargetable);
|
|
byte[] publicKeyOrToken = null;
|
|
if (usePublicKeyAssemblyReference)
|
|
{
|
|
publicKeyOrToken = name.GetPublicKey();
|
|
}
|
|
if (publicKeyOrToken == null || publicKeyOrToken.Length == 0)
|
|
{
|
|
publicKeyOrToken = name.GetPublicKeyToken();
|
|
}
|
|
else
|
|
{
|
|
const int PublicKey = 0x0001;
|
|
rec.Flags |= PublicKey;
|
|
}
|
|
rec.PublicKeyOrToken = this.Blobs.Add(ByteBuffer.Wrap(publicKeyOrToken));
|
|
rec.Name = this.Strings.Add(name.Name);
|
|
if (name.CultureInfo != null)
|
|
{
|
|
rec.Culture = this.Strings.Add(name.CultureInfo.Name);
|
|
}
|
|
else
|
|
{
|
|
rec.Culture = 0;
|
|
}
|
|
rec.HashValue = 0;
|
|
return 0x23000000 | 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 FixupMethodBodyTokens()
|
|
{
|
|
int methodToken = 0x06000001;
|
|
int fieldToken = 0x04000001;
|
|
int parameterToken = 0x08000001;
|
|
foreach (TypeBuilder type in types)
|
|
{
|
|
type.ResolveMethodAndFieldTokens(ref methodToken, ref fieldToken, ref parameterToken);
|
|
}
|
|
foreach (int offset in tokenFixupOffsets)
|
|
{
|
|
methodBodies.Position = offset;
|
|
int pseudoToken = methodBodies.GetInt32AtCurrentPosition();
|
|
methodBodies.Write(ResolvePseudoToken(pseudoToken));
|
|
}
|
|
}
|
|
|
|
private int GetHeaderLength()
|
|
{
|
|
return
|
|
4 + // Signature
|
|
2 + // MajorVersion
|
|
2 + // MinorVersion
|
|
4 + // Reserved
|
|
4 + // ImageRuntimeVersion Length
|
|
StringToPaddedUTF8Length(asm.ImageRuntimeVersion) +
|
|
2 + // Flags
|
|
2 + // Streams
|
|
4 + // #~ Offset
|
|
4 + // #~ Size
|
|
4 + // StringToPaddedUTF8Length("#~")
|
|
4 + // #Strings Offset
|
|
4 + // #Strings Size
|
|
12 + // StringToPaddedUTF8Length("#Strings")
|
|
4 + // #US Offset
|
|
4 + // #US Size
|
|
4 + // StringToPaddedUTF8Length("#US")
|
|
4 + // #GUID Offset
|
|
4 + // #GUID Size
|
|
8 + // StringToPaddedUTF8Length("#GUID")
|
|
(Blobs.IsEmpty ? 0 :
|
|
(
|
|
4 + // #Blob Offset
|
|
4 + // #Blob Size
|
|
8 // StringToPaddedUTF8Length("#Blob")
|
|
));
|
|
}
|
|
|
|
internal int MetadataLength
|
|
{
|
|
get
|
|
{
|
|
return GetHeaderLength() + (Blobs.IsEmpty ? 0 : Blobs.Length) + Tables.Length + Strings.Length + UserStrings.Length + Guids.Length;
|
|
}
|
|
}
|
|
|
|
internal void WriteMetadata(MetadataWriter mw)
|
|
{
|
|
mw.Write(0x424A5342); // Signature ("BSJB")
|
|
mw.Write((ushort)1); // MajorVersion
|
|
mw.Write((ushort)1); // MinorVersion
|
|
mw.Write(0); // Reserved
|
|
byte[] version = StringToPaddedUTF8(asm.ImageRuntimeVersion);
|
|
mw.Write(version.Length); // Length
|
|
mw.Write(version);
|
|
mw.Write((ushort)0); // Flags
|
|
// #Blob is the only optional heap
|
|
if (Blobs.IsEmpty)
|
|
{
|
|
mw.Write((ushort)4); // Streams
|
|
}
|
|
else
|
|
{
|
|
mw.Write((ushort)5); // Streams
|
|
}
|
|
|
|
int offset = GetHeaderLength();
|
|
|
|
// Streams
|
|
mw.Write(offset); // Offset
|
|
mw.Write(Tables.Length); // Size
|
|
mw.Write(StringToPaddedUTF8("#~"));
|
|
offset += Tables.Length;
|
|
|
|
mw.Write(offset); // Offset
|
|
mw.Write(Strings.Length); // Size
|
|
mw.Write(StringToPaddedUTF8("#Strings"));
|
|
offset += Strings.Length;
|
|
|
|
mw.Write(offset); // Offset
|
|
mw.Write(UserStrings.Length); // Size
|
|
mw.Write(StringToPaddedUTF8("#US"));
|
|
offset += UserStrings.Length;
|
|
|
|
mw.Write(offset); // Offset
|
|
mw.Write(Guids.Length); // Size
|
|
mw.Write(StringToPaddedUTF8("#GUID"));
|
|
offset += Guids.Length;
|
|
|
|
if (!Blobs.IsEmpty)
|
|
{
|
|
mw.Write(offset); // Offset
|
|
mw.Write(Blobs.Length); // Size
|
|
mw.Write(StringToPaddedUTF8("#Blob"));
|
|
}
|
|
|
|
Tables.Write(mw);
|
|
Strings.Write(mw);
|
|
UserStrings.Write(mw);
|
|
Guids.Write(mw);
|
|
if (!Blobs.IsEmpty)
|
|
{
|
|
Blobs.Write(mw);
|
|
}
|
|
}
|
|
|
|
private static int StringToPaddedUTF8Length(string str)
|
|
{
|
|
return (System.Text.Encoding.UTF8.GetByteCount(str) + 4) & ~3;
|
|
}
|
|
|
|
private static byte[] StringToPaddedUTF8(string str)
|
|
{
|
|
byte[] buf = new byte[(System.Text.Encoding.UTF8.GetByteCount(str) + 4) & ~3];
|
|
System.Text.Encoding.UTF8.GetBytes(str, 0, str.Length, buf, 0);
|
|
return buf;
|
|
}
|
|
|
|
internal override void ExportTypes(int fileToken, ModuleBuilder manifestModule)
|
|
{
|
|
manifestModule.ExportTypes(types.ToArray(), fileToken);
|
|
}
|
|
|
|
internal void ExportTypes(Type[] types, int fileToken)
|
|
{
|
|
Dictionary<Type, int> declaringTypes = new Dictionary<Type, int>();
|
|
foreach (Type type in types)
|
|
{
|
|
if (!type.IsModulePseudoType && IsVisible(type))
|
|
{
|
|
ExportedTypeTable.Record rec = new ExportedTypeTable.Record();
|
|
rec.Flags = (int)type.Attributes;
|
|
rec.TypeDefId = type.MetadataToken & 0xFFFFFF;
|
|
rec.TypeName = this.Strings.Add(type.__Name);
|
|
string ns = type.__Namespace;
|
|
rec.TypeNamespace = ns == null ? 0 : this.Strings.Add(ns);
|
|
if (type.IsNested)
|
|
{
|
|
rec.Implementation = declaringTypes[type.DeclaringType];
|
|
}
|
|
else
|
|
{
|
|
rec.Implementation = fileToken;
|
|
}
|
|
int exportTypeToken = 0x27000000 | this.ExportedType.AddRecord(rec);
|
|
declaringTypes.Add(type, exportTypeToken);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static bool IsVisible(Type type)
|
|
{
|
|
// NOTE this is not the same as Type.IsVisible, because that doesn't take into account family access
|
|
return type.IsPublic || ((type.IsNestedFamily || type.IsNestedFamORAssem || type.IsNestedPublic) && IsVisible(type.DeclaringType));
|
|
}
|
|
|
|
internal void AddConstant(int parentToken, object defaultValue)
|
|
{
|
|
ConstantTable.Record rec = new ConstantTable.Record();
|
|
rec.Parent = parentToken;
|
|
ByteBuffer val = new ByteBuffer(16);
|
|
if (defaultValue == null)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_CLASS;
|
|
val.Write((int)0);
|
|
}
|
|
else if (defaultValue is bool)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_BOOLEAN;
|
|
val.Write((bool)defaultValue ? (byte)1 : (byte)0);
|
|
}
|
|
else if (defaultValue is char)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_CHAR;
|
|
val.Write((char)defaultValue);
|
|
}
|
|
else if (defaultValue is sbyte)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_I1;
|
|
val.Write((sbyte)defaultValue);
|
|
}
|
|
else if (defaultValue is byte)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_U1;
|
|
val.Write((byte)defaultValue);
|
|
}
|
|
else if (defaultValue is short)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_I2;
|
|
val.Write((short)defaultValue);
|
|
}
|
|
else if (defaultValue is ushort)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_U2;
|
|
val.Write((ushort)defaultValue);
|
|
}
|
|
else if (defaultValue is int)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_I4;
|
|
val.Write((int)defaultValue);
|
|
}
|
|
else if (defaultValue is uint)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_U4;
|
|
val.Write((uint)defaultValue);
|
|
}
|
|
else if (defaultValue is long)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_I8;
|
|
val.Write((long)defaultValue);
|
|
}
|
|
else if (defaultValue is ulong)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_U8;
|
|
val.Write((ulong)defaultValue);
|
|
}
|
|
else if (defaultValue is float)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_R4;
|
|
val.Write((float)defaultValue);
|
|
}
|
|
else if (defaultValue is double)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_R8;
|
|
val.Write((double)defaultValue);
|
|
}
|
|
else if (defaultValue is string)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_STRING;
|
|
foreach (char c in (string)defaultValue)
|
|
{
|
|
val.Write(c);
|
|
}
|
|
}
|
|
else if (defaultValue is DateTime)
|
|
{
|
|
rec.Type = Signature.ELEMENT_TYPE_I8;
|
|
val.Write(((DateTime)defaultValue).Ticks);
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentException();
|
|
}
|
|
rec.Value = this.Blobs.Add(val);
|
|
this.Constant.AddRecord(rec);
|
|
}
|
|
|
|
ModuleBuilder ITypeOwner.ModuleBuilder
|
|
{
|
|
get { return this; }
|
|
}
|
|
|
|
public override Type ResolveType(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
|
|
{
|
|
if (genericTypeArguments != null || genericMethodArguments != null)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
return types[(metadataToken & 0xFFFFFF) - 1];
|
|
}
|
|
|
|
public override MethodBase ResolveMethod(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
|
|
{
|
|
if (genericTypeArguments != null || genericMethodArguments != null)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
// this method is inefficient, but since it isn't used we don't care
|
|
if ((metadataToken >> 24) == MemberRefTable.Index)
|
|
{
|
|
foreach (KeyValuePair<MemberInfo, int> kv in importedMembers)
|
|
{
|
|
if (kv.Value == metadataToken)
|
|
{
|
|
return (MethodBase)kv.Key;
|
|
}
|
|
}
|
|
}
|
|
// HACK if we're given a SymbolToken, we need to convert back
|
|
if ((metadataToken & 0xFF000000) == 0x06000000)
|
|
{
|
|
metadataToken = -(metadataToken & 0x00FFFFFF);
|
|
}
|
|
foreach (Type type in types)
|
|
{
|
|
MethodBase method = ((TypeBuilder)type).LookupMethod(metadataToken);
|
|
if (method != null)
|
|
{
|
|
return method;
|
|
}
|
|
}
|
|
return ((TypeBuilder)moduleType).LookupMethod(metadataToken);
|
|
}
|
|
|
|
public override FieldInfo ResolveField(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override MemberInfo ResolveMember(int metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override string ResolveString(int metadataToken)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override string FullyQualifiedName
|
|
{
|
|
get { return Path.GetFullPath(Path.Combine(asm.dir, fileName)); }
|
|
}
|
|
|
|
public override string Name
|
|
{
|
|
get { return fileName; }
|
|
}
|
|
|
|
public override Guid ModuleVersionId
|
|
{
|
|
get { return mvid; }
|
|
}
|
|
|
|
public override Type[] __ResolveOptionalParameterTypes(int metadataToken)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public override string ScopeName
|
|
{
|
|
get { return moduleName; }
|
|
}
|
|
|
|
public ISymbolWriter GetSymWriter()
|
|
{
|
|
return symbolWriter;
|
|
}
|
|
|
|
public void DefineUnmanagedResource(string resourceFileName)
|
|
{
|
|
// This method reads the specified resource file (Win32 .res file) and converts it into the appropriate format and embeds it in the .rsrc section,
|
|
// also setting the Resource Directory entry.
|
|
unmanagedResources = new ResourceSection();
|
|
unmanagedResources.ExtractResources(System.IO.File.ReadAllBytes(resourceFileName));
|
|
}
|
|
|
|
public bool IsTransient()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public void SetUserEntryPoint(MethodInfo entryPoint)
|
|
{
|
|
int token = entryPoint.MetadataToken;
|
|
if (token < 0)
|
|
{
|
|
token = -token | 0x06000000;
|
|
}
|
|
if (symbolWriter != null)
|
|
{
|
|
symbolWriter.SetUserEntryPoint(new SymbolToken(token));
|
|
}
|
|
}
|
|
|
|
public StringToken GetStringConstant(string str)
|
|
{
|
|
return new StringToken(this.UserStrings.Add(str) | (0x70 << 24));
|
|
}
|
|
|
|
public SignatureToken GetSignatureToken(SignatureHelper sigHelper)
|
|
{
|
|
return new SignatureToken(this.StandAloneSig.FindOrAddRecord(this.Blobs.Add(sigHelper.GetSignature(this))) | (StandAloneSigTable.Index << 24));
|
|
}
|
|
|
|
public SignatureToken GetSignatureToken(byte[] sigBytes, int sigLength)
|
|
{
|
|
return new SignatureToken(this.StandAloneSig.FindOrAddRecord(this.Blobs.Add(ByteBuffer.Wrap(sigBytes, sigLength))) | (StandAloneSigTable.Index << 24));
|
|
}
|
|
|
|
public MethodInfo GetArrayMethod(Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
|
|
{
|
|
return new ArrayMethod(this, arrayClass, methodName, callingConvention, returnType, parameterTypes);
|
|
}
|
|
|
|
public MethodToken GetArrayMethodToken(Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
|
|
{
|
|
return GetMethodToken(GetArrayMethod(arrayClass, methodName, callingConvention, returnType, parameterTypes));
|
|
}
|
|
|
|
internal override Type GetModuleType()
|
|
{
|
|
return moduleType;
|
|
}
|
|
|
|
internal override IKVM.Reflection.Reader.ByteReader GetBlob(int blobIndex)
|
|
{
|
|
return Blobs.GetBlob(blobIndex);
|
|
}
|
|
|
|
internal int GetSignatureBlobIndex(Signature sig)
|
|
{
|
|
ByteBuffer bb = new ByteBuffer(16);
|
|
sig.WriteSig(this, bb);
|
|
return this.Blobs.Add(bb);
|
|
}
|
|
|
|
// non-standard API
|
|
public long __ImageBase
|
|
{
|
|
get { return imageBaseAddress; }
|
|
set { imageBaseAddress = value; }
|
|
}
|
|
|
|
public override int MDStreamVersion
|
|
{
|
|
get { return asm.mdStreamVersion; }
|
|
}
|
|
|
|
private int AddTypeRefByName(int resolutionScope, string ns, string name)
|
|
{
|
|
TypeRefTable.Record rec = new TypeRefTable.Record();
|
|
rec.ResolutionScope = resolutionScope;
|
|
rec.TypeName = this.Strings.Add(name);
|
|
rec.TypeNameSpace = ns == null ? 0 : this.Strings.Add(ns);
|
|
return 0x01000000 | this.TypeRef.AddRecord(rec);
|
|
}
|
|
|
|
public void __Save(PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
|
|
{
|
|
PopulatePropertyAndEventTables();
|
|
IList<CustomAttributeData> attributes = asm.GetCustomAttributesData(null);
|
|
if (attributes.Count > 0)
|
|
{
|
|
int mscorlib = ImportAssemblyRef(universe.Mscorlib);
|
|
int[] placeholderTokens = new int[4];
|
|
string[] placeholderTypeNames = new string[] { "AssemblyAttributesGoHere", "AssemblyAttributesGoHereM", "AssemblyAttributesGoHereS", "AssemblyAttributesGoHereSM" };
|
|
foreach (CustomAttributeData cad in attributes)
|
|
{
|
|
int index;
|
|
if (cad.Constructor.DeclaringType.BaseType == universe.System_Security_Permissions_CodeAccessSecurityAttribute)
|
|
{
|
|
if (cad.Constructor.DeclaringType.IsAllowMultipleCustomAttribute)
|
|
{
|
|
index = 3;
|
|
}
|
|
else
|
|
{
|
|
index = 2;
|
|
}
|
|
}
|
|
else if (cad.Constructor.DeclaringType.IsAllowMultipleCustomAttribute)
|
|
{
|
|
index = 1;
|
|
}
|
|
else
|
|
{
|
|
index = 0;
|
|
}
|
|
if (placeholderTokens[index] == 0)
|
|
{
|
|
// we manually add a TypeRef without looking it up in mscorlib, because Mono and Silverlight's mscorlib don't have these types
|
|
placeholderTokens[index] = AddTypeRefByName(mscorlib, "System.Runtime.CompilerServices", placeholderTypeNames[index]);
|
|
}
|
|
SetCustomAttribute(placeholderTokens[index], cad.__ToBuilder());
|
|
}
|
|
}
|
|
FillAssemblyRefTable();
|
|
ModuleWriter.WriteModule(null, null, this, PEFileKinds.Dll, portableExecutableKind, imageFileMachine, unmanagedResources, 0);
|
|
}
|
|
|
|
public void __AddAssemblyReference(AssemblyName assemblyName)
|
|
{
|
|
if (referencedAssemblyNames == null)
|
|
{
|
|
referencedAssemblyNames = new List<AssemblyName>();
|
|
}
|
|
FindOrAddAssemblyRef(assemblyName);
|
|
referencedAssemblyNames.Add((AssemblyName)assemblyName.Clone());
|
|
}
|
|
|
|
public override AssemblyName[] __GetReferencedAssemblies()
|
|
{
|
|
List<AssemblyName> list = new List<AssemblyName>();
|
|
if (referencedAssemblyNames != null)
|
|
{
|
|
foreach (AssemblyName name in referencedAssemblyNames)
|
|
{
|
|
if (!list.Contains(name))
|
|
{
|
|
list.Add(name);
|
|
}
|
|
}
|
|
}
|
|
foreach (Assembly asm in referencedAssemblies.Keys)
|
|
{
|
|
AssemblyName name = asm.GetName();
|
|
if (!list.Contains(name))
|
|
{
|
|
list.Add(name);
|
|
}
|
|
}
|
|
return list.ToArray();
|
|
}
|
|
}
|
|
|
|
class ArrayMethod : MethodInfo
|
|
{
|
|
private readonly Module module;
|
|
private readonly Type arrayClass;
|
|
private readonly string methodName;
|
|
private readonly CallingConventions callingConvention;
|
|
private readonly Type returnType;
|
|
protected readonly Type[] parameterTypes;
|
|
private MethodSignature methodSignature;
|
|
|
|
internal ArrayMethod(Module module, Type arrayClass, string methodName, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
|
|
{
|
|
this.module = module;
|
|
this.arrayClass = arrayClass;
|
|
this.methodName = methodName;
|
|
this.callingConvention = callingConvention;
|
|
this.returnType = returnType ?? module.universe.System_Void;
|
|
this.parameterTypes = Util.Copy(parameterTypes);
|
|
}
|
|
|
|
public override MethodBody GetMethodBody()
|
|
{
|
|
throw new InvalidOperationException();
|
|
}
|
|
|
|
public override MethodImplAttributes GetMethodImplementationFlags()
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
public override ParameterInfo[] GetParameters()
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
|
|
internal override int ImportTo(ModuleBuilder module)
|
|
{
|
|
return module.ImportMethodOrField(arrayClass, methodName, MethodSignature);
|
|
}
|
|
|
|
public override MethodAttributes Attributes
|
|
{
|
|
get { throw new NotSupportedException(); }
|
|
}
|
|
|
|
public override CallingConventions CallingConvention
|
|
{
|
|
get { return callingConvention; }
|
|
}
|
|
|
|
public override Type DeclaringType
|
|
{
|
|
get { return arrayClass; }
|
|
}
|
|
|
|
internal override MethodSignature MethodSignature
|
|
{
|
|
get
|
|
{
|
|
if (methodSignature == null)
|
|
{
|
|
methodSignature = MethodSignature.MakeFromBuilder(returnType, parameterTypes, null, callingConvention, 0);
|
|
}
|
|
return methodSignature;
|
|
}
|
|
}
|
|
|
|
public override Module Module
|
|
{
|
|
// like .NET, we return the module that GetArrayMethod was called on, not the module associated with the array type
|
|
get { return module; }
|
|
}
|
|
|
|
public override string Name
|
|
{
|
|
get { return methodName; }
|
|
}
|
|
|
|
internal override int ParameterCount
|
|
{
|
|
get { return parameterTypes.Length; }
|
|
}
|
|
|
|
public override ParameterInfo ReturnParameter
|
|
{
|
|
get { throw new NotImplementedException(); }
|
|
}
|
|
|
|
public override Type ReturnType
|
|
{
|
|
get { return returnType; }
|
|
}
|
|
|
|
internal override bool HasThis
|
|
{
|
|
get { return (callingConvention & (CallingConventions.HasThis | CallingConventions.ExplicitThis)) == CallingConventions.HasThis; }
|
|
}
|
|
}
|
|
}
|