Browse Source

Removed the old Cxxi runtime implementation.

pull/1/head
triton 13 years ago
parent
commit
efe43c4ca9
  1. 976
      src/Mono.Cxxi/Abi/CppAbi.cs
  2. 12
      src/Mono.Cxxi/Abi/EmitInfo.cs
  3. 335
      src/Mono.Cxxi/Abi/Impl/ItaniumAbi.cs
  4. 87
      src/Mono.Cxxi/Abi/Impl/ItaniumTypeInfo.cs
  5. 220
      src/Mono.Cxxi/Abi/Impl/MsvcAbi.cs
  6. 39
      src/Mono.Cxxi/Abi/MethodType.cs
  7. 113
      src/Mono.Cxxi/Abi/SymbolResolver.cs
  8. 207
      src/Mono.Cxxi/Abi/VTable.cs
  9. 56
      src/Mono.Cxxi/AssemblyInfo.cs
  10. 173
      src/Mono.Cxxi/Attributes.cs
  11. 113
      src/Mono.Cxxi/CppField.cs
  12. 201
      src/Mono.Cxxi/CppInstancePtr.cs
  13. 139
      src/Mono.Cxxi/CppLibrary.cs
  14. 197
      src/Mono.Cxxi/CppModifiers.cs
  15. 412
      src/Mono.Cxxi/CppType.cs
  16. 430
      src/Mono.Cxxi/CppTypeInfo.cs
  17. 63
      src/Mono.Cxxi/Interfaces.cs
  18. 102
      src/Mono.Cxxi/Makefile.am
  19. 116
      src/Mono.Cxxi/Mono.Cxxi.csproj
  20. 92
      src/Mono.Cxxi/Util/DelegateTypeCache.cs
  21. 645
      src/Mono.Cxxi/Util/IEnumerableTransform.cs
  22. 126
      src/Mono.Cxxi/Util/LazyGeneratedList.cs
  23. 145
      src/Mono.Cxxi/Util/MethodSignature.cs
  24. 118
      src/Mono.Cxxi/Util/ReflectionHelper.cs
  25. 6
      src/Mono.Cxxi/mono.cxxi.pc.in

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

@ -1,976 +0,0 @@ @@ -1,976 +0,0 @@
//
// Mono.Cxxi.Abi.CppAbi.cs: Represents an abstract C++ ABI
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
//
// Copyright (C) 2010-2011 Alexander Corrado
// Copyright 2011 Xamarin Inc (http://www.xamarin.com)
//
// 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.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Mono.Cxxi.Util;
namespace Mono.Cxxi.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)
protected Dictionary<Type,CppTypeInfo> wrapper_to_typeinfo = new Dictionary<Type, CppTypeInfo> ();
protected MemberFilter vtable_override_filter = VTable.BindToSignatureAndAttribute;
// Cache some frequently used methodinfos:
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_tomanaged = typeof (CppInstancePtr).GetMethod ("ToManaged", BindingFlags.Static | BindingFlags.NonPublic, null, new Type [] { typeof (IntPtr) }, null);
protected static readonly MethodInfo cppip_tomanaged_size = typeof (CppInstancePtr).GetMethod ("ToManaged", BindingFlags.Static | BindingFlags.NonPublic, null, new Type [] { typeof (IntPtr), typeof (int) }, null);
protected static readonly MethodInfo cppip_dispose = typeof (CppInstancePtr).GetMethod ("Dispose");
protected static readonly ConstructorInfo cppip_fromnative = typeof (CppInstancePtr).GetConstructor (new Type [] { typeof (IntPtr) });
protected static readonly ConstructorInfo cppip_fromsize = typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null, new Type [] { typeof (int) }, null);
protected static readonly ConstructorInfo cppip_fromtype_managed = typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null,
new Type[] { typeof (CppTypeInfo), typeof (object) }, null);
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 MethodInfo marshal_ptrtostructure = typeof (Marshal).GetMethod ("PtrToStructure", BindingFlags.Static | BindingFlags.Public, null, new Type [] { typeof (IntPtr), typeof (Type) }, null);
protected static readonly MethodInfo marshal_writeintptr = typeof (Marshal).GetMethod ("WriteIntPtr", BindingFlags.Static | BindingFlags.Public, null, new Type [] { typeof (IntPtr), typeof (IntPtr) }, null);
protected static readonly FieldInfo intptr_zero = typeof (IntPtr).GetField ("Zero");
// These methods might be more commonly overridden for a given C++ ABI:
public virtual MethodType GetMethodType (CppTypeInfo typeInfo, MethodInfo imethod)
{
if (IsInline (imethod) && !IsVirtual (imethod) && typeInfo.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;
else if (imethod.IsDefined (typeof (DestructorAttribute), false))
return MethodType.NativeDtor;
return MethodType.Native;
}
// Implementing this is recommended..
// otherwise it is not possible to instantiate classes that have vtables and only implicitly defined ctor
// Return null if not implemented or if the symbol name of the vtable for the passed typeInfo cannot be mangled (i.e. because there's no vtable)
protected virtual string GetMangledVTableName (CppTypeInfo typeInfo)
{
return null;
}
// The members below must be implemented for a given C++ ABI:
public abstract CallingConvention? GetCallingConvention (MethodInfo methodInfo);
protected abstract string GetMangledMethodName (CppTypeInfo typeInfo, MethodInfo methodInfo);
// ---------------------------------
private struct EmptyNativeLayout { }
public virtual ICppClass ImplementClass (CppTypeInfo typeInfo)
{
if (typeInfo.WrapperType == null || !wrapper_to_typeinfo.ContainsKey (typeInfo.WrapperType)) {
if (typeInfo.WrapperType != null)
wrapper_to_typeinfo.Add (typeInfo.WrapperType, typeInfo);
DefineImplType (typeInfo);
var properties = GetProperties (typeInfo.InterfaceType);
var methods = GetMethods (typeInfo.InterfaceType).Select (m => GetPInvokeSignature (typeInfo, m));
// Implement all methods
int vtableIndex = 0;
foreach (var method in methods)
DefineMethod (typeInfo, method, ref vtableIndex);
// Implement all properties
foreach (var property in properties)
DefineProperty (typeInfo, property);
typeInfo.emit_info.ctor_il.Emit (OpCodes.Ret);
var native_vtable = default (IntPtr);
#if INIT_NATIVE_VTABLES
var vtable_symbol = GetMangledVTableName (typeInfo);
if (vtable_symbol != null)
native_vtable = SymbolResolver.ResolveSymbol (SymbolResolver.LoadImage (ref typeInfo.Library.name), vtable_symbol);
#endif
return (ICppClass)Activator.CreateInstance (typeInfo.emit_info.type_builder.CreateType (), typeInfo, native_vtable);
}
throw new InvalidOperationException ("This type has already been implemented");
}
public virtual CppTypeInfo MakeTypeInfo (CppLibrary lib, string typeName, Type interfaceType, Type layoutType/*?*/, Type/*?*/ wrapperType)
{
Debug.Assert (lib.Abi == this);
return new CppTypeInfo (lib, typeName, interfaceType, layoutType ?? typeof (EmptyNativeLayout), wrapperType);
}
public virtual IEnumerable<PInvokeSignature> GetVirtualMethodSlots (CppTypeInfo typeInfo, Type interfaceType)
{
return from m in GetMethods (interfaceType)
where IsVirtual (m)
select GetPInvokeSignature (typeInfo, m);
}
protected virtual IEnumerable<MethodInfo> GetMethods (Type interfaceType)
{
// get all methods defined on inherited interfaces first
var methods = (
from iface in interfaceType.GetInterfaces ()
from method in iface.GetMethods ()
where !method.IsSpecialName
select method
).Concat (
from method in interfaceType.GetMethods ()
where !method.IsSpecialName
orderby method.MetadataToken
select method
);
return methods;
}
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 = typeInfo.InterfaceType.Name + "_";
if (typeInfo.NativeLayout != null)
implTypeName += typeInfo.NativeLayout.Name + "_";
implTypeName += this.GetType ().Name + "_Impl";
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);
var native_vtable_field = impl_type.DefineField ("_nativeVTable", typeof (IntPtr), FieldAttributes.InitOnly | FieldAttributes.Private);
ConstructorBuilder ctor = impl_type.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard,
new Type[] { typeof (CppTypeInfo), typeof (IntPtr) });
var ctor_il = ctor.GetILGenerator ();
// this._typeInfo = (CppTypeInfo passed to constructor)
ctor_il.Emit (OpCodes.Ldarg_0);
ctor_il.Emit (OpCodes.Ldarg_1);
ctor_il.Emit (OpCodes.Stfld, typeinfo_field);
// this._nativeVTable = (vtable ptr passed to constructor)
ctor_il.Emit (OpCodes.Ldarg_0);
ctor_il.Emit (OpCodes.Ldarg_2);
ctor_il.Emit (OpCodes.Stfld, native_vtable_field);
typeInfo.emit_info.ctor_il = ctor_il;
typeInfo.emit_info.typeinfo_field = typeinfo_field;
typeInfo.emit_info.native_vtable_field = native_vtable_field;
typeInfo.emit_info.type_builder = impl_type;
}
protected virtual MethodBuilder DefineMethod (CppTypeInfo typeInfo, PInvokeSignature psig, ref int vtableIndex)
{
var interfaceMethod = psig.OrigMethod;
// 1. Generate managed trampoline to call native method
var trampoline = GetMethodBuilder (typeInfo, interfaceMethod);
var il = typeInfo.emit_info.current_il = trampoline.GetILGenerator ();
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
if (!interfaceMethod.ReturnType.Equals (typeof (void)))
il.Emit (OpCodes.Ldnull);
il.Emit (OpCodes.Ret);
return trampoline;
case MethodType.ManagedAlloc:
EmitManagedAlloc (typeInfo, interfaceMethod);
il.Emit (OpCodes.Ret);
return trampoline;
}
var isStatic = IsStatic (interfaceMethod);
LocalBuilder cppInstancePtr = null;
LocalBuilder nativePtr = null;
// If we're an instance method, load up the "this" pointer
if (!isStatic)
{
if (psig.ParameterTypes.Count == 0)
throw new ArgumentException ("First argument to non-static C++ method must be instance pointer.");
// 2. Load the native C++ instance pointer
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, psig.Type);
}
MethodInfo nativeMethod;
if (IsVirtual (interfaceMethod) && psig.Type != MethodType.NativeDtor) {
nativeMethod = EmitPrepareVirtualCall (typeInfo, cppInstancePtr, vtableIndex++);
} else {
if (IsVirtual (interfaceMethod))
vtableIndex++;
nativeMethod = GetPInvokeForMethod (typeInfo, psig);
}
switch (psig.Type) {
case MethodType.NativeCtor:
EmitConstruct (typeInfo, nativeMethod, psig, cppInstancePtr, nativePtr);
break;
case MethodType.NativeDtor:
EmitDestruct (typeInfo, nativeMethod, psig, cppInstancePtr, nativePtr);
break;
default:
EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr);
break;
}
il.Emit (OpCodes.Ret);
return trampoline;
}
protected virtual PropertyBuilder DefineProperty (CppTypeInfo typeInfo, PropertyInfo property)
{
if (property.CanWrite)
throw new InvalidProgramException ("Properties in C++ interface must be read-only.");
var imethod = property.GetGetMethod ();
var methodName = imethod.Name;
var propName = property.Name;
var retType = imethod.ReturnType;
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 fieldGetter = typeInfo.emit_info.type_builder.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
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
// 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);
// first, get field offset
// = ((int)Marshal.OffsetOf (layout_type, propName)) + FieldOffsetPadding;
il.Emit(OpCodes.Ldtoken, typeInfo.NativeLayout);
il.Emit(OpCodes.Call, type_gettypefromhandle);
il.Emit(OpCodes.Ldstr, propName);
il.Emit(OpCodes.Call, marshal_offsetof);
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeInfo.emit_info.typeinfo_field);
il.Emit (OpCodes.Callvirt, typeinfo_fieldoffset);
il.Emit (OpCodes.Add);
// new CppField<T> (<field offset>)
il.Emit (OpCodes.Newobj, retType.GetConstructor (new Type[] { typeof(int) }));
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.emit_info.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;
}
/**
* Implements the managed trampoline that will be invoked from the vtable by native C++ code when overriding
* the specified C++ virtual method with the specified managed one.
*/
// FIXME: This should be moved into CppTypeInfo class
internal virtual Delegate GetManagedOverrideTrampoline (CppTypeInfo typeInfo, int vtableIndex)
{
if (typeInfo.WrapperType == null)
return null;
var sig = typeInfo.VirtualMethods [vtableIndex];
if (sig == null)
return null;
var interfaceMethod = sig.OrigMethod;
var targetMethod = FindManagedOverrideTarget (typeInfo.WrapperType, interfaceMethod);
if (targetMethod == null)
return null;
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.
var trampolineIn = new DynamicMethod (typeInfo.WrapperType.Name + "_" + interfaceMethod.Name + "_FromNative", sig.ReturnType,
nativeArgs, typeof (CppInstancePtr).Module, true);
ReflectionHelper.ApplyMethodParameterAttributes (interfaceMethod, trampolineIn, true);
var il = trampolineIn.GetILGenerator ();
// for static (target) methods:
OpCode callInstruction = OpCodes.Call;
int argLoadStart = IsStatic (interfaceMethod)? 0 : 1; // chop off C++ instance ptr if there is one
// for instance methods, we need a managed instance to call them on!
if (!targetMethod.IsStatic) {
callInstruction = OpCodes.Callvirt;
argLoadStart = 1;
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldc_I4, typeInfo.GCHandleOffset);
var getManagedObj = cppip_tomanaged_size.MakeGenericMethod (typeInfo.WrapperType);
il.Emit (OpCodes.Call, getManagedObj);
}
for (int i = argLoadStart; i < interfaceArgs.Length; i++) {
il.Emit (OpCodes.Ldarg, i);
EmitInboundMarshal (il, nativeArgs [i], interfaceArgs [i]);
}
il.Emit (callInstruction, targetMethod);
EmitOutboundMarshal (il, targetMethod.ReturnType, sig.ReturnType);
il.Emit (OpCodes.Ret);
return trampolineIn.CreateDelegate (typeInfo.VTableDelegateTypes [vtableIndex]);
}
protected virtual MethodInfo FindManagedOverrideTarget (Type wrapper, MethodInfo interfaceMethod)
{
if (interfaceMethod == null)
return null;
var possibleMembers = wrapper.FindMembers (MemberTypes.Method, BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.Static, vtable_override_filter, interfaceMethod);
if (possibleMembers.Length > 1)
throw new InvalidProgramException ("More than one possible override found when binding virtual method: " + interfaceMethod.Name);
else if (possibleMembers.Length == 0)
return null;
return (MethodInfo)possibleMembers [0];
}
/**
* Defines a new MethodBuilder with the same signature as the passed MethodInfo
*/
protected virtual MethodBuilder GetMethodBuilder (CppTypeInfo typeInfo, MethodInfo interfaceMethod)
{
var parameterTypes = ReflectionHelper.GetMethodParameterTypes (interfaceMethod);
var methodBuilder = typeInfo.emit_info.type_builder.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 (CppTypeInfo typeInfo, PInvokeSignature sig)
{
var entryPoint = sig.Name;
if (entryPoint == null)
throw new NotSupportedException ("Could not mangle method name.");
string lib;
if (IsInline (sig.OrigMethod) && typeInfo.Library.InlineMethodPolicy == InlineMethods.SurrogateLib)
lib = typeInfo.Library.Name + "-inline";
else
lib = typeInfo.Library.Name;
var builder = typeInfo.emit_info.type_builder.DefinePInvokeMethod (entryPoint, lib, entryPoint,
MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl,
CallingConventions.Standard, sig.ReturnType, sig.ParameterTypes.ToArray (),
sig.CallingConvention.Value, CharSet.Ansi);
builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig);
ReflectionHelper.ApplyMethodParameterAttributes (sig.OrigMethod, builder, true);
return builder;
}
/**
* Emits the IL to load the correct delegate instance and/or retrieve the MethodInfo from the VTable
* for a C++ virtual call.
*/
protected virtual MethodInfo EmitPrepareVirtualCall (CppTypeInfo typeInfo, LocalBuilder cppInstancePtr, int vtableIndex)
{
var il = typeInfo.emit_info.current_il;
var vtableDelegateType = typeInfo.VTableDelegateTypes [vtableIndex];
var getDelegate = typeinfo_adjvcall.MakeGenericMethod (vtableDelegateType);
// this._typeInfo.GetAdjustedVirtualCall<T> (cppInstancePtr, vtableIndex);
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeInfo.emit_info.typeinfo_field);
il.Emit (OpCodes.Ldloc_S, cppInstancePtr);
il.Emit (OpCodes.Ldc_I4, vtableIndex);
il.Emit (OpCodes.Callvirt, getDelegate);
return ReflectionHelper.GetMethodInfoForDelegate (vtableDelegateType);
}
/**
* Emits IL to allocate the memory for a new instance of the C++ class.
* To complete method, emit OpCodes.Ret.
*/
protected virtual void EmitManagedAlloc (CppTypeInfo typeInfo, MethodInfo interfaceMethod)
{
var il = typeInfo.emit_info.current_il;
var cppip = il.DeclareLocal (typeof (CppInstancePtr));
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeInfo.emit_info.typeinfo_field);
if (typeInfo.WrapperType != null && interfaceMethod.GetParameters ().Any ()) {
// load managed wrapper
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Newobj, cppip_fromtype_managed);
} else {
il.Emit (OpCodes.Callvirt, typeinfo_nativesize);
il.Emit (OpCodes.Newobj, cppip_fromsize);
}
il.Emit (OpCodes.Stloc, cppip);
var unknown_native_vtable = il.DefineLabel ();
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeInfo.emit_info.native_vtable_field);
il.Emit (OpCodes.Brfalse_S, unknown_native_vtable);
il.Emit (OpCodes.Ldloca, cppip);
il.Emit (OpCodes.Call, cppip_native);
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeInfo.emit_info.native_vtable_field);
il.Emit (OpCodes.Call, marshal_writeintptr);
il.MarkLabel (unknown_native_vtable);
il.Emit (OpCodes.Ldloc, cppip);
}
protected virtual void EmitConstruct (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig,
LocalBuilder cppInstancePtr, LocalBuilder nativePtr)
{
Debug.Assert (psig.Type == MethodType.NativeCtor);
var il = typeInfo.emit_info.current_il;
EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr);
if (cppInstancePtr != null && psig.OrigMethod.ReturnType == typeof (CppInstancePtr)) {
EmitInitVTable (typeInfo, cppInstancePtr);
il.Emit (OpCodes.Ldloc_S, cppInstancePtr);
} else if (psig.OrigMethod.DeclaringType.GetInterfaces ().Any (i => i.IsGenericType && i.GetGenericTypeDefinition () == typeof (ICppClassOverridable<>))) {
throw new InvalidProgramException ("In ICppClassOverridable, native constructors must take as first argument and return CppInstancePtr");
}
}
protected virtual void EmitDestruct (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig,
LocalBuilder cppInstancePtr, LocalBuilder nativePtr)
{
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
if (cppInstancePtr == null)
return;
EmitCheckManagedAlloc (il, cppInstancePtr);
EmitResetVTable (typeInfo, cppInstancePtr);
EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr);
}
/**
* Emits IL to call the native method. nativeMethod should be either a method obtained by
* GetPInvokeForMethod or the MethodInfo of a vtable method.
* To complete method, emit OpCodes.Ret.
*/
protected virtual void EmitNativeCall (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr)
{
var il = typeInfo.emit_info.current_il;
var interfaceMethod = psig.OrigMethod;
var interfaceArgs = interfaceMethod.GetParameters ();
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
if (psig.Type != MethodType.NativeCtor)
EmitInboundMarshal (il, psig.ReturnType, interfaceMethod.ReturnType);
}
public virtual PInvokeSignature GetPInvokeSignature (CppTypeInfo typeInfo, MethodInfo method)
{
var methodType = GetMethodType (typeInfo, 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 (typeInfo, method),
Type = methodType,
CallingConvention = GetCallingConvention (method),
ParameterTypes = pinvokeTypes,
ReturnType = methodType == MethodType.NativeCtor? typeof (void) :
ToPInvokeType (method.ReturnType, method.ReturnTypeCustomAttributes)
};
}
public virtual Type ToPInvokeType (Type t, ICustomAttributeProvider icap)
{
if (t == typeof (bool)) {
return typeof (byte);
} else if (typeof (ICppObject).IsAssignableFrom (t)) {
if (IsByVal (icap)) {
return GetTypeInfo (t).NativeLayout;
} else { // by ref
return typeof (IntPtr);
}
}
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 (managedType.Equals (typeof (bool))) {
Label isTrue = il.DefineLabel ();
Label done = il.DefineLabel ();
il.Emit (OpCodes.Brtrue, isTrue);
il.Emit (OpCodes.Ldc_I4_0);
il.Emit (OpCodes.Br, done);
il.MarkLabel (isTrue);
il.Emit (OpCodes.Ldc_I4_1);
il.MarkLabel (done);
//il.Emit (OpCodes.Conv_I1);
}
// 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.Emit (OpCodes.Br_S, nextArg);
il.MarkLabel (nullCase);
// Null case
il.Emit (OpCodes.Pop);
il.Emit (OpCodes.Ldsfld, intptr_zero);
} 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 '" + managedType + "' to c++ by value");
il.Emit (OpCodes.Newobj, typeof (ArgumentException).GetConstructor (new Type[] { typeof(string) }));
il.Emit (OpCodes.Throw);
}
}
il.MarkLabel (nextArg);
}
// 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)
{
if (nativeType == typeof (void))
return; // <- yes, this is necessary
var next = il.DefineLabel ();
var ptr = il.DeclareLocal (typeof (CppInstancePtr));
// marshal IntPtr -> ICppObject
if (nativeType == typeof (IntPtr) && typeof (ICppObject).IsAssignableFrom (targetType)) {
var isNull = il.DefineLabel ();
// first, we check for null
il.Emit (OpCodes.Dup);
il.Emit (OpCodes.Brfalse_S, isNull);
il.Emit (OpCodes.Newobj, cppip_fromnative);
il.Emit (OpCodes.Stloc, ptr);
EmitCreateCppObjectFromNative (il, targetType, ptr);
il.Emit (OpCodes.Br_S, next);
il.MarkLabel (isNull);
il.Emit (OpCodes.Pop);
il.Emit (OpCodes.Ldnull);
} else if (nativeType.IsValueType && typeof (ICppObject).IsAssignableFrom (targetType)) {
// marshal value type -> ICppObject
// Obviously, we lose all managed overrides if we pass by value,
// but this "slicing" happens in vanilla C++ as well
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);
EmitCreateCppObjectFromNative (il, targetType, ptr);
}
il.MarkLabel (next);
}
// Gets a typeinfo for another ICppObject.
protected virtual CppTypeInfo GetTypeInfo (Type otherWrapperType)
{
CppTypeInfo info;
if (wrapper_to_typeinfo.TryGetValue (otherWrapperType, out info))
return info;
// 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) {
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];
}
// Expects cppip = CppInstancePtr local
protected virtual void EmitCreateCppObjectFromNative (ILGenerator il, Type targetType, LocalBuilder cppip)
{
CppTypeInfo targetTypeInfo = null;
if (targetType == typeof (ICppObject))
targetType = typeof (CppInstancePtr);
// check for a native constructor (i.e. a public ctor in the wrapper that takes CppInstancePtr)
if (typeof (ICppObject).IsAssignableFrom (targetType)) {
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));
// Basically emitting this:
// CppInstancePtr.ToManaged<targetType> (native) ?? new targetType (native)
// ..but ToManaged is only called if there's a vtable (FIXME: otherwise we rewrap)
var hasWrapper = il.DefineLabel ();
if (targetTypeInfo == null)
targetTypeInfo = GetTypeInfo (targetType); // FIXME: woof. do we really have to do this?
if (targetTypeInfo != null && targetTypeInfo.HasVTable) {
il.Emit (OpCodes.Ldloca, cppip);
il.Emit (OpCodes.Call, cppip_native);
il.Emit (OpCodes.Call, cppip_tomanaged.MakeGenericMethod (targetType));
il.Emit (OpCodes.Dup);
il.Emit (OpCodes.Brtrue_S, hasWrapper);
il.Emit (OpCodes.Pop);
}
il.Emit (OpCodes.Ldloc, cppip);
il.Emit (OpCodes.Newobj, ctor);
il.MarkLabel (hasWrapper);
} else if (targetType.IsValueType) {
// (targetType)Marshal.PtrToStructure (CppInstancePtr.Native, typeof (targetType))
il.Emit (OpCodes.Ldloca, cppip);
il.Emit (OpCodes.Call, cppip_native);
il.Emit (OpCodes.Ldtoken, targetType);
il.Emit (OpCodes.Call, type_gettypefromhandle);
il.Emit (OpCodes.Call, marshal_ptrtostructure);
il.Emit (OpCodes.Unbox_Any, targetType);
}
}
/**
* Emits IL to load the VTable object onto the stack.
*/
protected virtual void EmitLoadVTable (CppTypeInfo typeInfo)
{
var il = typeInfo.emit_info.current_il;
// this._typeInfo.VTable
il.Emit (OpCodes.Ldarg_0);
il.Emit (OpCodes.Ldfld, typeInfo.emit_info.typeinfo_field);
il.Emit (OpCodes.Callvirt, typeinfo_vtable);
}
/**
* Emits IL to set the vtable pointer of the instance (if class has a vtable).
* This should usually happen in the managed wrapper of the C++ instance constructor.
*/
protected virtual void EmitInitVTable (CppTypeInfo typeInfo, LocalBuilder cppip)
{
var il = typeInfo.emit_info.current_il;
// this._typeInfo.VTable.InitInstance (cppInstancePtr);
EmitLoadVTable (typeInfo);
il.Emit (OpCodes.Ldloca_S, cppip);
EmitCallVTableMethod (typeInfo, vtable_initinstance, 2, false);
}
protected virtual void EmitResetVTable (CppTypeInfo typeInfo, LocalBuilder cppip)
{
var il = typeInfo.emit_info.current_il;
// this._typeInfo.VTable.ResetInstance (cppInstancePtr);
EmitLoadVTable (typeInfo);
il.Emit (OpCodes.Ldloc_S, cppip);
EmitCallVTableMethod (typeInfo, vtable_resetinstance, 2, false);
}
/**
* A utility function to emit the IL for a vtable-dependant operation.
* In other words, classes with no virtual methods will not have vtables,
* so this method emits code to check for that and either throw an exception
* or do nothing if no vtable exists. To use, push the arguments to the method you
* want to call and pass the stackHeight for the call. If no vtable exists, this method
* will emit code to pop the arguments off the stack.
*/
protected virtual void EmitCallVTableMethod (CppTypeInfo typeInfo, MethodInfo method, int stackHeight, bool throwOnNoVTable)
{
var il = typeInfo.emit_info.current_il;
// prepare a jump; do not call vtable method if no vtable
var noVirt = il.DefineLabel ();
var dontPushOrThrow = il.DefineLabel ();
EmitLoadVTable (typeInfo);
il.Emit (OpCodes.Brfalse_S, noVirt); // if (vtableInfo == null) goto noVirt
il.Emit (OpCodes.Callvirt, method); // call method
il.Emit (OpCodes.Br_S, dontPushOrThrow); // goto dontPushOrThrow
il.MarkLabel (noVirt);
// noVirt:
// since there is no vtable, we did not make the method call.
// pop arguments
for (int i = 0; i < stackHeight; i++)
il.Emit (OpCodes.Pop);
// if the method was supposed to return a value, we must
// still push something onto the stack
// FIXME: This is a kludge. What about value types?
if (!method.ReturnType.Equals (typeof (void)))
il.Emit (OpCodes.Ldnull);
if (throwOnNoVTable) {
il.Emit (OpCodes.Ldstr, "Native class has no VTable.");
il.Emit (OpCodes.Newobj, typeof (InvalidOperationException).GetConstructor(new Type[] {typeof (string)}));
il.Emit (OpCodes.Throw);
}
il.MarkLabel (dontPushOrThrow);
}
protected virtual void EmitLoadInstancePtr (ILGenerator il, Type firstParamType, out LocalBuilder cppip,
out LocalBuilder native)
{
cppip = null;
native = null;
il.Emit (OpCodes.Ldarg_1);
if (firstParamType.Equals (typeof (CppInstancePtr))) {
cppip = il.DeclareLocal (typeof (CppInstancePtr));
native = il.DeclareLocal (typeof (IntPtr));
il.Emit (OpCodes.Stloc_S, cppip);
il.Emit (OpCodes.Ldloca_S, cppip);
il.Emit (OpCodes.Call, cppip_native);
il.Emit (OpCodes.Stloc_S, native);
} else if (firstParamType.Equals (typeof (IntPtr))) {
native = il.DeclareLocal (typeof (IntPtr));
il.Emit (OpCodes.Stloc_S, native);
} else if (firstParamType.IsByRef) {
native = il.DeclareLocal (firstParamType);
il.Emit (OpCodes.Stloc_S, native);
} else
throw new ArgumentException ("First argument to non-static C++ method must be byref, IntPtr or CppInstancePtr.");
}
protected virtual void EmitCheckManagedAlloc (ILGenerator il, LocalBuilder cppip)
{
// make sure we were allocated by managed code
// if not, return
var managedAlloc = il.DefineLabel ();
il.Emit (OpCodes.Ldloca_S, cppip);
il.Emit (OpCodes.Call, cppip_managedalloc);
il.Emit (OpCodes.Brtrue_S, managedAlloc);
il.Emit (OpCodes.Ret);
il.MarkLabel (managedAlloc);
}
/**
* throw ObjectDisposedException if we have a null pointer for native
* however, allow destructor to be called even if we're disposed (just return immediately)
*/
protected virtual void EmitCheckDisposed (ILGenerator il, LocalBuilder native, MethodType methodType)
{
var validRef = il.DefineLabel ();
il.Emit (OpCodes.Ldloc_S, native);
il.Emit (OpCodes.Brtrue_S, validRef);
if (methodType == MethodType.NativeDtor) {
il.Emit (OpCodes.Ret);
il.MarkLabel (validRef);
} else {
il.Emit (OpCodes.Ldstr, String.Empty);
il.Emit (OpCodes.Newobj, typeof (ObjectDisposedException).GetConstructor (new Type[] { typeof(string) }));
il.Emit (OpCodes.Throw);
il.MarkLabel (validRef);
}
}
}
}

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

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

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

