Browse Source

Implement better metadata sharing among types whilst they are being emitted.

Implement correct Itanium pass-by-value and return-by-value semantics.
pull/1/head
Alex Corrado 14 years ago
parent
commit
179207fb18
  1. 103
      src/Mono.VisualC.Interop/ABI/CppAbi.cs
  2. 63
      src/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs
  3. 5
      src/Mono.VisualC.Interop/ABI/Impl/MsvcAbi.cs
  4. 2
      src/Mono.VisualC.Interop/CppLibrary.cs
  5. 15
      src/Mono.VisualC.Interop/CppTypeInfo.cs

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

@ -22,7 +22,12 @@ namespace Mono.VisualC.Interop.ABI { @@ -22,7 +22,12 @@ namespace Mono.VisualC.Interop.ABI {
//FIXME: Exception handling, operator overloading etc.
//FIXME: Allow interface to override default calling convention
// Subclasses should be singletons
public abstract partial class CppAbi {
// (other part of this partial class in Attributes.cs)
// These fields are specific to the class we happen to be implementing:
protected ModuleBuilder impl_module;
protected TypeBuilder impl_type;
@ -33,27 +38,31 @@ namespace Mono.VisualC.Interop.ABI { @@ -33,27 +38,31 @@ namespace Mono.VisualC.Interop.ABI {
protected FieldBuilder typeinfo_field;
protected ILGenerator ctor_il;
// These fields are specific to the ABI:
protected Dictionary<Type,CppTypeInfo> wrapper_to_typeinfo = new Dictionary<Type, CppTypeInfo> ();
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 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,
protected static readonly MethodInfo typeinfo_nativesize = typeof (CppTypeInfo).GetProperty ("NativeSize").GetGetMethod ();
protected static readonly MethodInfo typeinfo_vtable = typeof (CppTypeInfo).GetProperty ("VTable").GetGetMethod ();
protected static readonly MethodInfo typeinfo_adjvcall = typeof (CppTypeInfo).GetMethod ("GetAdjustedVirtualCall");
protected static readonly MethodInfo typeinfo_fieldoffset = typeof (CppTypeInfo).GetProperty ("FieldOffsetPadding").GetGetMethod ();
protected static readonly MethodInfo vtable_initinstance = typeof (VTable).GetMethod ("InitInstance");
protected static readonly MethodInfo vtable_resetinstance = typeof (VTable).GetMethod ("ResetInstance");
protected static readonly MethodInfo cppobj_native = typeof (ICppObject).GetProperty ("Native").GetGetMethod ();
protected static readonly MethodInfo cppip_native = typeof (CppInstancePtr).GetProperty ("Native").GetGetMethod ();
protected static readonly MethodInfo cppip_managedalloc = typeof (CppInstancePtr).GetProperty ("IsManagedAlloc").GetGetMethod ();
protected static readonly MethodInfo cppip_getmanaged = typeof (CppInstancePtr).GetMethod ("GetManaged", BindingFlags.Static | BindingFlags.NonPublic);
protected static readonly ConstructorInfo cppip_fromnative = typeof (CppInstancePtr).GetConstructor (new Type [] { typeof (IntPtr) });
protected static readonly ConstructorInfo cppip_fromsize = typeof (CppInstancePtr).GetConstructor (new Type [] { typeof (int) });
protected 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");
protected static readonly ConstructorInfo notimplementedexception = typeof (NotImplementedException).GetConstructor (new Type [] { typeof (string) });
protected static readonly MethodInfo type_gettypefromhandle = typeof (Type).GetMethod ("GetTypeFromHandle");
protected static readonly MethodInfo marshal_offsetof = typeof (Marshal).GetMethod ("OffsetOf");
protected static readonly MethodInfo marshal_structuretoptr = typeof (Marshal).GetMethod ("StructureToPtr");
protected static readonly ConstructorInfo dummytypeinfo_ctor = typeof (DummyCppTypeInfo).GetConstructor (Type.EmptyTypes);
protected static readonly MethodInfo dummytypeinfo_getbase = typeof (DummyCppTypeInfo).GetProperty ("BaseTypeInfo").GetGetMethod ();
// These methods might be more commonly overridden for a given C++ ABI:
@ -86,13 +95,14 @@ namespace Mono.VisualC.Interop.ABI { @@ -86,13 +95,14 @@ namespace Mono.VisualC.Interop.ABI {
private struct EmptyNativeLayout { }
public Iface ImplementClass<Iface> (Type wrapperType, CppLibrary lib, string className)
where Iface : ICppClass
{
return this.ImplementClass<Iface,EmptyNativeLayout> (wrapperType, lib, className);
}
public virtual Iface ImplementClass<Iface, NLayout> (Type wrapperType, CppLibrary lib, string className)
where NLayout : struct
//where Iface : ICppClassInstantiatable or ICppClassOverridable
where Iface : ICppClass
{
this.impl_module = CppLibrary.interopModule;
this.library = lib;
@ -105,7 +115,10 @@ namespace Mono.VisualC.Interop.ABI { @@ -105,7 +115,10 @@ namespace Mono.VisualC.Interop.ABI {
var properties = GetProperties ();
var methods = GetMethods ().Select (m => GetPInvokeSignature (m));
var typeInfo = MakeTypeInfo (methods);
if (wrapperType != null)
wrapper_to_typeinfo.Add (wrapperType, typeInfo);
// Implement all methods
int vtableIndex = 0;
@ -555,15 +568,8 @@ namespace Mono.VisualC.Interop.ABI { @@ -555,15 +568,8 @@ namespace Mono.VisualC.Interop.ABI {
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;
var typeInfo = GetTypeInfo (t);
return typeInfo != null? typeInfo.NativeLayout : layout_type;
} else { // by ref
@ -645,6 +651,9 @@ namespace Mono.VisualC.Interop.ABI { @@ -645,6 +651,9 @@ namespace Mono.VisualC.Interop.ABI {
// The value it is marshaling will be on the stack.
protected virtual void EmitInboundMarshal (ILGenerator il, Type nativeType, Type targetType)
{
if (nativeType == typeof (void))
return; // <- yes, this is necessary
var next = il.DefineLabel ();
// marshal IntPtr -> ICppObject
@ -690,6 +699,46 @@ namespace Mono.VisualC.Interop.ABI { @@ -690,6 +699,46 @@ namespace Mono.VisualC.Interop.ABI {
il.MarkLabel (next);
}
// Gets a typeinfo for another ICppObject.
// Might return null for the type we're currently emitting.
protected virtual CppTypeInfo GetTypeInfo (Type otherWrapperType)
{
CppTypeInfo info;
if (wrapper_to_typeinfo.TryGetValue (otherWrapperType, out info))
return info;
if (otherWrapperType == wrapper_type)
return null;
// pass a "dummy" type info to subclass ctor to trigger the creation of the real one
try {
Activator.CreateInstance (otherWrapperType, (CppTypeInfo)(new DummyCppTypeInfo ()));
} catch (MissingMethodException mme) {
throw new InvalidProgramException (string.Format ("Type `{0}' implements ICppObject but does not contain a public constructor that takes CppTypeInfo", otherWrapperType));
}
return wrapper_to_typeinfo [otherWrapperType];
}
// Does the above passthru at runtime.
// This is perhaps a kludgy/roundabout way for pulling the type info for another
// ICppObject at runtime, but I think this keeps the wrappers clean.
protected virtual void EmitGetTypeInfo (ILGenerator il, Type targetType)
{
// check for a subclass constructor (i.e. a public ctor in the wrapper that takes CppTypeInfo)
var ctor = targetType.GetConstructor (BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.Instance, null, new Type [] { typeof (CppTypeInfo) }, null);
if (ctor == null)
throw new InvalidProgramException (string.Format ("Type `{0}' implements ICppObject but does not contain a public constructor that takes CppTypeInfo", targetType));
il.Emit (OpCodes.Newobj, dummytypeinfo_ctor);
il.Emit (OpCodes.Dup);
il.Emit (OpCodes.Newobj, ctor);
il.Emit (OpCodes.Pop);
il.Emit (OpCodes.Call, dummytypeinfo_getbase);
}
// Expects CppInstancePtr on stack. No null check performed
protected virtual void EmitCreateCppObjectFromNative (ILGenerator il, Type targetType)
{

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

@ -39,8 +39,18 @@ using Mono.VisualC.Interop.Util; @@ -39,8 +39,18 @@ using Mono.VisualC.Interop.Util;
namespace Mono.VisualC.Interop.ABI {
public class ItaniumAbi : CppAbi {
public ItaniumAbi ()
public static readonly ItaniumAbi Instance = new ItaniumAbi ();
private bool? hasNonDefaultCopyCtorOrDtor;
private ItaniumAbi ()
{
}
public override Iface ImplementClass<Iface, NLayout> (Type wrapperType, CppLibrary lib, string className)
{
hasNonDefaultCopyCtorOrDtor = null;
return base.ImplementClass<Iface, NLayout> (wrapperType, lib, className);
}
protected override CppTypeInfo MakeTypeInfo (IEnumerable<PInvokeSignature> methods)
@ -178,6 +188,57 @@ namespace Mono.VisualC.Interop.ABI { @@ -178,6 +188,57 @@ namespace Mono.VisualC.Interop.ABI {
return code.ToString ();
}
// Section 3.1.4:
// Classes with non-default copy ctors/destructors are returned using a hidden
// argument
bool ReturnByHiddenArgument (MethodInfo method)
{
if (!IsByVal (method.ReturnTypeCustomAttributes))
return false;
if (hasNonDefaultCopyCtorOrDtor == null)
hasNonDefaultCopyCtorOrDtor = GetMethods ().Any (m => (IsCopyConstructor (m) || GetMethodType (m) == MethodType.NativeDtor) && !IsArtificial (m));
return hasNonDefaultCopyCtorOrDtor.Value;
}
public override PInvokeSignature GetPInvokeSignature (MethodInfo method)
{
var psig = base.GetPInvokeSignature (method);
if (ReturnByHiddenArgument (method)) {
psig.ParameterTypes.Insert (0, typeof (IntPtr));
psig.ReturnType = typeof (void);
}
return psig;
}
protected override void EmitNativeCall (ILGenerator il, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr)
{
var method = psig.OrigMethod;
LocalBuilder returnValue = null;
var hiddenReturnByValue = ReturnByHiddenArgument (method);
if (hiddenReturnByValue)
{
returnValue = il.DeclareLocal (typeof (CppInstancePtr));
EmitGetTypeInfo (il, method.ReturnType);
il.Emit (OpCodes.Call, typeinfo_nativesize);
il.Emit (OpCodes.Newobj, cppip_fromsize);
il.Emit (OpCodes.Stloc, returnValue);
il.Emit (OpCodes.Ldloca, returnValue);
il.Emit (OpCodes.Call, cppip_native);
}
base.EmitNativeCall (il, nativeMethod, psig, nativePtr);
if (hiddenReturnByValue) {
il.Emit (OpCodes.Ldloc, returnValue);
EmitCreateCppObjectFromNative (il, method.ReturnType);
}
}
}

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

@ -40,7 +40,10 @@ namespace Mono.VisualC.Interop.ABI { @@ -40,7 +40,10 @@ namespace Mono.VisualC.Interop.ABI {
// FIXME: No 64-bit support
public class MsvcAbi : CppAbi {
public MsvcAbi ()
public static readonly MsvcAbi Instance = new MsvcAbi ();
private MsvcAbi ()
{
}

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

@ -77,7 +77,7 @@ namespace Mono.VisualC.Interop { @@ -77,7 +77,7 @@ namespace Mono.VisualC.Interop {
}
public CppLibrary (string name, InlineMethods inlinePolicy)
: this (name, new ItaniumAbi (), inlinePolicy)
: this (name, ItaniumAbi.Instance, inlinePolicy)
{
//FIXME: Ideally we would auto-detect ABI here.
}

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

@ -95,6 +95,10 @@ namespace Mono.VisualC.Interop { @@ -95,6 +95,10 @@ namespace Mono.VisualC.Interop {
lazy_vtable = null;
}
protected CppTypeInfo ()
{
}
public virtual void AddBase (CppTypeInfo baseType)
{
@ -211,5 +215,16 @@ namespace Mono.VisualC.Interop { @@ -211,5 +215,16 @@ namespace Mono.VisualC.Interop {
}
}
// This is used internally by CppAbi:
internal class DummyCppTypeInfo : CppTypeInfo {
public CppTypeInfo BaseTypeInfo { get; set; }
public override void AddBase (CppTypeInfo baseType)
{
BaseTypeInfo = baseType;
}
}
}

Loading…
Cancel
Save