Browse Source

Manually merge d28bc89..faa6350

pull/1/head
Alex Corrado 15 years ago
parent
commit
94cf0c5afd
  1. 603
      src/Mono.VisualC.Interop/ABI/CppAbi.cs
  2. 97
      src/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs
  3. 79
      src/Mono.VisualC.Interop/ABI/Impl/ItaniumTypeInfo.cs
  4. 5
      src/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs
  5. 4
      src/Mono.VisualC.Interop/ABI/Impl/MsvcTypeInfo.cs
  6. 1
      src/Mono.VisualC.Interop/ABI/MethodType.cs
  7. 14
      src/Mono.VisualC.Interop/Attributes.cs
  8. 10
      src/Mono.VisualC.Interop/CppInstancePtr.cs
  9. 38
      src/Mono.VisualC.Interop/CppLibrary.cs
  10. 60
      src/Mono.VisualC.Interop/CppTypeInfo.cs
  11. 8
      src/Mono.VisualC.Interop/Interfaces.cs
  12. 1
      src/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj
  13. 10
      src/Mono.VisualC.Interop/Util/DelegateTypeCache.cs
  14. 36
      src/Mono.VisualC.Interop/Util/MethodSignature.cs

603
src/Mono.VisualC.Interop/ABI/CppAbi.cs