@ -1,335 +0,0 @@ @@ -1,335 +0,0 @@
//
// Mono.Cxxi.Abi.ItaniumAbi.cs: An implementation of the Itanium C++ ABI
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
// Copyright 2011 Xamarin Inc (http://www.xamarin.com)
//
// 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.Text;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Mono.Cxxi.Util;
namespace Mono.Cxxi.Abi {
public class ItaniumAbi : CppAbi {
public static readonly ItaniumAbi Instance = new ItaniumAbi ();
private ItaniumAbi ()
{
}
public override CppTypeInfo MakeTypeInfo (CppLibrary lib, string typeName, Type interfaceType, Type layoutType/*?*/, Type/*?*/ wrapperType)
{
return new ItaniumTypeInfo (lib, typeName, interfaceType, layoutType, wrapperType);
}
public override IEnumerable<PInvokeSignature> GetVirtualMethodSlots (CppTypeInfo typeInfo, Type interfaceType)
{
foreach (var method in base.GetVirtualMethodSlots (typeInfo, interfaceType)) {
if (!IsVirtual (method.OrigMethod))
continue;
yield return method;
// Itanium has extra slot for virt dtor
if (method.Type == MethodType.NativeDtor)
yield return null;
}
}
internal override Delegate GetManagedOverrideTrampoline (CppTypeInfo typeInfo, int vtableIndex)
{
// FIXME: HACK! we really need to support by val return types for managed override trampolines
if (typeInfo.VirtualMethods [vtableIndex] != null &&
IsByVal (typeInfo.VirtualMethods [vtableIndex].OrigMethod.ReturnTypeCustomAttributes))
return null;
return base.GetManagedOverrideTrampoline (typeInfo, vtableIndex);
}
protected override MethodBuilder DefineMethod (CppTypeInfo typeInfo, PInvokeSignature sig, ref int vtableIndex)
{
var builder = base.DefineMethod (typeInfo, sig, 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)
{
return CallingConvention.Cdecl;
}
protected override string GetMangledMethodName (CppTypeInfo typeInfo, MethodInfo methodInfo)
{
var compressMap = new Dictionary<string, int> ();
var methodName = methodInfo.Name;
var type = typeInfo.GetMangleType ();
var className = type.ElementTypeName;
MethodType methodType = GetMethodType (typeInfo, methodInfo);
ParameterInfo [] parameters = methodInfo.GetParameters ();
StringBuilder nm = new StringBuilder ("_ZN", 30);
if (IsConst (methodInfo))
nm.Append ('K');
if (type.Namespaces != null) {
foreach (var ns in type.Namespaces)
nm.Append (GetIdentifier (compressMap, ns));
}
nm.Append (GetIdentifier (compressMap, className));
// FIXME: Implement compression completely
switch (methodType) {
case MethodType.NativeCtor:
nm.Append ("C1");
break;
case MethodType.NativeDtor:
nm.Append ("D1");
break;
default:
nm.Append (methodName.Length).Append (methodName);
break;
}
nm.Append ('E');
int argStart = (IsStatic (methodInfo)? 0 : 1);
if (parameters.Length == argStart) // no args (other than C++ "this" object)
nm.Append ('v');
else
for (int i = argStart; i < parameters.Length; i++)
nm.Append (GetTypeCode (GetMangleType (parameters [i], parameters [i].ParameterType), compressMap));
return nm.ToString ();
}
public virtual string GetTypeCode (CppType mangleType) {
return GetTypeCode (mangleType, new Dictionary<string, int> ());
}
string GetTypeCode (CppType mangleType, Dictionary<string, int> compressMap)
{
CppTypes element = mangleType.ElementType;
IEnumerable<CppModifiers> modifiers = mangleType.Modifiers;
StringBuilder code = new StringBuilder ();
var ptrOrRef = For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Reference);
var modifierCode = modifiers.Reverse ().Transform (
For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Array).Emit ("P"),
For.AnyInputIn (CppModifiers.Reference).Emit ("R"),
// Itanium mangled names do not include const or volatile unless
// they modify the type pointed to by pointer or reference.
Choose.TopOne (
For.AllInputsIn (CppModifiers.Volatile, CppModifiers.Const).InAnyOrder ().After (ptrOrRef).Emit ("VK"),
For.AnyInputIn (CppModifiers.Volatile).After (ptrOrRef).Emit ("V"),
For.AnyInputIn (CppModifiers.Const).After (ptrOrRef).Emit ("K")
)
);
code.Append (string.Join(string.Empty, modifierCode.ToArray ()));
switch (element) {
case CppTypes.Int:
code.Append (modifiers.Transform (
For.AllInputsIn (CppModifiers.Unsigned, CppModifiers.Short).InAnyOrder ().Emit ('t'),
For.AnyInputIn (CppModifiers.Short).Emit ('s'),
For.AllInputsIn (CppModifiers.Unsigned, CppModifiers.Long, CppModifiers.Long).InAnyOrder ().Emit ('y'),
For.AllInputsIn (CppModifiers.Long, CppModifiers.Long).InAnyOrder ().Emit ('x'),
For.AllInputsIn (CppModifiers.Unsigned, CppModifiers.Long).InAnyOrder ().Emit ('m'),
For.AnyInputIn (CppModifiers.Long).Emit ('l'),
For.AnyInputIn (CppModifiers.Unsigned).Emit ('j')
).DefaultIfEmpty ('i').ToArray ());
break;
case CppTypes.Bool:
code.Append ('b');
break;
case CppTypes.Char:
if (modifiers.Contains (CppModifiers.Signed))
code.Append ('a');
else if (modifiers.Contains (CppModifiers.Unsigned))
code.Append ('h');
else
code.Append ('c');
break;
case CppTypes.Float:
code.Append ('f');
break;
case CppTypes.Double:
if (modifiers.Contains (CppModifiers.Long))
code.Append ('e');
else
code.Append ('d');
break;
case CppTypes.Class:
case CppTypes.Struct:
case CppTypes.Union:
case CppTypes.Enum:
if (mangleType.Namespaces != null) {
code.Append ('N');
foreach (var ns in mangleType.Namespaces)
code.Append (GetIdentifier (compressMap, ns));
}
code.Append (GetIdentifier (compressMap, mangleType.ElementTypeName));
if (mangleType.Namespaces != null)
code.Append ('E');
break;
}
return code.ToString ();
}
protected override string GetMangledVTableName (CppTypeInfo typeInfo)
{
var compressMap = new Dictionary<string, int> ();
var type = typeInfo.GetMangleType ();
var nm = new StringBuilder ("_ZTV", 30);
if (type.Namespaces != null) {
nm.Append ('N');
foreach (var ns in type.Namespaces)
nm.Append (GetIdentifier (compressMap, ns));
}
nm.Append (GetIdentifier (compressMap, type.ElementTypeName));
if (type.Namespaces != null)
nm.Append ('E');
return nm.ToString ();
}
string GetIdentifier (Dictionary<string, int> compressMap, string identifier)
{
int cid;
if (compressMap.TryGetValue (identifier, out cid))
return cid == 0 ? "S_" : ToBase36String (cid - 1);
compressMap [identifier] = compressMap.Count;
return identifier.Length.ToString () + identifier;
}
const string Base36 = "0123456789abcdefghijklmnopqrstuvwxyz";
string ToBase36String (int input)
{
var result = new Stack<char> ();
while (input != 0)
{
result.Push (Base36 [input % 36]);
input /= 36;
}
return new string (result.ToArray ());
}
// Section 3.1.4:
// Classes with non-default copy ctors/destructors are returned using a hidden
// argument
bool ReturnByHiddenArgument (CppTypeInfo typeInfo, MethodInfo method)
{
var iti = (ItaniumTypeInfo)typeInfo;
if (!IsByVal (method.ReturnTypeCustomAttributes))
return false;
if (iti.has_non_default_copy_ctor_or_dtor == null)
iti.has_non_default_copy_ctor_or_dtor = GetMethods (typeInfo.InterfaceType)
.Any (m => (IsCopyConstructor (m) ||
GetMethodType (typeInfo, m) == MethodType.NativeDtor) &&
!IsArtificial (m));
return iti.has_non_default_copy_ctor_or_dtor.Value;
}
public override PInvokeSignature GetPInvokeSignature (CppTypeInfo/*?*/ typeInfo, MethodInfo method)
{
var psig = base.GetPInvokeSignature (typeInfo, method);
if (ReturnByHiddenArgument (typeInfo, method)) {
psig.ParameterTypes.Insert (0, typeof (IntPtr));
psig.ReturnType = typeof (void);
}
return psig;
}
protected override void EmitNativeCall (CppTypeInfo typeInfo, MethodInfo nativeMethod, PInvokeSignature psig, LocalBuilder nativePtr)
{
var il = typeInfo.emit_info.current_il;
var method = psig.OrigMethod;
var returnType = method.ReturnType;
var hiddenReturnByValue = ReturnByHiddenArgument (typeInfo, method);
LocalBuilder returnValue = null;
if (hiddenReturnByValue)
{
returnValue = il.DeclareLocal (typeof (CppInstancePtr));
if (typeof (ICppObject).IsAssignableFrom (returnType))
il.Emit (OpCodes.Ldc_I4, GetTypeInfo (returnType).NativeSize);
else if (returnType.IsValueType)
il.Emit (OpCodes.Ldc_I4, Marshal.SizeOf (returnType));
il.Emit (OpCodes.Newobj, cppip_fromsize);
il.Emit (OpCodes.Stloc, returnValue);
il.Emit (OpCodes.Ldloca, returnValue);
il.Emit (OpCodes.Call, cppip_native);
}
base.EmitNativeCall (typeInfo, nativeMethod, psig, nativePtr);
if (hiddenReturnByValue) {
EmitCreateCppObjectFromNative (il, returnType, returnValue);
if (returnType.IsValueType) {
// FIXME: This dispose should prolly be in a Finally block..
il.Emit (OpCodes.Ldloca, returnValue);
il.Emit (OpCodes.Call, cppip_dispose);
}
}
}
}
}

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

