Browse Source

Refactor CppAbi to move fields related to the type being emitted into CppTypeInfo

pull/1/head
Alexander Corrado 14 years ago
parent
commit
abbcad5411
  1. 286
      src/Mono.Cxxi/Abi/CppAbi.cs
  2. 12
      src/Mono.Cxxi/Abi/EmitInfo.cs
  3. 59
      src/Mono.Cxxi/Abi/Impl/ItaniumAbi.cs
  4. 7
      src/Mono.Cxxi/Abi/Impl/ItaniumTypeInfo.cs
  5. 11
      src/Mono.Cxxi/Abi/Impl/MsvcAbi.cs
  6. 6
      src/Mono.Cxxi/Abi/Impl/VirtualOnlyAbi.cs
  7. 8
      src/Mono.Cxxi/CppInstancePtr.cs
  8. 9
      src/Mono.Cxxi/CppLibrary.cs
  9. 57
      src/Mono.Cxxi/CppTypeInfo.cs
  10. 1
      src/Mono.Cxxi/Makefile.am
  11. 1
      src/Mono.Cxxi/Mono.Cxxi.csproj

286
src/Mono.Cxxi/Abi/CppAbi.cs

@ -45,18 +45,6 @@ namespace Mono.Cxxi.Abi {
public abstract partial class CppAbi { public abstract partial class CppAbi {
// (other part of this partial class in Attributes.cs) // (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;
protected Type interface_type, layout_type, wrapper_type;
protected CppLibrary library;
protected string class_name;
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 Dictionary<Type,CppTypeInfo> wrapper_to_typeinfo = new Dictionary<Type, CppTypeInfo> ();
protected MemberFilter vtable_override_filter = VTable.BindToSignatureAndAttribute; protected MemberFilter vtable_override_filter = VTable.BindToSignatureAndAttribute;
@ -80,15 +68,14 @@ namespace Mono.Cxxi.Abi {
protected static readonly MethodInfo type_gettypefromhandle = typeof (Type).GetMethod ("GetTypeFromHandle"); 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_offsetof = typeof (Marshal).GetMethod ("OffsetOf");
protected static readonly MethodInfo marshal_structuretoptr = typeof (Marshal).GetMethod ("StructureToPtr"); 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 marshal_ptrtostructure = typeof (Marshal).GetMethod ("PtrToStructure", BindingFlags.Static | BindingFlags.Public, null, new Type [] { typeof (IntPtr), typeof (Type) }, null);
protected static readonly MethodInfo dummytypeinfo_getbase = typeof (DummyCppTypeInfo).GetProperty ("BaseTypeInfo").GetGetMethod ();
protected static readonly FieldInfo intptr_zero = typeof (IntPtr).GetField ("Zero"); protected static readonly FieldInfo intptr_zero = typeof (IntPtr).GetField ("Zero");
// These methods might be more commonly overridden for a given C++ ABI: // These methods might be more commonly overridden for a given C++ ABI:
public virtual MethodType GetMethodType (MethodInfo imethod) public virtual MethodType GetMethodType (CppTypeInfo typeInfo, MethodInfo imethod)
{ {
if (IsInline (imethod) && library.InlineMethodPolicy == InlineMethods.NotPresent) if (IsInline (imethod) && typeInfo.Library.InlineMethodPolicy == InlineMethods.NotPresent)
return MethodType.NotImplemented; return MethodType.NotImplemented;
else if (imethod.IsDefined (typeof (ConstructorAttribute), false)) else if (imethod.IsDefined (typeof (ConstructorAttribute), false))
return MethodType.NativeCtor; return MethodType.NativeCtor;
@ -103,83 +90,63 @@ namespace Mono.Cxxi.Abi {
// The members below must be implemented for a given C++ ABI: // The members below must be implemented for a given C++ ABI:
public abstract CallingConvention? GetCallingConvention (MethodInfo methodInfo); public abstract CallingConvention? GetCallingConvention (MethodInfo methodInfo);
protected abstract string GetMangledMethodName (MethodInfo methodInfo); protected abstract string GetMangledMethodName (CppTypeInfo typeInfo, MethodInfo methodInfo);
public string GetMangledMethodName (string className, MethodInfo methodInfo)
{
class_name = className;
return GetMangledMethodName (methodInfo);
}
// The ImplementClass overrides are the main entry point to the Abi API: // ---------------------------------
private struct EmptyNativeLayout { } 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) public virtual ICppClass ImplementClass (CppTypeInfo typeInfo)
where NLayout : struct
where Iface : ICppClass
{ {
this.impl_module = CppLibrary.interopModule; if (typeInfo.WrapperType == null || !wrapper_to_typeinfo.ContainsKey (typeInfo.WrapperType)) {
this.library = lib;
this.class_name = className;
this.interface_type = typeof (Iface);
this.layout_type = typeof (NLayout);
this.wrapper_type = wrapperType;
DefineImplType ();
var properties = GetProperties (); if (typeInfo.WrapperType != null)
var methods = GetMethods ().Select (m => GetPInvokeSignature (m)); wrapper_to_typeinfo.Add (typeInfo.WrapperType, typeInfo);
var typeInfo = MakeTypeInfo (methods); DefineImplType (typeInfo);
if (wrapperType != null)
wrapper_to_typeinfo.Add (wrapperType, typeInfo);
// Implement all methods var properties = GetProperties (typeInfo.InterfaceType);
int vtableIndex = 0; var methods = GetMethods (typeInfo.InterfaceType).Select (m => GetPInvokeSignature (typeInfo, m));
foreach (var method in methods)
DefineMethod (method, typeInfo, ref vtableIndex); // Implement all methods
int vtableIndex = 0;
foreach (var method in methods)
DefineMethod (typeInfo, method, ref vtableIndex);
// Implement all properties // Implement all properties
foreach (var property in properties) foreach (var property in properties)
DefineProperty (property); DefineProperty (typeInfo, property);
ctor_il.Emit (OpCodes.Ret); typeInfo.emit_info.ctor_il.Emit (OpCodes.Ret);
return (ICppClass)Activator.CreateInstance (typeInfo.emit_info.type_builder.CreateType (), typeInfo);
}
return (Iface)Activator.CreateInstance (impl_type.CreateType (), typeInfo); throw new InvalidOperationException ("This type has already been implemented");
} }
protected virtual CppTypeInfo MakeTypeInfo (IEnumerable<PInvokeSignature> methods) public virtual CppTypeInfo MakeTypeInfo (CppLibrary lib, string typeName, Type interfaceType, Type layoutType/*?*/, Type/*?*/ wrapperType)
{ {
return new CppTypeInfo (this, methods.Where (m => IsVirtual (m.OrigMethod)), layout_type, wrapper_type); Debug.Assert (lib.Abi == this);
return new CppTypeInfo (lib, typeName, interfaceType, layoutType ?? typeof (EmptyNativeLayout), wrapperType);
} }
protected virtual IEnumerable<PropertyInfo> GetProperties () public virtual IEnumerable<PInvokeSignature> GetVirtualMethodSlots (CppTypeInfo typeInfo, Type interfaceType)
{ {
return ( // get all properties defined on the interface return from m in GetMethods (interfaceType)
from property in interface_type.GetProperties () where IsVirtual (m)
select property select GetPInvokeSignature (typeInfo, m);
).Union ( // ... as well as those defined on inherited interfaces
from iface in interface_type.GetInterfaces ()
from property in iface.GetProperties ()
select property
);
} }
protected virtual IEnumerable<MethodInfo> GetMethods () protected virtual IEnumerable<MethodInfo> GetMethods (Type interfaceType)
{ {
// get all methods defined on inherited interfaces first // get all methods defined on inherited interfaces first
var methods = ( var methods = (
from iface in interface_type.GetInterfaces () from iface in interfaceType.GetInterfaces ()
from method in iface.GetMethods () from method in iface.GetMethods ()
where !method.IsSpecialName where !method.IsSpecialName
select method select method
).Concat ( ).Concat (
from method in interface_type.GetMethods () from method in interfaceType.GetMethods ()
where !method.IsSpecialName where !method.IsSpecialName
orderby method.MetadataToken orderby method.MetadataToken
select method select method
@ -188,32 +155,52 @@ namespace Mono.Cxxi.Abi {
return methods; return methods;
} }
protected virtual void DefineImplType () protected virtual IEnumerable<PropertyInfo> GetProperties (Type interfaceType)
{
return ( // get all properties defined on the interface
from property in interfaceType.GetProperties ()
select property
).Union ( // ... as well as those defined on inherited interfaces
from iface in interfaceType.GetInterfaces ()
from property in iface.GetProperties ()
select property
);
}
protected virtual void DefineImplType (CppTypeInfo typeInfo)
{ {
string implTypeName = interface_type.Name + "_" + layout_type.Name + "_" + this.GetType ().Name + "_Impl"; string implTypeName = typeInfo.InterfaceType.Name + "_";
impl_type = impl_module.DefineType (implTypeName, TypeAttributes.Class | TypeAttributes.Sealed); if (typeInfo.NativeLayout != null)
impl_type.AddInterfaceImplementation (interface_type); implTypeName += typeInfo.NativeLayout.Name + "_";
implTypeName += this.GetType ().Name + "_Impl";
typeinfo_field = impl_type.DefineField ("_typeInfo", typeof (CppTypeInfo), FieldAttributes.InitOnly | FieldAttributes.Private); var impl_type = CppLibrary.interopModule.DefineType (implTypeName, TypeAttributes.Class | TypeAttributes.Sealed);
impl_type.AddInterfaceImplementation (typeInfo.InterfaceType);
var typeinfo_field = impl_type.DefineField ("_typeInfo", typeof (CppTypeInfo), FieldAttributes.InitOnly | FieldAttributes.Private);
ConstructorBuilder ctor = impl_type.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard, ConstructorBuilder ctor = impl_type.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard,
new Type[] { typeof (CppTypeInfo) }); new Type[] { typeof (CppTypeInfo) });
ctor_il = ctor.GetILGenerator (); var ctor_il = ctor.GetILGenerator ();
// this._typeInfo = (CppTypeInfo passed to constructor) // this._typeInfo = (CppTypeInfo passed to constructor)
ctor_il.Emit (OpCodes.Ldarg_0); ctor_il.Emit (OpCodes.Ldarg_0);
ctor_il.Emit (OpCodes.Ldarg_1); ctor_il.Emit (OpCodes.Ldarg_1);
ctor_il.Emit (OpCodes.Stfld, typeinfo_field); ctor_il.Emit (OpCodes.Stfld, typeinfo_field);
typeInfo.emit_info.ctor_il = ctor_il;
typeInfo.emit_info.typeinfo_field = typeinfo_field;
typeInfo.emit_info.type_builder = impl_type;
} }
protected virtual MethodBuilder DefineMethod (PInvokeSignature psig, CppTypeInfo typeInfo, ref int vtableIndex) protected virtual MethodBuilder DefineMethod (CppTypeInfo typeInfo, PInvokeSignature psig, ref int vtableIndex)
{ {
var interfaceMethod = psig.OrigMethod; var interfaceMethod = psig.OrigMethod;
// 1. Generate managed trampoline to call native method // 1. Generate managed trampoline to call native method
MethodBuilder trampoline = GetMethodBuilder (interfaceMethod); var trampoline = GetMethodBuilder (typeInfo, interfaceMethod);
ILGenerator il = trampoline.GetILGenerator (); var il = typeInfo.emit_info.current_il = trampoline.GetILGenerator ();
switch (psig.Type) { switch (psig.Type) {
@ -231,12 +218,12 @@ namespace Mono.Cxxi.Abi {
return trampoline; return trampoline;
case MethodType.ManagedAlloc: case MethodType.ManagedAlloc:
EmitManagedAlloc (il, interfaceMethod); EmitManagedAlloc (typeInfo, interfaceMethod);
il.Emit (OpCodes.Ret); il.Emit (OpCodes.Ret);
return trampoline; return trampoline;
} }
bool isStatic = IsStatic (interfaceMethod); var isStatic = IsStatic (interfaceMethod);
LocalBuilder cppInstancePtr = null; LocalBuilder cppInstancePtr = null;
LocalBuilder nativePtr = null; LocalBuilder nativePtr = null;
@ -256,23 +243,23 @@ namespace Mono.Cxxi.Abi {
MethodInfo nativeMethod; MethodInfo nativeMethod;
if (IsVirtual (interfaceMethod) && psig.Type != MethodType.NativeDtor) { if (IsVirtual (interfaceMethod) && psig.Type != MethodType.NativeDtor) {
nativeMethod = EmitPrepareVirtualCall (il, typeInfo, cppInstancePtr, vtableIndex++); nativeMethod = EmitPrepareVirtualCall (typeInfo, cppInstancePtr, vtableIndex++);
} else { } else {
if (IsVirtual (interfaceMethod)) if (IsVirtual (interfaceMethod))
vtableIndex++; vtableIndex++;
nativeMethod = GetPInvokeForMethod (psig); nativeMethod = GetPInvokeForMethod (typeInfo, psig);
} }
switch (psig.Type) { switch (psig.Type) {
case MethodType.NativeCtor: case MethodType.NativeCtor:
EmitConstruct (il, nativeMethod, psig, cppInstancePtr, nativePtr); EmitConstruct (typeInfo, nativeMethod, psig, cppInstancePtr, nativePtr);
break; break;
case MethodType.NativeDtor: case MethodType.NativeDtor:
EmitDestruct (il, nativeMethod, psig, cppInstancePtr, nativePtr); EmitDestruct (typeInfo, nativeMethod, psig, cppInstancePtr, nativePtr);
break; break;
default: default:
EmitNativeCall (il, nativeMethod, psig, nativePtr); EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr);
break; break;
} }
@ -280,7 +267,7 @@ namespace Mono.Cxxi.Abi {
return trampoline; return trampoline;
} }
protected virtual PropertyBuilder DefineProperty (PropertyInfo property) protected virtual PropertyBuilder DefineProperty (CppTypeInfo typeInfo, PropertyInfo property)
{ {
if (property.CanWrite) if (property.CanWrite)
throw new InvalidProgramException ("Properties in C++ interface must be read-only."); throw new InvalidProgramException ("Properties in C++ interface must be read-only.");
@ -290,17 +277,17 @@ namespace Mono.Cxxi.Abi {
var propName = property.Name; var propName = property.Name;
var retType = imethod.ReturnType; var retType = imethod.ReturnType;
var fieldProp = impl_type.DefineProperty (propName, PropertyAttributes.None, retType, Type.EmptyTypes); var fieldProp = typeInfo.emit_info.type_builder.DefineProperty (propName, PropertyAttributes.None, retType, Type.EmptyTypes);
var methodAttr = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig; var methodAttr = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
var fieldGetter = impl_type.DefineMethod (methodName, methodAttr, retType, Type.EmptyTypes); var fieldGetter = typeInfo.emit_info.type_builder.DefineMethod (methodName, methodAttr, retType, Type.EmptyTypes);
var il = fieldGetter.GetILGenerator (); var il = fieldGetter.GetILGenerator ();
// C++ interface properties are either to return the CppTypeInfo 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<>))) { if (retType.IsGenericType && retType.GetGenericTypeDefinition ().Equals (typeof (CppField<>))) {
// define a new field for the property // define a new field for the property
var fieldData = impl_type.DefineField ("__" + propName + "_Data", retType, FieldAttributes.InitOnly | FieldAttributes.Private); var fieldData = typeInfo.emit_info.type_builder.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 // 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) // all base classes have been added (by ctor)
@ -320,13 +307,13 @@ namespace Mono.Cxxi.Abi {
// first, get field offset // first, get field offset
// = ((int)Marshal.OffsetOf (layout_type, propName)) + FieldOffsetPadding; // = ((int)Marshal.OffsetOf (layout_type, propName)) + FieldOffsetPadding;
il.Emit(OpCodes.Ldtoken, layout_type); il.Emit(OpCodes.Ldtoken, typeInfo.NativeLayout);
il.Emit(OpCodes.Call, type_gettypefromhandle); il.Emit(OpCodes.Call, type_gettypefromhandle);
il.Emit(OpCodes.Ldstr, propName); il.Emit(OpCodes.Ldstr, propName);
il.Emit(OpCodes.Call, marshal_offsetof); il.Emit(OpCodes.Call, marshal_offsetof);
il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeinfo_field); il.Emit (OpCodes.Ldfld, typeInfo.emit_info.typeinfo_field);
il.Emit (OpCodes.Callvirt, typeinfo_fieldoffset); il.Emit (OpCodes.Callvirt, typeinfo_fieldoffset);
il.Emit (OpCodes.Add); il.Emit (OpCodes.Add);
@ -342,7 +329,7 @@ namespace Mono.Cxxi.Abi {
} else if (retType.Equals (typeof (CppTypeInfo))) { } else if (retType.Equals (typeof (CppTypeInfo))) {
il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeinfo_field); il.Emit (OpCodes.Ldfld, typeInfo.emit_info.typeinfo_field);
il.Emit (OpCodes.Ret); il.Emit (OpCodes.Ret);
} else } else
throw new InvalidProgramException ("Properties in C++ interface can only be of type CppField."); throw new InvalidProgramException ("Properties in C++ interface can only be of type CppField.");
@ -381,7 +368,7 @@ namespace Mono.Cxxi.Abi {
nativeArgs, typeof (CppInstancePtr).Module, true); nativeArgs, typeof (CppInstancePtr).Module, true);
ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, trampolineIn, true); ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, trampolineIn, true);
ILGenerator il = trampolineIn.GetILGenerator (); var il = trampolineIn.GetILGenerator ();
// for static (target) methods: // for static (target) methods:
OpCode callInstruction = OpCodes.Call; OpCode callInstruction = OpCodes.Call;
@ -430,11 +417,11 @@ namespace Mono.Cxxi.Abi {
/** /**
* Defines a new MethodBuilder with the same signature as the passed MethodInfo * Defines a new MethodBuilder with the same signature as the passed MethodInfo
*/ */
protected virtual MethodBuilder GetMethodBuilder (MethodInfo interfaceMethod) protected virtual MethodBuilder GetMethodBuilder (CppTypeInfo typeInfo, MethodInfo interfaceMethod)
{ {
Type [] parameterTypes = ReflectionHelper.GetMethodParameterTypes (interfaceMethod); var parameterTypes = ReflectionHelper.GetMethodParameterTypes (interfaceMethod);
MethodBuilder methodBuilder = impl_type.DefineMethod (interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual, var methodBuilder = typeInfo.emit_info.type_builder.DefineMethod (interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual,
interfaceMethod.ReturnType, parameterTypes); interfaceMethod.ReturnType, parameterTypes);
ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, methodBuilder, false); ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, methodBuilder, false);
return methodBuilder; return methodBuilder;
} }
@ -442,22 +429,22 @@ namespace Mono.Cxxi.Abi {
/** /**
* Defines a new MethodBuilder that calls the specified C++ (non-virtual) method using its mangled name * Defines a new MethodBuilder that calls the specified C++ (non-virtual) method using its mangled name
*/ */
protected virtual MethodBuilder GetPInvokeForMethod (PInvokeSignature sig) protected virtual MethodBuilder GetPInvokeForMethod (CppTypeInfo typeInfo, PInvokeSignature sig)
{ {
string entryPoint = sig.Name; var entryPoint = sig.Name;
if (entryPoint == null) if (entryPoint == null)
throw new NotSupportedException ("Could not mangle method name."); throw new NotSupportedException ("Could not mangle method name.");
string lib; string lib;
if (IsInline (sig.OrigMethod) && library.InlineMethodPolicy == InlineMethods.SurrogateLib) if (IsInline (sig.OrigMethod) && typeInfo.Library.InlineMethodPolicy == InlineMethods.SurrogateLib)
lib = library.Name + "-inline"; lib = typeInfo.Library.Name + "-inline";
else else
lib = library.Name; lib = typeInfo.Library.Name;
MethodBuilder builder = impl_type.DefinePInvokeMethod (entryPoint, lib, entryPoint, var builder = typeInfo.emit_info.type_builder.DefinePInvokeMethod (entryPoint, lib, entryPoint,
MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl, MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl,
CallingConventions.Standard, sig.ReturnType, sig.ParameterTypes.ToArray (), CallingConventions.Standard, sig.ReturnType, sig.ParameterTypes.ToArray (),
sig.CallingConvention.Value, CharSet.Ansi); sig.CallingConvention.Value, CharSet.Ansi);
builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig); builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig);
ReflectionHelper.ApplyMethodParameterAttributes (sig.OrigMethod, builder, true); ReflectionHelper.ApplyMethodParameterAttributes (sig.OrigMethod, builder, true);
return builder; return builder;
@ -467,15 +454,15 @@ namespace Mono.Cxxi.Abi {
* Emits the IL to load the correct delegate instance and/or retrieve the MethodInfo from the VTable * Emits the IL to load the correct delegate instance and/or retrieve the MethodInfo from the VTable
* for a C++ virtual call. * for a C++ virtual call.
*/ */
protected virtual MethodInfo EmitPrepareVirtualCall (ILGenerator il, CppTypeInfo typeInfo, protected virtual MethodInfo EmitPrepareVirtualCall (CppTypeInfo typeInfo, LocalBuilder cppInstancePtr, int vtableIndex)
LocalBuilder cppInstancePtr, int vtableIndex)
{ {
Type vtableDelegateType = typeInfo.VTableDelegateTypes [vtableIndex]; var il = typeInfo.emit_info.current_il;
MethodInfo getDelegate = typeinfo_adjvcall.MakeGenericMethod (vtableDelegateType); var vtableDelegateType = typeInfo.VTableDelegateTypes [vtableIndex];
var getDelegate = typeinfo_adjvcall.MakeGenericMethod (vtableDelegateType);
// this._typeInfo.GetAdjustedVirtualCall<T> (cppInstancePtr, vtableIndex); // this._typeInfo.GetAdjustedVirtualCall<T> (cppInstancePtr, vtableIndex);
il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeinfo_field); il.Emit (OpCodes.Ldfld, typeInfo.emit_info.typeinfo_field);
il.Emit (OpCodes.Ldloc_S, cppInstancePtr); il.Emit (OpCodes.Ldloc_S, cppInstancePtr);
il.Emit (OpCodes.Ldc_I4, vtableIndex); il.Emit (OpCodes.Ldc_I4, vtableIndex);
il.Emit (OpCodes.Callvirt, getDelegate); il.Emit (OpCodes.Callvirt, getDelegate);
@ -487,13 +474,15 @@ namespace Mono.Cxxi.Abi {
* Emits IL to allocate the memory for a new instance of the C++ class. * Emits IL to allocate the memory for a new instance of the C++ class.
* To complete method, emit OpCodes.Ret. * To complete method, emit OpCodes.Ret.
*/ */
protected virtual void EmitManagedAlloc (ILGenerator il, MethodInfo interfaceMethod) protected virtual void EmitManagedAlloc (CppTypeInfo typeInfo, MethodInfo interfaceMethod)
{ {
var il = typeInfo.emit_info.current_il;
// this._typeInfo.NativeSize // this._typeInfo.NativeSize
il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeinfo_field); il.Emit (OpCodes.Ldfld, typeInfo.emit_info.typeinfo_field);
if (wrapper_type != null && interfaceMethod.GetParameters ().Any ()) { if (typeInfo.WrapperType != null && interfaceMethod.GetParameters ().Any ()) {
// load managed wrapper // load managed wrapper
il.Emit (OpCodes.Ldarg_1); il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Newobj, cppip_fromtype_managed); il.Emit (OpCodes.Newobj, cppip_fromtype_managed);
@ -503,14 +492,16 @@ namespace Mono.Cxxi.Abi {
} }
} }
protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod, PInvokeSignature psig, protected virtual void EmitConstruct (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig,
LocalBuilder cppInstancePtr, LocalBuilder nativePtr) LocalBuilder cppInstancePtr, LocalBuilder nativePtr)
{ {
Debug.Assert (psig.Type == MethodType.NativeCtor); Debug.Assert (psig.Type == MethodType.NativeCtor);
EmitNativeCall (il, nativeMethod, psig, nativePtr); var il = typeInfo.emit_info.current_il;
EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr);
if (cppInstancePtr != null && psig.OrigMethod.ReturnType == typeof (CppInstancePtr)) { if (cppInstancePtr != null && psig.OrigMethod.ReturnType == typeof (CppInstancePtr)) {
EmitInitVTable (il, cppInstancePtr); EmitInitVTable (typeInfo, cppInstancePtr);
il.Emit (OpCodes.Ldloc_S, cppInstancePtr); il.Emit (OpCodes.Ldloc_S, cppInstancePtr);
} else if (psig.OrigMethod.DeclaringType.GetInterfaces ().Any (i => i.IsGenericType && i.GetGenericTypeDefinition () == typeof (ICppClassOverridable<>))) { } else if (psig.OrigMethod.DeclaringType.GetInterfaces ().Any (i => i.IsGenericType && i.GetGenericTypeDefinition () == typeof (ICppClassOverridable<>))) {
@ -518,10 +509,11 @@ namespace Mono.Cxxi.Abi {
} }
} }
protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod, PInvokeSignature psig, protected virtual void EmitDestruct (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig,
LocalBuilder cppInstancePtr, LocalBuilder nativePtr) LocalBuilder cppInstancePtr, LocalBuilder nativePtr)
{ {
Debug.Assert (psig.Type == MethodType.NativeDtor); Debug.Assert (psig.Type == MethodType.NativeDtor);
var il = typeInfo.emit_info.current_il;
// we don't do anything if the object wasn't managed alloc // we don't do anything if the object wasn't managed alloc
if (cppInstancePtr == null) if (cppInstancePtr == null)
@ -529,8 +521,8 @@ namespace Mono.Cxxi.Abi {
EmitCheckManagedAlloc (il, cppInstancePtr); EmitCheckManagedAlloc (il, cppInstancePtr);
EmitResetVTable (il, cppInstancePtr); EmitResetVTable (typeInfo, cppInstancePtr);
EmitNativeCall (il, nativeMethod, psig, nativePtr); EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr);
} }
/** /**
@ -538,8 +530,9 @@ namespace Mono.Cxxi.Abi {
* GetPInvokeForMethod or the MethodInfo of a vtable method. * GetPInvokeForMethod or the MethodInfo of a vtable method.
* To complete method, emit OpCodes.Ret. * To complete method, emit OpCodes.Ret.
*/ */
protected virtual void EmitNativeCall (ILGenerator il, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr) protected virtual void EmitNativeCall (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr)
{ {
var il = typeInfo.emit_info.current_il;
var interfaceMethod = psig.OrigMethod; var interfaceMethod = psig.OrigMethod;
var interfaceArgs = interfaceMethod.GetParameters (); var interfaceArgs = interfaceMethod.GetParameters ();
@ -564,9 +557,9 @@ namespace Mono.Cxxi.Abi {
} }
public virtual PInvokeSignature GetPInvokeSignature (MethodInfo method) public virtual PInvokeSignature GetPInvokeSignature (CppTypeInfo typeInfo, MethodInfo method)
{ {
var methodType = GetMethodType (method); var methodType = GetMethodType (typeInfo, method);
var parameters = method.GetParameters (); var parameters = method.GetParameters ();
var pinvokeTypes = new List<Type> (parameters.Length); var pinvokeTypes = new List<Type> (parameters.Length);
@ -576,7 +569,7 @@ namespace Mono.Cxxi.Abi {
return new PInvokeSignature { return new PInvokeSignature {
OrigMethod = method, OrigMethod = method,
Name = GetMangledMethodName (method), Name = GetMangledMethodName (typeInfo, method),
Type = methodType, Type = methodType,
CallingConvention = GetCallingConvention (method), CallingConvention = GetCallingConvention (method),
ParameterTypes = pinvokeTypes, ParameterTypes = pinvokeTypes,
@ -594,8 +587,7 @@ namespace Mono.Cxxi.Abi {
if (IsByVal (icap)) { if (IsByVal (icap)) {
var typeInfo = GetTypeInfo (t); return GetTypeInfo (t).NativeLayout;
return typeInfo != null? typeInfo.NativeLayout : layout_type;
} else { // by ref } else { // by ref
@ -731,16 +723,12 @@ namespace Mono.Cxxi.Abi {
} }
// Gets a typeinfo for another ICppObject. // Gets a typeinfo for another ICppObject.
// Might return null for the type we're currently emitting.
protected virtual CppTypeInfo GetTypeInfo (Type otherWrapperType) protected virtual CppTypeInfo GetTypeInfo (Type otherWrapperType)
{ {
CppTypeInfo info; CppTypeInfo info;
if (wrapper_to_typeinfo.TryGetValue (otherWrapperType, out info)) if (wrapper_to_typeinfo.TryGetValue (otherWrapperType, out info))
return 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 // pass a "dummy" type info to subclass ctor to trigger the creation of the real one
try { try {
Activator.CreateInstance (otherWrapperType, (CppTypeInfo)(new DummyCppTypeInfo ())); Activator.CreateInstance (otherWrapperType, (CppTypeInfo)(new DummyCppTypeInfo ()));
@ -804,11 +792,13 @@ namespace Mono.Cxxi.Abi {
/** /**
* Emits IL to load the VTable object onto the stack. * Emits IL to load the VTable object onto the stack.
*/ */
protected virtual void EmitLoadVTable (ILGenerator il) protected virtual void EmitLoadVTable (CppTypeInfo typeInfo)
{ {
var il = typeInfo.emit_info.current_il;
// this._typeInfo.VTable // this._typeInfo.VTable
il.Emit (OpCodes.Ldarg_0); il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeinfo_field); il.Emit (OpCodes.Ldfld, typeInfo.emit_info.typeinfo_field);
il.Emit (OpCodes.Callvirt, typeinfo_vtable); il.Emit (OpCodes.Callvirt, typeinfo_vtable);
} }
@ -816,20 +806,24 @@ namespace Mono.Cxxi.Abi {
* Emits IL to set the vtable pointer of the instance (if class has a 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. * This should usually happen in the managed wrapper of the C++ instance constructor.
*/ */
protected virtual void EmitInitVTable (ILGenerator il, LocalBuilder cppip) protected virtual void EmitInitVTable (CppTypeInfo typeInfo, LocalBuilder cppip)
{ {
var il = typeInfo.emit_info.current_il;
// this._typeInfo.VTable.InitInstance (cppInstancePtr); // this._typeInfo.VTable.InitInstance (cppInstancePtr);
EmitLoadVTable (il); EmitLoadVTable (typeInfo);
il.Emit (OpCodes.Ldloca_S, cppip); il.Emit (OpCodes.Ldloca_S, cppip);
EmitCallVTableMethod (il, vtable_initinstance, 2, false); EmitCallVTableMethod (typeInfo, vtable_initinstance, 2, false);
} }
protected virtual void EmitResetVTable (ILGenerator il, LocalBuilder cppip) protected virtual void EmitResetVTable (CppTypeInfo typeInfo, LocalBuilder cppip)
{ {
var il = typeInfo.emit_info.current_il;
// this._typeInfo.VTable.ResetInstance (cppInstancePtr); // this._typeInfo.VTable.ResetInstance (cppInstancePtr);
EmitLoadVTable (il); EmitLoadVTable (typeInfo);
il.Emit (OpCodes.Ldloc_S, cppip); il.Emit (OpCodes.Ldloc_S, cppip);
EmitCallVTableMethod (il, vtable_resetinstance, 2, false); EmitCallVTableMethod (typeInfo, vtable_resetinstance, 2, false);
} }
/** /**
@ -840,14 +834,15 @@ namespace Mono.Cxxi.Abi {
* want to call and pass the stackHeight for the call. If no vtable exists, this method * 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. * will emit code to pop the arguments off the stack.
*/ */
protected virtual void EmitCallVTableMethod (ILGenerator il, MethodInfo method, int stackHeight, protected virtual void EmitCallVTableMethod (CppTypeInfo typeInfo, MethodInfo method, int stackHeight, bool throwOnNoVTable)
bool throwOnNoVTable)
{ {
var il = typeInfo.emit_info.current_il;
// prepare a jump; do not call vtable method if no vtable // prepare a jump; do not call vtable method if no vtable
Label noVirt = il.DefineLabel (); var noVirt = il.DefineLabel ();
Label dontPushOrThrow = il.DefineLabel (); var dontPushOrThrow = il.DefineLabel ();
EmitLoadVTable (il); EmitLoadVTable (typeInfo);
il.Emit (OpCodes.Brfalse_S, noVirt); // if (vtableInfo == null) goto noVirt il.Emit (OpCodes.Brfalse_S, noVirt); // if (vtableInfo == null) goto noVirt
il.Emit (OpCodes.Callvirt, method); // call method il.Emit (OpCodes.Callvirt, method); // call method
@ -903,7 +898,8 @@ namespace Mono.Cxxi.Abi {
{ {
// make sure we were allocated by managed code // make sure we were allocated by managed code
// if not, return // if not, return
Label managedAlloc = il.DefineLabel (); var managedAlloc = il.DefineLabel ();
il.Emit (OpCodes.Ldloca_S, cppip); il.Emit (OpCodes.Ldloca_S, cppip);
il.Emit (OpCodes.Call, cppip_managedalloc); il.Emit (OpCodes.Call, cppip_managedalloc);
il.Emit (OpCodes.Brtrue_S, managedAlloc); il.Emit (OpCodes.Brtrue_S, managedAlloc);
@ -917,9 +913,11 @@ namespace Mono.Cxxi.Abi {
*/ */
protected virtual void EmitCheckDisposed (ILGenerator il, LocalBuilder native, MethodType methodType) protected virtual void EmitCheckDisposed (ILGenerator il, LocalBuilder native, MethodType methodType)
{ {
Label validRef = il.DefineLabel (); var validRef = il.DefineLabel ();
il.Emit (OpCodes.Ldloc_S, native); il.Emit (OpCodes.Ldloc_S, native);
il.Emit (OpCodes.Brtrue_S, validRef); il.Emit (OpCodes.Brtrue_S, validRef);
if (methodType == MethodType.NativeDtor) { if (methodType == MethodType.NativeDtor) {
il.Emit (OpCodes.Ret); il.Emit (OpCodes.Ret);
il.MarkLabel (validRef); il.MarkLabel (validRef);

12
src/Mono.Cxxi/Abi/EmitInfo.cs

@ -0,0 +1,12 @@
using System;
using System.Reflection.Emit;
namespace Mono.Cxxi.Abi {
public class EmitInfo {
public TypeBuilder type_builder;
public FieldBuilder typeinfo_field;
public ILGenerator ctor_il, current_il;
}
}

59
src/Mono.Cxxi/Abi/Impl/ItaniumAbi.cs

@ -41,26 +41,18 @@ namespace Mono.Cxxi.Abi {
public static readonly ItaniumAbi Instance = new ItaniumAbi (); public static readonly ItaniumAbi Instance = new ItaniumAbi ();
private bool? hasNonDefaultCopyCtorOrDtor;
private ItaniumAbi () private ItaniumAbi ()
{ {
} }
public override Iface ImplementClass<Iface, NLayout> (Type wrapperType, CppLibrary lib, string className) public override CppTypeInfo MakeTypeInfo (CppLibrary lib, string typeName, Type interfaceType, Type layoutType/*?*/, Type/*?*/ wrapperType)
{
hasNonDefaultCopyCtorOrDtor = null;
return base.ImplementClass<Iface, NLayout> (wrapperType, lib, className);
}
protected override CppTypeInfo MakeTypeInfo (IEnumerable<PInvokeSignature> methods)
{ {
return new ItaniumTypeInfo (this, GetVirtualMethodSlots (methods), layout_type, wrapper_type); return new ItaniumTypeInfo (lib, typeName, interfaceType, layoutType, wrapperType);
} }
private IEnumerable<PInvokeSignature> GetVirtualMethodSlots (IEnumerable<PInvokeSignature> methods) public override IEnumerable<PInvokeSignature> GetVirtualMethodSlots (CppTypeInfo typeInfo, Type interfaceType)
{ {
foreach (var method in methods) { foreach (var method in base.GetVirtualMethodSlots (typeInfo, interfaceType)) {
if (!IsVirtual (method.OrigMethod)) if (!IsVirtual (method.OrigMethod))
continue; continue;
@ -72,9 +64,9 @@ namespace Mono.Cxxi.Abi {
} }
} }
protected override MethodBuilder DefineMethod (PInvokeSignature sig, CppTypeInfo typeInfo, ref int vtableIndex) protected override MethodBuilder DefineMethod (CppTypeInfo typeInfo, PInvokeSignature sig, ref int vtableIndex)
{ {
var builder = base.DefineMethod (sig, typeInfo, ref vtableIndex); var builder = base.DefineMethod (typeInfo, sig, ref vtableIndex);
// increment vtableIndex an extra time for that extra vdtor slot (already incremented once in base) // increment vtableIndex an extra time for that extra vdtor slot (already incremented once in base)
if (IsVirtual (sig.OrigMethod) && sig.Type == MethodType.NativeDtor) if (IsVirtual (sig.OrigMethod) && sig.Type == MethodType.NativeDtor)
@ -88,12 +80,13 @@ namespace Mono.Cxxi.Abi {
return CallingConvention.Cdecl; return CallingConvention.Cdecl;
} }
protected override string GetMangledMethodName (MethodInfo methodInfo) protected override string GetMangledMethodName (CppTypeInfo typeInfo, MethodInfo methodInfo)
{ {
var compressMap = new Dictionary<string, int> (); var compressMap = new Dictionary<string, int> ();
var methodName = methodInfo.Name;
var className = typeInfo.TypeName;
string methodName = methodInfo.Name; MethodType methodType = GetMethodType (typeInfo, methodInfo);
MethodType methodType = GetMethodType (methodInfo);
ParameterInfo [] parameters = methodInfo.GetParameters (); ParameterInfo [] parameters = methodInfo.GetParameters ();
StringBuilder nm = new StringBuilder ("_ZN", 30); StringBuilder nm = new StringBuilder ("_ZN", 30);
@ -101,8 +94,8 @@ namespace Mono.Cxxi.Abi {
if (IsConst (methodInfo)) if (IsConst (methodInfo))
nm.Append ('K'); nm.Append ('K');
nm.Append (class_name.Length).Append (class_name); nm.Append (className.Length).Append (className);
compressMap [class_name] = compressMap.Count; compressMap [className] = compressMap.Count;
// FIXME: Implement compression completely // FIXME: Implement compression completely
@ -191,22 +184,27 @@ namespace Mono.Cxxi.Abi {
// Section 3.1.4: // Section 3.1.4:
// Classes with non-default copy ctors/destructors are returned using a hidden // Classes with non-default copy ctors/destructors are returned using a hidden
// argument // argument
bool ReturnByHiddenArgument (MethodInfo method) bool ReturnByHiddenArgument (CppTypeInfo typeInfo, MethodInfo method)
{ {
var iti = (ItaniumTypeInfo)typeInfo;
if (!IsByVal (method.ReturnTypeCustomAttributes)) if (!IsByVal (method.ReturnTypeCustomAttributes))
return false; return false;
if (hasNonDefaultCopyCtorOrDtor == null) if (iti.has_non_default_copy_ctor_or_dtor == null)
hasNonDefaultCopyCtorOrDtor = GetMethods ().Any (m => (IsCopyConstructor (m) || GetMethodType (m) == MethodType.NativeDtor) && !IsArtificial (m)); iti.has_non_default_copy_ctor_or_dtor = GetMethods (typeInfo.InterfaceType)
.Any (m => (IsCopyConstructor (m) ||
GetMethodType (typeInfo, m) == MethodType.NativeDtor) &&
!IsArtificial (m));
return hasNonDefaultCopyCtorOrDtor.Value; return iti.has_non_default_copy_ctor_or_dtor.Value;
} }
public override PInvokeSignature GetPInvokeSignature (MethodInfo method) public override PInvokeSignature GetPInvokeSignature (CppTypeInfo/*?*/ typeInfo, MethodInfo method)
{ {
var psig = base.GetPInvokeSignature (method); var psig = base.GetPInvokeSignature (typeInfo, method);
if (ReturnByHiddenArgument (method)) { if (ReturnByHiddenArgument (typeInfo, method)) {
psig.ParameterTypes.Insert (0, typeof (IntPtr)); psig.ParameterTypes.Insert (0, typeof (IntPtr));
psig.ReturnType = typeof (void); psig.ReturnType = typeof (void);
} }
@ -214,11 +212,13 @@ namespace Mono.Cxxi.Abi {
return psig; return psig;
} }
protected override void EmitNativeCall (ILGenerator il, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr) protected override void EmitNativeCall (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr)
{ {
var il = typeInfo.emit_info.current_il;
var method = psig.OrigMethod; var method = psig.OrigMethod;
var hiddenReturnByValue = ReturnByHiddenArgument (typeInfo, method);
LocalBuilder returnValue = null; LocalBuilder returnValue = null;
var hiddenReturnByValue = ReturnByHiddenArgument (method);
if (hiddenReturnByValue) if (hiddenReturnByValue)
{ {
@ -226,13 +226,14 @@ namespace Mono.Cxxi.Abi {
EmitGetTypeInfo (il, method.ReturnType); EmitGetTypeInfo (il, method.ReturnType);
il.Emit (OpCodes.Call, typeinfo_nativesize); il.Emit (OpCodes.Call, typeinfo_nativesize);
il.Emit (OpCodes.Newobj, cppip_fromsize); il.Emit (OpCodes.Newobj, cppip_fromsize);
il.Emit (OpCodes.Stloc, returnValue); il.Emit (OpCodes.Stloc, returnValue);
il.Emit (OpCodes.Ldloca, returnValue); il.Emit (OpCodes.Ldloca, returnValue);
il.Emit (OpCodes.Call, cppip_native); il.Emit (OpCodes.Call, cppip_native);
} }
base.EmitNativeCall (il, nativeMethod, psig, nativePtr); base.EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr);
if (hiddenReturnByValue) { if (hiddenReturnByValue) {
EmitCreateCppObjectFromNative (il, method.ReturnType, returnValue); EmitCreateCppObjectFromNative (il, method.ReturnType, returnValue);

7
src/Mono.Cxxi/Abi/Impl/ItaniumTypeInfo.cs

@ -36,8 +36,11 @@ using Mono.Cxxi.Util;
namespace Mono.Cxxi.Abi { namespace Mono.Cxxi.Abi {
public class ItaniumTypeInfo : CppTypeInfo { public class ItaniumTypeInfo : CppTypeInfo {
public ItaniumTypeInfo (ItaniumAbi abi, IEnumerable<PInvokeSignature> virtualMethods, Type nativeLayout, Type wrapperType)
: base (abi, virtualMethods, nativeLayout, wrapperType) protected internal bool? has_non_default_copy_ctor_or_dtor;
public ItaniumTypeInfo (CppLibrary lib, string typeName, Type interfaceType, Type nativeLayout, Type/*?*/ wrapperType)
: base (lib, typeName, interfaceType, nativeLayout, wrapperType)
{ {
} }

11
src/Mono.Cxxi/Abi/Impl/MsvcAbi.cs

@ -47,11 +47,6 @@ namespace Mono.Cxxi.Abi {
{ {
} }
protected override CppTypeInfo MakeTypeInfo (IEnumerable<PInvokeSignature> methods)
{
return new CppTypeInfo (this, methods.Where (m => IsVirtual (m.OrigMethod)), layout_type, wrapper_type);
}
public override CallingConvention? GetCallingConvention (MethodInfo methodInfo) public override CallingConvention? GetCallingConvention (MethodInfo methodInfo)
{ {
// FIXME: Varargs methods ... ? // FIXME: Varargs methods ... ?
@ -62,10 +57,10 @@ namespace Mono.Cxxi.Abi {
return CallingConvention.ThisCall; return CallingConvention.ThisCall;
} }
protected override string GetMangledMethodName (MethodInfo methodInfo) protected override string GetMangledMethodName (CppTypeInfo typeInfo, MethodInfo methodInfo)
{ {
string methodName = methodInfo.Name; string methodName = methodInfo.Name;
MethodType methodType = GetMethodType (methodInfo); MethodType methodType = GetMethodType (typeInfo, methodInfo);
ParameterInfo [] parameters = methodInfo.GetParameters (); ParameterInfo [] parameters = methodInfo.GetParameters ();
StringBuilder nm = new StringBuilder ("?", 30); StringBuilder nm = new StringBuilder ("?", 30);
@ -79,7 +74,7 @@ namespace Mono.Cxxi.Abi {
// FIXME: This has to include not only the name of the immediate containing class, // FIXME: This has to include not only the name of the immediate containing class,
// but also all names of containing classes and namespaces up the hierarchy. // but also all names of containing classes and namespaces up the hierarchy.
nm.Append (class_name).Append ("@@"); nm.Append (typeInfo.TypeName).Append ("@@");
// function modifiers are a matrix of consecutive uppercase letters // function modifiers are a matrix of consecutive uppercase letters
// depending on access type and virtual (far)/static (far)/far modifiers // depending on access type and virtual (far)/static (far)/far modifiers

6
src/Mono.Cxxi/Abi/Impl/VirtualOnlyAbi.cs

@ -41,15 +41,15 @@ namespace Mono.Cxxi.Abi {
} }
public VirtualOnlyAbi () { } public VirtualOnlyAbi () { }
public override MethodType GetMethodType (MethodInfo imethod) public override MethodType GetMethodType (CppTypeInfo typeInfo, MethodInfo imethod)
{ {
MethodType defaultType = base.GetMethodType (imethod); MethodType defaultType = base.GetMethodType (typeInfo, imethod);
if (defaultType == MethodType.NativeCtor || defaultType == MethodType.NativeDtor) if (defaultType == MethodType.NativeCtor || defaultType == MethodType.NativeDtor)
return MethodType.NoOp; return MethodType.NoOp;
return defaultType; return defaultType;
} }
protected override string GetMangledMethodName (MethodInfo methodInfo) protected override string GetMangledMethodName (CppTypeInfo typeInfo, MethodInfo methodInfo)
{ {
throw new NotSupportedException ("Name mangling is not supported by this class. All C++ interface methods must be declared virtual."); throw new NotSupportedException ("Name mangling is not supported by this class. All C++ interface methods must be declared virtual.");
} }

8
src/Mono.Cxxi/CppInstancePtr.cs

@ -56,9 +56,11 @@ namespace Mono.Cxxi {
if (!implCache.TryGetValue (typeof (Iface), out cachedImpl)) if (!implCache.TryGetValue (typeof (Iface), out cachedImpl))
{ {
VirtualOnlyAbi virtualABI = new VirtualOnlyAbi (VTable.BindToSignature); // FIXME: fix this? or not...
impl = virtualABI.ImplementClass<Iface> (typeof (TWrapper), new CppLibrary (string.Empty), string.Empty); //VirtualOnlyAbi virtualABI = new VirtualOnlyAbi (VTable.BindToSignature);
implCache.Add (typeof (Iface), impl); //impl = virtualABI.ImplementClass<Iface> (typeof (TWrapper), new CppLibrary (string.Empty), string.Empty);
//implCache.Add (typeof (Iface), impl);
throw new NotImplementedException ();
} }
else else
impl = (Iface)cachedImpl; impl = (Iface)cachedImpl;

9
src/Mono.Cxxi/CppLibrary.cs

@ -105,7 +105,8 @@ namespace Mono.Cxxi {
public Iface GetClass<Iface> (string className) public Iface GetClass<Iface> (string className)
where Iface : ICppClass where Iface : ICppClass
{ {
return Abi.ImplementClass<Iface> (null, this, className); var typeInfo = Abi.MakeTypeInfo (this, className, typeof (Iface), null, null);
return (Iface)Abi.ImplementClass (typeInfo);
} }
// For instantiating or working with a class that may have fields // For instantiating or working with a class that may have fields
@ -114,7 +115,8 @@ namespace Mono.Cxxi {
where Iface : ICppClassInstantiatable where Iface : ICppClassInstantiatable
where NativeLayout : struct where NativeLayout : struct
{ {
return Abi.ImplementClass<Iface, NativeLayout> (null, this, className); var typeInfo = Abi.MakeTypeInfo (this, className, typeof (Iface), typeof (NativeLayout), null);
return (Iface)Abi.ImplementClass (typeInfo);
} }
/* The most powerful override. Allows the following from managed code: /* The most powerful override. Allows the following from managed code:
@ -127,7 +129,8 @@ namespace Mono.Cxxi {
where NativeLayout : struct where NativeLayout : struct
where Managed : ICppObject where Managed : ICppObject
{ {
return Abi.ImplementClass<Iface, NativeLayout> (typeof (Managed), this, className); var typeInfo = Abi.MakeTypeInfo (this, className, typeof (Iface), typeof (NativeLayout), typeof (Managed));
return (Iface)Abi.ImplementClass (typeInfo);
} }
} }

57
src/Mono.Cxxi/CppTypeInfo.cs

@ -29,6 +29,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
@ -43,52 +44,61 @@ namespace Mono.Cxxi {
// TypeComplete indicates when the dust has settled. // TypeComplete indicates when the dust has settled.
public class CppTypeInfo { public class CppTypeInfo {
public CppAbi Abi { get; private set; } public CppLibrary Library { get; private set; }
public string TypeName { get; private set; }
public bool IsPrimaryBase { get; protected set; } // < True by default. set to False in cases where it is cloned as a non-primary base
// returns the number of vtable slots reserved for the
// base class(es) before this class's virtual methods start
public int BaseVTableSlots { get; protected set; }
public Type InterfaceType { get; private set; }
public Type NativeLayout { get; private set; } public Type NativeLayout { get; private set; }
public Type WrapperType { get; private set; } public Type WrapperType { get; private set; }
public IList<PInvokeSignature> VirtualMethods { get; private set; } // read only version // read only versions:
protected List<PInvokeSignature> virtual_methods; public IList<PInvokeSignature> VirtualMethods { get; private set; }
public IList<Type> VTableDelegateTypes { get; private set; }
public IList<Delegate> VTableOverrides { get; private set; }
public IList<CppTypeInfo> BaseClasses { get; private set; }
public IList<Type> VTableDelegateTypes { get; private set; } // read only version // backing lists:
protected List<PInvokeSignature> virtual_methods;
protected LazyGeneratedList<Type> vt_delegate_types; protected LazyGeneratedList<Type> vt_delegate_types;
public IList<Delegate> VTableOverrides { get; private set; } // read only version
protected LazyGeneratedList<Delegate> vt_overrides; protected LazyGeneratedList<Delegate> vt_overrides;
public IList<CppTypeInfo> BaseClasses { get; private set; } // read only version
protected List<CppTypeInfo> base_classes; protected List<CppTypeInfo> base_classes;
// returns the number of vtable slots reserved for the
// base class(es) before this class's virtual methods start
public int BaseVTableSlots { get; protected set; }
public bool TypeComplete { get; private set; }
public bool IsPrimaryBase { get; protected set; } // < True by default. set to False in cases where it is cloned as a non-primary base
protected int native_size_without_padding; // <- this refers to the size of all the fields declared in the nativeLayout struct protected int native_size_without_padding; // <- this refers to the size of all the fields declared in the nativeLayout struct
protected int field_offset_padding_without_vtptr; protected int field_offset_padding_without_vtptr;
protected int gchandle_offset_delta; protected int gchandle_offset_delta;
private VTable lazy_vtable; private VTable lazy_vtable;
public CppTypeInfo (CppAbi abi, IEnumerable<PInvokeSignature> virtualMethods, Type nativeLayout, Type/*?*/ wrapperType) internal EmitInfo emit_info; // <- will be null when the type is done being emitted
public bool TypeComplete { get { return emit_info == null; } }
public CppTypeInfo (CppLibrary lib, string typeName, Type interfaceType, Type nativeLayout, Type/*?*/ wrapperType)
: this () : this ()
{ {
Abi = abi; Library = lib;
TypeName = typeName;
InterfaceType = interfaceType;
NativeLayout = nativeLayout; NativeLayout = nativeLayout;
WrapperType = wrapperType; WrapperType = wrapperType;
virtual_methods = new List<PInvokeSignature> (virtualMethods); virtual_methods = new List<PInvokeSignature> (Library.Abi.GetVirtualMethodSlots (this, interfaceType));
VirtualMethods = new ReadOnlyCollection<PInvokeSignature> (virtual_methods); VirtualMethods = new ReadOnlyCollection<PInvokeSignature> (virtual_methods);
vt_delegate_types = new LazyGeneratedList<Type> (virtual_methods.Count, i => DelegateTypeCache.GetDelegateType (virtual_methods [i])); vt_delegate_types = new LazyGeneratedList<Type> (virtual_methods.Count, i => DelegateTypeCache.GetDelegateType (virtual_methods [i]));
VTableDelegateTypes = new ReadOnlyCollection<Type> (vt_delegate_types); VTableDelegateTypes = new ReadOnlyCollection<Type> (vt_delegate_types);
vt_overrides = new LazyGeneratedList<Delegate> (virtual_methods.Count, i => Abi.GetManagedOverrideTrampoline (this, i)); vt_overrides = new LazyGeneratedList<Delegate> (virtual_methods.Count, i => Library.Abi.GetManagedOverrideTrampoline (this, i));
VTableOverrides = new ReadOnlyCollection<Delegate> (vt_overrides); VTableOverrides = new ReadOnlyCollection<Delegate> (vt_overrides);
native_size_without_padding = nativeLayout.GetFields ().Any ()? Marshal.SizeOf (nativeLayout) : 0; if (nativeLayout != null)
native_size_without_padding = nativeLayout.GetFields ().Any ()? Marshal.SizeOf (nativeLayout) : 0;
} }
protected CppTypeInfo () protected CppTypeInfo ()
@ -98,10 +108,11 @@ namespace Mono.Cxxi {
field_offset_padding_without_vtptr = 0; field_offset_padding_without_vtptr = 0;
gchandle_offset_delta = 0; gchandle_offset_delta = 0;
TypeComplete = false;
IsPrimaryBase = true; IsPrimaryBase = true;
BaseVTableSlots = 0; BaseVTableSlots = 0;
lazy_vtable = null; lazy_vtable = null;
emit_info = new EmitInfo ();
} }
// The contract for Clone is that, if TypeComplete, working with the clone *through the public // The contract for Clone is that, if TypeComplete, working with the clone *through the public
@ -197,13 +208,13 @@ namespace Mono.Cxxi {
public virtual void CompleteType () public virtual void CompleteType ()
{ {
if (TypeComplete) if (emit_info == null)
return; return;
foreach (var baseClass in base_classes) foreach (var baseClass in base_classes)
baseClass.CompleteType (); baseClass.CompleteType ();
TypeComplete = true; emit_info = null;
RemoveVTableDuplicates (); RemoveVTableDuplicates ();
} }

1
src/Mono.Cxxi/Makefile.am

@ -44,6 +44,7 @@ all: $(ASSEMBLY) $(PROGRAMFILES) $(LINUX_PKGCONFIG)
FILES = \ FILES = \
Abi/CppAbi.cs \ Abi/CppAbi.cs \
Abi/EmitInfo.cs \
Abi/Impl/ItaniumAbi.cs \ Abi/Impl/ItaniumAbi.cs \
Abi/Impl/ItaniumTypeInfo.cs \ Abi/Impl/ItaniumTypeInfo.cs \
Abi/Impl/MsvcAbi.cs \ Abi/Impl/MsvcAbi.cs \

1
src/Mono.Cxxi/Mono.Cxxi.csproj

@ -79,6 +79,7 @@
<Compile Include="Util\MethodSignature.cs" /> <Compile Include="Util\MethodSignature.cs" />
<Compile Include="CppModifiers.cs" /> <Compile Include="CppModifiers.cs" />
<Compile Include="Abi\Impl\ItaniumTypeInfo.cs" /> <Compile Include="Abi\Impl\ItaniumTypeInfo.cs" />
<Compile Include="Abi\EmitInfo.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>

Loading…
Cancel
Save