Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/ikvm-fork.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjfrijters <jfrijters>2008-11-14 10:40:49 +0300
committerjfrijters <jfrijters>2008-11-14 10:40:49 +0300
commit4f74774934920bf3858a61f386946b678ed5b6ef (patch)
tree68810a38627d3d677aa26be8efbf2ce54fb875a3
parent19f5c9cd08a5f692a1153c5f2393b520e6269612 (diff)
New Ref.Emit implementation.
-rw-r--r--refemit/AssemblyBuilder.cs268
-rw-r--r--refemit/ConstructorBuilder.cs133
-rw-r--r--refemit/CustomAttributeBuilder.cs465
-rw-r--r--refemit/Enums.cs79
-rw-r--r--refemit/FieldBuilder.cs223
-rw-r--r--refemit/IKVM.Reflection.Emit.csproj77
-rw-r--r--refemit/ILGenerator.cs1000
-rw-r--r--refemit/IkvmAssembly.cs70
-rw-r--r--refemit/Impl/CryptoConvert.cs743
-rw-r--r--refemit/Impl/CryptoHack.cs57
-rw-r--r--refemit/Impl/ITypeOwner.cs31
-rw-r--r--refemit/Impl/PdbSupport.cs179
-rw-r--r--refemit/Impl/TypeBase.cs223
-rw-r--r--refemit/MethodBuilder.cs524
-rw-r--r--refemit/ModuleBuilder.cs911
-rw-r--r--refemit/OpCodes.cs308
-rw-r--r--refemit/ParameterBuilder.cs107
-rw-r--r--refemit/Properties/AssemblyInfo.cs28
-rw-r--r--refemit/PropertyBuilder.cs202
-rw-r--r--refemit/SignatureHelper.cs353
-rw-r--r--refemit/Tokens.cs81
-rw-r--r--refemit/TypeBuilder.cs893
-rw-r--r--refemit/Writer/ByteBuffer.cs281
-rw-r--r--refemit/Writer/Heaps.cs2107
-rw-r--r--refemit/Writer/MetadataWriter.cs538
-rw-r--r--refemit/Writer/ModuleWriter.cs394
-rw-r--r--refemit/Writer/PEWriter.cs301
-rw-r--r--refemit/Writer/TextSection.cs490
-rw-r--r--refemit/Writer/VersionInfo.cs244
-rw-r--r--refemit/refemit.build46
30 files changed, 11356 insertions, 0 deletions
diff --git a/refemit/AssemblyBuilder.cs b/refemit/AssemblyBuilder.cs
new file mode 100644
index 00000000..454dad68
--- /dev/null
+++ b/refemit/AssemblyBuilder.cs
@@ -0,0 +1,268 @@
+/*
+ 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.Reflection;
+using System.Collections.Generic;
+using System.IO;
+using System.Diagnostics;
+using System.Security.Cryptography;
+using IKVM.Reflection.Emit.Writer;
+using IKVM.Reflection.Emit.Impl;
+
+namespace IKVM.Reflection.Emit
+{
+ public sealed class AssemblyBuilder : IkvmAssembly
+ {
+ private readonly AssemblyName name;
+ private readonly string dir;
+ private PEFileKinds fileKind = PEFileKinds.Dll;
+ private MethodBuilder entryPoint;
+ private bool setVersionInfo;
+ private List<ResourceFile> resourceFiles = new List<ResourceFile>();
+ private List<ModuleBuilder> modules = new List<ModuleBuilder>();
+ private List<CustomAttributeBuilder> customAttributes = new List<CustomAttributeBuilder>();
+
+ private struct ResourceFile
+ {
+ internal string Name;
+ internal string FileName;
+ internal ResourceAttributes Attributes;
+ }
+
+ private AssemblyBuilder(AssemblyName name, string dir)
+ {
+ this.name = name;
+ this.dir = dir;
+ }
+
+ public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access)
+ {
+ return DefineDynamicAssembly(name, access, null);
+ }
+
+ public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access, string dir)
+ {
+ return new AssemblyBuilder(name, dir);
+ }
+
+ public AssemblyName GetName()
+ {
+ return name;
+ }
+
+ public string FullName
+ {
+ get { return name.FullName; }
+ }
+
+ public ModuleBuilder DefineDynamicModule(string name, string fileName, bool emitSymbolInfo)
+ {
+ ModuleBuilder module = new ModuleBuilder(this, name, fileName, emitSymbolInfo);
+ modules.Add(module);
+ return module;
+ }
+
+ public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+ {
+ if (customBuilder.Constructor.DeclaringType == typeof(AssemblyVersionAttribute))
+ {
+ throw new NotImplementedException();
+ }
+ else
+ {
+ customAttributes.Add(customBuilder);
+ }
+ }
+
+ public void SetEntryPoint(MethodBuilder mb)
+ {
+ SetEntryPoint(mb, PEFileKinds.ConsoleApplication);
+ }
+
+ public void SetEntryPoint(MethodBuilder mb, PEFileKinds kind)
+ {
+ this.entryPoint = mb;
+ this.fileKind = kind;
+ }
+
+ public void Save(string assemblyFileName)
+ {
+ Save(assemblyFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
+ }
+
+ public void Save(string assemblyFileName, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
+ {
+ ModuleBuilder manifestModule = null;
+
+ foreach (ModuleBuilder moduleBuilder in modules)
+ {
+ if (string.Compare(moduleBuilder.fileName, assemblyFileName, StringComparison.OrdinalIgnoreCase) == 0)
+ {
+ manifestModule = moduleBuilder;
+ break;
+ }
+ }
+
+ if (manifestModule == null)
+ {
+ manifestModule = DefineDynamicModule("RefEmit_OnDiskManifestModule", assemblyFileName, false);
+ }
+
+ TableHeap.AssemblyTable.Record assemblyRecord = new TableHeap.AssemblyTable.Record();
+ assemblyRecord.HashAlgId = 0x8004; // SHA1
+ assemblyRecord.Name = manifestModule.Strings.Add(name.Name);
+ if (name.Version != null)
+ {
+ assemblyRecord.MajorVersion = (short)name.Version.Major;
+ assemblyRecord.MinorVersion = (short)name.Version.Major;
+ assemblyRecord.BuildNumber = (short)name.Version.Build;
+ assemblyRecord.RevisionNumber = (short)name.Version.Revision;
+ }
+ if (name.KeyPair != null)
+ {
+ assemblyRecord.PublicKey = manifestModule.Blobs.Add(ByteBuffer.Wrap(name.KeyPair.PublicKey));
+ assemblyRecord.Flags |= 0x0001; // PublicKey
+ }
+ if (name.CultureInfo != null)
+ {
+ assemblyRecord.Culture = manifestModule.Strings.Add(name.CultureInfo.Name);
+ }
+ manifestModule.Tables.Assembly.AddRecord(assemblyRecord);
+
+ ByteBuffer versionInfoData = null;
+ if (setVersionInfo)
+ {
+ VersionInfo versionInfo = new VersionInfo();
+ versionInfo.SetName(name);
+ versionInfo.SetFileName(assemblyFileName);
+ foreach (CustomAttributeBuilder cab in customAttributes)
+ {
+ versionInfo.SetAttribute(cab);
+ }
+ versionInfoData = new ByteBuffer(512);
+ versionInfo.Write(versionInfoData);
+ }
+
+ foreach (CustomAttributeBuilder cab in customAttributes)
+ {
+ manifestModule.SetCustomAttribute(0x20000001, cab);
+ }
+
+ foreach (ResourceFile resfile in resourceFiles)
+ {
+ int fileToken = AddFile(manifestModule, resfile.FileName, 1 /*ContainsNoMetaData*/);
+ TableHeap.ManifestResourceTable.Record rec = new TableHeap.ManifestResourceTable.Record();
+ rec.Offset = 0;
+ rec.Flags = (int)resfile.Attributes;
+ rec.Name = manifestModule.Strings.Add(resfile.Name);
+ rec.Implementation = fileToken;
+ manifestModule.Tables.ManifestResource.AddRecord(rec);
+ }
+
+ int entryPointToken = 0;
+
+ foreach (ModuleBuilder moduleBuilder in modules)
+ {
+ if (moduleBuilder != manifestModule)
+ {
+ int fileToken;
+ if (entryPoint != null && entryPoint.ModuleBuilder == moduleBuilder)
+ {
+ ModuleWriter.WriteModule(dir, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, null, entryPoint.MetadataToken);
+ entryPointToken = fileToken = AddFile(manifestModule, moduleBuilder.fileName, 0 /*ContainsMetaData*/);
+ }
+ else
+ {
+ ModuleWriter.WriteModule(dir, null, moduleBuilder, fileKind, portableExecutableKind, imageFileMachine, null, 0);
+ fileToken = AddFile(manifestModule, moduleBuilder.fileName, 0 /*ContainsMetaData*/);
+ }
+ moduleBuilder.ExportTypes(fileToken, manifestModule);
+ }
+ }
+
+ if (entryPointToken == 0 && entryPoint != null)
+ {
+ entryPointToken = entryPoint.MetadataToken;
+ }
+
+ // finally, write the manifest module
+ ModuleWriter.WriteModule(dir, name.KeyPair, manifestModule, fileKind, portableExecutableKind, imageFileMachine, versionInfoData, entryPointToken);
+ }
+
+ private int AddFile(ModuleBuilder manifestModule, string fileName, int flags)
+ {
+ SHA1Managed hash = new SHA1Managed();
+ string fullPath = fileName;
+ if (dir != null)
+ {
+ fullPath = Path.Combine(dir, fileName);
+ }
+ using (FileStream fs = new FileStream(fullPath, FileMode.Open, FileAccess.Read))
+ {
+ using (CryptoStream cs = new CryptoStream(Stream.Null, hash, CryptoStreamMode.Write))
+ {
+ byte[] buf = new byte[8192];
+ ModuleWriter.HashChunk(fs, cs, buf, (int)fs.Length);
+ }
+ }
+ TableHeap.FileTable.Record file = new TableHeap.FileTable.Record();
+ file.Flags = flags;
+ file.Name = manifestModule.Strings.Add(fileName);
+ file.HashValue = manifestModule.Blobs.Add(ByteBuffer.Wrap(hash.Hash));
+ return 0x26000000 + manifestModule.Tables.File.AddRecord(file);
+ }
+
+ public void AddResourceFile(string name, string fileName)
+ {
+ AddResourceFile(name, fileName, ResourceAttributes.Public);
+ }
+
+ public void AddResourceFile(string name, string fileName, ResourceAttributes attribs)
+ {
+ ResourceFile resfile = new ResourceFile();
+ resfile.Name = name;
+ resfile.FileName = fileName;
+ resfile.Attributes = attribs;
+ resourceFiles.Add(resfile);
+ }
+
+ public void DefineVersionInfoResource()
+ {
+ setVersionInfo = true;
+ }
+
+ public override Type GetType(string typeName)
+ {
+ foreach (ModuleBuilder mb in modules)
+ {
+ Type type = mb.GetType(typeName);
+ if (type != null)
+ {
+ return type;
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/refemit/ConstructorBuilder.cs b/refemit/ConstructorBuilder.cs
new file mode 100644
index 00000000..8c208345
--- /dev/null
+++ b/refemit/ConstructorBuilder.cs
@@ -0,0 +1,133 @@
+/*
+ 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.Reflection;
+
+namespace IKVM.Reflection.Emit
+{
+ public sealed class ConstructorBuilder : ConstructorInfo
+ {
+ private readonly MethodBuilder methodBuilder;
+
+ internal ConstructorBuilder(MethodBuilder mb)
+ {
+ this.methodBuilder = mb;
+ }
+
+ public ParameterBuilder DefineParameter(int position, ParameterAttributes attributes, string strParamName)
+ {
+ return methodBuilder.DefineParameter(position, attributes, strParamName);
+ }
+
+ public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+ {
+ methodBuilder.SetCustomAttribute(customBuilder);
+ }
+
+ public void AddDeclarativeSecurity(System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet)
+ {
+ methodBuilder.AddDeclarativeSecurity(securityAction, permissionSet);
+ }
+
+ public void SetImplementationFlags(MethodImplAttributes attributes)
+ {
+ methodBuilder.SetImplementationFlags(attributes);
+ }
+
+ public ILGenerator GetILGenerator()
+ {
+ return methodBuilder.GetILGenerator();
+ }
+
+ public override object Invoke(BindingFlags invokeAttr, Binder binder, object[] parameters, System.Globalization.CultureInfo culture)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override MethodAttributes Attributes
+ {
+ get { return methodBuilder.Attributes; }
+ }
+
+ public override MethodImplAttributes GetMethodImplementationFlags()
+ {
+ return methodBuilder.GetMethodImplementationFlags();
+ }
+
+ public override ParameterInfo[] GetParameters()
+ {
+ return methodBuilder.GetParameters();
+ }
+
+ public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, System.Globalization.CultureInfo culture)
+ {
+ return methodBuilder.Invoke(obj, invokeAttr, binder, parameters, culture);
+ }
+
+ public override RuntimeMethodHandle MethodHandle
+ {
+ get { return methodBuilder.MethodHandle; }
+ }
+
+ public override Type DeclaringType
+ {
+ get { return methodBuilder.DeclaringType; }
+ }
+
+ public override object[] GetCustomAttributes(Type attributeType, bool inherit)
+ {
+ return methodBuilder.GetCustomAttributes(attributeType, inherit);
+ }
+
+ public override object[] GetCustomAttributes(bool inherit)
+ {
+ return methodBuilder.GetCustomAttributes(inherit);
+ }
+
+ public override bool IsDefined(Type attributeType, bool inherit)
+ {
+ return methodBuilder.IsDefined(attributeType, inherit);
+ }
+
+ public override string Name
+ {
+ get { return methodBuilder.Name; }
+ }
+
+ public override Type ReflectedType
+ {
+ get { return methodBuilder.ReflectedType; }
+ }
+
+ public override int MetadataToken
+ {
+ get { return methodBuilder.MetadataToken; }
+ }
+
+ internal ModuleBuilder ModuleBuilder
+ {
+ get { return methodBuilder.ModuleBuilder; }
+ }
+ }
+}
diff --git a/refemit/CustomAttributeBuilder.cs b/refemit/CustomAttributeBuilder.cs
new file mode 100644
index 00000000..1197d1d4
--- /dev/null
+++ b/refemit/CustomAttributeBuilder.cs
@@ -0,0 +1,465 @@
+/*
+ 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.Reflection;
+using System.IO;
+using IKVM.Reflection.Emit.Writer;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+namespace IKVM.Reflection.Emit
+{
+ public class CustomAttributeBuilder
+ {
+ private readonly ConstructorInfo con;
+ private readonly byte[] blob;
+ private readonly object[] constructorArgs;
+ private readonly PropertyInfo[] namedProperties;
+ private readonly object[] propertyValues;
+ private readonly FieldInfo[] namedFields;
+ private readonly object[] fieldValues;
+
+ internal CustomAttributeBuilder(ConstructorInfo con, byte[] blob)
+ {
+ this.con = con;
+ this.blob = blob;
+ this.constructorArgs = null;
+ this.namedProperties = null;
+ this.propertyValues = null;
+ this.namedFields = null;
+ this.fieldValues = null;
+ }
+
+ public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs)
+ : this(con, constructorArgs, null, null, null,null)
+ {
+ }
+
+ public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, FieldInfo[] namedFields, object[] fieldValues)
+ : this(con, constructorArgs, null, null, namedFields, fieldValues)
+ {
+ }
+
+ public CustomAttributeBuilder(ConstructorInfo con, object[] constructorArgs, PropertyInfo[] namedProperties, object[] propertyValues, FieldInfo[] namedFields, object[] fieldValues)
+ {
+ this.con = con;
+ this.blob = null;
+ this.constructorArgs = constructorArgs;
+ this.namedProperties = namedProperties;
+ this.propertyValues = propertyValues;
+ this.namedFields = namedFields;
+ this.fieldValues = fieldValues;
+ }
+
+ private class BlobWriter
+ {
+ private readonly ModuleBuilder moduleBuilder;
+ private readonly CustomAttributeBuilder cab;
+ private readonly MemoryStream str = new MemoryStream();
+
+ internal BlobWriter(ModuleBuilder moduleBuilder, CustomAttributeBuilder cab)
+ {
+ this.moduleBuilder = moduleBuilder;
+ this.cab = cab;
+ }
+
+ internal byte[] GetBlob()
+ {
+ // prolog
+ WriteUInt16(1);
+ ParameterInfo[] pi = cab.con.GetParameters();
+ for (int i = 0; i < pi.Length; i++)
+ {
+ WriteFixedArg(pi[i].ParameterType, cab.constructorArgs[i]);
+ }
+ // NumNamed
+ int named = 0;
+ if (cab.namedFields != null)
+ {
+ named += cab.namedFields.Length;
+ }
+ if (cab.namedProperties != null)
+ {
+ named += cab.namedProperties.Length;
+ }
+ WriteUInt16((ushort)named);
+ if (cab.namedFields != null)
+ {
+ for (int i = 0; i < cab.namedFields.Length; i++)
+ {
+ WriteNamedArg(0x53, cab.namedFields[i].FieldType, cab.namedFields[i].Name, cab.fieldValues[i]);
+ }
+ }
+ if (cab.namedProperties != null)
+ {
+ for (int i = 0; i < cab.namedProperties.Length; i++)
+ {
+ WriteNamedArg(0x54, cab.namedProperties[i].PropertyType, cab.namedProperties[i].Name, cab.propertyValues[i]);
+ }
+ }
+ return str.ToArray();
+ }
+
+ private void WriteNamedArg(byte fieldOrProperty, Type type, string name, object value)
+ {
+ str.WriteByte(fieldOrProperty);
+ WriteFieldOrPropType(type);
+ WriteString(name);
+ WriteFixedArg(type, value);
+ }
+
+ private void WriteUInt16(ushort value)
+ {
+ str.WriteByte((byte)value);
+ str.WriteByte((byte)(value >> 8));
+ }
+
+ private void WriteInt32(int value)
+ {
+ str.WriteByte((byte)(value >> 0));
+ str.WriteByte((byte)(value >> 8));
+ str.WriteByte((byte)(value >> 16));
+ str.WriteByte((byte)(value >> 24));
+ }
+
+ private void WriteFixedArg(Type type, object value)
+ {
+ if (type.IsArray)
+ {
+ if (value == null)
+ {
+ WriteInt32(-1);
+ }
+ else
+ {
+ Array array = (Array)value;
+ Type elemType = type.GetElementType();
+ WriteInt32(array.Length);
+ foreach (object val in array)
+ {
+ WriteElem(elemType, val);
+ }
+ }
+ }
+ else
+ {
+ WriteElem(type, value);
+ }
+ }
+
+ private void WriteElem(Type type, object value)
+ {
+ if (type == typeof(string))
+ {
+ WriteString((string)value);
+ }
+ else if (type == typeof(Type))
+ {
+ WriteTypeName((Type)value);
+ }
+ else if (type == typeof(object))
+ {
+ if (value == null)
+ {
+ type = typeof(string);
+ }
+ else if (value is Type)
+ {
+ // value.GetType() would return a RuntimeType, but we don't want to deal with that
+ type = typeof(Type);
+ }
+ else
+ {
+ type = value.GetType();
+ }
+ WriteFieldOrPropType(type);
+ WriteElem(type, value);
+ }
+ else if (type.IsArray)
+ {
+ if (value == null)
+ {
+ WriteInt32(-1);
+ }
+ else
+ {
+ Array array = (Array)value;
+ Type elemType = type.GetElementType();
+ WriteInt32(array.Length);
+ foreach (object val in array)
+ {
+ WriteElem(elemType, val);
+ }
+ }
+ }
+ else if (type.IsEnum)
+ {
+ WriteElem(Enum.GetUnderlyingType(type), value);
+ }
+ else
+ {
+ switch (Type.GetTypeCode(type))
+ {
+ case TypeCode.Boolean:
+ str.WriteByte((bool)value ? (byte)1 : (byte)0);
+ break;
+ case TypeCode.Char:
+ WriteUInt16((char)value);
+ break;
+ case TypeCode.SByte:
+ str.WriteByte((byte)(sbyte)value);
+ break;
+ case TypeCode.Byte:
+ str.WriteByte((byte)value);
+ break;
+ case TypeCode.Int16:
+ WriteUInt16((ushort)(short)value);
+ break;
+ case TypeCode.UInt16:
+ WriteUInt16((ushort)value);
+ break;
+ case TypeCode.Int32:
+ WriteInt32((int)value);
+ break;
+ case TypeCode.UInt32:
+ WriteInt32((int)(uint)value);
+ break;
+ case TypeCode.Int64:
+ WriteInt64((long)value);
+ break;
+ case TypeCode.UInt64:
+ WriteInt64((long)(ulong)value);
+ break;
+ case TypeCode.Single:
+ WriteSingle((float)value);
+ break;
+ case TypeCode.Double:
+ WriteDouble((double)value);
+ break;
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ }
+
+ private void WriteInt64(long value)
+ {
+ WriteInt32((int)value);
+ WriteInt32((int)(value >> 32));
+ }
+
+ private void WriteSingle(float value)
+ {
+ str.Write(BitConverter.GetBytes(value), 0, 4);
+ }
+
+ private void WriteDouble(double value)
+ {
+ WriteInt64(BitConverter.DoubleToInt64Bits(value));
+ }
+
+ private void WriteTypeName(Type type)
+ {
+ string name = null;
+ if (type != null)
+ {
+ // we could also use just the FullName for mscorlib types (IkvmAssembly.GetAssembly(type) == IkvmAssembly.GetAssembly(typeof(object)))
+ if (IkvmAssembly.GetAssembly(type) == moduleBuilder.Assembly)
+ {
+ name = type.FullName;
+ }
+ else
+ {
+ name = type.AssemblyQualifiedName;
+ }
+ }
+ WriteString(name);
+ }
+
+ private void WriteString(string val)
+ {
+ if (val == null)
+ {
+ str.WriteByte(0xFF);
+ }
+ else
+ {
+ byte[] buf = System.Text.Encoding.UTF8.GetBytes(val);
+ WritePackedLen(buf.Length);
+ str.Write(buf, 0, buf.Length);
+ }
+ }
+
+ private void WritePackedLen(int len)
+ {
+ if (len < 0 || len > 0x1FFFFFFF)
+ throw new ArgumentOutOfRangeException();
+
+ if (len <= 0x7F)
+ str.WriteByte((byte)len);
+ else if (len <= 0x3FFF)
+ {
+ str.WriteByte((byte)(0x80 | (len >> 8)));
+ str.WriteByte((byte)len);
+ }
+ else
+ {
+ str.WriteByte((byte)(0xC0 | (len >> 24)));
+ str.WriteByte((byte)(len >> 16));
+ str.WriteByte((byte)(len >> 8));
+ str.WriteByte((byte)len);
+ }
+ }
+
+ private void WriteFieldOrPropType(Type type)
+ {
+ if (type == typeof(Type))
+ {
+ str.WriteByte(0x50);
+ }
+ else if (type == typeof(object))
+ {
+ str.WriteByte(0x51);
+ }
+ else if (type.IsArray)
+ {
+ str.WriteByte(0x1D);
+ WriteFieldOrPropType(type.GetElementType());
+ }
+ else if (type.IsEnum)
+ {
+ str.WriteByte(0x55);
+ WriteTypeName(type);
+ }
+ else
+ {
+ switch (Type.GetTypeCode(type))
+ {
+ case TypeCode.Boolean:
+ str.WriteByte(0x02);
+ break;
+ case TypeCode.Char:
+ str.WriteByte(0x03);
+ break;
+ case TypeCode.SByte:
+ str.WriteByte(0x04);
+ break;
+ case TypeCode.Byte:
+ str.WriteByte(0x05);
+ break;
+ case TypeCode.Int16:
+ str.WriteByte(0x06);
+ break;
+ case TypeCode.UInt16:
+ str.WriteByte(0x07);
+ break;
+ case TypeCode.Int32:
+ str.WriteByte(0x08);
+ break;
+ case TypeCode.UInt32:
+ str.WriteByte(0x09);
+ break;
+ case TypeCode.Int64:
+ str.WriteByte(0x0A);
+ break;
+ case TypeCode.UInt64:
+ str.WriteByte(0x0B);
+ break;
+ case TypeCode.Single:
+ str.WriteByte(0x0C);
+ break;
+ case TypeCode.Double:
+ str.WriteByte(0x0D);
+ break;
+ case TypeCode.String:
+ str.WriteByte(0x0E);
+ break;
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ }
+ }
+
+ internal bool IsPseudoCustomAttribute
+ {
+ get
+ {
+ Type type = con.DeclaringType;
+ return type == typeof(AssemblyFlagsAttribute)
+ || type == typeof(AssemblyAlgorithmIdAttribute)
+ || type == typeof(DllImportAttribute)
+ || type == typeof(FieldOffsetAttribute)
+ || type == typeof(InAttribute)
+ || type == typeof(MarshalAsAttribute)
+ || type == typeof(MethodImplAttribute)
+ || type == typeof(OutAttribute)
+ || type == typeof(StructLayoutAttribute)
+ || type == typeof(NonSerializedAttribute)
+ || type == typeof(SerializableAttribute)
+ || type == typeof(OptionalAttribute)
+ || type == typeof(PreserveSigAttribute)
+ || type == typeof(AssemblyVersionAttribute)
+ || type == typeof(ComImportAttribute)
+ || type == typeof(DefaultParameterValueAttribute);
+ }
+ }
+
+ internal ConstructorInfo Constructor
+ {
+ get { return con; }
+ }
+
+ internal int WriteBlob(ModuleBuilder moduleBuilder)
+ {
+ BlobWriter bw = new BlobWriter(moduleBuilder, this);
+ return moduleBuilder.Blobs.Add(ByteBuffer.Wrap(bw.GetBlob()));
+ }
+
+ internal bool IsBlob
+ {
+ get { return blob != null; }
+ }
+
+ internal object GetConstructorArgument(int pos)
+ {
+ return constructorArgs[pos];
+ }
+
+ internal object GetFieldValue(string name)
+ {
+ if (namedFields != null)
+ {
+ for (int i = 0; i < namedFields.Length; i++)
+ {
+ if (namedFields[i].Name == name)
+ {
+ return fieldValues[i];
+ }
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/refemit/Enums.cs b/refemit/Enums.cs
new file mode 100644
index 00000000..ff10b50c
--- /dev/null
+++ b/refemit/Enums.cs
@@ -0,0 +1,79 @@
+/*
+ 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
+
+*/
+
+namespace IKVM.Reflection.Emit
+{
+ public enum AssemblyBuilderAccess
+ {
+ Save = 2,
+ ReflectionOnly = 6,
+ }
+
+ public enum OperandType
+ {
+ InlineBrTarget = 0,
+ InlineField = 1,
+ InlineI = 2,
+ InlineI8 = 3,
+ InlineMethod = 4,
+ InlineNone = 5,
+ InlinePhi = 6,
+ InlineR = 7,
+ InlineSig = 9,
+ InlineString = 10,
+ InlineSwitch = 11,
+ InlineTok = 12,
+ InlineType = 13,
+ InlineVar = 14,
+ ShortInlineBrTarget = 15,
+ ShortInlineI = 16,
+ ShortInlineR = 17,
+ ShortInlineVar = 18,
+ }
+
+ public enum FlowControl
+ {
+ Branch = 0,
+ Break = 1,
+ Call = 2,
+ Cond_Branch = 3,
+ Meta = 4,
+ Next = 5,
+ Return = 7,
+ Throw = 8,
+ }
+
+ public enum PackingSize
+ {
+ Unspecified = 0,
+ Size1 = 1,
+ }
+
+ public enum PEFileKinds
+ {
+ Dll = 1,
+ ConsoleApplication = 2,
+ WindowApplication = 3,
+ }
+}
diff --git a/refemit/FieldBuilder.cs b/refemit/FieldBuilder.cs
new file mode 100644
index 00000000..fbbfcda9
--- /dev/null
+++ b/refemit/FieldBuilder.cs
@@ -0,0 +1,223 @@
+/*
+ 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.Reflection;
+using IKVM.Reflection.Emit.Writer;
+using System.Runtime.InteropServices;
+
+namespace IKVM.Reflection.Emit
+{
+ public sealed class FieldBuilder : FieldInfo
+ {
+ private readonly TypeBuilder typeBuilder;
+ private readonly string name;
+ private readonly int pseudoToken;
+ private FieldAttributes attribs;
+ private readonly int nameIndex;
+ private readonly int signature;
+ private readonly Type fieldType;
+ private readonly Type[] requiredCustomModifiers;
+ private readonly Type[] optionalCustomModifiers;
+
+ internal FieldBuilder(TypeBuilder type, string name, Type fieldType, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers, FieldAttributes attribs)
+ {
+ this.typeBuilder = type;
+ this.name = name;
+ this.pseudoToken = type.ModuleBuilder.AllocPseudoToken();
+ this.nameIndex = type.ModuleBuilder.Strings.Add(name);
+ this.fieldType = fieldType;
+ ByteBuffer sig = new ByteBuffer(5);
+ SignatureHelper.WriteFieldSig(this.typeBuilder.ModuleBuilder, sig, fieldType, requiredCustomModifiers, optionalCustomModifiers);
+ this.signature = this.typeBuilder.ModuleBuilder.Blobs.Add(sig);
+ this.attribs = attribs;
+ this.typeBuilder.ModuleBuilder.Tables.Field.AddRow();
+ this.requiredCustomModifiers = MethodBuilder.Copy(requiredCustomModifiers);
+ this.optionalCustomModifiers = MethodBuilder.Copy(optionalCustomModifiers);
+ }
+
+ public void SetConstant(object defaultValue)
+ {
+ attribs |= FieldAttributes.HasDefault;
+ this.ModuleBuilder.AddConstant(pseudoToken, defaultValue);
+ }
+
+ public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+ {
+ if (customBuilder.Constructor.DeclaringType == typeof(FieldOffsetAttribute))
+ {
+ TableHeap.FieldLayoutTable.Record rec = new TableHeap.FieldLayoutTable.Record();
+ rec.Offset = (int)customBuilder.GetConstructorArgument(0);
+ rec.Field = pseudoToken;
+ this.ModuleBuilder.Tables.FieldLayout.AddRecord(rec);
+ }
+ else if (customBuilder.Constructor.DeclaringType == typeof(MarshalAsAttribute))
+ {
+ TableHeap.FieldMarshalTable.Record rec = new TableHeap.FieldMarshalTable.Record();
+ rec.Parent = pseudoToken;
+ rec.NativeType = WriteMarshallingDescriptor(this.ModuleBuilder, customBuilder);
+ this.ModuleBuilder.Tables.FieldMarshal.AddRecord(rec);
+ attribs |= FieldAttributes.HasFieldMarshal;
+ }
+ else if (customBuilder.Constructor.DeclaringType == typeof(NonSerializedAttribute))
+ {
+ attribs |= FieldAttributes.NotSerialized;
+ }
+ else
+ {
+ this.ModuleBuilder.SetCustomAttribute(pseudoToken, customBuilder);
+ }
+ }
+
+ internal static int WriteMarshallingDescriptor(ModuleBuilder moduleBuiler, CustomAttributeBuilder customBuilder)
+ {
+ UnmanagedType nativeType;
+ object val = customBuilder.GetConstructorArgument(0);
+ if (val is short)
+ {
+ nativeType = (UnmanagedType)(short)val;
+ }
+ else
+ {
+ nativeType = (UnmanagedType)val;
+ }
+
+ ByteBuffer bb = new ByteBuffer(5);
+ bb.Write((byte)nativeType);
+
+ object arraySubType = customBuilder.GetFieldValue("ArraySubType");
+ if (arraySubType != null)
+ {
+ bb.Write((byte)(UnmanagedType)arraySubType);
+ }
+ object sizeParamIndex = customBuilder.GetFieldValue("SizeParamIndex");
+ if (sizeParamIndex != null)
+ {
+ bb.WriteCompressedInt((short)sizeParamIndex + 1);
+ }
+ object sizeConst = customBuilder.GetFieldValue("SizeConst");
+ if (sizeConst != null)
+ {
+ if (sizeParamIndex == null)
+ {
+ bb.WriteCompressedInt(0);
+ }
+ bb.WriteCompressedInt((int)sizeConst);
+ }
+
+ if (customBuilder.GetFieldValue("IidParameterIndex") != null
+ || customBuilder.GetFieldValue("MarshalCookie") != null
+ || customBuilder.GetFieldValue("MarshalType") != null
+ || customBuilder.GetFieldValue("MarshalTypeRef") != null
+ || customBuilder.GetFieldValue("SafeArraySubType") != null
+ || customBuilder.GetFieldValue("SafeArrayUserDefinedSubType") != null)
+ {
+ throw new NotImplementedException();
+ }
+
+ return moduleBuiler.Blobs.Add(bb);
+ }
+
+ public override FieldAttributes Attributes
+ {
+ get { return attribs; }
+ }
+
+ public override RuntimeFieldHandle FieldHandle
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override Type FieldType
+ {
+ get { return fieldType; }
+ }
+
+ public override object GetValue(object obj)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, System.Globalization.CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override Type DeclaringType
+ {
+ get { return this.ModuleBuilder.IsModuleType(typeBuilder) ? null : typeBuilder; }
+ }
+
+ public override object[] GetCustomAttributes(Type attributeType, bool inherit)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object[] GetCustomAttributes(bool inherit)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override bool IsDefined(Type attributeType, bool inherit)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override string Name
+ {
+ get { return name; }
+ }
+
+ public override Type ReflectedType
+ {
+ get { return this.DeclaringType; }
+ }
+
+ public override int MetadataToken
+ {
+ get { return pseudoToken; }
+ }
+
+ internal void WriteFieldRecords(MetadataWriter mw)
+ {
+ mw.Write((short)attribs);
+ mw.WriteStringIndex(nameIndex);
+ mw.WriteBlobIndex(signature);
+ }
+
+ internal void FixupToken(int token)
+ {
+ typeBuilder.ModuleBuilder.RegisterTokenFixup(this.pseudoToken, token);
+ }
+
+ internal ModuleBuilder ModuleBuilder
+ {
+ get { return typeBuilder.ModuleBuilder; }
+ }
+
+ internal int ImportTo(ModuleBuilder other)
+ {
+ return other.ImportField(typeBuilder, name, fieldType, optionalCustomModifiers, requiredCustomModifiers);
+ }
+ }
+}
diff --git a/refemit/IKVM.Reflection.Emit.csproj b/refemit/IKVM.Reflection.Emit.csproj
new file mode 100644
index 00000000..4c404c45
--- /dev/null
+++ b/refemit/IKVM.Reflection.Emit.csproj
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{3949055D-38DF-4A8F-A632-0F0E62337428}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>IKVM.Reflection.Emit</RootNamespace>
+ <AssemblyName>IKVM.Reflection.Emit</AssemblyName>
+ <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SignAssembly>false</SignAssembly>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="ISymWrapper" />
+ <Reference Include="System" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="..\CommonAssemblyInfo.cs" />
+ <Compile Include="AssemblyBuilder.cs" />
+ <Compile Include="Enums.cs" />
+ <Compile Include="ConstructorBuilder.cs" />
+ <Compile Include="CustomAttributeBuilder.cs" />
+ <Compile Include="FieldBuilder.cs" />
+ <Compile Include="IkvmAssembly.cs" />
+ <Compile Include="ILGenerator.cs" />
+ <Compile Include="Impl\CryptoConvert.cs" />
+ <Compile Include="Impl\CryptoHack.cs" />
+ <Compile Include="Impl\ITypeOwner.cs" />
+ <Compile Include="Impl\PdbSupport.cs" />
+ <Compile Include="Impl\TypeBase.cs" />
+ <Compile Include="MethodBuilder.cs" />
+ <Compile Include="ModuleBuilder.cs" />
+ <Compile Include="OpCodes.cs" />
+ <Compile Include="ParameterBuilder.cs" />
+ <Compile Include="Tokens.cs" />
+ <Compile Include="Writer\ModuleWriter.cs" />
+ <Compile Include="Writer\PEWriter.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="PropertyBuilder.cs" />
+ <Compile Include="SignatureHelper.cs" />
+ <Compile Include="TypeBuilder.cs" />
+ <Compile Include="Writer\ByteBuffer.cs" />
+ <Compile Include="Writer\TextSection.cs" />
+ <Compile Include="Writer\Heaps.cs" />
+ <Compile Include="Writer\MetadataWriter.cs" />
+ <Compile Include="Writer\VersionInfo.cs" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/refemit/ILGenerator.cs b/refemit/ILGenerator.cs
new file mode 100644
index 00000000..975825f1
--- /dev/null
+++ b/refemit/ILGenerator.cs
@@ -0,0 +1,1000 @@
+/*
+ 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.Reflection;
+using System.Runtime.InteropServices;
+using System.Collections.Generic;
+using IKVM.Reflection.Emit.Writer;
+using System.Diagnostics.SymbolStore;
+using System.Diagnostics;
+
+namespace IKVM.Reflection.Emit
+{
+ public struct Label
+ {
+ // 1-based here, to make sure that an uninitialized Label isn't valid
+ private readonly int index1;
+
+ internal Label(int index)
+ {
+ this.index1 = index + 1;
+ }
+
+ internal int Index
+ {
+ get { return index1 - 1; }
+ }
+ }
+
+ public sealed class LocalBuilder
+ {
+ private readonly Type localType;
+ private readonly int index;
+ internal string name;
+
+ internal LocalBuilder(Type localType, int index)
+ {
+ this.localType = localType;
+ this.index = index;
+ }
+
+ public void SetLocalSymInfo(string name)
+ {
+ this.name = name;
+ }
+
+ public Type LocalType
+ {
+ get { return localType; }
+ }
+
+ public int LocalIndex
+ {
+ get { return index; }
+ }
+ }
+
+ public sealed class ILGenerator
+ {
+ private static readonly Type FAULT = typeof(ExceptionBlock); // the type we use here doesn't matter, as long as it can never be used as a real exception type
+ private readonly ModuleBuilder moduleBuilder;
+ private readonly ByteBuffer code = new ByteBuffer(16);
+ private readonly List<LocalBuilder> locals = new List<LocalBuilder>();
+ private readonly List<int> tokenFixups = new List<int>();
+ private readonly List<int> labels = new List<int>();
+ private readonly List<int> labelStackHeight = new List<int>();
+ private readonly List<LabelFixup> labelFixups = new List<LabelFixup>();
+ private readonly List<SequencePoint> sequencePoints = new List<SequencePoint>();
+ private readonly List<ExceptionBlock> exceptions = new List<ExceptionBlock>();
+ private readonly Stack<ExceptionBlock> exceptionStack = new Stack<ExceptionBlock>();
+ private ushort maxStack;
+ private int stackHeight;
+ private Scope scope;
+
+ private struct LabelFixup
+ {
+ internal int label;
+ internal int offset;
+ }
+
+ private class ExceptionBlock : IComparer<ExceptionBlock>
+ {
+ internal readonly int ordinal;
+ internal Label labelEnd;
+ internal int tryOffset;
+ internal int tryLength;
+ internal int handlerOffset;
+ internal int handlerLength;
+ internal Type exceptionType; // null = finally block, FAULT = fault block
+
+ internal ExceptionBlock(int ordinal)
+ {
+ this.ordinal = ordinal;
+ }
+
+ int IComparer<ExceptionBlock>.Compare(ExceptionBlock x, ExceptionBlock y)
+ {
+ if (x.tryOffset == y.tryOffset && x.tryLength == y.tryLength)
+ {
+ return x.ordinal < y.ordinal ? -1 : 1;
+ }
+ if (x.tryOffset + x.tryLength <= y.tryOffset)
+ {
+ return -1;
+ }
+ if (y.tryOffset + y.tryLength <= x.tryOffset)
+ {
+ return 1;
+ }
+ if (x.tryOffset > y.tryOffset || (x.tryOffset == y.tryOffset && x.tryLength < y.tryLength))
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ }
+
+ private struct SequencePoint
+ {
+ internal ISymbolDocumentWriter document;
+ internal int offset;
+ internal int startLine;
+ internal int startColumn;
+ internal int endLine;
+ internal int endColumn;
+ }
+
+ private class Scope
+ {
+ internal readonly Scope parent;
+ internal readonly List<Scope> children = new List<Scope>();
+ internal readonly List<LocalBuilder> locals = new List<LocalBuilder>();
+ internal int startOffset;
+ internal int endOffset;
+
+ internal Scope(Scope parent)
+ {
+ this.parent = parent;
+ }
+ }
+
+ internal ILGenerator(ModuleBuilder moduleBuilder)
+ {
+ this.moduleBuilder = moduleBuilder;
+ if (moduleBuilder.symbolWriter != null)
+ {
+ scope = new Scope(null);
+ }
+ }
+
+ public void BeginCatchBlock(Type exceptionType)
+ {
+ ExceptionBlock block = exceptionStack.Peek();
+ Emit(OpCodes.Leave, block.labelEnd);
+ stackHeight = 0;
+ UpdateStack(1);
+ if (block.tryLength == 0)
+ {
+ block.tryLength = code.Position - block.tryOffset;
+ }
+ else
+ {
+ block.handlerLength = code.Position - block.handlerOffset;
+ exceptionStack.Pop();
+ ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
+ newBlock.labelEnd = block.labelEnd;
+ newBlock.tryOffset = block.tryOffset;
+ newBlock.tryLength = block.tryLength;
+ block = newBlock;
+ exceptions.Add(block);
+ exceptionStack.Push(block);
+ }
+ block.handlerOffset = code.Position;
+ block.exceptionType = exceptionType;
+ }
+
+ public void BeginExceptFilterBlock()
+ {
+ throw new NotImplementedException();
+ }
+
+ public Label BeginExceptionBlock()
+ {
+ ExceptionBlock block = new ExceptionBlock(exceptions.Count);
+ block.labelEnd = DefineLabel();
+ block.tryOffset = code.Position;
+ exceptionStack.Push(block);
+ exceptions.Add(block);
+ return block.labelEnd;
+ }
+
+ public void BeginFaultBlock()
+ {
+ BeginFinallyBlock();
+ exceptionStack.Peek().exceptionType = FAULT;
+ }
+
+ public void BeginFinallyBlock()
+ {
+ ExceptionBlock block = exceptionStack.Peek();
+ Emit(OpCodes.Leave, block.labelEnd);
+ stackHeight = 0;
+ if (block.handlerOffset == 0)
+ {
+ block.tryLength = code.Position - block.tryOffset;
+ }
+ else
+ {
+ block.handlerLength = code.Position - block.handlerOffset;
+ MarkLabel(block.labelEnd);
+ Label labelEnd = DefineLabel();
+ Emit(OpCodes.Leave, labelEnd);
+ exceptionStack.Pop();
+ ExceptionBlock newBlock = new ExceptionBlock(exceptions.Count);
+ newBlock.labelEnd = labelEnd;
+ newBlock.tryOffset = block.tryOffset;
+ newBlock.tryLength = code.Position - block.tryOffset;
+ block = newBlock;
+ exceptions.Add(block);
+ exceptionStack.Push(block);
+ }
+ block.handlerOffset = code.Position;
+ }
+
+ public void EndExceptionBlock()
+ {
+ ExceptionBlock block = exceptionStack.Pop();
+ if (block.exceptionType != null && block.exceptionType != FAULT)
+ {
+ Emit(OpCodes.Leave, block.labelEnd);
+ }
+ else
+ {
+ Emit(OpCodes.Endfinally);
+ }
+ block.handlerLength = code.Position - block.handlerOffset;
+ MarkLabel(block.labelEnd);
+ }
+
+ public void BeginScope()
+ {
+ Scope newScope = new Scope(scope);
+ scope.children.Add(newScope);
+ scope = newScope;
+ scope.startOffset = code.Position;
+ }
+
+ public LocalBuilder DeclareLocal(Type localType)
+ {
+ LocalBuilder local = new LocalBuilder(localType, locals.Count);
+ locals.Add(local);
+ if (scope != null)
+ {
+ scope.locals.Add(local);
+ }
+ return local;
+ }
+
+ public Label DefineLabel()
+ {
+ Label label = new Label(labels.Count);
+ labels.Add(-1);
+ labelStackHeight.Add(-1);
+ return label;
+ }
+
+ public void Emit(OpCode opc)
+ {
+ if (opc.Value < 0)
+ {
+ code.Write((byte)(opc.Value >> 8));
+ }
+ code.Write((byte)opc.Value);
+ switch (opc.FlowControl)
+ {
+ case FlowControl.Branch:
+ case FlowControl.Break:
+ case FlowControl.Return:
+ case FlowControl.Throw:
+ stackHeight = -1;
+ break;
+ default:
+ UpdateStack(opc.StackDiff);
+ break;
+ }
+ }
+
+ private void UpdateStack(int stackdiff)
+ {
+ if (stackHeight == -1)
+ {
+ // we're about to emit unreachable code
+ stackHeight = 0;
+ }
+ Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
+ stackHeight += stackdiff;
+ Debug.Assert(stackHeight >= 0 && stackHeight <= ushort.MaxValue);
+ maxStack = Math.Max(maxStack, (ushort)stackHeight);
+ }
+
+ public void Emit(OpCode opc, byte arg)
+ {
+ Emit(opc);
+ code.Write(arg);
+ }
+
+ public void Emit(OpCode opc, double arg)
+ {
+ Emit(opc);
+ code.Write(arg);
+ }
+
+ public void Emit(OpCode opc, FieldInfo field)
+ {
+ Emit(opc);
+ WriteToken(moduleBuilder.GetFieldToken(field));
+ }
+
+ public void Emit(OpCode opc, short arg)
+ {
+ Emit(opc);
+ code.Write(arg);
+ }
+
+ public void Emit(OpCode opc, int arg)
+ {
+ Emit(opc);
+ code.Write(arg);
+ }
+
+ public void Emit(OpCode opc, long arg)
+ {
+ Emit(opc);
+ code.Write(arg);
+ }
+
+ public void Emit(OpCode opc, Label label)
+ {
+ // We need special stackHeight handling for unconditional branches,
+ // because the branch and next flows have differing stack heights.
+ // Note that this assumes that unconditional branches do not push/pop.
+ int flowStackHeight = this.stackHeight;
+ Emit(opc);
+ if (opc.Value == OpCodes.Leave.Value || opc.Value == OpCodes.Leave_S.Value)
+ {
+ flowStackHeight = 0;
+ }
+ else if (opc.FlowControl != FlowControl.Branch)
+ {
+ flowStackHeight = this.stackHeight;
+ }
+ // if the label has already been marked, we can emit the branch offset directly
+ if (labels[label.Index] != -1)
+ {
+ if (labelStackHeight[label.Index] != flowStackHeight)
+ {
+ // the "backward branch constraint" prohibits this, so we don't need to support it
+ throw new NotSupportedException();
+ }
+ switch (opc.OperandType)
+ {
+ case OperandType.InlineBrTarget:
+ code.Write(labels[label.Index] - (code.Position + 4));
+ break;
+ case OperandType.ShortInlineBrTarget:
+ code.Write((byte)(labels[label.Index] - (code.Position + 1)));
+ break;
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ else
+ {
+ Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == flowStackHeight);
+ labelStackHeight[label.Index] = flowStackHeight;
+ LabelFixup fix = new LabelFixup();
+ fix.label = label.Index;
+ fix.offset = code.Position;
+ labelFixups.Add(fix);
+ switch (opc.OperandType)
+ {
+ case OperandType.InlineBrTarget:
+ code.Write(4);
+ break;
+ case OperandType.ShortInlineBrTarget:
+ code.Write((byte)1);
+ break;
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ }
+
+ public void Emit(OpCode opc, Label[] labels)
+ {
+ Emit(opc);
+ LabelFixup fix = new LabelFixup();
+ fix.label = -1;
+ fix.offset = code.Position;
+ labelFixups.Add(fix);
+ code.Write(labels.Length);
+ foreach (Label label in labels)
+ {
+ code.Write(label.Index);
+ if (this.labels[label.Index] != -1)
+ {
+ if (labelStackHeight[label.Index] != stackHeight)
+ {
+ // the "backward branch constraint" prohibits this, so we don't need to support it
+ throw new NotSupportedException();
+ }
+ }
+ else
+ {
+ Debug.Assert(labelStackHeight[label.Index] == -1 || labelStackHeight[label.Index] == stackHeight);
+ labelStackHeight[label.Index] = stackHeight;
+ }
+ }
+ }
+
+ public void Emit(OpCode opc, LocalBuilder local)
+ {
+ if ((opc.Value == OpCodes.Ldloc.Value || opc.Value == OpCodes.Ldloca.Value || opc.Value == OpCodes.Stloc.Value) && local.LocalIndex < 256)
+ {
+ if (opc.Value == OpCodes.Ldloc.Value)
+ {
+ switch (local.LocalIndex)
+ {
+ case 0:
+ Emit(OpCodes.Ldloc_0);
+ break;
+ case 1:
+ Emit(OpCodes.Ldloc_1);
+ break;
+ case 2:
+ Emit(OpCodes.Ldloc_2);
+ break;
+ case 3:
+ Emit(OpCodes.Ldloc_3);
+ break;
+ default:
+ Emit(OpCodes.Ldloc_S);
+ code.Write((byte)local.LocalIndex);
+ break;
+ }
+ }
+ else if (opc.Value == OpCodes.Ldloca.Value)
+ {
+ Emit(OpCodes.Ldloca_S);
+ code.Write((byte)local.LocalIndex);
+ }
+ else if (opc.Value == OpCodes.Stloc.Value)
+ {
+ switch (local.LocalIndex)
+ {
+ case 0:
+ Emit(OpCodes.Stloc_0);
+ break;
+ case 1:
+ Emit(OpCodes.Stloc_1);
+ break;
+ case 2:
+ Emit(OpCodes.Stloc_2);
+ break;
+ case 3:
+ Emit(OpCodes.Stloc_3);
+ break;
+ default:
+ Emit(OpCodes.Stloc_S);
+ code.Write((byte)local.LocalIndex);
+ break;
+ }
+ }
+ }
+ else
+ {
+ Emit(opc);
+ switch (opc.OperandType)
+ {
+ case OperandType.InlineVar:
+ code.Write((ushort)local.LocalIndex);
+ break;
+ case OperandType.ShortInlineVar:
+ code.Write((byte)local.LocalIndex);
+ break;
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ }
+
+ private void WriteToken(FieldToken token)
+ {
+ if (token.IsPseudoToken)
+ {
+ tokenFixups.Add(code.Position);
+ }
+ code.Write(token.Token);
+ }
+
+ private void WriteToken(MethodToken token)
+ {
+ if (token.IsPseudoToken)
+ {
+ tokenFixups.Add(code.Position);
+ }
+ code.Write(token.Token);
+ }
+
+ private void WriteToken(ConstructorToken token)
+ {
+ if (token.IsPseudoToken)
+ {
+ tokenFixups.Add(code.Position);
+ }
+ code.Write(token.Token);
+ }
+
+ public void Emit(OpCode opc, MethodInfo method)
+ {
+ Emit(opc);
+ WriteToken(moduleBuilder.GetMethodToken(method));
+ if (opc.FlowControl == FlowControl.Call)
+ {
+ int stackdiff = 0;
+ if (!method.IsStatic && opc.Value != OpCodes.Newobj.Value)
+ {
+ // pop this
+ stackdiff--;
+ }
+ // pop parameters
+ stackdiff -= GetParameterCount(method);
+ if (method.ReturnType != typeof(void))
+ {
+ // push return value
+ stackdiff++;
+ }
+ UpdateStack(stackdiff);
+ }
+ }
+
+ public void Emit(OpCode opc, ConstructorInfo constructor)
+ {
+ Emit(opc);
+ WriteToken(moduleBuilder.GetConstructorToken(constructor));
+ if (opc.FlowControl == FlowControl.Call)
+ {
+ int stackdiff = 0;
+ if (!constructor.IsStatic && opc.Value != OpCodes.Newobj.Value)
+ {
+ // pop this
+ stackdiff--;
+ }
+ // pop parameters
+ stackdiff -= GetParameterCount(constructor);
+ UpdateStack(stackdiff);
+ }
+ }
+
+ private static int GetParameterCount(MethodBase mb)
+ {
+ if (mb.IsGenericMethod)
+ {
+ return ((MethodInfo)mb).GetGenericMethodDefinition().GetParameters().Length;
+ }
+ else
+ {
+ return mb.GetParameters().Length;
+ }
+ }
+
+ public void Emit(OpCode opc, sbyte arg)
+ {
+ Emit(opc);
+ code.Write(arg);
+ }
+
+ public void Emit(OpCode opc, SignatureHelper sig)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Emit(OpCode opc, float arg)
+ {
+ Emit(opc);
+ code.Write(arg);
+ }
+
+ public void Emit(OpCode opc, string str)
+ {
+ Emit(opc);
+ code.Write(0x70000000 | moduleBuilder.UserStrings.Add(str));
+ }
+
+ public void Emit(OpCode opc, Type type)
+ {
+ Emit(opc);
+ code.Write(moduleBuilder.GetTypeToken(type).Token);
+ }
+
+ public void EmitCall(OpCode opc, MethodInfo methodInfo, Type[] optionalParameterTypes)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void EmitCalli(OpCode opc, CallingConvention callingConvention, Type returnType, Type[] parameterTypes)
+ {
+ Emit(opc);
+ ByteBuffer sig = new ByteBuffer(16);
+ switch (callingConvention)
+ {
+ case CallingConvention.Cdecl:
+ sig.Write((byte)0x01); // C
+ break;
+ case CallingConvention.StdCall:
+ case CallingConvention.Winapi:
+ sig.Write((byte)0x02); // STDCALL
+ break;
+ case CallingConvention.ThisCall:
+ sig.Write((byte)0x03); // THISCALL
+ break;
+ case CallingConvention.FastCall:
+ sig.Write((byte)0x04); // FASTCALL
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ sig.WriteCompressedInt(parameterTypes.Length);
+ SignatureHelper.WriteType(moduleBuilder, sig, returnType);
+ foreach (Type t in parameterTypes)
+ {
+ SignatureHelper.WriteType(moduleBuilder, sig, t);
+ }
+ code.Write(0x11000000 | moduleBuilder.Tables.StandAloneSig.Add(moduleBuilder.Blobs.Add(sig)));
+ }
+
+ public void EmitCalli(OpCode opc, CallingConventions callingConvention, Type returnType, Type[] parameterTypes, Type[] optionalParameterTypes)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void EmitWriteLine(FieldInfo fld)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void EmitWriteLine(LocalBuilder localBuilder)
+ {
+ throw new NotImplementedException();
+ }
+
+ private void EmitWriteLineHelper(Type type)
+ {
+ throw new NotImplementedException();
+ }
+
+ public void EmitWriteLine(string text)
+ {
+ Emit(OpCodes.Ldstr, text);
+ Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
+ }
+
+ public void EndScope()
+ {
+ scope.endOffset = code.Position;
+ scope = scope.parent;
+ }
+
+ public void MarkLabel(Label loc)
+ {
+ Debug.Assert(stackHeight == -1 || labelStackHeight[loc.Index] == -1 || stackHeight == labelStackHeight[loc.Index]);
+ labels[loc.Index] = code.Position;
+ if (labelStackHeight[loc.Index] == -1)
+ {
+ if (stackHeight == -1)
+ {
+ // we're at a location that can only be reached by a backward branch,
+ // so according to the "backward branch constraint" that must mean the stack is empty
+ stackHeight = 0;
+ labelStackHeight[loc.Index] = 0;
+ }
+ else
+ {
+ labelStackHeight[loc.Index] = stackHeight;
+ }
+ }
+ else
+ {
+ Debug.Assert(stackHeight == -1 || stackHeight == labelStackHeight[loc.Index]);
+ stackHeight = labelStackHeight[loc.Index];
+ }
+ }
+
+ public void MarkSequencePoint(ISymbolDocumentWriter document, int startLine, int startColumn, int endLine, int endColumn)
+ {
+ SequencePoint sp = new SequencePoint();
+ sp.document = document;
+ sp.offset = code.Position;
+ sp.startLine = startLine;
+ sp.startColumn = startColumn;
+ sp.endLine = endLine;
+ sp.endColumn = endColumn;
+ sequencePoints.Add(sp);
+ }
+
+ public void ThrowException(Type excType)
+ {
+ Emit(OpCodes.Newobj, excType.GetConstructor(Type.EmptyTypes));
+ Emit(OpCodes.Throw);
+ }
+
+ public void UsingNamespace(string usingNamespace)
+ {
+ throw new NotImplementedException();
+ }
+
+ internal int WriteBody()
+ {
+ if (moduleBuilder.symbolWriter != null)
+ {
+ Debug.Assert(scope != null && scope.parent == null);
+ scope.endOffset = code.Position;
+ }
+
+ ResolveBranches();
+
+ ByteBuffer bb = moduleBuilder.methodBodies;
+
+ int rva;
+ if (locals.Count == 0 && exceptions.Count == 0 && maxStack <= 8 && code.Length < 64)
+ {
+ rva = WriteTinyHeaderAndCode(bb);
+ }
+ else
+ {
+ rva = WriteFatHeaderAndCode(bb);
+ }
+
+ if (moduleBuilder.symbolWriter != null)
+ {
+ if (sequencePoints.Count != 0)
+ {
+ ISymbolDocumentWriter document = sequencePoints[0].document;
+ int[] offsets = new int[sequencePoints.Count];
+ int[] lines = new int[sequencePoints.Count];
+ int[] columns = new int[sequencePoints.Count];
+ int[] endLines = new int[sequencePoints.Count];
+ int[] endColumns = new int[sequencePoints.Count];
+ for (int i = 0; i < sequencePoints.Count; i++)
+ {
+ if (sequencePoints[i].document != document)
+ {
+ throw new NotImplementedException();
+ }
+ offsets[i] = sequencePoints[i].offset;
+ lines[i] = sequencePoints[i].startLine;
+ columns[i] = sequencePoints[i].startColumn;
+ endLines[i] = sequencePoints[i].endLine;
+ endColumns[i] = sequencePoints[i].endColumn;
+ }
+ moduleBuilder.symbolWriter.DefineSequencePoints(document, offsets, lines, columns, endLines, endColumns);
+ }
+
+ WriteScope(scope);
+ }
+ return rva;
+ }
+
+ private void ResolveBranches()
+ {
+ foreach (LabelFixup fixup in labelFixups)
+ {
+ // is it a switch?
+ if (fixup.label == -1)
+ {
+ code.Position = fixup.offset;
+ int count = code.GetInt32AtCurrentPosition();
+ int offset = fixup.offset + 4 + 4 * count;
+ code.Position += 4;
+ for (int i = 0; i < count; i++)
+ {
+ int index = code.GetInt32AtCurrentPosition();
+ code.Write(labels[index] - offset);
+ }
+ }
+ else
+ {
+ code.Position = fixup.offset;
+ byte size = code.GetByteAtCurrentPosition();
+ int branchOffset = labels[fixup.label] - (code.Position + size);
+ if (size == 1)
+ {
+ code.Write((byte)branchOffset);
+ }
+ else
+ {
+ code.Write(branchOffset);
+ }
+ }
+ }
+ }
+
+ private int WriteTinyHeaderAndCode(ByteBuffer bb)
+ {
+ int rva = bb.Position;
+ const byte CorILMethod_TinyFormat = 0x2;
+ bb.Write((byte)(CorILMethod_TinyFormat | (code.Length << 2)));
+ WriteCode(bb);
+ return rva;
+ }
+
+ private int WriteFatHeaderAndCode(ByteBuffer bb)
+ {
+ // fat headers require 4-byte alignment
+ bb.Align(4);
+ int rva = bb.Position;
+
+ int localVarSigTok = 0;
+ if (locals.Count != 0)
+ {
+ const byte LOCAL_SIG = 0x07;
+
+ ByteBuffer localVarSig = new ByteBuffer(locals.Count + 2);
+ localVarSig.Write(LOCAL_SIG);
+ localVarSig.WriteCompressedInt(locals.Count);
+ foreach (LocalBuilder local in locals)
+ {
+ SignatureHelper.WriteType(moduleBuilder, localVarSig, local.LocalType);
+ }
+
+ localVarSigTok = 0x11000000 | moduleBuilder.Tables.StandAloneSig.Add(moduleBuilder.Blobs.Add(localVarSig));
+ }
+
+ const byte CorILMethod_FatFormat = 0x03;
+ const byte CorILMethod_MoreSects = 0x08;
+ const byte CorILMethod_InitLocals = 0x10;
+
+ short flagsAndSize = (short)(CorILMethod_FatFormat | CorILMethod_InitLocals | (3 << 12));
+
+ if (exceptions.Count > 0)
+ {
+ flagsAndSize |= CorILMethod_MoreSects;
+ }
+
+ bb.Write(flagsAndSize);
+ bb.Write(maxStack);
+ bb.Write(code.Length);
+ bb.Write(localVarSigTok);
+
+ WriteCode(bb);
+
+ if (exceptions.Count > 0)
+ {
+ bb.Align(4);
+
+ bool fat = false;
+ foreach (ExceptionBlock block in exceptions)
+ {
+ if (block.tryOffset > 65535 || block.tryLength > 255 || block.handlerOffset > 65535 || block.handlerLength > 255)
+ {
+ fat = true;
+ break;
+ }
+ }
+ exceptions.Sort(exceptions[0]);
+ if (exceptions.Count * 12 + 4 > 255)
+ {
+ fat = true;
+ }
+ const byte CorILMethod_Sect_EHTable = 0x1;
+ const byte CorILMethod_Sect_FatFormat = 0x40;
+ const short COR_ILEXCEPTION_CLAUSE_EXCEPTION = 0x0000;
+ const short COR_ILEXCEPTION_CLAUSE_FINALLY = 0x0002;
+ const short COR_ILEXCEPTION_CLAUSE_FAULT = 0x0004;
+
+ if (fat)
+ {
+ bb.Write((byte)(CorILMethod_Sect_EHTable | CorILMethod_Sect_FatFormat));
+ int dataSize = exceptions.Count * 24 + 4;
+ bb.Write((byte)dataSize);
+ bb.Write((short)(dataSize >> 8));
+ foreach (ExceptionBlock block in exceptions)
+ {
+ if (block.exceptionType == FAULT)
+ {
+ bb.Write((int)COR_ILEXCEPTION_CLAUSE_FAULT);
+ }
+ else if (block.exceptionType != null)
+ {
+ bb.Write((int)COR_ILEXCEPTION_CLAUSE_EXCEPTION);
+ }
+ else
+ {
+ bb.Write((int)COR_ILEXCEPTION_CLAUSE_FINALLY);
+ }
+ bb.Write(block.tryOffset);
+ bb.Write(block.tryLength);
+ bb.Write(block.handlerOffset);
+ bb.Write(block.handlerLength);
+ if (block.exceptionType != null)
+ {
+ bb.Write(moduleBuilder.GetTypeToken(block.exceptionType).Token);
+ }
+ else
+ {
+ bb.Write(0);
+ }
+ }
+ }
+ else
+ {
+ bb.Write(CorILMethod_Sect_EHTable);
+ bb.Write((byte)(exceptions.Count * 12 + 4));
+ bb.Write((short)0);
+ foreach (ExceptionBlock block in exceptions)
+ {
+ if (block.exceptionType == FAULT)
+ {
+ bb.Write(COR_ILEXCEPTION_CLAUSE_FAULT);
+ }
+ else if (block.exceptionType != null)
+ {
+ bb.Write(COR_ILEXCEPTION_CLAUSE_EXCEPTION);
+ }
+ else
+ {
+ bb.Write(COR_ILEXCEPTION_CLAUSE_FINALLY);
+ }
+ bb.Write((short)block.tryOffset);
+ bb.Write((byte)block.tryLength);
+ bb.Write((short)block.handlerOffset);
+ bb.Write((byte)block.handlerLength);
+ if (block.exceptionType != null)
+ {
+ bb.Write(moduleBuilder.GetTypeToken(block.exceptionType).Token);
+ }
+ else
+ {
+ bb.Write(0);
+ }
+ }
+ }
+ }
+ return rva;
+ }
+
+ private void WriteCode(ByteBuffer bb)
+ {
+ int codeOffset = bb.Position;
+ foreach (int fixup in this.tokenFixups)
+ {
+ moduleBuilder.tokenFixupOffsets.Add(fixup + codeOffset);
+ }
+ bb.Write(code);
+ }
+
+ private void WriteScope(Scope scope)
+ {
+ moduleBuilder.symbolWriter.OpenScope(scope.startOffset);
+ ByteBuffer localVarSig = new ByteBuffer(6);
+ foreach (LocalBuilder local in scope.locals)
+ {
+ if (local.name != null)
+ {
+ localVarSig.Clear();
+ SignatureHelper.WriteType(moduleBuilder, localVarSig, local.LocalType);
+ moduleBuilder.symbolWriter.DefineLocalVariable(local.name, 0, localVarSig.ToArray(), SymAddressKind.ILOffset, local.LocalIndex, 0, 0, scope.startOffset, scope.endOffset);
+ }
+ }
+ foreach (Scope child in scope.children)
+ {
+ WriteScope(child);
+ }
+ moduleBuilder.symbolWriter.CloseScope(scope.endOffset);
+ }
+ }
+}
diff --git a/refemit/IkvmAssembly.cs b/refemit/IkvmAssembly.cs
new file mode 100644
index 00000000..6d01628a
--- /dev/null
+++ b/refemit/IkvmAssembly.cs
@@ -0,0 +1,70 @@
+/*
+ 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.Reflection;
+using IKVM.Reflection.Emit.Impl;
+
+namespace IKVM.Reflection.Emit
+{
+ public abstract class IkvmAssembly
+ {
+ private static readonly Dictionary<Assembly, IkvmAssembly> assemblies = new Dictionary<Assembly, IkvmAssembly>();
+
+ internal IkvmAssembly() { }
+
+ private class AssemblyWrapper : IkvmAssembly
+ {
+ private readonly Assembly asm;
+
+ internal AssemblyWrapper(Assembly asm)
+ {
+ this.asm = asm;
+ }
+
+ public override Type GetType(string typeName)
+ {
+ return asm.GetType(typeName);
+ }
+ }
+
+ public static IkvmAssembly GetAssembly(Type type)
+ {
+ TypeBase tb = type as TypeBase;
+ if (tb != null)
+ {
+ return tb.ModuleBuilder.Assembly;
+ }
+ IkvmAssembly ikvmAssembly;
+ if (!assemblies.TryGetValue(type.Assembly, out ikvmAssembly))
+ {
+ ikvmAssembly = new AssemblyWrapper(type.Assembly);
+ assemblies.Add(type.Assembly, ikvmAssembly);
+ }
+ return ikvmAssembly;
+ }
+
+ public abstract Type GetType(string typeName);
+ }
+}
diff --git a/refemit/Impl/CryptoConvert.cs b/refemit/Impl/CryptoConvert.cs
new file mode 100644
index 00000000..14687dee
--- /dev/null
+++ b/refemit/Impl/CryptoConvert.cs
@@ -0,0 +1,743 @@
+//
+// CryptoConvert.cs - Crypto Convertion Routines
+//
+// Author:
+// Sebastien Pouliot <sebastien@ximian.com>
+//
+// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// [JF-20081013] begin modifications for IKVM
+#define INSIDE_CORLIB
+// end modifications for IKVM
+
+using System;
+using System.Globalization;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace Mono.Security.Cryptography {
+
+#if INSIDE_CORLIB
+ internal
+#else
+ public
+#endif
+ sealed class CryptoConvert {
+
+ private CryptoConvert ()
+ {
+ }
+
+ static private int ToInt32LE (byte [] bytes, int offset)
+ {
+ return (bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset];
+ }
+
+ static private uint ToUInt32LE (byte [] bytes, int offset)
+ {
+ return (uint)((bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]);
+ }
+
+ static private byte [] GetBytesLE (int val)
+ {
+ return new byte [] {
+ (byte) (val & 0xff),
+ (byte) ((val >> 8) & 0xff),
+ (byte) ((val >> 16) & 0xff),
+ (byte) ((val >> 24) & 0xff)
+ };
+ }
+
+ static private byte[] Trim (byte[] array)
+ {
+ for (int i=0; i < array.Length; i++) {
+ if (array [i] != 0x00) {
+ byte[] result = new byte [array.Length - i];
+ Buffer.BlockCopy (array, i, result, 0, result.Length);
+ return result;
+ }
+ }
+ return null;
+ }
+
+ // convert the key from PRIVATEKEYBLOB to RSA
+ // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/Security/private_key_blobs.asp
+ // e.g. SNK files, PVK files
+ static public RSA FromCapiPrivateKeyBlob (byte[] blob)
+ {
+ return FromCapiPrivateKeyBlob (blob, 0);
+ }
+
+ static public RSA FromCapiPrivateKeyBlob (byte[] blob, int offset)
+ {
+ if (blob == null)
+ throw new ArgumentNullException ("blob");
+ if (offset >= blob.Length)
+ throw new ArgumentException ("blob is too small.");
+
+ RSAParameters rsap = new RSAParameters ();
+ try {
+ if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
+ (blob [offset+1] != 0x02) || // Version (0x02)
+ (blob [offset+2] != 0x00) || // Reserved (word)
+ (blob [offset+3] != 0x00) ||
+ (ToUInt32LE (blob, offset+8) != 0x32415352)) // DWORD magic = RSA2
+ throw new CryptographicException ("Invalid blob header");
+
+ // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
+ // int algId = ToInt32LE (blob, offset+4);
+
+ // DWORD bitlen
+ int bitLen = ToInt32LE (blob, offset+12);
+
+ // DWORD public exponent
+ byte[] exp = new byte [4];
+ Buffer.BlockCopy (blob, offset+16, exp, 0, 4);
+ Array.Reverse (exp);
+ rsap.Exponent = Trim (exp);
+
+ int pos = offset+20;
+ // BYTE modulus[rsapubkey.bitlen/8];
+ int byteLen = (bitLen >> 3);
+ rsap.Modulus = new byte [byteLen];
+ Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
+ Array.Reverse (rsap.Modulus);
+ pos += byteLen;
+
+ // BYTE prime1[rsapubkey.bitlen/16];
+ int byteHalfLen = (byteLen >> 1);
+ rsap.P = new byte [byteHalfLen];
+ Buffer.BlockCopy (blob, pos, rsap.P, 0, byteHalfLen);
+ Array.Reverse (rsap.P);
+ pos += byteHalfLen;
+
+ // BYTE prime2[rsapubkey.bitlen/16];
+ rsap.Q = new byte [byteHalfLen];
+ Buffer.BlockCopy (blob, pos, rsap.Q, 0, byteHalfLen);
+ Array.Reverse (rsap.Q);
+ pos += byteHalfLen;
+
+ // BYTE exponent1[rsapubkey.bitlen/16];
+ rsap.DP = new byte [byteHalfLen];
+ Buffer.BlockCopy (blob, pos, rsap.DP, 0, byteHalfLen);
+ Array.Reverse (rsap.DP);
+ pos += byteHalfLen;
+
+ // BYTE exponent2[rsapubkey.bitlen/16];
+ rsap.DQ = new byte [byteHalfLen];
+ Buffer.BlockCopy (blob, pos, rsap.DQ, 0, byteHalfLen);
+ Array.Reverse (rsap.DQ);
+ pos += byteHalfLen;
+
+ // BYTE coefficient[rsapubkey.bitlen/16];
+ rsap.InverseQ = new byte [byteHalfLen];
+ Buffer.BlockCopy (blob, pos, rsap.InverseQ, 0, byteHalfLen);
+ Array.Reverse (rsap.InverseQ);
+ pos += byteHalfLen;
+
+ // ok, this is hackish but CryptoAPI support it so...
+ // note: only works because CRT is used by default
+ // http://bugzilla.ximian.com/show_bug.cgi?id=57941
+ rsap.D = new byte [byteLen]; // must be allocated
+ if (pos + byteLen + offset <= blob.Length) {
+ // BYTE privateExponent[rsapubkey.bitlen/8];
+ Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen);
+ Array.Reverse (rsap.D);
+ }
+ }
+ catch (Exception e) {
+ throw new CryptographicException ("Invalid blob.", e);
+ }
+
+ RSA rsa = null;
+ try {
+ rsa = RSA.Create ();
+ rsa.ImportParameters (rsap);
+ }
+ catch (CryptographicException ce) {
+ // this may cause problem when this code is run under
+ // the SYSTEM identity on Windows (e.g. ASP.NET). See
+ // http://bugzilla.ximian.com/show_bug.cgi?id=77559
+ try {
+ CspParameters csp = new CspParameters ();
+ csp.Flags = CspProviderFlags.UseMachineKeyStore;
+ rsa = new RSACryptoServiceProvider (csp);
+ rsa.ImportParameters (rsap);
+ }
+ catch {
+ // rethrow original, not the later, exception if this fails
+ throw ce;
+ }
+ }
+ return rsa;
+ }
+
+ static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob)
+ {
+ return FromCapiPrivateKeyBlobDSA (blob, 0);
+ }
+
+ static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob, int offset)
+ {
+ if (blob == null)
+ throw new ArgumentNullException ("blob");
+ if (offset >= blob.Length)
+ throw new ArgumentException ("blob is too small.");
+
+ DSAParameters dsap = new DSAParameters ();
+ try {
+ if ((blob [offset] != 0x07) || // PRIVATEKEYBLOB (0x07)
+ (blob [offset + 1] != 0x02) || // Version (0x02)
+ (blob [offset + 2] != 0x00) || // Reserved (word)
+ (blob [offset + 3] != 0x00) ||
+ (ToUInt32LE (blob, offset + 8) != 0x32535344)) // DWORD magic
+ throw new CryptographicException ("Invalid blob header");
+
+ int bitlen = ToInt32LE (blob, offset + 12);
+ int bytelen = bitlen >> 3;
+ int pos = offset + 16;
+
+ dsap.P = new byte [bytelen];
+ Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen);
+ Array.Reverse (dsap.P);
+ pos += bytelen;
+
+ dsap.Q = new byte [20];
+ Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20);
+ Array.Reverse (dsap.Q);
+ pos += 20;
+
+ dsap.G = new byte [bytelen];
+ Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen);
+ Array.Reverse (dsap.G);
+ pos += bytelen;
+
+ dsap.X = new byte [20];
+ Buffer.BlockCopy (blob, pos, dsap.X, 0, 20);
+ Array.Reverse (dsap.X);
+ pos += 20;
+
+ dsap.Counter = ToInt32LE (blob, pos);
+ pos += 4;
+
+ dsap.Seed = new byte [20];
+ Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
+ Array.Reverse (dsap.Seed);
+ pos += 20;
+ }
+ catch (Exception e) {
+ throw new CryptographicException ("Invalid blob.", e);
+ }
+
+ DSA dsa = null;
+ try {
+ dsa = (DSA)DSA.Create ();
+ dsa.ImportParameters (dsap);
+ }
+ catch (CryptographicException ce) {
+ // this may cause problem when this code is run under
+ // the SYSTEM identity on Windows (e.g. ASP.NET). See
+ // http://bugzilla.ximian.com/show_bug.cgi?id=77559
+ try {
+ CspParameters csp = new CspParameters ();
+ csp.Flags = CspProviderFlags.UseMachineKeyStore;
+ dsa = new DSACryptoServiceProvider (csp);
+ dsa.ImportParameters (dsap);
+ }
+ catch {
+ // rethrow original, not the later, exception if this fails
+ throw ce;
+ }
+ }
+ return dsa;
+ }
+
+ static public byte[] ToCapiPrivateKeyBlob (RSA rsa)
+ {
+ RSAParameters p = rsa.ExportParameters (true);
+ int keyLength = p.Modulus.Length; // in bytes
+ byte[] blob = new byte [20 + (keyLength << 2) + (keyLength >> 1)];
+
+ blob [0] = 0x07; // Type - PRIVATEKEYBLOB (0x07)
+ blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
+ // [2], [3] // RESERVED - Always 0
+ blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
+ blob [8] = 0x52; // Magic - RSA2 (ASCII in hex)
+ blob [9] = 0x53;
+ blob [10] = 0x41;
+ blob [11] = 0x32;
+
+ byte[] bitlen = GetBytesLE (keyLength << 3);
+ blob [12] = bitlen [0]; // bitlen
+ blob [13] = bitlen [1];
+ blob [14] = bitlen [2];
+ blob [15] = bitlen [3];
+
+ // public exponent (DWORD)
+ int pos = 16;
+ int n = p.Exponent.Length;
+ while (n > 0)
+ blob [pos++] = p.Exponent [--n];
+ // modulus
+ pos = 20;
+ byte[] part = p.Modulus;
+ int len = part.Length;
+ Array.Reverse (part, 0, len);
+ Buffer.BlockCopy (part, 0, blob, pos, len);
+ pos += len;
+ // private key
+ part = p.P;
+ len = part.Length;
+ Array.Reverse (part, 0, len);
+ Buffer.BlockCopy (part, 0, blob, pos, len);
+ pos += len;
+
+ part = p.Q;
+ len = part.Length;
+ Array.Reverse (part, 0, len);
+ Buffer.BlockCopy (part, 0, blob, pos, len);
+ pos += len;
+
+ part = p.DP;
+ len = part.Length;
+ Array.Reverse (part, 0, len);
+ Buffer.BlockCopy (part, 0, blob, pos, len);
+ pos += len;
+
+ part = p.DQ;
+ len = part.Length;
+ Array.Reverse (part, 0, len);
+ Buffer.BlockCopy (part, 0, blob, pos, len);
+ pos += len;
+
+ part = p.InverseQ;
+ len = part.Length;
+ Array.Reverse (part, 0, len);
+ Buffer.BlockCopy (part, 0, blob, pos, len);
+ pos += len;
+
+ part = p.D;
+ len = part.Length;
+ Array.Reverse (part, 0, len);
+ Buffer.BlockCopy (part, 0, blob, pos, len);
+
+ return blob;
+ }
+
+ static public byte[] ToCapiPrivateKeyBlob (DSA dsa)
+ {
+ DSAParameters p = dsa.ExportParameters (true);
+ int keyLength = p.P.Length; // in bytes
+
+ // header + P + Q + G + X + count + seed
+ byte[] blob = new byte [16 + keyLength + 20 + keyLength + 20 + 4 + 20];
+
+ blob [0] = 0x07; // Type - PRIVATEKEYBLOB (0x07)
+ blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
+ // [2], [3] // RESERVED - Always 0
+ blob [5] = 0x22; // ALGID
+ blob [8] = 0x44; // Magic
+ blob [9] = 0x53;
+ blob [10] = 0x53;
+ blob [11] = 0x32;
+
+ byte[] bitlen = GetBytesLE (keyLength << 3);
+ blob [12] = bitlen [0];
+ blob [13] = bitlen [1];
+ blob [14] = bitlen [2];
+ blob [15] = bitlen [3];
+
+ int pos = 16;
+ byte[] part = p.P;
+ Array.Reverse (part);
+ Buffer.BlockCopy (part, 0, blob, pos, keyLength);
+ pos += keyLength;
+
+ part = p.Q;
+ Array.Reverse (part);
+ Buffer.BlockCopy (part, 0, blob, pos, 20);
+ pos += 20;
+
+ part = p.G;
+ Array.Reverse (part);
+ Buffer.BlockCopy (part, 0, blob, pos, keyLength);
+ pos += keyLength;
+
+ part = p.X;
+ Array.Reverse (part);
+ Buffer.BlockCopy (part, 0, blob, pos, 20);
+ pos += 20;
+
+ Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4);
+ pos += 4;
+
+ part = p.Seed;
+ Array.Reverse (part);
+ Buffer.BlockCopy (part, 0, blob, pos, 20);
+
+ return blob;
+ }
+
+ static public RSA FromCapiPublicKeyBlob (byte[] blob)
+ {
+ return FromCapiPublicKeyBlob (blob, 0);
+ }
+
+ static public RSA FromCapiPublicKeyBlob (byte[] blob, int offset)
+ {
+ if (blob == null)
+ throw new ArgumentNullException ("blob");
+ if (offset >= blob.Length)
+ throw new ArgumentException ("blob is too small.");
+
+ try {
+ if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06)
+ (blob [offset+1] != 0x02) || // Version (0x02)
+ (blob [offset+2] != 0x00) || // Reserved (word)
+ (blob [offset+3] != 0x00) ||
+ (ToUInt32LE (blob, offset+8) != 0x31415352)) // DWORD magic = RSA1
+ throw new CryptographicException ("Invalid blob header");
+
+ // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
+ // int algId = ToInt32LE (blob, offset+4);
+
+ // DWORD bitlen
+ int bitLen = ToInt32LE (blob, offset+12);
+
+ // DWORD public exponent
+ RSAParameters rsap = new RSAParameters ();
+ rsap.Exponent = new byte [3];
+ rsap.Exponent [0] = blob [offset+18];
+ rsap.Exponent [1] = blob [offset+17];
+ rsap.Exponent [2] = blob [offset+16];
+
+ int pos = offset+20;
+ // BYTE modulus[rsapubkey.bitlen/8];
+ int byteLen = (bitLen >> 3);
+ rsap.Modulus = new byte [byteLen];
+ Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
+ Array.Reverse (rsap.Modulus);
+
+ RSA rsa = null;
+ try {
+ rsa = RSA.Create ();
+ rsa.ImportParameters (rsap);
+ }
+ catch (CryptographicException) {
+ // this may cause problem when this code is run under
+ // the SYSTEM identity on Windows (e.g. ASP.NET). See
+ // http://bugzilla.ximian.com/show_bug.cgi?id=77559
+ CspParameters csp = new CspParameters ();
+ csp.Flags = CspProviderFlags.UseMachineKeyStore;
+ rsa = new RSACryptoServiceProvider (csp);
+ rsa.ImportParameters (rsap);
+ }
+ return rsa;
+ }
+ catch (Exception e) {
+ throw new CryptographicException ("Invalid blob.", e);
+ }
+ }
+
+ static public DSA FromCapiPublicKeyBlobDSA (byte[] blob)
+ {
+ return FromCapiPublicKeyBlobDSA (blob, 0);
+ }
+
+ static public DSA FromCapiPublicKeyBlobDSA (byte[] blob, int offset)
+ {
+ if (blob == null)
+ throw new ArgumentNullException ("blob");
+ if (offset >= blob.Length)
+ throw new ArgumentException ("blob is too small.");
+
+ try {
+ if ((blob [offset] != 0x06) || // PUBLICKEYBLOB (0x06)
+ (blob [offset + 1] != 0x02) || // Version (0x02)
+ (blob [offset + 2] != 0x00) || // Reserved (word)
+ (blob [offset + 3] != 0x00) ||
+ (ToUInt32LE (blob, offset + 8) != 0x31535344)) // DWORD magic
+ throw new CryptographicException ("Invalid blob header");
+
+ int bitlen = ToInt32LE (blob, offset + 12);
+ DSAParameters dsap = new DSAParameters ();
+ int bytelen = bitlen >> 3;
+ int pos = offset + 16;
+
+ dsap.P = new byte [bytelen];
+ Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen);
+ Array.Reverse (dsap.P);
+ pos += bytelen;
+
+ dsap.Q = new byte [20];
+ Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20);
+ Array.Reverse (dsap.Q);
+ pos += 20;
+
+ dsap.G = new byte [bytelen];
+ Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen);
+ Array.Reverse (dsap.G);
+ pos += bytelen;
+
+ dsap.Y = new byte [bytelen];
+ Buffer.BlockCopy (blob, pos, dsap.Y, 0, bytelen);
+ Array.Reverse (dsap.Y);
+ pos += bytelen;
+
+ dsap.Counter = ToInt32LE (blob, pos);
+ pos += 4;
+
+ dsap.Seed = new byte [20];
+ Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
+ Array.Reverse (dsap.Seed);
+ pos += 20;
+
+ DSA dsa = (DSA)DSA.Create ();
+ dsa.ImportParameters (dsap);
+ return dsa;
+ }
+ catch (Exception e) {
+ throw new CryptographicException ("Invalid blob.", e);
+ }
+ }
+
+ static public byte[] ToCapiPublicKeyBlob (RSA rsa)
+ {
+ RSAParameters p = rsa.ExportParameters (false);
+ int keyLength = p.Modulus.Length; // in bytes
+ byte[] blob = new byte [20 + keyLength];
+
+ blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06)
+ blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
+ // [2], [3] // RESERVED - Always 0
+ blob [5] = 0x24; // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
+ blob [8] = 0x52; // Magic - RSA1 (ASCII in hex)
+ blob [9] = 0x53;
+ blob [10] = 0x41;
+ blob [11] = 0x31;
+
+ byte[] bitlen = GetBytesLE (keyLength << 3);
+ blob [12] = bitlen [0]; // bitlen
+ blob [13] = bitlen [1];
+ blob [14] = bitlen [2];
+ blob [15] = bitlen [3];
+
+ // public exponent (DWORD)
+ int pos = 16;
+ int n = p.Exponent.Length;
+ while (n > 0)
+ blob [pos++] = p.Exponent [--n];
+ // modulus
+ pos = 20;
+ byte[] part = p.Modulus;
+ int len = part.Length;
+ Array.Reverse (part, 0, len);
+ Buffer.BlockCopy (part, 0, blob, pos, len);
+ pos += len;
+ return blob;
+ }
+
+ static public byte[] ToCapiPublicKeyBlob (DSA dsa)
+ {
+ DSAParameters p = dsa.ExportParameters (false);
+ int keyLength = p.P.Length; // in bytes
+
+ // header + P + Q + G + Y + count + seed
+ byte[] blob = new byte [16 + keyLength + 20 + keyLength + keyLength + 4 + 20];
+
+ blob [0] = 0x06; // Type - PUBLICKEYBLOB (0x06)
+ blob [1] = 0x02; // Version - Always CUR_BLOB_VERSION (0x02)
+ // [2], [3] // RESERVED - Always 0
+ blob [5] = 0x22; // ALGID
+ blob [8] = 0x44; // Magic
+ blob [9] = 0x53;
+ blob [10] = 0x53;
+ blob [11] = 0x31;
+
+ byte[] bitlen = GetBytesLE (keyLength << 3);
+ blob [12] = bitlen [0];
+ blob [13] = bitlen [1];
+ blob [14] = bitlen [2];
+ blob [15] = bitlen [3];
+
+ int pos = 16;
+ byte[] part;
+
+ part = p.P;
+ Array.Reverse (part);
+ Buffer.BlockCopy (part, 0, blob, pos, keyLength);
+ pos += keyLength;
+
+ part = p.Q;
+ Array.Reverse (part);
+ Buffer.BlockCopy (part, 0, blob, pos, 20);
+ pos += 20;
+
+ part = p.G;
+ Array.Reverse (part);
+ Buffer.BlockCopy (part, 0, blob, pos, keyLength);
+ pos += keyLength;
+
+ part = p.Y;
+ Array.Reverse (part);
+ Buffer.BlockCopy (part, 0, blob, pos, keyLength);
+ pos += keyLength;
+
+ Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4);
+ pos += 4;
+
+ part = p.Seed;
+ Array.Reverse (part);
+ Buffer.BlockCopy (part, 0, blob, pos, 20);
+
+ return blob;
+ }
+
+ // PRIVATEKEYBLOB
+ // PUBLICKEYBLOB
+ static public RSA FromCapiKeyBlob (byte[] blob)
+ {
+ return FromCapiKeyBlob (blob, 0);
+ }
+
+ static public RSA FromCapiKeyBlob (byte[] blob, int offset)
+ {
+ if (blob == null)
+ throw new ArgumentNullException ("blob");
+ if (offset >= blob.Length)
+ throw new ArgumentException ("blob is too small.");
+
+ switch (blob [offset]) {
+ case 0x00:
+ // this could be a public key inside an header
+ // like "sn -e" would produce
+ if (blob [offset + 12] == 0x06) {
+ return FromCapiPublicKeyBlob (blob, offset + 12);
+ }
+ break;
+ case 0x06:
+ return FromCapiPublicKeyBlob (blob, offset);
+ case 0x07:
+ return FromCapiPrivateKeyBlob (blob, offset);
+ }
+ throw new CryptographicException ("Unknown blob format.");
+ }
+
+ static public DSA FromCapiKeyBlobDSA (byte[] blob)
+ {
+ return FromCapiKeyBlobDSA (blob, 0);
+ }
+
+ static public DSA FromCapiKeyBlobDSA (byte[] blob, int offset)
+ {
+ if (blob == null)
+ throw new ArgumentNullException ("blob");
+ if (offset >= blob.Length)
+ throw new ArgumentException ("blob is too small.");
+
+ switch (blob [offset]) {
+ case 0x06:
+ return FromCapiPublicKeyBlobDSA (blob, offset);
+ case 0x07:
+ return FromCapiPrivateKeyBlobDSA (blob, offset);
+ }
+ throw new CryptographicException ("Unknown blob format.");
+ }
+
+ static public byte[] ToCapiKeyBlob (AsymmetricAlgorithm keypair, bool includePrivateKey)
+ {
+ if (keypair == null)
+ throw new ArgumentNullException ("keypair");
+
+ // check between RSA and DSA (and potentially others like DH)
+ if (keypair is RSA)
+ return ToCapiKeyBlob ((RSA)keypair, includePrivateKey);
+ else if (keypair is DSA)
+ return ToCapiKeyBlob ((DSA)keypair, includePrivateKey);
+ else
+ return null; // TODO
+ }
+
+ static public byte[] ToCapiKeyBlob (RSA rsa, bool includePrivateKey)
+ {
+ if (rsa == null)
+ throw new ArgumentNullException ("rsa");
+
+ if (includePrivateKey)
+ return ToCapiPrivateKeyBlob (rsa);
+ else
+ return ToCapiPublicKeyBlob (rsa);
+ }
+
+ static public byte[] ToCapiKeyBlob (DSA dsa, bool includePrivateKey)
+ {
+ if (dsa == null)
+ throw new ArgumentNullException ("dsa");
+
+ if (includePrivateKey)
+ return ToCapiPrivateKeyBlob (dsa);
+ else
+ return ToCapiPublicKeyBlob (dsa);
+ }
+
+ static public string ToHex (byte[] input)
+ {
+ if (input == null)
+ return null;
+
+ StringBuilder sb = new StringBuilder (input.Length * 2);
+ foreach (byte b in input) {
+ sb.Append (b.ToString ("X2", CultureInfo.InvariantCulture));
+ }
+ return sb.ToString ();
+ }
+
+ static private byte FromHexChar (char c)
+ {
+ if ((c >= 'a') && (c <= 'f'))
+ return (byte) (c - 'a' + 10);
+ if ((c >= 'A') && (c <= 'F'))
+ return (byte) (c - 'A' + 10);
+ if ((c >= '0') && (c <= '9'))
+ return (byte) (c - '0');
+ throw new ArgumentException ("invalid hex char");
+ }
+
+ static public byte[] FromHex (string hex)
+ {
+ if (hex == null)
+ return null;
+ if ((hex.Length & 0x1) == 0x1)
+ throw new ArgumentException ("Length must be a multiple of 2");
+
+ byte[] result = new byte [hex.Length >> 1];
+ int n = 0;
+ int i = 0;
+ while (n < result.Length) {
+ result [n] = (byte) (FromHexChar (hex [i++]) << 4);
+ result [n++] += FromHexChar (hex [i++]);
+ }
+ return result;
+ }
+ }
+}
diff --git a/refemit/Impl/CryptoHack.cs b/refemit/Impl/CryptoHack.cs
new file mode 100644
index 00000000..f1b47ad0
--- /dev/null
+++ b/refemit/Impl/CryptoHack.cs
@@ -0,0 +1,57 @@
+/*
+ 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.Security.Cryptography;
+using System.Reflection;
+using System.Runtime.Serialization;
+
+namespace IKVM.Reflection.Emit.Impl
+{
+ static class CryptoHack
+ {
+ internal static RSA CreateRSA(StrongNameKeyPair keyPair)
+ {
+ // HACK use serialization to get at the private key or key container name,
+ // this should be more future proof than using reflection to access the fields directly.
+ SerializationInfo ser = new SerializationInfo(typeof(StrongNameKeyPair), new FormatterConverter());
+ ((ISerializable)keyPair).GetObjectData(ser, new StreamingContext());
+ byte[] key = (byte[])ser.GetValue("_keyPairArray", typeof(byte[]));
+ string keycontainer = ser.GetString("_keyPairContainer");
+ if (keycontainer != null)
+ {
+ CspParameters parm = new CspParameters();
+ parm.Flags = CspProviderFlags.UseMachineKeyStore;
+ parm.KeyContainerName = keycontainer;
+ parm.KeyNumber = 2; // Signature
+ return new RSACryptoServiceProvider(parm);
+ }
+ else
+ {
+ return Mono.Security.Cryptography.CryptoConvert.FromCapiKeyBlob(key);
+ }
+ }
+ }
+}
diff --git a/refemit/Impl/ITypeOwner.cs b/refemit/Impl/ITypeOwner.cs
new file mode 100644
index 00000000..c901a564
--- /dev/null
+++ b/refemit/Impl/ITypeOwner.cs
@@ -0,0 +1,31 @@
+/*
+ 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
+
+*/
+
+namespace IKVM.Reflection.Emit.Impl
+{
+ interface ITypeOwner
+ {
+ ModuleBuilder ModuleBuilder { get; }
+ }
+}
diff --git a/refemit/Impl/PdbSupport.cs b/refemit/Impl/PdbSupport.cs
new file mode 100644
index 00000000..5d641e8b
--- /dev/null
+++ b/refemit/Impl/PdbSupport.cs
@@ -0,0 +1,179 @@
+/*
+ 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.Runtime.InteropServices;
+using System.Diagnostics.SymbolStore;
+
+namespace IKVM.Reflection.Emit.Impl
+{
+ static class PdbSupport
+ {
+ [Guid("809c652e-7396-11d2-9771-00a0c9b4d50c")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [CoClass(typeof(MetaDataDispenserClass))]
+ [ComImport]
+ private interface IMetaDataDispenser
+ {
+ void DefineScope(
+ [In] ref Guid rclsid,
+ [In] int dwCreateFlags,
+ [In] ref Guid riid,
+ [Out, MarshalAs(UnmanagedType.IUnknown)] out object punk);
+ }
+
+ [Guid("e5cb7a31-7512-11d2-89ce-0080c792e5d8")]
+ [ComImport]
+ private class MetaDataDispenserClass { }
+
+ [Guid("7dac8207-d3ae-4c75-9b67-92801a497d44")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [ComImport]
+ private interface IMetadataImport { }
+
+ [Guid("ba3fee4c-ecb9-4e41-83b7-183fa41cd859")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [ComImport]
+ private interface IMetaDataEmit { }
+
+ [Guid("ed14aa72-78e2-4884-84e2-334293ae5214")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [ComImport]
+ [CoClass(typeof(CorSymWriterClass))]
+ private interface ISymUnmanagedWriter
+ {
+ void PlaceHolder_DefineDocument();
+ void PlaceHolder_SetUserEntryPoint();
+ void PlaceHolder_OpenMethod();
+ void PlaceHolder_CloseMethod();
+ void PlaceHolder_OpenScope();
+ void PlaceHolder_CloseScope();
+ void PlaceHolder_SetScopeRange();
+ void PlaceHolder_DefineLocalVariable();
+ void PlaceHolder_DefineParameter();
+ void PlaceHolder_DefineField();
+ void PlaceHolder_DefineGlobalVariable();
+ void PlaceHolder_Close();
+ void PlaceHolder_SetSymAttribute();
+ void PlaceHolder_OpenNamespace();
+ void PlaceHolder_CloseNamespace();
+ void PlaceHolder_UsingNamespace();
+ void PlaceHolder_SetMethodSourceRange();
+ void PlaceHolder_Initialize();
+
+ void GetDebugInfo(
+ [In, Out] ref IMAGE_DEBUG_DIRECTORY pIDD,
+ [In] uint cData,
+ [Out] out uint pcData,
+ [Out, MarshalAs(UnmanagedType.LPArray)] byte[] data);
+
+ void PlaceHolder_DefineSequencePoints();
+
+ void RemapToken(
+ [In] int oldToken,
+ [In] int newToken);
+ }
+
+ [Guid("108296c1-281e-11d3-bd22-0000f80849bd")]
+ [ComImport]
+ private class CorSymWriterClass { }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct IMAGE_DEBUG_DIRECTORY
+ {
+ internal uint Characteristics;
+ internal uint TimeDateStamp;
+ internal ushort MajorVersion;
+ internal ushort MinorVersion;
+ internal uint Type;
+ internal uint SizeOfData;
+ internal uint AddressOfRawData;
+ internal uint PointerToRawData;
+ }
+
+ private sealed class MySymWriter : SymWriter
+ {
+ private readonly IntPtr ppISymUnmanagedWriter = Marshal.AllocHGlobal(IntPtr.Size);
+ private readonly ISymUnmanagedWriter symUnmanagedWriter = new ISymUnmanagedWriter();
+ private readonly IntPtr pISymUnmanagedWriter;
+
+ internal MySymWriter(string fileName)
+ {
+ pISymUnmanagedWriter = Marshal.GetComInterfaceForObject(symUnmanagedWriter, typeof(ISymUnmanagedWriter));
+ Marshal.WriteIntPtr(ppISymUnmanagedWriter, pISymUnmanagedWriter);
+ SetUnderlyingWriter(ppISymUnmanagedWriter);
+ IMetaDataDispenser disp = new IMetaDataDispenser();
+ object emitter;
+ Guid CLSID_CorMetaDataRuntime = new Guid("005023ca-72b1-11d3-9fc4-00c04f79a0a3");
+ Guid IID_IMetaDataEmit = typeof(IMetaDataEmit).GUID;
+ disp.DefineScope(ref CLSID_CorMetaDataRuntime, 0, ref IID_IMetaDataEmit, out emitter);
+ IntPtr emitterPtr = Marshal.GetComInterfaceForObject(emitter, typeof(IMetaDataEmit));
+ try
+ {
+ Initialize(emitterPtr, fileName, true);
+ }
+ finally
+ {
+ Marshal.Release(emitterPtr);
+ }
+ Marshal.ReleaseComObject(disp);
+ Marshal.ReleaseComObject(emitter);
+ }
+
+ ~MySymWriter()
+ {
+ Marshal.Release(pISymUnmanagedWriter);
+ Marshal.FreeHGlobal(ppISymUnmanagedWriter);
+ }
+
+ internal byte[] GetDebugInfo(ref IMAGE_DEBUG_DIRECTORY idd)
+ {
+ uint cData;
+ symUnmanagedWriter.GetDebugInfo(ref idd, 0, out cData, null);
+ byte[] buf = new byte[cData];
+ symUnmanagedWriter.GetDebugInfo(ref idd, (uint)buf.Length, out cData, buf);
+ return buf;
+ }
+
+ internal void RemapToken(int oldToken, int newToken)
+ {
+ symUnmanagedWriter.RemapToken(oldToken, newToken);
+ }
+ }
+
+ internal static ISymbolWriter CreateSymbolWriter(string fileName)
+ {
+ return new MySymWriter(fileName);
+ }
+
+ internal static byte[] GetDebugInfo(ISymbolWriter writer, ref IMAGE_DEBUG_DIRECTORY idd)
+ {
+ return ((MySymWriter)writer).GetDebugInfo(ref idd);
+ }
+
+ internal static void RemapToken(ISymbolWriter writer, int oldToken, int newToken)
+ {
+ ((MySymWriter)writer).RemapToken(oldToken, newToken);
+ }
+ }
+}
diff --git a/refemit/Impl/TypeBase.cs b/refemit/Impl/TypeBase.cs
new file mode 100644
index 00000000..69a3ab2f
--- /dev/null
+++ b/refemit/Impl/TypeBase.cs
@@ -0,0 +1,223 @@
+/*
+ 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.Reflection;
+
+namespace IKVM.Reflection.Emit.Impl
+{
+ public abstract class TypeBase : Type
+ {
+ public sealed override Assembly Assembly
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public abstract override string AssemblyQualifiedName
+ {
+ get;
+ }
+
+ public abstract override Type BaseType
+ {
+ get;
+ }
+
+ public abstract override string FullName
+ {
+ get;
+ }
+
+ public sealed override Guid GUID
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ protected abstract override TypeAttributes GetAttributeFlagsImpl();
+
+ protected sealed override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override Type GetElementType()
+ {
+ return null;
+ }
+
+ public sealed override EventInfo GetEvent(string name, BindingFlags bindingAttr)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override EventInfo[] GetEvents(BindingFlags bindingAttr)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override FieldInfo GetField(string name, BindingFlags bindingAttr)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override FieldInfo[] GetFields(BindingFlags bindingAttr)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override Type GetInterface(string name, bool ignoreCase)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override Type[] GetInterfaces()
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override MemberInfo[] GetMembers(BindingFlags bindingAttr)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected abstract override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers);
+
+ public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override Type GetNestedType(string name, BindingFlags bindingAttr)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override Type[] GetNestedTypes(BindingFlags bindingAttr)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected sealed override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected abstract override bool HasElementTypeImpl();
+
+ public sealed override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters)
+ {
+ throw new NotSupportedException();
+ }
+
+ protected abstract override bool IsArrayImpl();
+
+ protected abstract override bool IsByRefImpl();
+
+ protected sealed override bool IsCOMObjectImpl()
+ {
+ throw new NotSupportedException();
+ }
+
+ protected sealed override bool IsPointerImpl()
+ {
+ return false;
+ }
+
+ protected sealed override bool IsPrimitiveImpl()
+ {
+ return false;
+ }
+
+ public sealed override Module Module
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public override Type UnderlyingSystemType
+ {
+ get { return this; }
+ }
+
+ public override Type DeclaringType
+ {
+ get { return null; }
+ }
+
+ public sealed override object[] GetCustomAttributes(Type attributeType, bool inherit)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override object[] GetCustomAttributes(bool inherit)
+ {
+ throw new NotSupportedException();
+ }
+
+ public sealed override bool IsDefined(Type attributeType, bool inherit)
+ {
+ throw new NotSupportedException();
+ }
+
+ public override string Name
+ {
+ get
+ {
+ string fullname = FullName;
+ return fullname.Substring(fullname.LastIndexOf('.') + 1);
+ }
+ }
+
+ public sealed override string Namespace
+ {
+ get
+ {
+ if (IsNested)
+ {
+ return null;
+ }
+ string fullname = FullName;
+ int index = fullname.LastIndexOf('.');
+ return index < 0 ? null : fullname.Substring(0, index);
+ }
+ }
+
+ public override Type MakeArrayType()
+ {
+ return ArrayType.Make(this);
+ }
+
+ internal abstract ModuleBuilder ModuleBuilder { get; }
+
+ internal abstract TypeToken GetToken();
+ }
+}
diff --git a/refemit/MethodBuilder.cs b/refemit/MethodBuilder.cs
new file mode 100644
index 00000000..35a8f230
--- /dev/null
+++ b/refemit/MethodBuilder.cs
@@ -0,0 +1,524 @@
+/*
+ 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.Reflection;
+using System.IO;
+using System.Diagnostics;
+using IKVM.Reflection.Emit.Writer;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Diagnostics.SymbolStore;
+
+namespace IKVM.Reflection.Emit
+{
+ public sealed class MethodBuilder : MethodInfo
+ {
+ private readonly TypeBuilder typeBuilder;
+ private readonly string name;
+ private readonly int nameIndex;
+ private readonly int signature;
+ private readonly int pseudoToken;
+ private readonly Type returnType;
+ private readonly Type[] parameterTypes;
+ private readonly Type[][] requiredCustomModifiers; // last element is for the return type
+ private readonly Type[][] optionalCustomModifiers;
+ private MethodAttributes attributes;
+ private MethodImplAttributes implFlags;
+ private ILGenerator ilgen;
+ private int rva;
+ private List<ParameterBuilder> parameters;
+
+ internal MethodBuilder(TypeBuilder typeBuilder, string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers, Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers)
+ {
+ this.typeBuilder = typeBuilder;
+ this.name = name;
+ this.pseudoToken = typeBuilder.ModuleBuilder.AllocPseudoToken();
+ this.nameIndex = typeBuilder.ModuleBuilder.Strings.Add(name);
+ this.attributes = attributes;
+ this.returnType = returnType ?? typeof(void);
+ this.parameterTypes = Copy(parameterTypes);
+ if ((attributes & MethodAttributes.Static) == 0)
+ {
+ callingConvention |= CallingConventions.HasThis;
+ }
+ ByteBuffer signature = new ByteBuffer(16);
+ SignatureHelper.WriteMethodSig(this.ModuleBuilder, signature, callingConvention, returnType, returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers, parameterTypes, parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers);
+ this.signature = this.ModuleBuilder.Blobs.Add(signature);
+ requiredCustomModifiers = PackCustomModifiers(returnTypeRequiredCustomModifiers, parameterTypeRequiredCustomModifiers, this.parameterTypes.Length);
+ optionalCustomModifiers = PackCustomModifiers(returnTypeOptionalCustomModifiers, parameterTypeOptionalCustomModifiers, this.parameterTypes.Length);
+ }
+
+ internal static Type[] Copy(Type[] array)
+ {
+ if (array == null || array.Length == 0)
+ {
+ return Type.EmptyTypes;
+ }
+ Type[] newArray = new Type[array.Length];
+ Array.Copy(array, newArray, array.Length);
+ return newArray;
+ }
+
+ private static Type[][] PackCustomModifiers(Type[] returnTypeCustomModifiers, Type[][] parameterTypeCustomModifiers, int parameterCount)
+ {
+ if (returnTypeCustomModifiers == null && parameterTypeCustomModifiers == null)
+ {
+ return null;
+ }
+ Type[][] newArray = new Type[parameterCount + 1][];
+ newArray[parameterCount] = Copy(returnTypeCustomModifiers);
+ if (parameterTypeCustomModifiers != null)
+ {
+ for (int i = 0; i < parameterCount; i++)
+ {
+ newArray[i] = Copy(parameterTypeCustomModifiers[i]);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < parameterCount; i++)
+ {
+ newArray[i] = Type.EmptyTypes;
+ }
+ }
+ return newArray;
+ }
+
+ public ILGenerator GetILGenerator()
+ {
+ if (ilgen == null)
+ {
+ ilgen = new ILGenerator(typeBuilder.ModuleBuilder);
+ }
+ return ilgen;
+ }
+
+ public void SetCustomAttribute(ConstructorInfo con, byte[] binaryAttribute)
+ {
+ SetCustomAttribute(new CustomAttributeBuilder(con, binaryAttribute));
+ }
+
+ private void SetDllImportPseudoCustomAttribute(CustomAttributeBuilder customBuilder)
+ {
+ if (customBuilder.IsBlob)
+ {
+ throw new NotImplementedException();
+ }
+ const short NoMangle = 0x0001;
+ const short CharSetMask = 0x0006;
+ const short CharSetNotSpec = 0x0000;
+ const short CharSetAnsi = 0x0002;
+ const short CharSetUnicode = 0x0004;
+ const short CharSetAuto = 0x0006;
+ const short SupportsLastError = 0x0040;
+ const short CallConvMask = 0x0700;
+ const short CallConvWinapi = 0x0100;
+ const short CallConvCdecl = 0x0200;
+ const short CallConvStdcall = 0x0300;
+ const short CallConvThiscall = 0x0400;
+ const short CallConvFastcall = 0x0500;
+ // non-standard flags
+ const short BestFitOn = 0x0010;
+ const short BestFitOff = 0x0020;
+ const short CharMapErrorOn = 0x1000;
+ const short CharMapErrorOff = 0x2000;
+ int name = this.nameIndex;
+ short flags = CharSetNotSpec | CallConvWinapi;
+ bool? bestFitMapping = (bool?)customBuilder.GetFieldValue("BestFitMapping");
+ if (bestFitMapping.HasValue)
+ {
+ flags |= bestFitMapping.Value ? BestFitOn : BestFitOff;
+ }
+ bool? throwOnUnmappableChar = (bool?)customBuilder.GetFieldValue("ThrowOnUnmappableChar");
+ if (throwOnUnmappableChar.HasValue)
+ {
+ flags |= throwOnUnmappableChar.Value ? CharMapErrorOn : CharMapErrorOff;
+ }
+ CallingConvention? callingConvention = (CallingConvention?)customBuilder.GetFieldValue("CallingConvention");
+ if (callingConvention.HasValue)
+ {
+ flags &= ~CallConvMask;
+ switch (callingConvention.Value)
+ {
+ case System.Runtime.InteropServices.CallingConvention.Cdecl:
+ flags |= CallConvCdecl;
+ break;
+ case System.Runtime.InteropServices.CallingConvention.FastCall:
+ flags |= CallConvFastcall;
+ break;
+ case System.Runtime.InteropServices.CallingConvention.StdCall:
+ flags |= CallConvStdcall;
+ break;
+ case System.Runtime.InteropServices.CallingConvention.ThisCall:
+ flags |= CallConvThiscall;
+ break;
+ case System.Runtime.InteropServices.CallingConvention.Winapi:
+ flags |= CallConvWinapi;
+ break;
+ }
+ }
+ CharSet? charSet = (CharSet?)customBuilder.GetFieldValue("CharSet");
+ if (charSet.HasValue)
+ {
+ flags &= ~CharSetMask;
+ switch (charSet.Value)
+ {
+ case CharSet.Ansi:
+ case CharSet.None:
+ flags |= CharSetAnsi;
+ break;
+ case CharSet.Auto:
+ flags |= CharSetAuto;
+ break;
+ case CharSet.Unicode:
+ flags |= CharSetUnicode;
+ break;
+ }
+ }
+ string entryPoint = (string)customBuilder.GetFieldValue("EntryPoint");
+ if (entryPoint != null)
+ {
+ name = this.ModuleBuilder.Strings.Add(entryPoint);
+ }
+ bool? exactSpelling = (bool?)customBuilder.GetFieldValue("ExactSpelling");
+ if (exactSpelling.HasValue && exactSpelling.Value)
+ {
+ flags |= NoMangle;
+ }
+ bool? preserveSig = (bool?)customBuilder.GetFieldValue("PreserveSig");
+ if (!preserveSig.HasValue || preserveSig.Value)
+ {
+ implFlags |= MethodImplAttributes.PreserveSig;
+ }
+ bool? setLastError = (bool?)customBuilder.GetFieldValue("SetLastError");
+ if (setLastError.HasValue && setLastError.Value)
+ {
+ flags |= SupportsLastError;
+ }
+ TableHeap.ImplMapTable.Record rec = new TableHeap.ImplMapTable.Record();
+ rec.MappingFlags = flags;
+ rec.MemberForwarded = pseudoToken;
+ rec.ImportName = name;
+ rec.ImportScope = this.ModuleBuilder.Tables.ModuleRef.Add(this.ModuleBuilder.Strings.Add((string)customBuilder.GetConstructorArgument(0)));
+ this.ModuleBuilder.Tables.ImplMap.AddRecord(rec);
+ }
+
+ private void SetMethodImplAttribute(CustomAttributeBuilder customBuilder)
+ {
+ MethodImplOptions opt;
+ switch (customBuilder.Constructor.GetParameters().Length)
+ {
+ case 0:
+ opt = 0;
+ break;
+ case 1:
+ {
+ object val = customBuilder.GetConstructorArgument(0);
+ if (val is short)
+ {
+ opt = (MethodImplOptions)(short)val;
+ }
+ else
+ {
+ opt = (MethodImplOptions)val;
+ }
+ break;
+ }
+ default:
+ throw new NotSupportedException();
+ }
+ MethodCodeType? type = (MethodCodeType?)customBuilder.GetFieldValue("MethodCodeType");
+ implFlags = (MethodImplAttributes)opt;
+ if (type.HasValue)
+ {
+ implFlags |= (MethodImplAttributes)type;
+ }
+ }
+
+ public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+ {
+ if (customBuilder.Constructor.DeclaringType == typeof(DllImportAttribute))
+ {
+ SetDllImportPseudoCustomAttribute(customBuilder);
+ }
+ else if (customBuilder.Constructor.DeclaringType == typeof(MethodImplAttribute))
+ {
+ SetMethodImplAttribute(customBuilder);
+ }
+ else if (customBuilder.Constructor.DeclaringType == typeof(PreserveSigAttribute))
+ {
+ implFlags |= MethodImplAttributes.PreserveSig;
+ }
+ else
+ {
+ this.ModuleBuilder.SetCustomAttribute(pseudoToken, customBuilder);
+ }
+ }
+
+ public void AddDeclarativeSecurity(System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet)
+ {
+ TableHeap.DeclSecurityTable.Record rec = new TableHeap.DeclSecurityTable.Record();
+ rec.Action = (short)securityAction;
+ rec.Parent = pseudoToken;
+ // like Ref.Emit, we're using the .NET 1.x xml format
+ rec.PermissionSet = this.ModuleBuilder.Blobs.Add(ByteBuffer.Wrap(System.Text.Encoding.Unicode.GetBytes(permissionSet.ToXml().ToString())));
+ this.ModuleBuilder.Tables.DeclSecurity.AddRecord(rec);
+ this.attributes |= MethodAttributes.HasSecurity;
+ }
+
+ public void SetImplementationFlags(MethodImplAttributes attributes)
+ {
+ implFlags = attributes;
+ }
+
+ public ParameterBuilder DefineParameter(int position, ParameterAttributes attributes, string strParamName)
+ {
+ if (parameters == null)
+ {
+ parameters = new List<ParameterBuilder>();
+ }
+ this.ModuleBuilder.Tables.Param.AddRow();
+ ParameterBuilder pb = new ParameterBuilder(this.ModuleBuilder, position, attributes, strParamName);
+ parameters.Add(pb);
+ return pb;
+ }
+
+ public override MethodInfo GetBaseDefinition()
+ {
+ throw new NotSupportedException();
+ }
+
+ public override Type ReturnType
+ {
+ get { return returnType; }
+ }
+
+ public override ParameterInfo ReturnParameter
+ {
+ get { return new ParameterInfoImpl(this, -1); }
+ }
+
+ public override ICustomAttributeProvider ReturnTypeCustomAttributes
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override MethodAttributes Attributes
+ {
+ get { return attributes; }
+ }
+
+ public override MethodImplAttributes GetMethodImplementationFlags()
+ {
+ return implFlags;
+ }
+
+ private class ParameterInfoImpl : ParameterInfo
+ {
+ private readonly MethodBuilder method;
+ private readonly int parameter;
+
+ internal ParameterInfoImpl(MethodBuilder method, int parameter)
+ {
+ this.method = method;
+ this.parameter = parameter;
+ }
+
+ public override Type ParameterType
+ {
+ get
+ {
+ return parameter == -1 ? method.returnType : method.parameterTypes[parameter];
+ }
+ }
+
+ public override Type[] GetOptionalCustomModifiers()
+ {
+ if (method.optionalCustomModifiers == null)
+ {
+ return Type.EmptyTypes;
+ }
+ int index = parameter == -1 ? method.optionalCustomModifiers.Length - 1 : parameter;
+ return Copy(method.optionalCustomModifiers[index]);
+ }
+
+ public override Type[] GetRequiredCustomModifiers()
+ {
+ if (method.requiredCustomModifiers == null)
+ {
+ return Type.EmptyTypes;
+ }
+ int index = parameter == -1 ? method.requiredCustomModifiers.Length - 1 : parameter;
+ return Copy(method.requiredCustomModifiers[index]);
+ }
+ }
+
+ public override ParameterInfo[] GetParameters()
+ {
+ ParameterInfo[] parameters = new ParameterInfo[parameterTypes.Length];
+ for (int i = 0; i < parameters.Length; i++)
+ {
+ parameters[i] = new ParameterInfoImpl(this, i);
+ }
+ return parameters;
+ }
+
+ public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, System.Globalization.CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override RuntimeMethodHandle MethodHandle
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override Type DeclaringType
+ {
+ get { return this.ModuleBuilder.IsModuleType(typeBuilder) ? null : typeBuilder; }
+ }
+
+ public override object[] GetCustomAttributes(Type attributeType, bool inherit)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object[] GetCustomAttributes(bool inherit)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override bool IsDefined(Type attributeType, bool inherit)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override string Name
+ {
+ get { return name; }
+ }
+
+ public override Type ReflectedType
+ {
+ get { return this.DeclaringType; }
+ }
+
+ public override CallingConventions CallingConvention
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override int MetadataToken
+ {
+ get { return pseudoToken; }
+ }
+
+ internal void Bake()
+ {
+ if (ilgen != null)
+ {
+ if (this.ModuleBuilder.symbolWriter != null)
+ {
+ this.ModuleBuilder.symbolWriter.OpenMethod(new SymbolToken(-pseudoToken | 0x06000000));
+ }
+ rva = ilgen.WriteBody();
+ if (this.ModuleBuilder.symbolWriter != null)
+ {
+ this.ModuleBuilder.symbolWriter.CloseMethod();
+ }
+ ilgen = null;
+ }
+ else
+ {
+ rva = -1;
+ }
+ }
+
+ internal ModuleBuilder ModuleBuilder
+ {
+ get { return typeBuilder.ModuleBuilder; }
+ }
+
+ internal void WriteMethodDefRecord(int baseRVA, MetadataWriter mw, ref int paramList)
+ {
+ if (rva != -1)
+ {
+ mw.Write(rva + baseRVA);
+ }
+ else
+ {
+ mw.Write(0);
+ }
+ mw.Write((short)implFlags);
+ mw.Write((short)attributes);
+ mw.WriteStringIndex(nameIndex);
+ mw.WriteBlobIndex(signature);
+ mw.WriteParam(paramList);
+ if (parameters != null)
+ {
+ paramList += parameters.Count;
+ }
+ }
+
+ internal void WriteParamRecords(MetadataWriter mw)
+ {
+ if (parameters != null)
+ {
+ foreach (ParameterBuilder pb in parameters)
+ {
+ pb.WriteParamRecord(mw);
+ }
+ }
+ }
+
+ internal void FixupToken(int token, ref int parameterToken)
+ {
+ typeBuilder.ModuleBuilder.RegisterTokenFixup(this.pseudoToken, token);
+ if (parameters != null)
+ {
+ foreach (ParameterBuilder pb in parameters)
+ {
+ pb.FixupToken(parameterToken++);
+ }
+ }
+ }
+
+ internal bool MatchParameters(Type[] types)
+ {
+ if (types.Length == parameterTypes.Length)
+ {
+ for (int i = 0; i < types.Length; i++)
+ {
+ if (!types[i].Equals(parameterTypes[i]))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/refemit/ModuleBuilder.cs b/refemit/ModuleBuilder.cs
new file mode 100644
index 00000000..4ad3cff8
--- /dev/null
+++ b/refemit/ModuleBuilder.cs
@@ -0,0 +1,911 @@
+/*
+ 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.Reflection;
+using System.Collections.Generic;
+using System.IO;
+using System.Diagnostics;
+using System.Diagnostics.SymbolStore;
+using IKVM.Reflection.Emit.Impl;
+using IKVM.Reflection.Emit.Writer;
+using System.Security.Cryptography;
+
+namespace IKVM.Reflection.Emit
+{
+ public sealed class ModuleBuilder : ITypeOwner
+ {
+ private readonly AssemblyBuilder asm;
+ internal readonly string moduleName;
+ internal readonly string fileName;
+ internal readonly ISymbolWriter symbolWriter;
+ private readonly TypeBuilder moduleType;
+ private readonly List<TypeBuilder> types = new List<TypeBuilder>();
+ private readonly Dictionary<Type, TypeToken> typeTokens = new Dictionary<Type, TypeToken>();
+ 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);
+ private readonly Dictionary<MemberInfo, int> importedMembers = new Dictionary<MemberInfo, int>();
+ private readonly Dictionary<AssemblyName, int> referencedAssemblies = new Dictionary<AssemblyName, int>(new AssemblyNameEqualityComparer());
+ private readonly Dictionary<Type, Type> canonicalizedTypes = new Dictionary<Type, Type>();
+ private readonly Dictionary<MethodInfo, MethodInfo> canonicalizedGenericMethods = new Dictionary<MethodInfo, MethodInfo>(new GenericMethodComparer());
+ private int nextPseudoToken = -1;
+ private readonly List<int> resolvedTokens = new List<int>();
+ internal readonly TableHeap Tables;
+ 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 bool bigStrings;
+ internal bool bigGuids;
+ internal bool bigBlobs;
+ internal bool bigField;
+ internal bool bigMethodDef;
+ internal bool bigParam;
+ internal bool bigTypeDef;
+ internal bool bigProperty;
+ internal bool bigGenericParam;
+ internal bool bigModuleRef;
+ internal bool bigResolutionScope;
+ internal bool bigMemberRefParent;
+ internal bool bigMethodDefOrRef;
+ internal bool bigTypeDefOrRef;
+ internal bool bigHasCustomAttribute;
+ internal bool bigCustomAttributeType;
+ internal bool bigHasConstant;
+ internal bool bigHasSemantics;
+ internal bool bigImplementation;
+ internal bool bigTypeOrMethodDef;
+ internal bool bigHasDeclSecurity;
+ internal bool bigMemberForwarded;
+ internal bool bigHasFieldMarshal;
+
+ // FXBUG AssemblyName doesn't have a working Equals (sigh)
+ private sealed class AssemblyNameEqualityComparer : IEqualityComparer<AssemblyName>
+ {
+ public bool Equals(AssemblyName x, AssemblyName y)
+ {
+ return x.FullName == y.FullName;
+ }
+
+ public int GetHashCode(AssemblyName obj)
+ {
+ return obj.FullName.GetHashCode();
+ }
+ }
+
+ // this class makes multiple instances of a generic method compare as equal,
+ // however, it does not ensure that the underlying method definition is canonicalized
+ private sealed class GenericMethodComparer : IEqualityComparer<MethodInfo>
+ {
+ public bool Equals(MethodInfo x, MethodInfo y)
+ {
+ if (x.GetGenericMethodDefinition() == y.GetGenericMethodDefinition())
+ {
+ Type[] xArgs = x.GetGenericArguments();
+ Type[] yArgs = y.GetGenericArguments();
+ for (int i = 0; i < xArgs.Length; i++)
+ {
+ if (xArgs[i] != yArgs[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public int GetHashCode(MethodInfo obj)
+ {
+ int hash = obj.GetGenericMethodDefinition().GetHashCode();
+ foreach (Type arg in obj.GetGenericArguments())
+ {
+ hash *= 37;
+ hash ^= arg.GetHashCode();
+ }
+ return hash;
+ }
+ }
+
+ internal ModuleBuilder(AssemblyBuilder asm, string moduleName, string fileName, bool emitSymbolInfo)
+ {
+ this.Tables = new TableHeap(this);
+ this.asm = asm;
+ this.moduleName = moduleName;
+ this.fileName = fileName;
+ if (emitSymbolInfo)
+ {
+ symbolWriter = PdbSupport.CreateSymbolWriter(Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName) + ".pdb"));
+ }
+ // <Module> must be the first record in the TypeDef table
+ moduleType = new TypeBuilder(this, "<Module>", null, 0);
+ types.Add(moduleType);
+ }
+
+ 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 GetTypeCount()
+ {
+ return types.Count;
+ }
+
+ internal int AllocPseudoToken()
+ {
+ return nextPseudoToken--;
+ }
+
+ public TypeBuilder DefineType(string name)
+ {
+ return DefineType(name, TypeAttributes.Class);
+ }
+
+ public TypeBuilder DefineType(string name, TypeAttributes attribs)
+ {
+ return DefineType(name, attribs, null);
+ }
+
+ public TypeBuilder DefineType(string name, TypeAttributes attribs, Type baseType)
+ {
+ return DefineType(name, attribs, baseType, PackingSize.Unspecified, 0);
+ }
+
+ public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, PackingSize packingSize, int typesize)
+ {
+ if (parent == null && (attr & TypeAttributes.Interface) == 0)
+ {
+ parent = typeof(object);
+ }
+ TypeBuilder typeBuilder = new TypeBuilder(this, name, parent, attr);
+ PostDefineType(typeBuilder, packingSize, typesize);
+ return typeBuilder;
+ }
+
+ internal TypeBuilder DefineNestedTypeHelper(TypeBuilder enclosingType, string name, TypeAttributes attr, Type parent, PackingSize packingSize, int typesize)
+ {
+ if (parent == null && (attr & TypeAttributes.Interface) == 0)
+ {
+ parent = typeof(object);
+ }
+ TypeBuilder typeBuilder = new TypeBuilder(enclosingType, name, parent, attr);
+ PostDefineType(typeBuilder, packingSize, typesize);
+ if (enclosingType != null)
+ {
+ TableHeap.NestedClassTable.Record rec = new TableHeap.NestedClassTable.Record();
+ rec.NestedClass = typeBuilder.GetToken().Token;
+ rec.EnclosingClass = enclosingType.GetToken().Token;
+ this.Tables.NestedClass.AddRecord(rec);
+ }
+ return typeBuilder;
+ }
+
+ private void PostDefineType(TypeBuilder typeBuilder, PackingSize packingSize, int typesize)
+ {
+ types.Add(typeBuilder);
+ fullNameToType.Add(typeBuilder.FullName, typeBuilder);
+ if (packingSize != PackingSize.Unspecified || typesize != 0)
+ {
+ TableHeap.ClassLayoutTable.Record rec = new TableHeap.ClassLayoutTable.Record();
+ rec.PackingSize = (short)packingSize;
+ rec.ClassSize = typesize;
+ rec.Parent = typeBuilder.GetToken().Token;
+ this.Tables.ClassLayout.AddRecord(rec);
+ }
+ }
+
+ public FieldBuilder DefineInitializedData(string name, byte[] data, FieldAttributes attributes)
+ {
+ Type fieldType = GetType("$ArrayType$" + data.Length);
+ if (fieldType == null)
+ {
+ fieldType = DefineType("$ArrayType$" + data.Length, TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.ExplicitLayout, typeof(ValueType), PackingSize.Size1, data.Length);
+ }
+ FieldBuilder fb = moduleType.DefineField(name, fieldType, attributes | FieldAttributes.Static | FieldAttributes.HasFieldRVA);
+ TableHeap.FieldRVATable.Record rec = new TableHeap.FieldRVATable.Record();
+ rec.RVA = initializedData.Position;
+ rec.Field = fb.MetadataToken;
+ this.Tables.FieldRVA.AddRecord(rec);
+ initializedData.Write(data);
+ return fb;
+ }
+
+ public MethodBuilder DefineGlobalMethod(string name, MethodAttributes attributes, Type returnType, Type[] parameterTypes)
+ {
+ return moduleType.DefineMethod(name, attributes, returnType, parameterTypes);
+ }
+
+ public void CreateGlobalFunctions()
+ {
+ moduleType.CreateType();
+ }
+
+ public TypeToken GetTypeToken(Type type)
+ {
+ TypeToken token;
+ if (!typeTokens.TryGetValue(type, out token))
+ {
+ token = ImportType(type);
+ typeTokens.Add(type, token);
+ }
+ return token;
+ }
+
+ public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+ {
+ SetCustomAttribute(0x00000001, customBuilder);
+ }
+
+ internal void SetCustomAttribute(int token, CustomAttributeBuilder customBuilder)
+ {
+ if (customBuilder.IsPseudoCustomAttribute)
+ {
+ throw new NotImplementedException("Pseudo custom attribute " + customBuilder.Constructor.DeclaringType.FullName + " is not implemented");
+ }
+ TableHeap.CustomAttributeTable.Record rec = new TableHeap.CustomAttributeTable.Record();
+ rec.Parent = token;
+ rec.Type = this.GetConstructorToken(customBuilder.Constructor).Token;
+ rec.Value = customBuilder.WriteBlob(this);
+ this.Tables.CustomAttribute.AddRecord(rec);
+ }
+
+ public void DefineManifestResource(string name, Stream stream, ResourceAttributes attribute)
+ {
+ TableHeap.ManifestResourceTable.Record rec = new TableHeap.ManifestResourceTable.Record();
+ rec.Offset = manifestResources.Position;
+ rec.Flags = (int)attribute;
+ rec.Name = this.Strings.Add(name);
+ rec.Implementation = 0;
+ this.Tables.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 AssemblyBuilder Assembly
+ {
+ get { return asm; }
+ }
+
+ public Type GetType(string className)
+ {
+ return GetType(className, false, false);
+ }
+
+ public Type GetType(string className, bool throwOnError, bool ignoreCase)
+ {
+ if (ignoreCase)
+ {
+ throw new NotImplementedException();
+ }
+ TypeBuilder type;
+ if (!fullNameToType.TryGetValue(className, out type) && throwOnError)
+ {
+ throw new TypeLoadException();
+ }
+ return type;
+ }
+
+ public ISymbolDocumentWriter DefineDocument(string url, Guid language, Guid languageVendor, Guid documentType)
+ {
+ return symbolWriter.DefineDocument(url, language, languageVendor, documentType);
+ }
+
+ public FieldToken GetFieldToken(FieldInfo field)
+ {
+ FieldBuilder fb = field as FieldBuilder;
+ if (fb != null)
+ {
+ if (fb.ModuleBuilder == this)
+ {
+ return new FieldToken(fb.MetadataToken);
+ }
+ else
+ {
+ int token;
+ if (!importedMembers.TryGetValue(field, out token))
+ {
+ token = fb.ImportTo(this);
+ importedMembers.Add(field, token);
+ }
+ return new FieldToken(token);
+ }
+ }
+ 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));
+ }
+ }
+
+ public ConstructorToken GetConstructorToken(ConstructorInfo constructor)
+ {
+ ConstructorBuilder cb = constructor as ConstructorBuilder;
+ if (cb != null)
+ {
+ if (cb.ModuleBuilder == this)
+ {
+ return new ConstructorToken(cb.MetadataToken);
+ }
+ else
+ {
+ throw new NotImplementedException();
+ }
+ }
+ else
+ {
+ return new ConstructorToken(ImportMember(constructor));
+ }
+ }
+
+ private int ImportMember(MemberInfo member)
+ {
+ int token;
+ if (!importedMembers.TryGetValue(member, out token))
+ {
+ if (member.DeclaringType == null)
+ {
+ throw new NotImplementedException();
+ }
+ if (member.ReflectedType != member.DeclaringType)
+ {
+ // look up the canonicalized member
+ token = ImportMember(member.Module.ResolveMember(member.MetadataToken));
+ importedMembers.Add(member, token);
+ return token;
+ }
+
+ MethodInfo method = member as MethodInfo;
+ if (method != null)
+ {
+ if (method.IsGenericMethod && !method.IsGenericMethodDefinition)
+ {
+ // FXBUG generic MethodInfos don't have a working Equals/GetHashCode,
+ // so we have to canonicalize them manually
+ // (we don't have to recursively call ImportMember here (like above), because the first method we encounter will always become the canonical one)
+ if (importedMembers.TryGetValue(CanonicalizeGenericMethod(method), out token))
+ {
+ importedMembers.Add(member, token);
+ return token;
+ }
+
+ const byte GENERICINST = 0x0A;
+ ByteBuffer spec = new ByteBuffer(10);
+ spec.Write(GENERICINST);
+ Type[] args = method.GetGenericArguments();
+ spec.WriteCompressedInt(args.Length);
+ foreach (Type arg in args)
+ {
+ SignatureHelper.WriteType(this, spec, arg);
+ }
+ TableHeap.MethodSpecTable.Record rec = new TableHeap.MethodSpecTable.Record();
+ rec.Method = GetMethodToken(method.GetGenericMethodDefinition()).Token;
+ rec.Instantiation = this.Blobs.Add(spec);
+ token = 0x2B000000 | this.Tables.MethodSpec.AddRecord(rec);
+ }
+ else
+ {
+ token = ImportMethodOrConstructorRef(method);
+ }
+ }
+ else
+ {
+ ConstructorInfo constructor = member as ConstructorInfo;
+ if (constructor != null)
+ {
+ token = ImportMethodOrConstructorRef(constructor);
+ }
+ else
+ {
+ FieldInfo field = member as FieldInfo;
+ if (field != null)
+ {
+ token = ImportField(field.DeclaringType, field.Name, field.FieldType, field.GetOptionalCustomModifiers(), field.GetRequiredCustomModifiers());
+ }
+ else
+ {
+ throw new NotImplementedException();
+ }
+ }
+ }
+ importedMembers.Add(member, token);
+ }
+ return token;
+ }
+
+ private int ImportMethodOrConstructorRef(MethodBase method)
+ {
+ if (method.DeclaringType == null)
+ {
+ throw new NotImplementedException();
+ }
+ TableHeap.MemberRefTable.Record rec = new TableHeap.MemberRefTable.Record();
+ rec.Class = GetTypeToken(method.DeclaringType).Token;
+ rec.Name = this.Strings.Add(method.Name);
+ ByteBuffer bb = new ByteBuffer(16);
+ SignatureHelper.WriteMethodSig(this, bb, method);
+ rec.Signature = this.Blobs.Add(bb);
+ return 0x0A000000 | this.Tables.MemberRef.AddRecord(rec);
+ }
+
+ internal int ImportField(Type declaringType, string name, Type fieldType, Type[] optionalCustomModifiers, Type[] requiredCustomModifiers)
+ {
+ if (declaringType == null)
+ {
+ throw new NotImplementedException();
+ }
+ TableHeap.MemberRefTable.Record rec = new TableHeap.MemberRefTable.Record();
+ rec.Class = GetTypeToken(declaringType).Token;
+ rec.Name = this.Strings.Add(name);
+ ByteBuffer bb = new ByteBuffer(16);
+ bb.Write(SignatureHelper.FIELD);
+ SignatureHelper.WriteCustomModifiers(this, bb, SignatureHelper.ELEMENT_TYPE_CMOD_OPT, optionalCustomModifiers);
+ SignatureHelper.WriteCustomModifiers(this, bb, SignatureHelper.ELEMENT_TYPE_CMOD_REQD, requiredCustomModifiers);
+ SignatureHelper.WriteType(this, bb, fieldType);
+ rec.Signature = this.Blobs.Add(bb);
+ return 0x0A000000 | this.Tables.MemberRef.AddRecord(rec);
+ }
+
+ private TypeToken ImportType(Type type)
+ {
+ if (type.IsPointer || type.IsByRef)
+ {
+ throw new NotImplementedException();
+ }
+ TypeBase tb = type as TypeBase;
+ if (tb != null)
+ {
+ if (tb.ModuleBuilder == this)
+ {
+ return tb.GetToken();
+ }
+ else if (tb.ModuleBuilder.Assembly != this.Assembly)
+ {
+ return ImportTypeRef(tb.ModuleBuilder.Assembly.GetName(), type);
+ }
+ else
+ {
+ throw new NotImplementedException();
+ }
+ }
+ else if (type.IsArray || (type.IsGenericType && !type.IsGenericTypeDefinition))
+ {
+ ByteBuffer spec = new ByteBuffer(5);
+ SignatureHelper.WriteType(this, spec, type);
+ return new TypeToken(0x1B000000 | this.Tables.TypeSpec.AddRecord(this.Blobs.Add(spec)));
+ }
+ else
+ {
+ return ImportTypeRef(type.Assembly.GetName(), type);
+ }
+ }
+
+ private TypeToken ImportTypeRef(AssemblyName asm, Type type)
+ {
+ TableHeap.TypeRefTable.Record rec = new TableHeap.TypeRefTable.Record();
+ if (type.IsNested)
+ {
+ rec.ResolutionScope = GetTypeToken(type.DeclaringType).Token;
+ rec.TypeName = this.Strings.Add(type.Name);
+ rec.TypeNameSpace = 0;
+ }
+ else
+ {
+ rec.ResolutionScope = ImportAssemblyRef(asm);
+ rec.TypeName = this.Strings.Add(type.Name);
+ string ns = type.Namespace;
+ rec.TypeNameSpace = ns == null ? 0 : this.Strings.Add(ns);
+ }
+ return new TypeToken(0x01000000 | this.Tables.TypeRef.AddRecord(rec));
+ }
+
+ private int ImportAssemblyRef(AssemblyName asm)
+ {
+ int token;
+ if (!referencedAssemblies.TryGetValue(asm, out token))
+ {
+ TableHeap.AssemblyRefTable.Record rec = new TableHeap.AssemblyRefTable.Record();
+ Version ver = asm.Version ?? new Version(0, 0, 0, 0);
+ rec.MajorVersion = (short)ver.Major;
+ rec.MinorVersion = (short)ver.Minor;
+ rec.BuildNumber = (short)ver.Build;
+ rec.RevisionNumber = (short)ver.Revision;
+ rec.Flags = 0;
+ byte[] pubkey = asm.GetPublicKeyToken();
+ if (pubkey == null && asm.KeyPair != null)
+ {
+ pubkey = GetPublicKeyToken(asm.KeyPair);
+ }
+ if (pubkey != null)
+ {
+ rec.PublicKeyOrToken = this.Blobs.Add(ByteBuffer.Wrap(pubkey));
+ }
+ rec.Name = this.Strings.Add(asm.Name);
+ rec.Culture = 0;
+ rec.HashValue = 0;
+ token = 0x23000000 | this.Tables.AssemblyRef.AddRecord(rec);
+ referencedAssemblies.Add(asm, token);
+ }
+ return token;
+ }
+
+ private byte[] GetPublicKeyToken(StrongNameKeyPair strongNameKeyPair)
+ {
+ SHA1Managed sha1 = new SHA1Managed();
+ byte[] hash = sha1.ComputeHash(strongNameKeyPair.PublicKey);
+ byte[] token = new byte[8];
+ Buffer.BlockCopy(hash, hash.Length - 8, token, 0, 8);
+ Array.Reverse(token);
+ return token;
+ }
+
+ 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);
+ PdbSupport.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));
+ }
+ }
+
+ internal int MetadataLength
+ {
+ get
+ {
+ return (Blobs.IsEmpty ? 92 : 108 + 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("v2.0.50727");
+ mw.Write(version.Length); // Length
+ mw.Write(version);
+ mw.Write((ushort)0); // Flags
+ int offset;
+ // #Blob is the only optional heap
+ if (Blobs.IsEmpty)
+ {
+ mw.Write((ushort)4); // Streams
+ offset = 92;
+ }
+ else
+ {
+ mw.Write((ushort)5); // Streams
+ offset = 108;
+ }
+
+ // 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 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 void Freeze()
+ {
+ Strings.Freeze(this);
+ UserStrings.Freeze(this);
+ Guids.Freeze(this);
+ Blobs.Freeze(this);
+ this.bigStrings = Strings.IsBig;
+ this.bigGuids = Guids.IsBig;
+ this.bigBlobs = Blobs.IsBig;
+ this.bigField = Tables.Field.IsBig;
+ this.bigMethodDef = Tables.MethodDef.IsBig;
+ this.bigParam = Tables.Param.IsBig;
+ this.bigTypeDef = Tables.TypeDef.IsBig;
+ this.bigProperty = Tables.Property.IsBig;
+ this.bigGenericParam = Tables.GenericParam.IsBig;
+ this.bigModuleRef = Tables.ModuleRef.IsBig;
+ this.bigResolutionScope = IsBig(2, Tables.Module, Tables.ModuleRef, Tables.AssemblyRef, Tables.TypeRef);
+ this.bigMemberRefParent = IsBig(3, Tables.TypeDef, Tables.TypeRef, Tables.ModuleRef, Tables.MethodDef, Tables.TypeSpec);
+ this.bigMethodDefOrRef = IsBig(1, Tables.MethodDef, Tables.MemberRef);
+ this.bigTypeDefOrRef = IsBig(2, Tables.TypeDef, Tables.TypeRef);
+ this.bigHasCustomAttribute = IsBig(5, Tables.MethodDef, Tables.Field, Tables.TypeDef, Tables.Param, Tables.Module, Tables.Property, Tables.Assembly);
+ this.bigCustomAttributeType = IsBig(3, Tables.MethodDef, Tables.MemberRef);
+ this.bigHasConstant = IsBig(2, Tables.Field, Tables.Param, Tables.Property);
+ this.bigHasSemantics = IsBig(1, /*Tables.Event,*/ Tables.Property);
+ this.bigImplementation = IsBig(2, Tables.File, Tables.AssemblyRef, Tables.ExportedType);
+ this.bigTypeOrMethodDef = IsBig(1, Tables.TypeDef, Tables.MethodDef);
+ this.bigHasDeclSecurity = IsBig(2, Tables.TypeDef, Tables.MethodDef, Tables.Assembly);
+ this.bigMemberForwarded = IsBig(1, Tables.Field, Tables.MethodDef);
+ this.bigHasFieldMarshal = IsBig(1, Tables.Field, Tables.Param);
+ Tables.Freeze(this);
+ }
+
+ private bool IsBig(int bitsUsed, params TableHeap.Table[] tables)
+ {
+ int limit = 1 << (16 - bitsUsed);
+ foreach (TableHeap.Table table in tables)
+ {
+ if (table.RowCount >= limit)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ internal Type CanonicalizeType(Type type)
+ {
+ Type canon;
+ if (!canonicalizedTypes.TryGetValue(type, out canon))
+ {
+ canon = type;
+ canonicalizedTypes.Add(canon, canon);
+ }
+ return canon;
+ }
+
+ private MethodInfo CanonicalizeGenericMethod(MethodInfo method)
+ {
+ MethodInfo canon;
+ if (!canonicalizedGenericMethods.TryGetValue(method, out canon))
+ {
+ canonicalizedGenericMethods.Add(method, method);
+ canon = method;
+ }
+ return canon;
+ }
+
+ internal void ExportTypes(int fileToken, ModuleBuilder manifestModule)
+ {
+ Dictionary<Type, int> declaringTypes = new Dictionary<Type, int>();
+ foreach (TypeBuilder type in types)
+ {
+ if (type != moduleType && IsVisible(type))
+ {
+ TableHeap.ExportedTypeTable.Record rec = new TableHeap.ExportedTypeTable.Record();
+ rec.Flags = (int)type.Attributes;
+ rec.TypeDefId = type.GetToken().Token & 0xFFFFFF;
+ rec.TypeName = manifestModule.Strings.Add(type.Name);
+ rec.TypeNamespace = manifestModule.Strings.Add(type.Namespace);
+ if (type.IsNested)
+ {
+ rec.Implementation = declaringTypes[type.DeclaringType];
+ }
+ else
+ {
+ rec.Implementation = fileToken;
+ }
+ int exportTypeToken = 0x27000000 | manifestModule.Tables.ExportedType.AddRecord(rec);
+ declaringTypes.Add(type, exportTypeToken);
+ }
+ }
+ }
+
+ internal static bool IsVisible(Type type)
+ {
+ return type.IsPublic || ((type.IsNestedFamily || type.IsNestedFamORAssem || type.IsNestedPublic) && IsVisible(type.DeclaringType));
+ }
+
+ internal void AddConstant(int parentToken, object defaultValue)
+ {
+ TableHeap.ConstantTable.Record rec = new TableHeap.ConstantTable.Record();
+ rec.Parent = parentToken;
+ ByteBuffer val = new ByteBuffer(16);
+ if (defaultValue == null)
+ {
+ rec.Type = SignatureHelper.ELEMENT_TYPE_CLASS;
+ }
+ else if (defaultValue is bool)
+ {
+ rec.Type = SignatureHelper.ELEMENT_TYPE_BOOLEAN;
+ val.Write((bool)defaultValue ? (byte)1 : (byte)0);
+ }
+ else if (defaultValue is char)
+ {
+ rec.Type = SignatureHelper.ELEMENT_TYPE_CHAR;
+ val.Write((char)defaultValue);
+ }
+ else if (defaultValue is byte)
+ {
+ rec.Type = SignatureHelper.ELEMENT_TYPE_U1;
+ val.Write((byte)defaultValue);
+ }
+ else if (defaultValue is short)
+ {
+ rec.Type = SignatureHelper.ELEMENT_TYPE_I2;
+ val.Write((short)defaultValue);
+ }
+ else if (defaultValue is int)
+ {
+ rec.Type = SignatureHelper.ELEMENT_TYPE_I4;
+ val.Write((int)defaultValue);
+ }
+ else if (defaultValue is long)
+ {
+ rec.Type = SignatureHelper.ELEMENT_TYPE_I8;
+ val.Write((long)defaultValue);
+ }
+ else if (defaultValue is float)
+ {
+ rec.Type = SignatureHelper.ELEMENT_TYPE_R4;
+ val.Write((float)defaultValue);
+ }
+ else if (defaultValue is double)
+ {
+ rec.Type = SignatureHelper.ELEMENT_TYPE_R8;
+ val.Write((double)defaultValue);
+ }
+ else if (defaultValue is string)
+ {
+ rec.Type = SignatureHelper.ELEMENT_TYPE_STRING;
+ foreach (char c in (string)defaultValue)
+ {
+ val.Write(c);
+ }
+ }
+ else
+ {
+ throw new NotImplementedException(defaultValue.GetType().FullName);
+ }
+ rec.Value = this.Blobs.Add(val);
+ this.Tables.Constant.AddRecord(rec);
+ }
+
+ internal bool IsModuleType(TypeBuilder type)
+ {
+ return type == moduleType;
+ }
+
+ ModuleBuilder ITypeOwner.ModuleBuilder
+ {
+ get { return this; }
+ }
+ }
+}
diff --git a/refemit/OpCodes.cs b/refemit/OpCodes.cs
new file mode 100644
index 00000000..8f428e57
--- /dev/null
+++ b/refemit/OpCodes.cs
@@ -0,0 +1,308 @@
+/*
+ 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.Diagnostics;
+
+namespace IKVM.Reflection.Emit
+{
+ public struct OpCode
+ {
+ private const int OperandTypeCount = 19;
+ private const int FlowControlCount = 9;
+ private const int StackDiffCount = 5;
+ private readonly short value;
+ private readonly short info;
+
+ internal OpCode(short value, OperandType operandType, FlowControl flowControl, short stackDiff)
+ {
+ Debug.Assert(operandType >= 0 && (int)operandType < OperandTypeCount);
+ Debug.Assert(flowControl >= 0 && (int)flowControl < FlowControlCount);
+ Debug.Assert(stackDiff >= -3 && stackDiff <= 1);
+
+ this.value = value;
+ this.info = (short)(operandType
+ + OperandTypeCount * (short)flowControl
+ + OperandTypeCount * FlowControlCount * (stackDiff + 3));
+
+ Debug.Assert(this.OperandType == operandType);
+ Debug.Assert(this.FlowControl == flowControl);
+ Debug.Assert(this.StackDiff == stackDiff);
+ }
+
+ public short Value
+ {
+ get { return value; }
+ }
+
+ public int Size
+ {
+ get { return value < 0 ? 2 : 1; }
+ }
+
+ public OperandType OperandType
+ {
+ get { return (OperandType)(info % OperandTypeCount); }
+ }
+
+ public FlowControl FlowControl
+ {
+ get { return (FlowControl)((info / OperandTypeCount) % FlowControlCount); }
+ }
+
+ internal short StackDiff
+ {
+ get { return (short)(((info / (OperandTypeCount * FlowControlCount)) % StackDiffCount) - 3); }
+ }
+ }
+
+ public class OpCodes
+ {
+ public static readonly OpCode Nop = new OpCode(0, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Break = new OpCode(1, OperandType.InlineNone, FlowControl.Break, 0);
+ public static readonly OpCode Ldarg_0 = new OpCode(2, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldarg_1 = new OpCode(3, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldarg_2 = new OpCode(4, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldarg_3 = new OpCode(5, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldloc_0 = new OpCode(6, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldloc_1 = new OpCode(7, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldloc_2 = new OpCode(8, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldloc_3 = new OpCode(9, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Stloc_0 = new OpCode(10, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Stloc_1 = new OpCode(11, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Stloc_2 = new OpCode(12, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Stloc_3 = new OpCode(13, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Ldarg_S = new OpCode(14, OperandType.ShortInlineVar, FlowControl.Next, 1);
+ public static readonly OpCode Ldarga_S = new OpCode(15, OperandType.ShortInlineVar, FlowControl.Next, 1);
+ public static readonly OpCode Starg_S = new OpCode(16, OperandType.ShortInlineVar, FlowControl.Next, -1);
+ public static readonly OpCode Ldloc_S = new OpCode(17, OperandType.ShortInlineVar, FlowControl.Next, 1);
+ public static readonly OpCode Ldloca_S = new OpCode(18, OperandType.ShortInlineVar, FlowControl.Next, 1);
+ public static readonly OpCode Stloc_S = new OpCode(19, OperandType.ShortInlineVar, FlowControl.Next, -1);
+ public static readonly OpCode Ldnull = new OpCode(20, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I4_M1 = new OpCode(21, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I4_0 = new OpCode(22, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I4_1 = new OpCode(23, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I4_2 = new OpCode(24, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I4_3 = new OpCode(25, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I4_4 = new OpCode(26, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I4_5 = new OpCode(27, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I4_6 = new OpCode(28, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I4_7 = new OpCode(29, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I4_8 = new OpCode(30, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I4_S = new OpCode(31, OperandType.ShortInlineI, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I4 = new OpCode(32, OperandType.InlineI, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_I8 = new OpCode(33, OperandType.InlineI8, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_R4 = new OpCode(34, OperandType.ShortInlineR, FlowControl.Next, 1);
+ public static readonly OpCode Ldc_R8 = new OpCode(35, OperandType.InlineR, FlowControl.Next, 1);
+ public static readonly OpCode Dup = new OpCode(37, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Pop = new OpCode(38, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Jmp = new OpCode(39, OperandType.InlineMethod, FlowControl.Call, 0);
+ public static readonly OpCode Call = new OpCode(40, OperandType.InlineMethod, FlowControl.Call, 0);
+ public static readonly OpCode Calli = new OpCode(41, OperandType.InlineSig, FlowControl.Call, 0);
+ public static readonly OpCode Ret = new OpCode(42, OperandType.InlineNone, FlowControl.Return, 0);
+ public static readonly OpCode Br_S = new OpCode(43, OperandType.ShortInlineBrTarget, FlowControl.Branch, 0);
+ public static readonly OpCode Brfalse_S = new OpCode(44, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -1);
+ public static readonly OpCode Brtrue_S = new OpCode(45, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -1);
+ public static readonly OpCode Beq_S = new OpCode(46, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Bge_S = new OpCode(47, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Bgt_S = new OpCode(48, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Ble_S = new OpCode(49, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Blt_S = new OpCode(50, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Bne_Un_S = new OpCode(51, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Bge_Un_S = new OpCode(52, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Bgt_Un_S = new OpCode(53, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Ble_Un_S = new OpCode(54, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Blt_Un_S = new OpCode(55, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Br = new OpCode(56, OperandType.InlineBrTarget, FlowControl.Branch, 0);
+ public static readonly OpCode Brfalse = new OpCode(57, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -1);
+ public static readonly OpCode Brtrue = new OpCode(58, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -1);
+ public static readonly OpCode Beq = new OpCode(59, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Bge = new OpCode(60, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Bgt = new OpCode(61, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Ble = new OpCode(62, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Blt = new OpCode(63, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Bne_Un = new OpCode(64, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Bge_Un = new OpCode(65, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Bgt_Un = new OpCode(66, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Ble_Un = new OpCode(67, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Blt_Un = new OpCode(68, OperandType.InlineBrTarget, FlowControl.Cond_Branch, -2);
+ public static readonly OpCode Switch = new OpCode(69, OperandType.InlineSwitch, FlowControl.Cond_Branch, -1);
+ public static readonly OpCode Ldind_I1 = new OpCode(70, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Ldind_U1 = new OpCode(71, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Ldind_I2 = new OpCode(72, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Ldind_U2 = new OpCode(73, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Ldind_I4 = new OpCode(74, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Ldind_U4 = new OpCode(75, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Ldind_I8 = new OpCode(76, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Ldind_I = new OpCode(77, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Ldind_R4 = new OpCode(78, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Ldind_R8 = new OpCode(79, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Ldind_Ref = new OpCode(80, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Stind_Ref = new OpCode(81, OperandType.InlineNone, FlowControl.Next, -2);
+ public static readonly OpCode Stind_I1 = new OpCode(82, OperandType.InlineNone, FlowControl.Next, -2);
+ public static readonly OpCode Stind_I2 = new OpCode(83, OperandType.InlineNone, FlowControl.Next, -2);
+ public static readonly OpCode Stind_I4 = new OpCode(84, OperandType.InlineNone, FlowControl.Next, -2);
+ public static readonly OpCode Stind_I8 = new OpCode(85, OperandType.InlineNone, FlowControl.Next, -2);
+ public static readonly OpCode Stind_R4 = new OpCode(86, OperandType.InlineNone, FlowControl.Next, -2);
+ public static readonly OpCode Stind_R8 = new OpCode(87, OperandType.InlineNone, FlowControl.Next, -2);
+ public static readonly OpCode Add = new OpCode(88, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Sub = new OpCode(89, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Mul = new OpCode(90, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Div = new OpCode(91, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Div_Un = new OpCode(92, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Rem = new OpCode(93, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Rem_Un = new OpCode(94, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode And = new OpCode(95, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Or = new OpCode(96, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Xor = new OpCode(97, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Shl = new OpCode(98, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Shr = new OpCode(99, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Shr_Un = new OpCode(100, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Neg = new OpCode(101, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Not = new OpCode(102, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_I1 = new OpCode(103, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_I2 = new OpCode(104, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_I4 = new OpCode(105, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_I8 = new OpCode(106, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_R4 = new OpCode(107, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_R8 = new OpCode(108, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_U4 = new OpCode(109, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_U8 = new OpCode(110, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Callvirt = new OpCode(111, OperandType.InlineMethod, FlowControl.Call, 0);
+ public static readonly OpCode Cpobj = new OpCode(112, OperandType.InlineType, FlowControl.Next, -2);
+ public static readonly OpCode Ldobj = new OpCode(113, OperandType.InlineType, FlowControl.Next, 0);
+ public static readonly OpCode Ldstr = new OpCode(114, OperandType.InlineString, FlowControl.Next, 1);
+ public static readonly OpCode Newobj = new OpCode(115, OperandType.InlineMethod, FlowControl.Call, 1);
+ public static readonly OpCode Castclass = new OpCode(116, OperandType.InlineType, FlowControl.Next, 0);
+ public static readonly OpCode Isinst = new OpCode(117, OperandType.InlineType, FlowControl.Next, 0);
+ public static readonly OpCode Conv_R_Un = new OpCode(118, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Unbox = new OpCode(121, OperandType.InlineType, FlowControl.Next, 0);
+ public static readonly OpCode Throw = new OpCode(122, OperandType.InlineNone, FlowControl.Throw, -1);
+ public static readonly OpCode Ldfld = new OpCode(123, OperandType.InlineField, FlowControl.Next, 0);
+ public static readonly OpCode Ldflda = new OpCode(124, OperandType.InlineField, FlowControl.Next, 0);
+ public static readonly OpCode Stfld = new OpCode(125, OperandType.InlineField, FlowControl.Next, -2);
+ public static readonly OpCode Ldsfld = new OpCode(126, OperandType.InlineField, FlowControl.Next, 1);
+ public static readonly OpCode Ldsflda = new OpCode(127, OperandType.InlineField, FlowControl.Next, 1);
+ public static readonly OpCode Stsfld = new OpCode(128, OperandType.InlineField, FlowControl.Next, -1);
+ public static readonly OpCode Stobj = new OpCode(129, OperandType.InlineType, FlowControl.Next, -2);
+ public static readonly OpCode Conv_Ovf_I1_Un = new OpCode(130, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_I2_Un = new OpCode(131, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_I4_Un = new OpCode(132, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_I8_Un = new OpCode(133, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_U1_Un = new OpCode(134, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_U2_Un = new OpCode(135, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_U4_Un = new OpCode(136, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_U8_Un = new OpCode(137, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_I_Un = new OpCode(138, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_U_Un = new OpCode(139, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Box = new OpCode(140, OperandType.InlineType, FlowControl.Next, 0);
+ public static readonly OpCode Newarr = new OpCode(141, OperandType.InlineType, FlowControl.Next, 0);
+ public static readonly OpCode Ldlen = new OpCode(142, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Ldelema = new OpCode(143, OperandType.InlineType, FlowControl.Next, -1);
+ public static readonly OpCode Ldelem_I1 = new OpCode(144, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Ldelem_U1 = new OpCode(145, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Ldelem_I2 = new OpCode(146, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Ldelem_U2 = new OpCode(147, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Ldelem_I4 = new OpCode(148, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Ldelem_U4 = new OpCode(149, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Ldelem_I8 = new OpCode(150, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Ldelem_I = new OpCode(151, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Ldelem_R4 = new OpCode(152, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Ldelem_R8 = new OpCode(153, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Ldelem_Ref = new OpCode(154, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Stelem_I = new OpCode(155, OperandType.InlineNone, FlowControl.Next, -3);
+ public static readonly OpCode Stelem_I1 = new OpCode(156, OperandType.InlineNone, FlowControl.Next, -3);
+ public static readonly OpCode Stelem_I2 = new OpCode(157, OperandType.InlineNone, FlowControl.Next, -3);
+ public static readonly OpCode Stelem_I4 = new OpCode(158, OperandType.InlineNone, FlowControl.Next, -3);
+ public static readonly OpCode Stelem_I8 = new OpCode(159, OperandType.InlineNone, FlowControl.Next, -3);
+ public static readonly OpCode Stelem_R4 = new OpCode(160, OperandType.InlineNone, FlowControl.Next, -3);
+ public static readonly OpCode Stelem_R8 = new OpCode(161, OperandType.InlineNone, FlowControl.Next, -3);
+ public static readonly OpCode Stelem_Ref = new OpCode(162, OperandType.InlineNone, FlowControl.Next, -3);
+ public static readonly OpCode Ldelem = new OpCode(163, OperandType.InlineType, FlowControl.Next, -1);
+ public static readonly OpCode Stelem = new OpCode(164, OperandType.InlineType, FlowControl.Next, -3);
+ public static readonly OpCode Unbox_Any = new OpCode(165, OperandType.InlineType, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_I1 = new OpCode(179, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_U1 = new OpCode(180, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_I2 = new OpCode(181, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_U2 = new OpCode(182, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_I4 = new OpCode(183, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_U4 = new OpCode(184, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_I8 = new OpCode(185, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_U8 = new OpCode(186, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Refanyval = new OpCode(194, OperandType.InlineType, FlowControl.Next, 0);
+ public static readonly OpCode Ckfinite = new OpCode(195, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Mkrefany = new OpCode(198, OperandType.InlineType, FlowControl.Next, 0);
+ public static readonly OpCode Ldtoken = new OpCode(208, OperandType.InlineTok, FlowControl.Next, 1);
+ public static readonly OpCode Conv_U2 = new OpCode(209, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_U1 = new OpCode(210, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_I = new OpCode(211, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_I = new OpCode(212, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Conv_Ovf_U = new OpCode(213, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Add_Ovf = new OpCode(214, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Add_Ovf_Un = new OpCode(215, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Mul_Ovf = new OpCode(216, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Mul_Ovf_Un = new OpCode(217, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Sub_Ovf = new OpCode(218, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Sub_Ovf_Un = new OpCode(219, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Endfinally = new OpCode(220, OperandType.InlineNone, FlowControl.Return, 0);
+ public static readonly OpCode Leave = new OpCode(221, OperandType.InlineBrTarget, FlowControl.Branch, 0);
+ public static readonly OpCode Leave_S = new OpCode(222, OperandType.ShortInlineBrTarget, FlowControl.Branch, 0);
+ public static readonly OpCode Stind_I = new OpCode(223, OperandType.InlineNone, FlowControl.Next, -2);
+ public static readonly OpCode Conv_U = new OpCode(224, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Prefix7 = new OpCode(248, OperandType.InlineNone, FlowControl.Meta, 0);
+ public static readonly OpCode Prefix6 = new OpCode(249, OperandType.InlineNone, FlowControl.Meta, 0);
+ public static readonly OpCode Prefix5 = new OpCode(250, OperandType.InlineNone, FlowControl.Meta, 0);
+ public static readonly OpCode Prefix4 = new OpCode(251, OperandType.InlineNone, FlowControl.Meta, 0);
+ public static readonly OpCode Prefix3 = new OpCode(252, OperandType.InlineNone, FlowControl.Meta, 0);
+ public static readonly OpCode Prefix2 = new OpCode(253, OperandType.InlineNone, FlowControl.Meta, 0);
+ public static readonly OpCode Prefix1 = new OpCode(254, OperandType.InlineNone, FlowControl.Meta, 0);
+ public static readonly OpCode Prefixref = new OpCode(255, OperandType.InlineNone, FlowControl.Meta, 0);
+ public static readonly OpCode Arglist = new OpCode(-512, OperandType.InlineNone, FlowControl.Next, 1);
+ public static readonly OpCode Ceq = new OpCode(-511, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Cgt = new OpCode(-510, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Cgt_Un = new OpCode(-509, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Clt = new OpCode(-508, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Clt_Un = new OpCode(-507, OperandType.InlineNone, FlowControl.Next, -1);
+ public static readonly OpCode Ldftn = new OpCode(-506, OperandType.InlineMethod, FlowControl.Next, 1);
+ public static readonly OpCode Ldvirtftn = new OpCode(-505, OperandType.InlineMethod, FlowControl.Next, 0);
+ public static readonly OpCode Ldarg = new OpCode(-503, OperandType.InlineVar, FlowControl.Next, 1);
+ public static readonly OpCode Ldarga = new OpCode(-502, OperandType.InlineVar, FlowControl.Next, 1);
+ public static readonly OpCode Starg = new OpCode(-501, OperandType.InlineVar, FlowControl.Next, -1);
+ public static readonly OpCode Ldloc = new OpCode(-500, OperandType.InlineVar, FlowControl.Next, 1);
+ public static readonly OpCode Ldloca = new OpCode(-499, OperandType.InlineVar, FlowControl.Next, 1);
+ public static readonly OpCode Stloc = new OpCode(-498, OperandType.InlineVar, FlowControl.Next, -1);
+ public static readonly OpCode Localloc = new OpCode(-497, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Endfilter = new OpCode(-495, OperandType.InlineNone, FlowControl.Return, -1);
+ public static readonly OpCode Unaligned = new OpCode(-494, OperandType.ShortInlineI, FlowControl.Meta, 0);
+ public static readonly OpCode Volatile = new OpCode(-493, OperandType.InlineNone, FlowControl.Meta, 0);
+ public static readonly OpCode Tailcall = new OpCode(-492, OperandType.InlineNone, FlowControl.Meta, 0);
+ public static readonly OpCode Initobj = new OpCode(-491, OperandType.InlineType, FlowControl.Next, -1);
+ public static readonly OpCode Constrained = new OpCode(-490, OperandType.InlineType, FlowControl.Meta, 0);
+ public static readonly OpCode Cpblk = new OpCode(-489, OperandType.InlineNone, FlowControl.Next, -3);
+ public static readonly OpCode Initblk = new OpCode(-488, OperandType.InlineNone, FlowControl.Next, -3);
+ public static readonly OpCode Rethrow = new OpCode(-486, OperandType.InlineNone, FlowControl.Throw, 0);
+ public static readonly OpCode Sizeof = new OpCode(-484, OperandType.InlineType, FlowControl.Next, 1);
+ public static readonly OpCode Refanytype = new OpCode(-483, OperandType.InlineNone, FlowControl.Next, 0);
+ public static readonly OpCode Readonly = new OpCode(-482, OperandType.InlineNone, FlowControl.Meta, 0);
+ }
+}
diff --git a/refemit/ParameterBuilder.cs b/refemit/ParameterBuilder.cs
new file mode 100644
index 00000000..995d2d74
--- /dev/null
+++ b/refemit/ParameterBuilder.cs
@@ -0,0 +1,107 @@
+/*
+ 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.Reflection;
+using IKVM.Reflection.Emit.Writer;
+using System.Runtime.InteropServices;
+
+namespace IKVM.Reflection.Emit
+{
+ public sealed class ParameterBuilder
+ {
+ private readonly ModuleBuilder moduleBuilder;
+ private short flags;
+ private readonly short sequence;
+ private readonly int name;
+ private int lazyPseudoToken;
+
+ internal ParameterBuilder(ModuleBuilder moduleBuilder, int sequence, ParameterAttributes attribs, string name)
+ {
+ this.moduleBuilder = moduleBuilder;
+ this.flags = (short)attribs;
+ this.sequence = (short)sequence;
+ this.name = name == null ? 0 : moduleBuilder.Strings.Add(name);
+ }
+
+ public void SetCustomAttribute(CustomAttributeBuilder customAttributeBuilder)
+ {
+ if (customAttributeBuilder.Constructor.DeclaringType == typeof(InAttribute))
+ {
+ flags |= (short)ParameterAttributes.In;
+ }
+ else if (customAttributeBuilder.Constructor.DeclaringType == typeof(OutAttribute))
+ {
+ flags |= (short)ParameterAttributes.Out;
+ }
+ else if (customAttributeBuilder.Constructor.DeclaringType == typeof(OptionalAttribute))
+ {
+ flags |= (short)ParameterAttributes.Optional;
+ }
+ else if (customAttributeBuilder.Constructor.DeclaringType == typeof(MarshalAsAttribute))
+ {
+ flags |= (short)ParameterAttributes.HasFieldMarshal;
+ if (lazyPseudoToken == 0)
+ {
+ lazyPseudoToken = moduleBuilder.AllocPseudoToken();
+ }
+ TableHeap.FieldMarshalTable.Record rec = new TableHeap.FieldMarshalTable.Record();
+ rec.Parent = lazyPseudoToken;
+ rec.NativeType = FieldBuilder.WriteMarshallingDescriptor(moduleBuilder, customAttributeBuilder);
+ moduleBuilder.Tables.FieldMarshal.AddRecord(rec);
+ }
+ else if (customAttributeBuilder.Constructor.DeclaringType == typeof(DefaultParameterValueAttribute))
+ {
+ flags |= (short)ParameterAttributes.HasDefault;
+ if (lazyPseudoToken == 0)
+ {
+ lazyPseudoToken = moduleBuilder.AllocPseudoToken();
+ }
+ moduleBuilder.AddConstant(lazyPseudoToken, customAttributeBuilder.GetConstructorArgument(0));
+ }
+ else
+ {
+ if (lazyPseudoToken == 0)
+ {
+ lazyPseudoToken = moduleBuilder.AllocPseudoToken();
+ }
+ moduleBuilder.SetCustomAttribute(lazyPseudoToken, customAttributeBuilder);
+ }
+ }
+
+ internal void WriteParamRecord(MetadataWriter mw)
+ {
+ mw.Write(flags);
+ mw.Write(sequence);
+ mw.WriteStringIndex(name);
+ }
+
+ internal void FixupToken(int parameterToken)
+ {
+ if (lazyPseudoToken != 0)
+ {
+ moduleBuilder.RegisterTokenFixup(lazyPseudoToken, parameterToken);
+ }
+ }
+ }
+}
diff --git a/refemit/Properties/AssemblyInfo.cs b/refemit/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..329573a6
--- /dev/null
+++ b/refemit/Properties/AssemblyInfo.cs
@@ -0,0 +1,28 @@
+/*
+ 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.Reflection;
+using System.Runtime.CompilerServices;
+
+[assembly: AssemblyTitle("IKVM.NET Reflection Emit")]
+[assembly: AssemblyDescription("Managed (partial) Reflection Emit implementation for use by ikvmc")]
diff --git a/refemit/PropertyBuilder.cs b/refemit/PropertyBuilder.cs
new file mode 100644
index 00000000..a79bff9c
--- /dev/null
+++ b/refemit/PropertyBuilder.cs
@@ -0,0 +1,202 @@
+/*
+ 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.Reflection;
+using IKVM.Reflection.Emit.Writer;
+
+namespace IKVM.Reflection.Emit
+{
+ public class PropertyBuilder : PropertyInfo
+ {
+ private readonly ModuleBuilder moduleBuilder;
+ private readonly int name;
+ private readonly PropertyAttributes attributes;
+ private readonly ByteBuffer signature;
+ private int getMethodToken;
+ private int setMethodToken;
+ private int pseudoToken;
+
+ internal PropertyBuilder(ModuleBuilder moduleBuilder, string name, PropertyAttributes attributes, Type returnType, Type[] parameterTypes)
+ {
+ this.moduleBuilder = moduleBuilder;
+ this.name = moduleBuilder.Strings.Add(name);
+ this.attributes = attributes;
+ signature = new ByteBuffer(16);
+ // later on we'll patch this byte, if it turns out that it is an instance property
+ signature.Write(SignatureHelper.PROPERTY);
+ signature.WriteCompressedInt(parameterTypes == null ? 0 : parameterTypes.Length);
+ SignatureHelper.WriteType(moduleBuilder, signature, returnType);
+ if (parameterTypes != null)
+ {
+ foreach (Type type in parameterTypes)
+ {
+ SignatureHelper.WriteType(moduleBuilder, signature, type);
+ }
+ }
+ }
+
+ public void SetGetMethod(MethodBuilder mdBuilder)
+ {
+ if (!mdBuilder.IsStatic)
+ {
+ signature.Position = 0;
+ signature.Write((byte)(SignatureHelper.PROPERTY | SignatureHelper.HASTHIS));
+ }
+ getMethodToken = mdBuilder.MetadataToken;
+ }
+
+ public void SetSetMethod(MethodBuilder mdBuilder)
+ {
+ if (!mdBuilder.IsStatic)
+ {
+ signature.Position = 0;
+ signature.Write((byte)(SignatureHelper.PROPERTY | SignatureHelper.HASTHIS));
+ }
+ setMethodToken = mdBuilder.MetadataToken;
+ }
+
+ public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+ {
+ if (pseudoToken == 0)
+ {
+ pseudoToken = moduleBuilder.AllocPseudoToken();
+ }
+ moduleBuilder.SetCustomAttribute(pseudoToken, customBuilder);
+ }
+
+ public override PropertyAttributes Attributes
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override bool CanRead
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override bool CanWrite
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override MethodInfo[] GetAccessors(bool nonPublic)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override MethodInfo GetGetMethod(bool nonPublic)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override ParameterInfo[] GetIndexParameters()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override MethodInfo GetSetMethod(bool nonPublic)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override Type PropertyType
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override Type DeclaringType
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override object[] GetCustomAttributes(Type attributeType, bool inherit)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override object[] GetCustomAttributes(bool inherit)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override bool IsDefined(Type attributeType, bool inherit)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override string Name
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override Type ReflectedType
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ internal void Bake()
+ {
+ TableHeap.PropertyTable.Record rec = new TableHeap.PropertyTable.Record();
+ rec.Flags = (short)attributes;
+ rec.Name = name;
+ rec.Type = moduleBuilder.Blobs.Add(signature);
+ int token = 0x17000000 | moduleBuilder.Tables.Property.AddRecord(rec);
+
+ if (pseudoToken != 0)
+ {
+ moduleBuilder.RegisterTokenFixup(pseudoToken, token);
+ }
+
+ if (getMethodToken != 0)
+ {
+ const short Getter = 0x0002;
+ AddMethodSemantics(Getter, getMethodToken, token);
+ }
+ if (setMethodToken != 0)
+ {
+ const short Setter = 0x0001;
+ AddMethodSemantics(Setter, setMethodToken, token);
+ }
+ }
+
+ private void AddMethodSemantics(short semantics, int methodToken, int propertyToken)
+ {
+ TableHeap.MethodSemanticsTable.Record rec = new TableHeap.MethodSemanticsTable.Record();
+ rec.Semantics = semantics;
+ rec.Method = methodToken;
+ rec.Association = propertyToken;
+ moduleBuilder.Tables.MethodSemantics.AddRecord(rec);
+ }
+ }
+}
diff --git a/refemit/SignatureHelper.cs b/refemit/SignatureHelper.cs
new file mode 100644
index 00000000..5c35b2bb
--- /dev/null
+++ b/refemit/SignatureHelper.cs
@@ -0,0 +1,353 @@
+/*
+ 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.Reflection;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using IKVM.Reflection.Emit.Writer;
+
+namespace IKVM.Reflection.Emit
+{
+ public class SignatureHelper
+ {
+ internal const byte DEFAULT = 0x00;
+ internal const byte GENERIC = 0x10;
+ internal const byte HASTHIS = 0x20;
+ internal const byte FIELD = 0x06;
+ internal const byte PROPERTY = 0x08;
+ internal const byte ELEMENT_TYPE_VOID = 0x01;
+ internal const byte ELEMENT_TYPE_BOOLEAN = 0x02;
+ internal const byte ELEMENT_TYPE_CHAR = 0x03;
+ internal const byte ELEMENT_TYPE_I1 = 0x04;
+ internal const byte ELEMENT_TYPE_U1 = 0x05;
+ internal const byte ELEMENT_TYPE_I2 = 0x06;
+ internal const byte ELEMENT_TYPE_U2 = 0x07;
+ internal const byte ELEMENT_TYPE_I4 = 0x08;
+ internal const byte ELEMENT_TYPE_U4 = 0x09;
+ internal const byte ELEMENT_TYPE_I8 = 0x0a;
+ internal const byte ELEMENT_TYPE_U8 = 0x0b;
+ internal const byte ELEMENT_TYPE_R4 = 0x0c;
+ internal const byte ELEMENT_TYPE_R8 = 0x0d;
+ internal const byte ELEMENT_TYPE_STRING = 0x0e;
+ internal const byte ELEMENT_TYPE_BYREF = 0x10;
+ internal const byte ELEMENT_TYPE_VALUETYPE = 0x11;
+ internal const byte ELEMENT_TYPE_CLASS = 0x12;
+ internal const byte ELEMENT_TYPE_VAR = 0x13;
+ internal const byte ELEMENT_TYPE_GENERICINST = 0x15;
+ internal const byte ELEMENT_TYPE_I = 0x18;
+ internal const byte ELEMENT_TYPE_OBJECT = 0x1c;
+ internal const byte ELEMENT_TYPE_SZARRAY = 0x1d;
+ internal const byte ELEMENT_TYPE_MVAR = 0x1e;
+ internal const byte ELEMENT_TYPE_CMOD_REQD = 0x1f;
+ internal const byte ELEMENT_TYPE_CMOD_OPT = 0x020;
+
+ private enum GenericParameterType
+ {
+ None,
+ Method,
+ Type
+ }
+
+ internal static void WriteType(ModuleBuilder moduleBuilder, ByteBuffer bb, Type type)
+ {
+ WriteType(moduleBuilder, bb, type, GenericParameterType.None);
+ }
+
+ private static void WriteType(ModuleBuilder moduleBuilder, ByteBuffer bb, Type type, GenericParameterType genericParameter)
+ {
+ while (type.IsArray)
+ {
+ // check for non-szarrays
+ if (!type.FullName.EndsWith("[]", StringComparison.Ordinal))
+ {
+ throw new NotImplementedException();
+ }
+ bb.Write(ELEMENT_TYPE_SZARRAY);
+ type = type.GetElementType();
+ }
+ while (type.IsByRef)
+ {
+ bb.Write(ELEMENT_TYPE_BYREF);
+ type = type.GetElementType();
+ }
+ if (type == typeof(void))
+ {
+ bb.Write(ELEMENT_TYPE_VOID);
+ }
+ else if (type == typeof(bool))
+ {
+ bb.Write(ELEMENT_TYPE_BOOLEAN);
+ }
+ else if (type == typeof(char))
+ {
+ bb.Write(ELEMENT_TYPE_CHAR);
+ }
+ else if (type == typeof(sbyte))
+ {
+ bb.Write(ELEMENT_TYPE_I1);
+ }
+ else if (type == typeof(byte))
+ {
+ bb.Write(ELEMENT_TYPE_U1);
+ }
+ else if (type == typeof(short))
+ {
+ bb.Write(ELEMENT_TYPE_I2);
+ }
+ else if (type == typeof(ushort))
+ {
+ bb.Write(ELEMENT_TYPE_U2);
+ }
+ else if (type == typeof(int))
+ {
+ bb.Write(ELEMENT_TYPE_I4);
+ }
+ else if (type == typeof(uint))
+ {
+ bb.Write(ELEMENT_TYPE_U4);
+ }
+ else if (type == typeof(long))
+ {
+ bb.Write(ELEMENT_TYPE_I8);
+ }
+ else if (type == typeof(ulong))
+ {
+ bb.Write(ELEMENT_TYPE_U8);
+ }
+ else if (type == typeof(float))
+ {
+ bb.Write(ELEMENT_TYPE_R4);
+ }
+ else if (type == typeof(double))
+ {
+ bb.Write(ELEMENT_TYPE_R8);
+ }
+ else if (type == typeof(string))
+ {
+ bb.Write(ELEMENT_TYPE_STRING);
+ }
+ else if (type == typeof(IntPtr))
+ {
+ bb.Write(ELEMENT_TYPE_I);
+ }
+ else if (type == typeof(object))
+ {
+ bb.Write(ELEMENT_TYPE_OBJECT);
+ }
+ else if (type.IsGenericParameter)
+ {
+ switch (genericParameter)
+ {
+ case GenericParameterType.Type:
+ bb.Write(ELEMENT_TYPE_VAR);
+ bb.WriteCompressedInt(type.GenericParameterPosition);
+ break;
+ case GenericParameterType.Method:
+ bb.Write(ELEMENT_TYPE_MVAR);
+ bb.WriteCompressedInt(type.GenericParameterPosition);
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+ else if (type.IsGenericType && !type.IsGenericTypeDefinition)
+ {
+ WriteGenericSignature(moduleBuilder, bb, type.GetGenericTypeDefinition(), type.GetGenericArguments());
+ }
+ else if (!type.IsPrimitive)
+ {
+ if (type.IsValueType)
+ {
+ bb.Write(ELEMENT_TYPE_VALUETYPE);
+ }
+ else
+ {
+ bb.Write(ELEMENT_TYPE_CLASS);
+ }
+ bb.WriteTypeDefOrRefEncoded(moduleBuilder.GetTypeToken(type).Token);
+ }
+ else
+ {
+ throw new NotImplementedException(type.FullName);
+ }
+ }
+
+ internal static void WriteCustomModifiers(ModuleBuilder moduleBuilder, ByteBuffer bb, byte mod, Type[] modifiers)
+ {
+ if (modifiers != null)
+ {
+ foreach (Type type in modifiers)
+ {
+ bb.Write(mod);
+ bb.WriteTypeDefOrRefEncoded(moduleBuilder.GetTypeToken(type).Token);
+ }
+ }
+ }
+
+ internal static void WriteFieldSig(ModuleBuilder moduleBuilder, ByteBuffer bb, Type fieldType, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers)
+ {
+ bb.Write(FIELD);
+ WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_REQD, requiredCustomModifiers);
+ WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_OPT, optionalCustomModifiers);
+ WriteType(moduleBuilder, bb, fieldType);
+ }
+
+ internal static void WriteMethodSig(ModuleBuilder moduleBuilder, ByteBuffer bb, CallingConventions callingConvention, Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers, Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers)
+ {
+ if ((callingConvention & ~CallingConventions.HasThis) != CallingConventions.Standard)
+ {
+ throw new NotImplementedException();
+ }
+ byte first = DEFAULT;
+ if ((callingConvention & CallingConventions.HasThis) != 0)
+ {
+ first |= HASTHIS;
+ }
+ parameterTypes = parameterTypes ?? Type.EmptyTypes;
+ bb.Write(first);
+ bb.WriteCompressedInt(parameterTypes.Length);
+ // RetType
+ WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_REQD, returnTypeRequiredCustomModifiers);
+ WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_OPT, returnTypeOptionalCustomModifiers);
+ WriteType(moduleBuilder, bb, returnType ?? typeof(void));
+ // Param
+ for (int i = 0; i < parameterTypes.Length; i++)
+ {
+ if (parameterTypeRequiredCustomModifiers != null && parameterTypeRequiredCustomModifiers.Length > i)
+ {
+ WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_REQD, parameterTypeRequiredCustomModifiers[i]);
+ }
+ if (parameterTypeOptionalCustomModifiers != null && parameterTypeOptionalCustomModifiers.Length > i)
+ {
+ WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_OPT, parameterTypeOptionalCustomModifiers[i]);
+ }
+ WriteType(moduleBuilder, bb, parameterTypes[i]);
+ }
+ }
+
+ private static MethodBase GetMethodOnTypeDefinition(MethodBase method)
+ {
+ Type type = method.DeclaringType;
+ if (type != null && type.IsGenericType && !type.IsGenericTypeDefinition)
+ {
+ // this trick allows us to go from the method on the generic type instance, to the equivalent method on the generic type definition
+ method = method.Module.ResolveMethod(method.MetadataToken);
+ }
+ return method;
+ }
+
+ internal static void WriteMethodSig(ModuleBuilder moduleBuilder, ByteBuffer bb, MethodBase methodOnTypeInstance)
+ {
+ Debug.Assert(!methodOnTypeInstance.IsGenericMethod || methodOnTypeInstance.IsGenericMethodDefinition);
+ MethodBase method = GetMethodOnTypeDefinition(methodOnTypeInstance);
+ ParameterInfo returnParameter = null;
+ ParameterInfo[] parameters = method.GetParameters();
+ if (method is MethodInfo)
+ {
+ returnParameter = ((MethodInfo)method).ReturnParameter;
+ }
+ bool methodIsGeneric = false;
+ ParameterInfo methodOnTypeInstanceReturnParameter = returnParameter;
+ ParameterInfo[] methodOnTypeInstanceParameters = parameters;
+ if (methodOnTypeInstance.IsGenericMethodDefinition)
+ {
+ methodIsGeneric = true;
+ methodOnTypeInstanceReturnParameter = ((MethodInfo)methodOnTypeInstance).ReturnParameter;
+ methodOnTypeInstanceParameters = methodOnTypeInstance.GetParameters();
+ }
+ byte first = DEFAULT;
+ if (!method.IsStatic)
+ {
+ first |= HASTHIS;
+ }
+ if (method.IsGenericMethod)
+ {
+ first |= GENERIC;
+ }
+ bb.Write(first);
+ if (method.IsGenericMethod)
+ {
+ bb.WriteCompressedInt(method.GetGenericArguments().Length);
+ }
+ bb.WriteCompressedInt(parameters.Length);
+ // RetType
+ if (returnParameter == null)
+ {
+ WriteType(moduleBuilder, bb, typeof(void));
+ }
+ else
+ {
+ WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_REQD, returnParameter.GetRequiredCustomModifiers());
+ WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_OPT, returnParameter.GetOptionalCustomModifiers());
+ WriteMethodParameterType(moduleBuilder, bb, returnParameter.ParameterType, methodOnTypeInstanceReturnParameter.ParameterType, methodIsGeneric);
+ }
+ // Param
+ for (int i = 0; i < parameters.Length; i++)
+ {
+ WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_REQD, parameters[i].GetRequiredCustomModifiers());
+ WriteCustomModifiers(moduleBuilder, bb, ELEMENT_TYPE_CMOD_OPT, parameters[i].GetOptionalCustomModifiers());
+ WriteMethodParameterType(moduleBuilder, bb, parameters[i].ParameterType, methodOnTypeInstanceParameters[i].ParameterType, methodIsGeneric);
+ }
+ }
+
+ private static bool IsGenericParameter(Type type)
+ {
+ while (type.HasElementType)
+ {
+ type = type.GetElementType();
+ }
+ return type.IsGenericParameter;
+ }
+
+ private static void WriteMethodParameterType(ModuleBuilder moduleBuilder, ByteBuffer bb, Type type1, Type type2, bool methodIsGeneric)
+ {
+ if (methodIsGeneric && IsGenericParameter(type2))
+ {
+ WriteType(moduleBuilder, bb, type1, GenericParameterType.Method);
+ }
+ else if (IsGenericParameter(type1))
+ {
+ WriteType(moduleBuilder, bb, type1, GenericParameterType.Type);
+ }
+ else
+ {
+ WriteType(moduleBuilder, bb, type1);
+ }
+ }
+
+ internal static void WriteGenericSignature(ModuleBuilder moduleBuilder, ByteBuffer bb, Type type, Type[] typeArguments)
+ {
+ Debug.Assert(type.IsGenericTypeDefinition);
+ bb.Write(ELEMENT_TYPE_GENERICINST);
+ WriteType(moduleBuilder, bb, type);
+ bb.WriteCompressedInt(typeArguments.Length);
+ foreach (Type t in typeArguments)
+ {
+ WriteType(moduleBuilder, bb, t);
+ }
+ }
+ }
+}
diff --git a/refemit/Tokens.cs b/refemit/Tokens.cs
new file mode 100644
index 00000000..b3904317
--- /dev/null
+++ b/refemit/Tokens.cs
@@ -0,0 +1,81 @@
+/*
+ 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
+
+*/
+
+namespace IKVM.Reflection.Emit
+{
+ public struct ConstructorToken
+ {
+ internal readonly int Token;
+
+ internal ConstructorToken(int token)
+ {
+ this.Token = token;
+ }
+
+ internal bool IsPseudoToken
+ {
+ get { return Token < 0; }
+ }
+ }
+
+ public struct FieldToken
+ {
+ internal readonly int Token;
+
+ internal FieldToken(int token)
+ {
+ this.Token = token;
+ }
+
+ internal bool IsPseudoToken
+ {
+ get { return Token < 0; }
+ }
+ }
+
+ public struct MethodToken
+ {
+ internal readonly int Token;
+
+ internal MethodToken(int token)
+ {
+ this.Token = token;
+ }
+
+ internal bool IsPseudoToken
+ {
+ get { return Token < 0; }
+ }
+ }
+
+ public struct TypeToken
+ {
+ internal readonly int Token;
+
+ internal TypeToken(int token)
+ {
+ this.Token = token;
+ }
+ }
+}
diff --git a/refemit/TypeBuilder.cs b/refemit/TypeBuilder.cs
new file mode 100644
index 00000000..52759267
--- /dev/null
+++ b/refemit/TypeBuilder.cs
@@ -0,0 +1,893 @@
+/*
+ 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.Reflection;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using IKVM.Reflection.Emit.Writer;
+using IKVM.Reflection.Emit.Impl;
+
+namespace IKVM.Reflection.Emit
+{
+ public class GenericTypeParameterBuilder
+ {
+ private readonly ModuleBuilder moduleBuilder;
+ private readonly int owner;
+
+ internal GenericTypeParameterBuilder(ModuleBuilder moduleBuilder, int owner)
+ {
+ this.moduleBuilder = moduleBuilder;
+ this.owner = owner;
+ }
+
+ public void SetBaseTypeConstraint(Type baseTypeConstraint)
+ {
+ TableHeap.GenericParamConstraintTable.Record rec = new TableHeap.GenericParamConstraintTable.Record();
+ rec.Owner = owner;
+ rec.Constraint = moduleBuilder.GetTypeToken(baseTypeConstraint).Token;
+ moduleBuilder.Tables.GenericParamConstraint.AddRecord(rec);
+ }
+ }
+
+ public sealed class TypeBuilder : Impl.TypeBase, ITypeOwner
+ {
+ private readonly ITypeOwner owner;
+ private readonly TypeToken token;
+ private readonly TypeToken extends;
+ private readonly int typeName;
+ private readonly int typeNameSpace;
+ private readonly string nameOrFullName;
+ private readonly Type baseType;
+ private readonly List<MethodBuilder> methods = new List<MethodBuilder>();
+ private readonly List<FieldBuilder> fields = new List<FieldBuilder>();
+ private List<PropertyBuilder> properties;
+ private TypeAttributes attribs;
+ private TypeFlags typeFlags;
+
+ [Flags]
+ private enum TypeFlags
+ {
+ IsGenericTypeDefinition = 1,
+ }
+
+ internal TypeBuilder(ITypeOwner owner, string name, Type baseType, TypeAttributes attribs)
+ {
+ this.owner = owner;
+ this.token = this.ModuleBuilder.Tables.TypeDef.AllocToken();
+ this.nameOrFullName = Escape(name);
+ this.baseType = baseType;
+ if (baseType != null)
+ {
+ extends = this.ModuleBuilder.GetTypeToken(baseType);
+ }
+ this.attribs = attribs;
+ if (!this.IsNested)
+ {
+ int lastdot = name.LastIndexOf('.');
+ if (lastdot > 0)
+ {
+ this.typeNameSpace = this.ModuleBuilder.Strings.Add(name.Substring(0, lastdot));
+ name = name.Substring(lastdot + 1);
+ }
+ }
+ this.typeName = this.ModuleBuilder.Strings.Add(name);
+ }
+
+ private static string Escape(string name)
+ {
+ System.Text.StringBuilder sb = null;
+ int pos;
+ for (pos = 0; pos < name.Length; pos++)
+ {
+ if ("+\\[],*&".IndexOf(name[pos]) != -1)
+ {
+ if (sb == null)
+ {
+ sb = new System.Text.StringBuilder(name, 0, pos, name.Length + 3);
+ }
+ sb.Append('\\').Append(name[pos]);
+ }
+ }
+ return sb != null ? sb.ToString() : name;
+ }
+
+ public ConstructorBuilder DefineConstructor(MethodAttributes attribs, CallingConventions callConv, Type[] parameterTypes)
+ {
+ return DefineConstructor(attribs, callConv, parameterTypes, null, null);
+ }
+
+ public ConstructorBuilder DefineConstructor(MethodAttributes attribs, CallingConventions callingConvention, Type[] parameterTypes, Type[][] requiredCustomModifiers, Type[][] optionalCustomModifiers)
+ {
+ attribs |= MethodAttributes.RTSpecialName | MethodAttributes.SpecialName;
+ string name = ".ctor";
+ if ((attribs & MethodAttributes.Static) != 0)
+ {
+ name = ".cctor";
+ }
+ MethodBuilder mb = DefineMethod(name, attribs, CallingConventions.Standard, typeof(void), null, null, parameterTypes, requiredCustomModifiers, optionalCustomModifiers);
+ return new ConstructorBuilder(mb);
+ }
+
+ public ConstructorBuilder DefineTypeInitializer()
+ {
+ MethodBuilder mb = DefineMethod(".cctor", MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName, typeof(void), Type.EmptyTypes);
+ return new ConstructorBuilder(mb);
+ }
+
+ public MethodBuilder DefineMethod(string name, MethodAttributes attribs)
+ {
+ return DefineMethod(name, attribs, null, null);
+ }
+
+ public MethodBuilder DefineMethod(string name, MethodAttributes attribs, Type returnType, Type[] parameterTypes)
+ {
+ return DefineMethod(name, attribs, CallingConventions.Standard, returnType, null, null, parameterTypes, null, null);
+ }
+
+ public MethodBuilder DefineMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] parameterTypes)
+ {
+ return DefineMethod(name, attributes, callingConvention, returnType, null, null, parameterTypes, null, null);
+ }
+
+ public MethodBuilder DefineMethod(string name, MethodAttributes attributes, CallingConventions callingConvention, Type returnType, Type[] returnTypeRequiredCustomModifiers, Type[] returnTypeOptionalCustomModifiers, Type[] parameterTypes, Type[][] parameterTypeRequiredCustomModifiers, Type[][] parameterTypeOptionalCustomModifiers)
+ {
+ this.ModuleBuilder.Tables.MethodDef.AddRow();
+ MethodBuilder mb = new MethodBuilder(this, name, attributes, callingConvention, returnType, returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers, parameterTypes, parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers);
+ methods.Add(mb);
+ return mb;
+ }
+
+ public void DefineMethodOverride(MethodInfo methodInfoBody, MethodInfo methodInfoDeclaration)
+ {
+ TableHeap.MethodImplTable.Record rec = new TableHeap.MethodImplTable.Record();
+ rec.Class = token.Token;
+ rec.MethodBody = this.ModuleBuilder.GetMethodToken(methodInfoBody).Token;
+ rec.MethodDeclaration = this.ModuleBuilder.GetMethodToken(methodInfoDeclaration).Token;
+ this.ModuleBuilder.Tables.MethodImpl.AddRecord(rec);
+ }
+
+ public FieldBuilder DefineField(string name, Type fieldType, FieldAttributes attribs)
+ {
+ return DefineField(name, fieldType, null, null, attribs);
+ }
+
+ public FieldBuilder DefineField(string fieldName, Type type, Type[] requiredCustomModifiers, Type[] optionalCustomModifiers, FieldAttributes attributes)
+ {
+ FieldBuilder fb = new FieldBuilder(this, fieldName, type, requiredCustomModifiers, optionalCustomModifiers, attributes);
+ fields.Add(fb);
+ return fb;
+ }
+
+ public PropertyBuilder DefineProperty(string name, PropertyAttributes attributes, Type returnType, Type[] parameterTypes)
+ {
+ if (properties == null)
+ {
+ properties = new List<PropertyBuilder>();
+ }
+ PropertyBuilder pb = new PropertyBuilder(this.ModuleBuilder, name, attributes, returnType, parameterTypes);
+ properties.Add(pb);
+ return pb;
+ }
+
+ public TypeBuilder DefineNestedType(string name)
+ {
+ return DefineNestedType(name, TypeAttributes.Class | TypeAttributes.NestedPrivate);
+ }
+
+ public TypeBuilder DefineNestedType(string name, TypeAttributes attribs)
+ {
+ return DefineNestedType(name, attribs, null);
+ }
+
+ public TypeBuilder DefineNestedType(string name, TypeAttributes attr, Type parent)
+ {
+ return this.ModuleBuilder.DefineNestedTypeHelper(this, name, attr, parent, PackingSize.Unspecified, 0);
+ }
+
+ public TypeBuilder DefineNestedType(string name, TypeAttributes attr, Type parent, Type[] interfaces)
+ {
+ TypeBuilder tb = DefineNestedType(name, attr, parent);
+ foreach (Type iface in interfaces)
+ {
+ tb.AddInterfaceImplementation(iface);
+ }
+ return tb;
+ }
+
+ public void AddInterfaceImplementation(Type interfaceType)
+ {
+ TableHeap.InterfaceImplTable.Record rec = new TableHeap.InterfaceImplTable.Record();
+ rec.Class = token.Token;
+ rec.Interface = this.ModuleBuilder.GetTypeToken(interfaceType).Token;
+ this.ModuleBuilder.Tables.InterfaceImpl.AddRecord(rec);
+ }
+
+ private void SetStructLayoutPseudoCustomAttribute(CustomAttributeBuilder customBuilder)
+ {
+ object val = customBuilder.GetConstructorArgument(0);
+ LayoutKind layout;
+ if (val is short)
+ {
+ layout = (LayoutKind)(short)val;
+ }
+ else
+ {
+ layout = (LayoutKind)val;
+ }
+ int? pack = (int?)customBuilder.GetFieldValue("Pack");
+ int? size = (int?)customBuilder.GetFieldValue("Size");
+ if (pack.HasValue || size.HasValue)
+ {
+ TableHeap.ClassLayoutTable.Record rec = new TableHeap.ClassLayoutTable.Record();
+ rec.PackingSize = (short)(pack ?? 0);
+ rec.ClassSize = size ?? 0;
+ rec.Parent = token.Token;
+ this.ModuleBuilder.Tables.ClassLayout.AddRecord(rec);
+ }
+ attribs &= ~TypeAttributes.LayoutMask;
+ switch (layout)
+ {
+ case LayoutKind.Auto:
+ attribs |= TypeAttributes.AutoLayout;
+ break;
+ case LayoutKind.Explicit:
+ attribs |= TypeAttributes.ExplicitLayout;
+ break;
+ case LayoutKind.Sequential:
+ attribs |= TypeAttributes.SequentialLayout;
+ break;
+ }
+ CharSet? charSet = (CharSet?)customBuilder.GetFieldValue("CharSet");
+ attribs &= ~TypeAttributes.StringFormatMask;
+ switch (charSet ?? CharSet.None)
+ {
+ case CharSet.None:
+ case CharSet.Ansi:
+ attribs |= TypeAttributes.AnsiClass;
+ break;
+ case CharSet.Auto:
+ attribs |= TypeAttributes.AutoClass;
+ break;
+ case CharSet.Unicode:
+ attribs |= TypeAttributes.UnicodeClass;
+ break;
+ }
+ }
+
+ public void SetCustomAttribute(CustomAttributeBuilder customBuilder)
+ {
+ if (customBuilder.Constructor.DeclaringType == typeof(StructLayoutAttribute))
+ {
+ SetStructLayoutPseudoCustomAttribute(customBuilder);
+ }
+ else if (customBuilder.Constructor.DeclaringType == typeof(SerializableAttribute))
+ {
+ attribs |= TypeAttributes.Serializable;
+ }
+ else if (customBuilder.Constructor.DeclaringType == typeof(ComImportAttribute))
+ {
+ attribs |= TypeAttributes.Import;
+ }
+ else
+ {
+ this.ModuleBuilder.SetCustomAttribute(token.Token, customBuilder);
+ }
+ }
+
+ public void AddDeclarativeSecurity(System.Security.Permissions.SecurityAction securityAction, System.Security.PermissionSet permissionSet)
+ {
+ throw new NotImplementedException();
+ }
+
+ public GenericTypeParameterBuilder[] DefineGenericParameters(params string[] names)
+ {
+ typeFlags |= TypeFlags.IsGenericTypeDefinition;
+ GenericTypeParameterBuilder[] gtpb = new GenericTypeParameterBuilder[names.Length];
+ for (int i = 0; i < names.Length; i++)
+ {
+ TableHeap.GenericParamTable.Record rec = new TableHeap.GenericParamTable.Record();
+ rec.Number = (short)i;
+ rec.Flags = 0;
+ rec.Owner = token.Token;
+ rec.Name = this.ModuleBuilder.Strings.Add(names[i]);
+ gtpb[i] = new GenericTypeParameterBuilder(this.ModuleBuilder, this.ModuleBuilder.Tables.GenericParam.AddRecord(rec));
+ }
+ return gtpb;
+ }
+
+ public Type CreateType()
+ {
+ foreach (MethodBuilder mb in methods)
+ {
+ mb.Bake();
+ }
+ if (properties != null)
+ {
+ TableHeap.PropertyMapTable.Record rec = new TableHeap.PropertyMapTable.Record();
+ rec.Parent = token.Token;
+ rec.PropertyList = this.ModuleBuilder.Tables.Property.RowCount + 1;
+ this.ModuleBuilder.Tables.PropertyMap.AddRecord(rec);
+ foreach (PropertyBuilder pb in properties)
+ {
+ pb.Bake();
+ }
+ properties = null;
+ }
+ return new BakedType(this);
+ }
+
+ public override string AssemblyQualifiedName
+ {
+ get { return FullName + ", " + this.ModuleBuilder.Assembly.FullName; }
+ }
+
+ public override Type BaseType
+ {
+ get { return baseType; }
+ }
+
+ public override string FullName
+ {
+ get
+ {
+ if (this.IsNested)
+ {
+ return this.DeclaringType.FullName + "+" + nameOrFullName;
+ }
+ else
+ {
+ return nameOrFullName;
+ }
+ }
+ }
+
+ public override string Name
+ {
+ get
+ {
+ if (this.IsNested)
+ {
+ return nameOrFullName;
+ }
+ else
+ {
+ return base.Name;
+ }
+ }
+ }
+
+ protected override TypeAttributes GetAttributeFlagsImpl()
+ {
+ return attribs;
+ }
+
+ internal MethodInfo __GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
+ {
+ return GetMethodImpl(name, bindingAttr, binder, callConvention, types, modifiers);
+ }
+
+ protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
+ {
+ const BindingFlags supportedFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
+ if (binder != null || (bindingAttr & ~supportedFlags) != 0)
+ {
+ throw new NotSupportedException();
+ }
+ foreach (MethodBuilder mb in methods)
+ {
+ if (mb.Name == name
+ && ((mb.IsPublic && ((bindingAttr & BindingFlags.Public) != 0)) || (!mb.IsPublic && ((bindingAttr & BindingFlags.NonPublic) != 0)))
+ && ((mb.IsStatic && ((bindingAttr & BindingFlags.Static) != 0)) || (!mb.IsStatic && ((bindingAttr & BindingFlags.Instance) != 0)))
+ && (types == null || mb.MatchParameters(types)))
+ {
+ return mb;
+ }
+ }
+ if (baseType == null || (bindingAttr & BindingFlags.DeclaredOnly) != 0)
+ {
+ return null;
+ }
+ return baseType.GetMethod(name, bindingAttr, binder, callConvention, types, modifiers);
+ }
+
+ public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override bool HasElementTypeImpl()
+ {
+ return false;
+ }
+
+ protected override bool IsArrayImpl()
+ {
+ return false;
+ }
+
+ protected override bool IsByRefImpl()
+ {
+ return false;
+ }
+
+ protected override bool IsValueTypeImpl()
+ {
+ return baseType == typeof(ValueType) || baseType == typeof(Enum);
+ }
+
+ public override Type MakeGenericType(params Type[] typeArguments)
+ {
+ return GenericType.Make(this, typeArguments);
+ }
+
+ public override StructLayoutAttribute StructLayoutAttribute
+ {
+ get
+ {
+ StructLayoutAttribute attr;
+ if ((attribs & TypeAttributes.ExplicitLayout) != 0)
+ {
+ attr = new StructLayoutAttribute(LayoutKind.Explicit);
+ attr.Pack = 8;
+ attr.Size = 0;
+ this.ModuleBuilder.Tables.ClassLayout.GetLayout(token, ref attr.Pack, ref attr.Size);
+ }
+ else
+ {
+ attr = new StructLayoutAttribute((attribs & TypeAttributes.SequentialLayout) != 0 ? LayoutKind.Sequential : LayoutKind.Auto);
+ attr.Pack = 8;
+ attr.Size = 0;
+ }
+ switch (attribs & TypeAttributes.StringFormatMask)
+ {
+ case TypeAttributes.AutoClass:
+ attr.CharSet = CharSet.Auto;
+ break;
+ case TypeAttributes.UnicodeClass:
+ attr.CharSet = CharSet.Unicode;
+ break;
+ case TypeAttributes.AnsiClass:
+ attr.CharSet = CharSet.Ansi;
+ break;
+ }
+ return attr;
+ }
+ }
+
+ public override Type DeclaringType
+ {
+ get
+ {
+ return owner as TypeBuilder;
+ }
+ }
+
+ public override bool IsGenericType
+ {
+ get
+ {
+ return IsGenericTypeDefinition;
+ }
+ }
+
+ public override bool IsGenericTypeDefinition
+ {
+ get
+ {
+ return (typeFlags & TypeFlags.IsGenericTypeDefinition) != 0;
+ }
+ }
+
+ internal void WriteTypeDefRecord(MetadataWriter mw, ref int fieldList, ref int methodList)
+ {
+ mw.Write((int)attribs);
+ mw.WriteStringIndex(typeName);
+ mw.WriteStringIndex(typeNameSpace);
+ mw.WriteTypeDefOrRef(extends.Token);
+ mw.WriteField(fieldList);
+ mw.WriteMethodDef(methodList);
+ methodList += methods.Count;
+ fieldList += fields.Count;
+ }
+
+ internal void WriteMethodDefRecords(int baseRVA, MetadataWriter mw, ref int paramList)
+ {
+ foreach (MethodBuilder mb in methods)
+ {
+ mb.WriteMethodDefRecord(baseRVA, mw, ref paramList);
+ }
+ }
+
+ internal void ResolveMethodAndFieldTokens(ref int methodToken, ref int fieldToken, ref int parameterToken)
+ {
+ foreach (MethodBuilder method in methods)
+ {
+ method.FixupToken(methodToken++, ref parameterToken);
+ }
+ foreach (FieldBuilder field in fields)
+ {
+ field.FixupToken(fieldToken++);
+ }
+ }
+
+ internal void WriteParamRecords(MetadataWriter mw)
+ {
+ foreach (MethodBuilder mb in methods)
+ {
+ mb.WriteParamRecords(mw);
+ }
+ }
+
+ internal void WriteFieldRecords(MetadataWriter mw)
+ {
+ foreach (FieldBuilder fb in fields)
+ {
+ fb.WriteFieldRecords(mw);
+ }
+ }
+
+ internal override ModuleBuilder ModuleBuilder
+ {
+ get { return owner.ModuleBuilder; }
+ }
+
+ internal override TypeToken GetToken()
+ {
+ return token;
+ }
+
+ ModuleBuilder ITypeOwner.ModuleBuilder
+ {
+ get { return owner.ModuleBuilder; }
+ }
+ }
+
+ sealed class ArrayType : Impl.TypeBase
+ {
+ private readonly Impl.TypeBase type;
+ private TypeToken token;
+
+ internal static Type Make(Impl.TypeBase type)
+ {
+ return type.ModuleBuilder.CanonicalizeType(new ArrayType(type));
+ }
+
+ private ArrayType(Impl.TypeBase type)
+ {
+ this.type = type;
+ }
+
+ public override string AssemblyQualifiedName
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override Type BaseType
+ {
+ get { return typeof(System.Array); }
+ }
+
+ public override string FullName
+ {
+ get { return type.FullName + "[]"; }
+ }
+
+ protected override TypeAttributes GetAttributeFlagsImpl()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override Type GetElementType()
+ {
+ return type;
+ }
+
+ protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override bool HasElementTypeImpl()
+ {
+ return true;
+ }
+
+ protected override bool IsArrayImpl()
+ {
+ return true;
+ }
+
+ protected override bool IsByRefImpl()
+ {
+ return false;
+ }
+
+ protected override bool IsValueTypeImpl()
+ {
+ return false;
+ }
+
+ public override bool Equals(object o)
+ {
+ ArrayType at = o as ArrayType;
+ return at != null && at.type.Equals(type);
+ }
+
+ public override int GetHashCode()
+ {
+ return type.GetHashCode() * 5;
+ }
+
+ internal override ModuleBuilder ModuleBuilder
+ {
+ get { return type.ModuleBuilder; }
+ }
+
+ internal override TypeToken GetToken()
+ {
+ if (token.Token == 0)
+ {
+ ByteBuffer spec = new ByteBuffer(5);
+ SignatureHelper.WriteType(this.ModuleBuilder, spec, this);
+ token = new TypeToken(0x1B000000 | this.ModuleBuilder.Tables.TypeSpec.AddRecord(this.ModuleBuilder.Blobs.Add(spec)));
+ }
+ return token;
+ }
+ }
+
+ sealed class BakedType : Impl.TypeBase
+ {
+ private readonly TypeBuilder typeBuilder;
+
+ internal BakedType(TypeBuilder typeBuilder)
+ {
+ this.typeBuilder = typeBuilder;
+ }
+
+ public override string AssemblyQualifiedName
+ {
+ get { return typeBuilder.AssemblyQualifiedName; }
+ }
+
+ public override Type BaseType
+ {
+ get { return typeBuilder.BaseType; }
+ }
+
+ public override string Name
+ {
+ get { return typeBuilder.Name; }
+ }
+
+ public override string FullName
+ {
+ get { return typeBuilder.FullName; }
+ }
+
+ protected override TypeAttributes GetAttributeFlagsImpl()
+ {
+ return typeBuilder.Attributes;
+ }
+
+ protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
+ {
+ return typeBuilder.__GetMethodImpl(name, bindingAttr, binder, callConvention, types, modifiers);
+ }
+
+ public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
+ {
+ return typeBuilder.GetMethods(bindingAttr);
+ }
+
+ protected override bool HasElementTypeImpl()
+ {
+ return false;
+ }
+
+ protected override bool IsArrayImpl()
+ {
+ return false;
+ }
+
+ protected override bool IsByRefImpl()
+ {
+ return false;
+ }
+
+ protected override bool IsValueTypeImpl()
+ {
+ return typeBuilder.IsValueType;
+ }
+
+ public override Type MakeArrayType()
+ {
+ return typeBuilder.MakeArrayType();
+ }
+
+ public override Type MakeGenericType(params Type[] typeArguments)
+ {
+ return typeBuilder.MakeGenericType(typeArguments);
+ }
+
+ public override System.Runtime.InteropServices.StructLayoutAttribute StructLayoutAttribute
+ {
+ get { return typeBuilder.StructLayoutAttribute; }
+ }
+
+ public override Type UnderlyingSystemType
+ {
+ // Type.Equals/GetHashCode relies on this
+ get { return typeBuilder; }
+ }
+
+ public override bool IsGenericType
+ {
+ get
+ {
+ return typeBuilder.IsGenericType;
+ }
+ }
+
+ public override bool IsGenericTypeDefinition
+ {
+ get
+ {
+ return typeBuilder.IsGenericTypeDefinition;
+ }
+ }
+
+ internal override ModuleBuilder ModuleBuilder
+ {
+ get { return typeBuilder.ModuleBuilder; }
+ }
+
+ internal override TypeToken GetToken()
+ {
+ return typeBuilder.GetToken();
+ }
+ }
+
+ sealed class GenericType : Impl.TypeBase
+ {
+ private readonly TypeBuilder typeBuilder;
+ private readonly Type[] typeArguments;
+ private TypeToken token;
+
+ internal static Type Make(TypeBuilder typeBuilder, Type[] typeArguments)
+ {
+ return typeBuilder.ModuleBuilder.CanonicalizeType(new GenericType(typeBuilder, typeArguments));
+ }
+
+ private GenericType(TypeBuilder typeBuilder, Type[] typeArguments)
+ {
+ this.typeBuilder = typeBuilder;
+ this.typeArguments = typeArguments;
+ }
+
+ public override string AssemblyQualifiedName
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override Type BaseType
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override string FullName
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override string Name
+ {
+ get { throw new NotImplementedException(); }
+ }
+
+ public override Type[] GetGenericArguments()
+ {
+ return (Type[])typeArguments.Clone();
+ }
+
+ protected override TypeAttributes GetAttributeFlagsImpl()
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override bool HasElementTypeImpl()
+ {
+ return false;
+ }
+
+ protected override bool IsArrayImpl()
+ {
+ return false;
+ }
+
+ protected override bool IsByRefImpl()
+ {
+ return false;
+ }
+
+ public override bool Equals(object o)
+ {
+ GenericType gt = o as GenericType;
+ if (gt != null && gt.typeBuilder == typeBuilder)
+ {
+ for (int i = 0; i < typeArguments.Length; i++)
+ {
+ if (typeArguments[i] != gt.typeArguments[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ int hash = typeBuilder.GetHashCode();
+ for (int i = 0; i < typeArguments.Length; i++)
+ {
+ hash *= 37;
+ hash ^= typeArguments[i].GetHashCode();
+ }
+ return hash;
+ }
+
+ public override bool IsGenericType
+ {
+ get { return true; }
+ }
+
+ public override bool IsGenericTypeDefinition
+ {
+ get { return false; }
+ }
+
+ internal override ModuleBuilder ModuleBuilder
+ {
+ get { return typeBuilder.ModuleBuilder; }
+ }
+
+ internal override TypeToken GetToken()
+ {
+ if (token.Token == 0)
+ {
+ ByteBuffer spec = new ByteBuffer(5);
+ SignatureHelper.WriteGenericSignature(typeBuilder.ModuleBuilder, spec, typeBuilder, typeArguments);
+ token = new TypeToken(0x1B000000 | this.ModuleBuilder.Tables.TypeSpec.AddRecord(this.ModuleBuilder.Blobs.Add(spec)));
+ }
+ return token;
+ }
+ }
+}
diff --git a/refemit/Writer/ByteBuffer.cs b/refemit/Writer/ByteBuffer.cs
new file mode 100644
index 00000000..e5a41d62
--- /dev/null
+++ b/refemit/Writer/ByteBuffer.cs
@@ -0,0 +1,281 @@
+/*
+ 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;
+
+namespace IKVM.Reflection.Emit.Writer
+{
+ sealed class ByteBuffer
+ {
+ private byte[] buffer;
+ private int pos;
+ private int __length; // __length is only valid if > pos, otherwise pos is the current length
+
+ internal ByteBuffer(int initialCapacity)
+ {
+ buffer = new byte[initialCapacity];
+ }
+
+ private ByteBuffer(byte[] wrap)
+ {
+ this.buffer = wrap;
+ this.pos = wrap.Length;
+ }
+
+ internal int Position
+ {
+ get { return pos; }
+ set
+ {
+ if (value > this.Length || value > buffer.Length)
+ throw new ArgumentOutOfRangeException();
+ __length = Math.Max(__length, pos);
+ pos = value;
+ }
+ }
+
+ internal int Length
+ {
+ get { return Math.Max(pos, __length); }
+ }
+
+ private void Grow(int minGrow)
+ {
+ byte[] newbuf = new byte[Math.Max(buffer.Length + minGrow, buffer.Length * 2)];
+ Buffer.BlockCopy(buffer, 0, newbuf, 0, buffer.Length);
+ buffer = newbuf;
+ }
+
+ // NOTE this does not advance the position
+ internal int GetInt32AtCurrentPosition()
+ {
+ return buffer[pos]
+ + (buffer[pos + 1] << 8)
+ + (buffer[pos + 2] << 16)
+ + (buffer[pos + 3] << 24);
+ }
+
+ // NOTE this does not advance the position
+ internal byte GetByteAtCurrentPosition()
+ {
+ return buffer[pos];
+ }
+
+ internal void Write(byte[] value)
+ {
+ if (pos + value.Length > buffer.Length)
+ Grow(value.Length);
+ Buffer.BlockCopy(value, 0, buffer, pos, value.Length);
+ pos += value.Length;
+ }
+
+ internal void Write(byte value)
+ {
+ if (pos == buffer.Length)
+ Grow(1);
+ buffer[pos++] = value;
+ }
+
+ internal void Write(sbyte value)
+ {
+ Write((byte)value);
+ }
+
+ internal void Write(ushort value)
+ {
+ Write((short)value);
+ }
+
+ internal void Write(short value)
+ {
+ if (pos + 2 > buffer.Length)
+ Grow(2);
+ buffer[pos++] = (byte)value;
+ buffer[pos++] = (byte)(value >> 8);
+ }
+
+ internal void Write(uint value)
+ {
+ Write((int)value);
+ }
+
+ internal void Write(int value)
+ {
+ if (pos + 4 > buffer.Length)
+ Grow(4);
+ buffer[pos++] = (byte)value;
+ buffer[pos++] = (byte)(value >> 8);
+ buffer[pos++] = (byte)(value >> 16);
+ buffer[pos++] = (byte)(value >> 24);
+ }
+
+ internal void Write(ulong value)
+ {
+ Write((long)value);
+ }
+
+ internal void Write(long value)
+ {
+ if (pos + 8 > buffer.Length)
+ Grow(8);
+ buffer[pos++] = (byte)value;
+ buffer[pos++] = (byte)(value >> 8);
+ buffer[pos++] = (byte)(value >> 16);
+ buffer[pos++] = (byte)(value >> 24);
+ buffer[pos++] = (byte)(value >> 32);
+ buffer[pos++] = (byte)(value >> 40);
+ buffer[pos++] = (byte)(value >> 48);
+ buffer[pos++] = (byte)(value >> 56);
+ }
+
+ internal void Write(float value)
+ {
+ Write(BitConverter.GetBytes(value));
+ }
+
+ internal void Write(double value)
+ {
+ Write(BitConverter.DoubleToInt64Bits(value));
+ }
+
+ internal void WriteCompressedInt(int value)
+ {
+ if (value <= 0x7F)
+ {
+ Write((byte)value);
+ }
+ else if (value <= 0x3FFF)
+ {
+ Write((byte)(0x80 | (value >> 8)));
+ Write((byte)value);
+ }
+ else
+ {
+ Write((byte)(0xC0 | (value >> 24)));
+ Write((byte)(value >> 16));
+ Write((byte)(value >> 8));
+ Write((byte)value);
+ }
+ }
+
+ internal void Write(ByteBuffer bb)
+ {
+ if (pos + bb.Length > buffer.Length)
+ Grow(bb.Length);
+ Buffer.BlockCopy(bb.buffer, 0, buffer, pos, bb.Length);
+ pos += bb.Length;
+ }
+
+ internal void WriteTo(System.IO.Stream stream)
+ {
+ stream.Write(buffer, 0, this.Length);
+ }
+
+ internal void Clear()
+ {
+ pos = 0;
+ __length = 0;
+ }
+
+ internal void Align(int alignment)
+ {
+ if (pos + alignment > buffer.Length)
+ Grow(alignment);
+ int newpos = (pos + alignment - 1) & ~(alignment - 1);
+ while (pos < newpos)
+ buffer[pos++] = 0;
+ }
+
+ internal void WriteTypeDefOrRefEncoded(int token)
+ {
+ switch (token >> 24)
+ {
+ case TableHeap.TypeDefTable.Index:
+ WriteCompressedInt((token & 0xFFFFFF) << 2 | 0);
+ break;
+ case TableHeap.TypeRefTable.Index:
+ WriteCompressedInt((token & 0xFFFFFF) << 2 | 1);
+ break;
+ case TableHeap.TypeSpecTable.Index:
+ WriteCompressedInt((token & 0xFFFFFF) << 2 | 2);
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+ internal void Write(System.IO.Stream stream)
+ {
+ const int chunkSize = 8192;
+ for (; ; )
+ {
+ if (pos + chunkSize > buffer.Length)
+ Grow(chunkSize);
+ int read = stream.Read(buffer, pos, chunkSize);
+ if (read <= 0)
+ {
+ break;
+ }
+ pos += read;
+ }
+ }
+
+ internal static ByteBuffer Wrap(byte[] pubkey)
+ {
+ return new ByteBuffer(pubkey);
+ }
+
+ internal byte[] ToArray()
+ {
+ byte[] buf = new byte[this.Length];
+ Buffer.BlockCopy(this.buffer, 0, buf, 0, buf.Length);
+ return buf;
+ }
+
+ internal bool Match(int pos, ByteBuffer bb2, int pos2, int len)
+ {
+ for (int i = 0; i < len; i++)
+ {
+ if (buffer[pos + i] != bb2.buffer[pos2 + i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ internal int Hash()
+ {
+ int hash = 0;
+ int len = this.Length;
+ for (int i = 0; i < len; i++)
+ {
+ hash *= 37;
+ hash ^= buffer[i];
+ }
+ return hash;
+ }
+ }
+}
diff --git a/refemit/Writer/Heaps.cs b/refemit/Writer/Heaps.cs
new file mode 100644
index 00000000..799177cb
--- /dev/null
+++ b/refemit/Writer/Heaps.cs
@@ -0,0 +1,2107 @@
+/*
+ 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 TypeToken AllocToken()
+ {
+ return new TypeToken(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.WriteTypeDefOrRef(records[i].Interface);
+ }
+ }
+
+ protected override int GetRowSize(RowSizeCalc rsc)
+ {
+ return rsc
+ .WriteTypeDef()
+ .WriteTypeDefOrRef()
+ .Value;
+ }
+
+ internal void Fixup(ModuleBuilder moduleBuilder)
+ {
+ 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(TypeToken token, ref int pack, ref int size)
+ {
+ for (int i = 0; i < rowCount; i++)
+ {
+ if (records[i].Parent == token.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 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 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)
+ {
+ int pos = mw.Position;
+ 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; }
+ }
+ }
+}
diff --git a/refemit/Writer/MetadataWriter.cs b/refemit/Writer/MetadataWriter.cs
new file mode 100644
index 00000000..762772ab
--- /dev/null
+++ b/refemit/Writer/MetadataWriter.cs
@@ -0,0 +1,538 @@
+/*
+ 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.IO;
+using System.Collections.Generic;
+using System.Text;
+
+namespace IKVM.Reflection.Emit.Writer
+{
+ sealed class MetadataWriter
+ {
+ private readonly ModuleBuilder moduleBuilder;
+ private readonly Stream stream;
+ private readonly byte[] buffer = new byte[8];
+
+ internal MetadataWriter(ModuleBuilder moduleBuilder, Stream stream)
+ {
+ this.moduleBuilder = moduleBuilder;
+ this.stream = stream;
+ }
+
+ internal ModuleBuilder ModuleBuilder
+ {
+ get { return moduleBuilder; }
+ }
+
+ internal int Position
+ {
+ get { return (int)stream.Position; }
+ }
+
+ internal void Write(ByteBuffer bb)
+ {
+ bb.WriteTo(stream);
+ }
+
+ internal void Write(byte[] value)
+ {
+ stream.Write(value, 0, value.Length);
+ }
+
+ internal void Write(byte value)
+ {
+ stream.WriteByte(value);
+ }
+
+ internal void Write(ushort value)
+ {
+ Write((short)value);
+ }
+
+ internal void Write(short value)
+ {
+ buffer[0] = (byte)value;
+ buffer[1] = (byte)(value >> 8);
+ stream.Write(buffer, 0, 2);
+ }
+
+ internal void Write(uint value)
+ {
+ Write((int)value);
+ }
+
+ internal void Write(int value)
+ {
+ buffer[0] = (byte)value;
+ buffer[1] = (byte)(value >> 8);
+ buffer[2] = (byte)(value >> 16);
+ buffer[3] = (byte)(value >> 24);
+ stream.Write(buffer, 0, 4);
+ }
+
+ internal void Write(ulong value)
+ {
+ Write((long)value);
+ }
+
+ internal void Write(long value)
+ {
+ buffer[0] = (byte)value;
+ buffer[1] = (byte)(value >> 8);
+ buffer[2] = (byte)(value >> 16);
+ buffer[3] = (byte)(value >> 24);
+ buffer[4] = (byte)(value >> 32);
+ buffer[5] = (byte)(value >> 40);
+ buffer[6] = (byte)(value >> 48);
+ buffer[7] = (byte)(value >> 56);
+ stream.Write(buffer, 0, 8);
+ }
+
+ internal void WriteCompressedInt(int value)
+ {
+ if (value <= 0x7F)
+ {
+ Write((byte)value);
+ }
+ else if (value <= 0x3FFF)
+ {
+ Write((byte)(0x80 | (value >> 8)));
+ Write((byte)value);
+ }
+ else
+ {
+ Write((byte)(0xC0 | (value >> 24)));
+ Write((byte)(value >> 16));
+ Write((byte)(value >> 8));
+ Write((byte)value);
+ }
+ }
+
+ internal static int GetCompressedIntLength(int value)
+ {
+ if (value <= 0x7F)
+ {
+ return 1;
+ }
+ else if (value <= 0x3FFF)
+ {
+ return 2;
+ }
+ else
+ {
+ return 4;
+ }
+ }
+
+ internal void WriteStringIndex(int index)
+ {
+ if (moduleBuilder.bigStrings)
+ {
+ Write(index);
+ }
+ else
+ {
+ Write((short)index);
+ }
+ }
+
+ internal void WriteGuidIndex(int index)
+ {
+ if (moduleBuilder.bigGuids)
+ {
+ Write(index);
+ }
+ else
+ {
+ Write((short)index);
+ }
+ }
+
+ internal void WriteBlobIndex(int index)
+ {
+ if (moduleBuilder.bigBlobs)
+ {
+ Write(index);
+ }
+ else
+ {
+ Write((short)index);
+ }
+ }
+
+ internal void WriteTypeDefOrRef(int token)
+ {
+ 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 NotImplementedException();
+ }
+ if (moduleBuilder.bigTypeDefOrRef)
+ {
+ Write(token);
+ }
+ else
+ {
+ Write((short)token);
+ }
+ }
+
+ internal void WriteHasCustomAttribute(int encodedToken)
+ {
+ // NOTE because we've already had to do the encoding (to be able to sort the table)
+ // here we simple write the value
+ if (moduleBuilder.bigHasCustomAttribute)
+ {
+ Write(encodedToken);
+ }
+ else
+ {
+ Write((short)encodedToken);
+ }
+ }
+
+ internal void WriteCustomAttributeType(int token)
+ {
+ switch (token >> 24)
+ {
+ case TableHeap.MethodDefTable.Index:
+ token = (token & 0xFFFFFF) << 3 | 2;
+ break;
+ case TableHeap.MemberRefTable.Index:
+ token = (token & 0xFFFFFF) << 3 | 3;
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ if (moduleBuilder.bigCustomAttributeType)
+ {
+ Write(token);
+ }
+ else
+ {
+ Write((short)token);
+ }
+ }
+
+ internal void WriteField(int index)
+ {
+ if (moduleBuilder.bigField)
+ {
+ Write(index & 0xFFFFFF);
+ }
+ else
+ {
+ Write((short)index);
+ }
+ }
+
+ internal void WriteMethodDef(int index)
+ {
+ if (moduleBuilder.bigMethodDef)
+ {
+ Write(index & 0xFFFFFF);
+ }
+ else
+ {
+ Write((short)index);
+ }
+ }
+
+ internal void WriteParam(int index)
+ {
+ if (moduleBuilder.bigParam)
+ {
+ Write(index & 0xFFFFFF);
+ }
+ else
+ {
+ Write((short)index);
+ }
+ }
+
+ internal void WriteTypeDef(int index)
+ {
+ if (moduleBuilder.bigTypeDef)
+ {
+ Write(index & 0xFFFFFF);
+ }
+ else
+ {
+ Write((short)index);
+ }
+ }
+
+ internal void WriteProperty(int index)
+ {
+ if (moduleBuilder.bigProperty)
+ {
+ Write(index & 0xFFFFFF);
+ }
+ else
+ {
+ Write((short)index);
+ }
+ }
+
+ internal void WriteGenericParam(int index)
+ {
+ if (moduleBuilder.bigGenericParam)
+ {
+ Write(index & 0xFFFFFF);
+ }
+ else
+ {
+ Write((short)index);
+ }
+ }
+
+ internal void WriteModuleRef(int index)
+ {
+ if (moduleBuilder.bigModuleRef)
+ {
+ Write(index & 0xFFFFFF);
+ }
+ else
+ {
+ Write((short)index);
+ }
+ }
+
+ internal void WriteResolutionScope(int token)
+ {
+ switch (token >> 24)
+ {
+ case TableHeap.ModuleTable.Index:
+ token = (token & 0xFFFFFF) << 2 | 0;
+ break;
+ case TableHeap.ModuleRefTable.Index:
+ token = (token & 0xFFFFFF) << 2 | 1;
+ break;
+ case TableHeap.AssemblyRefTable.Index:
+ token = (token & 0xFFFFFF) << 2 | 2;
+ break;
+ case TableHeap.TypeRefTable.Index:
+ token = (token & 0xFFFFFF) << 2 | 3;
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ if (moduleBuilder.bigResolutionScope)
+ {
+ Write(token);
+ }
+ else
+ {
+ Write((short)token);
+ }
+ }
+
+ internal void WriteMemberRefParent(int token)
+ {
+ switch (token >> 24)
+ {
+ case TableHeap.TypeDefTable.Index:
+ token = (token & 0xFFFFFF) << 3 | 0;
+ break;
+ case TableHeap.TypeRefTable.Index:
+ token = (token & 0xFFFFFF) << 3 | 1;
+ break;
+ case TableHeap.ModuleRefTable.Index:
+ token = (token & 0xFFFFFF) << 3 | 2;
+ break;
+ case TableHeap.MethodDefTable.Index:
+ token = (token & 0xFFFFFF) << 3 | 3;
+ break;
+ case TableHeap.TypeSpecTable.Index:
+ token = (token & 0xFFFFFF) << 3 | 4;
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ if (moduleBuilder.bigMemberRefParent)
+ {
+ Write(token);
+ }
+ else
+ {
+ Write((short)token);
+ }
+ }
+
+ internal void WriteMethodDefOrRef(int token)
+ {
+ switch (token >> 24)
+ {
+ case TableHeap.MethodDefTable.Index:
+ token = (token & 0xFFFFFF) << 1 | 0;
+ break;
+ case TableHeap.MemberRefTable.Index:
+ token = (token & 0xFFFFFF) << 1 | 1;
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ if (moduleBuilder.bigMethodDefOrRef)
+ {
+ Write(token);
+ }
+ else
+ {
+ Write((short)token);
+ }
+ }
+
+ internal void WriteHasConstant(int encodedToken)
+ {
+ // NOTE because we've already had to do the encoding (to be able to sort the table)
+ // here we simple write the value
+ if (moduleBuilder.bigHasConstant)
+ {
+ Write(encodedToken);
+ }
+ else
+ {
+ Write((short)encodedToken);
+ }
+ }
+
+ internal void WriteHasSemantics(int encodedToken)
+ {
+ // NOTE because we've already had to do the encoding (to be able to sort the table)
+ // here we simple write the value
+ if (moduleBuilder.bigHasSemantics)
+ {
+ Write(encodedToken);
+ }
+ else
+ {
+ Write((short)encodedToken);
+ }
+ }
+
+ internal void WriteImplementation(int token)
+ {
+ switch (token >> 24)
+ {
+ case 0:
+ break;
+ case TableHeap.FileTable.Index:
+ token = (token & 0xFFFFFF) << 2 | 0;
+ break;
+ case TableHeap.AssemblyRefTable.Index:
+ token = (token & 0xFFFFFF) << 2 | 1;
+ break;
+ case TableHeap.ExportedTypeTable.Index:
+ token = (token & 0xFFFFFF) << 2 | 2;
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ if (moduleBuilder.bigImplementation)
+ {
+ Write(token);
+ }
+ else
+ {
+ Write((short)token);
+ }
+ }
+
+ internal void WriteTypeOrMethodDef(int encodedToken)
+ {
+ // NOTE because we've already had to do the encoding (to be able to sort the table)
+ // here we simple write the value
+ if (moduleBuilder.bigTypeOrMethodDef)
+ {
+ Write(encodedToken);
+ }
+ else
+ {
+ Write((short)encodedToken);
+ }
+ }
+
+ internal void WriteHasDeclSecurity(int encodedToken)
+ {
+ // NOTE because we've already had to do the encoding (to be able to sort the table)
+ // here we simple write the value
+ if (moduleBuilder.bigHasDeclSecurity)
+ {
+ Write(encodedToken);
+ }
+ else
+ {
+ Write((short)encodedToken);
+ }
+ }
+
+ internal void WriteMemberForwarded(int token)
+ {
+ switch (token >> 24)
+ {
+ case TableHeap.FieldTable.Index:
+ token = (token & 0xFFFFFF) << 1 | 0;
+ break;
+ case TableHeap.MethodDefTable.Index:
+ token = (token & 0xFFFFFF) << 1 | 1;
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ if (moduleBuilder.bigMemberForwarded)
+ {
+ Write(token);
+ }
+ else
+ {
+ Write((short)token);
+ }
+ }
+
+ internal void WriteHasFieldMarshal(int encodedToken)
+ {
+ // NOTE because we've already had to do the encoding (to be able to sort the table)
+ // here we simple write the value
+ if (moduleBuilder.bigHasFieldMarshal)
+ {
+ Write(encodedToken & 0xFFFFFF);
+ }
+ else
+ {
+ Write((short)encodedToken);
+ }
+ }
+ }
+}
diff --git a/refemit/Writer/ModuleWriter.cs b/refemit/Writer/ModuleWriter.cs
new file mode 100644
index 00000000..9bc88292
--- /dev/null
+++ b/refemit/Writer/ModuleWriter.cs
@@ -0,0 +1,394 @@
+/*
+ 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.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Security.Cryptography;
+using IKVM.Reflection.Emit;
+using IKVM.Reflection.Emit.Impl;
+
+namespace IKVM.Reflection.Emit.Writer
+{
+ static class ModuleWriter
+ {
+ private const int versionInfoResourceHeaderLength = 0x58;
+
+ internal static void WriteModule(string directory, StrongNameKeyPair keyPair, ModuleBuilder moduleBuilder, PEFileKinds fileKind, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine, ByteBuffer versionInfoData, int entryPointToken)
+ {
+ moduleBuilder.FixupMethodBodyTokens();
+
+ moduleBuilder.Tables.Module.Add(0, moduleBuilder.Strings.Add(moduleBuilder.moduleName), moduleBuilder.Guids.Add(Guid.NewGuid()), 0, 0);
+
+ if (moduleBuilder.UserStrings.IsEmpty)
+ {
+ // for compat with Ref.Emit, if there aren't any user strings, we add one
+ moduleBuilder.UserStrings.Add(" ");
+ }
+
+ string fileName = moduleBuilder.fileName;
+ if (directory != null)
+ {
+ fileName = Path.Combine(directory, fileName);
+ }
+ using (FileStream fs = new FileStream(fileName, FileMode.Create))
+ {
+ PEWriter writer = new PEWriter(fs);
+ switch (imageFileMachine)
+ {
+ case ImageFileMachine.I386:
+ writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386;
+ writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_32BIT_MACHINE;
+ break;
+ case ImageFileMachine.AMD64:
+ writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64;
+ writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE;
+ writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0;
+ writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ writer.Headers.OptionalHeader.SizeOfStackReserve = 0x400000;
+ writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000;
+ writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000;
+ break;
+ case ImageFileMachine.IA64:
+ writer.Headers.FileHeader.Machine = IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64;
+ writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_LARGE_ADDRESS_AWARE;
+ writer.Headers.FileHeader.SizeOfOptionalHeader = 0xF0;
+ writer.Headers.OptionalHeader.Magic = IMAGE_OPTIONAL_HEADER.IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ writer.Headers.OptionalHeader.SizeOfStackReserve = 0x400000;
+ writer.Headers.OptionalHeader.SizeOfStackCommit = 0x4000;
+ writer.Headers.OptionalHeader.SizeOfHeapCommit = 0x2000;
+ break;
+ default:
+ throw new ArgumentOutOfRangeException("imageFileName");
+ }
+ if (fileKind == PEFileKinds.Dll)
+ {
+ writer.Headers.FileHeader.Characteristics |= IMAGE_FILE_HEADER.IMAGE_FILE_DLL;
+ }
+
+ switch (fileKind)
+ {
+ case PEFileKinds.WindowApplication:
+ writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_GUI;
+ break;
+ default:
+ writer.Headers.OptionalHeader.Subsystem = IMAGE_OPTIONAL_HEADER.IMAGE_SUBSYSTEM_WINDOWS_CUI;
+ break;
+ }
+ writer.Headers.OptionalHeader.DllCharacteristics =
+ IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE |
+ IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_NO_SEH |
+ IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_NX_COMPAT |
+ IMAGE_OPTIONAL_HEADER.IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE;
+
+ CliHeader cliHeader = new CliHeader();
+ cliHeader.Cb = 0x48;
+ cliHeader.MajorRuntimeVersion = 2;
+ cliHeader.MinorRuntimeVersion = 5;
+ if ((portableExecutableKind & PortableExecutableKinds.ILOnly) != 0)
+ {
+ cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_ILONLY;
+ }
+ if ((portableExecutableKind & PortableExecutableKinds.Required32Bit) != 0)
+ {
+ cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_32BITREQUIRED;
+ }
+ if (keyPair != null)
+ {
+ cliHeader.Flags |= CliHeader.COMIMAGE_FLAGS_STRONGNAMESIGNED;
+ }
+ if (moduleBuilder.IsPseudoToken(entryPointToken))
+ {
+ entryPointToken = moduleBuilder.ResolvePseudoToken(entryPointToken);
+ }
+ cliHeader.EntryPointToken = (uint)entryPointToken;
+ TextSection code = new TextSection(writer, cliHeader, moduleBuilder);
+
+ // Import Directory
+ writer.Headers.OptionalHeader.DataDirectory[1].VirtualAddress = code.ImportDirectoryRVA;
+ writer.Headers.OptionalHeader.DataDirectory[1].Size = code.ImportDirectoryLength;
+
+ // Import Address Table Directory
+ writer.Headers.OptionalHeader.DataDirectory[12].VirtualAddress = code.ImportAddressTableRVA;
+ writer.Headers.OptionalHeader.DataDirectory[12].Size = code.ImportAddressTableLength;
+
+ // COM Descriptor Directory
+ writer.Headers.OptionalHeader.DataDirectory[14].VirtualAddress = code.ComDescriptorRVA;
+ writer.Headers.OptionalHeader.DataDirectory[14].Size = code.ComDescriptorLength;
+
+ // Debug Directory
+ if (code.DebugDirectoryLength != 0)
+ {
+ writer.Headers.OptionalHeader.DataDirectory[6].VirtualAddress = code.DebugDirectoryRVA;
+ writer.Headers.OptionalHeader.DataDirectory[6].Size = code.DebugDirectoryLength;
+ }
+
+ writer.Headers.FileHeader.NumberOfSections = 2;
+
+ if (moduleBuilder.initializedData.Length != 0)
+ {
+ writer.Headers.FileHeader.NumberOfSections++;
+ }
+
+ if (versionInfoData != null)
+ {
+ writer.Headers.FileHeader.NumberOfSections++;
+ }
+
+ SectionHeader text = new SectionHeader();
+ text.Name = ".text";
+ text.VirtualAddress = code.BaseRVA;
+ text.VirtualSize = (uint)code.Length;
+ text.PointerToRawData = code.PointerToRawData;
+ text.SizeOfRawData = writer.ToFileAlignment((uint)code.Length);
+ text.Characteristics = SectionHeader.IMAGE_SCN_CNT_CODE | SectionHeader.IMAGE_SCN_MEM_EXECUTE | SectionHeader.IMAGE_SCN_MEM_READ;
+
+ SectionHeader sdata = new SectionHeader();
+ sdata.Name = ".sdata";
+ sdata.VirtualAddress = text.VirtualAddress + writer.ToSectionAlignment(text.VirtualSize);
+ sdata.VirtualSize = (uint)moduleBuilder.initializedData.Length;
+ sdata.PointerToRawData = text.PointerToRawData + text.SizeOfRawData;
+ sdata.SizeOfRawData = writer.ToFileAlignment((uint)moduleBuilder.initializedData.Length);
+ sdata.Characteristics = SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_MEM_WRITE;
+
+ SectionHeader rsrc = new SectionHeader();
+ rsrc.Name = ".rsrc";
+ rsrc.VirtualAddress = sdata.VirtualAddress + writer.ToSectionAlignment(sdata.VirtualSize);
+ rsrc.PointerToRawData = sdata.PointerToRawData + sdata.SizeOfRawData;
+ if (versionInfoData != null)
+ {
+ rsrc.VirtualSize = (uint)versionInfoData.Length + versionInfoResourceHeaderLength;
+ rsrc.SizeOfRawData = writer.ToFileAlignment((uint)versionInfoData.Length + versionInfoResourceHeaderLength);
+ }
+ rsrc.Characteristics = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA;
+
+ if (rsrc.SizeOfRawData != 0)
+ {
+ // Resource Directory
+ writer.Headers.OptionalHeader.DataDirectory[2].VirtualAddress = rsrc.VirtualAddress;
+ writer.Headers.OptionalHeader.DataDirectory[2].Size = rsrc.VirtualSize;
+ }
+
+ SectionHeader reloc = new SectionHeader();
+ reloc.Name = ".reloc";
+ reloc.VirtualAddress = rsrc.VirtualAddress + writer.ToSectionAlignment(rsrc.VirtualSize);
+ reloc.VirtualSize = 12;
+ reloc.PointerToRawData = rsrc.PointerToRawData + rsrc.SizeOfRawData;
+ reloc.SizeOfRawData = writer.ToFileAlignment(reloc.VirtualSize);
+ reloc.Characteristics = SectionHeader.IMAGE_SCN_MEM_READ | SectionHeader.IMAGE_SCN_CNT_INITIALIZED_DATA | SectionHeader.IMAGE_SCN_MEM_DISCARDABLE;
+
+ // Base Relocation Directory
+ writer.Headers.OptionalHeader.DataDirectory[5].VirtualAddress = reloc.VirtualAddress;
+ writer.Headers.OptionalHeader.DataDirectory[5].Size = reloc.VirtualSize;
+
+ writer.Headers.OptionalHeader.SizeOfCode = text.SizeOfRawData;
+ writer.Headers.OptionalHeader.SizeOfInitializedData = sdata.SizeOfRawData + rsrc.SizeOfRawData + reloc.SizeOfRawData;
+ writer.Headers.OptionalHeader.SizeOfUninitializedData = 0;
+ writer.Headers.OptionalHeader.SizeOfImage = reloc.VirtualAddress + writer.ToSectionAlignment(reloc.VirtualSize);
+ writer.Headers.OptionalHeader.SizeOfHeaders = text.PointerToRawData;
+ writer.Headers.OptionalHeader.BaseOfCode = code.BaseRVA;
+ writer.Headers.OptionalHeader.BaseOfData = sdata.VirtualAddress;
+
+ if (imageFileMachine == ImageFileMachine.IA64)
+ {
+ // apparently for IA64 AddressOfEntryPoint points to the address of the entry point
+ // (i.e. there is an additional layer of indirection), so we add the offset to the pointer
+ writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA + 0x20;
+ }
+ else
+ {
+ writer.Headers.OptionalHeader.AddressOfEntryPoint = code.StartupStubRVA;
+ }
+
+ writer.WritePEHeaders();
+ writer.WriteSectionHeader(text);
+ if (sdata.SizeOfRawData != 0)
+ {
+ writer.WriteSectionHeader(sdata);
+ }
+ if (rsrc.SizeOfRawData != 0)
+ {
+ writer.WriteSectionHeader(rsrc);
+ }
+ writer.WriteSectionHeader(reloc);
+
+ MetadataWriter mw = new MetadataWriter(moduleBuilder, fs);
+
+ fs.Seek(text.PointerToRawData, SeekOrigin.Begin);
+ code.Write(mw, (int)sdata.VirtualAddress);
+
+ fs.Seek(sdata.PointerToRawData, SeekOrigin.Begin);
+ mw.Write(moduleBuilder.initializedData);
+
+ if (versionInfoData != null)
+ {
+ fs.Seek(rsrc.PointerToRawData, SeekOrigin.Begin);
+ WriteVersionInfoResource(mw, (int)rsrc.VirtualAddress, versionInfoData);
+ }
+
+ fs.Seek(reloc.PointerToRawData, SeekOrigin.Begin);
+ // .reloc section
+ uint pageRVA = code.StartupStubRVA & ~0xFFFU;
+ mw.Write(pageRVA); // PageRVA
+ mw.Write(0x000C); // Block Size
+ if (imageFileMachine == ImageFileMachine.I386)
+ {
+ mw.Write(0x3000 + code.StartupStubRVA - pageRVA + 2); // Type / Offset + padding
+ }
+ else if (imageFileMachine == ImageFileMachine.AMD64)
+ {
+ mw.Write(0xA000 + code.StartupStubRVA - pageRVA + 2); // Type / Offset + padding
+ }
+ else if (imageFileMachine == ImageFileMachine.IA64)
+ {
+ mw.Write((short)(0xA000 + code.StartupStubRVA - pageRVA + 0x20)); // Type / Offset
+ mw.Write((short)(0xA000 + code.StartupStubRVA - pageRVA + 0x28)); // Type / Offset
+ }
+
+ // file alignment
+ mw.Write(new byte[writer.Headers.OptionalHeader.FileAlignment - reloc.VirtualSize]);
+
+ // do the strong naming
+ if (keyPair != null)
+ {
+ StrongName(fs, keyPair, writer.HeaderSize, text.PointerToRawData, code.StrongNameSignatureRVA - text.VirtualAddress + text.PointerToRawData, code.StrongNameSignatureLength);
+ }
+ }
+
+ if (moduleBuilder.symbolWriter != null)
+ {
+ moduleBuilder.WriteSymbolTokenMap();
+ moduleBuilder.symbolWriter.Close();
+ }
+ }
+
+ private static void StrongName(FileStream fs, StrongNameKeyPair keyPair, uint headerLength, uint textSectionFileOffset, uint strongNameSignatureFileOffset, uint strongNameSignatureLength)
+ {
+ SHA1Managed hash = new SHA1Managed();
+ using (CryptoStream cs = new CryptoStream(Stream.Null, hash, CryptoStreamMode.Write))
+ {
+ fs.Seek(0, SeekOrigin.Begin);
+ byte[] buf = new byte[8192];
+ HashChunk(fs, cs, buf, (int)headerLength);
+ fs.Seek(textSectionFileOffset, SeekOrigin.Begin);
+ HashChunk(fs, cs, buf, (int)(strongNameSignatureFileOffset - textSectionFileOffset));
+ fs.Seek(strongNameSignatureLength, SeekOrigin.Current);
+ HashChunk(fs, cs, buf, (int)(fs.Length - (strongNameSignatureFileOffset + strongNameSignatureLength)));
+ }
+ using (RSA rsa = CryptoHack.CreateRSA(keyPair))
+ {
+ RSAPKCS1SignatureFormatter sign = new RSAPKCS1SignatureFormatter(rsa);
+ sign.SetHashAlgorithm("SHA1");
+ byte[] signature = sign.CreateSignature(hash.Hash);
+ Array.Reverse(signature);
+ Debug.Assert(signature.Length == strongNameSignatureLength);
+ fs.Seek(strongNameSignatureFileOffset, SeekOrigin.Begin);
+ fs.Write(signature, 0, signature.Length);
+ }
+
+ // compute the PE checksum
+ fs.Seek(0, SeekOrigin.Begin);
+ int count = (int)fs.Length / 4;
+ BinaryReader br = new BinaryReader(fs);
+ long sum = 0;
+ for (int i = 0; i < count; i++)
+ {
+ sum += br.ReadUInt32();
+ int carry = (int)(sum >> 32);
+ sum &= 0xFFFFFFFFU;
+ sum += carry;
+ }
+ while ((sum >> 16) != 0)
+ {
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ }
+ sum += fs.Length;
+
+ // write the PE checksum, note that it is always of offset 0xD8 in the file
+ ByteBuffer bb = new ByteBuffer(4);
+ bb.Write((int)sum);
+ fs.Seek(0xD8, SeekOrigin.Begin);
+ bb.WriteTo(fs);
+ }
+
+ internal static void HashChunk(FileStream fs, CryptoStream cs, byte[] buf, int length)
+ {
+ while (length > 0)
+ {
+ int read = fs.Read(buf, 0, Math.Min(buf.Length, length));
+ cs.Write(buf, 0, read);
+ length -= read;
+ }
+ }
+
+ private static void WriteVersionInfoResource(MetadataWriter mw, int rsrcRVA, ByteBuffer versionInfoData)
+ {
+ mw.Write(new byte[] {
+ 0x00, 0x00, 0x00, 0x00, // Characteristics
+ 0x00, 0x00, 0x00, 0x00, // Time/Date Stamp
+ 0x00, 0x00, // Major Version
+ 0x00, 0x00, // Minor Version
+ 0x00, 0x00, // Number of Name Entries
+ 0x01, 0x00, // Number of ID Entries
+
+ // Resource Directory Entry
+ 0x10, 0x00, 0x00, 0x00, // Integer ID
+ 0x18, 0x00, 0x00, 0x80, // Subdirectory RVA (offset 0x18)
+
+ // Resource Directory Table (at offset 0x18)
+ 0x00, 0x00, 0x00, 0x00, // Characterics
+ 0x00, 0x00, 0x00, 0x00, // Time/Date Stamp
+ 0x00, 0x00, // Major Version
+ 0x00, 0x00, // Minor Version
+ 0x00, 0x00, // Number of Name Entries
+ 0x01, 0x00, // Number of ID Entries
+
+ // Resource Directory Entry
+ 0x01, 0x00, 0x00, 0x00, // Integer ID
+ 0x30, 0x00, 0x00, 0x80, // Subdirectory RVA (offset 0x30)
+
+ // Resource Directory Table (at offset 0x30)
+ 0x00, 0x00, 0x00, 0x00, // Characterics
+ 0x00, 0x00, 0x00, 0x00, // Time/Date Stamp
+ 0x00, 0x00, // Major Version
+ 0x00, 0x00, // Minor Version
+ 0x00, 0x00, // Number of Name Entries
+ 0x01, 0x00, // Number of ID Entries
+
+ // Resource Directory Entry
+ 0x00, 0x00, 0x00, 0x00, // Integer ID
+ 0x48, 0x00, 0x00, 0x00, // Date Entry RVA (offset 0x48)
+ });
+
+ // Data Entry (at offset 0x48)
+ mw.Write(versionInfoResourceHeaderLength + rsrcRVA); // Data RVA
+ mw.Write(versionInfoData.Length); // Size
+ mw.Write(0); // Codepage
+ mw.Write(0); // Reserved
+
+ mw.Write(versionInfoData);
+ }
+ }
+}
diff --git a/refemit/Writer/PEWriter.cs b/refemit/Writer/PEWriter.cs
new file mode 100644
index 00000000..a2757f1d
--- /dev/null
+++ b/refemit/Writer/PEWriter.cs
@@ -0,0 +1,301 @@
+/*
+ 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.IO;
+using BYTE = System.Byte;
+using WORD = System.UInt16;
+using DWORD = System.UInt32;
+using ULONGLONG = System.UInt64;
+
+namespace IKVM.Reflection.Emit.Writer
+{
+ sealed class PEWriter
+ {
+ private readonly BinaryWriter bw;
+ private readonly IMAGE_NT_HEADERS hdr = new IMAGE_NT_HEADERS();
+
+ internal PEWriter(Stream stream)
+ {
+ bw = new BinaryWriter(stream);
+ WriteMSDOSHeader();
+ }
+
+ public IMAGE_NT_HEADERS Headers
+ {
+ get { return hdr; }
+ }
+
+ public uint HeaderSize
+ {
+ get
+ {
+ return (uint)
+ ((8 * 16) + // MSDOS header
+ 4 + // signature
+ 20 + // IMAGE_FILE_HEADER
+ hdr.FileHeader.SizeOfOptionalHeader +
+ hdr.FileHeader.NumberOfSections * 40);
+ }
+ }
+
+ private void WriteMSDOSHeader()
+ {
+ bw.Write(new byte[] {
+ 0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
+ 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
+ 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD,
+ 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68,
+ 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72,
+ 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F,
+ 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E,
+ 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20,
+ 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x0D, 0x0D, 0x0A,
+ 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ });
+ }
+
+ internal void WritePEHeaders()
+ {
+ bw.Write(hdr.Signature);
+
+ // IMAGE_FILE_HEADER
+ bw.Write(hdr.FileHeader.Machine);
+ bw.Write(hdr.FileHeader.NumberOfSections);
+ bw.Write(hdr.FileHeader.TimeDateStamp);
+ bw.Write(hdr.FileHeader.PointerToSymbolTable);
+ bw.Write(hdr.FileHeader.NumberOfSymbols);
+ bw.Write(hdr.FileHeader.SizeOfOptionalHeader);
+ bw.Write(hdr.FileHeader.Characteristics);
+
+ // IMAGE_OPTIONAL_HEADER
+ hdr.OptionalHeader.Write(bw);
+ }
+
+ internal void WriteSectionHeader(SectionHeader sectionHeader)
+ {
+ byte[] name = new byte[8];
+ System.Text.Encoding.UTF8.GetBytes(sectionHeader.Name, 0, sectionHeader.Name.Length, name, 0);
+ bw.Write(name);
+ bw.Write(sectionHeader.VirtualSize);
+ bw.Write(sectionHeader.VirtualAddress);
+ bw.Write(sectionHeader.SizeOfRawData);
+ bw.Write(sectionHeader.PointerToRawData);
+ bw.Write(sectionHeader.PointerToRelocations);
+ bw.Write(sectionHeader.PointerToLinenumbers);
+ bw.Write(sectionHeader.NumberOfRelocations);
+ bw.Write(sectionHeader.NumberOfLinenumbers);
+ bw.Write(sectionHeader.Characteristics);
+ }
+
+ internal uint ToFileAlignment(uint p)
+ {
+ return (p + (Headers.OptionalHeader.FileAlignment - 1)) & ~(Headers.OptionalHeader.FileAlignment - 1);
+ }
+
+ internal uint ToSectionAlignment(uint p)
+ {
+ return (p + (Headers.OptionalHeader.SectionAlignment - 1)) & ~(Headers.OptionalHeader.SectionAlignment - 1);
+ }
+ }
+
+ sealed class IMAGE_NT_HEADERS
+ {
+ public DWORD Signature = 0x00004550; // "PE\0\0"
+ public IMAGE_FILE_HEADER FileHeader = new IMAGE_FILE_HEADER();
+ public IMAGE_OPTIONAL_HEADER OptionalHeader = new IMAGE_OPTIONAL_HEADER();
+ }
+
+ sealed class IMAGE_FILE_HEADER
+ {
+ public const WORD IMAGE_FILE_MACHINE_I386 = 0x014c;
+ public const WORD IMAGE_FILE_MACHINE_IA64 = 0x0200;
+ public const WORD IMAGE_FILE_MACHINE_AMD64 = 0x8664;
+
+ public const WORD IMAGE_FILE_32BIT_MACHINE = 0x0100;
+ public const WORD IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002;
+ public const WORD IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020;
+ public const WORD IMAGE_FILE_DLL = 0x2000;
+
+ public WORD Machine;
+ public WORD NumberOfSections;
+ public DWORD TimeDateStamp = (uint)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds;
+ public DWORD PointerToSymbolTable = 0;
+ public DWORD NumberOfSymbols = 0;
+ public WORD SizeOfOptionalHeader = 0xE0;
+ public WORD Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE;
+ }
+
+ sealed class IMAGE_OPTIONAL_HEADER
+ {
+ public const WORD IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
+ public const WORD IMAGE_NT_OPTIONAL_HDR64_MAGIC = 0x20b;
+
+ public const WORD IMAGE_SUBSYSTEM_WINDOWS_GUI = 2;
+ public const WORD IMAGE_SUBSYSTEM_WINDOWS_CUI = 3;
+
+ public const WORD IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040;
+ public const WORD IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100;
+ public const WORD IMAGE_DLLCHARACTERISTICS_NO_SEH = 0x0400;
+ public const WORD IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 0x8000;
+
+ public WORD Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
+ public BYTE MajorLinkerVersion = 8;
+ public BYTE MinorLinkerVersion = 0;
+ public DWORD SizeOfCode;
+ public DWORD SizeOfInitializedData;
+ public DWORD SizeOfUninitializedData;
+ public DWORD AddressOfEntryPoint;
+ public DWORD BaseOfCode;
+ public DWORD BaseOfData;
+ public ULONGLONG ImageBase = 0x00400000;
+ public DWORD SectionAlignment = 0x2000;
+ public DWORD FileAlignment = 0x200;
+ public WORD MajorOperatingSystemVersion = 4;
+ public WORD MinorOperatingSystemVersion = 0;
+ public WORD MajorImageVersion = 0;
+ public WORD MinorImageVersion = 0;
+ public WORD MajorSubsystemVersion = 4;
+ public WORD MinorSubsystemVersion = 0;
+ public DWORD Win32VersionValue = 0;
+ public DWORD SizeOfImage;
+ public DWORD SizeOfHeaders;
+ public DWORD CheckSum = 0;
+ public WORD Subsystem;
+ public WORD DllCharacteristics;
+ public ULONGLONG SizeOfStackReserve = 0x100000;
+ public ULONGLONG SizeOfStackCommit = 0x1000;
+ public ULONGLONG SizeOfHeapReserve = 0x100000;
+ public ULONGLONG SizeOfHeapCommit = 0x1000;
+ public DWORD LoaderFlags = 0;
+ public DWORD NumberOfRvaAndSizes = 16;
+ public IMAGE_DATA_DIRECTORY[] DataDirectory = new IMAGE_DATA_DIRECTORY[16];
+
+ internal void Write(BinaryWriter bw)
+ {
+ bw.Write(Magic);
+ bw.Write(MajorLinkerVersion);
+ bw.Write(MinorLinkerVersion);
+ bw.Write(SizeOfCode);
+ bw.Write(SizeOfInitializedData);
+ bw.Write(SizeOfUninitializedData);
+ bw.Write(AddressOfEntryPoint);
+ bw.Write(BaseOfCode);
+ if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+ {
+ bw.Write(BaseOfData);
+ bw.Write((DWORD)ImageBase);
+ }
+ else
+ {
+ bw.Write(ImageBase);
+ }
+ bw.Write(SectionAlignment);
+ bw.Write(FileAlignment);
+ bw.Write(MajorOperatingSystemVersion);
+ bw.Write(MinorOperatingSystemVersion);
+ bw.Write(MajorImageVersion);
+ bw.Write(MinorImageVersion);
+ bw.Write(MajorSubsystemVersion);
+ bw.Write(MinorSubsystemVersion);
+ bw.Write(Win32VersionValue);
+ bw.Write(SizeOfImage);
+ bw.Write(SizeOfHeaders);
+ bw.Write(CheckSum);
+ bw.Write(Subsystem);
+ bw.Write(DllCharacteristics);
+ if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+ {
+ bw.Write((DWORD)SizeOfStackReserve);
+ }
+ else
+ {
+ bw.Write(SizeOfStackReserve);
+ }
+ if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+ {
+ bw.Write((DWORD)SizeOfStackCommit);
+ }
+ else
+ {
+ bw.Write(SizeOfStackCommit);
+ }
+ if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+ {
+ bw.Write((DWORD)SizeOfHeapReserve);
+ }
+ else
+ {
+ bw.Write(SizeOfHeapReserve);
+ }
+ if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+ {
+ bw.Write((DWORD)SizeOfHeapCommit);
+ }
+ else
+ {
+ bw.Write(SizeOfHeapCommit);
+ }
+ bw.Write(LoaderFlags);
+ bw.Write(NumberOfRvaAndSizes);
+ for (int i = 0; i < DataDirectory.Length; i++)
+ {
+ bw.Write(DataDirectory[i].VirtualAddress);
+ bw.Write(DataDirectory[i].Size);
+ }
+ }
+ }
+
+ struct IMAGE_DATA_DIRECTORY
+ {
+ public DWORD VirtualAddress;
+ public DWORD Size;
+ }
+
+ class SectionHeader
+ {
+ public const DWORD IMAGE_SCN_CNT_CODE = 0x00000020;
+ public const DWORD IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
+ public const DWORD IMAGE_SCN_MEM_DISCARDABLE = 0x02000000;
+ public const DWORD IMAGE_SCN_MEM_EXECUTE = 0x20000000;
+ public const DWORD IMAGE_SCN_MEM_READ = 0x40000000;
+ public const DWORD IMAGE_SCN_MEM_WRITE = 0x80000000;
+
+ public string Name; // 8 byte UTF8 encoded 0-padded
+ public DWORD VirtualSize;
+ public DWORD VirtualAddress;
+ public DWORD SizeOfRawData;
+ public DWORD PointerToRawData;
+ public DWORD PointerToRelocations = 0;
+ public DWORD PointerToLinenumbers = 0;
+ public WORD NumberOfRelocations = 0;
+ public WORD NumberOfLinenumbers = 0;
+ public DWORD Characteristics;
+ }
+}
diff --git a/refemit/Writer/TextSection.cs b/refemit/Writer/TextSection.cs
new file mode 100644
index 00000000..a2007074
--- /dev/null
+++ b/refemit/Writer/TextSection.cs
@@ -0,0 +1,490 @@
+/*
+ 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.Diagnostics;
+using System.IO;
+using System.Collections.Generic;
+using System.Text;
+using IKVM.Reflection.Emit.Impl;
+
+namespace IKVM.Reflection.Emit.Writer
+{
+ sealed class TextSection
+ {
+ private readonly PEWriter peWriter;
+ private readonly CliHeader cliHeader;
+ private readonly ModuleBuilder moduleBuilder;
+
+ internal TextSection(PEWriter peWriter, CliHeader cliHeader, ModuleBuilder moduleBuilder)
+ {
+ this.peWriter = peWriter;
+ this.cliHeader = cliHeader;
+ this.moduleBuilder = moduleBuilder;
+ moduleBuilder.Freeze();
+ }
+
+ internal uint PointerToRawData
+ {
+ get { return peWriter.ToFileAlignment(peWriter.HeaderSize); }
+ }
+
+ internal uint BaseRVA
+ {
+ get { return 0x2000; }
+ }
+
+ internal uint ImportAddressTableRVA
+ {
+ get { return BaseRVA; }
+ }
+
+ internal uint ImportAddressTableLength
+ {
+ get
+ {
+ if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
+ {
+ return 8;
+ }
+ else
+ {
+ return 16;
+ }
+ }
+ }
+
+ internal uint ComDescriptorRVA
+ {
+ get { return ImportAddressTableRVA + ImportAddressTableLength; }
+ }
+
+ internal uint ComDescriptorLength
+ {
+ get { return cliHeader.Cb; }
+ }
+
+ internal uint MethodBodiesRVA
+ {
+ get { return (ComDescriptorRVA + ComDescriptorLength + 7) & ~7U; }
+ }
+
+ private uint MethodBodiesLength
+ {
+ get { return (uint)moduleBuilder.methodBodies.Length; }
+ }
+
+ private uint ResourcesRVA
+ {
+ get
+ {
+ if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
+ {
+ return (MethodBodiesRVA + MethodBodiesLength + 3) & ~3U;
+ }
+ else
+ {
+ return (MethodBodiesRVA + MethodBodiesLength + 15) & ~15U;
+ }
+ }
+ }
+
+ private uint ResourcesLength
+ {
+ get { return (uint)moduleBuilder.manifestResources.Length; }
+ }
+
+ internal uint StrongNameSignatureRVA
+ {
+ get
+ {
+ return (ResourcesRVA + ResourcesLength + 3) & ~3U;
+ }
+ }
+
+ internal uint StrongNameSignatureLength
+ {
+ get
+ {
+ if ((cliHeader.Flags & CliHeader.COMIMAGE_FLAGS_STRONGNAMESIGNED) != 0)
+ {
+ return 128;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ }
+
+ private uint MetadataRVA
+ {
+ get
+ {
+ return (StrongNameSignatureRVA + StrongNameSignatureLength + 3) & ~3U;
+ }
+ }
+
+ private uint MetadataLength
+ {
+ get { return (uint)moduleBuilder.MetadataLength; }
+ }
+
+ internal uint DebugDirectoryRVA
+ {
+ get { return MetadataRVA + MetadataLength; }
+ }
+
+ internal uint DebugDirectoryLength
+ {
+ get
+ {
+ if (moduleBuilder.symbolWriter != null)
+ {
+ return 28;
+ }
+ return 0;
+ }
+ }
+
+ private uint DebugDirectoryContentsLength
+ {
+ get
+ {
+ if (moduleBuilder.symbolWriter != null)
+ {
+ PdbSupport.IMAGE_DEBUG_DIRECTORY idd = new PdbSupport.IMAGE_DEBUG_DIRECTORY();
+ return (uint)PdbSupport.GetDebugInfo(moduleBuilder.symbolWriter, ref idd).Length;
+ }
+ return 0;
+ }
+ }
+
+ internal uint ImportDirectoryRVA
+ {
+ get { return (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength + 3) & ~3U; }
+ }
+
+ internal uint ImportDirectoryLength
+ {
+ get { return (ImportHintNameTableRVA - ImportDirectoryRVA) + 27; }
+ }
+
+ private uint ImportHintNameTableRVA
+ {
+ get
+ {
+ if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
+ {
+ return (ImportDirectoryRVA + 48 + 15) & ~15U;
+ }
+ else
+ {
+ return (ImportDirectoryRVA + 48 + 4 + 15) & ~15U;
+ }
+ }
+ }
+
+ internal uint StartupStubRVA
+ {
+ get
+ {
+ if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64)
+ {
+ return (ImportDirectoryRVA + ImportDirectoryLength + 15U) & ~15U;
+ }
+ else
+ {
+ // the additional 2 bytes padding are to align the address in the jump (which is a relocation fixup)
+ return 2 + ((ImportDirectoryRVA + ImportDirectoryLength + 3U) & ~3U);
+ }
+ }
+ }
+
+ internal uint StartupStubLength
+ {
+ get
+ {
+ if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64)
+ {
+ return 12;
+ }
+ else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64)
+ {
+ return 48;
+ }
+ else
+ {
+ return 6;
+ }
+ }
+ }
+
+ private void WriteRVA(MetadataWriter mw, uint rva)
+ {
+ if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
+ {
+ mw.Write(rva);
+ }
+ else
+ {
+ mw.Write((ulong)rva);
+ }
+ }
+
+ internal void Write(MetadataWriter mw, int sdataRVA)
+ {
+ // Now that we're ready to start writing, we need to do some fix ups
+ moduleBuilder.Tables.MethodDef.Fixup(this);
+ moduleBuilder.Tables.MethodImpl.Fixup(moduleBuilder);
+ moduleBuilder.Tables.MethodSemantics.Fixup(moduleBuilder);
+ moduleBuilder.Tables.InterfaceImpl.Fixup(moduleBuilder);
+ moduleBuilder.Tables.Constant.Fixup(moduleBuilder);
+ moduleBuilder.Tables.FieldMarshal.Fixup(moduleBuilder);
+ moduleBuilder.Tables.DeclSecurity.Fixup(moduleBuilder);
+ moduleBuilder.Tables.CustomAttribute.Fixup(moduleBuilder);
+ moduleBuilder.Tables.FieldLayout.Fixup(moduleBuilder);
+ moduleBuilder.Tables.FieldRVA.Fixup(moduleBuilder, sdataRVA);
+ moduleBuilder.Tables.ImplMap.Fixup(moduleBuilder);
+ moduleBuilder.Tables.GenericParam.Fixup(moduleBuilder);
+ moduleBuilder.Tables.MethodSpec.Fixup(moduleBuilder);
+ moduleBuilder.Tables.GenericParamConstraint.Fixup(moduleBuilder);
+
+ // Import Address Table
+ AssertRVA(mw, ImportAddressTableRVA);
+ WriteRVA(mw, ImportHintNameTableRVA);
+ WriteRVA(mw, 0);
+
+ // CLI Header
+ AssertRVA(mw, ComDescriptorRVA);
+ cliHeader.MetaDataRVA = MetadataRVA;
+ cliHeader.MetaDataSize = MetadataLength;
+ if (ResourcesLength != 0)
+ {
+ cliHeader.ResourcesRVA = ResourcesRVA;
+ cliHeader.ResourcesSize = ResourcesLength;
+ }
+ if (StrongNameSignatureLength != 0)
+ {
+ cliHeader.StrongNameSignatureRVA = StrongNameSignatureRVA;
+ cliHeader.StrongNameSignatureSize = StrongNameSignatureLength;
+ }
+ cliHeader.Write(mw);
+
+ // alignment padding
+ for (int i = (int)(MethodBodiesRVA - (ComDescriptorRVA + ComDescriptorLength)); i > 0; i--)
+ {
+ mw.Write((byte)0);
+ }
+
+ // Method Bodies
+ mw.Write(moduleBuilder.methodBodies);
+
+ // alignment padding
+ for (int i = (int)(ResourcesRVA - (MethodBodiesRVA + MethodBodiesLength)); i > 0; i--)
+ {
+ mw.Write((byte)0);
+ }
+
+ // Resources
+ mw.Write(moduleBuilder.manifestResources);
+
+ // The strong name signature live here (if it exists), but it will written later
+ // and the following alignment padding will take care of reserving the space.
+
+ // alignment padding
+ for (int i = (int)(MetadataRVA - (ResourcesRVA + ResourcesLength)); i > 0; i--)
+ {
+ mw.Write((byte)0);
+ }
+
+ // Metadata
+ AssertRVA(mw, MetadataRVA);
+ moduleBuilder.WriteMetadata(mw);
+
+ // Debug Directory
+ AssertRVA(mw, DebugDirectoryRVA);
+ WriteDebugDirectory(mw);
+
+ // alignment padding
+ for (int i = (int)(ImportDirectoryRVA - (DebugDirectoryRVA + DebugDirectoryLength + DebugDirectoryContentsLength)); i > 0; i--)
+ {
+ mw.Write((byte)0);
+ }
+
+ // Import Directory
+ AssertRVA(mw, ImportDirectoryRVA);
+ WriteImportDirectory(mw);
+
+ // alignment padding
+ for (int i = (int)(StartupStubRVA - (ImportDirectoryRVA + ImportDirectoryLength)); i > 0; i--)
+ {
+ mw.Write((byte)0);
+ }
+
+ // Startup Stub
+ AssertRVA(mw, StartupStubRVA);
+ if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_AMD64)
+ {
+ /*
+ * 48 A1 00 20 40 00 00 00 00 00 mov rax,qword ptr [0000000000402000h]
+ * FF E0 jmp rax
+ */
+ mw.Write((ushort)0xA148);
+ mw.Write(peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA);
+ mw.Write((ushort)0xE0FF);
+ }
+ else if (peWriter.Headers.FileHeader.Machine == IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_IA64)
+ {
+ mw.Write(new byte[] {
+ 0x0B, 0x48, 0x00, 0x02, 0x18, 0x10, 0xA0, 0x40, 0x24, 0x30, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00,
+ 0x10, 0x08, 0x00, 0x12, 0x18, 0x10, 0x60, 0x50, 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0x80, 0x00
+ });
+ mw.Write(peWriter.Headers.OptionalHeader.ImageBase + StartupStubRVA);
+ mw.Write(peWriter.Headers.OptionalHeader.ImageBase + BaseRVA);
+ }
+ else
+ {
+ mw.Write((ushort)0x25FF);
+ mw.Write((uint)peWriter.Headers.OptionalHeader.ImageBase + ImportAddressTableRVA);
+ }
+ }
+
+ [Conditional("DEBUG")]
+ private void AssertRVA(MetadataWriter mw, uint rva)
+ {
+ Debug.Assert(mw.Position - PointerToRawData + BaseRVA == rva);
+ }
+
+ private void WriteDebugDirectory(MetadataWriter mw)
+ {
+ if (moduleBuilder.symbolWriter != null)
+ {
+ PdbSupport.IMAGE_DEBUG_DIRECTORY idd = new PdbSupport.IMAGE_DEBUG_DIRECTORY();
+ idd.Characteristics = 0;
+ idd.TimeDateStamp = peWriter.Headers.FileHeader.TimeDateStamp;
+ byte[] buf = PdbSupport.GetDebugInfo(moduleBuilder.symbolWriter, ref idd);
+ idd.PointerToRawData = (DebugDirectoryRVA - BaseRVA) + DebugDirectoryLength + PointerToRawData;
+ mw.Write(idd.Characteristics);
+ mw.Write(idd.TimeDateStamp);
+ mw.Write(idd.MajorVersion);
+ mw.Write(idd.MinorVersion);
+ mw.Write(idd.Type);
+ mw.Write(idd.SizeOfData);
+ mw.Write(idd.AddressOfRawData);
+ mw.Write(idd.PointerToRawData);
+ mw.Write(buf);
+ }
+ }
+
+ private void WriteImportDirectory(MetadataWriter mw)
+ {
+ mw.Write(ImportDirectoryRVA + 40); // ImportLookupTable
+ mw.Write(0); // DateTimeStamp
+ mw.Write(0); // ForwarderChain
+ mw.Write(ImportHintNameTableRVA + 14); // Name
+ mw.Write(ImportAddressTableRVA);
+ mw.Write(new byte[20]);
+ // Import Lookup Table
+ mw.Write(ImportHintNameTableRVA); // Hint/Name Table RVA
+ int size = 48;
+ if (peWriter.Headers.FileHeader.Machine != IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE_I386)
+ {
+ size += 4;
+ mw.Write(0);
+ }
+ mw.Write(0);
+
+ // alignment padding
+ for (int i = (int)(ImportHintNameTableRVA - (ImportDirectoryRVA + size)); i > 0; i--)
+ {
+ mw.Write((byte)0);
+ }
+
+ // Hint/Name Table
+ AssertRVA(mw, ImportHintNameTableRVA);
+ mw.Write((ushort)0); // Hint
+ if ((peWriter.Headers.FileHeader.Characteristics & IMAGE_FILE_HEADER.IMAGE_FILE_DLL) != 0)
+ {
+ mw.Write(System.Text.Encoding.ASCII.GetBytes("_CorDllMain"));
+ }
+ else
+ {
+ mw.Write(System.Text.Encoding.ASCII.GetBytes("_CorExeMain"));
+ }
+ mw.Write((byte)0);
+ // Name
+ mw.Write(System.Text.Encoding.ASCII.GetBytes("mscoree.dll"));
+ mw.Write((ushort)0);
+ }
+
+ internal int Length
+ {
+ get { return (int)(StartupStubRVA - BaseRVA + StartupStubLength); }
+ }
+ }
+
+ class CliHeader
+ {
+ internal const uint COMIMAGE_FLAGS_ILONLY = 0x00000001;
+ internal const uint COMIMAGE_FLAGS_32BITREQUIRED = 0x00000002;
+ internal const uint COMIMAGE_FLAGS_STRONGNAMESIGNED = 0x00000008;
+
+ internal uint Cb = 0x48;
+ internal ushort MajorRuntimeVersion;
+ internal ushort MinorRuntimeVersion;
+ internal uint MetaDataRVA;
+ internal uint MetaDataSize;
+ internal uint Flags;
+ internal uint EntryPointToken;
+ internal uint ResourcesRVA;
+ internal uint ResourcesSize;
+ internal uint StrongNameSignatureRVA;
+ internal uint StrongNameSignatureSize;
+ internal ulong CodeManagerTable = 0;
+ internal uint VTableFixupsRVA = 0;
+ internal uint VTableFixupsSize = 0;
+ internal ulong ExportAddressTableJumps = 0;
+ internal ulong ManagedNativeHeader = 0;
+
+ internal void Write(MetadataWriter mw)
+ {
+ mw.Write(Cb);
+ mw.Write(MajorRuntimeVersion);
+ mw.Write(MinorRuntimeVersion);
+ mw.Write(MetaDataRVA);
+ mw.Write(MetaDataSize);
+ mw.Write(Flags);
+ mw.Write(EntryPointToken);
+ mw.Write(ResourcesRVA);
+ mw.Write(ResourcesSize);
+ mw.Write(StrongNameSignatureRVA);
+ mw.Write(StrongNameSignatureSize);
+ mw.Write(CodeManagerTable);
+ mw.Write(VTableFixupsRVA);
+ mw.Write(VTableFixupsSize);
+ mw.Write(ExportAddressTableJumps);
+ mw.Write(ManagedNativeHeader);
+ }
+ }
+}
diff --git a/refemit/Writer/VersionInfo.cs b/refemit/Writer/VersionInfo.cs
new file mode 100644
index 00000000..925fadf9
--- /dev/null
+++ b/refemit/Writer/VersionInfo.cs
@@ -0,0 +1,244 @@
+/*
+ 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.Reflection;
+using System.Globalization;
+
+namespace IKVM.Reflection.Emit.Writer
+{
+ sealed class VersionInfo
+ {
+ private AssemblyName name;
+ private string fileName;
+ private string copyright;
+ private string trademark;
+ private string product;
+ private string company;
+ private string description;
+ private string title;
+ private string informationalVersion;
+ private string culture;
+ private string fileVersion;
+
+ internal void SetName(AssemblyName name)
+ {
+ this.name = name;
+ }
+
+ internal void SetFileName(string assemblyFileName)
+ {
+ this.fileName = assemblyFileName;
+ }
+
+ internal void SetAttribute(CustomAttributeBuilder cab)
+ {
+ Type type = cab.Constructor.DeclaringType;
+ if (type == typeof(AssemblyCopyrightAttribute))
+ {
+ copyright = (string)cab.GetConstructorArgument(0);
+ }
+ else if (type == typeof(AssemblyTrademarkAttribute))
+ {
+ trademark = (string)cab.GetConstructorArgument(0);
+ }
+ else if (type == typeof(AssemblyProductAttribute))
+ {
+ product = (string)cab.GetConstructorArgument(0);
+ }
+ else if (type == typeof(AssemblyCompanyAttribute))
+ {
+ company = (string)cab.GetConstructorArgument(0);
+ }
+ else if (type == typeof(AssemblyDescriptionAttribute))
+ {
+ description = (string)cab.GetConstructorArgument(0);
+ }
+ else if (type == typeof(AssemblyTitleAttribute))
+ {
+ title = (string)cab.GetConstructorArgument(0);
+ }
+ else if (type == typeof(AssemblyInformationalVersionAttribute))
+ {
+ informationalVersion = (string)cab.GetConstructorArgument(0);
+ }
+ else if (type == typeof(AssemblyCultureAttribute))
+ {
+ culture = (string)cab.GetConstructorArgument(0);
+ }
+ else if (type == typeof(AssemblyFileVersionAttribute))
+ {
+ fileVersion = (string)cab.GetConstructorArgument(0);
+ }
+ }
+
+ internal void Write(ByteBuffer bb)
+ {
+ if (fileVersion == null)
+ {
+ if (name.Version != null)
+ {
+ fileVersion = name.Version.ToString();
+ }
+ else
+ {
+ fileVersion = "0.0.0.0";
+ }
+ }
+
+ int codepage = 1200; // Unicode codepage
+ int lcid = 0x7f;
+ if (name.CultureInfo != null)
+ {
+ lcid = name.CultureInfo.LCID;
+ }
+ if (culture != null)
+ {
+ lcid = new CultureInfo(culture).LCID;
+ }
+
+ Version filever = new Version(fileVersion);
+ int fileVersionMajor = filever.Major;
+ int fileVersionMinor = filever.Minor;
+ int fileVersionBuild = filever.Build;
+ int fileVersionRevision = filever.Revision;
+
+ int productVersionMajor = 0;
+ int productVersionMinor = 0;
+ int productVersionBuild = 0;
+ int productVersionRevision = 0;
+ if (informationalVersion != null)
+ {
+ Version productver = new Version(informationalVersion);
+ productVersionMajor = productver.Major;
+ productVersionMinor = productver.Minor;
+ productVersionBuild = productver.Build;
+ productVersionRevision = productver.Revision;
+ }
+
+ ByteBuffer stringTable = new ByteBuffer(512);
+ stringTable.Write((short)0); // wLength (placeholder)
+ stringTable.Write((short)0); // wValueLength
+ stringTable.Write((short)1); // wType
+ WriteUTF16Z(stringTable, string.Format("{0:x4}{1:x4}", lcid, codepage));
+ stringTable.Align(4);
+
+ WriteString(stringTable, "Comments", description);
+ WriteString(stringTable, "CompanyName", company);
+ WriteString(stringTable, "FileDescription", title);
+ WriteString(stringTable, "FileVersion", fileVersion);
+ WriteString(stringTable, "InternalName", name.Name);
+ WriteString(stringTable, "LegalCopyright", copyright);
+ WriteString(stringTable, "LegalTrademarks", trademark);
+ WriteString(stringTable, "OriginalFilename", fileName);
+ WriteString(stringTable, "ProductName", product);
+ WriteString(stringTable, "ProductVersion", informationalVersion);
+
+ stringTable.Position = 0;
+ stringTable.Write((short)stringTable.Length);
+
+ ByteBuffer stringFileInfo = new ByteBuffer(512);
+ stringFileInfo.Write((short)0); // wLength (placeholder)
+ stringFileInfo.Write((short)0); // wValueLength
+ stringFileInfo.Write((short)1); // wType
+ WriteUTF16Z(stringFileInfo, "StringFileInfo");
+ stringFileInfo.Align(4);
+ stringFileInfo.Write(stringTable);
+ stringFileInfo.Position = 0;
+ stringFileInfo.Write((short)stringFileInfo.Length);
+
+ byte[] preamble1 = new byte[] {
+ // VS_VERSIONINFO (platform SDK)
+ 0x34, 0x00, // wValueLength
+ 0x00, 0x00, // wType
+ 0x56, 0x00, 0x53, 0x00, 0x5F, 0x00, 0x56, 0x00, 0x45, 0x00, 0x52, 0x00, 0x53, 0x00, 0x49, 0x00, 0x4F, 0x00, 0x4E, 0x00, 0x5F, 0x00, 0x49, 0x00, 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00, 0x00, 0x00, // "VS_VERSION_INFO\0"
+ 0x00, 0x00, // Padding1 (32 bit alignment)
+ // VS_FIXEDFILEINFO starts
+ 0xBD, 0x04, 0xEF, 0xFE, // dwSignature (0xFEEF04BD)
+ 0x00, 0x00, 0x01, 0x00, // dwStrucVersion
+ };
+ byte[] preamble2 = new byte[] {
+ 0x3F, 0x00, 0x00, 0x00, // dwFileFlagsMask (??)
+ 0x00, 0x00, 0x00, 0x00, // dwFileFlags (??)
+ 0x04, 0x00, 0x00, 0x00, // dwFileOS
+ 0x02, 0x00, 0x00, 0x00, // dwFileType
+ 0x00, 0x00, 0x00, 0x00, // dwFileSubtype
+ 0x00, 0x00, 0x00, 0x00, // dwFileDateMS
+ 0x00, 0x00, 0x00, 0x00, // dwFileDateLS
+ // Padding2 (32 bit alignment)
+ // VarFileInfo
+ 0x44, 0x00, // wLength
+ 0x00, 0x00, // wValueLength
+ 0x01, 0x00, // wType
+ 0x56, 0x00, 0x61, 0x00, 0x72, 0x00, 0x46, 0x00, 0x69, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x49, 0x00, 0x6E, 0x00, 0x66, 0x00, 0x6F, 0x00, 0x00, 0x00, // "VarFileInfo\0"
+ 0x00, 0x00, // Padding
+ // Var
+ 0x24, 0x00, // wLength
+ 0x04, 0x00, // wValueLength
+ 0x00, 0x00, // wType
+ 0x54, 0x00, 0x72, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x00, // "Translation\0"
+ 0x00, 0x00, // Padding (32 bit alignment)
+ };
+ bb.Write((short)(2 + preamble1.Length + 8 + 8 + preamble2.Length + 4 + stringFileInfo.Length));
+ bb.Write(preamble1);
+ bb.Write((short)fileVersionMinor);
+ bb.Write((short)fileVersionMajor);
+ bb.Write((short)fileVersionRevision);
+ bb.Write((short)fileVersionBuild);
+ bb.Write((short)productVersionMinor);
+ bb.Write((short)productVersionMajor);
+ bb.Write((short)productVersionRevision);
+ bb.Write((short)productVersionBuild);
+ bb.Write(preamble2);
+ bb.Write((short)lcid);
+ bb.Write((short)codepage);
+ bb.Write(stringFileInfo);
+ }
+
+ private void WriteUTF16Z(ByteBuffer bb, string str)
+ {
+ foreach (char c in str)
+ {
+ bb.Write((short)c);
+ }
+ bb.Write((short)0);
+ }
+
+ private void WriteString(ByteBuffer bb, string name, string value)
+ {
+ value = value ?? " ";
+ int pos = bb.Position;
+ bb.Write((short)0); // wLength (placeholder)
+ bb.Write((short)(value.Length + 1));// wValueLength
+ bb.Write((short)1); // wType
+ WriteUTF16Z(bb, name);
+ bb.Align(4);
+ WriteUTF16Z(bb, value);
+ bb.Align(4);
+ int savedPos = bb.Position;
+ bb.Position = pos;
+ bb.Write((short)(savedPos - pos));
+ bb.Position = savedPos;
+ }
+ }
+}
diff --git a/refemit/refemit.build b/refemit/refemit.build
new file mode 100644
index 00000000..afaa34a8
--- /dev/null
+++ b/refemit/refemit.build
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<project name="refemit" default="IKVM.Reflection.Emit">
+ <target name="IKVM.Reflection.Emit">
+ <property overwrite="false" name="signed" value="" />
+ <property name="defs" value="IKVM_REF_EMIT" />
+ <if test="${property::exists('signed')}">
+ <property name="defs" value="${defs};${signed}" />
+ </if>
+ <csc target="library" output="../bin/IKVM.Reflection.Emit.dll" define="${defs}">
+ <sources>
+ <include name="../CommonAssemblyInfo.cs" />
+ <include name="AssemblyBuilder.cs" />
+ <include name="ConstructorBuilder.cs" />
+ <include name="CustomAttributeBuilder.cs" />
+ <include name="Enums.cs" />
+ <include name="FieldBuilder.cs" />
+ <include name="IkvmAssembly.cs" />
+ <include name="ILGenerator.cs" />
+ <include name="MethodBuilder.cs" />
+ <include name="ModuleBuilder.cs" />
+ <include name="OpCodes.cs" />
+ <include name="ParameterBuilder.cs" />
+ <include name="PropertyBuilder.cs" />
+ <include name="SignatureHelper.cs" />
+ <include name="Tokens.cs" />
+ <include name="TypeBuilder.cs" />
+ <include name="impl/CryptoConvert.cs" />
+ <include name="impl/CryptoHack.cs" />
+ <include name="impl/ITypeOwner.cs" />
+ <include name="impl/PdbSupport.cs" />
+ <include name="impl/TypeBase.cs" />
+ <include name="Properties/AssemblyInfo.cs" />
+ <include name="Writer/ByteBuffer.cs" />
+ <include name="Writer/Heaps.cs" />
+ <include name="Writer/MetadataWriter.cs" />
+ <include name="Writer/ModuleWriter.cs" />
+ <include name="Writer/PEWriter.cs" />
+ <include name="Writer/TextSection.cs" />
+ <include name="Writer/VersionInfo.cs" />
+ </sources>
+ <references>
+ <include name="${framework::get-assembly-directory(framework::get-target-framework())}/ISymWrapper.dll" />
+ </references>
+ </csc>
+ </target>
+</project>