@ -1,87 +0,0 @@ @@ -1,87 +0,0 @@
//
// Mono.Cxxi.Abi.ItaniumTypeInfo.cs: An implementation of the Itanium C++ ABI
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
//
// Copyright (C) 2011 Alexander Corrado
//
// 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.Runtime.InteropServices;
using System.Reflection;
using Mono.Cxxi.Util;
namespace Mono.Cxxi.Abi {
public class ItaniumTypeInfo : CppTypeInfo {
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)
{
}
/*
protected override void AddBase (CppTypeInfo baseType, BaseVirtualMethods location)
{
if (TypeComplete)
return;
// When adding a non-primary base class's complete vtable, we need to reserve space for
// the stuff before the address point of the vtptr..
// Includes vbase & vcall offsets (virtual inheritance), offset to top, and RTTI info
if (addVTable) {
// FIXME: virtual inheritance
virtual_methods.Add (null);
virtual_methods.Add (null);
vt_overrides.Add (2);
vt_delegate_types.Add (2);
}
base.AddBase (baseType, addVTable);
}
*/
protected override bool OnVTableDuplicate (ref int iter, ref int adj, PInvokeSignature sig, PInvokeSignature dup)
{
var isOverride = base.OnVTableDuplicate (ref iter, ref adj, sig, dup);
if (isOverride && sig.Type == MethodType.NativeDtor) {
// also remove that pesky extra dtor
virtual_methods.RemoveAt (iter + 1);
vt_overrides.Remove (1);
vt_delegate_types.Remove (1);
vtable_index_adjustments.Add (0);
adj--;
return true;
}
return false;
}
}
}

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

@ -1,220 +0,0 @@ @@ -1,220 +0,0 @@
//
// Mono.Cxxi.Abi.MsvcAbi.cs: An implementation of the Microsoft Visual C++ ABI
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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.Text;
using System.Reflection;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Mono.Cxxi;
using Mono.Cxxi.Util;
namespace Mono.Cxxi.Abi {
// FIXME: No 64-bit support
public class MsvcAbi : CppAbi {
public static readonly MsvcAbi Instance = new MsvcAbi ();
private MsvcAbi ()
{
}
public override CallingConvention? GetCallingConvention (MethodInfo methodInfo)
{
// FIXME: Varargs methods ... ?
if (IsStatic (methodInfo))
return CallingConvention.Cdecl;
else
return CallingConvention.ThisCall;
}
protected override string GetMangledMethodName (CppTypeInfo typeInfo, MethodInfo methodInfo)
{
var methodName = methodInfo.Name;
var type = typeInfo.GetMangleType ();
var className = type.ElementTypeName;
MethodType methodType = GetMethodType (typeInfo, methodInfo);
ParameterInfo [] parameters = methodInfo.GetParameters ();
StringBuilder nm = new StringBuilder ("?", 30);
if (methodType == MethodType.NativeCtor)
nm.Append ("?0");
else if (methodType == MethodType.NativeDtor)
nm.Append ("?1");
else
nm.Append (methodName).Append ('@');
// 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.
nm.Append (className).Append ("@@");
// function modifiers are a matrix of consecutive uppercase letters
// depending on access type and virtual (far)/static (far)/far modifiers
// first, access type
char funcModifier = 'Q'; // (public)
if (IsProtected (methodInfo))
funcModifier = 'I';
else if (IsPrivate (methodInfo)) // (probably don't need this)
funcModifier = 'A';
// now, offset based on other modifiers
if (IsStatic (methodInfo))
funcModifier += (char)2;
else if (IsVirtual (methodInfo))
funcModifier += (char)4;
nm.Append (funcModifier);
// FIXME: deal with other storage classes for "this" i.e. the "volatile" in -> int foo () volatile;
if (!IsStatic (methodInfo)) {
if (IsConst (methodInfo))
nm.Append ('B');
else
nm.Append ('A');
}
switch (GetCallingConvention (methodInfo)) {
case CallingConvention.Cdecl:
nm.Append ('A');
break;
case CallingConvention.ThisCall:
nm.Append ('E');
break;
case CallingConvention.StdCall:
nm.Append ('G');
break;
case CallingConvention.FastCall:
nm.Append ('I');
break;
}
// FIXME: handle const, volatile modifiers on return type
// FIXME: the manual says this is only omitted for simple types.. are we doing the right thing here?
CppType returnType = GetMangleType (methodInfo.ReturnTypeCustomAttributes, methodInfo.ReturnType);
if (returnType.ElementType == CppTypes.Class ||
returnType.ElementType == CppTypes.Struct ||
returnType.ElementType == CppTypes.Union)
nm.Append ("?A");
if (methodType == MethodType.NativeCtor || methodType == MethodType.NativeDtor)
nm.Append ('@');
else
nm.Append (GetTypeCode (returnType));
int argStart = (IsStatic (methodInfo)? 0 : 1);
if (parameters.Length == argStart) { // no args (other than C++ "this" object)
nm.Append ("XZ");
return nm.ToString ();
} else
for (int i = argStart; i < parameters.Length; i++)
nm.Append (GetTypeCode (GetMangleType (parameters [i], parameters [i].ParameterType)));
nm.Append ("@Z");
return nm.ToString ();
}
public virtual string GetTypeCode (CppType mangleType)
{
CppTypes element = mangleType.ElementType;
IEnumerable<CppModifiers> modifiers = mangleType.Modifiers;
StringBuilder code = new StringBuilder ();
var ptr = For.AnyInputIn (CppModifiers.Pointer);
var ptrRefOrArray = For.AnyInputIn (CppModifiers.Pointer, CppModifiers.Reference, CppModifiers.Array);
var modifierCode = modifiers.Reverse ().Transform (
Choose.TopOne (
For.AllInputsIn (CppModifiers.Const, CppModifiers.Volatile).InAnyOrder ().After (ptrRefOrArray).Emit ('D'),
For.AnyInputIn (CppModifiers.Const).After (ptrRefOrArray).Emit ('B'),
For.AnyInputIn (CppModifiers.Volatile).After (ptrRefOrArray).Emit ('C'),
For.AnyInput<CppModifiers> ().After (ptrRefOrArray).Emit ('A')
),
For.AnyInputIn (CppModifiers.Array).Emit ('Q'),
For.AnyInputIn (CppModifiers.Reference).Emit ('A'),
Choose.TopOne (
ptr.After ().AllInputsIn (CppModifiers.Const, CppModifiers.Volatile).InAnyOrder ().Emit ('S'),
ptr.After ().AnyInputIn (CppModifiers.Const).Emit ('Q'),
ptr.After ().AnyInputIn (CppModifiers.Volatile).Emit ('R'),
ptr.Emit ('P')
),
ptrRefOrArray.AtEnd ().Emit ('A')
);
code.Append (modifierCode.ToArray ());
switch (element) {
case CppTypes.Void:
code.Append ('X');
break;
case CppTypes.Int:
code.Append (modifiers.Transform (
For.AllInputsIn (CppModifiers.Unsigned, CppModifiers.Short).InAnyOrder ().Emit ('G')
).DefaultIfEmpty ('H').ToArray ());
break;
case CppTypes.Char:
code.Append ('D');
break;
case CppTypes.Class:
code.Append ('V');
code.Append(mangleType.ElementTypeName);
code.Append ("@@");
break;
case CppTypes.Struct:
code.Append ('U');
code.Append(mangleType.ElementTypeName);
code.Append ("@@");
break;
case CppTypes.Union:
code.Append ('T');
code.Append(mangleType.ElementTypeName);
code.Append ("@@");
break;
case CppTypes.Enum:
code.Append ("W4");
code.Append(mangleType.ElementTypeName);
code.Append ("@@");
break;
}
return code.ToString ();
}
}
}

39
src/Mono.Cxxi/Abi/MethodType.cs

@ -1,39 +0,0 @@ @@ -1,39 +0,0 @@
//
// Mono.Cxxi.Abi.MethodType.cs: Method annotation for IL codegen
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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;
namespace Mono.Cxxi.Abi {
public enum MethodType {
NoOp,
NotImplemented,
Native,
NativeCtor,
NativeDtor,
ManagedAlloc
}
}

113
src/Mono.Cxxi/Abi/SymbolResolver.cs

