ikvm-fork/refemit/Writer/Heaps.cs

2155 строки
47 KiB
C#

/*
Copyright (C) 2008 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.Text;
using System.Diagnostics;
namespace IKVM.Reflection.Emit.Writer
{
abstract class Heap
{
private bool frozen;
private int unalignedlength;
internal void Write(MetadataWriter mw)
{
int pos = mw.Position;
WriteImpl(mw);
Debug.Assert(mw.Position == pos + unalignedlength);
int align = Length - unalignedlength;
for (int i = 0; i < align; i++)
{
mw.Write((byte)0);
}
}
internal void Freeze(ModuleBuilder md)
{
if (frozen)
throw new InvalidOperationException();
frozen = true;
unalignedlength = GetLength(md);
}
internal bool IsBig
{
get { return Length > 65535; }
}
internal int Length
{
get
{
if (!frozen)
throw new InvalidOperationException();
return (unalignedlength + 3) & ~3;
}
}
protected abstract void WriteImpl(MetadataWriter mw);
protected abstract int GetLength(ModuleBuilder md);
}
sealed class TableHeap : Heap
{
internal readonly ModuleTable Module = new ModuleTable();
internal readonly TypeRefTable TypeRef = new TypeRefTable();
internal readonly TypeDefTable TypeDef = new TypeDefTable();
internal readonly FieldTable Field = new FieldTable();
internal readonly MemberRefTable MemberRef = new MemberRefTable();
internal readonly ConstantTable Constant = new ConstantTable();
internal readonly CustomAttributeTable CustomAttribute = new CustomAttributeTable();
internal readonly FieldMarshalTable FieldMarshal = new FieldMarshalTable();
internal readonly DeclSecurityTable DeclSecurity = new DeclSecurityTable();
internal readonly ClassLayoutTable ClassLayout = new ClassLayoutTable();
internal readonly FieldLayoutTable FieldLayout = new FieldLayoutTable();
internal readonly ParamTable Param = new ParamTable();
internal readonly InterfaceImplTable InterfaceImpl = new InterfaceImplTable();
internal readonly StandAloneSigTable StandAloneSig = new StandAloneSigTable();
internal readonly PropertyMapTable PropertyMap = new PropertyMapTable();
internal readonly PropertyTable Property = new PropertyTable();
internal readonly MethodSemanticsTable MethodSemantics = new MethodSemanticsTable();
internal readonly MethodImplTable MethodImpl = new MethodImplTable();
internal readonly ModuleRefTable ModuleRef = new ModuleRefTable();
internal readonly TypeSpecTable TypeSpec = new TypeSpecTable();
internal readonly ImplMapTable ImplMap = new ImplMapTable();
internal readonly FieldRVATable FieldRVA = new FieldRVATable();
internal readonly AssemblyTable Assembly = new AssemblyTable();
internal readonly AssemblyRefTable AssemblyRef = new AssemblyRefTable();
internal readonly MethodDefTable MethodDef = new MethodDefTable();
internal readonly NestedClassTable NestedClass = new NestedClassTable();
internal readonly FileTable File = new FileTable();
internal readonly ExportedTypeTable ExportedType = new ExportedTypeTable();
internal readonly ManifestResourceTable ManifestResource = new ManifestResourceTable();
internal readonly GenericParamTable GenericParam = new GenericParamTable();
internal readonly MethodSpecTable MethodSpec = new MethodSpecTable();
internal readonly GenericParamConstraintTable GenericParamConstraint = new GenericParamConstraintTable();
private readonly Table[] tables = new Table[64];
internal TableHeap(ModuleBuilder moduleBuilder)
{
tables[ModuleTable.Index] = Module;
tables[TypeRefTable.Index] = TypeRef;
tables[TypeDefTable.Index] = TypeDef;
tables[FieldTable.Index] = Field;
tables[MemberRefTable.Index] = MemberRef;
tables[ConstantTable.Index] = Constant;
tables[CustomAttributeTable.Index] = CustomAttribute;
tables[FieldMarshalTable.Index] = FieldMarshal;
tables[DeclSecurityTable.Index] = DeclSecurity;
tables[ClassLayoutTable.Index] = ClassLayout;
tables[FieldLayoutTable.Index] = FieldLayout;
tables[ParamTable.Index] = Param;
tables[InterfaceImplTable.Index] = InterfaceImpl;
tables[StandAloneSigTable.Index] = StandAloneSig;
tables[PropertyMapTable.Index] = PropertyMap;
tables[PropertyTable.Index] = Property;
tables[MethodSemanticsTable.Index] = MethodSemantics;
tables[MethodImplTable.Index] = MethodImpl;
tables[ModuleRefTable.Index] = ModuleRef;
tables[TypeSpecTable.Index] = TypeSpec;
tables[ImplMapTable.Index] = ImplMap;
tables[FieldRVATable.Index] = FieldRVA;
tables[AssemblyTable.Index] = Assembly;
tables[AssemblyRefTable.Index] = AssemblyRef;
tables[MethodDefTable.Index] = MethodDef;
tables[NestedClassTable.Index] = NestedClass;
tables[FileTable.Index] = File;
tables[ExportedTypeTable.Index] = ExportedType;
tables[ManifestResourceTable.Index] = ManifestResource;
tables[GenericParamTable.Index] = GenericParam;
tables[MethodSpecTable.Index] = MethodSpec;
tables[GenericParamConstraintTable.Index] = GenericParamConstraint;
}
internal abstract class Table
{
internal bool IsBig
{
get { return RowCount > 65535; }
}
internal abstract int RowCount { get; }
internal abstract void Write(MetadataWriter mw);
internal int GetLength(ModuleBuilder md)
{
return RowCount * GetRowSize(new RowSizeCalc(md));
}
protected abstract int GetRowSize(RowSizeCalc rsc);
protected sealed class RowSizeCalc
{
private readonly ModuleBuilder md;
private int size;
internal RowSizeCalc(ModuleBuilder md)
{
this.md = md;
this.size = 0;
}
internal RowSizeCalc AddFixed(int size)
{
this.size += size;
return this;
}
internal RowSizeCalc WriteStringIndex()
{
if (md.bigStrings)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteGuidIndex()
{
if (md.bigGuids)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteBlobIndex()
{
if (md.bigBlobs)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteTypeDefOrRef()
{
if (md.bigTypeDefOrRef)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteField()
{
if (md.bigField)
{
size += 4;
}
else
{
size += 2;
}
return this;
}
internal RowSizeCalc WriteMethodDef()
{
if (md.bigMethodDef)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteParam()
{
if (md.bigParam)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteResolutionScope()
{
if (md.bigResolutionScope)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteMemberRefParent()
{
if (md.bigMemberRefParent)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteHasCustomAttribute()
{
if (md.bigHasCustomAttribute)
{
size += 4;
}
else
{
size += 2;
}
return this;
}
internal RowSizeCalc WriteCustomAttributeType()
{
if (md.bigCustomAttributeType)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteHasConstant()
{
if (md.bigHasConstant)
{
size += 4;
}
else
{
size += 2;
}
return this;
}
internal RowSizeCalc WriteTypeDef()
{
if (md.bigTypeDef)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteMethodDefOrRef()
{
if (md.bigMethodDefOrRef)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteProperty()
{
if (md.bigProperty)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteHasSemantics()
{
if (md.bigHasSemantics)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteImplementation()
{
if (md.bigImplementation)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteTypeOrMethodDef()
{
if (md.bigTypeOrMethodDef)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteGenericParam()
{
if (md.bigGenericParam)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteHasDeclSecurity()
{
if (md.bigHasDeclSecurity)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteMemberForwarded()
{
if (md.bigMemberForwarded)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteModuleRef()
{
if (md.bigModuleRef)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal RowSizeCalc WriteHasFieldMarshal()
{
if (md.bigHasFieldMarshal)
{
this.size += 4;
}
else
{
this.size += 2;
}
return this;
}
internal int Value
{
get { return size; }
}
}
}
internal abstract class Table<T> : Table
{
protected T[] records = new T[1];
protected int rowCount;
internal override int RowCount
{
get { return rowCount; }
}
internal int AddRecord(T newRecord)
{
if (rowCount == records.Length)
{
T[] newarr = new T[records.Length * 2];
Array.Copy(records, newarr, records.Length);
records = newarr;
}
records[rowCount++] = newRecord;
return rowCount;
}
}
internal abstract class VirtualTable : Table
{
protected int rowCount;
internal sealed override int RowCount
{
get { return rowCount; }
}
internal int AddRow()
{
return ++rowCount;
}
}
internal sealed class ModuleTable : Table<ModuleTable.Record>
{
internal const int Index = 0x00;
internal struct Record
{
internal short Generation;
internal int Name; // -> StringHeap
internal int Mvid; // -> GuidHeap
internal int EncId; // -> GuidHeap
internal int EncBaseId; // -> GuidHeap
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].Generation);
mw.WriteStringIndex(records[i].Name);
mw.WriteGuidIndex(records[i].Mvid);
mw.WriteGuidIndex(records[i].EncId);
mw.WriteGuidIndex(records[i].EncBaseId);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(2)
.WriteStringIndex()
.WriteGuidIndex()
.WriteGuidIndex()
.WriteGuidIndex()
.Value;
}
internal void Add(short generation, int name, int mvid, int encid, int encbaseid)
{
Record record = new Record();
record.Generation = generation;
record.Name = name;
record.Mvid = mvid;
record.EncId = encid;
record.EncBaseId = encbaseid;
AddRecord(record);
}
}
internal sealed class AssemblyTable : Table<AssemblyTable.Record>
{
internal const int Index = 0x20;
internal struct Record
{
internal int HashAlgId;
internal short MajorVersion;
internal short MinorVersion;
internal short BuildNumber;
internal short RevisionNumber;
internal int Flags;
internal int PublicKey;
internal int Name;
internal int Culture;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].HashAlgId);
mw.Write(records[i].MajorVersion);
mw.Write(records[i].MinorVersion);
mw.Write(records[i].BuildNumber);
mw.Write(records[i].RevisionNumber);
mw.Write(records[i].Flags);
mw.WriteBlobIndex(records[i].PublicKey);
mw.WriteStringIndex(records[i].Name);
mw.WriteStringIndex(records[i].Culture);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(16)
.WriteBlobIndex()
.WriteStringIndex()
.WriteStringIndex()
.Value;
}
}
internal sealed class AssemblyRefTable : Table<AssemblyRefTable.Record>
{
internal const int Index = 0x23;
internal struct Record
{
internal short MajorVersion;
internal short MinorVersion;
internal short BuildNumber;
internal short RevisionNumber;
internal int Flags;
internal int PublicKeyOrToken;
internal int Name;
internal int Culture;
internal int HashValue;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].MajorVersion);
mw.Write(records[i].MinorVersion);
mw.Write(records[i].BuildNumber);
mw.Write(records[i].RevisionNumber);
mw.Write(records[i].Flags);
mw.WriteBlobIndex(records[i].PublicKeyOrToken);
mw.WriteStringIndex(records[i].Name);
mw.WriteStringIndex(records[i].Culture);
mw.WriteBlobIndex(records[i].HashValue);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(12)
.WriteBlobIndex()
.WriteStringIndex()
.WriteStringIndex()
.WriteBlobIndex()
.Value;
}
}
internal sealed class TypeRefTable : Table<TypeRefTable.Record>
{
internal const int Index = 0x01;
internal struct Record
{
internal int ResolutionScope;
internal int TypeName;
internal int TypeNameSpace;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteResolutionScope(records[i].ResolutionScope);
mw.WriteStringIndex(records[i].TypeName);
mw.WriteStringIndex(records[i].TypeNameSpace);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.WriteResolutionScope()
.WriteStringIndex()
.WriteStringIndex()
.Value;
}
}
internal sealed class TypeDefTable : VirtualTable
{
internal const int Index = 0x02;
internal int AllocToken()
{
return 0x02000000 + AddRow();
}
internal override void Write(MetadataWriter mw)
{
mw.ModuleBuilder.WriteTypeDefTable(mw);
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(4)
.WriteStringIndex()
.WriteStringIndex()
.WriteTypeDefOrRef()
.WriteField()
.WriteMethodDef()
.Value;
}
}
internal sealed class FieldTable : VirtualTable
{
internal const int Index = 0x04;
internal override void Write(MetadataWriter mw)
{
mw.ModuleBuilder.WriteFieldTable(mw);
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(2)
.WriteStringIndex()
.WriteBlobIndex()
.Value;
}
}
internal sealed class MethodDefTable : VirtualTable
{
internal const int Index = 0x06;
private int baseRVA;
internal override void Write(MetadataWriter mw)
{
mw.ModuleBuilder.WriteMethodDefTable(baseRVA, mw);
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(8)
.WriteStringIndex()
.WriteBlobIndex()
.WriteParam()
.Value;
}
internal void Fixup(TextSection code)
{
baseRVA = (int)code.MethodBodiesRVA;
}
}
internal sealed class ParamTable : VirtualTable
{
internal const int Index = 0x08;
internal override void Write(MetadataWriter mw)
{
mw.ModuleBuilder.WriteParamTable(mw);
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(4)
.WriteStringIndex()
.Value;
}
}
internal sealed class InterfaceImplTable : Table<InterfaceImplTable.Record>, IComparer<InterfaceImplTable.Record>
{
internal const int Index = 0x09;
internal struct Record
{
internal int Class;
internal int Interface;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteTypeDef(records[i].Class);
mw.WriteEncodedTypeDefOrRef(records[i].Interface);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.WriteTypeDef()
.WriteTypeDefOrRef()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder)
{
for (int i = 0; i < rowCount; i++)
{
int token = records[i].Interface;
switch (token >> 24)
{
case 0:
break;
case TableHeap.TypeDefTable.Index:
token = (token & 0xFFFFFF) << 2 | 0;
break;
case TableHeap.TypeRefTable.Index:
token = (token & 0xFFFFFF) << 2 | 1;
break;
case TableHeap.TypeSpecTable.Index:
token = (token & 0xFFFFFF) << 2 | 2;
break;
default:
throw new InvalidOperationException();
}
records[i].Interface = token;
}
Array.Sort(records, 0, rowCount, this);
}
int IComparer<Record>.Compare(Record x, Record y)
{
if (x.Class == y.Class)
{
return x.Interface == y.Interface ? 0 : (x.Interface > y.Interface ? 1 : -1);
}
return x.Class > y.Class ? 1 : -1;
}
}
internal sealed class MemberRefTable : Table<MemberRefTable.Record>
{
internal const int Index = 0x0A;
internal struct Record
{
internal int Class;
internal int Name;
internal int Signature;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteMemberRefParent(records[i].Class);
mw.WriteStringIndex(records[i].Name);
mw.WriteBlobIndex(records[i].Signature);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.WriteMemberRefParent()
.WriteStringIndex()
.WriteBlobIndex()
.Value;
}
}
internal sealed class ConstantTable : Table<ConstantTable.Record>, IComparer<ConstantTable.Record>
{
internal const int Index = 0x0B;
internal struct Record
{
internal short Type;
internal int Parent;
internal int Value;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].Type);
mw.WriteHasConstant(records[i].Parent);
mw.WriteBlobIndex(records[i].Value);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(2)
.WriteHasConstant()
.WriteBlobIndex()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder)
{
for (int i = 0; i < rowCount; i++)
{
int token = records[i].Parent;
if (moduleBuilder.IsPseudoToken(token))
{
token = moduleBuilder.ResolvePseudoToken(token);
}
// do the HasConstant encoding, so that we can sort the table
switch (token >> 24)
{
case TableHeap.FieldTable.Index:
records[i].Parent = (token & 0xFFFFFF) << 2 | 0;
break;
case TableHeap.ParamTable.Index:
records[i].Parent = (token & 0xFFFFFF) << 2 | 1;
break;
case TableHeap.PropertyTable.Index:
records[i].Parent = (token & 0xFFFFFF) << 2 | 2;
break;
default:
throw new NotImplementedException();
}
}
Array.Sort(records, 0, rowCount, this);
}
int IComparer<Record>.Compare(Record x, Record y)
{
return x.Parent == y.Parent ? 0 : (x.Parent > y.Parent ? 1 : -1);
}
}
internal sealed class CustomAttributeTable : Table<CustomAttributeTable.Record>, IComparer<CustomAttributeTable.Record>
{
internal const int Index = 0x0C;
internal struct Record
{
internal int Parent;
internal int Type;
internal int Value;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteHasCustomAttribute(records[i].Parent);
mw.WriteCustomAttributeType(records[i].Type);
mw.WriteBlobIndex(records[i].Value);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.WriteHasCustomAttribute()
.WriteCustomAttributeType()
.WriteBlobIndex()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder)
{
for (int i = 0; i < rowCount; i++)
{
if (moduleBuilder.IsPseudoToken(records[i].Type))
{
records[i].Type = moduleBuilder.ResolvePseudoToken(records[i].Type);
}
int token = records[i].Parent;
if (moduleBuilder.IsPseudoToken(token))
{
token = moduleBuilder.ResolvePseudoToken(token);
}
// do the HasCustomAttribute encoding, so that we can sort the table
switch (token >> 24)
{
case TableHeap.MethodDefTable.Index:
records[i].Parent = (token & 0xFFFFFF) << 5 | 0;
break;
case TableHeap.FieldTable.Index:
records[i].Parent = (token & 0xFFFFFF) << 5 | 1;
break;
case TableHeap.TypeDefTable.Index:
records[i].Parent = (token & 0xFFFFFF) << 5 | 3;
break;
case TableHeap.ParamTable.Index:
records[i].Parent = (token & 0xFFFFFF) << 5 | 4;
break;
case TableHeap.ModuleTable.Index:
records[i].Parent = (token & 0xFFFFFF) << 5 | 7;
break;
case TableHeap.PropertyTable.Index:
records[i].Parent = (token & 0xFFFFFF) << 5 | 9;
break;
case TableHeap.AssemblyTable.Index:
records[i].Parent = (token & 0xFFFFFF) << 5 | 14;
break;
default:
throw new NotImplementedException();
}
}
Array.Sort(records, 0, rowCount, this);
}
int IComparer<Record>.Compare(Record x, Record y)
{
return x.Parent == y.Parent ? 0 : (x.Parent > y.Parent ? 1 : -1);
}
}
internal sealed class FieldMarshalTable : Table<FieldMarshalTable.Record>, IComparer<FieldMarshalTable.Record>
{
internal const int Index = 0x0D;
internal struct Record
{
internal int Parent;
internal int NativeType;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteHasFieldMarshal(records[i].Parent);
mw.WriteBlobIndex(records[i].NativeType);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.WriteHasFieldMarshal()
.WriteBlobIndex()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder)
{
for (int i = 0; i < rowCount; i++)
{
int token = moduleBuilder.ResolvePseudoToken(records[i].Parent);
// do the HasFieldMarshal encoding, so that we can sort the table
switch (token >> 24)
{
case TableHeap.FieldTable.Index:
records[i].Parent = (token & 0xFFFFFF) << 1 | 0;
break;
case TableHeap.ParamTable.Index:
records[i].Parent = (token & 0xFFFFFF) << 1 | 1;
break;
default:
throw new NotImplementedException();
}
}
Array.Sort(records, 0, rowCount, this);
}
int IComparer<Record>.Compare(Record x, Record y)
{
return x.Parent == y.Parent ? 0 : (x.Parent > y.Parent ? 1 : -1);
}
}
internal sealed class DeclSecurityTable : Table<DeclSecurityTable.Record>, IComparer<DeclSecurityTable.Record>
{
internal const int Index = 0x0E;
internal struct Record
{
internal short Action;
internal int Parent;
internal int PermissionSet;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].Action);
mw.WriteHasDeclSecurity(records[i].Parent);
mw.WriteBlobIndex(records[i].PermissionSet);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(2)
.WriteHasDeclSecurity()
.WriteBlobIndex()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder)
{
for (int i = 0; i < rowCount; i++)
{
int token = records[i].Parent;
if (moduleBuilder.IsPseudoToken(token))
{
token = moduleBuilder.ResolvePseudoToken(token);
}
// do the HasDeclSecurity encoding, so that we can sort the table
switch (token >> 24)
{
case TableHeap.TypeDefTable.Index:
token = (token & 0xFFFFFF) << 2 | 0;
break;
case TableHeap.MethodDefTable.Index:
token = (token & 0xFFFFFF) << 2 | 1;
break;
case TableHeap.AssemblyTable.Index:
token = (token & 0xFFFFFF) << 2 | 2;
break;
default:
throw new InvalidOperationException();
}
records[i].Parent = token;
}
Array.Sort(records, 0, rowCount, this);
}
int IComparer<Record>.Compare(Record x, Record y)
{
return x.Parent == y.Parent ? 0 : (x.Parent > y.Parent ? 1 : -1);
}
}
internal sealed class ClassLayoutTable : Table<ClassLayoutTable.Record>, IComparer<ClassLayoutTable.Record>
{
internal const int Index = 0x0f;
internal struct Record
{
internal short PackingSize;
internal int ClassSize;
internal int Parent;
}
internal override void Write(MetadataWriter mw)
{
Array.Sort(records, 0, rowCount, this);
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].PackingSize);
mw.Write(records[i].ClassSize);
mw.WriteTypeDef(records[i].Parent);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(6)
.WriteTypeDef()
.Value;
}
int IComparer<Record>.Compare(Record x, Record y)
{
return x.Parent == y.Parent ? 0 : (x.Parent > y.Parent ? 1 : -1);
}
internal void GetLayout(int token, ref int pack, ref int size)
{
for (int i = 0; i < rowCount; i++)
{
if (records[i].Parent == token)
{
pack = records[i].PackingSize;
size = records[i].ClassSize;
break;
}
}
}
}
internal sealed class FieldLayoutTable : Table<FieldLayoutTable.Record>, IComparer<FieldLayoutTable.Record>
{
internal const int Index = 0x10;
internal struct Record
{
internal int Offset;
internal int Field;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].Offset);
mw.WriteField(records[i].Field);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(4)
.WriteField()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder)
{
for (int i = 0; i < rowCount; i++)
{
records[i].Field = moduleBuilder.ResolvePseudoToken(records[i].Field);
}
Array.Sort(records, 0, rowCount, this);
}
int IComparer<Record>.Compare(Record x, Record y)
{
return x.Field == y.Field ? 0 : (x.Field > y.Field ? 1 : -1);
}
}
internal sealed class StandAloneSigTable : Table<int>
{
internal const int Index = 0x11;
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteBlobIndex(records[i]);
}
}
protected override int GetRowSize(Table.RowSizeCalc rsc)
{
return rsc.WriteBlobIndex().Value;
}
internal int Add(int blob)
{
for (int i = 0; i < rowCount; i++)
{
if (records[i] == blob)
{
return i + 1;
}
}
return AddRecord(blob);
}
}
internal sealed class PropertyMapTable : Table<PropertyMapTable.Record>
{
internal const int Index = 0x15;
internal struct Record
{
internal int Parent;
internal int PropertyList;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteTypeDef(records[i].Parent);
mw.WriteProperty(records[i].PropertyList);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.WriteTypeDef()
.WriteProperty()
.Value;
}
}
internal sealed class PropertyTable : Table<PropertyTable.Record>
{
internal const int Index = 0x17;
internal struct Record
{
internal short Flags;
internal int Name;
internal int Type;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].Flags);
mw.WriteStringIndex(records[i].Name);
mw.WriteBlobIndex(records[i].Type);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(2)
.WriteStringIndex()
.WriteBlobIndex()
.Value;
}
}
internal sealed class MethodSemanticsTable : Table<MethodSemanticsTable.Record>, IComparer<MethodSemanticsTable.Record>
{
internal const int Index = 0x18;
internal struct Record
{
internal short Semantics;
internal int Method;
internal int Association;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].Semantics);
mw.WriteMethodDef(records[i].Method);
mw.WriteHasSemantics(records[i].Association);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(2)
.WriteMethodDef()
.WriteHasSemantics()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder)
{
for (int i = 0; i < rowCount; i++)
{
if (moduleBuilder.IsPseudoToken(records[i].Method))
{
records[i].Method = moduleBuilder.ResolvePseudoToken(records[i].Method);
}
int token = records[i].Association;
// do the HasSemantics encoding, so that we can sort the table
switch (token >> 24)
{
case TableHeap.PropertyTable.Index:
token = (token & 0xFFFFFF) << 1 | 1;
break;
default:
throw new NotImplementedException();
}
records[i].Association = token;
}
Array.Sort(records, 0, rowCount, this);
}
int IComparer<Record>.Compare(Record x, Record y)
{
return x.Association == y.Association ? 0 : (x.Association > y.Association ? 1 : -1);
}
}
internal sealed class MethodImplTable : Table<MethodImplTable.Record>, IComparer<MethodImplTable.Record>
{
internal const int Index = 0x19;
internal struct Record
{
internal int Class;
internal int MethodBody;
internal int MethodDeclaration;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteTypeDef(records[i].Class);
mw.WriteMethodDefOrRef(records[i].MethodBody);
mw.WriteMethodDefOrRef(records[i].MethodDeclaration);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.WriteTypeDef()
.WriteMethodDefOrRef()
.WriteMethodDefOrRef()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder)
{
for (int i = 0; i < rowCount; i++)
{
if (moduleBuilder.IsPseudoToken(records[i].MethodBody))
{
records[i].MethodBody = moduleBuilder.ResolvePseudoToken(records[i].MethodBody);
}
if (moduleBuilder.IsPseudoToken(records[i].MethodDeclaration))
{
records[i].MethodDeclaration = moduleBuilder.ResolvePseudoToken(records[i].MethodDeclaration);
}
}
Array.Sort(records, 0, rowCount, this);
}
int IComparer<Record>.Compare(Record x, Record y)
{
return x.Class == y.Class ? 0 : (x.Class > y.Class ? 1 : -1);
}
}
internal sealed class ModuleRefTable : Table<int>
{
internal const int Index = 0x1A;
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteStringIndex(records[i]);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.WriteStringIndex()
.Value;
}
internal int Add(int str)
{
for (int i = 0; i < rowCount; i++)
{
if (records[i] == str)
{
return i + 1;
}
}
return AddRecord(str);
}
}
internal sealed class TypeSpecTable : Table<int>
{
internal const int Index = 0x1B;
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteBlobIndex(records[i]);
}
}
protected override int GetRowSize(Table.RowSizeCalc rsc)
{
return rsc.WriteBlobIndex().Value;
}
}
internal sealed class ImplMapTable : Table<ImplMapTable.Record>, IComparer<ImplMapTable.Record>
{
internal const int Index = 0x1C;
internal struct Record
{
internal short MappingFlags;
internal int MemberForwarded;
internal int ImportName;
internal int ImportScope;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].MappingFlags);
mw.WriteMemberForwarded(records[i].MemberForwarded);
mw.WriteStringIndex(records[i].ImportName);
mw.WriteModuleRef(records[i].ImportScope);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(2)
.WriteMemberForwarded()
.WriteStringIndex()
.WriteModuleRef()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder)
{
for (int i = 0; i < rowCount; i++)
{
if (moduleBuilder.IsPseudoToken(records[i].MemberForwarded))
{
records[i].MemberForwarded = moduleBuilder.ResolvePseudoToken(records[i].MemberForwarded);
}
}
Array.Sort(records, 0, rowCount, this);
}
int IComparer<Record>.Compare(Record x, Record y)
{
return x.MemberForwarded == y.MemberForwarded ? 0 : (x.MemberForwarded > y.MemberForwarded ? 1 : -1);
}
}
internal sealed class FieldRVATable : Table<FieldRVATable.Record>, IComparer<FieldRVATable.Record>
{
internal const int Index = 0x1D;
internal struct Record
{
internal int RVA;
internal int Field;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].RVA);
mw.WriteField(records[i].Field);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(4)
.WriteField()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder, int sdataRVA)
{
for (int i = 0; i < rowCount; i++)
{
records[i].RVA += sdataRVA;
if (moduleBuilder.IsPseudoToken(records[i].Field))
{
records[i].Field = moduleBuilder.ResolvePseudoToken(records[i].Field);
}
}
Array.Sort(records, 0, rowCount, this);
}
int IComparer<Record>.Compare(Record x, Record y)
{
return x.Field == y.Field ? 0 : (x.Field > y.Field ? 1 : -1);
}
}
internal sealed class FileTable : Table<FileTable.Record>
{
internal const int Index = 0x26;
internal struct Record
{
internal int Flags;
internal int Name;
internal int HashValue;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].Flags);
mw.WriteStringIndex(records[i].Name);
mw.WriteBlobIndex(records[i].HashValue);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(4)
.WriteStringIndex()
.WriteBlobIndex()
.Value;
}
}
internal sealed class ExportedTypeTable : Table<ExportedTypeTable.Record>
{
internal const int Index = 0x27;
internal struct Record
{
internal int Flags;
internal int TypeDefId;
internal int TypeName;
internal int TypeNamespace;
internal int Implementation;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].Flags);
mw.Write(records[i].TypeDefId);
mw.WriteStringIndex(records[i].TypeName);
mw.WriteStringIndex(records[i].TypeNamespace);
mw.WriteImplementation(records[i].Implementation);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(8)
.WriteStringIndex()
.WriteStringIndex()
.WriteImplementation()
.Value;
}
internal int FindOrAddRecord(Record rec)
{
for (int i = 0; i < rowCount; i++)
{
if (records[i].Implementation == rec.Implementation
&& records[i].TypeName == rec.TypeName
&& records[i].TypeNamespace == rec.TypeNamespace)
{
return i + 1;
}
}
return AddRecord(rec);
}
}
internal sealed class ManifestResourceTable : Table<ManifestResourceTable.Record>
{
internal const int Index = 0x28;
internal struct Record
{
internal int Offset;
internal int Flags;
internal int Name;
internal int Implementation;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].Offset);
mw.Write(records[i].Flags);
mw.WriteStringIndex(records[i].Name);
mw.WriteImplementation(records[i].Implementation);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(8)
.WriteStringIndex()
.WriteImplementation()
.Value;
}
}
internal sealed class NestedClassTable : Table<NestedClassTable.Record>
{
internal const int Index = 0x29;
internal struct Record
{
internal int NestedClass;
internal int EnclosingClass;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteTypeDef(records[i].NestedClass);
mw.WriteTypeDef(records[i].EnclosingClass);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.WriteTypeDef()
.WriteTypeDef()
.Value;
}
internal List<int> GetNestedClasses(int enclosingClass)
{
List<int> nestedClasses = new List<int>();
for (int i = 0; i < rowCount; i++)
{
if (records[i].EnclosingClass == enclosingClass)
{
nestedClasses.Add(records[i].NestedClass);
}
}
return nestedClasses;
}
}
internal sealed class GenericParamTable : Table<GenericParamTable.Record>, IComparer<GenericParamTable.Record>
{
internal const int Index = 0x2A;
internal struct Record
{
internal short Number;
internal short Flags;
internal int Owner;
internal int Name;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.Write(records[i].Number);
mw.Write(records[i].Flags);
mw.WriteTypeOrMethodDef(records[i].Owner);
mw.WriteStringIndex(records[i].Name);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.AddFixed(4)
.WriteTypeOrMethodDef()
.WriteStringIndex()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder)
{
for (int i = 0; i < rowCount; i++)
{
int token = records[i].Owner;
if (moduleBuilder.IsPseudoToken(token))
{
token = moduleBuilder.ResolvePseudoToken(token);
}
// do the TypeOrMethodDef encoding, so that we can sort the table
switch (token >> 24)
{
case TableHeap.TypeDefTable.Index:
records[i].Owner = (token & 0xFFFFFF) << 1 | 0;
break;
case TableHeap.MethodDefTable.Index:
records[i].Owner = (token & 0xFFFFFF) << 1 | 1;
break;
default:
throw new InvalidOperationException();
}
}
Array.Sort(records, 0, rowCount, this);
}
int IComparer<Record>.Compare(Record x, Record y)
{
if (x.Owner == y.Owner)
{
return x.Number == y.Number ? 0 : (x.Number > y.Number ? 1 : -1);
}
return x.Owner > y.Owner ? 1 : -1;
}
}
internal sealed class MethodSpecTable : Table<MethodSpecTable.Record>
{
internal const int Index = 0x2B;
internal struct Record
{
internal int Method;
internal int Instantiation;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteMethodDefOrRef(records[i].Method);
mw.WriteBlobIndex(records[i].Instantiation);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.WriteMethodDefOrRef()
.WriteBlobIndex()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder)
{
for (int i = 0; i < rowCount; i++)
{
if (moduleBuilder.IsPseudoToken(records[i].Method))
{
records[i].Method = moduleBuilder.ResolvePseudoToken(records[i].Method);
}
}
}
}
internal sealed class GenericParamConstraintTable : Table<GenericParamConstraintTable.Record>, IComparer<GenericParamConstraintTable.Record>
{
internal const int Index = 0x2C;
internal struct Record
{
internal int Owner;
internal int Constraint;
}
internal override void Write(MetadataWriter mw)
{
for (int i = 0; i < rowCount; i++)
{
mw.WriteGenericParam(records[i].Owner);
mw.WriteTypeDefOrRef(records[i].Constraint);
}
}
protected override int GetRowSize(RowSizeCalc rsc)
{
return rsc
.WriteGenericParam()
.WriteTypeDefOrRef()
.Value;
}
internal void Fixup(ModuleBuilder moduleBuilder)
{
Array.Sort(records, 0, rowCount, this);
}
int IComparer<Record>.Compare(Record x, Record y)
{
return x.Owner == y.Owner ? 0 : (x.Owner > y.Owner ? 1 : -1);
}
}
protected override void WriteImpl(MetadataWriter mw)
{
// Header
mw.Write(0); // Reserved
mw.Write((byte)2); // MajorVersion
mw.Write((byte)0); // MinorVersion
byte heapSizes = 0;
if (mw.ModuleBuilder.Strings.IsBig)
{
heapSizes |= 0x01;
}
if (mw.ModuleBuilder.Guids.IsBig)
{
heapSizes |= 0x02;
}
if (mw.ModuleBuilder.Blobs.IsBig)
{
heapSizes |= 0x04;
}
mw.Write(heapSizes);// HeapSizes
// LAMESPEC spec says reserved, but .NET 2.0 Ref.Emit sets it to 0x10
mw.Write((byte)0x10); // Reserved
long bit = 1;
long valid = 0;
foreach (Table table in tables)
{
if (table != null && table.RowCount > 0)
{
valid |= bit;
}
bit <<= 1;
}
mw.Write(valid); // Valid
mw.Write(0x0016003301FA00L); // Sorted
// Rows
foreach (Table table in tables)
{
if (table != null && table.RowCount > 0)
{
mw.Write(table.RowCount);
}
}
// Tables
foreach (Table table in tables)
{
if (table != null && table.RowCount > 0)
{
int pos = mw.Position;
table.Write(mw);
Debug.Assert(mw.Position - pos == table.GetLength(mw.ModuleBuilder));
}
}
// unexplained extra padding
mw.Write((byte)0);
}
protected override int GetLength(ModuleBuilder md)
{
int len = 4 + 4 + 8 + 8;
foreach (Table table in tables)
{
if (table != null && table.RowCount > 0)
{
len += 4; // row count
len += table.GetLength(md);
}
}
// note that we pad one extra (unexplained) byte
return len + 1;
}
}
sealed class StringHeap : Heap
{
private List<string> list = new List<string>();
private Dictionary<string, int> strings = new Dictionary<string, int>();
private int nextOffset;
internal StringHeap()
{
Add("");
}
internal int Add(string str)
{
int offset;
if (!strings.TryGetValue(str, out offset))
{
offset = nextOffset;
nextOffset += System.Text.Encoding.UTF8.GetByteCount(str) + 1;
list.Add(str);
strings.Add(str, offset);
}
return offset;
}
protected override int GetLength(ModuleBuilder md)
{
return nextOffset;
}
protected override void WriteImpl(MetadataWriter mw)
{
foreach (string str in list)
{
mw.Write(System.Text.Encoding.UTF8.GetBytes(str));
mw.Write((byte)0);
}
}
}
sealed class UserStringHeap : Heap
{
private List<string> list = new List<string>();
private Dictionary<string, int> strings = new Dictionary<string, int>();
private int nextOffset;
internal UserStringHeap()
{
nextOffset = 1;
}
internal bool IsEmpty
{
get { return nextOffset == 1; }
}
internal int Add(string str)
{
int offset;
if (!strings.TryGetValue(str, out offset))
{
offset = nextOffset;
nextOffset += str.Length * 2 + 1 + MetadataWriter.GetCompressedIntLength(str.Length * 2 + 1);
list.Add(str);
strings.Add(str, offset);
}
return offset;
}
protected override int GetLength(ModuleBuilder md)
{
return nextOffset;
}
protected override void WriteImpl(MetadataWriter mw)
{
mw.Write((byte)0);
foreach (string str in list)
{
mw.WriteCompressedInt(str.Length * 2 + 1);
byte hasSpecialChars = 0;
foreach (char ch in str)
{
mw.Write((ushort)ch);
if (hasSpecialChars == 0 && (ch < 0x20 || ch > 0x7E))
{
if (ch > 0x7E
|| (ch >= 0x01 && ch <= 0x08)
|| (ch >= 0x0E && ch <= 0x1F)
|| ch == 0x27
|| ch == 0x2D)
{
hasSpecialChars = 1;
}
}
}
mw.Write(hasSpecialChars);
}
}
}
sealed class GuidHeap : Heap
{
private List<Guid> list = new List<Guid>();
internal GuidHeap()
{
}
internal int Add(Guid guid)
{
list.Add(guid);
return list.Count;
}
protected override int GetLength(ModuleBuilder md)
{
return list.Count * 16;
}
protected override void WriteImpl(MetadataWriter mw)
{
foreach (Guid guid in list)
{
mw.Write(guid.ToByteArray());
}
}
}
sealed class BlobHeap : Heap
{
private Key[] map = new Key[8179];
private readonly ByteBuffer buf = new ByteBuffer(32);
private struct Key
{
internal Key[] next;
internal int len;
internal int hash;
internal int offset;
}
internal BlobHeap()
{
buf.Write((byte)0);
}
internal int Add(ByteBuffer bb)
{
if (bb.Length == 0)
{
return 0;
}
int lenlen = MetadataWriter.GetCompressedIntLength(bb.Length);
int hash = bb.Hash();
int index = (hash & 0x7FFFFFFF) % map.Length;
Key[] keys = map;
int last = index;
while (keys[index].offset != 0)
{
if (keys[index].hash == hash
&& keys[index].len == bb.Length
&& buf.Match(keys[index].offset + lenlen, bb, 0, bb.Length))
{
return keys[index].offset;
}
if (index == last)
{
if (keys[index].next == null)
{
keys[index].next = new Key[4];
keys = keys[index].next;
index = 0;
break;
}
keys = keys[index].next;
index = -1;
last = keys.Length - 1;
}
index++;
}
int offset = buf.Position;
buf.WriteCompressedInt(bb.Length);
buf.Write(bb);
keys[index].len = bb.Length;
keys[index].hash = hash;
keys[index].offset = offset;
return offset;
}
protected override int GetLength(ModuleBuilder md)
{
return buf.Position;
}
protected override void WriteImpl(MetadataWriter mw)
{
mw.Write(buf);
}
internal bool IsEmpty
{
get { return buf.Position == 1; }
}
}
}