Browse Source

Refined mechanism for representing C++ inheritance that enables more accurate calculation of native class size. Lazy generation and caching of delegate types.

git-svn-id: https://mono-soc-2010.googlecode.com/svn/trunk/cppinterop@95 a470b8cb-0e6f-1642-1b45-71e107334c4b
pull/1/head
alexander.corrado 15 years ago
parent
commit
14e5a64fdb
  1. 2
      CPPInterop.sln
  2. 366
      Mono.VisualC.Interop/ABI/CppAbi.cs
  3. 24
      Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs
  4. 47
      Mono.VisualC.Interop/ABI/Impl/ItaniumTypeInfo.cs
  5. 16
      Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs
  6. 32
      Mono.VisualC.Interop/ABI/Impl/MsvcTypeInfo.cs
  7. 3
      Mono.VisualC.Interop/ABI/Impl/VirtualOnlyAbi.cs
  8. 42
      Mono.VisualC.Interop/ABI/VTable.cs
  9. 33
      Mono.VisualC.Interop/ABI/VTableCOM.cs
  10. 43
      Mono.VisualC.Interop/ABI/VTableManaged.cs
  11. 37
      Mono.VisualC.Interop/Attributes.cs
  12. 17
      Mono.VisualC.Interop/CppInstancePtr.cs
  13. 2
      Mono.VisualC.Interop/CppObjectMarshaler.cs
  14. 184
      Mono.VisualC.Interop/CppTypeInfo.cs
  15. 13
      Mono.VisualC.Interop/Interfaces.cs
  16. 12
      Mono.VisualC.Interop/Mono.VisualC.Interop.csproj
  17. 74
      Mono.VisualC.Interop/Util/DelegateTypeCache.cs
  18. 212
      Mono.VisualC.Interop/Util/IEnumerableTransform.cs
  19. 105
      Mono.VisualC.Interop/Util/LazyGeneratedList.cs
  20. 102
      Mono.VisualC.Interop/Util/MethodSignature.cs
  21. 13
      Mono.VisualC.Interop/Util/ReflectionHelper.cs
  22. 33
      QtBindings/Core/QCoreApplication.cs
  23. 29
      QtBindings/Core/QObject.cs
  24. 2
      QtBindings/Core/QString.cs
  25. 22
      QtBindings/Gui/QAbstractButton.cs
  26. 30
      QtBindings/Gui/QApplication.cs
  27. 23
      QtBindings/Gui/QPaintDevice.cs
  28. 27
      QtBindings/Gui/QPushButton.cs
  29. 32
      QtBindings/Gui/QWidget.cs
  30. 8
      QtTest/Main.cs

2
CPPInterop.sln