@ -1,113 +0,0 @@ @@ -1,113 +0,0 @@
//
// Mono.Cxxi.Abi.SymbolResolver.cs: Platform-independent dynamic symbol lookup
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
//
// Copyright 2011 Xamarin Inc (http://www.xamarin.com)
//
// 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.Runtime.InteropServices;
namespace Mono.Cxxi.Abi {
internal static class SymbolResolver {
static readonly string [] formats;
static readonly Func<string,IntPtr> load_image;
static readonly Func<IntPtr,string,IntPtr> resolve_symbol;
static SymbolResolver ()
{
switch (Environment.OSVersion.Platform) {
case PlatformID.Unix:
case PlatformID.MacOSX:
load_image = dlopen;
resolve_symbol = dlsym;
formats = new[] {
"{0}",
"{0}.so",
"{0}.dylib",
"lib{0}.so",
"lib{0}.dylib",
"{0}.bundle"
};
break;
default:
load_image = LoadLibrary;
resolve_symbol = GetProcAddress;
formats = new[] { "{0}", "{0}.dll" };
break;
}
}
// will fix up name with a more precise name to speed up later p/invokes (hopefully?)
public static IntPtr LoadImage (ref string name)
{
foreach (var format in formats) {
var attempted = string.Format (format, name);
var ptr = load_image (attempted);
if (ptr != IntPtr.Zero) {
name = attempted;
return ptr;
}
}
return IntPtr.Zero;
}
public static IntPtr ResolveSymbol (IntPtr image, string symbol)
{
if (image != IntPtr.Zero)
return resolve_symbol (image, symbol);
return IntPtr.Zero;
}
#region POSIX
static IntPtr dlopen (string path)
{
return dlopen (path, 0x0);
}
[DllImport ("dl", CharSet=CharSet.Ansi)]
static extern IntPtr dlopen (string path, int flags);
[DllImport ("dl", CharSet=CharSet.Ansi)]
static extern IntPtr dlsym (IntPtr handle, string symbol);
#endregion
#region Win32
[DllImport("kernel32", SetLastError=true)]
static extern IntPtr LoadLibrary (string lpFileName);
[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
static extern IntPtr GetProcAddress (IntPtr hModule, string procName);
#endregion
}
}

207
src/Mono.Cxxi/Abi/VTable.cs

@ -1,207 +0,0 @@ @@ -1,207 +0,0 @@
//
// Mono.Cxxi.Abi.VTable.cs: Managed VTable Implementation
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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.Diagnostics;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
namespace Mono.Cxxi.Abi {
// TODO: RTTI .. support virtual inheritance
public class VTable : IDisposable {
protected bool initialized;
protected CppTypeInfo type_info;
protected IntPtr vtPtr;
public virtual int EntryCount {
get { return type_info.VirtualMethods.Count; }
}
public virtual int EntrySize {
get { return IntPtr.Size; }
}
// Subclasses should allocate vtPtr and then call WriteOverrides
public VTable (CppTypeInfo typeInfo)
{
this.initialized = false;
this.type_info = typeInfo;
this.vtPtr = Marshal.AllocHGlobal ((EntryCount * EntrySize) + typeInfo.VTableTopPadding + typeInfo.VTableBottomPadding);
WriteOverrides ();
CppInstancePtr.RegisterManagedVTable (this);
}
protected virtual void WriteOverrides ()
{
IntPtr vtEntryPtr;
int currentOffset = type_info.VTableTopPadding;
for (int i = 0; i < EntryCount; i++) {
Delegate currentOverride = type_info.VTableOverrides [i];
if (currentOverride != null) // managed override
vtEntryPtr = Marshal.GetFunctionPointerForDelegate (currentOverride);
else
vtEntryPtr = IntPtr.Zero;
Marshal.WriteIntPtr (vtPtr, currentOffset, vtEntryPtr);
currentOffset += EntrySize;
}
}
public virtual T GetVirtualCallDelegate<T> (CppInstancePtr instance, int index)
where T : class /*Delegate*/
{
var vtable = instance.NativeVTable;
var ftnptr = Marshal.ReadIntPtr (vtable, (index * EntrySize) + type_info.VTableTopPadding);
if (ftnptr == IntPtr.Zero)
throw new NullReferenceException ("Native VTable contains null...possible abstract class???");
var del = Marshal.GetDelegateForFunctionPointer (ftnptr, typeof (T));
return del as T;
}
// FIXME: Make this method unsafe.. it would probably be much faster
public virtual void InitInstance (ref CppInstancePtr instance)
{
var basePtr = Marshal.ReadIntPtr (instance.Native);
Debug.Assert (basePtr != IntPtr.Zero);
if (basePtr == vtPtr)
return;
instance.NativeVTable = basePtr;
if (!initialized) {
// FIXME: This could probably be a more efficient memcpy
for (int i = 0; i < type_info.VTableTopPadding; i++)
Marshal.WriteByte(vtPtr, i, Marshal.ReadByte(basePtr, i));
int currentOffset = type_info.VTableTopPadding;
for (int i = 0; i < EntryCount; i++) {
if (Marshal.ReadIntPtr (vtPtr, currentOffset) == IntPtr.Zero)
Marshal.WriteIntPtr (vtPtr, currentOffset, Marshal.ReadIntPtr (basePtr, currentOffset));
currentOffset += EntrySize;
}
// FIXME: This could probably be a more efficient memcpy
for (int i = 0; i < type_info.VTableBottomPadding; i++)
Marshal.WriteByte(vtPtr, currentOffset + i, Marshal.ReadByte(basePtr, currentOffset + i));
initialized = true;
}
Marshal.WriteIntPtr (instance.Native, vtPtr);
}
public virtual void ResetInstance (CppInstancePtr instance)
{
Marshal.WriteIntPtr (instance.Native, instance.NativeVTable);
}
public CppTypeInfo TypeInfo {
get { return type_info; }
}
public IntPtr Pointer {
get { return vtPtr; }
}
protected virtual void Dispose (bool disposing)
{
if (vtPtr != IntPtr.Zero) {
Marshal.FreeHGlobal (vtPtr);
vtPtr = IntPtr.Zero;
}
}
// TODO: This WON'T usually be called because VTables are associated with classes
// (not instances) and managed C++ class wrappers are staticly held?
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
~VTable ()
{
Dispose (false);
}
public static bool BindToSignatureAndAttribute (MemberInfo member, object obj)
{
var overrideNative = member.GetCustomAttributes (typeof (OverrideNativeAttribute), true);
if (overrideNative.Length == 0)
return false;
var name = ((OverrideNativeAttribute)overrideNative [0]).NativeMethod ?? member.Name;
return BindToSignature (member, obj, name);
}
public static bool BindToSignature (MemberInfo member, object obj)
{
return BindToSignature (member, obj, member.Name);
}
public static bool BindToSignature (MemberInfo member, object obj, string nativeMethod)
{
MethodInfo imethod = (MethodInfo) obj;
MethodInfo candidate = (MethodInfo) member;
if (nativeMethod != imethod.Name)
return false;
ParameterInfo[] invokeParams = imethod.GetParameters ();
ParameterInfo[] methodParams = candidate.GetParameters ();
if (invokeParams.Length == methodParams.Length) {
for (int i = 0; i < invokeParams.Length; i++) {
if (!invokeParams [i].ParameterType.IsAssignableFrom (methodParams [i].ParameterType))
return false;
}
} else if (invokeParams.Length == methodParams.Length + 1) {
for (int i = 1; i < invokeParams.Length; i++) {
if (!invokeParams [i].ParameterType.IsAssignableFrom (methodParams [i - 1].ParameterType))
return false;
}
} else
return false;
return true;
}
}
}

56
src/Mono.Cxxi/AssemblyInfo.cs

@ -1,56 +0,0 @@ @@ -1,56 +0,0 @@
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("Mono.Cxxi")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]
[assembly: CLSCompliant(true)]
// FIXME: This will not work if we ever support saving these assemblies
[assembly: InternalsVisibleTo("__CppLibraryImplAssembly")]

173
src/Mono.Cxxi/Attributes.cs

