diff --git a/source/Indy.IL2CPU.IL.X86/Callvirt.cs b/source/Indy.IL2CPU.IL.X86/Callvirt.cs index b7bc6dcd8..c9ee83dcc 100644 --- a/source/Indy.IL2CPU.IL.X86/Callvirt.cs +++ b/source/Indy.IL2CPU.IL.X86/Callvirt.cs @@ -1,14 +1,46 @@ using System; -using System.IO; +using System.Linq; using Mono.Cecil; using Mono.Cecil.Cil; -using CPU = Indy.IL2CPU.Assembler.X86; +using CPU = Indy.IL2CPU.Assembler; +using CPUx86 = Indy.IL2CPU.Assembler.X86; namespace Indy.IL2CPU.IL.X86 { [OpCode(Code.Callvirt, false)] - public class Callvirt: Call { - public Callvirt(Mono.Cecil.Cil.Instruction aInstruction, MethodInformation aMethodInfo) + public class Callvirt: Op { + private int mMethodIdentifier; + private string mThisAddress; + private bool mHasReturn; + private string mNormalAddress; + public Callvirt(Instruction aInstruction, MethodInformation aMethodInfo) : base(aInstruction, aMethodInfo) { + MethodReference xMethod = aInstruction.Operand as MethodReference; + if (xMethod == null) { + throw new Exception("Unable to determine Method!"); + } + if (!aMethodInfo.IsInstanceMethod) { + mNormalAddress = new CPU.Label(xMethod).Name; + mHasReturn = !xMethod.ReturnType.ReturnType.FullName.StartsWith("System.Void"); + return; + } + mMethodIdentifier = Engine.GetMethodIdentifier(Engine.GetDefinitionFromMethodReference(xMethod)); + mThisAddress = aMethodInfo.Arguments[0].VirtualAddress; + mHasReturn = !xMethod.ReturnType.ReturnType.FullName.StartsWith("System.Void"); + } + + public override void DoAssemble() { + if (!String.IsNullOrEmpty(mNormalAddress)) { + Call(mNormalAddress); + } else { + Ldarg(Assembler, mThisAddress); + Pop("eax"); + Pushd("[eax]"); + Call(new CPU.Label(VTablesImplRefs.GetMethodAddressForTypeRef).Name); + Call("eax"); + } + if (mHasReturn) { + Pushd("eax"); + } } } } \ No newline at end of file diff --git a/source/Indy.IL2CPU/Engine.cs b/source/Indy.IL2CPU/Engine.cs index 11408818c..1b9af907f 100644 --- a/source/Indy.IL2CPU/Engine.cs +++ b/source/Indy.IL2CPU/Engine.cs @@ -127,6 +127,7 @@ namespace Indy.IL2CPU { mMethods.Add(mCrawledAssembly.EntryPoint, false); // initialize the runtime engine mAssembler.Add( + new Assembler.X86.Call("____INIT__VMT____"), new Assembler.X86.Call(new Label(RuntimeEngineRefs.InitializeApplicationRef).Name), new Assembler.X86.Call(new Label(mCrawledAssembly.EntryPoint).Name)); if (mCrawledAssembly.EntryPoint.ReturnType.ReturnType.FullName.StartsWith("System.Void", StringComparison.InvariantCultureIgnoreCase)) { @@ -144,11 +145,8 @@ namespace Indy.IL2CPU { break; } } while (true); + GenerateVMT(); ProcessAllStaticFields(); - Console.WriteLine("All Registered Types:"); - foreach (TypeDefinition xTypeDef in mTypes) { - Console.WriteLine("\t{0}", xTypeDef.FullName); - } } finally { mAssembler.Flush(); IL.Op.QueueMethod -= QueueMethod; @@ -160,6 +158,61 @@ namespace Indy.IL2CPU { } } + private void GenerateVMT() { + // todo: abstract this code generation out to IL.* implementation + mAssembler.Add(new Label("____INIT__VMT____")); + mAssembler.Add(new Pushd("0" + mTypes.Count.ToString("X") + "h")); + mAssembler.Add(new Call(new Label(VTablesImplRefs.LoadTypeTableRef).Name)); + for (int i = 0; i < mTypes.Count; i++) { + TypeDefinition xType = mTypes[i]; + List xEmittedMethods = new List(); + foreach (MethodDefinition xMethod in xType.Methods) { + if (mMethods.ContainsKey(xMethod)) { + xEmittedMethods.Add(xMethod); + } + } + foreach (MethodDefinition xCtor in xType.Constructors) { + if (mMethods.ContainsKey(xCtor)) { + xEmittedMethods.Add(xCtor); + } + } + mAssembler.Add(new Pushd("0" + i.ToString("X") + "h")); + int? xBaseIndex = null; + if (xType.BaseType == null) { + for (int t = 0; t < mTypes.Count; t++) { + if (mTypes[t].BaseType == null && mTypes[t].FullName == xType.FullName) { + xBaseIndex = t; + break; + } + } + } else { + for (int t = 0; t < mTypes.Count; t++) { + if (mTypes[t].BaseType == null) { + continue; + } + if (mTypes[t].BaseType.FullName == xType.BaseType.FullName && mTypes[t].FullName == xType.FullName) { + xBaseIndex = t; + break; + } + } + } + if (xBaseIndex == null) { + throw new Exception("Base type not found!"); + } + mAssembler.Add(new Pushd("0" + xBaseIndex.Value.ToString("X") + "h")); + mAssembler.Add(new Pushd("0" + xEmittedMethods.Count.ToString("X") + "h")); + mAssembler.Add(new Call(new Label(VTablesImplRefs.SetTypeInfoRef).Name)); + for (int j = 0; j < xEmittedMethods.Count; j++) { + MethodDefinition xMethod = xEmittedMethods[j]; + mAssembler.Add(new Pushd("0" + i.ToString("X") + "h")); + mAssembler.Add(new Pushd("0" + j.ToString("X") + "h")); + mAssembler.Add(new Pushd("0" + mMethods.IndexOfKey(mMethods.Keys.First(x => x.GetFullName() == xMethod.GetFullName())).ToString("X") + "h")); + mAssembler.Add(new Pushd(new Label(xMethod).Name)); + mAssembler.Add(new Call(new Label(VTablesImplRefs.SetMethodInfoRef).Name)); + } + } + } + private void ScanForMethodToIncludeForVMT() { List xCheckedTypes = new List(); foreach (MethodDefinition xMethod in mMethods.Keys) { @@ -532,11 +585,11 @@ namespace Indy.IL2CPU { where !mMethods[item] select item).FirstOrDefault()) != null) { OnDebugLog(LogSeverityEnum.Informational, "Processing method '{0}'", xCurrentMethod.GetFullName()); - if(xCurrentMethod.IsAbstract) { + if (xCurrentMethod.IsAbstract) { mMethods[xCurrentMethod] = true; continue; } - string xMethodName = new Label(xCurrentMethod).Name; + string xMethodName = new Label(xCurrentMethod).Name; foreach (CustomAttribute xAttrib in xCurrentMethod.CustomAttributes) { if (xAttrib.Constructor.DeclaringType.FullName == typeof(MethodAliasAttribute).FullName) { //xMethodName = (string)xAttrib.Fields["Name"]; @@ -815,6 +868,11 @@ namespace Indy.IL2CPU { } } + public static int GetMethodIdentifier(MethodDefinition aMethod) { + QueueMethod(aMethod); + return mCurrent.mMethods.IndexOfKey(aMethod); + } + public static int RegisterTypeRef(TypeReference aTypeRef) { if (aTypeRef == null) { throw new ArgumentNullException("aTypeRef"); diff --git a/source/Indy.IL2CPU/Indy.IL2CPU.csproj b/source/Indy.IL2CPU/Indy.IL2CPU.csproj index f234bbedf..561ffaf92 100644 --- a/source/Indy.IL2CPU/Indy.IL2CPU.csproj +++ b/source/Indy.IL2CPU/Indy.IL2CPU.csproj @@ -82,6 +82,7 @@ +