@ -39,7 +39,7 @@ Global @@ -39,7 +39,7 @@ Global
{B01E6282-144E-481A-8E1F-95F708DFBC2D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
StartupItem = Mono.VisualC.Interop\Mono.VisualC.Interop.csproj
StartupItem = QtTest\QtTest.csproj
Policies = $0
$0.TextStylePolicy = $1
$1.NoTabsAfterNonTabs = True

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

@ -15,6 +15,8 @@ using System.Reflection.Emit; @@ -15,6 +15,8 @@ using System.Reflection.Emit;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Mono.VisualC.Interop.Util;
namespace Mono.VisualC.Interop.ABI {
//FIXME: Exception handling, operator overloading etc.
@ -27,64 +29,44 @@ namespace Mono.VisualC.Interop.ABI { @@ -27,64 +29,44 @@ namespace Mono.VisualC.Interop.ABI {
protected Type interface_type, layout_type, wrapper_type;
protected string library, class_name;
protected VTable vtable;
protected FieldBuilder vtable_field, native_size_field;
protected FieldBuilder typeinfo_field;
protected ILGenerator ctor_il;
// Default settings that subclasses can override:
protected MakeVTableDelegate make_vtable_method = VTable.DefaultImplementation;
protected MemberFilter vtable_override_filter = VTable.BindToSignatureAndAttribute;
protected MemberFilter vtable_override_filter = VTable.BindToSignatureAndAttribute;
// Cache some frequently used methodinfos:
private static readonly MethodInfo typeinfo_nativesize = typeof (CppTypeInfo).GetProperty ("NativeSize").GetGetMethod ();
private static readonly MethodInfo typeinfo_vtable = typeof (CppTypeInfo).GetProperty ("VTable").GetGetMethod ();
private static readonly MethodInfo typeinfo_adjvcall = typeof (CppTypeInfo).GetMethod ("GetAdjustedVirtualCall");
private static readonly MethodInfo vtable_initinstance = typeof (VTable).GetMethod ("InitInstance");
private static readonly MethodInfo vtable_resetinstance = typeof (VTable).GetMethod ("ResetInstance");
// These methods might be more commonly overridden for a given C++ ABI:
public virtual MethodType GetMethodType (MethodInfo imethod)
{
if (imethod.Name.Equals (class_name))
if (imethod.IsDefined (typeof (ConstructorAttribute), false))
return MethodType.NativeCtor;
else if (imethod.Name.Equals ("Alloc"))
return MethodType.ManagedAlloc;
else if (imethod.Name.Equals ("Destruct"))
else if (imethod.IsDefined (typeof (DestructorAttribute), false))
return MethodType.NativeDtor;
return MethodType.Native;
}
public virtual int FieldOffsetPadding {
get { return Marshal.SizeOf (typeof (IntPtr)); }
}
// the padding in the data pointed to by the vtable pointer before the list of function pointers starts
public virtual int VTableTopPadding {
get { return 0; }
}
// the amount of extra room alloc'd after the function pointer list of the vtbl
public virtual int VTableBottomPadding {
get { return 0; }
}
protected virtual int NativeSize {
get {
// By default: native size = C++ class size + field offset padding (usually just vtable pointer)
// FIXME: Only include vtable ptr if there are virtual functions? Here I guess it doesn't really matter,
// we're just allocing extra memory.
return Marshal.SizeOf (layout_type) + FieldOffsetPadding;
}
}
// The members below must be implemented for a given C++ ABI:
// The members below must be implemented for a given C++ ABI:
public abstract string GetMangledMethodName (MethodInfo methodInfo);
public abstract CallingConvention? GetCallingConvention (MethodInfo methodInfo);
private struct EmptyNativeLayout { }
public abstract string GetMangledMethodName (MethodInfo methodInfo);
public abstract CallingConvention? GetCallingConvention (MethodInfo methodInfo);
// The ImplementClass overrides are the main entry point to the Abi API:
public Iface ImplementClass<Iface> (Type wrapperType, string lib, string className)
{
return this.ImplementClass<Iface,EmptyNativeLayout> (wrapperType, lib, className);
}
private struct EmptyNativeLayout { }
public Iface ImplementClass<Iface> (Type wrapperType, string lib, string className)
{
return this.ImplementClass<Iface,EmptyNativeLayout> (wrapperType, lib, className);
}
public virtual Iface ImplementClass<Iface, NLayout> (Type wrapperType, string lib, string className)
where NLayout : struct
@ -101,41 +83,29 @@ namespace Mono.VisualC.Interop.ABI { @@ -101,41 +83,29 @@ namespace Mono.VisualC.Interop.ABI {
var properties = GetProperties ();
var methods = GetMethods ();
var baseVirtualMethods = GetBaseVirtualMethods ();
// FIXME: Lazy generate vtable delegates and cache them
List<Type> delegateTypes = new List<Type> ();
List<Delegate> delegates = new List<Delegate> ();
foreach (var method in baseVirtualMethods.Concat (GetVirtualMethods ())) {
Type delType = DefineVTableDelegate (method);
delegateTypes.Add (delType);
delegates.Add (GetManagedOverrideTrampoline (method, delType, vtable_override_filter));
}
CppTypeInfo typeInfo = MakeTypeInfo (methods.Where (m => IsVirtual (m)));
// ONLY make vtable if there are virtual methods
if (delegateTypes.Count > 0)
vtable = make_vtable_method (delegateTypes, delegates, VTableTopPadding, VTableBottomPadding);
else
vtable = null;
int vtableIndex = baseVirtualMethods.Count ();
// Implement all methods
foreach (var method in methods) {
DefineMethod (method, vtableIndex);
if (IsVirtual (method))
vtableIndex++;
}
// Implement all methods
int vtableIndex = 0;
foreach (var method in methods)
DefineMethod (method, typeInfo, ref vtableIndex);
// Implement all properties
foreach (var property in properties)
DefineProperty (property);
ctor_il.Emit (OpCodes.Ret);
return (Iface)Activator.CreateInstance (impl_type.CreateType (), vtable, NativeSize);
return (Iface)Activator.CreateInstance (impl_type.CreateType (), typeInfo);
}
protected virtual CppTypeInfo MakeTypeInfo (IEnumerable<MethodInfo> virtualMethods)
{
return new CppTypeInfo (this, virtualMethods, layout_type);
}
protected virtual IEnumerable<PropertyInfo> GetProperties ()
{
return ( // get all properties defined on the interface
@ -148,20 +118,16 @@ namespace Mono.VisualC.Interop.ABI { @@ -148,20 +118,16 @@ namespace Mono.VisualC.Interop.ABI {
);
}
protected IEnumerable<MethodInfo> GetMethods ()
{
return GetMethods (interface_type);
}
protected virtual IEnumerable<MethodInfo> GetMethods (Type interfaceType)
protected virtual IEnumerable<MethodInfo> GetMethods ()
{
// get all methods defined on inherited interfaces first
var methods = (
from iface in interfaceType.GetInterfaces ()
from iface in interface_type.GetInterfaces ()
from method in iface.GetMethods ()
where !method.IsSpecialName
select method
).Concat (
from method in interfaceType.GetMethods ()
from method in interface_type.GetMethods ()
where !method.IsSpecialName
orderby method.MetadataToken
select method
@ -170,81 +136,27 @@ namespace Mono.VisualC.Interop.ABI { @@ -170,81 +136,27 @@ namespace Mono.VisualC.Interop.ABI {
return methods;
}
protected IEnumerable<MethodInfo> GetVirtualMethods ()
{
return GetVirtualMethods (interface_type);
}
protected virtual IEnumerable<MethodInfo> GetVirtualMethods (Type interfaceType)
{
var delegates = (
from method in GetMethods (interfaceType)
where IsVirtual (method)
select method
);
return delegates;
}
protected virtual IEnumerable<MethodInfo> GetBaseVirtualMethods ()
{
var bases = GetBasesRecursive ();
if (!bases.Any ())
return Enumerable.Empty<MethodInfo> ();
var virtualMethods = from iface in bases
from method in GetVirtualMethods (iface)
select method;
return virtualMethods;
}
protected IEnumerable<Type> GetImmediateBases ()
{
return GetImmediateBases (interface_type);
}
protected virtual IEnumerable<Type> GetImmediateBases (Type interfaceType)
{
var immediateBases = (
from baseIface in interfaceType.GetInterfaces ()
where baseIface.Name.Equals ("Base`1")
from iface in baseIface.GetGenericArguments ()
select iface
);
return immediateBases;
}
protected IEnumerable<Type> GetBasesRecursive ()
{
return GetBasesRecursive (interface_type);
}
protected IEnumerable<Type> GetBasesRecursive (Type searchStart)
{
var immediateBases = GetImmediateBases (searchStart);
if (!immediateBases.Any ())
return Enumerable.Empty<Type> ();
List<Type> allBases = new List<Type> ();
foreach (var baseInterface in immediateBases) {
allBases.AddRange (GetBasesRecursive (baseInterface));
allBases.Add (baseInterface);
}
return allBases;
}
protected virtual void DefineImplType ()
{
string implTypeName = interface_type.Name + "_" + layout_type.Name + "_" + this.GetType ().Name + "_Impl";
impl_type = impl_module.DefineType (implTypeName, TypeAttributes.Class | TypeAttributes.Sealed);
impl_type.AddInterfaceImplementation (interface_type);
vtable_field = impl_type.DefineField ("_vtable", typeof (VTable), FieldAttributes.InitOnly | FieldAttributes.Private);
native_size_field = impl_type.DefineField ("_nativeSize", typeof (int), FieldAttributes.InitOnly | FieldAttributes.Private);
//vtable_field = impl_type.DefineField ("_vtable", typeof (VTable), FieldAttributes.InitOnly | FieldAttributes.Private);
//native_size_field = impl_type.DefineField ("_nativeSize", typeof (int), FieldAttributes.InitOnly | FieldAttributes.Private);
typeinfo_field = impl_type.DefineField ("_typeInfo", typeof (CppTypeInfo), FieldAttributes.InitOnly | FieldAttributes.Private);
ConstructorBuilder ctor = impl_type.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard,
new Type[] { typeof (VTable), typeof (int) });
new Type[] { typeof (CppTypeInfo) });
ctor_il = ctor.GetILGenerator ();
// this._typeInfo = (CppTypeInfo passed to constructor)
ctor_il.Emit (OpCodes.Ldarg_0);
ctor_il.Emit (OpCodes.Ldarg_1);
ctor_il.Emit (OpCodes.Stfld, typeinfo_field);
/*
// this._vtable = (VTable passed to constructor)
ctor_il.Emit (OpCodes.Ldarg_0);
ctor_il.Emit (OpCodes.Ldarg_1);
@ -253,13 +165,14 @@ namespace Mono.VisualC.Interop.ABI { @@ -253,13 +165,14 @@ namespace Mono.VisualC.Interop.ABI {
ctor_il.Emit (OpCodes.Ldarg_0);
ctor_il.Emit (OpCodes.Ldarg_2);
ctor_il.Emit (OpCodes.Stfld, native_size_field);
*/
}
protected virtual MethodBuilder DefineMethod (MethodInfo interfaceMethod, int index)
protected virtual MethodBuilder DefineMethod (MethodInfo interfaceMethod, CppTypeInfo typeInfo, ref int vtableIndex)
{
// 0. Introspect method
MethodType methodType = GetMethodType (interfaceMethod);
Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod);
Type [] parameterTypes = ReflectionHelper.GetMethodParameterTypes (interfaceMethod);
// 1. Generate managed trampoline to call native method
MethodBuilder trampoline = GetMethodBuilder (interfaceMethod);
@ -279,35 +192,29 @@ namespace Mono.VisualC.Interop.ABI { @@ -279,35 +192,29 @@ namespace Mono.VisualC.Interop.ABI {
return trampoline;
}
bool isStatic = true;
bool isStatic = IsStatic (interfaceMethod);
LocalBuilder cppInstancePtr = null;
LocalBuilder nativePtr = null;
// If we're not a static method, do the following ...
if (!IsStatic (interfaceMethod))
// If we're an instance method, load up the "this" pointer
if (!isStatic)
{
isStatic = false;
if (parameterTypes.Length < 1)
throw new ArgumentException ("First argument to non-static C++ method must be IntPtr or CppInstancePtr.");
// 2. Load the native C++ instance pointer
EmitLoadInstancePtr (il, parameterTypes[0], out cppInstancePtr, out nativePtr);
EmitLoadInstancePtr (il, parameterTypes [0], out cppInstancePtr, out nativePtr);
// 3. Make sure our native pointer is a valid reference. If not, throw ObjectDisposedException
EmitCheckDisposed (il, nativePtr, methodType);
}
MethodInfo nativeMethod;
bool isVirtual;
if (IsVirtual (interfaceMethod)) {
isVirtual = true;
nativeMethod = vtable.PrepareVirtualCall (interfaceMethod, GetCallingConvention (interfaceMethod),
il, nativePtr, vtable_field, index);
} else {
isVirtual = false;
if (IsVirtual (interfaceMethod) && methodType != MethodType.NativeDtor)
nativeMethod = EmitPrepareVirtualCall (il, typeInfo, nativePtr, vtableIndex++);
else
nativeMethod = GetPInvokeForMethod (interfaceMethod);
}
switch (methodType) {
case MethodType.NativeCtor:
@ -315,10 +222,10 @@ namespace Mono.VisualC.Interop.ABI { @@ -315,10 +222,10 @@ namespace Mono.VisualC.Interop.ABI {
break;
case MethodType.NativeDtor:
EmitDestruct (il, nativeMethod, isVirtual, parameterTypes, cppInstancePtr, nativePtr);
EmitDestruct (il, nativeMethod, parameterTypes, cppInstancePtr, nativePtr);
break;
default: // regular native method
default:
EmitCallNative (il, nativeMethod, isStatic, parameterTypes, nativePtr);
break;
@ -339,14 +246,15 @@ namespace Mono.VisualC.Interop.ABI { @@ -339,14 +246,15 @@ namespace Mono.VisualC.Interop.ABI {
Type retType = imethod.ReturnType;
FieldBuilder fieldData;
// C++ interface properties are either to return the VTable, get NativeSize, or to access C++ fields
// C++ interface properties are either to return the CppTypeInfo or to access C++ fields
if (retType.IsGenericType && retType.GetGenericTypeDefinition ().Equals (typeof (CppField<>))) {
// define a new field for the property
fieldData = impl_type.DefineField ("__" + propName + "_Data", retType, FieldAttributes.InitOnly | FieldAttributes.Private);
// define a new field for the property
// fieldData = impl_type.DefineField ("__" + propName + "_Data", retType, FieldAttributes.InitOnly | FieldAttributes.Private);
// init our field data with a new instance of CppField
// first, get field offset
ctor_il.Emit (OpCodes.Ldarg_0);
//ctor_il.Emit (OpCodes.Ldarg_0);
/* TODO: Code prolly should not emit hardcoded offsets n such, in case we end up saving these assemblies in the future.
* Something more like this perhaps? (need to figure out how to get field offset padding into this)
@ -355,15 +263,16 @@ namespace Mono.VisualC.Interop.ABI { @@ -355,15 +263,16 @@ namespace Mono.VisualC.Interop.ABI {
* ctorIL.Emit(OpCodes.Ldstr, propName);
* ctorIL.Emit(OpCodes.Call, typeof(Marshal).GetMethod("OffsetOf"));
*/
/*
int fieldOffset = ((int)Marshal.OffsetOf (layout_type, propName)) + FieldOffsetPadding;
ctor_il.Emit (OpCodes.Ldc_I4, fieldOffset);
ctor_il.Emit (OpCodes.Newobj, retType.GetConstructor (new Type[] { typeof(int) }));
ctor_il.Emit (OpCodes.Stfld, fieldData);
} else if (retType.Equals (typeof (VTable)))
fieldData = vtable_field;
else if (retType.Equals (typeof (int)))
fieldData = native_size_field;
*/
throw new NotImplementedException ("CppFields need to be reimplemented to use CppTypeInfo.");
} else if (retType.Equals (typeof (CppTypeInfo)))
fieldData = typeinfo_field;
else
throw new InvalidProgramException ("Properties in C++ interface can only be of type CppField.");
@ -386,12 +295,13 @@ namespace Mono.VisualC.Interop.ABI { @@ -386,12 +295,13 @@ 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, Type delegateType, MemberFilter binder)
internal virtual Delegate GetManagedOverrideTrampoline (CppTypeInfo typeInfo, int vtableIndex)
{
if (wrapper_type == null)
return null;
MethodInfo targetMethod = FindManagedOverrideTarget (interfaceMethod, binder);
MethodInfo interfaceMethod = typeInfo.VirtualMethods [vtableIndex];
MethodInfo targetMethod = FindManagedOverrideTarget (interfaceMethod);
if (targetMethod == null)
return null;
@ -403,7 +313,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -403,7 +313,7 @@ namespace Mono.VisualC.Interop.ABI {
DynamicMethod trampolineIn = new DynamicMethod (wrapper_type.Name + "_" + interfaceMethod.Name + "_FromNative", interfaceMethod.ReturnType,
parameterTypes, typeof (CppInstancePtr).Module, true);
Util.ApplyMethodParameterAttributes (interfaceMethod, trampolineIn, true);
ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, trampolineIn, true);
ILGenerator il = trampolineIn.GetILGenerator ();
// for static methods:
@ -415,8 +325,8 @@ namespace Mono.VisualC.Interop.ABI { @@ -415,8 +325,8 @@ namespace Mono.VisualC.Interop.ABI {
callInstruction = OpCodes.Callvirt;
//argLoadStart = 1;
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldc_I4, NativeSize);
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldc_I4, typeInfo.NativeSize);
MethodInfo getManagedObj = typeof (CppInstancePtr).GetMethod ("GetManaged", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod (wrapper_type);
il.Emit (OpCodes.Call, getManagedObj);
@ -429,13 +339,14 @@ namespace Mono.VisualC.Interop.ABI { @@ -429,13 +339,14 @@ namespace Mono.VisualC.Interop.ABI {
il.Emit (callInstruction, targetMethod);
il.Emit (OpCodes.Ret);
return trampolineIn.CreateDelegate (delegateType);
return trampolineIn.CreateDelegate (typeInfo.VTableDelegateTypes [vtableIndex]);
}
protected virtual MethodInfo FindManagedOverrideTarget (MethodInfo interfaceMethod, MemberFilter filter)
protected virtual MethodInfo FindManagedOverrideTarget (MethodInfo interfaceMethod)
{
MemberInfo[] possibleMembers = wrapper_type.FindMembers (MemberTypes.Method, BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.Static, filter, interfaceMethod);
// FIXME: Does/should this look in superclasses?
MemberInfo [] possibleMembers = wrapper_type.FindMembers (MemberTypes.Method, BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.Static, vtable_override_filter, interfaceMethod);
if (possibleMembers.Length > 1)
throw new InvalidProgramException ("More than one possible override found when binding virtual method: " + interfaceMethod.Name);
@ -444,16 +355,17 @@ namespace Mono.VisualC.Interop.ABI { @@ -444,16 +355,17 @@ namespace Mono.VisualC.Interop.ABI {
return (MethodInfo)possibleMembers [0];
}
/**
* Defines a new MethodBuilder with the same signature as the passed MethodInfo
*/
protected virtual MethodBuilder GetMethodBuilder (MethodInfo interfaceMethod)
{
Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod);
Type [] parameterTypes = ReflectionHelper.GetMethodParameterTypes (interfaceMethod);
MethodBuilder methodBuilder = impl_type.DefineMethod (interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual,
interfaceMethod.ReturnType, parameterTypes);
Util.ApplyMethodParameterAttributes (interfaceMethod, methodBuilder, false);
ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, methodBuilder, false);
return methodBuilder;
}
@ -466,46 +378,34 @@ namespace Mono.VisualC.Interop.ABI { @@ -466,46 +378,34 @@ namespace Mono.VisualC.Interop.ABI {
if (entryPoint == null)
throw new NotSupportedException ("Could not mangle method name.");
Type[] parameterTypes = GetParameterTypesForPInvoke (signature).ToArray ();
Type [] parameterTypes = GetParameterTypesForPInvoke (signature).ToArray ();
MethodBuilder builder = impl_type.DefinePInvokeMethod ("__$" + signature.Name + "_Impl", library, entryPoint,
MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl,
CallingConventions.Standard, signature.ReturnType, parameterTypes,
GetCallingConvention (signature).Value, CharSet.Ansi);
builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig);
Util.ApplyMethodParameterAttributes (signature, builder, true);
ReflectionHelper.ApplyMethodParameterAttributes (signature, builder, true);
return builder;
}
protected virtual Type DefineVTableDelegate (MethodInfo targetMethod)
/**
* Emits the IL to load the correct delegate instance and/or retrieve the MethodInfo from the VTable
* for a C++ virtual call.
*/
protected virtual MethodInfo EmitPrepareVirtualCall (ILGenerator il, CppTypeInfo typeInfo, LocalBuilder native, int vtableIndex)
{
// FIXME: Actually return the same delegate type instead of creating a new one if
// a suitable type already exists??
CallingConvention? callingConvention = GetCallingConvention (targetMethod);
string delTypeName = "_" + targetMethod.DeclaringType.Name + "_" + targetMethod.Name + "_VTdel";
while (CppLibrary.interopModule.GetType (delTypeName) != null)
delTypeName += "_";
TypeAttributes typeAttr = TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass;
TypeBuilder del = CppLibrary.interopModule.DefineType (delTypeName, typeAttr, typeof(MulticastDelegate));
if (callingConvention.HasValue) {
ConstructorInfo ufpa = typeof (UnmanagedFunctionPointerAttribute).GetConstructor (new Type [] { typeof (CallingConvention) });
CustomAttributeBuilder unmanagedPointer = new CustomAttributeBuilder (ufpa, new object [] { callingConvention.Value });
del.SetCustomAttribute (unmanagedPointer);
}
MethodAttributes ctorAttr = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public;
ConstructorBuilder ctor = del.DefineConstructor (ctorAttr, CallingConventions.Standard, new Type[] { typeof(object), typeof(System.IntPtr) });
ctor.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
Type vtableDelegateType = typeInfo.VTableDelegateTypes [vtableIndex];
MethodInfo getDelegate = typeinfo_adjvcall.MakeGenericMethod (vtableDelegateType);
Type[] parameterTypes = GetParameterTypesForPInvoke (targetMethod).ToArray ();
MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual;
// this._typeInfo.GetAdjustedVirtualCall<T> (native, vtableIndex);
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeinfo_field);
il.Emit (OpCodes.Ldloc_S, native);
il.Emit (OpCodes.Ldc_I4, vtableIndex);
il.Emit (OpCodes.Callvirt, getDelegate);
MethodBuilder invokeMethod = del.DefineMethod ("Invoke", methodAttr, targetMethod.ReturnType, parameterTypes);
invokeMethod.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
return del.CreateType ();
return ReflectionHelper.GetMethodInfoForDelegate (vtableDelegateType);
}
/**
@ -514,22 +414,14 @@ namespace Mono.VisualC.Interop.ABI { @@ -514,22 +414,14 @@ namespace Mono.VisualC.Interop.ABI {
*/
protected virtual void EmitManagedAlloc (ILGenerator il, MethodInfo interfaceMethod)
{
Type paramType = interfaceMethod.GetParameters () [0].ParameterType;
if (typeof (ICppObject).IsAssignableFrom (paramType))
{
// TODO: This is probably going to be causing us to alloc too much memory
// if the ICppObject is returning impl.NativeSize + base.NativeSize. (We get FieldOffsetPadding
// each time).
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Callvirt, typeof (ICppObject).GetProperty ("NativeSize").GetGetMethod ());
} else
il.Emit (OpCodes.Ldfld, native_size_field);
// this._typeInfo.NativeSize
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeinfo_field);
il.Emit (OpCodes.Callvirt, typeinfo_nativesize);
if (wrapper_type != null) {
// load managed object
// load managed wrapper
il.Emit (OpCodes.Ldarg_1);
//new CppInstancePtr (Abi.GetNativeSize (typeof (NativeLayout)), managedWrapper);
il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null,
new Type[] { typeof (int), typeof (object) }, null));
} else
@ -544,12 +436,11 @@ namespace Mono.VisualC.Interop.ABI { @@ -544,12 +436,11 @@ namespace Mono.VisualC.Interop.ABI {
EmitInitVTable (il, nativePtr);
}
protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod, bool isVirtual, Type [] parameterTypes,
protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod, Type [] parameterTypes,
LocalBuilder cppInstancePtr, LocalBuilder nativePtr)
{
// bail if we weren't alloc'd by managed code
Label bail = il.DefineLabel ();
Label retNormal = il.DefineLabel ();
il.Emit (OpCodes.Ldloca_S, cppInstancePtr);
il.Emit (OpCodes.Brfalse_S, bail); // <- FIXME? (would this ever branch?)
@ -559,15 +450,8 @@ namespace Mono.VisualC.Interop.ABI { @@ -559,15 +450,8 @@ namespace Mono.VisualC.Interop.ABI {
EmitResetVTable (il, nativePtr);
EmitCallNative (il, nativeMethod, false, parameterTypes, nativePtr);
il.Emit (OpCodes.Br_S, retNormal);
// before we bail, we have to pop the vtbl delegate from the stack if this
// is a virtual destructor
il.MarkLabel (bail);
if (isVirtual)
il.Emit (OpCodes.Pop);
il.MarkLabel (retNormal);
}
/**
@ -610,9 +494,9 @@ namespace Mono.VisualC.Interop.ABI { @@ -610,9 +494,9 @@ namespace Mono.VisualC.Interop.ABI {
// auto marshal ICppObject
}
protected virtual IEnumerable<Type> GetParameterTypesForPInvoke (MethodInfo method)
public virtual IEnumerable<Type> GetParameterTypesForPInvoke (MethodInfo method)
{
var originalTypes = Util.GetMethodParameterTypes (method);
var originalTypes = ReflectionHelper.GetMethodParameterTypes (method);
var pinvokeTypes = originalTypes.Transform (
For.AnyInputIn (typeof (bool)).Emit (typeof (byte)),
@ -625,26 +509,35 @@ namespace Mono.VisualC.Interop.ABI { @@ -625,26 +509,35 @@ namespace Mono.VisualC.Interop.ABI {
return pinvokeTypes;
}
/**
* Emits IL to load the VTable object onto the stack.
*/
protected virtual void EmitLoadVTable (ILGenerator il)
{
// this._typeInfo.VTable
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeinfo_field);
il.Emit (OpCodes.Callvirt, typeinfo_vtable);
}
/**
* Emits IL to set the vtable pointer of the instance (if class has a vtable).
* This should usually happen in the managed wrapper of the C++ instance constructor.
*/
protected virtual void EmitInitVTable (ILGenerator il, LocalBuilder nativePtr)
{
// this._vtable.InitInstance (nativePtr);
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, vtable_field);
// this._typeInfo.VTable.InitInstance (nativePtr);
EmitLoadVTable (il);
il.Emit (OpCodes.Ldloc_S, nativePtr);
EmitVTableOp (il, typeof (VTable).GetMethod ("InitInstance"), 2, false);
EmitCallVTableMethod (il, vtable_initinstance, 2, false);
}
protected virtual void EmitResetVTable (ILGenerator il, LocalBuilder nativePtr)
{
// this._vtable.ResetInstance (nativePtr);
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, vtable_field);
// this._typeInfo.VTable.ResetInstance (nativePtr);
EmitLoadVTable (il);
il.Emit (OpCodes.Ldloc_S, nativePtr);
EmitVTableOp (il, typeof(VTable).GetMethod ("ResetInstance"), 2, false);
EmitCallVTableMethod (il, vtable_resetinstance, 2, false);
}
/**
@ -655,15 +548,14 @@ namespace Mono.VisualC.Interop.ABI { @@ -655,15 +548,14 @@ namespace Mono.VisualC.Interop.ABI {
* want to call and pass the stackHeight for the call. If no vtable exists, this method
* will emit code to pop the arguments off the stack.
*/
protected virtual void EmitVTableOp(ILGenerator il, MethodInfo method, int stackHeight,
bool throwOnNoVTable)
protected virtual void EmitCallVTableMethod (ILGenerator il, MethodInfo method, int stackHeight,
bool throwOnNoVTable)
{
// prepare a jump; do not call vtable method if no vtable
Label noVirt = il.DefineLabel ();
Label dontPushOrThrow = il.DefineLabel ();
il.Emit (OpCodes.Ldarg_0); // load this
il.Emit (OpCodes.Ldfld, vtable_field); // load this._vtable
EmitLoadVTable (il);
il.Emit (OpCodes.Brfalse_S, noVirt); // if (vtableInfo == null) goto noVirt
il.Emit (OpCodes.Callvirt, method); // call method
@ -678,7 +570,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -678,7 +570,7 @@ namespace Mono.VisualC.Interop.ABI {
// if the method was supposed to return a value, we must
// still push something onto the stack
// TODO: This is a kludge. What about value types?
// FIXME: This is a kludge. What about value types?
if (!method.ReturnType.Equals (typeof (void)))
il.Emit (OpCodes.Ldnull);

24
Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs

@ -14,6 +14,8 @@ using System.Reflection; @@ -14,6 +14,8 @@ using System.Reflection;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Mono.VisualC.Interop.Util;
namespace Mono.VisualC.Interop.ABI {
public class ItaniumAbi : CppAbi {
@ -21,27 +23,9 @@ namespace Mono.VisualC.Interop.ABI { @@ -21,27 +23,9 @@ namespace Mono.VisualC.Interop.ABI {
{
}
// Itanium puts all its virtual dtors at the bottom of the vtable (2 slots each).
// Since we will never be in a position of calling a dtor virtually, we can just pad the vtable out.
public override bool IsVirtual (MethodInfo method)
protected override CppTypeInfo MakeTypeInfo (IEnumerable<MethodInfo> virtualMethods)
{
return base.IsVirtual (method) && !method.IsDefined (typeof (VirtualDestructorAttribute), false);
}
public override int VTableBottomPadding {
get {
int vtableBottomPadding = 0;
bool hasVdtor = false;
int vdtorPadding = Marshal.SizeOf (typeof (IntPtr)) * 2;
foreach (var iface in GetBasesRecursive ().With (interface_type)) {
if (hasVdtor || HasVirtualDtor (iface)) {
vtableBottomPadding += vdtorPadding;
hasVdtor = true;
}
}
return vtableBottomPadding;
}
return new ItaniumTypeInfo (this, virtualMethods, layout_type);
}
public override CallingConvention? GetCallingConvention (MethodInfo methodInfo)

47
Mono.VisualC.Interop/ABI/Impl/ItaniumTypeInfo.cs

@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
namespace Mono.VisualC.Interop.ABI {
public class ItaniumTypeInfo : CppTypeInfo {
private bool hasVirtualDtor;
public ItaniumTypeInfo (ItaniumAbi abi, IEnumerable<MethodInfo> virtualMethods, Type nativeLayout)
: base (abi, virtualMethods, nativeLayout)
{
for (int i = 0; i < VirtualMethods.Count; i++) {
if (Abi.GetMethodType (VirtualMethods [i]) != MethodType.NativeDtor)
continue;
hasVirtualDtor = true;
VirtualMethods.RemoveAt (i);
break;
}
}
public bool HasVirtualDestructor {
get { return hasVirtualDtor; }
}
public override void AddBase (CppTypeInfo baseType)
{
hasVirtualDtor |= ((ItaniumTypeInfo)baseType).HasVirtualDestructor;
base.AddBase (baseType);
}
// Itanium puts all its virtual dtors at the bottom of the vtable (2 slots each).
// Since we will never be in a position of calling a dtor virtually, we can just pad the vtable out.
public override int VTableBottomPadding {
get {
if (!hasVirtualDtor)
return 0;
return 2 + CountBases (b => ((ItaniumTypeInfo)b).HasVirtualDestructor) * 2;
}
}
}
}

16
Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs

@ -15,6 +15,7 @@ using System.Collections.Generic; @@ -15,6 +15,7 @@ using System.Collections.Generic;
using System.Runtime.InteropServices;
using Mono.VisualC.Interop;
using Mono.VisualC.Interop.Util;
namespace Mono.VisualC.Interop.ABI {
@ -24,6 +25,11 @@ namespace Mono.VisualC.Interop.ABI { @@ -24,6 +25,11 @@ namespace Mono.VisualC.Interop.ABI {
{
}
protected override CppTypeInfo MakeTypeInfo (IEnumerable<MethodInfo> virtualMethods)
{
return new MsvcTypeInfo (this, virtualMethods, layout_type);
}
public override CallingConvention? GetCallingConvention (MethodInfo methodInfo)
{
// FIXME: Varargs methods ... ?
@ -34,14 +40,6 @@ namespace Mono.VisualC.Interop.ABI { @@ -34,14 +40,6 @@ namespace Mono.VisualC.Interop.ABI {
return CallingConvention.ThisCall;
}
// AFIK, MSVC places only its first base's virtual methods in the derived class's
// primary vtable.
protected override IEnumerable<Type> GetImmediateBases (Type interfaceType)
{
var immediateBases = base.GetImmediateBases (interfaceType);
return immediateBases.Take (1);
}
public override string GetMangledMethodName (MethodInfo methodInfo)
{
string methodName = methodInfo.Name;
@ -74,7 +72,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -74,7 +72,7 @@ namespace Mono.VisualC.Interop.ABI {
// now, offset based on other modifiers
if (IsStatic (methodInfo))
funcModifier += (char)2;
else if (IsVirtual (methodInfo) || IsVirtualDtor (methodInfo))
else if (IsVirtual (methodInfo))
funcModifier += (char)4;
nm.Append (funcModifier);

32
Mono.VisualC.Interop/ABI/Impl/MsvcTypeInfo.cs

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Reflection;
namespace Mono.VisualC.Interop.ABI {
public class MsvcTypeInfo : CppTypeInfo {
public MsvcTypeInfo (MsvcAbi abi, IEnumerable<MethodInfo> virtualMethods, Type nativeLayout)
: base (abi, virtualMethods, nativeLayout)
{
}
// AFIK, MSVC places only its first base's virtual methods in the derived class's
// primary vtable. Subsequent base classes (each?) get another vtable pointer
public override void AddBase (CppTypeInfo baseType)
{
if (TypeComplete)
return;
if (BaseClasses.Count == 0) {
base.AddBase (baseType);
return;
}
BaseClasses.Add (baseType);
field_offset_padding += baseType.NativeSize;
}
}
}

3
Mono.VisualC.Interop/ABI/Impl/VirtualOnlyAbi.cs

@ -16,9 +16,8 @@ namespace Mono.VisualC.Interop.ABI { @@ -16,9 +16,8 @@ namespace Mono.VisualC.Interop.ABI {
public class VirtualOnlyAbi : CppAbi {
public VirtualOnlyAbi (MakeVTableDelegate makeVTable, MemberFilter vtableOverrideFilter)
public VirtualOnlyAbi (MemberFilter vtableOverrideFilter)
{
this.make_vtable_method = makeVTable;
this.vtable_override_filter = vtableOverrideFilter;
}
public VirtualOnlyAbi () { }

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

@ -15,53 +15,40 @@ using System.Reflection.Emit; @@ -15,53 +15,40 @@ using System.Reflection.Emit;
using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop.ABI {
public delegate VTable MakeVTableDelegate (IList<Type> delegateTypes, IList<Delegate> overrides, int paddingTop, int paddingBottom);
public delegate VTable MakeVTableDelegate (CppTypeInfo metadata);
// TODO: RTTI .. support virtual inheritance
public abstract class VTable : IDisposable {
public static MakeVTableDelegate DefaultImplementation = VTableManaged.Implementation;
protected int paddingTop, paddingBottom;
protected CppTypeInfo typeInfo;
protected IntPtr basePtr, vtPtr;
// FIXME: Either make this a lazy list that only generates the delegate type if
// it is needed, and/or cache generated delegate types (see FIXME in CppAbi::DefineVTableDelegate)
protected IList<Type> delegate_types;
// The Length of the array will be equal to the number of entries in the vtable;
// entries that aren't overridden will be NULL.
protected IList<Delegate> overrides;
public virtual int EntryCount {
get { return overrides.Count; }
get { return typeInfo.VirtualMethods.Count; }
}
public virtual int EntrySize {
get { return Marshal.SizeOf (typeof (IntPtr)); }
}
public abstract MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention? callingConvention, ILGenerator callsite,
LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex);
public abstract T GetVirtualCallDelegate<T> (IntPtr native, int vtableIndex) where T : class; /*Delegate*/
// Subclasses should allocate vtPtr and then call WriteOverrides
public VTable (IList<Type> delegateTypes, IList<Delegate> overrides, int paddingTop, int paddingBottom)
public VTable (CppTypeInfo typeInfo)
{
this.delegate_types = delegateTypes;
this.overrides = overrides;
this.basePtr = IntPtr.Zero;
this.vtPtr = IntPtr.Zero;
this.paddingTop = paddingTop;
this.paddingBottom = paddingBottom;
this.typeInfo = typeInfo;
}
protected virtual void WriteOverrides ()
{
IntPtr vtEntryPtr;
int currentOffset = paddingTop;
int currentOffset = typeInfo.VTableTopPadding;
for (int i = 0; i < EntryCount; i++) {
Delegate currentOverride = typeInfo.VTableOverrides [i];
if (overrides [i] != null) // managed override
vtEntryPtr = Marshal.GetFunctionPointerForDelegate (overrides [i]);
if (currentOverride != null) // managed override
vtEntryPtr = Marshal.GetFunctionPointerForDelegate (currentOverride);
else
vtEntryPtr = IntPtr.Zero;
@ -70,26 +57,27 @@ namespace Mono.VisualC.Interop.ABI { @@ -70,26 +57,27 @@ namespace Mono.VisualC.Interop.ABI {
}
}
// FIXME: Make this method unsafe.. it would probably be much faster
public virtual void InitInstance (IntPtr instance)
{
if (basePtr == IntPtr.Zero) {
basePtr = Marshal.ReadIntPtr (instance);
if ((basePtr != IntPtr.Zero) && (basePtr != vtPtr)) {
// FIXME: This could probably be a more efficient memcpy
for(int i = 0; i < paddingTop; i++)
for(int i = 0; i < typeInfo.VTableTopPadding; i++)
Marshal.WriteByte(vtPtr, i, Marshal.ReadByte(basePtr, i));
int currentOffset = paddingTop;
int currentOffset = typeInfo.VTableTopPadding;
for (int i = 0; i < EntryCount; i++) {
if (overrides [i] == null)
if (Marshal.ReadIntPtr (vtPtr, currentOffset) == IntPtr.Zero)
Marshal.WriteIntPtr (vtPtr, currentOffset, Marshal.ReadIntPtr (basePtr, currentOffset));
currentOffset += EntrySize;
}
// FIXME: This could probably be a more efficient memcpy
for(int i = 0; i < paddingBottom; i++)
for(int i = 0; i < typeInfo.VTableBottomPadding; i++)
Marshal.WriteByte(vtPtr, currentOffset + i, Marshal.ReadByte(basePtr, currentOffset + i));
}
}

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

@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
//
// Mono.VisualC.Interop.ABI.VTableCOM.cs: vtable implementation based on COM interop (reqiures mono patch)
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
//
// Copyright (C) 2010 Alexander Corrado
//
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop.ABI {
public class VTableCOM : VTable {
public static MakeVTableDelegate Implementation = (types, overrides, paddingTop, paddingBottom) => { return new VTableCOM (types, overrides, paddingTop, paddingBottom); };
private VTableCOM (IList<Type> types, IList<Delegate> overrides, int paddingTop, int paddingBottom) : base(types, overrides, paddingTop, paddingBottom)
{
}
public override MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention? callingConvention, ILGenerator callsite,
LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex)
{
throw new System.NotImplementedException ();
}
}
}

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

@ -14,54 +14,27 @@ using System.Reflection; @@ -14,54 +14,27 @@ using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using Mono.VisualC.Interop.Util;
namespace Mono.VisualC.Interop.ABI {
public class VTableManaged : VTable {
public static MakeVTableDelegate Implementation = (types, overrides, paddingTop, paddingBottom) => { return new VTableManaged (types, overrides, paddingTop, paddingBottom); };
private VTableManaged (IList<Type> types, IList<Delegate> overrides, int paddingTop, int paddingBottom) : base(types, overrides, paddingTop, paddingBottom)
public static MakeVTableDelegate Implementation = metadata => { return new VTableManaged (metadata); };
private VTableManaged (CppTypeInfo metadata) : base (metadata)
{
this.vtPtr = Marshal.AllocHGlobal ((EntryCount * EntrySize) + paddingTop + paddingBottom);
this.vtPtr = Marshal.AllocHGlobal ((EntryCount * EntrySize) + typeInfo.VTableTopPadding + typeInfo.VTableBottomPadding);
WriteOverrides ();
}
public override MethodInfo PrepareVirtualCall (MethodInfo target, CallingConvention? callingConvention, ILGenerator callsite,
LocalBuilder nativePtr, FieldInfo vtableField, int vtableIndex)
{
Type delegateType = delegate_types [vtableIndex];
MethodInfo getDelegate = typeof (VTableManaged).GetMethod ("GetDelegateForNative").MakeGenericMethod (delegateType);
// 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, nativePtr);
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 Util.GetMethodInfoForDelegate (delegateType);
}
public virtual T GetDelegateForNative<T> (IntPtr native, int index) where T : class /*Delegate*/
public override T GetVirtualCallDelegate<T> (IntPtr native, int index)
{
IntPtr vtable = Marshal.ReadIntPtr (native);
if (vtable == vtPtr) // do not return managed overrides
vtable = basePtr;
IntPtr ftnptr = Marshal.ReadIntPtr (vtable, (index * EntrySize) + paddingTop);
IntPtr ftnptr = Marshal.ReadIntPtr (vtable, (index * EntrySize) + typeInfo.VTableTopPadding);
if (ftnptr == IntPtr.Zero)
return null;
throw new NullReferenceException ("Native VTable contains null...possible abstract class???");
Delegate del = Marshal.GetDelegateForFunctionPointer (ftnptr, typeof (T));
return del as T;

37
Mono.VisualC.Interop/Attributes.cs

@ -14,11 +14,16 @@ using System.Reflection; @@ -14,11 +14,16 @@ using System.Reflection;
namespace Mono.VisualC.Interop {
#region Interface method attributes
[AttributeUsage (AttributeTargets.Method)]
public class VirtualAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class VirtualDestructorAttribute : Attribute {}
public class ConstructorAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class DestructorAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class VirtualAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class StaticAttribute : Attribute {}
@ -42,7 +47,7 @@ namespace Mono.VisualC.Interop { @@ -42,7 +47,7 @@ namespace Mono.VisualC.Interop {
{
this.MangleType = new CppType (mangleTypeStr);
}
public MangleAsAttribute (params object[] cppTypeSpec)
public MangleAsAttribute (params object [] cppTypeSpec)
{
this.MangleType = new CppType (cppTypeSpec);
}
@ -60,30 +65,8 @@ using Mono.VisualC.Interop; @@ -60,30 +65,8 @@ using Mono.VisualC.Interop;
public virtual bool IsVirtual (MethodInfo method)
{
return method.IsDefined (typeof (VirtualAttribute), false) ||
method.IsDefined (typeof (VirtualDestructorAttribute), false);
return method.IsDefined (typeof (VirtualAttribute), false);
}
// Ok, this is tricky.. return true if this class has a [VirtualDestructor]
// or any of its bases do, up the hierarchy.
public virtual bool IsVirtualDtor (MethodInfo method)
{
return HasVirtualDtor () && GetMethodType (method) == MethodType.NativeDtor;
}
public bool HasVirtualDtor ()
{
return HasVirtualDtor (interface_type);
}
public virtual bool HasVirtualDtor (Type interfaceType)
{
var methods = from iface in GetBasesRecursive ().With (interface_type)
from method in GetMethods (iface)
where method.IsDefined (typeof (VirtualDestructorAttribute), false)
select method;
return methods.Any ();
}
public virtual bool IsStatic (MethodInfo method)
{
return method.IsDefined (typeof (StaticAttribute), false);

17
Mono.VisualC.Interop/CppInstancePtr.cs

@ -20,7 +20,7 @@ namespace Mono.VisualC.Interop { @@ -20,7 +20,7 @@ namespace Mono.VisualC.Interop {
private IntPtr ptr;
private bool manage_memory;
private static Dictionary<Type,object> implCache = new Dictionary<Type,object> ();
private static Dictionary<Type,object> implCache = null;
// TODO: the managed instance argument may only be NULL if all methods in TWrapper
// that correspond to the virtual methods in Iface are static.
@ -30,9 +30,12 @@ namespace Mono.VisualC.Interop { @@ -30,9 +30,12 @@ namespace Mono.VisualC.Interop {
object cachedImpl;
Iface impl;
if (implCache == null)
implCache = new Dictionary<Type,object> ();
if (!implCache.TryGetValue (typeof (Iface), out cachedImpl))
{
VirtualOnlyAbi virtualABI = new VirtualOnlyAbi (VTableManaged.Implementation, VTable.BindToSignature);
VirtualOnlyAbi virtualABI = new VirtualOnlyAbi (VTable.BindToSignature);
impl = virtualABI.ImplementClass<Iface> (typeof (TWrapper), string.Empty, string.Empty);
implCache.Add (typeof (Iface), impl);
}
@ -40,7 +43,7 @@ namespace Mono.VisualC.Interop { @@ -40,7 +43,7 @@ namespace Mono.VisualC.Interop {
impl = (Iface)cachedImpl;
CppInstancePtr instance = impl.Alloc (managed);
impl.ClassVTable.InitInstance ((IntPtr)instance);
impl.TypeInfo.VTable.InitInstance ((IntPtr)instance);
return instance;
}
@ -73,8 +76,8 @@ namespace Mono.VisualC.Interop { @@ -73,8 +76,8 @@ namespace Mono.VisualC.Interop {
// Get a CppInstancePtr for an existing C++ instance from an IntPtr
public CppInstancePtr (IntPtr native)
{
//if (native == IntPtr.Zero)
// throw new ArgumentOutOfRangeException ("native cannot be null pointer");
if (native == IntPtr.Zero)
throw new ArgumentOutOfRangeException ("native cannot be null pointer");
ptr = native;
manage_memory = false;
@ -101,6 +104,10 @@ namespace Mono.VisualC.Interop { @@ -101,6 +104,10 @@ namespace Mono.VisualC.Interop {
}
}
CppInstancePtr ICppObject.Native {
get { return this; }
}
public int NativeSize {
get {
throw new NotImplementedException ();

2
Mono.VisualC.Interop/CppObjectMarshaler.cs

@ -16,7 +16,7 @@ namespace Mono.VisualC.Interop { @@ -16,7 +16,7 @@ namespace Mono.VisualC.Interop {
if (cppObject == null)
throw new ArgumentException ("Object to marshal must implement ICppObject");
return cppObject.Native;
return (IntPtr)cppObject.Native;
}
public object MarshalNativeToManaged (IntPtr pNativeData)

184
Mono.VisualC.Interop/CppTypeInfo.cs

@ -0,0 +1,184 @@ @@ -0,0 +1,184 @@
//
// Mono.VisualC.Interop.CppTypeInfo.cs: Type metadata for C++ types
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
//
// Copyright (C) 2010 Alexander Corrado
//
using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Mono.VisualC.Interop.ABI;
using Mono.VisualC.Interop.Util;
namespace Mono.VisualC.Interop {
// NOTE: As AddBase is called, properties change.
// TypeComplete indicates when the dust has settled.
public class CppTypeInfo {
public CppAbi Abi { get; private set; }
public Type NativeLayout {get; private set; }
public IList<MethodInfo> VirtualMethods { get; private set; }
public LazyGeneratedList<Type> VTableDelegateTypes { get; private set; }
public LazyGeneratedList<Delegate> VTableOverrides { get; private set; }
public IList<CppTypeInfo> BaseClasses { get; private set; }
// returns the number of vtable slots reserved for the
// base class(es)
public int BaseVTableSlots { get; protected set; }
public bool TypeComplete { get; private set; }
protected int native_size;
protected int field_offset_padding;
private VTable lazy_vtable;
public CppTypeInfo (CppAbi abi, IEnumerable<MethodInfo> virtualMethods, Type nativeLayout)
{
Abi = abi;
NativeLayout = nativeLayout;
VirtualMethods = new List<MethodInfo> (virtualMethods);
VTableDelegateTypes = new LazyGeneratedList<Type> (VirtualMethods.Count, VTableDelegateTypeGenerator);
VTableOverrides = new LazyGeneratedList<Delegate> (VirtualMethods.Count, VTableOverrideGenerator);
BaseClasses = new List<CppTypeInfo> ();
BaseVTableSlots = 0;
TypeComplete = false;
native_size = Marshal.SizeOf (nativeLayout);
field_offset_padding = 0;
lazy_vtable = null;
}
public virtual void AddBase (CppTypeInfo baseType)
{
if (TypeComplete)
return;
BaseClasses.Add (baseType);
int newVirtualMethodCount = baseType.VirtualMethods.Count;
for (int i = 0; i < newVirtualMethodCount; i++)
VirtualMethods.Insert (BaseVTableSlots + i, baseType.VirtualMethods [i]);
BaseVTableSlots += newVirtualMethodCount;
VTableDelegateTypes.Skew (newVirtualMethodCount);
VTableOverrides.Skew (newVirtualMethodCount);
field_offset_padding += Marshal.SizeOf (baseType.NativeLayout) + baseType.field_offset_padding;
}
public int CountBases (Func<CppTypeInfo, bool> predicate)
{
int count = 0;
foreach (var baseClass in BaseClasses) {
count += baseClass.CountBases (predicate);
count += predicate (baseClass)? 1 : 0;
}
return count;
}
public virtual void CompleteType ()
{
if (TypeComplete) return;
foreach (var baseClass in BaseClasses)
baseClass.CompleteType ();
TypeComplete = true;
// check that any virtual methods overridden in a subclass are only included once
HashSet<MethodSignature> vsignatures = new HashSet<MethodSignature> ();
for (int i = 0; i < VirtualMethods.Count; i++) {
MethodSignature sig = GetVTableMethodSignature (i);
if (vsignatures.Contains (sig))
VirtualMethods.RemoveAt (i--);
else
vsignatures.Add (sig);
}
}
public virtual T GetAdjustedVirtualCall<T> (IntPtr native, int derivedVirtualMethodIndex) where T : class /* Delegate */
{
return VTable.GetVirtualCallDelegate<T> (native, BaseVTableSlots + derivedVirtualMethodIndex);
}
//public virtual long GetFieldOffset (
public virtual VTable VTable {
get {
CompleteType ();
if (!VirtualMethods.Any ())
return null;
if (lazy_vtable == null)
lazy_vtable = VTable.DefaultImplementation (this);
return lazy_vtable;
}
}
public virtual int NativeSize {
get {
CompleteType ();
return native_size + FieldOffsetPadding;
}
}
// the extra padding to allocate at the top of the class before the fields begin
// (by default, just the vtable pointer)
public virtual int FieldOffsetPadding {
get { return field_offset_padding + (VirtualMethods.Any ()? Marshal.SizeOf (typeof (IntPtr)) : 0); }
}
// the padding in the data pointed to by the vtable pointer before the list of function pointers starts
public virtual int VTableTopPadding {
get { return 0; }
}
// the amount of extra room alloc'd after the function pointer list of the vtbl
public virtual int VTableBottomPadding {
get { return 0; }
}
public virtual MethodSignature GetVTableMethodSignature (int index)
{
MethodInfo method = VirtualMethods [index];
return new MethodSignature () { Name = method.Name,
Type = Abi.GetMethodType (method),
Signature = GetVTableDelegateSignature (index) };
}
public virtual DelegateSignature GetVTableDelegateSignature (int index)
{
MethodInfo method = VirtualMethods [index];
return new DelegateSignature () { ParameterTypes = Abi.GetParameterTypesForPInvoke (method),
ReturnType = method.ReturnType,
CallingConvention = Abi.GetCallingConvention (method) };
}
private Type VTableDelegateTypeGenerator (int index)
{
return DelegateTypeCache.GetDelegateType (GetVTableDelegateSignature (index));
}
private Delegate VTableOverrideGenerator (int index)
{
return Abi.GetManagedOverrideTrampoline (this, index);
}
}
}

13
Mono.VisualC.Interop/Interfaces.cs

@ -12,25 +12,17 @@ using Mono.VisualC.Interop.ABI; @@ -12,25 +12,17 @@ using Mono.VisualC.Interop.ABI;
namespace Mono.VisualC.Interop {
public interface ICppObject : IDisposable {
IntPtr Native { get; }
int NativeSize { get; }
}
// A marker interface to signify that the vtable needs to include all
// methods inherited from T as well.
public interface Base<T> where T : ICppClass {
CppInstancePtr Native { get; }
}
public interface ICppClass {
VTable ClassVTable { get; }
int NativeSize { get; }
CppTypeInfo TypeInfo { get; }
}
// This should go without saying, but the C++ class must have a constructor
// if it is to be instantiatable.
public interface ICppClassInstantiatable : ICppClass {
CppInstancePtr Alloc ();
void Destruct (CppInstancePtr instance);
}
// It is recommended that managed wrappers implement ICppObject, but
@ -38,6 +30,5 @@ namespace Mono.VisualC.Interop { @@ -38,6 +30,5 @@ namespace Mono.VisualC.Interop {
// C++ via CppInstancePtr.ForManagedObject.
public interface ICppClassOverridable<T> : ICppClass /* where T : ICppObject */ {
CppInstancePtr Alloc (T managed);
void Destruct (CppInstancePtr instance);
}
}

12
Mono.VisualC.Interop/Mono.VisualC.Interop.csproj

@ -42,21 +42,27 @@ @@ -42,21 +42,27 @@
<Compile Include="Attributes.cs" />
<Compile Include="CppInstancePtr.cs" />
<Compile Include="CppField.cs" />
<Compile Include="ABI\VTableCOM.cs" />
<Compile Include="ABI\VTable.cs" />
<Compile Include="Util.cs" />
<Compile Include="ABI\MethodType.cs" />
<Compile Include="ABI\Impl\ItaniumAbi.cs" />
<Compile Include="ABI\Impl\VirtualOnlyAbi.cs" />
<Compile Include="ABI\Impl\MsvcAbi.cs" />
<Compile Include="CppObjectMarshaler.cs" />
<Compile Include="CppType.cs" />
<Compile Include="IEnumerableTransform.cs" />
<Compile Include="CppTypeInfo.cs" />
<Compile Include="ABI\Impl\ItaniumTypeInfo.cs" />
<Compile Include="Util\IEnumerableTransform.cs" />
<Compile Include="Util\LazyGeneratedList.cs" />
<Compile Include="Util\DelegateTypeCache.cs" />
<Compile Include="Util\ReflectionHelper.cs" />
<Compile Include="ABI\Impl\MsvcTypeInfo.cs" />
<Compile Include="Util\MethodSignature.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<Folder Include="ABI\" />
<Folder Include="ABI\Impl\" />
<Folder Include="Util\" />
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>

74
Mono.VisualC.Interop/Util/DelegateTypeCache.cs

@ -0,0 +1,74 @@ @@ -0,0 +1,74 @@
//
// Mono.VisualC.Interop.Util.DelegateTypeCache.cs: Automatic delegate type creation and caching
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
//
// Copyright (C) 2010 Alexander Corrado
//
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace Mono.VisualC.Interop.Util {
public static class DelegateTypeCache {
private static Dictionary<DelegateSignature, Type> type_cache;
public static Type GetDelegateType (MethodInfo signature, CallingConvention? callingConvention)
{
return GetDelegateType (ReflectionHelper.GetMethodParameterTypes (signature), signature.ReturnType, callingConvention);
}
public static Type GetDelegateType (IEnumerable<Type> parameterTypes, Type returnType, CallingConvention? callingConvention)
{
return GetDelegateType (new DelegateSignature () { ParameterTypes = parameterTypes, ReturnType = returnType, CallingConvention = callingConvention });
}
public static Type GetDelegateType (DelegateSignature signature)
{
Type delegateType;
if (type_cache == null)
type_cache = new Dictionary<DelegateSignature, Type> ();
if (!type_cache.TryGetValue (signature, out delegateType)) {
delegateType = CreateDelegateType (signature);
type_cache.Add (signature, delegateType);
}
return delegateType;
}
private static Type CreateDelegateType (DelegateSignature signature)
{
string delTypeName = signature.UniqueName;
TypeAttributes typeAttr = TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass;
TypeBuilder del = CppLibrary.interopModule.DefineType (delTypeName, typeAttr, typeof(MulticastDelegate));
if (signature.CallingConvention.HasValue) {
ConstructorInfo ufpa = typeof (UnmanagedFunctionPointerAttribute).GetConstructor (new Type [] { typeof (CallingConvention) });
CustomAttributeBuilder unmanagedPointer = new CustomAttributeBuilder (ufpa, new object [] { signature.CallingConvention.Value });
del.SetCustomAttribute (unmanagedPointer);
}
MethodAttributes ctorAttr = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public;
ConstructorBuilder ctor = del.DefineConstructor (ctorAttr, CallingConventions.Standard, new Type[] { typeof(object), typeof(System.IntPtr) });
ctor.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
Type [] parameterTypes = signature.ParameterTypes.ToArray ();
MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual;
MethodBuilder invokeMethod = del.DefineMethod ("Invoke", methodAttr, signature.ReturnType, parameterTypes);
invokeMethod.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
return del.CreateType ();
}
}
}

212
Mono.VisualC.Interop/IEnumerableTransform.cs → Mono.VisualC.Interop/Util/IEnumerableTransform.cs

@ -1,9 +1,129 @@ @@ -1,9 +1,129 @@
//
// Mono.VisualC.Interop.Util.IEnumerableTransform.cs: Rule-based transformation for IEnumerable
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
//
// Copyright (C) 2010 Alexander Corrado
//
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
namespace Mono.VisualC.Interop {
namespace Mono.VisualC.Interop.Util {
public static class IEnumerableTransform {
// Transforms an IEnumerable into another by specific rules.
public static IEnumerable<TOut> Transform<TIn, TOut> (this IEnumerable<TIn> input, params EmitterFunc<TIn, TOut> [] rules)
{
CloneableEnumerator<TIn> enumerator = new CloneableEnumerator<TIn> (input, 0);
while (enumerator.MoveNext ()) {
InputData<TIn> inputData = new InputData<TIn> (input, enumerator);
foreach (var rule in rules) {
TOut output;
if (rule (inputData.NewContext (), out output) == RuleResult.MatchEmit)
yield return output;
}
}
}
public static IRule<TIn> And<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules)
{
return new AndRule<TIn> (previousRules, parentheticalRules);
}
public static RuleCompound<TIn> And<TIn> (this IRule<TIn> previousRules)
{
return new RuleCompound<TIn> ((subsequentRules) => {
return And<TIn> (previousRules, subsequentRules);
});
}
public static IRule<TIn> Or<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules)
{
return new OrRule<TIn> (previousRules, parentheticalRules);
}
public static RuleCompound<TIn> Or<TIn> (this IRule<TIn> previousRules)
{
return new RuleCompound<TIn> ((subsequentRules) => {
return Or<TIn> (previousRules, subsequentRules);
});
}
public static IRule<TIn> After<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules)
{
return new AndRule<TIn> (new AfterRule<TIn> (parentheticalRules), previousRules);
}
public static RuleCompound<TIn> After<TIn> (this IRule<TIn> previousRules)
{
return new RuleCompound<TIn> ((subsequentRules) => {
return After<TIn> (previousRules, subsequentRules);
});
}
public static IRule<TIn> AtEnd<TIn> (this IRule<TIn> previousRules)
{
return new AtEndRule<TIn> (previousRules);
}
public static EmitterFunc<TIn, TOut> Emit<TIn, TOut> (this IRule<TIn> rule, Func<TIn, TOut> result)
{
return delegate (InputData<TIn> input, out TOut output) {
output = default (TOut);
TIn value = input.Value;
RuleResult ruleResult = rule.SatisfiedBy (input);
if (ruleResult != RuleResult.NoMatch) {
input.MatchedRules.Add (rule);
output = result (value);
return ruleResult;
}
return RuleResult.NoMatch;
};
}
public static EmitterFunc<TIn, TOut> Emit<TIn, TOut> (this IRule<TIn> rule, TOut result)
{
return Emit (rule, (input) => result);
}
// helpers:
public static IEnumerable<T> With<T> (this IEnumerable<T> current, T additionalValue)
{
foreach (var output in current)
yield return output;
yield return additionalValue;
}
public static int SequenceHashCode<T> (this IEnumerable<T> sequence)
{
int hash = 0;
foreach (var item in sequence)
hash ^= item.GetHashCode ();
return hash;
}
// FIXME: Faster way to do this?
public static void AddFirst<T> (this List<T> list, IEnumerable<T> items)
{
T [] temp = new T [list.Count];
list.CopyTo (temp, 0);
list.Clear ();
list.AddRange (items);
list.AddRange (temp);
}
}
public enum RuleResult {
NoMatch,
@ -464,95 +584,5 @@ namespace Mono.VisualC.Interop { @@ -464,95 +584,5 @@ namespace Mono.VisualC.Interop {
{
}
}
public static class EnumerableSequenceExtensions {
// helper
public static IEnumerable<T> With<T> (this IEnumerable<T> current, T additionalValue)
{
foreach (var output in current)
yield return output;
yield return additionalValue;
}
// Transforms an IEnumerable into another by specific rules.
public static IEnumerable<TOut> Transform<TIn, TOut> (this IEnumerable<TIn> input, params EmitterFunc<TIn, TOut> [] rules)
{
CloneableEnumerator<TIn> enumerator = new CloneableEnumerator<TIn> (input, 0);
while (enumerator.MoveNext ()) {
InputData<TIn> inputData = new InputData<TIn> (input, enumerator);
foreach (var rule in rules) {
TOut output;
if (rule (inputData.NewContext (), out output) == RuleResult.MatchEmit)
yield return output;
}
}
}
public static IRule<TIn> And<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules)
{
return new AndRule<TIn> (previousRules, parentheticalRules);
}
public static RuleCompound<TIn> And<TIn> (this IRule<TIn> previousRules)
{
return new RuleCompound<TIn> ((subsequentRules) => {
return And<TIn> (previousRules, subsequentRules);
});
}
public static IRule<TIn> Or<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules)
{
return new OrRule<TIn> (previousRules, parentheticalRules);
}
public static RuleCompound<TIn> Or<TIn> (this IRule<TIn> previousRules)
{
return new RuleCompound<TIn> ((subsequentRules) => {
return Or<TIn> (previousRules, subsequentRules);
});
}
public static IRule<TIn> After<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules)
{
return new AndRule<TIn> (new AfterRule<TIn> (parentheticalRules), previousRules);
}
public static RuleCompound<TIn> After<TIn> (this IRule<TIn> previousRules)
{
return new RuleCompound<TIn> ((subsequentRules) => {
return After<TIn> (previousRules, subsequentRules);
});
}
public static IRule<TIn> AtEnd<TIn> (this IRule<TIn> previousRules)
{
return new AtEndRule<TIn> (previousRules);
}
public static EmitterFunc<TIn, TOut> Emit<TIn, TOut> (this IRule<TIn> rule, Func<TIn, TOut> result)
{
return delegate (InputData<TIn> input, out TOut output) {
output = default (TOut);
TIn value = input.Value;
RuleResult ruleResult = rule.SatisfiedBy (input);
if (ruleResult != RuleResult.NoMatch) {
input.MatchedRules.Add (rule);
output = result (value);
return ruleResult;
}
return RuleResult.NoMatch;
};
}
public static EmitterFunc<TIn, TOut> Emit<TIn, TOut> (this IRule<TIn> rule, TOut result)
{
return Emit (rule, (input) => result);
}
}
}

105
Mono.VisualC.Interop/Util/LazyGeneratedList.cs

@ -0,0 +1,105 @@ @@ -0,0 +1,105 @@
//
// Mono.VisualC.Interop.Util.LazyGeneratedList.cs: A list whose items are generated and cached on first access
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
//
// Copyright (C) 2010 Alexander Corrado
//
using System;
using System.Collections;
using System.Collections.Generic;
namespace Mono.VisualC.Interop.Util {
public class LazyGeneratedList<TItem> : IList<TItem> where TItem : class {
private TItem [] cache;
private Func<int, TItem> generator;
private int skew;
public LazyGeneratedList (int count, Func<int, TItem> generator)
{
this.cache = new TItem [count];
this.generator = generator;
this.skew = 0;
}
public IEnumerator<TItem> GetEnumerator ()
{
for (int i = 0; i < Count; i++)
yield return this [i];
}
IEnumerator IEnumerable.GetEnumerator ()
{
return this.GetEnumerator ();
}
public int Count {
get { return cache.Length + skew; }
}
public bool IsReadOnly {
get { return true; }
}
public TItem this [int index] {
get {
int realIndex = index - skew;
if (realIndex < 0) return null;
if (cache [realIndex] == null)
cache [realIndex] = generator (realIndex);
return cache [realIndex];
}
set {
throw new NotSupportedException ("This IList is read only");
}
}
public void Skew (int skew)
{
this.skew += skew;
}
// FIXME: Should probably implement these 3 at some point
public bool Contains (TItem item)
{
throw new NotImplementedException ();
}
public void CopyTo (TItem[] array, int arrayIndex)
{
throw new NotImplementedException ();
}
public int IndexOf (TItem item)
{
throw new NotImplementedException ();
}
public void Insert (int index, TItem item)
{
throw new NotImplementedException ();
}
public void RemoveAt (int index)
{
throw new NotImplementedException ();
}
public void Add (TItem item)
{
throw new NotImplementedException ();
}
public void Clear ()
{
throw new NotImplementedException ();
}
public bool Remove (TItem item)
{
throw new NotImplementedException ();
}
}
}

102
Mono.VisualC.Interop/Util/MethodSignature.cs

@ -0,0 +1,102 @@ @@ -0,0 +1,102 @@
//
// Mono.VisualC.Interop.Util.MethodSignature.cs: Hash-friendly structs to represent arbitrary method and delegate signatures
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
//
// Copyright (C) 2010 Alexander Corrado
//
using System;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace Mono.VisualC.Interop.Util {
public struct DelegateSignature {
public CallingConvention? CallingConvention { get; set; }
public IEnumerable<Type> ParameterTypes { get; set; }
public Type ReturnType { get; set; }
private string uniqueName;
public string UniqueName {
get {
if (uniqueName != null)
return uniqueName;
StringBuilder sb = new StringBuilder ("_");
if (CallingConvention.HasValue)
sb.Append (Enum.GetName (typeof (CallingConvention), CallingConvention.Value));
sb.Append ('_').Append (ReturnType.Name);
if (ParameterTypes == null)
return uniqueName = sb.ToString ();
foreach (var param in ParameterTypes)
sb.Append ('_').Append (param.Name);
return uniqueName = sb.ToString ();
}
}
public override bool Equals (object obj)
{
if (obj == null)
return false;
if (obj.GetType () != typeof(DelegateSignature))
return false;
DelegateSignature other = (DelegateSignature)obj;
return CallingConvention == other.CallingConvention &&
((ParameterTypes == null && other.ParameterTypes == null) ||
ParameterTypes.SequenceEqual (other.ParameterTypes)) &&
ReturnType.Equals (other.ReturnType);
}
public override int GetHashCode ()
{
unchecked {
return CallingConvention.GetHashCode () ^
(ParameterTypes != null? ParameterTypes.SequenceHashCode () : 0) ^
ReturnType.GetHashCode ();
}
}
}
public struct MethodSignature {
public string Name { get; set; }
public MethodType Type { get; set; }
public DelegateSignature Signature { get; set; }
public override bool Equals (object obj)
{
if (obj == null)
return false;
if (obj.GetType () != typeof(MethodSignature))
return false;
MethodSignature other = (MethodSignature)obj;
return Signature.Equals (other.Signature) &&
Type == other.Type &&
(Type != MethodType.Native || Name.Equals (other.Name));
}
public override int GetHashCode ()
{
unchecked {
return Signature.GetHashCode () ^
Type.GetHashCode () ^
(Type == MethodType.Native? Name.GetHashCode () : 0);
}
}
}
}

13
Mono.VisualC.Interop/Util.cs → Mono.VisualC.Interop/Util/ReflectionHelper.cs

@ -1,3 +1,12 @@ @@ -1,3 +1,12 @@
//
// Mono.VisualC.Interop.Util.ReflectionHelper.cs: Helper methods for common reflection API tasks
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
//
// Copyright (C) 2010 Alexander Corrado
//
using System;
using System.Linq;
using System.Collections.Generic;
@ -5,8 +14,8 @@ using System.Runtime.InteropServices; @@ -5,8 +14,8 @@ using System.Runtime.InteropServices;
using System.Reflection;
using System.Reflection.Emit;
namespace Mono.VisualC.Interop {
internal static class Util {
namespace Mono.VisualC.Interop.Util {
internal static class ReflectionHelper {
public static MethodInfo GetMethodInfoForDelegate (Type delType)
{

33
QtBindings/Core/QCoreApplication.cs

@ -6,15 +6,17 @@ namespace Qt.Core { @@ -6,15 +6,17 @@ namespace Qt.Core {
public class QCoreApplication : QObject {
#region Sync with qcoreapplication.h
// C++ interface
public interface IQCoreApplication : ICppClassOverridable<QCoreApplication>, Base<QObject.IQObject> {
public interface IQCoreApplication : ICppClassOverridable<QCoreApplication> {
// ...
void QCoreApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc,
[MangleAs ("char**")] IntPtr argv);
[Constructor] void QCoreApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc,
[MangleAs ("char**")] IntPtr argv);
// ...
[Static] int exec ();
// ...
[Virtual] bool notify (CppInstancePtr @this, IntPtr qObject, IntPtr qEvent);
[Virtual] bool compressEvent (CppInstancePtr @this, IntPtr qEvent, IntPtr qObject, IntPtr qPostEventList);
[Virtual, Destructor] void Destruct (CppInstancePtr @this);
}
// C++ fields
private struct _QCoreApplication {
@ -26,34 +28,33 @@ namespace Qt.Core { @@ -26,34 +28,33 @@ namespace Qt.Core {
protected IntPtr argv;
public QCoreApplication () : base (IntPtr.Zero)
public QCoreApplication () : base (impl.TypeInfo)
{
this.native = impl.Alloc (this);
Native = impl.Alloc (this);
InitArgcAndArgv ();
impl.QCoreApplication (native, argc, argv);
impl.QCoreApplication (Native, argc, argv);
}
public QCoreApplication (IntPtr native) : base (native)
public QCoreApplication (IntPtr native) : base (impl.TypeInfo)
{
Native = native;
}
// TODO: Should this be virtual in C#? was static in C++, but alas,
// I made it an instance, since that seems to fit .net semantics a bit better...
// but if I don't make it virtual, then what to do about Exec () in QApplication?
internal QCoreApplication (CppTypeInfo subClass) : base (impl.TypeInfo)
{
subClass.AddBase (impl.TypeInfo);
}
public virtual int Exec ()
{
return impl.exec ();
}
public override int NativeSize {
get { return impl.NativeSize + base.NativeSize; }
}
public override void Dispose ()
{
impl.Destruct (native);
impl.Destruct (Native);
FreeArgcAndArgv ();
native.Dispose ();
Native.Dispose ();
}
protected void InitArgcAndArgv ()

29
QtBindings/Core/QObject.cs

@ -12,8 +12,8 @@ namespace Qt.Core { @@ -12,8 +12,8 @@ namespace Qt.Core {
[Virtual] /*void */ IntPtr qt_metacast(CppInstancePtr @this, string s);
[Virtual] int qt_metacall(CppInstancePtr @this, /*QMetaObject::Call */ int qMetaObjectCall, int x, /*void **/ IntPtr p);
// ...
void QObject (CppInstancePtr @this, QObject parent);
[VirtualDestructor] void vdtor (CppInstancePtr @this);
[Constructor] void QObject (CppInstancePtr @this, QObject parent);
[Virtual, Destructor] void Destruct (CppInstancePtr @this);
// ...
[Virtual] bool @event (CppInstancePtr @this, IntPtr qEvent);
[Virtual] bool eventFilter (CppInstancePtr @this, IntPtr qObject, IntPtr qEvent);
@ -30,35 +30,32 @@ namespace Qt.Core { @@ -30,35 +30,32 @@ namespace Qt.Core {
#endregion
private static IQObject impl = Qt.Libs.QtCore.GetClass<IQObject,_QObject,QObject> ("QObject");
protected CppInstancePtr native;
public CppInstancePtr Native { get; protected set; }
public QObject (QObject parent)
{
native = impl.Alloc (this);
impl.QObject (native, parent);
Native = impl.Alloc (this);
impl.QObject (Native, parent);
}
public QObject () : this (null)
public QObject () : this ((QObject)null)
{
}
public QObject (IntPtr native)
{
this.native = native;
Native = native;
}
public IntPtr Native {
get { return (IntPtr)native; }
}
public virtual int NativeSize {
get { return impl.NativeSize; }
}
internal QObject (CppTypeInfo subClass)
{
subClass.AddBase (impl.TypeInfo);
}
public virtual void Dispose ()
{
impl.Destruct (native);
native.Dispose ();
impl.Destruct (Native);
Native.Dispose ();
}
}

2
QtBindings/Core/QString.cs

@ -11,7 +11,7 @@ namespace Qt.Core { @@ -11,7 +11,7 @@ namespace Qt.Core {
public unsafe struct QString {
#region Sync with qstring.h
public interface IQString : ICppClass {
void QString(ref QString @this, [MangleAs ("const QChar*")] IntPtr unicode, int size);
[Constructor] void QString(ref QString @this, [MangleAs ("const QChar*")] IntPtr unicode, int size);
}
[StructLayout (LayoutKind.Sequential)]

22
QtBindings/Gui/QAbstractButton.cs

@ -5,10 +5,7 @@ namespace Qt.Gui { @@ -5,10 +5,7 @@ namespace Qt.Gui {
public class QAbstractButton : QWidget {
#region Sync with qabstractbutton.h
// C++ interface
public interface IQAbstractButton : ICppClassOverridable<QAbstractButton>, Base<QWidget.IQWidget> {
// ...
void QAbstractButton (CppInstancePtr @this, QWidget parent);
// ...
public interface IQAbstractButton : ICppClassOverridable<QAbstractButton> {
[Virtual] void paintEvent (CppInstancePtr @this, /*QPaintEvent */ IntPtr e); // abstract
[Virtual] bool hitButton (CppInstancePtr @this, /*const QPoint &*/ IntPtr pos);
[Virtual] void checkStateSet (CppInstancePtr @this);
@ -18,19 +15,20 @@ namespace Qt.Gui { @@ -18,19 +15,20 @@ namespace Qt.Gui {
}
#endregion
private static IQAbstractButton impl = Qt.Libs.QtGui.GetClass<IQAbstractButton, _QAbstractButton, QAbstractButton> ("QAbstractButton");
public QAbstractButton (IntPtr native) : base (native)
public QAbstractButton (IntPtr native) : base (impl.TypeInfo)
{
Native = native;
}
/*
public override int NativeSize {
get { return impl.NativeSize + base.NativeSize; }
}
*/
internal QAbstractButton (CppTypeInfo subClass) : base (impl.TypeInfo)
{
subClass.AddBase (impl.TypeInfo);
}
public override void Dispose ()
{
throw new Exception ("This should never be called!");
}
}
}

30
QtBindings/Gui/QApplication.cs

@ -8,10 +8,10 @@ namespace Qt.Gui { @@ -8,10 +8,10 @@ namespace Qt.Gui {
public class QApplication : QCoreApplication {
#region Sync with qapplication.h
// C++ interface
public interface IQApplication : ICppClassOverridable<QApplication>, Base<QCoreApplication.IQCoreApplication> {
public interface IQApplication : ICppClassOverridable<QApplication> {
// ...
void QApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc,
[MangleAs ("char**")] IntPtr argv, int version);
[Constructor] void QApplication (CppInstancePtr @this, [MangleAs ("int&")] IntPtr argc,
[MangleAs ("char**")] IntPtr argv, int version);
// ...
[Virtual] bool macEventFilter(CppInstancePtr @this, IntPtr eventHandlerCallRef, IntPtr eventRef);
// ...
@ -19,6 +19,8 @@ namespace Qt.Gui { @@ -19,6 +19,8 @@ namespace Qt.Gui {
[Virtual] void saveState(CppInstancePtr @this, IntPtr qSessionManager); // was QSessionManager&
// ...
[Static] int exec ();
[Virtual, Destructor] void Destruct (CppInstancePtr @this);
}
// C++ fields
private struct _QApplication {
@ -27,31 +29,33 @@ namespace Qt.Gui { @@ -27,31 +29,33 @@ namespace Qt.Gui {
private static IQApplication impl = Qt.Libs.QtGui.GetClass<IQApplication,_QApplication,QApplication> ("QApplication");
public QApplication () : base (IntPtr.Zero)
public QApplication () : base (impl.TypeInfo)
{
this.native = impl.Alloc (this);
Native = impl.Alloc (this);
InitArgcAndArgv ();
impl.QApplication (native, argc, argv, QGlobal.QT_VERSION);
impl.QApplication (Native, argc, argv, QGlobal.QT_VERSION);
}
public QApplication (IntPtr native) : base (native)
public QApplication (IntPtr native) : base (impl.TypeInfo)
{
Native = native;
}
internal QApplication (CppTypeInfo subClass) : base (impl.TypeInfo)
{
subClass.AddBase (impl.TypeInfo);
}
public override int Exec ()
{
return impl.exec ();
}
public override int NativeSize {
get { return impl.NativeSize + base.NativeSize; }
}
public override void Dispose ()
{
impl.Destruct (native);
impl.Destruct (Native);
FreeArgcAndArgv ();
native.Dispose ();
Native.Dispose ();
}
}

23
QtBindings/Gui/QPaintDevice.cs

@ -20,31 +20,20 @@ namespace Qt.Gui { @@ -20,31 +20,20 @@ namespace Qt.Gui {
#endregion
private static IQPaintDevice impl = Qt.Libs.QtGui.GetClass<IQPaintDevice,_QPaintDevice,QPaintDevice> ("QPaintDevice");
protected CppInstancePtr native;
/* no point to this - subclasses will call QPaintDevice (IntPtr.Zero)
protected QPaintDevice ()
{
}
*/
public CppInstancePtr Native { get; protected set; }
public QPaintDevice (IntPtr native)
{
this.native = native;
Native = native;
}
public IntPtr Native {
get { return (IntPtr)native; }
}
public virtual int NativeSize {
get { return impl.NativeSize; }
}
internal QPaintDevice (CppTypeInfo subClass)
{
subClass.AddBase (impl.TypeInfo);
}
public void Dispose ()
{
throw new Exception ("This should never be called!");
}
}
}

27
QtBindings/Gui/QPushButton.cs

@ -6,42 +6,45 @@ namespace Qt.Gui { @@ -6,42 +6,45 @@ namespace Qt.Gui {
public class QPushButton : QAbstractButton {
#region Sync with qpushbutton.h
// C++ interface
public interface IQPushButton : ICppClassOverridable<QPushButton>, Base<QAbstractButton.IQAbstractButton> {
public interface IQPushButton : ICppClassOverridable<QPushButton> {
// ...
void QPushButton (CppInstancePtr @this, [MangleAs ("const QString &")] ref QString text, QWidget parent);
[Constructor] void QPushButton (CppInstancePtr @this, [MangleAs ("const QString &")] ref QString text, QWidget parent);
// ...
[Virtual, Destructor] void Destruct (CppInstancePtr @this);
}
// C++ fields
private struct _QPushButton {
}
#endregion
private IQPushButton impl = Qt.Libs.QtGui.GetClass<IQPushButton,_QPushButton,QPushButton> ("QPushButton");
private static IQPushButton impl = Qt.Libs.QtGui.GetClass<IQPushButton,_QPushButton,QPushButton> ("QPushButton");
public QPushButton (string btnText, QWidget parent) : base (IntPtr.Zero)
public QPushButton (string btnText, QWidget parent) : base (impl.TypeInfo)
{
this.native = impl.Alloc (this);
Native = impl.Alloc (this);
QString text = btnText;
impl.QPushButton (native, ref text, parent);
impl.QPushButton (Native, ref text, parent);
}
public QPushButton (string text) : this (text, (QWidget)null)
{
}
public QPushButton (IntPtr native) : base (native)
public QPushButton (IntPtr native) : base (impl.TypeInfo)
{
Native = native;
}
public override int NativeSize {
get { return impl.NativeSize + base.NativeSize; }
}
internal QPushButton (CppTypeInfo subClass) : base (impl.TypeInfo)
{
subClass.AddBase (impl.TypeInfo);
}
public override void Dispose ()
{
impl.Destruct (native);
native.Dispose ();
impl.Destruct (Native);
Native.Dispose ();
}
}
}

32
QtBindings/Gui/QWidget.cs

@ -9,11 +9,11 @@ namespace Qt.Gui { @@ -9,11 +9,11 @@ namespace Qt.Gui {
public class QWidget : QObject {
#region Sync with qwidget.h
// C++ interface
public interface IQWidget : ICppClassOverridable<QWidget>, Base<QObject.IQObject>, Base<QPaintDevice.IQPaintDevice> {
public interface IQWidget : ICppClassOverridable<QWidget> {
// ...
void QWidget (CppInstancePtr @this, QWidget parent, /*Qt::WindowFlags */ int f);
[Constructor] void QWidget (CppInstancePtr @this, QWidget parent, /*Qt::WindowFlags */ int f);
// ...
[Virtual] void setVisible (CppInstancePtr @this, /*[MarshalAs (UnmanagedType.U1)]*/ bool visible);
[Virtual] void setVisible (CppInstancePtr @this, bool visible);
// ...
void resize (CppInstancePtr @this, [MangleAs ("const QSize &")] ref QSize size);
// ...
@ -73,31 +73,37 @@ namespace Qt.Gui { @@ -73,31 +73,37 @@ namespace Qt.Gui {
// TODO: ctor ...
public QWidget (IntPtr native) : base (native)
public QWidget (IntPtr native) : this ()
{
Native = native;
}
internal QWidget (CppTypeInfo subClass) : this ()
{
subClass.AddBase (impl.TypeInfo);
}
private QWidget ()
: base (impl.TypeInfo) // Add QObject as base class
{
// FIXME: Hold on to this object and create methods for it on this class?
new QPaintDevice (impl.TypeInfo); // Add QPaintDevice as base class
}
public bool Visible {
get {
throw new NotImplementedException ();
}
set {
//Debug.Assert (false, "Attach debugger now.");
impl.setVisible (native, value);
impl.setVisible (Native, value);
}
}
public void Resize (int width, int height)
{
QSize s = new QSize (width, height);
impl.resize (native, ref s);
}
// TODO: HELP! I think this really should be:
// sizeof(QWidget) [impl.NativeSize] + sizeof(QObject) [base.NativeSize] + sizeof(QPaintDevice) [????]
// Works for now because we're already alloc'ing too much memory!!? (NativeSize property contains vtbl pointer)
public override int NativeSize {
get { return impl.NativeSize + base.NativeSize + 4; }
impl.resize (Native, ref s);
}
public override void Dispose ()

8
QtTest/Main.cs

@ -9,11 +9,15 @@ namespace QtTest { @@ -9,11 +9,15 @@ namespace QtTest {
{
//System.Diagnostics.Debug.Assert(false, "Whao");
using (QApplication app = new QApplication ()) {
using (QPushButton hello = new QPushButton ("Hello world!")) {
using (QPushButton hello = new QPushButton ("Hello world!"),
hello2 = new QPushButton ("Another button")) {
hello.Resize (100, 30);
CppLibrary.SaveInteropAssembly ();
hello2.Resize (200, 30);
//CppLibrary.SaveInteropAssembly ();
hello.Visible = true;
hello2.Visible = true;
app.Exec ();

Loading…
Cancel
Save