diff --git a/CPPPOC/CSimpleClass.cs b/CPPPOC/CSimpleClass.cs index c29740eb..b8664ad3 100644 --- a/CPPPOC/CSimpleClass.cs +++ b/CPPPOC/CSimpleClass.cs @@ -9,21 +9,39 @@ using Mono.VisualC.Interop; namespace CPPPOC { +<<<<<<< HEAD public class CSimpleClass : ICppInstance { private interface __ICSimpleClass : ICppOverridable { +======= + public class CSimpleClass : ICppObject { + + #region C++ Header + // This interface is analogous to the C++ class public header -- it defines the + // C++ class's interface. The order of methods must be the same as in the C++ header. + private interface __ICSimpleClass : ICppClassOverridable { + // constructor +>>>>>>> Refactored and completed managed VTable implementation. Prepared for void CSimpleClass(CppInstancePtr ths, int value); + void M0(CppInstancePtr ths); [Virtual] void V0(CppInstancePtr ths, int x, int y); void M1(CppInstancePtr ths, int x); [Virtual] void V1(CppInstancePtr ths, int x); void M2(CppInstancePtr ths, int x, int y); [Virtual] void V2(CppInstancePtr ths); + + // a C++ field directly accessible to managed code CppField value {get;} } + + // This struct defines the C++ class's memory footprint. + // Basically, it includes both the class's public and private fields. + // Again, the order must be the same as in the C++ header. private struct __CSimpleClass { public int value; } + #endregion private static __ICSimpleClass _impl; diff --git a/Mono.VisualC.Interop/ABI/CppAbi.cs b/Mono.VisualC.Interop/ABI/CppAbi.cs index bfc1d7b6..8ec1132c 100644 --- a/Mono.VisualC.Interop/ABI/CppAbi.cs +++ b/Mono.VisualC.Interop/ABI/CppAbi.cs @@ -8,6 +8,7 @@ // using System; +using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -26,6 +27,7 @@ namespace Mono.VisualC.Interop.ABI { protected Type interfaceType, layoutType, wrapperType; protected string library, className; + protected VTable vtable; protected FieldBuilder vtableField; protected ILGenerator ctorIL; @@ -41,15 +43,15 @@ namespace Mono.VisualC.Interop.ABI { this.wrapperType = wrapperType; MethodInfo[] methods = interfaceType.GetMethods (); + var managedOverrides = from method in methods + where Modifiers.IsVirtual (method) + orderby method.MetadataToken + select GetManagedOverrideTrampoline (method, VTable.BindToSignatureAndAttribute); - // sort methods into declaration order - // TODO: This is kinda kludgy isn't it? - Array.Sort (methods, (x, y) => x.MetadataToken - y.MetadataToken); - - int vtableIndex = 0; - List vtableDelegates = new List(); + vtable = MakeVTable (managedOverrides.ToArray ()); // Implement all methods + int vtableIndex = 0; for (int i = 0; i < methods.Length; i++) { // Skip over special methods like property accessors -- properties will be handled later if (methods [i].IsSpecialName) @@ -57,14 +59,8 @@ namespace Mono.VisualC.Interop.ABI { DefineMethod (methods [i], vtableIndex); - if (!Modifiers.IsVirtual (methods [i])) - continue; - - MethodInfo overrideTarget = FindManagedOverrideTarget (methods [i], VTable.BindOverridesOnly); - if (overrideTarget != null) - vtableDelegates.Insert(vtableIndex, GetManagedOverrideTrampoline (methods [i], overrideTarget)); - - vtableIndex++; + if (Modifiers.IsVirtual (methods [i])) + vtableIndex++; } DefineImplType (); @@ -107,7 +103,7 @@ namespace Mono.VisualC.Interop.ABI { protected virtual VTable MakeVTable (Delegate[] overrides) { - return new VTableManaged (overrides); + return new VTableManaged (implModule, overrides); } // The members below must be implemented for a given C++ ABI: @@ -158,8 +154,8 @@ namespace Mono.VisualC.Interop.ABI { EmitCheckDisposed (il, nativePtr, methodType); MethodInfo nativeMethod; - if (!Modifiers.IsVirtual (interfaceMethod)) { - nativeMethod = null; + if (Modifiers.IsVirtual (interfaceMethod)) + nativeMethod = vtable.PrepareVirtualCall (interfaceMethod, il, vtableField, nativePtr, index); else nativeMethod = GetPInvokeForMethod (interfaceMethod); @@ -175,9 +171,8 @@ namespace Mono.VisualC.Interop.ABI { default: // regular native method EmitCallNative (il, nativeMethod, parameterTypes.Length, nativePtr); break; - } - } else + } il.Emit (OpCodes.Ret); return trampoline; @@ -233,8 +228,12 @@ namespace Mono.VisualC.Interop.ABI { * Implements the managed trampoline that will be invoked from the vtable by native C++ code when overriding * the specified C++ virtual method with the specified managed one. */ - protected virtual Delegate GetManagedOverrideTrampoline (MethodInfo interfaceMethod, MethodInfo targetMethod) + protected virtual Delegate GetManagedOverrideTrampoline (MethodInfo interfaceMethod, MemberFilter binder) { + MethodInfo targetMethod = FindManagedOverrideTarget (interfaceMethod, binder); + if (targetMethod == null) + return null; + Type delegateType = Util.GetDelegateTypeForMethodInfo (implModule, interfaceMethod); Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, true); diff --git a/Mono.VisualC.Interop/ABI/VTable.cs b/Mono.VisualC.Interop/ABI/VTable.cs index f907e534..e64c0d6a 100644 --- a/Mono.VisualC.Interop/ABI/VTable.cs +++ b/Mono.VisualC.Interop/ABI/VTable.cs @@ -19,37 +19,34 @@ namespace Mono.VisualC.Interop.ABI { protected IntPtr basePtr, vtPtr; public virtual int EntryCount { get; protected set; } + public virtual int EntrySize { + get { return Marshal.SizeOf (typeof (IntPtr)); } + } - public abstract int EntrySize { get; } - public abstract void EmitVirtualCall (ILGenerator il, IntPtr native, int index); + public abstract MethodInfo PrepareVirtualCall (MethodInfo target, ILGenerator callsite, FieldInfo vtableField, + LocalBuilder native, int vtableIndex); // Creates a new VTable public VTable (Delegate[] overrides) { EntryCount = overrides.Length; - - int vtableSize = EntryCount * EntrySize; - IntPtr vtEntryPtr; - basePtr = IntPtr.Zero; - vtPtr = Marshal.AllocHGlobal (vtableSize); - - try { - int offset = 0; - for (int i = 0; i < EntryCount; i++) { + vtPtr = IntPtr.Zero; + } - if (overrides [i] != null) // managed override - vtEntryPtr = Marshal.GetFunctionPointerForDelegate (overrides [i]); - else - vtEntryPtr = IntPtr.Zero; + public virtual void WriteOverrides (Delegate[] overrides) + { + IntPtr vtEntryPtr; + int offset = 0; + for (int i = 0; i < EntryCount; i++) { - Marshal.WriteIntPtr (vtPtr, offset, vtEntryPtr); - offset += EntrySize; - } - } catch { + if (overrides [i] != null) // managed override + vtEntryPtr = Marshal.GetFunctionPointerForDelegate (overrides [i]); + else + vtEntryPtr = IntPtr.Zero; - Marshal.FreeHGlobal (vtPtr); - throw; + Marshal.WriteIntPtr (vtPtr, offset, vtEntryPtr); + offset += EntrySize; } } @@ -102,16 +99,21 @@ namespace Mono.VisualC.Interop.ABI { Dispose (false); } - public static bool BindOverridesOnly (MemberInfo member, object obj) + public static bool BindToSignatureAndAttribute (MemberInfo member, object obj) { - bool result = BindAny (member, obj); + bool result = BindToSignature (member, obj); if (member.GetCustomAttributes (typeof (OverrideNativeAttribute), true).Length != 1) return false; return result; } +<<<<<<< HEAD public static bool BindAny (MemberInfo member, object obj) +======= + + public static bool BindToSignature (MemberInfo member, object obj) +>>>>>>> Refactored and completed managed VTable implementation. Prepared for { MethodInfo imethod = (MethodInfo) obj; MethodInfo candidate = (MethodInfo) member; diff --git a/Mono.VisualC.Interop/ABI/VTableCOM.cs b/Mono.VisualC.Interop/ABI/VTableCOM.cs index 691e2654..1c36b2d0 100644 --- a/Mono.VisualC.Interop/ABI/VTableCOM.cs +++ b/Mono.VisualC.Interop/ABI/VTableCOM.cs @@ -8,6 +8,7 @@ // using System; +using System.Linq; using System.Collections.Generic; using System.Reflection; @@ -19,15 +20,19 @@ namespace Mono.VisualC.Interop.ABI { public VTableCOM (Delegate[] entries) : base(entries) { - } + int managedOverrides = (from entry in entries + where entry != null + select entry).Count(); - public override int EntrySize { - get { return Marshal.SizeOf (typeof (IntPtr)); } + vtPtr = Marshal.AllocHGlobal ((EntryCount + managedOverrides) * EntrySize); + WriteOverrides (entries); } - public override T GetDelegateForNative (IntPtr native, int index) - { - return default(T); - } + public override MethodInfo PrepareVirtualCall (MethodInfo target, ILGenerator callsite, FieldInfo vtableField, + LocalBuilder native, int vtableIndex) + { + throw new System.NotImplementedException (); + } + } } diff --git a/Mono.VisualC.Interop/ABI/VTableManaged.cs b/Mono.VisualC.Interop/ABI/VTableManaged.cs index 57a22dcb..3ba7260b 100644 --- a/Mono.VisualC.Interop/ABI/VTableManaged.cs +++ b/Mono.VisualC.Interop/ABI/VTableManaged.cs @@ -17,15 +17,55 @@ using System.Runtime.InteropServices; namespace Mono.VisualC.Interop.ABI { public class VTableManaged : VTable { - public VTableManaged (Delegate[] entries) : base(entries) + private Type[] delegateTypes; + private ModuleBuilder implModule; + + public VTableManaged (ModuleBuilder implModule, Delegate[] entries) : base(entries) { + this.implModule = implModule; + this.delegateTypes = new Type [EntryCount]; + + for (int i = 0; i < EntryCount; i++) { + if (entries [i] != null) + delegateTypes [i] = entries [i].GetType (); + } + + vtPtr = Marshal.AllocHGlobal (EntryCount * EntrySize); + WriteOverrides (entries); } - public override int EntrySize { - get { return Marshal.SizeOf (typeof (IntPtr)); } + public override MethodInfo PrepareVirtualCall (MethodInfo target, ILGenerator callsite, FieldInfo vtableField, + LocalBuilder native, int vtableIndex) + { + if (delegateTypes [vtableIndex] == null) + delegateTypes [vtableIndex] = Util.GetDelegateTypeForMethodInfo (implModule, target); + + MethodInfo getDelegate = typeof (VTableManaged).GetMethod ("GetDelegateForNative").MakeGenericMethod (delegateTypes [vtableIndex]); + + // load this._vtable + callsite.Emit (OpCodes.Ldarg_0); + callsite.Emit (OpCodes.Ldfld, vtableField); + // call this._vtable.GetDelegateForNative(IntPtr native, int vtableIndex) + callsite.Emit (OpCodes.Ldloc_S, native); + callsite.Emit (OpCodes.Ldc_I4, vtableIndex); + callsite.Emit (OpCodes.Callvirt, getDelegate); + // check for null + Label notNull = callsite.DefineLabel (); + callsite.Emit (OpCodes.Dup); + callsite.Emit (OpCodes.Brtrue_S, notNull); + callsite.Emit (OpCodes.Pop); + // mono bug makes it crash here instead of throwing a NullReferenceException--so do it ourselves + callsite.Emit (OpCodes.Ldstr, "Native VTable contains null...possible abstract class???"); + callsite.Emit (OpCodes.Newobj, typeof (NullReferenceException).GetConstructor (new Type[] {typeof (string)})); + callsite.Emit (OpCodes.Throw); + callsite.MarkLabel (notNull); + + return delegateTypes [vtableIndex].GetMethod ("Invoke"); + } - public override T GetDelegateForNative (IntPtr native, int index) + + public T GetDelegateForNative (IntPtr native, int index) where T : class /*Delegate*/ { IntPtr vtable = Marshal.ReadIntPtr (native); if (vtable == vtPtr) // do not return managed overrides diff --git a/Mono.VisualC.Interop/CppField.cs b/Mono.VisualC.Interop/CppField.cs index 0b65b338..f7a68fc1 100644 --- a/Mono.VisualC.Interop/CppField.cs +++ b/Mono.VisualC.Interop/CppField.cs @@ -10,10 +10,8 @@ using System; using System.Runtime.InteropServices; -namespace Mono.VisualC.Interop -{ - public class CppField - { +namespace Mono.VisualC.Interop { + public class CppField { private int fieldOffset; public CppField (int fieldOffset) @@ -23,8 +21,9 @@ namespace Mono.VisualC.Interop public T this [CppInstancePtr ip] { get { - Type retType = typeof(T); + Type retType = typeof (T); object retVal; +<<<<<<< HEAD if (retType.Equals(typeof(Byte))) retVal = Marshal.ReadByte(ip.Native, fieldOffset); else if (retType.Equals(typeof(Int16))) @@ -33,17 +32,27 @@ namespace Mono.VisualC.Interop retVal = Marshal.ReadInt32(ip.Native, fieldOffset); else throw new NotImplementedException("Cannot read C++ fields of type " + retType.Name); +======= + if (retType.Equals (typeof (Byte))) + retVal = Marshal.ReadByte (ip.Native, fieldOffset); + else if (retType.Equals (typeof (Int16))) + retVal = Marshal.ReadInt16 (ip.Native, fieldOffset); + else if (retType.Equals (typeof (Int32))) + retVal = Marshal.ReadInt32 (ip.Native, fieldOffset); + else throw new NotImplementedException ("Cannot read C++ fields of type " + retType.Name); + +>>>>>>> Refactored and completed managed VTable implementation. Prepared for return (T)retVal; } set { - Type setType = typeof(T); + Type setType = typeof (T); object setVal = value; - if (setType.Equals(typeof(Byte))) - Marshal.WriteByte(ip.Native, fieldOffset, (byte)setVal); - else if (setType.Equals(typeof(Int16))) - Marshal.WriteInt16(ip.Native, fieldOffset, (Int16)setVal); - else if (setType.Equals(typeof(Int32))) - Marshal.WriteInt32(ip.Native, fieldOffset, (Int32)setVal); + if (setType.Equals (typeof (Byte))) + Marshal.WriteByte (ip.Native, fieldOffset, (byte)setVal); + else if (setType.Equals (typeof (Int16))) + Marshal.WriteInt16 (ip.Native, fieldOffset, (Int16)setVal); + else if (setType.Equals (typeof (Int32))) + Marshal.WriteInt32 (ip.Native, fieldOffset, (Int32)setVal); else throw new NotImplementedException("Cannot write C++ fields of type " + setType.Name); } } diff --git a/Mono.VisualC.Interop/CppInstancePtr.cs b/Mono.VisualC.Interop/CppInstancePtr.cs index 1b6d7d9e..12734e4b 100644 --- a/Mono.VisualC.Interop/CppInstancePtr.cs +++ b/Mono.VisualC.Interop/CppInstancePtr.cs @@ -11,7 +11,7 @@ using System; using System.Runtime.InteropServices; namespace Mono.VisualC.Interop { - public struct CppInstancePtr : ICppInstance { + public struct CppInstancePtr : ICppObject { private IntPtr ptr; private bool manageMemory; diff --git a/Mono.VisualC.Interop/CppLibrary.cs b/Mono.VisualC.Interop/CppLibrary.cs index 513f787d..6568cc5d 100644 --- a/Mono.VisualC.Interop/CppLibrary.cs +++ b/Mono.VisualC.Interop/CppLibrary.cs @@ -60,7 +60,7 @@ namespace Mono.VisualC.Interop // For a class that may have fields with no virtual methods to be overridden public Iface GetClass (string className) - where Iface : ICppInstantiatable + where Iface : ICppClassInstantiatable where NativeLayout : struct { @@ -69,9 +69,9 @@ namespace Mono.VisualC.Interop // For a class that may have fields and virtual methods to be overridden public Iface GetClass (string className) - where Iface : ICppOverridable + where Iface : ICppClassOverridable where NativeLayout : struct - where Managed : ICppInstance + where Managed : ICppObject { return Abi.ImplementClass (interopModule, typeof (Managed), Name, className); diff --git a/Mono.VisualC.Interop/Interfaces.cs b/Mono.VisualC.Interop/Interfaces.cs index 537b4a29..59e2c115 100644 --- a/Mono.VisualC.Interop/Interfaces.cs +++ b/Mono.VisualC.Interop/Interfaces.cs @@ -9,23 +9,36 @@ using System; +<<<<<<< HEAD namespace Mono.VisualC.Interop { public interface ICppInstance : IDisposable { IntPtr Native { get; } +======= +namespace Mono.VisualC.Interop { + + public interface ICppObject : IDisposable { + IntPtr Native { get; } +>>>>>>> Refactored and completed managed VTable implementation. Prepared for } - public interface ICppInstantiatable - { - CppInstancePtr Alloc(); - void Destruct(CppInstancePtr instance); + public interface ICppClassInstantiatable { + CppInstancePtr Alloc (); + void Destruct (CppInstancePtr instance); } +<<<<<<< HEAD public interface ICppOverridable where T : ICppInstance { CppInstancePtr Alloc(T managed); void Destruct(CppInstancePtr instance); +======= + + public interface ICppClassOverridable where T : ICppObject { + CppInstancePtr Alloc (T managed); + void Destruct (CppInstancePtr instance); +>>>>>>> Refactored and completed managed VTable implementation. Prepared for } } \ No newline at end of file diff --git a/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj b/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj index fac8ee3b..4353d554 100644 --- a/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj +++ b/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj @@ -18,7 +18,6 @@ prompt 4 false - true Mono.VisualC.Interop @@ -28,7 +27,6 @@ prompt 4 false - true CPPInterop @@ -37,7 +35,6 @@ bin\Release prompt 4 - true false CPPInterop @@ -50,6 +47,7 @@ +