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; @@ -9,21 +9,39 @@ using Mono.VisualC.Interop;
namespace CPPPOC {
<<<<<<< HEAD
public class CSimpleClass : ICppInstance {
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 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<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 {
public int value;
}
#endregion
private static __ICSimpleClass _impl;

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

@ -8,6 +8,7 @@ @@ -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 { @@ -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 { @@ -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<Delegate> vtableDelegates = new List<Delegate>();
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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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);

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

@ -19,37 +19,34 @@ namespace Mono.VisualC.Interop.ABI { @@ -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 { @@ -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;

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

@ -8,6 +8,7 @@ @@ -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 { @@ -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<T> (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 ();
}
}
}

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

@ -17,15 +17,55 @@ using System.Runtime.InteropServices; @@ -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<T> (IntPtr native, int index)
public T GetDelegateForNative<T> (IntPtr native, int index) where T : class /*Delegate*/
{
IntPtr vtable = Marshal.ReadIntPtr (native);
if (vtable == vtPtr) // do not return managed overrides

33
Mono.VisualC.Interop/CppField.cs

@ -10,10 +10,8 @@ @@ -10,10 +10,8 @@
using System;
using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop
{
public class CppField<T>
{
namespace Mono.VisualC.Interop {
public class CppField<T> {
private int fieldOffset;
public CppField (int fieldOffset)
@ -23,8 +21,9 @@ namespace Mono.VisualC.Interop @@ -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 @@ -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);
}
}

2
Mono.VisualC.Interop/CppInstancePtr.cs

@ -11,7 +11,7 @@ using System; @@ -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;

6
Mono.VisualC.Interop/CppLibrary.cs

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

21
Mono.VisualC.Interop/Interfaces.cs

@ -9,23 +9,36 @@ @@ -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<T> where T : ICppInstance
{
CppInstancePtr Alloc(T managed);
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 @@ @@ -18,7 +18,6 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AssemblyName>Mono.VisualC.Interop</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
@ -28,7 +27,6 @@ @@ -28,7 +27,6 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AssemblyName>CPPInterop</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Linux|AnyCPU' ">
@ -37,7 +35,6 @@ @@ -37,7 +35,6 @@
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ConsolePause>false</ConsolePause>
<AssemblyName>CPPInterop</AssemblyName>
</PropertyGroup>
@ -50,6 +47,7 @@ @@ -50,6 +47,7 @@
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="CppLibrary.cs" />

Loading…
Cancel
Save