using System; using System.Collections.Generic; using System.Linq; using System.Text; using Indy.IL2CPU.Assembler; using System.Xml; using System.Reflection; namespace Indy.IL2CPU.IL { public class MethodBaseComparer : IComparer { #region IComparer Members public int Compare(MethodBase x, MethodBase y) { return x.GetFullName().CompareTo(y.GetFullName()); } #endregion } public abstract class InitVmtImplementationOp: Op { public delegate int GetMethodIdentifierEventHandler(MethodBase aMethod); public InitVmtImplementationOp(ILReader aReader, MethodInformation aMethodInfo) : base(aReader, aMethodInfo) { } private static readonly bool mDebugMode = false; static InitVmtImplementationOp() { // flag for conditional debug code for Matthijs, please leave it. mDebugMode = Environment.MachineName.Equals("laptop-matthijs", StringComparison.InvariantCultureIgnoreCase); } private IList mTypes; public MethodBase LoadTypeTableRef; public MethodBase SetTypeInfoRef; public MethodBase SetMethodInfoRef; public FieldInfo TypesFieldRef; public int VTableEntrySize; public uint ArrayTypeId; public IList Methods; public event GetMethodIdentifierEventHandler GetMethodIdentifier; public IList Types { get { return mTypes; } set { mTypes = value; } } protected abstract void Pushd(string aValue); protected abstract void Call(MethodBase aMethod); public override void DoAssemble() { XmlWriter xDebug=null; if (mDebugMode) { xDebug = XmlWriter.Create(@"d:\vtables.xml"); xDebug.WriteStartDocument(); xDebug.WriteStartElement("VTables"); xDebug.WriteStartElement("AllMethods"); for (int i = 0; i < Methods.Count; i++) { MethodBase xTheMethod = Methods[i]; xDebug.WriteStartElement("Method"); xDebug.WriteAttributeString("Id", GetMethodIdentifier(xTheMethod).ToString("X")); xDebug.WriteAttributeString("Name", xTheMethod.GetFullName()); xDebug.WriteEndElement(); } xDebug.WriteEndElement(); } string xTheName = DataMember.GetStaticFieldName(TypesFieldRef); DataMember xDataMember = (from item in Assembler.DataMembers where item.Value.Name == xTheName select item.Value).FirstOrDefault(); if (xDataMember != null) { Assembler.DataMembers.Remove((from item in Assembler.DataMembers where item.Value == xDataMember select item).First()); } StringBuilder xDataByteArray = new StringBuilder(); xDataByteArray.Append(BitConverter.GetBytes(ArrayTypeId).Aggregate("", (r, b) => r + b + ",")); xDataByteArray.Append(BitConverter.GetBytes((uint)0x80000002).Aggregate("", (r, b) => r + b + ",")); xDataByteArray.Append(BitConverter.GetBytes(mTypes.Count).Aggregate("", (r, b) => r + b + ",")); xDataByteArray.Append(BitConverter.GetBytes(VTableEntrySize).Aggregate("", (r, b) => r + b + ",")); for (uint i = 0; i < mTypes.Count; i++) { for (int j = 0; j < VTableEntrySize; j++) { xDataByteArray.Append("0,"); } } Assembler.DataMembers.Add(new KeyValuePair(Assembler.CurrentGroup, new DataMember(xTheName + "__Contents", "db", xDataByteArray.ToString().TrimEnd(',')))); Assembler.DataMembers.Add(new KeyValuePair(Assembler.CurrentGroup, new DataMember(xTheName, "dd", xTheName + "__Contents"))); Pushd("0" + mTypes.Count.ToString("X") + "h"); Call(LoadTypeTableRef); for (int i = 0; i < mTypes.Count; i++) { if (mDebugMode) { xDebug.WriteStartElement("Type"); xDebug.WriteAttributeString("Id", i.ToString("X")); xDebug.WriteAttributeString("Name", mTypes[i].FullName); } try { Type xType = mTypes[i]; if (xType.FullName == "MatthijsTest.TestImpl") { System.Diagnostics.Debugger.Break(); } // value contains true if the method is an interface method definition SortedList xEmittedMethods = new SortedList(new MethodBaseComparer()); foreach (MethodBase xMethod in xType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { if (Methods.Contains(xMethod) && !xMethod.IsAbstract) { xEmittedMethods.Add(xMethod, false); } } foreach (MethodBase xCtor in xType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { if (Methods.Contains(xCtor) && !xCtor.IsAbstract) { xEmittedMethods.Add(xCtor, false); } } foreach (var xIntf in xType.GetInterfaces()) { foreach (var xMethodIntf in xIntf.GetMethods()) { var xActualMethod = xType.GetMethod(xIntf.FullName + "." + xMethodIntf.Name, (from xParam in xMethodIntf.GetParameters() select xParam.ParameterType).ToArray()); if (xActualMethod == null) { // get private implemenation xActualMethod = xType.GetMethod(xMethodIntf.Name, (from xParam in xMethodIntf.GetParameters() select xParam.ParameterType).ToArray()); } if (xActualMethod == null) { try { var xMap = xType.GetInterfaceMap(xIntf); for (int k = 0; k < xMap.InterfaceMethods.Length; k++) { if (xMap.InterfaceMethods[k] == xMethodIntf) { xActualMethod = xMap.TargetMethods[k]; break; } } } catch { } } if (Methods.Contains(xMethodIntf)) { if (!xEmittedMethods.ContainsKey(xMethodIntf)) { xEmittedMethods.Add(xMethodIntf, true); } } } } if (!xType.IsInterface) { Pushd("0" + i.ToString("X") + "h"); } int? xBaseIndex = null; if (xType.BaseType == null) { xBaseIndex = i; } else { for (int t = 0; t < mTypes.Count; t++) { if (mTypes[t].ToString() == xType.BaseType.ToString()) { xBaseIndex = t; break; } } } if (xBaseIndex == null) { throw new Exception("Base type not found!"); } if (mDebugMode) { xDebug.WriteAttributeString("BaseId", xBaseIndex.Value.ToString("X")); } for (int x = xEmittedMethods.Count - 1; x >= 0; x--) { if (!Methods.Contains(xEmittedMethods.Keys[x])) { xEmittedMethods.RemoveAt(x); } } if (!xType.IsInterface) { Pushd("0" + xBaseIndex.Value.ToString("X") + "h"); //Pushd("0" + xEmittedMethods.Count.ToString("X") + "h"); xDataByteArray.Remove(0, xDataByteArray.Length); xDataByteArray.Append(BitConverter.GetBytes(ArrayTypeId).Aggregate("", (r, b) => r + b + ",")); xDataByteArray.Append(BitConverter.GetBytes(0x80000002 /* EmbeddedArray */).Aggregate("", (r, b) => r + b + ",")); xDataByteArray.Append(BitConverter.GetBytes(xEmittedMethods.Count).Aggregate("", (r, b) => r + b + ",")); xDataByteArray.Append("0,0,0,0,"); for (uint j = 0; j < xEmittedMethods.Count; j++) { xDataByteArray.Append("0,0,0,0,"); } string xDataValue = xDataByteArray.ToString(); string xDataName = "____SYSTEM____TYPE___" + DataMember.FilterStringForIncorrectChars(mTypes[i].FullName) + "__MethodIndexesArray"; Assembler.DataMembers.Add(new KeyValuePair(Assembler.CurrentGroup, new DataMember(xDataName, "db", xDataValue.TrimEnd(',')))); Pushd(xDataName); xDataName = "____SYSTEM____TYPE___" + DataMember.FilterStringForIncorrectChars(mTypes[i].FullName) + "__MethodAddressesArray"; Assembler.DataMembers.Add(new KeyValuePair(Assembler.CurrentGroup, new DataMember(xDataName, "db", xDataValue.TrimEnd(',')))); Pushd(xDataName); xDataByteArray.Remove(0, xDataByteArray.Length); xDataByteArray.Append(BitConverter.GetBytes(ArrayTypeId).Aggregate("", (r, b) => r + b + ",")); xDataByteArray.Append(BitConverter.GetBytes(0x80000002 /* EmbeddedArray */).Aggregate("", (r, b) => r + b + ",")); xDataByteArray.Append(BitConverter.GetBytes((mTypes[i].FullName + ", " + mTypes[i].Module.Assembly.GetName().FullName).Length).Aggregate("", (r, b) => r + b + ",")); xDataByteArray.Append(BitConverter.GetBytes((uint)2).Aggregate("", (r, b) => r + b + ",")); xDataByteArray.Append(Encoding.Unicode.GetBytes(mTypes[i].FullName + ", " + mTypes[i].Module.Assembly.GetName().FullName).Aggregate("", (b, x) => b + x + ",") + "0"); xDataName = "____SYSTEM____TYPE___" + DataMember.FilterStringForIncorrectChars(mTypes[i].FullName); mAssembler.DataMembers.Add(new KeyValuePair(Assembler.CurrentGroup, new DataMember(xDataName, "db", xDataByteArray.ToString()))); Pushd(xDataName); //Pushd("0"); Call(SetTypeInfoRef); } for (int j = 0; j < xEmittedMethods.Count; j++) { MethodBase xMethod = xEmittedMethods.Keys[j]; var xMethodId = GetMethodIdentifier(xMethod); if (mDebugMode) { xDebug.WriteStartElement("Method"); xDebug.WriteAttributeString("Id", xMethodId.ToString("X")); xDebug.WriteAttributeString("Name", xMethod.GetFullName()); xDebug.WriteEndElement(); } if (!xType.IsInterface) { if (xEmittedMethods.Values[j]) { var xNewMethod = xType.GetMethod(xMethod.DeclaringType.FullName + "." + xMethod.Name, (from xParam in xMethod.GetParameters() select xParam.ParameterType).ToArray()); if (xNewMethod == null) { // get private implemenation xNewMethod = xType.GetMethod(xMethod.Name, (from xParam in xMethod.GetParameters() select xParam.ParameterType).ToArray()); } if (xNewMethod == null) { try { var xMap = xType.GetInterfaceMap(xMethod.DeclaringType); for (int k = 0; k < xMap.InterfaceMethods.Length; k++) { if (xMap.InterfaceMethods[k] == xMethod) { xNewMethod = xMap.TargetMethods[k]; break; } } } catch { } } if (xNewMethod == null) { System.Diagnostics.Debugger.Break(); } xMethod = xNewMethod; } Pushd("0" + i.ToString("X") + "h"); Pushd("0" + j.ToString("X") + "h"); Pushd("0" + xMethodId.ToString("X") + "h"); Pushd(Label.GenerateLabelName(xMethod)); //xDataValue = Encoding.ASCII.GetBytes(GetFullName(xMethod)).Aggregate("", (b, x) => b + x + ",") + "0"; //xDataName = "____SYSTEM____METHOD___" + DataMember.FilterStringForIncorrectChars(GetFullName(xMethod)); //mAssembler.DataMembers.Add(new DataMember(xDataName, "db", xDataValue)); //Pushd(xDataName); Pushd("0"); Call(SetMethodInfoRef); } } } finally { if (mDebugMode) { xDebug.WriteEndElement(); } } } if (mDebugMode) { xDebug.Close(); } } } }