@ -20,32 +20,6 @@ using Mono.VisualC.Interop.Util; @@ -20,32 +20,6 @@ using Mono.VisualC.Interop.Util;
namespace Mono.VisualC.Interop.ABI {
//
// Marshalling to be done for a single parameter
//
public enum ParameterMarshal {
Default = 0,
ClassByRef = 1,
ClassByVal = 2
}
//
// Describes the signature of the pinvoke wrapper of a c++ method, along with
// marshalling information
//
public class PInvokeSignature {
// The original c# method this signature was generated from
public MethodInfo OrigMethod;
public List<Type> ParameterTypes { get; set; }
public List<ParameterMarshal> ParameterMarshallers { get; set; }
public Type ReturnType { get; set; }
// Whenever to return a class value
public bool ReturnClass { get; set; }
// Whenever to return a class value by passing a hidden first argument
// Used by the itanium c++ abi
public bool ReturnByAddr { get; set; }
}
//FIXME: Exception handling, operator overloading etc.
//FIXME: Allow interface to override default calling convention
public abstract partial class CppAbi {
@ -53,7 +27,8 @@ namespace Mono.VisualC.Interop.ABI { @@ -53,7 +27,8 @@ namespace Mono.VisualC.Interop.ABI {
protected TypeBuilder impl_type;
protected Type interface_type, layout_type, wrapper_type;
protected string library, class_name;
protected CppLibrary library;
protected string class_name;
protected FieldBuilder typeinfo_field;
protected ILGenerator ctor_il;
@ -64,14 +39,30 @@ namespace Mono.VisualC.Interop.ABI { @@ -64,14 +39,30 @@ namespace Mono.VisualC.Interop.ABI {
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 typeinfo_fieldoffset = typeof (CppTypeInfo).GetProperty ("FieldOffsetPadding").GetGetMethod ();
private static readonly MethodInfo vtable_initinstance = typeof (VTable).GetMethod ("InitInstance");
private static readonly MethodInfo vtable_resetinstance = typeof (VTable).GetMethod ("ResetInstance");
private static readonly MethodInfo cppobj_native = typeof (ICppObject).GetProperty ("Native").GetGetMethod ();
private static readonly MethodInfo cppip_native = typeof (CppInstancePtr).GetProperty ("Native").GetGetMethod ();
private static readonly MethodInfo cppip_managedalloc = typeof (CppInstancePtr).GetProperty ("IsManagedAlloc").GetGetMethod ();
private static readonly MethodInfo cppip_getmanaged = typeof (CppInstancePtr).GetMethod ("GetManaged", BindingFlags.Static | BindingFlags.NonPublic);
private static readonly ConstructorInfo cppip_fromnative = typeof (CppInstancePtr).GetConstructor (new Type [] { typeof (IntPtr) });
private static readonly ConstructorInfo cppip_fromsize = typeof (CppInstancePtr).GetConstructor (new Type [] { typeof (int) });
private static readonly ConstructorInfo cppip_fromsize_managed = typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null,
new Type[] { typeof (int), typeof (object) }, null);
private static readonly ConstructorInfo notimplementedexception = typeof (NotImplementedException).GetConstructor (new Type [] { typeof (string) });
private static readonly MethodInfo type_gettypefromhandle = typeof (Type).GetMethod ("GetTypeFromHandle");
private static readonly MethodInfo marshal_offsetof = typeof (Marshal).GetMethod ("OffsetOf");
private static readonly MethodInfo marshal_structuretoptr = typeof (Marshal).GetMethod ("StructureToPtr");
// These methods might be more commonly overridden for a given C++ ABI:
public virtual MethodType GetMethodType (MethodInfo imethod)
{
if (imethod.IsDefined (typeof (ConstructorAttribute), false))
if (IsInline (imethod) && library.InlineMethodPolicy == InlineMethods.NotPresent)
return MethodType.NotImplemented;
else if (imethod.IsDefined (typeof (ConstructorAttribute), false))
return MethodType.NativeCtor;
else if (imethod.Name.Equals ("Alloc"))
return MethodType.ManagedAlloc;
@ -94,12 +85,12 @@ namespace Mono.VisualC.Interop.ABI { @@ -94,12 +85,12 @@ namespace Mono.VisualC.Interop.ABI {
// The ImplementClass overrides are the main entry point to the Abi API:
private struct EmptyNativeLayout { }
public Iface ImplementClass<Iface> (Type wrapperType, string lib, string className)
public Iface ImplementClass<Iface> (Type wrapperType, CppLibrary lib, string className)
{
return this.ImplementClass<Iface,EmptyNativeLayout> (wrapperType, lib, className);
}
public virtual Iface ImplementClass<Iface, NLayout> (Type wrapperType, string lib, string className)
public virtual Iface ImplementClass<Iface, NLayout> (Type wrapperType, CppLibrary lib, string className)
where NLayout : struct
//where Iface : ICppClassInstantiatable or ICppClassOverridable
{
@ -113,8 +104,8 @@ namespace Mono.VisualC.Interop.ABI { @@ -113,8 +104,8 @@ namespace Mono.VisualC.Interop.ABI {
DefineImplType ();
var properties = GetProperties ();
var methods = GetMethods ();
CppTypeInfo typeInfo = MakeTypeInfo (methods, methods.Where (m => IsVirtual (m)));
var methods = GetMethods ().Select (m => GetPInvokeSignature (m));
var typeInfo = MakeTypeInfo (methods);
// Implement all methods
int vtableIndex = 0;
@ -130,9 +121,9 @@ namespace Mono.VisualC.Interop.ABI { @@ -130,9 +121,9 @@ namespace Mono.VisualC.Interop.ABI {
return (Iface)Activator.CreateInstance (impl_type.CreateType (), typeInfo);
}
protected virtual CppTypeInfo MakeTypeInfo (IEnumerable<MethodInfo> methods, IEnumerable<MethodInfo> virtualMethods)
protected virtual CppTypeInfo MakeTypeInfo (IEnumerable<PInvokeSignature> methods)
{
return new CppTypeInfo (this, virtualMethods, layout_type);
return new CppTypeInfo (this, methods.Where (m => IsVirtual (m.OrigMethod)), layout_type);
}
protected virtual IEnumerable<PropertyInfo> GetProperties ()
@ -171,8 +162,6 @@ namespace Mono.VisualC.Interop.ABI { @@ -171,8 +162,6 @@ namespace Mono.VisualC.Interop.ABI {
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);
typeinfo_field = impl_type.DefineField ("_typeInfo", typeof (CppTypeInfo), FieldAttributes.InitOnly | FieldAttributes.Private);
ConstructorBuilder ctor = impl_type.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard,
@ -184,38 +173,32 @@ namespace Mono.VisualC.Interop.ABI { @@ -184,38 +173,32 @@ namespace Mono.VisualC.Interop.ABI {
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);
ctor_il.Emit (OpCodes.Stfld, vtable_field);
// this._nativeSize = (native size passed to constructor)
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, CppTypeInfo typeInfo, ref int vtableIndex)
protected virtual MethodBuilder DefineMethod (PInvokeSignature psig, CppTypeInfo typeInfo, ref int vtableIndex)
{
// 0. Introspect method
MethodType methodType = GetMethodType (interfaceMethod);
Type [] parameterTypes = ReflectionHelper.GetMethodParameterTypes (interfaceMethod);
var interfaceMethod = psig.OrigMethod;
// 1. Generate managed trampoline to call native method
MethodBuilder trampoline = GetMethodBuilder (interfaceMethod);
ILGenerator il = trampoline.GetILGenerator ();
if (methodType == MethodType.NoOp) {
switch (psig.Type) {
case MethodType.NotImplemented:
il.Emit (OpCodes.Ldstr, "This method is not available.");
il.Emit (OpCodes.Newobj, notimplementedexception);
il.Emit (OpCodes.Throw);
goto case MethodType.NoOp; // fallthrough
case MethodType.NoOp:
// return NULL if method is supposed to return a value
// FIXME: this will make value types explode?
if (!interfaceMethod.ReturnType.Equals (typeof (void)))
il.Emit (OpCodes.Ldnull);
il.Emit (OpCodes.Ret);
return trampoline;
} else if (methodType == MethodType.ManagedAlloc) {
case MethodType.ManagedAlloc:
EmitManagedAlloc (il, interfaceMethod);
il.Emit (OpCodes.Ret);
return trampoline;
@ -224,93 +207,43 @@ namespace Mono.VisualC.Interop.ABI { @@ -224,93 +207,43 @@ namespace Mono.VisualC.Interop.ABI {
bool isStatic = IsStatic (interfaceMethod);
LocalBuilder cppInstancePtr = null;
LocalBuilder nativePtr = null;
LocalBuilder retVal = null;
LocalBuilder retArg = null;
// If we're an instance method, load up the "this" pointer
if (!isStatic)
{
if (parameterTypes.Length < 1)
if (psig.ParameterTypes.Count == 0)
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, interfaceMethod.GetParameters () [0].ParameterType, out cppInstancePtr, out nativePtr);
// 3. Make sure our native pointer is a valid reference. If not, throw ObjectDisposedException
EmitCheckDisposed (il, nativePtr, methodType);
EmitCheckDisposed (il, nativePtr, psig.Type);
}
MethodInfo nativeMethod;
var psig = GetPInvokeSignature (typeInfo, interfaceMethod);
if (psig.ReturnClass) {
Debug.Assert (wrapper_type != null);
retVal = il.DeclareLocal (wrapper_type);
// Construct the manager wrapper object
var ctor = wrapper_type.GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null, new Type [] { typeof (CppLibrary) }, null);
Debug.Assert (ctor != null);
il.Emit (OpCodes.Ldnull);
il.Emit (OpCodes.Newobj, ctor);
il.Emit (OpCodes.Stloc, retVal);
psig.ReturnType = layout_type;
}
if (IsVirtual (interfaceMethod) && psig.Type != MethodType.NativeDtor) {
nativeMethod = EmitPrepareVirtualCall (il, typeInfo, nativePtr, vtableIndex++);
} else {
if (IsVirtual (interfaceMethod))
vtableIndex++;
if (psig.ReturnByAddr) {
//
// When using the Itanium c++ abi, some classes are returned by passing a
// hidden first argument.
//
// Put the address of the native return memory into a local
retArg = il.DeclareLocal (typeof (IntPtr));
il.Emit (OpCodes.Ldloc, retVal);
EmitLoadNativePtr (il);
il.Emit (OpCodes.Stloc, retArg);
psig.ReturnType = typeof (void);
nativeMethod = GetPInvokeForMethod (psig);
}
if (IsVirtual (interfaceMethod) && methodType != MethodType.NativeDtor)
nativeMethod = EmitPrepareVirtualCall (il, typeInfo, nativePtr, vtableIndex++);
else
nativeMethod = GetPInvokeForMethod (interfaceMethod, psig);
switch (methodType) {
switch (psig.Type) {
case MethodType.NativeCtor:
EmitConstruct (il, nativeMethod, psig, nativePtr);
break;
case MethodType.NativeDtor:
EmitDestruct (il, nativeMethod, psig, cppInstancePtr, nativePtr);
break;
default:
EmitNativeCall (il, nativeMethod, isStatic, psig, nativePtr, retArg);
EmitNativeCall (il, nativeMethod, psig, nativePtr);
break;
}
if (psig.ReturnClass) {
if (!psig.ReturnByAddr) {
//
// The method return a struct in native format which is on the stack,
// have to copy into the native memory belonging to our object
//
// Save the method return value
var rval = il.DeclareLocal (layout_type);
il.Emit (OpCodes.Stloc, rval);
// Load the ptr to the native memory (dest)
il.Emit (OpCodes.Ldloc, retVal);
EmitLoadNativePtr (il);
// Load the address of the method return value (src)
il.Emit (OpCodes.Ldloca, rval);
// Copy
il.Emit (OpCodes.Cpobj, layout_type);
}
il.Emit (OpCodes.Ldloc, retVal);
}
il.Emit (OpCodes.Ret);
return trampoline;
}
@ -320,51 +253,68 @@ namespace Mono.VisualC.Interop.ABI { @@ -320,51 +253,68 @@ namespace Mono.VisualC.Interop.ABI {
if (property.CanWrite)
throw new InvalidProgramException ("Properties in C++ interface must be read-only.");
MethodInfo imethod = property.GetGetMethod ();
string methodName = imethod.Name;
string propName = property.Name;
Type retType = imethod.ReturnType;
FieldBuilder fieldData;
var imethod = property.GetGetMethod ();
var methodName = imethod.Name;
var propName = property.Name;
var retType = imethod.ReturnType;
var fieldProp = impl_type.DefineProperty (propName, PropertyAttributes.None, retType, Type.EmptyTypes);
var methodAttr = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
var fieldGetter = impl_type.DefineMethod (methodName, methodAttr, retType, Type.EmptyTypes);
var il = fieldGetter.GetILGenerator ();
// 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);
var fieldData = impl_type.DefineField ("__" + propName + "_Data", retType, FieldAttributes.InitOnly | FieldAttributes.Private);
// we need to lazy init the field because we don't have accurate field offset until after
// all base classes have been added (by ctor)
var lazyInit = il.DefineLabel ();
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, fieldData);
il.Emit (OpCodes.Dup);
il.Emit (OpCodes.Brfalse_S, lazyInit);
il.Emit (OpCodes.Ret);
// init new CppField
il.MarkLabel (lazyInit);
il.Emit (OpCodes.Pop);
il.Emit (OpCodes.Ldarg_0);
// init our field data with a new instance of CppField
// first, get field offset
//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)
* ctorIL.Emit(OpCodes.Ldtoken, nativeLayout);
* ctorIL.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
* 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) }));
// = ((int)Marshal.OffsetOf (layout_type, propName)) + FieldOffsetPadding;
il.Emit(OpCodes.Ldtoken, layout_type);
il.Emit(OpCodes.Call, type_gettypefromhandle);
il.Emit(OpCodes.Ldstr, propName);
il.Emit(OpCodes.Call, marshal_offsetof);
ctor_il.Emit (OpCodes.Stfld, fieldData);
*/
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.");
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeinfo_field);
il.Emit (OpCodes.Callvirt, typeinfo_fieldoffset);
il.Emit (OpCodes.Add);
PropertyBuilder fieldProp = impl_type.DefineProperty (propName, PropertyAttributes.None, retType, Type.EmptyTypes);
// new CppField<T> (<field offset>)
il.Emit (OpCodes.Newobj, retType.GetConstructor (new Type[] { typeof(int) }));
MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
MethodBuilder fieldGetter = impl_type.DefineMethod (methodName, methodAttr, retType, Type.EmptyTypes);
ILGenerator il = fieldGetter.GetILGenerator ();
il.Emit (OpCodes.Stfld, fieldData);
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, fieldData);
il.Emit (OpCodes.Ret);
} else if (retType.Equals (typeof (CppTypeInfo))) {
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeinfo_field);
il.Emit (OpCodes.Ret);
} else
throw new InvalidProgramException ("Properties in C++ interface can only be of type CppField.");
fieldProp.SetGetMethod (fieldGetter);
return fieldProp;
@ -379,43 +329,47 @@ namespace Mono.VisualC.Interop.ABI { @@ -379,43 +329,47 @@ namespace Mono.VisualC.Interop.ABI {
if (wrapper_type == null)
return null;
MethodInfo interfaceMethod = typeInfo.VirtualMethods [vtableIndex];
MethodInfo targetMethod = FindManagedOverrideTarget (interfaceMethod);
var sig = typeInfo.VirtualMethods [vtableIndex];
var interfaceMethod = sig.OrigMethod;
var targetMethod = FindManagedOverrideTarget (interfaceMethod);
if (targetMethod == null)
return null;
var psig = GetPInvokeSignature (typeInfo, interfaceMethod);
var interfaceArgs = ReflectionHelper.GetMethodParameterTypes (interfaceMethod);
var nativeArgs = sig.ParameterTypes.ToArray ();
// TODO: According to http://msdn.microsoft.com/en-us/library/w16z8yc4.aspx
// The dynamic method created with this constructor has access to public and internal members of all the types contained in module m.
// This does not appear to hold true, so we also disable JIT visibility checks.
DynamicMethod trampolineIn = new DynamicMethod (wrapper_type.Name + "_" + interfaceMethod.Name + "_FromNative", psig.ReturnType,
psig.ParameterTypes.ToArray (), typeof (CppInstancePtr).Module, true);
var trampolineIn = new DynamicMethod (wrapper_type.Name + "_" + interfaceMethod.Name + "_FromNative", sig.ReturnType,
nativeArgs, typeof (CppInstancePtr).Module, true);
ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, trampolineIn, true);
ILGenerator il = trampolineIn.GetILGenerator ();
// for static methods:
// for static (target) methods:
OpCode callInstruction = OpCodes.Call;
int argLoadStart = 1;
int argLoadStart = IsStatic (interfaceMethod)? 0 : 1; // chop off C++ instance ptr if there is one
// for instance methods, we need an instance to call them on!
// for instance methods, we need a managed instance to call them on!
if (!targetMethod.IsStatic) {
callInstruction = OpCodes.Callvirt;
//argLoadStart = 1;
argLoadStart = 1;
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);
MethodInfo getManagedObj = cppip_getmanaged.MakeGenericMethod (wrapper_type);
il.Emit (OpCodes.Call, getManagedObj);
}
for (int i = argLoadStart; i < psig.ParameterTypes.Count; i++) {
for (int i = argLoadStart; i < interfaceArgs.Length; i++) {
il.Emit (OpCodes.Ldarg, i);
EmitInboundMarshal (il, nativeArgs [i], interfaceArgs [i]);
}
il.Emit (OpCodes.Tailcall);
il.Emit (callInstruction, targetMethod);
EmitOutboundMarshal (il, targetMethod.ReturnType, sig.ReturnType);
il.Emit (OpCodes.Ret);
return trampolineIn.CreateDelegate (typeInfo.VTableDelegateTypes [vtableIndex]);
@ -423,6 +377,9 @@ namespace Mono.VisualC.Interop.ABI { @@ -423,6 +377,9 @@ namespace Mono.VisualC.Interop.ABI {
protected virtual MethodInfo FindManagedOverrideTarget (MethodInfo interfaceMethod)
{
if (interfaceMethod == null)
return null;
// 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);
@ -444,31 +401,30 @@ namespace Mono.VisualC.Interop.ABI { @@ -444,31 +401,30 @@ namespace Mono.VisualC.Interop.ABI {
MethodBuilder methodBuilder = impl_type.DefineMethod (interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual,
interfaceMethod.ReturnType, parameterTypes);
ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, methodBuilder, false);
return methodBuilder;
}
/**
* Defines a new MethodBuilder that calls the specified C++ (non-virtual) method using its mangled name
*/
protected virtual MethodBuilder GetPInvokeForMethod (MethodInfo signature, PInvokeSignature psig)
protected virtual MethodBuilder GetPInvokeForMethod (PInvokeSignature sig)
{
string entryPoint = GetMangledMethodName (signature);
string entryPoint = sig.Name;
if (entryPoint == null)
throw new NotSupportedException ("Could not mangle method name.");
string lib;
if (IsInline (signature))
lib = library + "-inline";
if (IsInline (sig.OrigMethod) && library.InlineMethodPolicy == InlineMethods.SurrogateLib)
lib = library.Name + "-inline";
else
lib = library;
lib = library.Name;
MethodBuilder builder = impl_type.DefinePInvokeMethod ("__$" + signature.Name + "_Impl", lib, entryPoint,
MethodBuilder builder = impl_type.DefinePInvokeMethod (entryPoint, lib, entryPoint,
MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl,
CallingConventions.Standard, psig.ReturnType, psig.ParameterTypes.ToArray (),
GetCallingConvention (signature).Value, CharSet.Ansi);
CallingConventions.Standard, sig.ReturnType, sig.ParameterTypes.ToArray (),
sig.CallingConvention.Value, CharSet.Ansi);
builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig);
ReflectionHelper.ApplyMethodParameterAttributes (signature, builder, true);
ReflectionHelper.ApplyMethodParameterAttributes (sig.OrigMethod, builder, true);
return builder;
}
@ -502,38 +458,41 @@ namespace Mono.VisualC.Interop.ABI { @@ -502,38 +458,41 @@ namespace Mono.VisualC.Interop.ABI {
il.Emit (OpCodes.Ldfld, typeinfo_field);
il.Emit (OpCodes.Callvirt, typeinfo_nativesize);
if (wrapper_type != null) {
if (wrapper_type != null && interfaceMethod.GetParameters ().Any ()) {
// load managed wrapper
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof (int), typeof (object) }, null));
il.Emit (OpCodes.Newobj, cppip_fromsize_managed);
} else
il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof (int) }, null));
il.Emit (OpCodes.Newobj, cppip_fromsize);
}
protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod,
PInvokeSignature psig,
LocalBuilder nativePtr)
protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr)
{
EmitNativeCall (il, nativeMethod, false, psig, nativePtr, null);
// FIXME: Why is this needed ? The c++ ctor initializes it
//EmitInitVTable (il, nativePtr);
Debug.Assert (psig.Type == MethodType.NativeCtor);
EmitNativeCall (il, nativeMethod, psig, nativePtr);
EmitInitVTable (il, nativePtr);
}
protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod,
PInvokeSignature psig,
protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod, PInvokeSignature psig,
LocalBuilder cppInstancePtr, LocalBuilder nativePtr)
{
Debug.Assert (psig.Type == MethodType.NativeDtor);
// we don't do anything if the object wasn't managed alloc
if (cppInstancePtr == null)
return;
// bail if we weren't alloc'd by managed code
Label bail = il.DefineLabel ();
il.Emit (OpCodes.Ldloca_S, cppInstancePtr);
il.Emit (OpCodes.Brfalse_S, bail); // <- FIXME? (would this ever branch?)
il.Emit (OpCodes.Ldloca_S, cppInstancePtr);
il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("IsManagedAlloc").GetGetMethod ());
il.Emit (OpCodes.Call, cppip_managedalloc);
il.Emit (OpCodes.Brfalse_S, bail);
EmitResetVTable (il, nativePtr);
EmitNativeCall (il, nativeMethod, false, psig, nativePtr, null);
EmitNativeCall (il, nativeMethod, psig, nativePtr);
il.MarkLabel (bail);
}
@ -543,142 +502,206 @@ namespace Mono.VisualC.Interop.ABI { @@ -543,142 +502,206 @@ namespace Mono.VisualC.Interop.ABI {
* GetPInvokeForMethod or the MethodInfo of a vtable method.
* To complete method, emit OpCodes.Ret.
*/
protected virtual void EmitNativeCall (ILGenerator il, MethodInfo nativeMethod,
bool isStatic, PInvokeSignature psig,
LocalBuilder nativePtr, LocalBuilder retArg)
protected virtual void EmitNativeCall (ILGenerator il, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr)
{
//
// The managed signature looks like this:
// (<.net this>, @this (if not static), <additional args>
// The native signature looks like this:
// (<hidden retarg if present>, @this, <additional args>)
//
// The managed argument index, skip .net this
int aindex = 1;
var interfaceMethod = psig.OrigMethod;
var interfaceArgs = interfaceMethod.GetParameters ();
// Do conversions
int argLoadStart = 1; // For static methods, just strip off arg0 (.net this pointer)
if (!IsStatic (interfaceMethod))
{
argLoadStart = 2; // For instance methods, strip off CppInstancePtr and pass the corresponding IntPtr
il.Emit (OpCodes.Ldloc_S, nativePtr);
}
// load and marshal arguments
for (int i = argLoadStart; i <= interfaceArgs.Length; i++) {
il.Emit (OpCodes.Ldarg, i);
EmitOutboundMarshal (il, interfaceArgs [i - 1].ParameterType, psig.ParameterTypes [i - 1]);
}
il.Emit (OpCodes.Call, nativeMethod);
// Marshal return value
EmitInboundMarshal (il, psig.ReturnType, interfaceMethod.ReturnType);
}
public virtual PInvokeSignature GetPInvokeSignature (MethodInfo method)
{
var parameters = method.GetParameters ();
var pinvokeTypes = new List<Type> (parameters.Length);
foreach (var pi in parameters) {
pinvokeTypes.Add (ToPInvokeType (pi.ParameterType, pi));
}
return new PInvokeSignature {
OrigMethod = method,
Name = GetMangledMethodName (method),
Type = GetMethodType (method),
CallingConvention = GetCallingConvention (method),
ParameterTypes = pinvokeTypes,
ReturnType = ToPInvokeType (method.ReturnType, method.ReturnTypeCustomAttributes)
};
}
public virtual Type ToPInvokeType (Type t, ICustomAttributeProvider icap)
{
if (t == typeof (bool)) {
return typeof (byte);
LocalBuilder[] args = new LocalBuilder [psig.ParameterTypes.Count];
aindex = 1;
for (int pindex = 0; pindex < psig.ParameterTypes.Count; pindex++) {
if (!isStatic && pindex == 0) {
// For instance methods, strip off CppInstancePtr and pass the corresponding IntPtr
args [pindex] = nativePtr;
aindex ++;
continue;
} else if (typeof (ICppObject).IsAssignableFrom (t)) {
if (IsByVal (icap)) {
// Can't use an interface/cattr since the native layout type is private
// Pass it as a type argument to I<Foo> ?
var f = t.GetField ("native_layout", BindingFlags.Static|BindingFlags.NonPublic);
if (f == null || f.FieldType != typeof (Type))
throw new NotImplementedException ("Type '" + t + "' needs to have a 'native_layout' field before it can be passed by value.");
t = (Type)f.GetValue (null);
if (!t.IsValueType)
throw new NotSupportedException ("The value for 'native_layout' for type '" + t + "' must be a value type.");
return t;
} else { // by ref
return typeof (IntPtr);
}
}
Type ptype = psig.ParameterTypes [pindex];
switch (psig.ParameterMarshallers [pindex]) {
case ParameterMarshal.Default:
return t;
}
// The above should return parameter/return types that
// correspond with the marshalling implemented in the next 2 methods.
// This method marshals from managed -> C++
// The value it is marshaling will be on the stack.
protected virtual void EmitOutboundMarshal (ILGenerator il, Type managedType, Type targetType)
{
var nextArg = il.DefineLabel ();
// FIXME: Why is this needed ?
// auto marshal bool to C++ bool type (0 = false , 1 = true )
if (ptype.Equals (typeof (bool))) {
args [pindex] = il.DeclareLocal (typeof (bool));
if (managedType.Equals (typeof (bool))) {
Label isTrue = il.DefineLabel ();
Label done = il.DefineLabel ();
il.Emit (OpCodes.Ldarg, aindex);
il.Emit (OpCodes.Brtrue_S, isTrue);
il.Emit (OpCodes.Brtrue, isTrue);
il.Emit (OpCodes.Ldc_I4_0);
il.Emit (OpCodes.Br_S, done);
il.Emit (OpCodes.Br, done);
il.MarkLabel (isTrue);
il.Emit (OpCodes.Ldc_I4_1);
il.MarkLabel (done);
il.Emit (OpCodes.Stloc, args [pindex]);
//il.Emit (OpCodes.Conv_I1);
}
break;
case ParameterMarshal.ClassByRef: {
args [pindex] = il.DeclareLocal (typeof (IntPtr));
// Pass the native pointer of the class
// Null check
Label isNull = il.DefineLabel ();
Label contLabel = il.DefineLabel ();
il.Emit (OpCodes.Ldarg, aindex);
il.Emit (OpCodes.Brfalse_S, isNull);
// Non-null case
il.Emit (OpCodes.Ldarg, aindex);
EmitLoadNativePtr (il);
// FIXME: Dispose check
il.Emit (OpCodes.Br_S, contLabel);
// Null case
il.MarkLabel (isNull);
il.Emit (OpCodes.Ldnull);
il.Emit (OpCodes.Conv_I);
// Common case
il.MarkLabel (contLabel);
il.Emit (OpCodes.Stloc, args [pindex]);
break;
}
case ParameterMarshal.ClassByVal: {
// Pass a copy of the native memory of the class
args [pindex] = il.DeclareLocal (ptype);
Label normalLabel = il.DefineLabel ();
il.Emit (OpCodes.Ldarg, aindex);
il.Emit (OpCodes.Brtrue_S, normalLabel);
// auto marshal ICppObject
if (typeof (ICppObject).IsAssignableFrom (managedType)) {
var nullCase = il.DefineLabel ();
var param = il.DeclareLocal (typeof (CppInstancePtr));
// check for null
il.Emit (OpCodes.Dup);
il.Emit (OpCodes.Brfalse_S, nullCase);
// FIXME: ICppObject could be implemented by a value type
il.Emit (OpCodes.Callvirt, cppobj_native);
il.Emit (OpCodes.Stloc, param);
if (targetType == typeof (IntPtr)) { // by ref
il.Emit (OpCodes.Ldloca, param);
il.Emit (OpCodes.Call, cppip_native);
il.MarkLabel (nullCase);
} else { // by val
var val = il.DeclareLocal (targetType);
il.Emit (OpCodes.Ldloca, val); // dest
il.Emit (OpCodes.Ldloca, param);
il.Emit (OpCodes.Call, cppip_native); // src
il.Emit (OpCodes.Cpobj, targetType);
il.Emit (OpCodes.Ldloc, val);
il.Emit (OpCodes.Br_S, nextArg);
il.MarkLabel (nullCase);
// Null case
il.Emit (OpCodes.Ldstr, "Cannot pass null object of type '" + ptype.DeclaringType + "' to c++ by value");
il.Emit (OpCodes.Ldstr, "Cannot pass null object of type '" + managedType + "' to c++ by value");
il.Emit (OpCodes.Newobj, typeof (ArgumentException).GetConstructor (new Type[] { typeof(string) }));
il.Emit (OpCodes.Throw);
// Non-null case
il.MarkLabel (normalLabel);
// Dest
il.Emit (OpCodes.Ldloca, args [pindex]);
// Load the native ptr of the object (src)
il.Emit (OpCodes.Ldarg, aindex);
EmitLoadNativePtr (il);
// FIXME: Dispose check
// Copy
il.Emit (OpCodes.Cpobj, ptype);
break;
}
default:
throw new NotImplementedException ();
}
aindex ++;
il.MarkLabel (nextArg);
}
// Pass arguments
aindex = 1;
int pindexStart = 0;
// This method marshals from C++ -> managed
// The value it is marshaling will be on the stack.
protected virtual void EmitInboundMarshal (ILGenerator il, Type nativeType, Type targetType)
{
var next = il.DefineLabel ();
if (retArg != null) {
pindexStart ++;
il.Emit (OpCodes.Ldloc, retArg);
}
// marshal IntPtr -> ICppObject
if (nativeType == typeof (IntPtr) && typeof (ICppObject).IsAssignableFrom (targetType)) {
for (int pindex = pindexStart; pindex < psig.ParameterTypes.Count; pindex++) {
// The first argument is the .net this argument
if (args [pindex] != null)
il.Emit (OpCodes.Ldloc, args [pindex]);
else
il.Emit (OpCodes.Ldarg, aindex);
var isNull = il.DefineLabel ();
aindex ++;
}
// first, we check for null
il.Emit (OpCodes.Dup);
il.Emit (OpCodes.Brfalse_S, isNull);
// Make the call
il.Emit (OpCodes.Newobj, cppip_fromnative);
EmitCreateCppObjectFromNative (il, targetType);
il.Emit (OpCodes.Call, nativeMethod);
}
il.MarkLabel (isNull);
il.Emit (OpCodes.Pop);
il.Emit (OpCodes.Ldnull);
public virtual PInvokeSignature GetPInvokeSignature (CppTypeInfo typeInfo, MethodInfo method) {
var originalTypes = ReflectionHelper.GetMethodParameterTypes (method);
} else if (nativeType.IsValueType && typeof (ICppObject).IsAssignableFrom (targetType)) {
// marshal value type -> ICppObject
var pinvokeTypes = originalTypes.Transform (
For.AnyInputIn (typeof (bool)).Emit (typeof (byte)),
// Obviously, we lose all managed overrides if we pass by value,
// but this "slicing" happens in vanilla C++ as well
// CppInstancePtr implements ICppObject
For.InputsWhere ((Type t) => typeof (ICppObject).IsAssignableFrom (t)).Emit (typeof (IntPtr)),
var ptr = il.DeclareLocal (typeof (CppInstancePtr));
For.UnmatchedInput<Type> ().Emit (t => t)
);
il.Emit (OpCodes.Box, nativeType); // structure
il.Emit (OpCodes.Sizeof, nativeType);
il.Emit (OpCodes.Newobj, cppip_fromsize);
il.Emit (OpCodes.Stloc, ptr);
il.Emit (OpCodes.Ldloca, ptr);
il.Emit (OpCodes.Call, cppip_native); // ptr
il.Emit (OpCodes.Ldc_I4_0); // fDeleteOld
il.Emit (OpCodes.Call, marshal_structuretoptr);
il.Emit (OpCodes.Ldloc, ptr);
EmitCreateCppObjectFromNative (il, targetType);
}
il.MarkLabel (next);
}
// Expects CppInstancePtr on stack. No null check performed
protected virtual void EmitCreateCppObjectFromNative (ILGenerator il, Type targetType)
{
if (targetType == typeof (ICppObject))
targetType = typeof (CppInstancePtr);
Type returnType = method.ReturnType;
// check for a native constructor (i.e. a public ctor in the wrapper that takes CppInstancePtr)
var ctor = targetType.GetConstructor (BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Instance, null, new Type [] { typeof (CppInstancePtr) }, null);
if (ctor == null)
throw new InvalidProgramException (string.Format ("Type `{0}' implements ICppObject but does not contain a public constructor that takes CppInstancePtr", targetType));
return new PInvokeSignature { OrigMethod = method, ParameterTypes = pinvokeTypes.ToList (), ReturnType = returnType };
il.Emit (OpCodes.Newobj, ctor);
}
/**
@ -767,7 +790,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -767,7 +790,7 @@ namespace Mono.VisualC.Interop.ABI {
native = il.DeclareLocal (typeof (IntPtr));
il.Emit (OpCodes.Stloc_S, cppip);
il.Emit (OpCodes.Ldloca_S, cppip);
il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("Native").GetGetMethod ());
il.Emit (OpCodes.Call, cppip_native);
il.Emit (OpCodes.Stloc_S, native);
} else if (firstParamType.Equals (typeof (IntPtr))) {
native = il.DeclareLocal (typeof (IntPtr));
@ -779,17 +802,6 @@ namespace Mono.VisualC.Interop.ABI { @@ -779,17 +802,6 @@ namespace Mono.VisualC.Interop.ABI {
throw new ArgumentException ("First argument to non-static C++ method must be byref, IntPtr or CppInstancePtr.");
}
// Emit obj.Native.Native
// On enter, the stack should contain a reference to a CppInstancePtr
// On exit, it contains an IntPtr
void EmitLoadNativePtr (ILGenerator il) {
LocalBuilder cppip = il.DeclareLocal (typeof (CppInstancePtr));
il.Emit (OpCodes.Call, typeof (ICppObject).GetMethod ("get_Native"));
il.Emit (OpCodes.Stloc_S, cppip);
il.Emit (OpCodes.Ldloca_S, cppip);
il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("Native").GetGetMethod ());
}
protected virtual void EmitCheckManagedAlloc (ILGenerator il, LocalBuilder cppip)
{
// make sure we were allocated by managed code
@ -822,4 +834,5 @@ namespace Mono.VisualC.Interop.ABI { @@ -822,4 +834,5 @@ namespace Mono.VisualC.Interop.ABI {
}
}
}
}

97
src/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs

@ -30,6 +30,7 @@ using System; @@ -30,6 +30,7 @@ using System;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Runtime.InteropServices;
@ -42,19 +43,34 @@ namespace Mono.VisualC.Interop.ABI { @@ -42,19 +43,34 @@ namespace Mono.VisualC.Interop.ABI {
{
}
protected override CppTypeInfo MakeTypeInfo (IEnumerable<MethodInfo> methods, IEnumerable<MethodInfo> virtualMethods)
protected override CppTypeInfo MakeTypeInfo (IEnumerable<PInvokeSignature> methods)
{
bool hasExplicitCopyCtor = false;
bool hasExplicitDtor = false;
foreach (var m in methods) {
if (m.IsDefined (typeof (CopyConstructorAttribute), false) && !m.IsDefined (typeof (ArtificialAttribute), false))
hasExplicitCopyCtor = true;
if (m.IsDefined (typeof (DestructorAttribute), false) && !m.IsDefined (typeof (ArtificialAttribute), false))
hasExplicitDtor = true;
return new CppTypeInfo (this, GetVirtualMethodSlots (methods), layout_type);
}
return new ItaniumTypeInfo (this, virtualMethods, layout_type) { HasExplicitCopyCtor = hasExplicitCopyCtor, HasExplicitDtor = hasExplicitDtor };
private IEnumerable<PInvokeSignature> GetVirtualMethodSlots (IEnumerable<PInvokeSignature> methods)
{
foreach (var method in methods) {
if (!IsVirtual (method.OrigMethod))
continue;
yield return method;
// Itanium has extra slot for virt dtor
if (method.Type == MethodType.NativeDtor)
yield return null;
}
}
protected override MethodBuilder DefineMethod (PInvokeSignature sig, CppTypeInfo typeInfo, ref int vtableIndex)
{
var builder = base.DefineMethod (sig, typeInfo, ref vtableIndex);
// increment vtableIndex an extra time for that extra vdtor slot (already incremented once in base)
if (IsVirtual (sig.OrigMethod) && sig.Type == MethodType.NativeDtor)
vtableIndex++;
return builder;
}
public override CallingConvention? GetCallingConvention (MethodInfo methodInfo)
@ -71,6 +87,10 @@ namespace Mono.VisualC.Interop.ABI { @@ -71,6 +87,10 @@ namespace Mono.VisualC.Interop.ABI {
ParameterInfo [] parameters = methodInfo.GetParameters ();
StringBuilder nm = new StringBuilder ("_ZN", 30);
if (IsConst (methodInfo))
nm.Append ('K');
nm.Append (class_name.Length).Append (class_name);
compressMap [class_name] = compressMap.Count;
@ -158,63 +178,6 @@ namespace Mono.VisualC.Interop.ABI { @@ -158,63 +178,6 @@ namespace Mono.VisualC.Interop.ABI {
return code.ToString ();
}
public override PInvokeSignature GetPInvokeSignature (CppTypeInfo typeInfo, MethodInfo method) {
Type returnType = method.ReturnType;
bool retClass = false;
bool retByAddr = false;
if (typeof (ICppObject).IsAssignableFrom (returnType)) {
retClass = true;
if ((typeInfo as ItaniumTypeInfo).HasExplicitCopyCtor ||
(typeInfo as ItaniumTypeInfo).HasExplicitDtor) {
// Section 3.1.4:
// Classes with non-default copy ctors/destructors are returned using a
// hidden argument
retByAddr = true;
}
}
ParameterInfo[] parameters = method.GetParameters ();
var ptypes = new List<Type> ();
var pmarshal = new List<ParameterMarshal> ();
// FIXME: Handle ByVal attributes
foreach (var pi in parameters) {
Type t = pi.ParameterType;
Type ptype = t;
ParameterMarshal m = ParameterMarshal.Default;
if (t == typeof (bool)) {
ptype = typeof (byte);
} else if (typeof (ICppObject).IsAssignableFrom (t) && t != typeof (CppInstancePtr)) {
if (pi.IsDefined (typeof (ByValAttribute), false)) {
m = ParameterMarshal.ClassByVal;
// Can't use an interface/cattr since the native layout type is private
// Pass it as a type argument to I<Foo> ?
var f = t.GetField ("native_layout", BindingFlags.Static|BindingFlags.NonPublic);
if (f == null || f.FieldType != typeof (Type))
throw new NotImplementedException ("Type '" + t + "' needs to have a 'native_layout' field before it can be passed by value.");
ptype = (Type)f.GetValue (null);
} else {
ptype = typeof (IntPtr);
m = ParameterMarshal.ClassByRef;
}
} else if (typeof (ICppObject).IsAssignableFrom (t)) {
// CppInstancePtr implements ICppObject
ptype = typeof (IntPtr);
}
ptypes.Add (ptype);
pmarshal.Add (m);
}
if (retByAddr) {
ptypes.Insert (0, typeof (IntPtr));
pmarshal.Insert (0, ParameterMarshal.Default);
}
return new PInvokeSignature { OrigMethod = method, ParameterTypes = ptypes, ParameterMarshallers = pmarshal, ReturnType = returnType, ReturnClass = retClass, ReturnByAddr = retByAddr };
}
}

79
src/Mono.VisualC.Interop/ABI/Impl/ItaniumTypeInfo.cs

@ -1,79 +0,0 @@ @@ -1,79 +0,0 @@
//
// Author:
// Andreia Gaita (shana@spoiledcat.net)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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)
{
// Remove all virtual destructors from their declared position in the vtable
for (int i = 0; i < VirtualMethods.Count; i++) {
if (Abi.GetMethodType (VirtualMethods [i]) != MethodType.NativeDtor)
continue;
hasVirtualDtor = true;
VirtualMethods.RemoveAt (i);
VTableDelegateTypes.RemoveAt (i);
VTableOverrides.RemoveAt (i);
break;
}
}
public bool HasVirtualDestructor {
get { return hasVirtualDtor; }
}
public bool HasExplicitCopyCtor { get; set; }
public bool HasExplicitDtor { get; set; }
public override void AddBase (CppTypeInfo baseType)
{
if (TypeComplete)
return;
hasVirtualDtor |= ((ItaniumTypeInfo)baseType).HasVirtualDestructor;
base.AddBase (baseType, false);
}
// 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;
}
}
}
}

5
src/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs

@ -44,9 +44,9 @@ namespace Mono.VisualC.Interop.ABI { @@ -44,9 +44,9 @@ namespace Mono.VisualC.Interop.ABI {
{
}
protected override CppTypeInfo MakeTypeInfo (IEnumerable<MethodInfo> methods, IEnumerable<MethodInfo> virtualMethods)
protected override CppTypeInfo MakeTypeInfo (IEnumerable<PInvokeSignature> methods)
{
return new MsvcTypeInfo (this, virtualMethods, layout_type);
return new MsvcTypeInfo (this, methods.Where (m => IsVirtual (m.OrigMethod)), layout_type);
}
public override CallingConvention? GetCallingConvention (MethodInfo methodInfo)
@ -209,7 +209,6 @@ namespace Mono.VisualC.Interop.ABI { @@ -209,7 +209,6 @@ namespace Mono.VisualC.Interop.ABI {
code.Append(mangleType.ElementTypeName);
code.Append ("@@");
break;
}
return code.ToString ();

4
src/Mono.VisualC.Interop/ABI/Impl/MsvcTypeInfo.cs

@ -29,9 +29,11 @@ using System.Collections.Generic; @@ -29,9 +29,11 @@ using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Reflection;
using Mono.VisualC.Interop.Util;
namespace Mono.VisualC.Interop.ABI {
public class MsvcTypeInfo : CppTypeInfo {
public MsvcTypeInfo (MsvcAbi abi, IEnumerable<MethodInfo> virtualMethods, Type nativeLayout)
public MsvcTypeInfo (MsvcAbi abi, IEnumerable<PInvokeSignature> virtualMethods, Type nativeLayout)
: base (abi, virtualMethods, nativeLayout)
{
}

1
src/Mono.VisualC.Interop/ABI/MethodType.cs

@ -27,6 +27,7 @@ using System; @@ -27,6 +27,7 @@ using System;
namespace Mono.VisualC.Interop {
public enum MethodType {
NoOp,
NotImplemented,
Native,
NativeCtor,
NativeDtor,

14
src/Mono.VisualC.Interop/Attributes.cs

@ -49,7 +49,7 @@ namespace Mono.VisualC.Interop { @@ -49,7 +49,7 @@ namespace Mono.VisualC.Interop {
[AttributeUsage (AttributeTargets.Method)]
public class CopyConstructorAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Parameter)]
[AttributeUsage (AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
public class ByValAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
@ -119,6 +119,18 @@ using Mono.VisualC.Interop; @@ -119,6 +119,18 @@ using Mono.VisualC.Interop;
{
return method.IsDefined (typeof (InlineAttribute), false);
}
public virtual bool IsArtificial (MethodInfo method)
{
return method.IsDefined (typeof (ArtificialAttribute), false);
}
public virtual bool IsCopyConstructor (MethodInfo method)
{
return method.IsDefined (typeof (CopyConstructorAttribute), false);
}
public virtual bool IsByVal (ICustomAttributeProvider icap)
{
return icap.IsDefined (typeof (ByValAttribute), false);
}
public virtual CppType GetMangleType (ICustomAttributeProvider icap, Type managedType)
{

10
src/Mono.VisualC.Interop/CppInstancePtr.cs

@ -55,7 +55,7 @@ namespace Mono.VisualC.Interop { @@ -55,7 +55,7 @@ namespace Mono.VisualC.Interop {
if (!implCache.TryGetValue (typeof (Iface), out cachedImpl))
{
VirtualOnlyAbi virtualABI = new VirtualOnlyAbi (VTable.BindToSignature);
impl = virtualABI.ImplementClass<Iface> (typeof (TWrapper), string.Empty, string.Empty);
impl = virtualABI.ImplementClass<Iface> (typeof (TWrapper), new CppLibrary (string.Empty), string.Empty);
implCache.Add (typeof (Iface), impl);
}
else
@ -86,7 +86,7 @@ namespace Mono.VisualC.Interop { @@ -86,7 +86,7 @@ namespace Mono.VisualC.Interop {
}
// Alloc a new C++ instance when there is no managed wrapper.
internal CppInstancePtr (int nativeSize)
public CppInstancePtr (int nativeSize)
{
ptr = Marshal.AllocHGlobal (nativeSize);
manage_memory = true;
@ -127,12 +127,6 @@ namespace Mono.VisualC.Interop { @@ -127,12 +127,6 @@ namespace Mono.VisualC.Interop {
get { return this; }
}
public int NativeSize {
get {
throw new NotImplementedException ();
}
}
public bool IsManagedAlloc {
get { return manage_memory; }
}

38
src/Mono.VisualC.Interop/CppLibrary.cs

@ -38,12 +38,29 @@ using System.Reflection.Emit; @@ -38,12 +38,29 @@ using System.Reflection.Emit;
using Mono.VisualC.Interop.ABI;
namespace Mono.VisualC.Interop {
public enum InlineMethods {
// Normally, C++ inline methods are not exported from the library, so C++ interop cannot call them.
// This is the default option. It throws a NotImplementedException if you try to call the native version of one of these methods.
// Use this if you reimplement the inline methods in managed code, or if they are not to be available in the bindings.
NotPresent,
// Expect the inline methods to be present in the specified library
// For example, if the library was compiled with GCC's -fkeep-inline-functions option
Present,
// Expect the inline methods to be exported in a separate library named %name%-inline
SurrogateLib,
}
public sealed class CppLibrary {
internal static AssemblyBuilder interopAssembly;
internal static ModuleBuilder interopModule;
public CppAbi Abi { get; private set; }
public string Name { get; private set; }
public InlineMethods InlineMethodPolicy { get; private set; }
static CppLibrary ()
{
@ -55,17 +72,17 @@ namespace Mono.VisualC.Interop { @@ -55,17 +72,17 @@ namespace Mono.VisualC.Interop {
}
public CppLibrary (string name)
: this (name, InlineMethods.NotPresent)
{
if (name == null)
throw new ArgumentNullException ("Name cannot be NULL.");
this.Name = name;
}
// FIXME: This is where we'd auto detect the ABI
this.Abi = new ItaniumAbi ();
public CppLibrary (string name, InlineMethods inlinePolicy)
: this (name, new ItaniumAbi (), inlinePolicy)
{
//FIXME: Ideally we would auto-detect ABI here.
}
public CppLibrary (string name, CppAbi abi)
public CppLibrary (string name, CppAbi abi, InlineMethods inlinePolicy)
{
if (name == null)
throw new ArgumentNullException ("Name cannot be NULL.");
@ -74,6 +91,7 @@ namespace Mono.VisualC.Interop { @@ -74,6 +91,7 @@ namespace Mono.VisualC.Interop {
this.Name = name;
this.Abi = abi;
this.InlineMethodPolicy = inlinePolicy;
}
// Mainly for debugging at this point
@ -87,7 +105,7 @@ namespace Mono.VisualC.Interop { @@ -87,7 +105,7 @@ namespace Mono.VisualC.Interop {
public Iface GetClass<Iface> (string className)
where Iface : ICppClass
{
return Abi.ImplementClass<Iface> (null, Name, className);
return Abi.ImplementClass<Iface> (null, this, className);
}
// For instantiating or working with a class that may have fields
@ -96,7 +114,7 @@ namespace Mono.VisualC.Interop { @@ -96,7 +114,7 @@ namespace Mono.VisualC.Interop {
where Iface : ICppClassInstantiatable
where NativeLayout : struct
{
return Abi.ImplementClass<Iface, NativeLayout> (null, Name, className);
return Abi.ImplementClass<Iface, NativeLayout> (null, this, className);
}
/* The most powerful override. Allows the following from managed code:
@ -109,7 +127,7 @@ namespace Mono.VisualC.Interop { @@ -109,7 +127,7 @@ namespace Mono.VisualC.Interop {
where NativeLayout : struct
where Managed : ICppObject
{
return Abi.ImplementClass<Iface, NativeLayout> (typeof (Managed), Name, className);
return Abi.ImplementClass<Iface, NativeLayout> (typeof (Managed), this, className);
}
}

60
src/Mono.VisualC.Interop/CppTypeInfo.cs

@ -45,7 +45,7 @@ namespace Mono.VisualC.Interop { @@ -45,7 +45,7 @@ namespace Mono.VisualC.Interop {
public CppAbi Abi { get; private set; }
public Type NativeLayout {get; private set; }
public IList<MethodInfo> VirtualMethods { get; private set; }
public IList<PInvokeSignature> VirtualMethods { get; private set; }
public LazyGeneratedList<Type> VTableDelegateTypes { get; private set; }
public LazyGeneratedList<Delegate> VTableOverrides { get; private set; }
@ -62,14 +62,14 @@ namespace Mono.VisualC.Interop { @@ -62,14 +62,14 @@ namespace Mono.VisualC.Interop {
private VTable lazy_vtable;
public CppTypeInfo (CppAbi abi, IEnumerable<MethodInfo> virtualMethods, Type nativeLayout)
public CppTypeInfo (CppAbi abi, IEnumerable<PInvokeSignature> 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);
VirtualMethods = new List<PInvokeSignature> (virtualMethods);
VTableDelegateTypes = new LazyGeneratedList<Type> (VirtualMethods.Count, i => DelegateTypeCache.GetDelegateType (VirtualMethods [i]));
VTableOverrides = new LazyGeneratedList<Delegate> (VirtualMethods.Count, i => Abi.GetManagedOverrideTrampoline (this, i));
BaseClasses = new List<CppTypeInfo> ();
BaseVTableSlots = 0;
@ -83,8 +83,6 @@ namespace Mono.VisualC.Interop { @@ -83,8 +83,6 @@ namespace Mono.VisualC.Interop {
public virtual void AddBase (CppTypeInfo baseType)
{
if (TypeComplete)
return;
// by default, do not add another vtable pointer for this new base class
AddBase (baseType, false);
@ -92,6 +90,9 @@ namespace Mono.VisualC.Interop { @@ -92,6 +90,9 @@ namespace Mono.VisualC.Interop {
protected virtual void AddBase (CppTypeInfo baseType, bool addVTablePointer)
{
if (TypeComplete)
return;
BaseClasses.Add (baseType);
if (!addVTablePointer) {
@ -121,7 +122,6 @@ namespace Mono.VisualC.Interop { @@ -121,7 +122,6 @@ namespace Mono.VisualC.Interop {
return count;
}
// FIXME: Make this thread safe?
public virtual void CompleteType ()
{
if (TypeComplete)
@ -131,18 +131,27 @@ namespace Mono.VisualC.Interop { @@ -131,18 +131,27 @@ namespace Mono.VisualC.Interop {
baseClass.CompleteType ();
TypeComplete = true;
RemoveVTableDuplicates (ms => true);
}
protected virtual void RemoveVTableDuplicates (Predicate<MethodSignature> pred)
{
// check that any virtual methods overridden in a subclass are only included once
HashSet<MethodSignature> vsignatures = new HashSet<MethodSignature> ();
var vsignatures = new HashSet<MethodSignature> ();
for (int i = 0; i < VirtualMethods.Count; i++) {
MethodSignature sig = GetVTableMethodSignature (i);
var sig = VirtualMethods [i];
if (sig == null)
continue;
if (vsignatures.Contains (sig))
if (vsignatures.Contains (sig)) {
if (pred (sig))
VirtualMethods.RemoveAt (i--);
else
} else {
vsignatures.Add (sig);
}
}
}
public virtual T GetAdjustedVirtualCall<T> (IntPtr native, int derivedVirtualMethodIndex) where T : class /* Delegate */
{
@ -187,33 +196,6 @@ namespace Mono.VisualC.Interop { @@ -187,33 +196,6 @@ namespace Mono.VisualC.Interop {
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];
var psig = Abi.GetPInvokeSignature (this, method);
return new DelegateSignature () { ParameterTypes = psig.ParameterTypes,
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);
}
}
}

8
src/Mono.VisualC.Interop/Interfaces.cs

@ -30,6 +30,8 @@ using System; @@ -30,6 +30,8 @@ using System;
using Mono.VisualC.Interop.ABI;
namespace Mono.VisualC.Interop {
// Part of the contract for ICppObject is a public constructor that takes CppInstancePtr (native constructor)
public interface ICppObject : IDisposable {
CppInstancePtr Native { get; }
}
@ -47,7 +49,9 @@ namespace Mono.VisualC.Interop { @@ -47,7 +49,9 @@ namespace Mono.VisualC.Interop {
// It is recommended that managed wrappers implement ICppObject, but
// I'm not making it required so that any arbitrary object can be exposed to
// C++ via CppInstancePtr.ForManagedObject.
public interface ICppClassOverridable<T> : ICppClass /* where T : ICppObject */ {
CppInstancePtr Alloc (T managed);
public interface ICppClassOverridable<TManaged> : ICppClassInstantiatable
/* where TManaged : ICppObject */
{
CppInstancePtr Alloc (TManaged managed);
}
}

1
src/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj

@ -74,7 +74,6 @@ @@ -74,7 +74,6 @@
<Compile Include="CppObjectMarshaler.cs" />
<Compile Include="CppType.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" />

10
src/Mono.VisualC.Interop/Util/DelegateTypeCache.cs

@ -37,7 +37,7 @@ namespace Mono.VisualC.Interop.Util { @@ -37,7 +37,7 @@ namespace Mono.VisualC.Interop.Util {
public static class DelegateTypeCache {
private static Dictionary<DelegateSignature, Type> type_cache;
private static Dictionary<BasicSignature, Type> type_cache;
public static Type GetDelegateType (MethodInfo signature, CallingConvention? callingConvention)
{
@ -45,13 +45,13 @@ namespace Mono.VisualC.Interop.Util { @@ -45,13 +45,13 @@ namespace Mono.VisualC.Interop.Util {
}
public static Type GetDelegateType (IEnumerable<Type> parameterTypes, Type returnType, CallingConvention? callingConvention)
{
return GetDelegateType (new DelegateSignature () { ParameterTypes = parameterTypes, ReturnType = returnType, CallingConvention = callingConvention });
return GetDelegateType (new BasicSignature { ParameterTypes = parameterTypes.ToList (), ReturnType = returnType, CallingConvention = callingConvention });
}
public static Type GetDelegateType (DelegateSignature signature)
public static Type GetDelegateType (BasicSignature signature)
{
Type delegateType;
if (type_cache == null)
type_cache = new Dictionary<DelegateSignature, Type> ();
type_cache = new Dictionary<BasicSignature, Type> ();
if (!type_cache.TryGetValue (signature, out delegateType)) {
delegateType = CreateDelegateType (signature);
@ -61,7 +61,7 @@ namespace Mono.VisualC.Interop.Util { @@ -61,7 +61,7 @@ namespace Mono.VisualC.Interop.Util {
return delegateType;
}
private static Type CreateDelegateType (DelegateSignature signature)
private static Type CreateDelegateType (BasicSignature signature)
{
string delTypeName = signature.UniqueName;

36
src/Mono.VisualC.Interop/Util/MethodSignature.cs

@ -35,9 +35,9 @@ using System.Collections.Generic; @@ -35,9 +35,9 @@ using System.Collections.Generic;
namespace Mono.VisualC.Interop.Util {
public struct DelegateSignature {
public class BasicSignature {
public CallingConvention? CallingConvention { get; set; }
public IEnumerable<Type> ParameterTypes { get; set; }
public List<Type> ParameterTypes { get; set; }
public Type ReturnType { get; set; }
private string uniqueName;
@ -64,18 +64,23 @@ namespace Mono.VisualC.Interop.Util { @@ -64,18 +64,23 @@ namespace Mono.VisualC.Interop.Util {
}
}
public bool IsCompatibleWith (BasicSignature other)
{
return CallingConvention == other.CallingConvention &&
((ParameterTypes == null && other.ParameterTypes == null) ||
ParameterTypes.SequenceEqual (other.ParameterTypes)) &&
ReturnType.Equals (other.ReturnType);
}
public override bool Equals (object obj)
{
if (obj == null)
return false;
if (obj.GetType () != typeof(DelegateSignature))
if (obj.GetType () != typeof(BasicSignature))
return false;
DelegateSignature other = (DelegateSignature)obj;
BasicSignature other = (BasicSignature)obj;
return CallingConvention == other.CallingConvention &&
((ParameterTypes == null && other.ParameterTypes == null) ||
ParameterTypes.SequenceEqual (other.ParameterTypes)) &&
ReturnType.Equals (other.ReturnType);
return IsCompatibleWith (other);
}
public override int GetHashCode ()
@ -88,10 +93,9 @@ namespace Mono.VisualC.Interop.Util { @@ -88,10 +93,9 @@ namespace Mono.VisualC.Interop.Util {
}
}
public struct MethodSignature {
public class MethodSignature : BasicSignature {
public string Name { get; set; }
public MethodType Type { get; set; }
public DelegateSignature Signature { get; set; }
public override bool Equals (object obj)
{
@ -100,21 +104,27 @@ namespace Mono.VisualC.Interop.Util { @@ -100,21 +104,27 @@ namespace Mono.VisualC.Interop.Util {
if (obj.GetType () != typeof(MethodSignature))
return false;
MethodSignature other = (MethodSignature)obj;
return Signature.Equals (other.Signature) &&
return IsCompatibleWith (other) &&
Type == other.Type &&
(Type != MethodType.Native || Name.Equals (other.Name));
(Name.Equals (other.Name) || Type != MethodType.Native);
}
public override int GetHashCode ()
{
unchecked {
return Signature.GetHashCode () ^
return base.GetHashCode () ^
Type.GetHashCode () ^
(Type == MethodType.Native? Name.GetHashCode () : 0);
}
}
}
public class PInvokeSignature : MethodSignature {
// The original c# method this signature was generated from
public MethodInfo OrigMethod;
}
}

Loading…
Cancel
Save