mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-20 21:08:51 +00:00
647 lines
32 KiB
C#
647 lines
32 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Reflection;
|
|
using Cosmos.IL2CPU.Plugs;
|
|
using System.Runtime.InteropServices;
|
|
using Cosmos.Compiler.Assembler;
|
|
|
|
namespace Cosmos.IL2CPU
|
|
{
|
|
public abstract class AppAssembler
|
|
{
|
|
protected ILOp[] mILOpsLo = new ILOp[256];
|
|
protected ILOp[] mILOpsHi = new ILOp[256];
|
|
|
|
private System.IO.TextWriter mLog;
|
|
|
|
protected readonly Assembler mAssembler;
|
|
public AppAssembler(Assembler assembler)
|
|
{
|
|
mAssembler = assembler;
|
|
mLog = new System.IO.StreamWriter("Cosmos.Assembler.Log");
|
|
InitILOps();
|
|
}
|
|
|
|
public Assembler Assembler
|
|
{
|
|
get
|
|
{
|
|
return mAssembler;
|
|
}
|
|
}
|
|
|
|
protected virtual void MethodBegin(MethodInfo aMethod)
|
|
{
|
|
new Comment("---------------------------------------------------------");
|
|
new Comment("Type: " + aMethod.MethodBase.DeclaringType.ToString());
|
|
new Comment("Name: " + aMethod.MethodBase.Name);
|
|
new Comment("Plugged: " + (aMethod.PlugMethod == null ? "No" : "Yes"));
|
|
}
|
|
|
|
protected virtual void MethodBegin(string aMethodName)
|
|
{
|
|
new Comment("---------------------------------------------------------");
|
|
new Comment("Name: " + aMethodName);
|
|
}
|
|
|
|
protected virtual void MethodEnd(string aMethodName)
|
|
{
|
|
new Comment("End Method: " + aMethodName);
|
|
}
|
|
|
|
protected virtual void MethodEnd(MethodInfo aMethod)
|
|
{
|
|
new Comment("End Method: " + aMethod.MethodBase.Name);
|
|
}
|
|
|
|
public void ProcessMethod(MethodInfo aMethod, List<ILOpCode> aOpCodes)
|
|
{
|
|
// We check this here and not scanner as when scanner makes these
|
|
// plugs may still have not yet been scanned that it will depend on.
|
|
// But by the time we make it here, they have to be resolved.
|
|
if (aMethod.Type == MethodInfo.TypeEnum.NeedsPlug && aMethod.PlugMethod == null)
|
|
{
|
|
throw new Exception("Method needs plug, but no plug was assigned.");
|
|
}
|
|
|
|
// todo: MtW: how to do this? we need some extra space.
|
|
// see ConstructLabel for extra info
|
|
if (aMethod.UID > 0x00FFFFFF)
|
|
{
|
|
throw new Exception("For now, too much methods");
|
|
}
|
|
|
|
MethodBegin(aMethod);
|
|
mAssembler.Stack.Clear();
|
|
mLog.WriteLine("Method '{0}'", aMethod.MethodBase.GetFullName());
|
|
mLog.Flush();
|
|
if (aMethod.MethodAssembler != null)
|
|
{
|
|
mLog.WriteLine("Emitted using MethodAssembler", aMethod.MethodBase.GetFullName());
|
|
mLog.Flush();
|
|
var xAssembler = (AssemblerMethod)Activator.CreateInstance(aMethod.MethodAssembler);
|
|
xAssembler.AssembleNew(mAssembler, aMethod.PluggedMethod);
|
|
}
|
|
else
|
|
{
|
|
foreach (var xOpCode in aOpCodes)
|
|
{
|
|
uint xOpCodeVal = (uint)xOpCode.OpCode;
|
|
ILOp xILOp;
|
|
if (xOpCodeVal <= 0xFF)
|
|
{
|
|
xILOp = mILOpsLo[xOpCodeVal];
|
|
}
|
|
else
|
|
{
|
|
xILOp = mILOpsHi[xOpCodeVal & 0xFF];
|
|
}
|
|
//mLog.WriteLine ( "\t[" + xILOp.ToString() + "] \t Stack start: " + Stack.Count.ToString() );
|
|
mLog.WriteLine("\t{0} {1}", mAssembler.Stack.Count, xILOp.GetType().Name);
|
|
mLog.Flush();
|
|
BeforeOp(aMethod, xOpCode);
|
|
new Comment("[" + xILOp.ToString() + "]");
|
|
var xNextPosition = xOpCode.Position + 1;
|
|
#region Exception handling support code
|
|
ExceptionHandlingClause xCurrentHandler = null;
|
|
var xBody = aMethod.MethodBase.GetMethodBody();
|
|
// todo: add support for nested handlers using a stack or so..
|
|
foreach (ExceptionHandlingClause xHandler in xBody.ExceptionHandlingClauses)
|
|
{
|
|
if (xHandler.TryOffset > 0)
|
|
{
|
|
if (xHandler.TryOffset <= xNextPosition && (xHandler.TryLength + xHandler.TryOffset) > xNextPosition)
|
|
{
|
|
if (xCurrentHandler == null)
|
|
{
|
|
xCurrentHandler = xHandler;
|
|
continue;
|
|
}
|
|
else if (xHandler.TryOffset > xCurrentHandler.TryOffset && (xHandler.TryLength + xHandler.TryOffset) < (xCurrentHandler.TryLength + xCurrentHandler.TryOffset))
|
|
{
|
|
// only replace if the current found handler is narrower
|
|
xCurrentHandler = xHandler;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (xHandler.HandlerOffset > 0)
|
|
{
|
|
if (xHandler.HandlerOffset <= xNextPosition && (xHandler.HandlerOffset + xHandler.HandlerLength) > xNextPosition)
|
|
{
|
|
if (xCurrentHandler == null)
|
|
{
|
|
xCurrentHandler = xHandler;
|
|
continue;
|
|
}
|
|
else if (xHandler.HandlerOffset > xCurrentHandler.HandlerOffset && (xHandler.HandlerOffset + xHandler.HandlerLength) < (xCurrentHandler.HandlerOffset + xCurrentHandler.HandlerLength))
|
|
{
|
|
// only replace if the current found handler is narrower
|
|
xCurrentHandler = xHandler;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if ((xHandler.Flags & ExceptionHandlingClauseOptions.Filter) > 0)
|
|
{
|
|
if (xHandler.FilterOffset > 0)
|
|
{
|
|
if (xHandler.FilterOffset <= xNextPosition)
|
|
{
|
|
if (xCurrentHandler == null)
|
|
{
|
|
xCurrentHandler = xHandler;
|
|
continue;
|
|
}
|
|
else if (xHandler.FilterOffset > xCurrentHandler.FilterOffset)
|
|
{
|
|
// only replace if the current found handler is narrower
|
|
xCurrentHandler = xHandler;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
var xNeedsExceptionPush = (xCurrentHandler != null) && (((xCurrentHandler.HandlerOffset > 0 && xCurrentHandler.HandlerOffset == xOpCode.Position) || ((xCurrentHandler.Flags & ExceptionHandlingClauseOptions.Filter) > 0 && xCurrentHandler.FilterOffset > 0 && xCurrentHandler.FilterOffset == xOpCode.Position)) && (xCurrentHandler.Flags == ExceptionHandlingClauseOptions.Clause));
|
|
if (xNeedsExceptionPush)
|
|
{
|
|
Push(0);
|
|
mAssembler.Stack.Push(4, typeof(Exception));
|
|
}
|
|
xILOp.Execute(aMethod, xOpCode);
|
|
AfterOp(aMethod, xOpCode);
|
|
//mLog.WriteLine( " end: " + Stack.Count.ToString() );
|
|
}
|
|
}
|
|
MethodEnd(aMethod);
|
|
}
|
|
|
|
//
|
|
|
|
protected virtual void BeforeOp(MethodInfo aMethod, ILOpCode aOpCode)
|
|
{
|
|
}
|
|
|
|
protected virtual void AfterOp(MethodInfo aMethod, ILOpCode aOpCode)
|
|
{
|
|
}
|
|
|
|
protected abstract void InitILOps();
|
|
|
|
protected virtual void InitILOps(Type aAssemblerBaseOp)
|
|
{
|
|
foreach (var xType in aAssemblerBaseOp.Assembly.GetExportedTypes())
|
|
{
|
|
if (xType.IsSubclassOf(aAssemblerBaseOp))
|
|
{
|
|
var xAttribs = (OpCodeAttribute[])xType.GetCustomAttributes(typeof(OpCodeAttribute), false);
|
|
foreach (var xAttrib in xAttribs)
|
|
{
|
|
var xOpCode = (ushort)xAttrib.OpCode;
|
|
var xCtor = xType.GetConstructor(new Type[] { typeof(Assembler) });
|
|
var xILOp = (ILOp)xCtor.Invoke(new Object[] { Assembler });
|
|
if (xOpCode <= 0xFF)
|
|
{
|
|
mILOpsLo[xOpCode] = xILOp;
|
|
}
|
|
else
|
|
{
|
|
mILOpsHi[xOpCode & 0xFF] = xILOp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected abstract void Push(uint aValue);
|
|
protected abstract void Push(string aLabelName);
|
|
protected abstract void Call(MethodBase aMethod);
|
|
protected abstract void Move(string aDestLabelName, int aValue);
|
|
protected abstract void Jump(string aLabelName);
|
|
protected abstract int GetVTableEntrySize();
|
|
|
|
|
|
public const string InitVMTCodeLabel = "___INIT__VMT__CODE____";
|
|
public void GenerateVMTCode(HashSet<Type> aTypesSet, HashSet<MethodBase> aMethodsSet, Func<Type, uint> aGetTypeID, Func<MethodBase, uint> aGetMethodUID)
|
|
{
|
|
// initialization
|
|
MethodBegin(InitVMTCodeLabel);
|
|
{
|
|
var xSetTypeInfoRef = VTablesImplRefs.SetTypeInfoRef;
|
|
var xSetMethodInfoRef = VTablesImplRefs.SetMethodInfoRef;
|
|
var xLoadTypeTableRef = VTablesImplRefs.LoadTypeTableRef;
|
|
var xTypesFieldRef = VTablesImplRefs.VTablesImplDef.GetField("mTypes",
|
|
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
|
|
string xTheName = DataMember.GetStaticFieldName(xTypesFieldRef);
|
|
DataMember xDataMember = (from item in Assembler.CurrentInstance.DataMembers
|
|
where item.Name == xTheName
|
|
select item).FirstOrDefault();
|
|
if (xDataMember != null)
|
|
{
|
|
Assembler.CurrentInstance.DataMembers.Remove((from item in Assembler.CurrentInstance.DataMembers
|
|
where item == xDataMember
|
|
select item).First());
|
|
}
|
|
var xData = new byte[16 + (aTypesSet.Count * GetVTableEntrySize())];
|
|
var xTemp = BitConverter.GetBytes(aGetTypeID(typeof(Array)));
|
|
xTemp = BitConverter.GetBytes(0x80000002);
|
|
Array.Copy(xTemp, 0, xData, 4, 4);
|
|
xTemp = BitConverter.GetBytes(aTypesSet.Count);
|
|
Array.Copy(xTemp, 0, xData, 8, 4);
|
|
xTemp = BitConverter.GetBytes(GetVTableEntrySize());
|
|
Array.Copy(xTemp, 0, xData, 12, 4);
|
|
Assembler.CurrentInstance.DataMembers.Add(new DataMember(xTheName + "__Contents", xData));
|
|
Assembler.CurrentInstance.DataMembers.Add(new DataMember(xTheName, ElementReference.New(xTheName + "__Contents")));
|
|
#if VMT_DEBUG
|
|
using (var xVmtDebugOutput = XmlWriter.Create(@"e:\vmt_debug.xml"))
|
|
{
|
|
xVmtDebugOutput.WriteStartDocument();
|
|
xVmtDebugOutput.WriteStartElement("VMT");
|
|
#endif
|
|
//Push((uint)aTypesSet.Count);
|
|
//Call(xLoadTypeTableRef);
|
|
foreach (var xType in aTypesSet)
|
|
{
|
|
#if VMT_DEBUG
|
|
xVmtDebugOutput.WriteStartElement("Type");
|
|
xVmtDebugOutput.WriteAttributeString("TypeId", aGetTypeID(xType).ToString());
|
|
if (xType.BaseType != null)
|
|
{
|
|
xVmtDebugOutput.WriteAttributeString("BaseTypeId", aGetTypeID(xType.BaseType).ToString());
|
|
}
|
|
xVmtDebugOutput.WriteAttributeString("Name", xType.FullName);
|
|
#endif
|
|
// value contains true if the method is an interface method definition
|
|
SortedList<MethodBase, bool> xEmittedMethods = new SortedList<MethodBase, bool>(new MethodBaseComparer());
|
|
foreach (MethodBase xMethod in xType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
|
|
{
|
|
if (aMethodsSet.Contains(xMethod))//) && !xMethod.IsAbstract)
|
|
{
|
|
xEmittedMethods.Add(xMethod, false);
|
|
}
|
|
}
|
|
foreach (MethodBase xCtor in xType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
|
|
{
|
|
if (aMethodsSet.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 (aMethodsSet.Contains(xMethodIntf))
|
|
{
|
|
if (!xEmittedMethods.ContainsKey(xMethodIntf))
|
|
{
|
|
xEmittedMethods.Add(xMethodIntf,
|
|
true);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
if (!xType.IsInterface)
|
|
{
|
|
Push(aGetTypeID(xType));
|
|
}
|
|
int? xBaseIndex = null;
|
|
if (xType.BaseType == null)
|
|
{
|
|
xBaseIndex = (int)aGetTypeID(xType);
|
|
}
|
|
else
|
|
{
|
|
for (int t = 0; t < aTypesSet.Count; t++)
|
|
{
|
|
// todo: optimize check
|
|
var xItem = aTypesSet.Skip(t).First();
|
|
if (xItem.ToString() == xType.BaseType.ToString())
|
|
{
|
|
xBaseIndex = (int)aGetTypeID(xItem);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (xBaseIndex == null)
|
|
{
|
|
throw new Exception("Base type not found!");
|
|
}
|
|
for (int x = xEmittedMethods.Count - 1; x >= 0; x--)
|
|
{
|
|
if (!aMethodsSet.Contains(xEmittedMethods.Keys[x]))
|
|
{
|
|
xEmittedMethods.RemoveAt(x);
|
|
}
|
|
}
|
|
if (!xType.IsInterface)
|
|
{
|
|
Move("VMT__TYPE_ID_HOLDER__" + DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GetFullName(xType) + " ASM_IS__" + xType.Assembly.GetName().Name), (int)aGetTypeID(xType));
|
|
Assembler.CurrentInstance.DataMembers.Add(
|
|
new DataMember("VMT__TYPE_ID_HOLDER__" + DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GetFullName(xType) + " ASM_IS__" + xType.Assembly.GetName().Name), new int[] { (int)aGetTypeID(xType) }));
|
|
Push((uint)xBaseIndex.Value);
|
|
xData = new byte[16 + (xEmittedMethods.Count * 4)];
|
|
xTemp = BitConverter.GetBytes(aGetTypeID(typeof(Array)));
|
|
Array.Copy(xTemp, 0, xData, 0, 4);
|
|
xTemp = BitConverter.GetBytes(0x80000002); // embedded array
|
|
Array.Copy(xTemp, 0, xData, 4, 4);
|
|
xTemp = BitConverter.GetBytes(xEmittedMethods.Count); // embedded array
|
|
Array.Copy(xTemp, 0, xData, 8, 4);
|
|
xTemp = BitConverter.GetBytes(4); // embedded array
|
|
Array.Copy(xTemp, 0, xData, 12, 4);
|
|
string xDataName = "____SYSTEM____TYPE___" + DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GetFullName(xType) + " ASM_IS__" + xType.Assembly.GetName().Name) + "__MethodIndexesArray";
|
|
Assembler.CurrentInstance.DataMembers.Add(new DataMember(xDataName, xData));
|
|
Push(xDataName);
|
|
xDataName = "____SYSTEM____TYPE___" + DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GetFullName(xType) + " ASM_IS__" + xType.Assembly.GetName().Name) + "__MethodAddressesArray";
|
|
Assembler.CurrentInstance.DataMembers.Add(new DataMember(xDataName, xData));
|
|
Push(xDataName);
|
|
xData = new byte[16 + Encoding.Unicode.GetByteCount(xType.FullName + ", " + xType.Module.Assembly.GetName().FullName)];
|
|
xTemp = BitConverter.GetBytes(aGetTypeID(typeof(Array)));
|
|
Array.Copy(xTemp, 0, xData, 0, 4);
|
|
xTemp = BitConverter.GetBytes(0x80000002); // embedded array
|
|
Array.Copy(xTemp, 0, xData, 4, 4);
|
|
xTemp = BitConverter.GetBytes((xType.FullName + ", " + xType.Module.Assembly.GetName().FullName).Length);
|
|
Array.Copy(xTemp, 0, xData, 8, 4);
|
|
xTemp = BitConverter.GetBytes(2); // embedded array
|
|
Array.Copy(xTemp, 0, xData, 12, 4);
|
|
xDataName = "____SYSTEM____TYPE___" + DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GetFullName(xType) + " ASM_IS__" + xType.Assembly.GetName().Name);
|
|
Assembler.CurrentInstance.DataMembers.Add(new DataMember(xDataName, xData));
|
|
Push("0" + xEmittedMethods.Count.ToString("X") + "h");
|
|
Call(xSetTypeInfoRef);
|
|
}
|
|
for (int j = 0; j < xEmittedMethods.Count; j++)
|
|
{
|
|
MethodBase xMethod = xEmittedMethods.Keys[j];
|
|
#if VMT_DEBUG
|
|
xVmtDebugOutput.WriteStartElement("Method");
|
|
xVmtDebugOutput.WriteAttributeString("Id", aGetMethodUID(xMethod).ToString());
|
|
xVmtDebugOutput.WriteAttributeString("Name", xMethod.GetFullName());
|
|
xVmtDebugOutput.WriteEndElement();
|
|
#endif
|
|
var xMethodId = aGetMethodUID(xMethod);
|
|
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
|
|
{
|
|
}
|
|
}
|
|
xMethod = xNewMethod;
|
|
}
|
|
|
|
Push((uint)aGetTypeID(xType));
|
|
Push((uint)j);
|
|
|
|
Push((uint)xMethodId);
|
|
if (xMethod.IsAbstract)
|
|
{
|
|
// abstract methods dont have bodies, oiw, are not emitted
|
|
Push(0);
|
|
}
|
|
else
|
|
{
|
|
Push(ILOp.GetMethodLabel(xMethod));
|
|
}
|
|
Push(0);
|
|
Call(VTablesImplRefs.SetMethodInfoRef);
|
|
}
|
|
}
|
|
#if VMT_DEBUG
|
|
xVmtDebugOutput.WriteEndElement(); // type
|
|
#endif
|
|
}
|
|
#if VMT_DEBUG
|
|
xVmtDebugOutput.WriteEndElement(); // types
|
|
xVmtDebugOutput.WriteEndDocument();
|
|
}
|
|
#endif
|
|
}
|
|
MethodEnd(InitVMTCodeLabel);
|
|
}
|
|
|
|
public void ProcessField(FieldInfo aField)
|
|
{
|
|
string xFieldName = MethodInfoLabelGenerator.GetFullName(aField);
|
|
xFieldName = DataMember.GetStaticFieldName(aField);
|
|
if (Assembler.CurrentInstance.DataMembers.Count(x => x.Name == xFieldName) == 0)
|
|
{
|
|
var xItemList = (from item in aField.GetCustomAttributes(false)
|
|
where item.GetType().FullName == "ManifestResourceStreamAttribute"
|
|
select item).ToList();
|
|
|
|
object xItem = null;
|
|
if (xItemList.Count > 0)
|
|
xItem = xItemList[0];
|
|
string xManifestResourceName = null;
|
|
if (xItem != null)
|
|
{
|
|
var xItemType = xItem.GetType();
|
|
xManifestResourceName = (string)xItemType.GetField("ResourceName").GetValue(xItem);
|
|
}
|
|
if (xManifestResourceName != null)
|
|
{
|
|
// todo: add support for manifest streams again
|
|
//RegisterType(xCurrentField.FieldType);
|
|
//string xFileName = Path.Combine(mOutputDir,
|
|
// (xCurrentField.DeclaringType.Assembly.FullName + "__" + xManifestResourceName).Replace(",",
|
|
// "_") + ".res");
|
|
//using (var xStream = xCurrentField.DeclaringType.Assembly.GetManifestResourceStream(xManifestResourceName)) {
|
|
// if (xStream == null) {
|
|
// throw new Exception("Resource '" + xManifestResourceName + "' not found!");
|
|
// }
|
|
// using (var xTarget = File.Create(xFileName)) {
|
|
// // todo: abstract this array code out.
|
|
// xTarget.Write(BitConverter.GetBytes(Engine.RegisterType(Engine.GetType("mscorlib",
|
|
// "System.Array"))),
|
|
// 0,
|
|
// 4);
|
|
// xTarget.Write(BitConverter.GetBytes((uint)InstanceTypeEnum.StaticEmbeddedArray),
|
|
// 0,
|
|
// 4);
|
|
// xTarget.Write(BitConverter.GetBytes((int)xStream.Length), 0, 4);
|
|
// xTarget.Write(BitConverter.GetBytes((int)1), 0, 4);
|
|
// var xBuff = new byte[128];
|
|
// while (xStream.Position < xStream.Length) {
|
|
// int xBytesRead = xStream.Read(xBuff, 0, 128);
|
|
// xTarget.Write(xBuff, 0, xBytesRead);
|
|
// }
|
|
// }
|
|
//}
|
|
//mAssembler.DataMembers.Add(new DataMember("___" + xFieldName + "___Contents",
|
|
// "incbin",
|
|
// "\"" + xFileName + "\""));
|
|
//mAssembler.DataMembers.Add(new DataMember(xFieldName,
|
|
// "dd",
|
|
// "___" + xFieldName + "___Contents"));
|
|
throw new NotImplementedException();
|
|
}
|
|
else
|
|
{
|
|
uint xTheSize;
|
|
//string theType = "db";
|
|
Type xFieldTypeDef = aField.FieldType;
|
|
if (!xFieldTypeDef.IsClass || xFieldTypeDef.IsValueType)
|
|
{
|
|
xTheSize = GetSizeOfType(aField.FieldType);
|
|
}
|
|
else
|
|
{
|
|
xTheSize = 4;
|
|
}
|
|
byte[] xData = new byte[xTheSize];
|
|
try
|
|
{
|
|
object xValue = aField.GetValue(null);
|
|
if (xValue != null)
|
|
{
|
|
try
|
|
{
|
|
xData = new byte[xTheSize];
|
|
if (xValue.GetType().IsValueType)
|
|
{
|
|
for (int x = 0; x < xTheSize; x++)
|
|
{
|
|
xData[x] = Marshal.ReadByte(xValue,
|
|
x);
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
Assembler.CurrentInstance.DataMembers.Add(new DataMember(xFieldName, xData));
|
|
}
|
|
}
|
|
}
|
|
|
|
public abstract uint GetSizeOfType(Type aType);
|
|
|
|
public abstract void EmitEntrypoint(MethodBase aEntrypoint, IEnumerable<MethodBase> aMethods);
|
|
|
|
protected abstract void Ldarg(MethodInfo aMethod, int aIndex);
|
|
protected abstract void Ldflda(MethodInfo aMethod, string aFieldId);
|
|
protected abstract void Call(MethodInfo aMethod, MethodInfo aTargetMethod);
|
|
protected abstract void Pop();
|
|
|
|
internal void GenerateMethodForward(MethodInfo aFrom, MethodInfo aTo)
|
|
{
|
|
// todo: completely get rid of this kind of trampoline code
|
|
MethodBegin(aFrom);
|
|
{
|
|
var xParams = aTo.MethodBase.GetParameters().ToArray();
|
|
|
|
if (aTo.MethodAssembler != null)
|
|
{
|
|
xParams = aFrom.MethodBase.GetParameters();
|
|
}
|
|
|
|
//if (aFrom.MethodBase.GetParameters().Length > 0 || !aFrom.MethodBase.IsStatic) {
|
|
// Ldarg(aFrom, 0);
|
|
// Pop();
|
|
//}
|
|
|
|
int xCurParamIdx = 0;
|
|
if (!aFrom.MethodBase.IsStatic)
|
|
{
|
|
Ldarg(aFrom, 0);
|
|
xCurParamIdx++;
|
|
if (aTo.MethodAssembler == null)
|
|
{
|
|
xParams = xParams.Skip(1).ToArray();
|
|
}
|
|
}
|
|
foreach (var xParam in xParams)
|
|
{
|
|
FieldAccessAttribute xFieldAccessAttrib = null;
|
|
foreach (var xAttrib in xParam.GetCustomAttributes(typeof(FieldAccessAttribute), true))
|
|
{
|
|
xFieldAccessAttrib = xAttrib as FieldAccessAttribute;
|
|
}
|
|
|
|
if (xFieldAccessAttrib != null)
|
|
{
|
|
// field access
|
|
new Comment("Loading address of field '" + xFieldAccessAttrib.Name + "'");
|
|
Ldarg(aFrom, 0);
|
|
Ldflda(aFrom, xFieldAccessAttrib.Name);
|
|
}
|
|
else
|
|
{
|
|
// normal field access
|
|
new Comment("Loading parameter " + xCurParamIdx);
|
|
Ldarg(aFrom, xCurParamIdx);
|
|
xCurParamIdx++;
|
|
}
|
|
}
|
|
Call(aFrom, aTo);
|
|
}
|
|
MethodEnd(aFrom);
|
|
}
|
|
|
|
}
|
|
}
|