Browse Source

Refactored and completed managed VTable implementation. Prepared for

first commit to mono-gsoc repo.

git-svn-id: https://mono-soc-2010.googlecode.com/svn/trunk/cppinterop@8 a470b8cb-0e6f-1642-1b45-71e107334c4b
pull/1/head
alexander.corrado 16 years ago
parent
commit
feb797a2f2
  1. 18
      CPPPOC/CSimpleClass.cs
  2. 39
      Mono.VisualC.Interop/ABI/CppAbi.cs
  3. 48
      Mono.VisualC.Interop/ABI/VTable.cs
  4. 19
      Mono.VisualC.Interop/ABI/VTableCOM.cs
  5. 48
      Mono.VisualC.Interop/ABI/VTableManaged.cs
  6. 33
      Mono.VisualC.Interop/CppField.cs
  7. 2
      Mono.VisualC.Interop/CppInstancePtr.cs
  8. 6
      Mono.VisualC.Interop/CppLibrary.cs
  9. 21
      Mono.VisualC.Interop/Interfaces.cs
  10. 4
      Mono.VisualC.Interop/Mono.VisualC.Interop.csproj

18
CPPPOC/CSimpleClass.cs

@ -9,21 +9,39 @@ using Mono.VisualC.Interop;
namespace CPPPOC { namespace CPPPOC {
<<<<<<< HEAD
public class CSimpleClass : ICppInstance { public class CSimpleClass : ICppInstance {
private interface __ICSimpleClass : ICppOverridable<CSimpleClass> { private interface __ICSimpleClass : ICppOverridable<CSimpleClass> {
=======
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<CSimpleClass> {
// constructor
>>>>>>> Refactored and completed managed VTable implementation. Prepared for
void CSimpleClass(CppInstancePtr ths, int value); void CSimpleClass(CppInstancePtr ths, int value);
void M0(CppInstancePtr ths); void M0(CppInstancePtr ths);
[Virtual] void V0(CppInstancePtr ths, int x, int y); [Virtual] void V0(CppInstancePtr ths, int x, int y);
void M1(CppInstancePtr ths, int x); void M1(CppInstancePtr ths, int x);
[Virtual] void V1(CppInstancePtr ths, int x); [Virtual] void V1(CppInstancePtr ths, int x);
void M2(CppInstancePtr ths, int x, int y); void M2(CppInstancePtr ths, int x, int y);
[Virtual] void V2(CppInstancePtr ths); [Virtual] void V2(CppInstancePtr ths);
// a C++ field directly accessible to managed code
CppField<int> value {get;} CppField<int> 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 { private struct __CSimpleClass {
public int value; public int value;
} }
#endregion
private static __ICSimpleClass _impl; private static __ICSimpleClass _impl;

39
Mono.VisualC.Interop/ABI/CppAbi.cs

@ -8,6 +8,7 @@
// //
using System; using System;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
@ -26,6 +27,7 @@ namespace Mono.VisualC.Interop.ABI {
protected Type interfaceType, layoutType, wrapperType; protected Type interfaceType, layoutType, wrapperType;
protected string library, className; protected string library, className;
protected VTable vtable;
protected FieldBuilder vtableField; protected FieldBuilder vtableField;
protected ILGenerator ctorIL; protected ILGenerator ctorIL;
@ -41,15 +43,15 @@ namespace Mono.VisualC.Interop.ABI {
this.wrapperType = wrapperType; this.wrapperType = wrapperType;
MethodInfo[] methods = interfaceType.GetMethods (); 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 vtable = MakeVTable (managedOverrides.ToArray ());
// TODO: This is kinda kludgy isn't it?
Array.Sort (methods, (x, y) => x.MetadataToken - y.MetadataToken);
int vtableIndex = 0;
List<Delegate> vtableDelegates = new List<Delegate>();
// Implement all methods // Implement all methods
int vtableIndex = 0;
for (int i = 0; i < methods.Length; i++) { for (int i = 0; i < methods.Length; i++) {
// Skip over special methods like property accessors -- properties will be handled later // Skip over special methods like property accessors -- properties will be handled later
if (methods [i].IsSpecialName) if (methods [i].IsSpecialName)
@ -57,14 +59,8 @@ namespace Mono.VisualC.Interop.ABI {
DefineMethod (methods [i], vtableIndex); DefineMethod (methods [i], vtableIndex);
if (!Modifiers.IsVirtual (methods [i])) if (Modifiers.IsVirtual (methods [i]))
continue; vtableIndex++;
MethodInfo overrideTarget = FindManagedOverrideTarget (methods [i], VTable.BindOverridesOnly);
if (overrideTarget != null)
vtableDelegates.Insert(vtableIndex, GetManagedOverrideTrampoline (methods [i], overrideTarget));
vtableIndex++;
} }
DefineImplType (); DefineImplType ();
@ -107,7 +103,7 @@ namespace Mono.VisualC.Interop.ABI {
protected virtual VTable MakeVTable (Delegate[] overrides) 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: // The members below must be implemented for a given C++ ABI:
@ -158,8 +154,8 @@ namespace Mono.VisualC.Interop.ABI {
EmitCheckDisposed (il, nativePtr, methodType); EmitCheckDisposed (il, nativePtr, methodType);
MethodInfo nativeMethod; MethodInfo nativeMethod;
if (!Modifiers.IsVirtual (interfaceMethod)) { if (Modifiers.IsVirtual (interfaceMethod))
nativeMethod = null; nativeMethod = vtable.PrepareVirtualCall (interfaceMethod, il, vtableField, nativePtr, index);
else else
nativeMethod = GetPInvokeForMethod (interfaceMethod); nativeMethod = GetPInvokeForMethod (interfaceMethod);
@ -175,9 +171,8 @@ namespace Mono.VisualC.Interop.ABI {
default: // regular native method default: // regular native method
EmitCallNative (il, nativeMethod, parameterTypes.Length, nativePtr); EmitCallNative (il, nativeMethod, parameterTypes.Length, nativePtr);
break; break;
}
} else
}
il.Emit (OpCodes.Ret); il.Emit (OpCodes.Ret);
return trampoline; 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 * 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. * 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 delegateType = Util.GetDelegateTypeForMethodInfo (implModule, interfaceMethod);
Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, true); Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, true);

48
Mono.VisualC.Interop/ABI/VTable.cs

@ -19,37 +19,34 @@ namespace Mono.VisualC.Interop.ABI {
protected IntPtr basePtr, vtPtr; protected IntPtr basePtr, vtPtr;
public virtual int EntryCount { get; protected set; } public virtual int EntryCount { get; protected set; }
public virtual int EntrySize {
get { return Marshal.SizeOf (typeof (IntPtr)); }
}
public abstract int EntrySize { get; } public abstract MethodInfo PrepareVirtualCall (MethodInfo target, ILGenerator callsite, FieldInfo vtableField,
public abstract void EmitVirtualCall (ILGenerator il, IntPtr native, int index); LocalBuilder native, int vtableIndex);
// Creates a new VTable // Creates a new VTable
public VTable (Delegate[] overrides) public VTable (Delegate[] overrides)
{ {
EntryCount = overrides.Length; EntryCount = overrides.Length;
int vtableSize = EntryCount * EntrySize;
IntPtr vtEntryPtr;
basePtr = IntPtr.Zero; basePtr = IntPtr.Zero;
vtPtr = Marshal.AllocHGlobal (vtableSize); vtPtr = IntPtr.Zero;
}
try {
int offset = 0;
for (int i = 0; i < EntryCount; i++) {
if (overrides [i] != null) // managed override public virtual void WriteOverrides (Delegate[] overrides)
vtEntryPtr = Marshal.GetFunctionPointerForDelegate (overrides [i]); {
else IntPtr vtEntryPtr;
vtEntryPtr = IntPtr.Zero; int offset = 0;
for (int i = 0; i < EntryCount; i++) {
Marshal.WriteIntPtr (vtPtr, offset, vtEntryPtr); if (overrides [i] != null) // managed override
offset += EntrySize; vtEntryPtr = Marshal.GetFunctionPointerForDelegate (overrides [i]);
} else
} catch { vtEntryPtr = IntPtr.Zero;
Marshal.FreeHGlobal (vtPtr); Marshal.WriteIntPtr (vtPtr, offset, vtEntryPtr);
throw; offset += EntrySize;
} }
} }
@ -102,16 +99,21 @@ namespace Mono.VisualC.Interop.ABI {
Dispose (false); 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) if (member.GetCustomAttributes (typeof (OverrideNativeAttribute), true).Length != 1)
return false; return false;
return result; return result;
} }
<<<<<<< HEAD
public static bool BindAny (MemberInfo member, object obj) 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 imethod = (MethodInfo) obj;
MethodInfo candidate = (MethodInfo) member; MethodInfo candidate = (MethodInfo) member;

19
Mono.VisualC.Interop/ABI/VTableCOM.cs

@ -8,6 +8,7 @@
// //
using System; using System;
using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
@ -19,15 +20,19 @@ namespace Mono.VisualC.Interop.ABI {
public VTableCOM (Delegate[] entries) : base(entries) public VTableCOM (Delegate[] entries) : base(entries)
{ {
} int managedOverrides = (from entry in entries
where entry != null
select entry).Count();
public override int EntrySize { vtPtr = Marshal.AllocHGlobal ((EntryCount + managedOverrides) * EntrySize);
get { return Marshal.SizeOf (typeof (IntPtr)); } WriteOverrides (entries);
} }
public override T GetDelegateForNative<T> (IntPtr native, int index) public override MethodInfo PrepareVirtualCall (MethodInfo target, ILGenerator callsite, FieldInfo vtableField,
{ LocalBuilder native, int vtableIndex)
return default(T); {
} throw new System.NotImplementedException ();
}
} }
} }

48
Mono.VisualC.Interop/ABI/VTableManaged.cs

@ -17,15 +17,55 @@ using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop.ABI { namespace Mono.VisualC.Interop.ABI {
public class VTableManaged : VTable { 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 { public override MethodInfo PrepareVirtualCall (MethodInfo target, ILGenerator callsite, FieldInfo vtableField,
get { return Marshal.SizeOf (typeof (IntPtr)); } 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<T> (IntPtr native, int index)
public T GetDelegateForNative<T> (IntPtr native, int index) where T : class /*Delegate*/
{ {
IntPtr vtable = Marshal.ReadIntPtr (native); IntPtr vtable = Marshal.ReadIntPtr (native);
if (vtable == vtPtr) // do not return managed overrides if (vtable == vtPtr) // do not return managed overrides

33
Mono.VisualC.Interop/CppField.cs

@ -10,10 +10,8 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop namespace Mono.VisualC.Interop {
{ public class CppField<T> {
public class CppField<T>
{
private int fieldOffset; private int fieldOffset;
public CppField (int fieldOffset) public CppField (int fieldOffset)
@ -23,8 +21,9 @@ namespace Mono.VisualC.Interop
public T this [CppInstancePtr ip] { public T this [CppInstancePtr ip] {
get { get {
Type retType = typeof(T); Type retType = typeof (T);
object retVal; object retVal;
<<<<<<< HEAD
if (retType.Equals(typeof(Byte))) if (retType.Equals(typeof(Byte)))
retVal = Marshal.ReadByte(ip.Native, fieldOffset); retVal = Marshal.ReadByte(ip.Native, fieldOffset);
else if (retType.Equals(typeof(Int16))) else if (retType.Equals(typeof(Int16)))
@ -33,17 +32,27 @@ namespace Mono.VisualC.Interop
retVal = Marshal.ReadInt32(ip.Native, fieldOffset); retVal = Marshal.ReadInt32(ip.Native, fieldOffset);
else throw new NotImplementedException("Cannot read C++ fields of type " + retType.Name); 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; return (T)retVal;
} }
set { set {
Type setType = typeof(T); Type setType = typeof (T);
object setVal = value; object setVal = value;
if (setType.Equals(typeof(Byte))) if (setType.Equals (typeof (Byte)))
Marshal.WriteByte(ip.Native, fieldOffset, (byte)setVal); Marshal.WriteByte (ip.Native, fieldOffset, (byte)setVal);
else if (setType.Equals(typeof(Int16))) else if (setType.Equals (typeof (Int16)))
Marshal.WriteInt16(ip.Native, fieldOffset, (Int16)setVal); Marshal.WriteInt16 (ip.Native, fieldOffset, (Int16)setVal);
else if (setType.Equals(typeof(Int32))) else if (setType.Equals (typeof (Int32)))
Marshal.WriteInt32(ip.Native, fieldOffset, (Int32)setVal); Marshal.WriteInt32 (ip.Native, fieldOffset, (Int32)setVal);
else throw new NotImplementedException("Cannot write C++ fields of type " + setType.Name); else throw new NotImplementedException("Cannot write C++ fields of type " + setType.Name);
} }
} }

2
Mono.VisualC.Interop/CppInstancePtr.cs

@ -11,7 +11,7 @@ using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop { namespace Mono.VisualC.Interop {
public struct CppInstancePtr : ICppInstance { public struct CppInstancePtr : ICppObject {
private IntPtr ptr; private IntPtr ptr;
private bool manageMemory; private bool manageMemory;

6
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 // For a class that may have fields with no virtual methods to be overridden
public Iface GetClass<Iface,NativeLayout> (string className) public Iface GetClass<Iface,NativeLayout> (string className)
where Iface : ICppInstantiatable where Iface : ICppClassInstantiatable
where NativeLayout : struct where NativeLayout : struct
{ {
@ -69,9 +69,9 @@ namespace Mono.VisualC.Interop
// For a class that may have fields and virtual methods to be overridden // For a class that may have fields and virtual methods to be overridden
public Iface GetClass<Iface,NativeLayout,Managed> (string className) public Iface GetClass<Iface,NativeLayout,Managed> (string className)
where Iface : ICppOverridable<Managed> where Iface : ICppClassOverridable<Managed>
where NativeLayout : struct where NativeLayout : struct
where Managed : ICppInstance where Managed : ICppObject
{ {
return Abi.ImplementClass<Iface, NativeLayout> (interopModule, typeof (Managed), Name, className); return Abi.ImplementClass<Iface, NativeLayout> (interopModule, typeof (Managed), Name, className);

21
Mono.VisualC.Interop/Interfaces.cs

@ -9,23 +9,36 @@
using System; using System;
<<<<<<< HEAD
namespace Mono.VisualC.Interop namespace Mono.VisualC.Interop
{ {
public interface ICppInstance : IDisposable public interface ICppInstance : IDisposable
{ {
IntPtr Native { get; } 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 public interface ICppClassInstantiatable {
{ CppInstancePtr Alloc ();
CppInstancePtr Alloc(); void Destruct (CppInstancePtr instance);
void Destruct(CppInstancePtr instance);
} }
<<<<<<< HEAD
public interface ICppOverridable<T> where T : ICppInstance public interface ICppOverridable<T> where T : ICppInstance
{ {
CppInstancePtr Alloc(T managed); CppInstancePtr Alloc(T managed);
void Destruct(CppInstancePtr instance); void Destruct(CppInstancePtr instance);
=======
public interface ICppClassOverridable<T> where T : ICppObject {
CppInstancePtr Alloc (T managed);
void Destruct (CppInstancePtr instance);
>>>>>>> Refactored and completed managed VTable implementation. Prepared for
} }
} }

4
Mono.VisualC.Interop/Mono.VisualC.Interop.csproj

@ -18,7 +18,6 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AssemblyName>Mono.VisualC.Interop</AssemblyName> <AssemblyName>Mono.VisualC.Interop</AssemblyName>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
@ -28,7 +27,6 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AssemblyName>CPPInterop</AssemblyName> <AssemblyName>CPPInterop</AssemblyName>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Linux|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Linux|AnyCPU' ">
@ -37,7 +35,6 @@
<OutputPath>bin\Release</OutputPath> <OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<AssemblyName>CPPInterop</AssemblyName> <AssemblyName>CPPInterop</AssemblyName>
</PropertyGroup> </PropertyGroup>
@ -50,6 +47,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CppLibrary.cs" /> <Compile Include="CppLibrary.cs" />

Loading…
Cancel
Save