@ -1,173 +0,0 @@ @@ -1,173 +0,0 @@
//
// Mono.Cxxi.Attributes.cs
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
//
// Copyright (C) 2010 Alexander Corrado
//
using System;
using System.Linq;
using System.Reflection;
namespace Mono.Cxxi {
#region Interface method attributes
[AttributeUsage (AttributeTargets.Method)]
public class ConstructorAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class DestructorAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class VirtualAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class StaticAttribute : Attribute {}
// used for the const "this" - for example: int value () const;
// use MangleAsAttribute for const parameters
[AttributeUsage (AttributeTargets.Method)]
public class ConstAttribute : Attribute {}
// FIXME: Will we ever be calling private methods?
[AttributeUsage (AttributeTargets.Method)]
public class PrivateAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class ProtectedAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class InlineAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class ArtificialAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class CopyConstructorAttribute : Attribute {}
// applied when the target would normally be passed by reference (e.g. class)
[AttributeUsage (AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
public class ByValAttribute : Attribute {}
// used for byref return of things that would normally be passed by value (e.g. int&)
[AttributeUsage (AttributeTargets.ReturnValue)]
public class ByRefAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Interface | AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
public class MangleAsAttribute : Attribute {
public CppType MangleType { get; private set; }
public MangleAsAttribute (CppType mangleType)
{
this.MangleType = mangleType;
}
public MangleAsAttribute (string mangleTypeStr)
{
this.MangleType = new CppType (mangleTypeStr);
}
public MangleAsAttribute (params object [] cppTypeSpec)
{
this.MangleType = new CppType (cppTypeSpec);
}
}
// for testing:
[AttributeUsage (AttributeTargets.Method)]
public class AbiTestAttribute : Attribute {
public string MangledName { get; set; }
public Type Abi { get; set; }
public AbiTestAttribute (string mangledName)
{
MangledName = mangledName;
}
}
#endregion
#region Wrapper method attributes
[AttributeUsage (AttributeTargets.Method)]
public class OverrideNativeAttribute : Attribute {
public string NativeMethod { get; set; }
public OverrideNativeAttribute ()
{
}
public OverrideNativeAttribute (string nativeMethod)
{
this.NativeMethod = nativeMethod;
}
}
#endregion
}
namespace Mono.Cxxi.Abi {
using Mono.Cxxi;
public partial class CppAbi {
public virtual bool IsVirtual (MethodInfo method)
{
return method.IsDefined (typeof (VirtualAttribute), false);
}
public virtual bool IsStatic (MethodInfo method)
{
return method.IsDefined (typeof (StaticAttribute), false);
}
public virtual bool IsConst (MethodInfo method)
{
return method.IsDefined (typeof (ConstAttribute), false);
}
public virtual bool IsPrivate (MethodInfo method)
{
return method.IsDefined (typeof (PrivateAttribute), false);
}
public virtual bool IsProtected (MethodInfo method)
{
return method.IsDefined (typeof (ProtectedAttribute), false);
}
public virtual bool IsInline (MethodInfo method)
{
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 bool IsByRef (ICustomAttributeProvider icap, Type type)
{
return type.IsByRef || icap.IsDefined (typeof (ByRefAttribute), false);
}
public virtual CppType GetMangleType (ICustomAttributeProvider icap, Type managedType)
{
CppType mangleType = new CppType ();
MangleAsAttribute maa = (MangleAsAttribute)icap.GetCustomAttributes (typeof (MangleAsAttribute), false).FirstOrDefault ();
if (maa != null)
mangleType = maa.MangleType;
// this means that either no MangleAsAttribute was defined, or
// only CppModifiers were applied .. apply CppType from managed parameter type
if (mangleType.ElementType == CppTypes.Unknown && mangleType.ElementTypeName == null)
mangleType.CopyTypeFrom (CppType.ForManagedType (managedType));
else if (mangleType.ElementType == CppTypes.Unknown)
// FIXME: otherwise, we just assume it's CppTypes.Class for now.
mangleType.ElementType = CppTypes.Class;
return mangleType;
}
}
}

113
src/Mono.Cxxi/CppField.cs

@ -1,113 +0,0 @@ @@ -1,113 +0,0 @@
//
// Mono.Cxxi.CppField.cs: Represents a field in a native C++ object
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
// Copyright 2011 Xamarin Inc (http://www.xamarin.com)
//
// 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.Runtime.InteropServices;
namespace Mono.Cxxi {
public class CppField<T> {
private int fieldOffset;
public CppField (int fieldOffset)
{
this.fieldOffset = fieldOffset;
}
public T this [CppInstancePtr ip] {
get {
Type retType = typeof (T).IsEnum? Enum.GetUnderlyingType (typeof (T)) : typeof (T);
object retVal;
if (retType.Equals (typeof (IntPtr)))
retVal = Marshal.ReadIntPtr (ip.Native, fieldOffset);
else if (retType.Equals (typeof (Byte)))
retVal = Marshal.ReadByte (ip.Native, fieldOffset);
else if (retType.Equals (typeof (Int16)))
retVal = Marshal.ReadInt16 (ip.Native, fieldOffset);
else if (retType.Equals (typeof (Int32)))
retVal = Marshal.ReadInt32 (ip.Native, fieldOffset);
else if (typeof (ICppObject).IsAssignableFrom (retType)) {
var ptr = Marshal.ReadIntPtr (ip.Native, fieldOffset);
if (ptr == IntPtr.Zero)
return default (T);
var ctor = retType.GetConstructor (new Type [] { typeof (IntPtr) });
if (ctor != null) {
retVal = ctor.Invoke (new object [] { ptr });
} else {
ctor = retType.GetConstructor (new Type [] { typeof (CppInstancePtr) });
if (ctor == null)
throw new NotSupportedException ("Type " + retType.Name + " does not have a constructor that takes either IntPtr or CppInstancePtr.");
retVal = ctor.Invoke (new object [] { new CppInstancePtr (ptr) });
}
} else {
throw new NotSupportedException ("Cannot read C++ fields of type " + retType.Name);
}
return (T)retVal;
}
set {
Type setType = typeof (T).IsEnum? Enum.GetUnderlyingType (typeof (T)) : typeof (T);
object setVal = value;
if (setType.Equals (typeof (IntPtr)))
Marshal.WriteIntPtr (ip.Native, fieldOffset, (IntPtr)setVal);
else if (setType.Equals (typeof (Byte)))
Marshal.WriteByte (ip.Native, fieldOffset, (byte)setVal);
else if (setType.Equals (typeof (Int16)))
Marshal.WriteInt16 (ip.Native, fieldOffset, (Int16)setVal);
else if (setType.Equals (typeof (Int32)))
Marshal.WriteInt32 (ip.Native, fieldOffset, (Int32)setVal);
else if (typeof (ICppObject).IsAssignableFrom (setType)) {
if (value == null) {
Marshal.WriteIntPtr (ip.Native, fieldOffset, IntPtr.Zero);
} else {
var cppobj = (ICppObject)value;
Marshal.WriteIntPtr (ip.Native, fieldOffset, (IntPtr)cppobj.Native);
}
} else {
throw new NotSupportedException ("Cannot write C++ fields of type " + setType.Name);
}
}
}
}
}

201
src/Mono.Cxxi/CppInstancePtr.cs

@ -1,201 +0,0 @@ @@ -1,201 +0,0 @@
//
// Mono.Cxxi.CppInstancePtr.cs: Represents a pointer to a native C++ instance
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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.Reflection.Emit;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Mono.Cxxi.Abi;
namespace Mono.Cxxi {
public struct CppInstancePtr : ICppObject {
private IntPtr ptr, native_vtptr;
private bool manage_memory;
private static Dictionary<IntPtr,int> managed_vtptr_to_gchandle_offset = null;
// Alloc a new C++ instance
internal CppInstancePtr (CppTypeInfo typeInfo, object managedWrapper)
{
// Under the hood, we're secretly subclassing this C++ class to store a
// handle to the managed wrapper.
int allocSize = typeInfo.GCHandleOffset + IntPtr.Size;
ptr = Marshal.AllocHGlobal (allocSize);
// NOTE: native_vtptr will be set later after native ctor is called
native_vtptr = IntPtr.Zero;
// zero memory for sanity
// FIXME: This should be an initblk
byte[] zeroArray = new byte [allocSize];
Marshal.Copy (zeroArray, 0, ptr, allocSize);
IntPtr handlePtr = MakeGCHandle (managedWrapper);
Marshal.WriteIntPtr (ptr, typeInfo.GCHandleOffset, handlePtr);
manage_memory = true;
}
// Alloc a new C++ instance when there is no managed wrapper.
internal CppInstancePtr (int nativeSize)
{
ptr = Marshal.AllocHGlobal (nativeSize);
native_vtptr = IntPtr.Zero;
manage_memory = true;
}
// Gets a casted CppInstancePtr
internal CppInstancePtr (CppInstancePtr instance, int offset)
{
// FIXME: On NET_4_0 use IntPtr.Add
ptr = new IntPtr (instance.Native.ToInt64 () + offset);
native_vtptr = IntPtr.Zero;
manage_memory = false;
}
// Get a CppInstancePtr for an existing C++ instance from an IntPtr
public CppInstancePtr (IntPtr native)
{
if (native == IntPtr.Zero)
throw new ArgumentOutOfRangeException ("native cannot be null pointer");
ptr = native;
native_vtptr = IntPtr.Zero;
manage_memory = false;
}
// Fulfills ICppObject requirement
public CppInstancePtr (CppInstancePtr copy)
{
this.ptr = copy.ptr;
this.native_vtptr = copy.native_vtptr;
this.manage_memory = copy.manage_memory;
}
// Provide casts to/from IntPtr:
public static implicit operator CppInstancePtr (IntPtr native)
{
return new CppInstancePtr (native);
}
// cast from CppInstancePtr -> IntPtr is explicit because we lose information
public static explicit operator IntPtr (CppInstancePtr ip)
{
return ip.Native;
}
public IntPtr Native {
get {
if (ptr == IntPtr.Zero)
throw new ObjectDisposedException ("CppInstancePtr");
return ptr;
}
}
// Internal for now to prevent attempts to read vtptr from non-virtual class
internal IntPtr NativeVTable {
get {
if (native_vtptr == IntPtr.Zero) {
// For pointers from native code...
// Kludge! CppInstancePtr doesn't know whether this class is virtual or not, but we'll just assume that either
// way it's at least sizeof(void*) and read what would be the vtptr anyway. Supposedly, if it's not virtual,
// the wrappers won't use this field anyway...
native_vtptr = Marshal.ReadIntPtr (ptr);
}
return native_vtptr;
}
set {
native_vtptr = value;
}
}
CppInstancePtr ICppObject.Native {
get { return this; }
}
public bool IsManagedAlloc {
get { return manage_memory; }
}
internal static void RegisterManagedVTable (VTable vtable)
{
if (managed_vtptr_to_gchandle_offset == null)
managed_vtptr_to_gchandle_offset = new Dictionary<IntPtr, int> ();
managed_vtptr_to_gchandle_offset [vtable.Pointer] = vtable.TypeInfo.GCHandleOffset;
}
internal static IntPtr MakeGCHandle (object managedWrapper)
{
// TODO: Dispose() should probably be called at some point on this GCHandle.
GCHandle handle = GCHandle.Alloc (managedWrapper, GCHandleType.Normal);
return GCHandle.ToIntPtr (handle);
}
// This might be made public, but in this form it only works for classes with vtables.
// Returns null if the native ptr passed in does not appear to be a managed instance.
// (i.e. its vtable ptr is not in managed_vtptr_to_gchandle_offset)
internal static T ToManaged<T> (IntPtr native) where T : class
{
if (managed_vtptr_to_gchandle_offset == null)
return null;
int gchOffset;
if (!managed_vtptr_to_gchandle_offset.TryGetValue (Marshal.ReadIntPtr (native), out gchOffset))
return null;
return ToManaged<T> (native, gchOffset);
}
// WARNING! This method is not safe. DO NOT call
// if we do not KNOW that this instance is managed.
internal static T ToManaged<T> (IntPtr native, int nativeSize) where T : class
{
IntPtr handlePtr = Marshal.ReadIntPtr (native, nativeSize);
GCHandle handle = GCHandle.FromIntPtr (handlePtr);
return handle.Target as T;
}
// TODO: Free GCHandle?
public void Dispose ()
{
if (manage_memory && ptr != IntPtr.Zero)
Marshal.FreeHGlobal (ptr);
ptr = IntPtr.Zero;
manage_memory = false;
}
}
}

139
src/Mono.Cxxi/CppLibrary.cs

@ -1,139 +0,0 @@ @@ -1,139 +0,0 @@
//
// Mono.Cxxi.CppLibrary.cs: Represents a native C++ library for interop
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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.IO;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Reflection.Emit;
using Mono.Cxxi.Abi;
namespace Mono.Cxxi {
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 InlineMethods InlineMethodPolicy { get; private set; }
internal string name;
public string Name { get { return name; } }
static CppLibrary ()
{
AssemblyName assemblyName = new AssemblyName ("__CppLibraryImplAssembly");
string moduleName = "CppLibraryImplAssembly.dll";
interopAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly (assemblyName, AssemblyBuilderAccess.RunAndSave);
interopModule = interopAssembly.DefineDynamicModule (moduleName, moduleName, true);
}
public CppLibrary (string name)
: this (name, InlineMethods.NotPresent)
{
}
public CppLibrary (string name, InlineMethods inlinePolicy)
: this (name, ItaniumAbi.Instance, inlinePolicy)
{
//FIXME: Ideally we would auto-detect ABI here.
}
public CppLibrary (string name, CppAbi abi, InlineMethods inlinePolicy)
{
if (name == null)
throw new ArgumentNullException ("Name cannot be NULL.");
if (abi == null)
throw new ArgumentNullException ("Abi cannot be NULL.");
this.name = name;
this.Abi = abi;
this.InlineMethodPolicy = inlinePolicy;
}
// Mainly for debugging at this point
public static void SaveInteropAssembly ()
{
interopAssembly.Save ("CppLibraryImplAssembly.dll");
}
// For working with a class that you are not instantiating
// from managed code and where access to fields is not necessary
public Iface GetClass<Iface> (string className)
where Iface : ICppClass
{
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
// but where overriding virtual methods in managed code is not necessary
public Iface GetClass<Iface,NativeLayout> (string className)
where Iface : ICppClassInstantiatable
where NativeLayout : struct
{
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:
* + Instantiation
* + Field access
* + Virtual method overriding
*/
public Iface GetClass<Iface,NativeLayout,Managed> (string className)
where Iface : ICppClassOverridable<Managed>
where NativeLayout : struct
where Managed : ICppObject
{
var typeInfo = Abi.MakeTypeInfo (this, className, typeof (Iface), typeof (NativeLayout), typeof (Managed));
return (Iface)Abi.ImplementClass (typeInfo);
}
}
}

197
src/Mono.Cxxi/CppModifiers.cs

@ -1,197 +0,0 @@ @@ -1,197 +0,0 @@
//
// Mono.Cxxi.CppModifiers.cs: Abstracts a C++ type modifiers
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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.Text.RegularExpressions;
using Mono.Cxxi.Util;
namespace Mono.Cxxi {
public abstract class CppModifiers {
#pragma warning disable 0414
static int tmp;
#pragma warning restore
// This can be added to at runtime to support other modifiers
// The list should be prioritized, in that the first items should be modifiers that can potentially contain other modifiers
public static readonly Dictionary<string,Action<Match,List<CppModifiers>>> Tokenize = new Dictionary<string,Action<Match,List<CppModifiers>>> () {
{ "\\<(.*)\\>", (m,l) => l.AddFirst (m.Groups [1].Success && m.Groups [1].Value.Trim () != ""? new TemplateModifier (m.Groups [1].Value) : CppModifiers.Template) },
{ "\\[([^\\]]*)\\]", (m,l) => l.Add (m.Groups [1].Success && m.Groups [1].Value.Trim () != "" && int.TryParse (m.Groups [1].Value, out tmp) ? new ArrayModifier (int.Parse (m.Groups [1].Value)) : CppModifiers.Array) },
{ "\\bconst\\b", (m,l) => l.Add (CppModifiers.Const) },
{ "\\*", (m,l) => l.Add (CppModifiers.Pointer) },
{ "\\&", (m,l) => l.Add (CppModifiers.Reference) },
{ "\\bvolatile\\b", (m,l) => l.Add (CppModifiers.Volatile) },
{ "\\bunsigned\\b", (m,l) => l.Add (CppModifiers.Unsigned) },
{ "\\bsigned\\b", (m,l) => l.Add (CppModifiers.Signed) },
{ "\\bshort\\b", (m,l) => l.Add (CppModifiers.Short) },
{ "\\blong\\b", (m,l) => l.Add (CppModifiers.Long) }
};
private struct Token {
public Action<Match, List<CppModifiers>> action;
public Match match;
}
private static IEnumerable<Token> Tokenizer (string input) {
foreach (var token in Tokenize) {
Match match;
while ((match = Regex.Match (input, token.Key)) != null && match.Success) {
yield return new Token { match = match, action = token.Value };
input = input.Remove (match.Index, match.Length);
}
}
}
public static List<CppModifiers> Parse (string input)
{
List<CppModifiers> cpm = new List<CppModifiers> ();
var tokenizer = Tokenizer (input);
foreach (var token in tokenizer.OrderBy (t => t.match.Index))
token.action (token.match, cpm);
return cpm;
}
// removes any modifiers from the passed input
public static string Remove (string input)
{
foreach (var token in Tokenize)
input = Regex.Replace (input, token.Key, "");
return input;
}
// normalizes the order of order-agnostic modifiers
public static IEnumerable<CppModifiers> NormalizeOrder (IEnumerable<CppModifiers> modifiers)
{
var parts = modifiers.Transform (
For.AllInputsIn (CppModifiers.Unsigned, CppModifiers.Long).InAnyOrder ().Emit (new CppModifiers [] { CppModifiers.Unsigned, CppModifiers.Long }),
For.AllInputsIn (CppModifiers.Signed, CppModifiers.Long).InAnyOrder ().Emit (new CppModifiers [] { CppModifiers.Signed, CppModifiers.Long }),
For.AllInputsIn (CppModifiers.Unsigned, CppModifiers.Short).InAnyOrder ().Emit (new CppModifiers [] { CppModifiers.Unsigned, CppModifiers.Short }),
For.AllInputsIn (CppModifiers.Signed, CppModifiers.Short).InAnyOrder ().Emit (new CppModifiers [] { CppModifiers.Signed, CppModifiers.Short }),
For.UnmatchedInput<CppModifiers> ().Emit (cppmod => new CppModifiers [] { cppmod })
);
foreach (var array in parts)
foreach (var item in array)
yield return item;
}
public override bool Equals (object obj)
{
return this == obj as CppModifiers;
}
public override int GetHashCode ()
{
return GetType ().GetHashCode ();
}
public static bool operator == (CppModifiers a, CppModifiers b)
{
if ((object)a == (object)b)
return true;
if ((object)a == null || (object)b == null)
return false;
return a.GetHashCode () == b.GetHashCode ();
}
public static bool operator != (CppModifiers a, CppModifiers b)
{
return !(a == b);
}
public static readonly CppModifiers Const = new ConstModifier ();
public static readonly CppModifiers Pointer = new PointerModifier ();
public static readonly CppModifiers Array = new ArrayModifier ();
public static readonly CppModifiers Reference = new ReferenceModifier ();
public static readonly CppModifiers Volatile = new VolatileModifier ();
public static readonly CppModifiers Signed = new SignedModifier ();
public static readonly CppModifiers Unsigned = new UnsignedModifier ();
public static readonly CppModifiers Short = new ShortModifier ();
public static readonly CppModifiers Long = new LongModifier ();
public static readonly CppModifiers Template = new TemplateModifier ();
// Add list of modifiers here:
public class ConstModifier : CppModifiers { public override string ToString () { return "const"; } }
public class PointerModifier : CppModifiers { public override string ToString () { return "*"; } }
public class ReferenceModifier : CppModifiers { public override string ToString () { return "&"; } }
public class VolatileModifier : CppModifiers { public override string ToString () { return "volatile"; } }
public class SignedModifier : CppModifiers { public override string ToString () { return "signed"; } }
public class UnsignedModifier : CppModifiers { public override string ToString () { return "unsigned"; } }
public class ShortModifier : CppModifiers { public override string ToString () { return "short"; } }
public class LongModifier : CppModifiers { public override string ToString () { return "long"; } }
public class ArrayModifier : CppModifiers {
public int? Size { get; set; }
public ArrayModifier ()
{
}
public ArrayModifier (int size) {
Size = size;
}
public override string ToString ()
{
return string.Format ("[{0}]", Size.HasValue? Size.ToString () : "");
}
}
public class TemplateModifier : CppModifiers {
public CppType [] Types { get; set; }
public TemplateModifier ()
{
}
public TemplateModifier (string types)
{
Types = Regex.Split (types, "(?<!\\<[^\\>]*),").Select (p => new CppType (p)).ToArray ();
}
public TemplateModifier (CppType [] types)
{
Types = types;
}
public override string ToString ()
{
return string.Format ("<{0}>", Types == null? "" : string.Join (", ", Types.Select (t => t.ToString ()).ToArray ()));
}
}
}
}

412
src/Mono.Cxxi/CppType.cs

@ -1,412 +0,0 @@ @@ -1,412 +0,0 @@
//
// Mono.Cxxi.CppType.cs: Abstracts a C++ type declaration
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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.Text;
using System.Text.RegularExpressions;
using System.Reflection;
using System.Collections.Generic;
using Mono.Cxxi.Util;
namespace Mono.Cxxi {
// These can be used anywhere a CppType could be used.
public enum CppTypes {
Unknown,
Class,
Struct,
Enum,
Union,
Void,
Bool,
Char,
Int,
Float,
Double,
WChar_T,
// for template type parameters
Typename
}
public struct CppType {
// FIXME: Passing these as delegates allows for the flexibility of doing processing on the
// type (i.e. to correctly mangle the function pointer arguments if the managed type is a delegate),
// however this does not make it very easy to override the default mappings at runtime.
public static List<Func<CppType,Type>> CppTypeToManagedMap = new List<Func<CppType, Type>> () {
(t) => (t.ElementType == CppTypes.Class ||
t.ElementType == CppTypes.Struct ||
(t.ElementType == CppTypes.Unknown && t.ElementTypeName != null)) &&
(t.Modifiers.Count (m => m == CppModifiers.Pointer) == 1 ||
t.Modifiers.Contains (CppModifiers.Reference))? typeof (ICppObject) : null,
// void* gets IntPtr
(t) => t.ElementType == CppTypes.Void && t.Modifiers.Contains (CppModifiers.Pointer)? typeof (IntPtr) : null,
// single pointer to char gets string
// same with wchar_t (needs marshaling attribute though!)
(t) => (t.ElementType == CppTypes.Char || t.ElementType == CppTypes.WChar_T) && t.Modifiers.Count (m => m == CppModifiers.Pointer) == 1? typeof (string) : null,
// pointer to pointer to char gets string[]
(t) => t.ElementType == CppTypes.Char && t.Modifiers.Count (m => m == CppModifiers.Pointer) == 2? typeof (string).MakeArrayType () : null,
// arrays
(t) => t.Modifiers.Contains (CppModifiers.Array) && (t.Subtract (CppModifiers.Array).ToManagedType () != null)? t.Subtract (CppModifiers.Array).ToManagedType ().MakeArrayType () : null,
// convert single pointers to primatives to managed byref
(t) => t.Modifiers.Count (m => m == CppModifiers.Pointer) == 1 && (t.Subtract (CppModifiers.Pointer).ToManagedType () != null)? t.Subtract (CppModifiers.Pointer).ToManagedType ().MakeByRefType () : null,
// more than one level of indirection gets IntPtr type
(t) => t.Modifiers.Contains (CppModifiers.Pointer)? typeof (IntPtr) : null,
(t) => t.Modifiers.Contains (CppModifiers.Reference) && (t.Subtract (CppModifiers.Reference).ToManagedType () != null)? t.Subtract (CppModifiers.Reference).ToManagedType ().MakeByRefType () : null,
(t) => t.ElementType == CppTypes.Int && t.Modifiers.Contains (CppModifiers.Short) && t.Modifiers.Contains (CppModifiers.Unsigned)? typeof (ushort) : null,
(t) => t.ElementType == CppTypes.Int && t.Modifiers.Count (m => m == CppModifiers.Long) == 2 && t.Modifiers.Contains (CppModifiers.Unsigned)? typeof (ulong) : null,
(t) => t.ElementType == CppTypes.Int && t.Modifiers.Contains (CppModifiers.Short)? typeof (short) : null,
(t) => t.ElementType == CppTypes.Int && t.Modifiers.Count (m => m == CppModifiers.Long) == 2? typeof (long) : null,
(t) => t.ElementType == CppTypes.Int && t.Modifiers.Contains (CppModifiers.Unsigned)? typeof (uint) : null,
(t) => t.ElementType == CppTypes.Void? typeof (void) : null,
(t) => t.ElementType == CppTypes.Bool? typeof (bool) : null,
(t) => t.ElementType == CppTypes.Char? typeof (char) : null,
(t) => t.ElementType == CppTypes.Int? typeof (int) : null,
(t) => t.ElementType == CppTypes.Float? typeof (float) : null,
(t) => t.ElementType == CppTypes.Double? typeof (double) : null
};
public static List<Func<Type,CppType>> ManagedToCppTypeMap = new List<Func<Type,CppType>> () {
(t) => typeof (void).Equals (t) ? CppTypes.Void : CppTypes.Unknown,
(t) => typeof (bool).Equals (t) ? CppTypes.Bool : CppTypes.Unknown,
(t) => typeof (char).Equals (t) ? CppTypes.Char : CppTypes.Unknown,
(t) => typeof (int).Equals (t) ? CppTypes.Int : CppTypes.Unknown,
(t) => typeof (float).Equals (t) ? CppTypes.Float : CppTypes.Unknown,
(t) => typeof (double).Equals (t)? CppTypes.Double : CppTypes.Unknown,
(t) => typeof (short).Equals (t) ? new CppType (CppModifiers.Short, CppTypes.Int) : CppTypes.Unknown,
(t) => typeof (long).Equals (t) ? new CppType (CppModifiers.Long, CppTypes.Int) : CppTypes.Unknown,
(t) => typeof (uint).Equals (t) ? new CppType (CppModifiers.Unsigned, CppTypes.Int) : CppTypes.Unknown,
(t) => typeof (ushort).Equals (t)? new CppType (CppModifiers.Unsigned, CppModifiers.Short, CppTypes.Int) : CppTypes.Unknown,
(t) => typeof (ulong).Equals (t)? new CppType (CppModifiers.Unsigned, CppModifiers.Long, CppTypes.Int) : CppTypes.Unknown,
(t) => typeof (IntPtr).Equals (t)? new CppType (CppTypes.Void, CppModifiers.Pointer) : CppTypes.Unknown,
(t) => typeof (UIntPtr).Equals(t)? new CppType (CppTypes.Void, CppModifiers.Pointer) : CppTypes.Unknown,
// strings mangle as "const char*" by default
(t) => typeof (string).Equals (t)? new CppType (CppModifiers.Const, CppTypes.Char, CppModifiers.Pointer) : CppTypes.Unknown,
// StringBuilder gets "char*"
(t) => typeof (StringBuilder).Equals (t)? new CppType (CppTypes.Char, CppModifiers.Pointer) : CppTypes.Unknown,
// delegate types get special treatment
(t) => typeof (Delegate).IsAssignableFrom (t)? CppType.ForDelegate (t) : CppTypes.Unknown,
// ... and of course ICppObjects do too!
// FIXME: We assume c++ class not struct. There should probably be an attribute
// we can apply to managed wrappers to indicate if the underlying C++ type is actually declared struct
(t) => typeof (ICppObject).IsAssignableFrom (t)? new CppType (CppTypes.Class, Regex.Replace (t.Name, "`\\d\\d?$", ""), CppModifiers.Pointer) : CppTypes.Unknown,
// value types or interface (ICppClass) that don't fit the above categories...
(t) => t.IsValueType || t.IsInterface? new CppType (CppTypes.Class, Regex.Replace (t.Name, "`\\d\\d?$", "")) : CppTypes.Unknown,
// convert managed type modifiers to C++ type modifiers like so:
// ref types to C++ references
// pointer types to C++ pointers
// array types to C++ arrays
(t) => {
var cppType = CppType.ForManagedType (t.GetElementType () ?? (t.IsGenericType? t.GetGenericTypeDefinition () : null));
if (t.IsByRef) cppType.Modifiers.Add (CppModifiers.Reference);
if (t.IsPointer) cppType.Modifiers.Add (CppModifiers.Pointer);
if (t.IsArray) cppType.Modifiers.Add (CppModifiers.Array);
if (t.IsGenericType) cppType.Modifiers.Add (new CppModifiers.TemplateModifier (t.GetGenericArguments ().Select (g => CppType.ForManagedType (g)).ToArray ()));
return cppType;
}
};
public CppTypes ElementType { get; set; }
// if the ElementType is Union, Struct, Class, or Enum
// this will contain the name of said type
public string ElementTypeName { get; set; }
// may be null, and will certainly be null if ElementTypeName is null
public string [] Namespaces { get; set; }
// this is initialized lazily to avoid unnecessary heap
// allocations if possible
private List<CppModifiers> internalModifiers;
public List<CppModifiers> Modifiers {
get {
if (internalModifiers == null)
internalModifiers = new List<CppModifiers> ();
return internalModifiers;
}
}
// here, you can pass in things like "const char*" or "const Foo * const"
// DISCLAIMER: this is really just for convenience for now, and is not meant to be able
// to parse even moderately complex C++ type declarations.
public CppType (string type) : this (Regex.Split (type, "\\s+(?![^\\>]*\\>|[^\\[\\]]*\\])"))
{
}
public CppType (params object[] cppTypeSpec) : this ()
{
ElementType = CppTypes.Unknown;
ElementTypeName = null;
Namespaces = null;
internalModifiers = null;
Parse (cppTypeSpec);
}
// FIXME: This makes no attempt to actually verify that the parts compose a valid C++ type.
private void Parse (object [] parts)
{
foreach (object part in parts) {
if (part is CppModifiers) {
Modifiers.Add ((CppModifiers)part);
continue;
}
if (part is CppModifiers [] || part is IEnumerable<CppModifiers>) {
Modifiers.AddRange ((IEnumerable<CppModifiers>)part);
continue;
}
if (part is CppTypes) {
ElementType = (CppTypes)part;
continue;
}
Type managedType = part as Type;
if (managedType != null) {
CppType mapped = CppType.ForManagedType (managedType);
CopyTypeFrom (mapped);
continue;
}
string strPart = part as string;
if (strPart != null) {
var parsed = CppModifiers.Parse (strPart);
if (parsed.Count > 0) {
if (internalModifiers == null)
internalModifiers = parsed;
else
internalModifiers.AddRange (parsed);
strPart = CppModifiers.Remove (strPart);
}
// if we have something left, it must be a type name
strPart = strPart.Trim ();
if (strPart != "") {
string [] qualifiedName = strPart.Split (new string [] { "::" }, StringSplitOptions.RemoveEmptyEntries);
int numNamespaces = qualifiedName.Length - 1;
if (numNamespaces > 0) {
Namespaces = new string [numNamespaces];
for (int i = 0; i < numNamespaces; i++)
Namespaces [i] = qualifiedName [i];
}
strPart = qualifiedName [numNamespaces];
// FIXME: Fix this mess
switch (strPart) {
case "void":
ElementType = CppTypes.Void;
break;
case "bool":
ElementType = CppTypes.Bool;
break;
case "char":
ElementType = CppTypes.Char;
break;
case "int":
ElementType = CppTypes.Int;
break;
case "float":
ElementType = CppTypes.Float;
break;
case "double":
ElementType = CppTypes.Double;
break;
default:
// otherwise it is the element type name...
ElementTypeName = strPart;
break;
}
}
}
}
}
// Applies the element type of the passed instance
// and combines its modifiers into this instance.
// Use when THIS instance may have attributes you want,
// but want the element type of the passed instance.
public CppType CopyTypeFrom (CppType type)
{
ElementType = type.ElementType;
ElementTypeName = type.ElementTypeName;
Namespaces = type.Namespaces;
List<CppModifiers> oldModifiers = internalModifiers;
internalModifiers = type.internalModifiers;
if (oldModifiers != null)
Modifiers.AddRange (oldModifiers);
return this;
}
// Removes the modifiers on the passed instance from this instance
public CppType Subtract (CppType type)
{
if (internalModifiers == null)
return this;
CppType current = this;
foreach (var modifier in ((IEnumerable<CppModifiers>)type.Modifiers).Reverse ())
current = current.Subtract (modifier);
return current;
}
public CppType Subtract (CppModifiers modifier)
{
CppType newType = this;
newType.internalModifiers = new List<CppModifiers> (((IEnumerable<CppModifiers>)newType.Modifiers).Reverse ().WithoutFirst (modifier));
return newType;
}
// note: this adds modifiers "backwards" (it is mainly used by the generator)
public CppType Modify (CppModifiers modifier)
{
CppType newType = this;
var newModifier = new CppModifiers [] { modifier };
if (newType.internalModifiers != null)
newType.internalModifiers.AddFirst (newModifier);
else
newType.internalModifiers = new List<CppModifiers> (newModifier);
return newType;
}
public override bool Equals (object obj)
{
if (obj == null)
return false;
if (obj.GetType () == typeof (CppTypes))
return Equals (new CppType (obj));
if (obj.GetType () != typeof (CppType))
return false;
CppType other = (CppType)obj;
return (((internalModifiers == null || !internalModifiers.Any ()) &&
(other.internalModifiers == null || !other.internalModifiers.Any ())) ||
(internalModifiers != null && other.internalModifiers != null &&
CppModifiers.NormalizeOrder (internalModifiers).SequenceEqual (CppModifiers.NormalizeOrder (other.internalModifiers)))) &&
(((Namespaces == null || !Namespaces.Any ()) &&
(other.Namespaces == null || !other.Namespaces.Any ())) ||
(Namespaces != null && other.Namespaces != null &&
Namespaces.SequenceEqual (other.Namespaces))) &&
ElementType == other.ElementType &&
ElementTypeName == other.ElementTypeName;
}
public override int GetHashCode ()
{
unchecked {
return (internalModifiers != null? internalModifiers.SequenceHashCode () : 0) ^
ElementType.GetHashCode () ^
(Namespaces != null? Namespaces.SequenceHashCode () : 0) ^
(ElementTypeName != null? ElementTypeName.GetHashCode () : 0);
}
}
public override string ToString ()
{
StringBuilder cppTypeString = new StringBuilder ();
if (ElementType != CppTypes.Unknown && ElementType != CppTypes.Typename)
cppTypeString.Append (Enum.GetName (typeof (CppTypes), ElementType).ToLower ()).Append (' ');
if (Namespaces != null) {
foreach (var ns in Namespaces)
cppTypeString.Append (ns).Append ("::");
}
if (ElementTypeName != null && ElementType != CppTypes.Typename)
cppTypeString.Append (ElementTypeName);
if (internalModifiers != null) {
foreach (var modifier in internalModifiers)
cppTypeString.Append (' ').Append (modifier.ToString ());
}
return cppTypeString.ToString ().Trim ();
}
public Type ToManagedType ()
{
CppType me = this;
Type mappedType = (from checkType in CppTypeToManagedMap
where checkType (me) != null
select checkType (me)).FirstOrDefault ();
return mappedType;
}
public static CppType ForManagedType (Type type)
{
CppType mappedType = (from checkType in ManagedToCppTypeMap
where checkType (type).ElementType != CppTypes.Unknown
select checkType (type)).FirstOrDefault ();
return mappedType;
}
public static CppType ForDelegate (Type delType)
{
if (!typeof (Delegate).IsAssignableFrom (delType))
throw new ArgumentException ("Argument must be a delegate type");
throw new NotImplementedException ();
}
public static implicit operator CppType (CppTypes type) {
return new CppType (type);
}
}
}

430
src/Mono.Cxxi/CppTypeInfo.cs

@ -1,430 +0,0 @@ @@ -1,430 +0,0 @@
//
// Mono.Cxxi.CppTypeInfo.cs: Type metadata for C++ types
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using Mono.Cxxi.Abi;
using Mono.Cxxi.Util;
namespace Mono.Cxxi {
public enum BaseVirtualMethods {
// Prepends this base's virtual methods to the primary vtable
PrependPrimary,
// Appends this base's virtual methods to the primary vtable
AppendPrimary,
// Creates a new out-of-band vtable for this base's virtual methods
NewVTable,
}
// NOTE: As AddBase is called, properties change.
// TypeComplete indicates when the dust has settled.
public class CppTypeInfo {
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 WrapperType { get; private set; }
// read only versions:
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; }
// backing lists:
protected List<PInvokeSignature> virtual_methods;
protected LazyGeneratedList<Type> vt_delegate_types;
protected LazyGeneratedList<Delegate> vt_overrides;
protected List<CppTypeInfo> base_classes;
protected List<int> vtable_index_adjustments;
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 gchandle_offset_delta;
private VTable lazy_vtable;
internal EmitInfo emit_info; // <- will be null when the type is done being emitted
public bool TypeComplete { get { return emit_info == null; } }
#region Construction
public CppTypeInfo (CppLibrary lib, string typeName, Type interfaceType, Type nativeLayout, Type/*?*/ wrapperType)
: this ()
{
Library = lib;
TypeName = typeName;
InterfaceType = interfaceType;
NativeLayout = nativeLayout;
WrapperType = wrapperType;
virtual_methods = new List<PInvokeSignature> (Library.Abi.GetVirtualMethodSlots (this, interfaceType));
VirtualMethods = new ReadOnlyCollection<PInvokeSignature> (virtual_methods);
vt_delegate_types = new LazyGeneratedList<Type> (virtual_methods.Count, i => DelegateTypeCache.GetDelegateType (virtual_methods [i]));
VTableDelegateTypes = new ReadOnlyCollection<Type> (vt_delegate_types);
vt_overrides = new LazyGeneratedList<Delegate> (virtual_methods.Count, i => Library.Abi.GetManagedOverrideTrampoline (this, i));
VTableOverrides = new ReadOnlyCollection<Delegate> (vt_overrides);
vtable_index_adjustments = new List<int> (virtual_methods.Count);
if (nativeLayout != null)
native_size_without_padding = nativeLayout.GetFields ().Any ()? Marshal.SizeOf (nativeLayout) : 0;
}
protected CppTypeInfo ()
{
base_classes = new List<CppTypeInfo> ();
BaseClasses = new ReadOnlyCollection<CppTypeInfo> (base_classes);
field_offset_padding_without_vtptr = 0;
gchandle_offset_delta = 0;
IsPrimaryBase = true;
BaseVTableSlots = 0;
lazy_vtable = null;
emit_info = new EmitInfo ();
}
// The contract for Clone is that, if TypeComplete, working with the clone *through the public
// interface* is guaranteed not to affect the original. Note that any subclassses
// have access to protected stuff that is not covered by this guarantee.
public virtual CppTypeInfo Clone ()
{
return this.MemberwiseClone () as CppTypeInfo;
}
#endregion
#region Type Layout
public virtual int Alignment {
get { return IntPtr.Size; }
}
// the extra padding to allocate at the top of the class before the fields begin
// (by default, just the vtable pointer)
public virtual int FieldOffsetPadding {
get { return field_offset_padding_without_vtptr + (virtual_methods.Count != 0? IntPtr.Size : 0); }
}
public virtual int NativeSize {
get {
var basesize = native_size_without_padding + FieldOffsetPadding;
return basesize + (basesize % Alignment);
}
}
public virtual int GCHandleOffset {
get { return NativeSize + gchandle_offset_delta; }
}
public void AddBase (CppTypeInfo baseType)
{
// by default, only the primary base shares the subclass's primary vtable
AddBase (baseType, base_classes.Count == 0 ? BaseVirtualMethods.PrependPrimary : BaseVirtualMethods.NewVTable);
}
protected virtual void AddBase (CppTypeInfo baseType, BaseVirtualMethods location)
{
if (TypeComplete)
return;
var baseVMethodCount = baseType.virtual_methods.Count;
baseType = baseType.Clone ();
switch (location) {
case BaseVirtualMethods.PrependPrimary:
for (int i = 0; i < baseVMethodCount; i++)
virtual_methods.Insert (BaseVTableSlots + i, baseType.virtual_methods [i]);
gchandle_offset_delta = baseType.gchandle_offset_delta;
BaseVTableSlots += baseVMethodCount;
vt_delegate_types.Add (baseVMethodCount);
vt_overrides.Add (baseVMethodCount);
break;
case BaseVirtualMethods.AppendPrimary:
for (int i = 0; i < baseVMethodCount; i++)
virtual_methods.Add (baseType.virtual_methods [i]);
gchandle_offset_delta = baseType.gchandle_offset_delta;
vt_delegate_types.Add (baseVMethodCount);
vt_overrides.Add (baseVMethodCount);
break;
case BaseVirtualMethods.NewVTable:
baseType.IsPrimaryBase = (base_classes.Count == 0);
// offset all previously added bases
foreach (var previousBase in base_classes)
previousBase.gchandle_offset_delta += baseType.NativeSize;
// offset derived (this) type's gchandle
gchandle_offset_delta += baseType.GCHandleOffset;
baseType.gchandle_offset_delta += native_size_without_padding + CountBases (b => !b.IsPrimaryBase) * IntPtr.Size;
// ensure managed override tramps will be regenerated with correct gchandle offset
baseType.vt_overrides = new LazyGeneratedList<Delegate> (baseType.virtual_methods.Count, i => Library.Abi.GetManagedOverrideTrampoline (baseType, i));
baseType.VTableOverrides = new ReadOnlyCollection<Delegate> (baseType.vt_overrides);
baseType.lazy_vtable = null;
break;
}
base_classes.Add (baseType);
field_offset_padding_without_vtptr += baseType.native_size_without_padding +
(location == BaseVirtualMethods.NewVTable? baseType.FieldOffsetPadding : baseType.field_offset_padding_without_vtptr);
}
public virtual void CompleteType ()
{
if (emit_info == null)
return;
foreach (var baseClass in base_classes)
baseClass.CompleteType ();
emit_info = null;
RemoveVTableDuplicates ();
}
public virtual CppType GetMangleType ()
{
var mangleType = Library.Abi.GetMangleType (InterfaceType, InterfaceType);
mangleType.ElementTypeName = TypeName;
return mangleType;
}
public int CountBases (Func<CppTypeInfo, bool> predicate)
{
int count = 0;
foreach (var baseClass in base_classes) {
count += baseClass.CountBases (predicate);
count += predicate (baseClass)? 1 : 0;
}
return count;
}
#endregion
#region Casting
protected virtual CppTypeInfo GetCastInfo (Type sourceType, Type targetType, out int offset)
{
offset = 0;
if (WrapperType.Equals (targetType)) {
// check for downcast (base type -> this type)
foreach (var baseClass in base_classes) {
if (baseClass.WrapperType.Equals (sourceType)) {
return baseClass;
}
offset -= baseClass.NativeSize;
}
} else if (WrapperType.IsAssignableFrom (sourceType)) {
// check for upcast (this type -> base type)
foreach (var baseClass in base_classes) {
if (baseClass.WrapperType.Equals (targetType)) {
return baseClass;
}
offset += baseClass.NativeSize;
}
} else {
throw new ArgumentException ("Either source type or target type must be equal to this wrapper type.");
}
throw new InvalidCastException ("Cannot cast an instance of " + sourceType + " to " + targetType);
}
public virtual CppInstancePtr Cast (ICppObject instance, Type targetType)
{
int offset;
var baseTypeInfo = GetCastInfo (instance.GetType (), targetType, out offset);
var result = new CppInstancePtr (instance.Native, offset);
if (offset > 0 && instance.Native.IsManagedAlloc && baseTypeInfo.HasVTable) {
// we might need to paste the managed base-in-derived vtptr here --also inits native_vtptr
baseTypeInfo.VTable.InitInstance (ref result);
}
return result;
}
public virtual TTarget Cast<TTarget> (ICppObject instance) where TTarget : class
{
TTarget result;
var ptr = Cast (instance, typeof (TTarget));
// Check for existing instance based on vtable ptr
result = CppInstancePtr.ToManaged<TTarget> (ptr.Native);
// Create a new wrapper if necessary
if (result == null)
result = Activator.CreateInstance (typeof (TTarget), ptr) as TTarget;
return result;
}
public virtual void InitNonPrimaryBase (ICppObject baseInDerived, ICppObject derived, Type baseType)
{
int offset;
var baseTypeInfo = GetCastInfo (derived.GetType (), baseType, out offset);
Marshal.WriteIntPtr (baseInDerived.Native.Native, baseTypeInfo.GCHandleOffset, CppInstancePtr.MakeGCHandle (baseInDerived));
}
#endregion
#region V-Table
public virtual bool HasVTable {
get { return VirtualMethods.Any (); }
}
public virtual VTable VTable {
get {
CompleteType ();
if (!HasVTable)
return null;
if (lazy_vtable == null)
lazy_vtable = new VTable (this);
return lazy_vtable;
}
}
// the padding in the data pointed to by the vtable pointer before the list of function pointers starts
public virtual int VTableTopPadding {
get { return 0; }
}
// the amount of extra room alloc'd after the function pointer list of the vtbl
public virtual int VTableBottomPadding {
get { return 0; }
}
public virtual T GetAdjustedVirtualCall<T> (CppInstancePtr instance, int derivedVirtualMethodIndex)
where T : class /* Delegate */
{
var base_adjusted = BaseVTableSlots + derivedVirtualMethodIndex;
return VTable.GetVirtualCallDelegate<T> (instance, base_adjusted + vtable_index_adjustments [base_adjusted]);
}
protected virtual void RemoveVTableDuplicates ()
{
// check that any virtual methods overridden in a subclass are only included once
var vsignatures = new Dictionary<MethodSignature,PInvokeSignature> (MethodSignature.EqualityComparer);
var adjustment = 0;
for (int i = 0; i < virtual_methods.Count; i++) {
vtable_index_adjustments.Add (adjustment);
var sig = virtual_methods [i];
if (sig == null)
continue;
PInvokeSignature existing;
if (vsignatures.TryGetValue (sig, out existing)) {
OnVTableDuplicate (ref i, ref adjustment, sig, existing);
} else {
vsignatures.Add (sig, sig);
}
}
}
protected virtual bool OnVTableDuplicate (ref int iter, ref int adj, PInvokeSignature sig, PInvokeSignature dup)
{
// This predicate ensures that duplicates are only removed
// if declared in different classes (i.e. overridden methods).
// We usually want to allow the same exact virtual methods to appear
// multiple times, in the case of nonvirtual diamond inheritance, for example.
if (!sig.OrigMethod.Equals (dup.OrigMethod)) {
virtual_methods.RemoveAt (iter--);
vt_overrides.Remove (1);
vt_delegate_types.Remove (1);
adj--;
return true;
}
return false;
}
#endregion
}
// This is used internally by CppAbi:
internal class DummyCppTypeInfo : CppTypeInfo {
public CppTypeInfo BaseTypeInfo { get; set; }
protected override void AddBase (CppTypeInfo baseType, BaseVirtualMethods location)
{
BaseTypeInfo = baseType;
}
}
}

63
src/Mono.Cxxi/Interfaces.cs

@ -1,63 +0,0 @@ @@ -1,63 +0,0 @@
//
// Mono.Cxxi.Interfaces.cs
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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 Mono.Cxxi.Abi;
namespace Mono.Cxxi {
// The contract for ICppObject requires implementations to have the following constructors:
// + A public constructor that takes CppInstancePtr (native constructor)
// + A public constructor that takes CppTypeInfo, and as its sole operation,
// calls AddBase on that passed CppTypeInfo, passing its own typeinfo (subclass constructor)
// NOTE: It is important that the subclass constructor have no side effects.
// All constructors for wrappers of native subclasses must call the subclass constructor for the
// wrappers of their base class(es).
public interface ICppObject : IDisposable {
CppInstancePtr Native { get; }
}
public interface ICppClass {
CppTypeInfo TypeInfo { get; }
}
// This should go without saying, but the C++ class must have a constructor
// if it is to be instantiatable.
public interface ICppClassInstantiatable : ICppClass {
CppInstancePtr Alloc ();
}
// 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<TManaged> : ICppClassInstantiatable
/* where TManaged : ICppObject */
{
CppInstancePtr Alloc (TManaged managed);
}
}

102
src/Mono.Cxxi/Makefile.am

@ -1,102 +0,0 @@ @@ -1,102 +0,0 @@
EXTRA_DIST = m4/expansions.m4
if ENABLE_DEBUG
ASSEMBLY_COMPILER_COMMAND = $(GMCS)
ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize- -debug "-define:DEBUG"
BUILD_DIR = $(top_srcdir)/bin/Debug
ASSEMBLY = $(BUILD_DIR)/Mono.Cxxi.dll
ASSEMBLY_MDB = $(ASSEMBLY).mdb
MONO_CXXI_DLL_MDB=$(BUILD_DIR)/Mono.Cxxi.dll.mdb
endif
if ENABLE_RELEASE
ASSEMBLY_COMPILER_COMMAND = $(GMCS)
ASSEMBLY_COMPILER_FLAGS = -noconfig -codepage:utf8 -warn:4 -optimize+
BUILD_DIR = $(top_srcdir)/bin/Release
ASSEMBLY = $(BUILD_DIR)/Mono.Cxxi.dll
ASSEMBLY_MDB =
MONO_VISUALC_INTEROP_DLL_MDB=
endif
COMPILE_TARGET = library
PROJECT_REFERENCES =
AL=al2
SATELLITE_ASSEMBLY_NAME=$(notdir $(basename $(ASSEMBLY))).resources.dll
PROGRAMFILES = \
$(MONO_CXXI_DLL_MDB)
LINUX_PKGCONFIG = \
$(MONO_CXXI_PC)
RESGEN=resgen2
all: $(ASSEMBLY) $(PROGRAMFILES) $(LINUX_PKGCONFIG)
FILES = \
Abi/CppAbi.cs \
Abi/EmitInfo.cs \
Abi/Impl/ItaniumAbi.cs \
Abi/Impl/ItaniumTypeInfo.cs \
Abi/Impl/MsvcAbi.cs \
Abi/MethodType.cs \
Abi/SymbolResolver.cs \
Abi/VTable.cs \
AssemblyInfo.cs \
Attributes.cs \
CppField.cs \
CppInstancePtr.cs \
CppLibrary.cs \
CppModifiers.cs \
CppType.cs \
CppTypeInfo.cs \
Interfaces.cs \
Util/DelegateTypeCache.cs \
Util/IEnumerableTransform.cs \
Util/LazyGeneratedList.cs \
Util/MethodSignature.cs \
Util/ReflectionHelper.cs
DATA_FILES =
RESOURCES =
EXTRAS = \
Abi \
Abi/Impl \
Util \
mono.cxxi.pc.in
REFERENCES = \
System \
System.Core
DLL_REFERENCES =
CLEANFILES = $(PROGRAMFILES) $(LINUX_PKGCONFIG)
include $(top_srcdir)/Makefile.include
MONO_CXXI_PC = $(BUILD_DIR)/mono.cxxi.pc
$(eval $(call emit-deploy-wrapper,MONO_CXXI_PC,mono.cxxi.pc))
$(eval $(call emit_resgen_targets))
$(build_xamlg_list): %.xaml.g.cs: %.xaml
xamlg '$<'
$(ASSEMBLY_MDB): $(ASSEMBLY)
$(ASSEMBLY): $(build_sources) $(build_resources) $(build_datafiles) $(DLL_REFERENCES) $(PROJECT_REFERENCES) $(build_xamlg_list) $(build_satellite_assembly_list)
mkdir -p $(shell dirname $(ASSEMBLY))
$(ASSEMBLY_COMPILER_COMMAND) $(ASSEMBLY_COMPILER_FLAGS) -out:$(ASSEMBLY) -target:$(COMPILE_TARGET) $(build_sources_embed) $(build_resources_embed) $(build_references_ref)

116
src/Mono.Cxxi/Mono.Cxxi.csproj

@ -1,116 +0,0 @@ @@ -1,116 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<ProjectGuid>{4A864586-93C5-4DC1-8A80-F094A88506D7}</ProjectGuid>
<OutputType>Library</OutputType>
<SchemaVersion>2.0</SchemaVersion>
<RootNamespace>Mono.Cxxi</RootNamespace>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>2.0</OldToolsVersion>
<PublishUrl>http://localhost/Mono.VisualC.Interop/</PublishUrl>
<Install>true</Install>
<InstallFrom>Web</InstallFrom>
<UpdateEnabled>true</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>true</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<AssemblyName>Mono.Cxxi</AssemblyName>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<AssemblyName>CPPInterop</AssemblyName>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="CppLibrary.cs" />
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Abi\CppAbi.cs" />
<Compile Include="Interfaces.cs" />
<Compile Include="Attributes.cs" />
<Compile Include="CppInstancePtr.cs" />
<Compile Include="CppField.cs" />
<Compile Include="Abi\VTable.cs" />
<Compile Include="Abi\MethodType.cs" />
<Compile Include="Abi\Impl\ItaniumAbi.cs" />
<Compile Include="Abi\Impl\MsvcAbi.cs" />
<Compile Include="CppType.cs" />
<Compile Include="CppTypeInfo.cs" />
<Compile Include="Util\IEnumerableTransform.cs" />
<Compile Include="Util\LazyGeneratedList.cs" />
<Compile Include="Util\DelegateTypeCache.cs" />
<Compile Include="Util\ReflectionHelper.cs" />
<Compile Include="Util\MethodSignature.cs" />
<Compile Include="CppModifiers.cs" />
<Compile Include="Abi\Impl\ItaniumTypeInfo.cs" />
<Compile Include="Abi\EmitInfo.cs" />
<Compile Include="Abi\SymbolResolver.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ProjectExtensions>
<MonoDevelop>
<Properties>
<MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="true" RelativeMakefileName="Makefile.am" SyncReferences="true" IsAutotoolsProject="true" RelativeConfigureInPath="../..">
<BuildFilesVar Sync="true" Name="FILES" />
<DeployFilesVar />
<ResourcesVar Sync="true" Name="RESOURCES" />
<OthersVar />
<GacRefVar Sync="true" Name="REFERENCES" />
<AsmRefVar Sync="true" Name="REFERENCES" />
<ProjectRefVar Sync="true" Name="REFERENCES" />
</MonoDevelop.Autotools.MakefileInfo>
</Properties>
</MonoDevelop>
</ProjectExtensions>
</Project>

92
src/Mono.Cxxi/Util/DelegateTypeCache.cs

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

645
src/Mono.Cxxi/Util/IEnumerableTransform.cs

@ -1,645 +0,0 @@ @@ -1,645 +0,0 @@
//
// Mono.Cxxi.Util.IEnumerableTransform.cs: Rule-based transformation for IEnumerable
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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;
using System.Collections.Generic;
namespace Mono.Cxxi.Util {
public static class IEnumerableTransform {
// Transforms an IEnumerable into another by specific rules.
public static IEnumerable<TOut> Transform<TIn, TOut> (this IEnumerable<TIn> input, params EmitterFunc<TIn, TOut> [] rules)
{
CloneableEnumerator<TIn> enumerator = new CloneableEnumerator<TIn> (input, 0);
while (enumerator.MoveNext ()) {
InputData<TIn> inputData = new InputData<TIn> (input, enumerator);
foreach (var rule in rules) {
TOut output;
if (rule (inputData.NewContext (), out output) == RuleResult.MatchEmit)
yield return output;
}
}
}
public static IRule<TIn> And<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules)
{
return new AndRule<TIn> (previousRules, parentheticalRules);
}
public static RuleCompound<TIn> And<TIn> (this IRule<TIn> previousRules)
{
return new RuleCompound<TIn> ((subsequentRules) => {
return And<TIn> (previousRules, subsequentRules);
});
}
public static IRule<TIn> Or<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules)
{
return new OrRule<TIn> (previousRules, parentheticalRules);
}
public static RuleCompound<TIn> Or<TIn> (this IRule<TIn> previousRules)
{
return new RuleCompound<TIn> ((subsequentRules) => {
return Or<TIn> (previousRules, subsequentRules);
});
}
public static IRule<TIn> After<TIn> (this IRule<TIn> previousRules, IRule<TIn> parentheticalRules)
{
return new AndRule<TIn> (new AfterRule<TIn> (parentheticalRules), previousRules);
}
public static RuleCompound<TIn> After<TIn> (this IRule<TIn> previousRules)
{
return new RuleCompound<TIn> ((subsequentRules) => {
return After<TIn> (previousRules, subsequentRules);
});
}
public static IRule<TIn> AtEnd<TIn> (this IRule<TIn> previousRules)
{
return new AtEndRule<TIn> (previousRules);
}
public static EmitterFunc<TIn, TOut> Emit<TIn, TOut> (this IRule<TIn> rule, Func<TIn, TOut> result)
{
return delegate (InputData<TIn> input, out TOut output) {
output = default (TOut);
TIn value = input.Value;
RuleResult ruleResult = rule.SatisfiedBy (input);
if (ruleResult != RuleResult.NoMatch) {
input.MatchedRules.Add (rule);
output = result (value);
return ruleResult;
}
return RuleResult.NoMatch;
};
}
public static EmitterFunc<TIn, TOut> Emit<TIn, TOut> (this IRule<TIn> rule, TOut result)
{
return Emit (rule, (input) => result);
}
// helpers:
public static IEnumerable<T> With<T> (this IEnumerable<T> current, T additionalValue)
{
foreach (var output in current)
yield return output;
yield return additionalValue;
}
public static bool StartsWith<T> (this IEnumerable<T> current, IEnumerable<T> beginning)
{
IEnumerator<T> currentEnum = current.GetEnumerator ();
IEnumerator<T> beginEnum = beginning.GetEnumerator ();
while (currentEnum.MoveNext ()) {
if (!beginEnum.MoveNext ())
return true;
if (!currentEnum.Current.Equals (beginEnum.Current))
return false;
}
return !beginEnum.MoveNext ();
}
public static IEnumerable<T> Without<T> (this IEnumerable<T> current, T unwantedValue)
{
foreach (var output in current) {
if (!output.Equals (unwantedValue))
yield return output;
}
}
public static IEnumerable<T> WithoutFirst<T> (this IEnumerable<T> current, T unwantedValue)
{
bool first = true;
foreach (var output in current) {
if (first && output.Equals (unwantedValue))
first = false;
else
yield return output;
}
}
public static int SequenceHashCode<T> (this IEnumerable<T> sequence)
{
int hash = 0;
foreach (var item in sequence)
hash ^= item.GetHashCode ();
return hash;
}
// FIXME: Faster way to do this?
public static void AddFirst<T> (this List<T> list, IEnumerable<T> items)
{
T [] temp = new T [list.Count];
list.CopyTo (temp, 0);
list.Clear ();
list.AddRange (items);
list.AddRange (temp);
}
public static void AddFirst<T> (this List<T> list, T item)
{
list.Insert (0, item);
}
}
public enum RuleResult {
NoMatch,
MatchEmit,
MatchNoEmit
}
public delegate RuleResult EmitterFunc<TIn, TOut> (InputData<TIn> input, out TOut output);
public struct InputData<TIn> {
public IEnumerable<TIn> AllValues;
public CloneableEnumerator<TIn> Enumerator;
public List<IRule<TIn>> MatchedRules;
public InputData (IEnumerable<TIn> input, CloneableEnumerator<TIn> enumerator)
{
this.AllValues = input;
this.Enumerator = enumerator;
this.MatchedRules = new List<IRule<TIn>> ();
}
public InputData<TIn> NewContext ()
{
InputData<TIn> nctx = new InputData<TIn> ();
nctx.AllValues = this.AllValues;
nctx.Enumerator = this.Enumerator.Clone ();
nctx.MatchedRules = this.MatchedRules;
return nctx;
}
public TIn Value {
get { return Enumerator.Current; }
}
}
#region Rules
public interface IRule<TIn> {
RuleResult SatisfiedBy (InputData<TIn> input);
}
// yields all inputs indescriminately
public class AnyRule<TIn> : IRule<TIn> {
public AnyRule ()
{
}
public RuleResult SatisfiedBy (InputData<TIn> input)
{
return RuleResult.MatchEmit;
}
}
// yields all inputs that haven't satisfied
// any other rule
public class UnmatchedRule<TIn> : IRule<TIn> {
public UnmatchedRule ()
{
}
public RuleResult SatisfiedBy (InputData<TIn> input)
{
return !input.MatchedRules.Any ()? RuleResult.MatchEmit : RuleResult.NoMatch;
}
}
// yields input if it hasn't been satisfied before
public class FirstRule<TIn> : IRule<TIn> {
protected bool triggered = false;
public FirstRule ()
{
}
public RuleResult SatisfiedBy (InputData<TIn> input)
{
if (!triggered) {
triggered = true;
return RuleResult.MatchEmit;
}
return RuleResult.NoMatch;
}
}
// yields input if it is the last that would satisfy
// all its matched rules
public class LastRule<TIn> : IRule<TIn> {
public LastRule ()
{
}
public RuleResult SatisfiedBy (InputData<TIn> input)
{
throw new NotImplementedException ();
}
}
// yields input if the specified previous rule has already been satisfied
public class AfterRule<TIn> : IRule<TIn> {
protected IRule<TIn> previousRule;
protected bool satisfied = false;
public AfterRule (IRule<TIn> previousRule)
{
this.previousRule = previousRule;
}
public RuleResult SatisfiedBy (InputData<TIn> input)
{
if (satisfied)
return RuleResult.MatchEmit;
satisfied = previousRule.SatisfiedBy (input) != RuleResult.NoMatch;
return RuleResult.NoMatch;
}
}
// yields all inputs found in the specified set
public class InSetRule<TIn> : IRule<TIn> {
protected IEnumerable<TIn> conditions;
public InSetRule (params TIn [] conditions)
{
this.conditions = conditions;
}
public InSetRule (IEnumerable<TIn> conditions)
{
this.conditions = conditions;
}
public RuleResult SatisfiedBy (InputData<TIn> input)
{
return conditions.Contains (input.Value)? RuleResult.MatchEmit : RuleResult.NoMatch;
}
}
public class PredicateRule<TIn> : IRule<TIn> {
protected Func<TIn, bool> predicate;
public PredicateRule (Func<TIn, bool> predicate)
{
this.predicate = predicate;
}
public RuleResult SatisfiedBy (InputData<TIn> input)
{
return predicate (input.Value)? RuleResult.MatchEmit : RuleResult.NoMatch;
}
}
// is satisfied by any of the specified items as long the
// item appears adjacent with all the other items
public class AnyOrderRule<TIn> : IRule<TIn> {
protected IEnumerable<TIn> conditions;
protected Queue<TIn> verifiedItems = new Queue<TIn> ();
protected bool verified = false;
public AnyOrderRule (params TIn [] conditions)
{
this.conditions = conditions;
}
public AnyOrderRule (IEnumerable<TIn> conditions)
{
this.conditions = conditions;
}
public RuleResult SatisfiedBy (InputData<TIn> inputData)
{
if (verified && verifiedItems.Count > 0) {
verifiedItems.Dequeue ();
return RuleResult.MatchNoEmit;
} else
verified = false;
IEnumerator<TIn> input = inputData.Enumerator;
while (conditions.Contains (input.Current) && !verifiedItems.Contains (input.Current)) {
verifiedItems.Enqueue (input.Current);
if (!input.MoveNext ()) break;
}
if (verifiedItems.Count == conditions.Count ()) {
verified = true;
verifiedItems.Dequeue ();
return RuleResult.MatchEmit;
} else
verifiedItems.Clear ();
return RuleResult.NoMatch;
}
}
public class InOrderRule<TIn> : IRule<TIn> {
protected IEnumerable<TIn> conditions;
protected bool verified = false;
protected int verifiedCount = 0;
public InOrderRule (params TIn [] conditions)
{
this.conditions = conditions;
}
public InOrderRule (IEnumerable<TIn> conditions)
{
this.conditions = conditions;
}
public RuleResult SatisfiedBy (InputData<TIn> inputData)
{
if (verified && verifiedCount > 0) {
verifiedCount--;
return RuleResult.MatchNoEmit;
} else
verified = false;
IEnumerator<TIn> condition = conditions.GetEnumerator ();
IEnumerator<TIn> input = inputData.Enumerator;
while (condition.MoveNext () && condition.Equals (input.Current)) {
verifiedCount++;
if (!input.MoveNext ()) break;
}
if (verifiedCount == conditions.Count ()) {
verified = true;
verifiedCount--;
return RuleResult.MatchEmit;
} else
verifiedCount = 0;
return RuleResult.NoMatch;
}
}
// yields all inputs that match all specified rules
public class AndRule<TIn> : IRule<TIn> {
protected IEnumerable<IRule<TIn>> rules;
public AndRule (IEnumerable<IRule<TIn>> rules)
{
this.rules = rules;
}
public AndRule (params IRule<TIn>[] rules)
{
this.rules = rules;
}
public RuleResult SatisfiedBy (InputData<TIn> input)
{
RuleResult finalResult = RuleResult.NoMatch;
foreach (var rule in rules) {
RuleResult result = rule.SatisfiedBy (input.NewContext ());
if (result == RuleResult.NoMatch)
return RuleResult.NoMatch;
if (finalResult != RuleResult.MatchNoEmit)
finalResult = result;
input.MatchedRules.Add (rule);
}
return finalResult;
}
}
// yields all inputs that match any specified rules
public class OrRule<TIn> : IRule<TIn> {
protected IEnumerable<IRule<TIn>> rules;
public OrRule (IEnumerable<IRule<TIn>> rules)
{
this.rules = rules;
}
public OrRule (params IRule<TIn>[] rules)
{
this.rules = rules;
}
public RuleResult SatisfiedBy (InputData<TIn> input)
{
foreach (var rule in rules) {
RuleResult result = rule.SatisfiedBy (input.NewContext ());
if (result != RuleResult.NoMatch) {
input.MatchedRules.Add (rule);
return result;
}
}
return RuleResult.NoMatch;
}
}
public class AtEndRule<TIn> : IRule<TIn> {
protected IRule<TIn> rule;
public AtEndRule (IRule<TIn> rule)
{
this.rule = rule;
}
public RuleResult SatisfiedBy (InputData<TIn> input)
{
RuleResult rr = rule.SatisfiedBy (input);
if (!input.Enumerator.MoveNext ())
return rr;
return RuleResult.NoMatch;
}
}
#endregion
// the base point for building up rules
// All rules start For...
public static class For {
public static IRule<TIn> AnyInputIn<TIn> (params TIn [] input)
{
return new InSetRule<TIn> (input);
}
public static IRule<TIn> AnyInputIn<TIn> (IEnumerable<TIn> input)
{
return new InSetRule<TIn> (input);
}
public static SequenceQualifier<TIn> AllInputsIn<TIn> (params TIn [] input)
{
return new SequenceQualifier<TIn> (input, null);
}
public static SequenceQualifier<TIn> AllInputsIn<TIn> (IEnumerable<TIn> input)
{
return new SequenceQualifier<TIn> (input, null);
}
public static RuleCompound<TIn> First<TIn> ()
{
return new RuleCompound<TIn> ((subsequentRules) => {
return new AndRule<TIn> (subsequentRules, new FirstRule<TIn> ());
});
}
public static RuleCompound<TIn> Last<TIn> ()
{
return new RuleCompound<TIn> ((subsequentRules) => {
return new AndRule<TIn> (subsequentRules, new LastRule<TIn> ());
});
}
public static IRule<TIn> InputsWhere<TIn> (Func<TIn, bool> predicate)
{
return new PredicateRule<TIn> (predicate);
}
public static IRule<TIn> AnyInput<TIn> ()
{
return new AnyRule<TIn> ();
}
public static IRule<TIn> UnmatchedInput<TIn> ()
{
return new UnmatchedRule<TIn> ();
}
}
public class RuleCompound<TIn> {
protected Func<IRule<TIn>,IRule<TIn>> additionalRuleCallback;
public RuleCompound (Func<IRule<TIn>,IRule<TIn>> additionalRuleCallback)
{
this.additionalRuleCallback = additionalRuleCallback;
}
public SequenceQualifier<TIn> AllInputsIn (params TIn [] input)
{
return new SequenceQualifier<TIn> (input, additionalRuleCallback);
}
public SequenceQualifier<TIn> AllInputsIn (IEnumerable<TIn> input)
{
return new SequenceQualifier<TIn> (input, additionalRuleCallback);
}
public IRule<TIn> AnyInputIn (params TIn[] input)
{
return additionalRuleCallback (new InSetRule<TIn> (input));
}
public IRule<TIn> AnyInputIn (IEnumerable<TIn> input)
{
return additionalRuleCallback (new InSetRule<TIn> (input));
}
public IRule<TIn> InputsWhere (Func<TIn, bool> predicate)
{
return additionalRuleCallback (new PredicateRule<TIn> (predicate));
}
public IRule<TIn> AnyInput ()
{
return additionalRuleCallback (new AnyRule<TIn> ());
}
}
public class SequenceQualifier<TIn> {
protected IEnumerable<TIn> sequence;
protected Func<IRule<TIn>, IRule<TIn>> additionalRuleCallback;
public SequenceQualifier (IEnumerable<TIn> sequence, Func<IRule<TIn>, IRule<TIn>> additionalRuleCallback)
{
this.sequence = sequence;
this.additionalRuleCallback = additionalRuleCallback ?? (rul => rul);
}
public IRule<TIn> InThatOrder ()
{
return additionalRuleCallback (new InOrderRule<TIn> (sequence));
}
public IRule<TIn> InAnyOrder ()
{
return additionalRuleCallback (new AnyOrderRule<TIn> (sequence));
}
}
public static class Choose {
public static EmitterFunc<TIn, TOut> TopOne<TIn, TOut> (params EmitterFunc<TIn, TOut> [] rules)
{
return delegate (InputData<TIn> input, out TOut output) {
output = default (TOut);
foreach (var rule in rules) {
RuleResult result = rule (input.NewContext (), out output);
if (result != RuleResult.NoMatch)
return result;
}
return RuleResult.NoMatch;
};
}
}
public class CloneableEnumerator<T> : IEnumerator<T> {
private IEnumerable<T> wrappedEnumerable;
private IEnumerator<T> wrappedEnumerator;
private int position;
public CloneableEnumerator (IEnumerable<T> enumerable, int position)
{
this.wrappedEnumerable = enumerable;
this.position = position;
this.wrappedEnumerator = wrappedEnumerable.GetEnumerator ();
for (int i = 0; i < position; i++)
wrappedEnumerator.MoveNext ();
}
public CloneableEnumerator<T> Clone () {
return new CloneableEnumerator<T> (this.wrappedEnumerable, this.position);
}
public void Reset ()
{
wrappedEnumerator.Reset ();
}
public bool MoveNext ()
{
position++;
return wrappedEnumerator.MoveNext ();
}
public T Current {
get { return wrappedEnumerator.Current; }
}
object IEnumerator.Current {
get { return this.Current; }
}
public void Dispose ()
{
}
}
}

126
src/Mono.Cxxi/Util/LazyGeneratedList.cs

@ -1,126 +0,0 @@ @@ -1,126 +0,0 @@
//
// Mono.Cxxi.Util.LazyGeneratedList.cs: A list whose items are generated and cached on first access
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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.Collections;
using System.Collections.Generic;
namespace Mono.Cxxi.Util {
public class LazyGeneratedList<TItem> : IList<TItem>
where TItem : class
{
private TItem [] cache;
private Func<int, TItem> generator;
private int count;
public LazyGeneratedList (int count, Func<int, TItem> generator)
{
this.cache = new TItem [count];
this.generator = generator;
this.count = count;
}
public IEnumerator<TItem> GetEnumerator ()
{
for (int i = 0; i < Count; i++)
yield return this [i];
}
IEnumerator IEnumerable.GetEnumerator ()
{
return this.GetEnumerator ();
}
public int Count {
get { return count; }
}
public bool IsReadOnly {
get { return true; }
}
public TItem this [int i] {
get {
// access to cache [i] will throw the IndexOutOfRange exception for us
return cache [i] == null? (cache [i] = generator (i)) : cache [i];
}
set {
throw new NotSupportedException ("This IList is read only");
}
}
public void Add (int count)
{
this.count += count;
// flush cache
cache = new TItem [this.count];
}
public void Remove (int count)
{
this.count -= count;
// flush cache
cache = new TItem [this.count];
}
// FIXME: Should probably implement these at some point
public bool Contains (TItem item)
{
throw new NotImplementedException ();
}
public void CopyTo (TItem[] array, int arrayIndex)
{
throw new NotImplementedException ();
}
public int IndexOf (TItem item)
{
throw new NotImplementedException ();
}
public void Insert (int index, TItem item)
{
throw new NotImplementedException ();
}
public void RemoveAt (int index)
{
throw new NotImplementedException ();
}
public void Add (TItem item)
{
throw new NotImplementedException ();
}
public void Clear ()
{
throw new NotImplementedException ();
}
public bool Remove (TItem item)
{
throw new NotImplementedException ();
}
}
}

145
src/Mono.Cxxi/Util/MethodSignature.cs

@ -1,145 +0,0 @@ @@ -1,145 +0,0 @@
//
// Mono.Cxxi.Util.MethodSignature.cs: Hash-friendly structs to represent arbitrary method and delegate signatures
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using Mono.Cxxi.Abi;
namespace Mono.Cxxi.Util {
public class BasicSignature {
public CallingConvention? CallingConvention { get; set; }
public List<Type> ParameterTypes { get; set; }
public Type ReturnType { get; set; }
private string uniqueName;
public string UniqueName {
get {
if (uniqueName != null)
return uniqueName;
StringBuilder sb = new StringBuilder ("_");
if (CallingConvention.HasValue)
sb.Append (Enum.GetName (typeof (CallingConvention), CallingConvention.Value));
sb.Append ('_').Append (ReturnType.Name);
if (ParameterTypes == null)
return uniqueName = sb.ToString ();
foreach (var param in ParameterTypes)
sb.Append ('_').Append (param.Name);
return uniqueName = sb.ToString ();
}
}
public 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)
{
var other = obj as BasicSignature;
if (other == null)
return false;
return IsCompatibleWith (other);
}
public override int GetHashCode ()
{
unchecked {
return CallingConvention.GetHashCode () ^
(ParameterTypes != null? ParameterTypes.SequenceHashCode () : 0) ^
ReturnType.GetHashCode ();
}
}
}
public class MethodSignature : BasicSignature {
public static readonly IEqualityComparer<MethodSignature> EqualityComparer = new MethodSignatureEqualityComparer ();
public string Name { get; set; }
public MethodType Type { get; set; }
public new bool Equals (object obj)
{
var other = obj as MethodSignature;
if (other == null)
return false;
return IsCompatibleWith (other) &&
Type == other.Type &&
(Name.Equals (other.Name) || Type != MethodType.Native);
}
public new int GetHashCode ()
{
unchecked {
return base.GetHashCode () ^
Type.GetHashCode () ^
(Type == MethodType.Native? Name.GetHashCode () : 0);
}
}
private class MethodSignatureEqualityComparer : IEqualityComparer<MethodSignature> {
public bool Equals (MethodSignature x, MethodSignature y)
{
return x.Equals (y);
}
public int GetHashCode (MethodSignature obj)
{
return obj.GetHashCode ();
}
}
public override string ToString ()
{
return string.Format ("[{0} {1} ({2})]", ReturnType.Name, Name, string.Join (", ", ParameterTypes.Select (t => t.Name).ToArray ()));
}
}
public class PInvokeSignature : MethodSignature {
// The original c# method this signature was generated from
public MethodInfo OrigMethod;
}
}

118
src/Mono.Cxxi/Util/ReflectionHelper.cs

@ -1,118 +0,0 @@ @@ -1,118 +0,0 @@
//
// Mono.Cxxi.Util.ReflectionHelper.cs: Helper methods for common reflection API tasks
//
// Author:
// Alexander Corrado (alexander.corrado@gmail.com)
// Andreia Gaita (shana@spoiledcat.net)
//
// Copyright (C) 2010-2011 Alexander Corrado
//
// 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.Runtime.InteropServices;
using System.Reflection;
using System.Reflection.Emit;
namespace Mono.Cxxi.Util {
internal static class ReflectionHelper {
public static MethodInfo GetMethodInfoForDelegate (Type delType)
{
return delType.GetMethod ("Invoke");
}
public static Type[] GetDelegateParameterTypes (Type delType)
{
MethodInfo invoke = GetMethodInfoForDelegate (delType);
if (invoke == null)
return null;
return GetMethodParameterTypes (invoke);
}
public static Type[] GetMethodParameterTypes (MethodInfo method)
{
ParameterInfo[] parameters = method.GetParameters ();
Type[] parameterTypes = new Type [parameters.Length];
for (int i = 0; i < parameters.Length; i++)
parameterTypes [i] = parameters [i].ParameterType;
return parameterTypes;
}
public static void ApplyMethodParameterAttributes (MethodInfo source, MethodBuilder target, bool forPInvoke)
{
ParameterInfo[] parameters = source.GetParameters ();
foreach (var param in parameters)
ApplyAttributes (param, target.DefineParameter, forPInvoke);
}
public static void ApplyMethodParameterAttributes (MethodInfo source, DynamicMethod target, bool forPInvoke)
{
ParameterInfo[] parameters = source.GetParameters ();
foreach (var param in parameters)
ApplyAttributes (param, target.DefineParameter, forPInvoke);
}
public static ParameterBuilder ApplyAttributes (ParameterInfo param, Func<int,ParameterAttributes,string,ParameterBuilder> makePB, bool forPInvoke)
{
ParameterAttributes attr = param.Attributes;
CustomAttributeBuilder marshalAsAttr = null;
MarshalAsAttribute existingMarshalAs = param.GetCustomAttributes (typeof (MarshalAsAttribute),
false).FirstOrDefault () as MarshalAsAttribute;
/* if (forPInvoke &&
typeof (ICppObject).IsAssignableFrom (param.ParameterType) &&
!param.ParameterType.Equals (typeof (CppInstancePtr)) &&
existingMarshalAs == null)
{
ConstructorInfo ctor = typeof (MarshalAsAttribute).GetConstructor (new Type[] { typeof (UnmanagedType) });
object[] args = new object [] { UnmanagedType.CustomMarshaler };
FieldInfo[] fields = new FieldInfo [] { typeof (MarshalAsAttribute).GetField("MarshalTypeRef") };
object[] values = new object [] { typeof (CppObjectMarshaler) };
marshalAsAttr = new CustomAttributeBuilder (ctor, args, fields, values);
attr = attr | ParameterAttributes.HasFieldMarshal;
} else */ if (forPInvoke && existingMarshalAs != null) {
// FIXME: This still doesn't feel like it's working right.. especially for virtual functions
ConstructorInfo ctor = typeof (MarshalAsAttribute).GetConstructor (new Type[] { typeof (UnmanagedType) });
object[] args = new object [] { existingMarshalAs.Value };
var fields = from field in typeof (MarshalAsAttribute).GetFields ()
where field.GetValue (existingMarshalAs) != null
select field;
var values = from field in fields select field.GetValue (existingMarshalAs);
marshalAsAttr = new CustomAttributeBuilder (ctor, args, fields.ToArray (), values.ToArray ());
attr = attr | ParameterAttributes.HasFieldMarshal;
}
ParameterBuilder pb = makePB (param.Position, attr, param.Name);
if (marshalAsAttr != null) pb.SetCustomAttribute (marshalAsAttr);
return pb;
}
}
}

6
src/Mono.Cxxi/mono.cxxi.pc.in

@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
Name: Mono.Cxxi
Description: C++ interoperability for managed code
Version: 0.1
Requires:
Libs: -r:@expanded_libdir@/@PACKAGE@/Mono.Cxxi.dll
Loading…
Cancel
Save