mirror of https://github.com/mono/CppSharp.git
25 changed files with 0 additions and 5123 deletions
@ -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); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -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; |
||||
} |
||||
} |
||||
|
||||
@ -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); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
||||
} |
||||
@ -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; |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
@ -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 (); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
@ -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 |
||||
} |
||||
} |
||||
@ -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
|
||||
|
||||
} |
||||
} |
||||
|
||||
@ -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; |
||||
} |
||||
} |
||||
} |
||||
@ -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")] |
||||
@ -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; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -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); |
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -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; |
||||
} |
||||
} |
||||
} |
||||
@ -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); |
||||
} |
||||
|
||||
} |
||||
} |
||||
@ -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 ())); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -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); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -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; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -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); |
||||
} |
||||
} |
||||
@ -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) |
||||
@ -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> |
||||
@ -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 (); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
@ -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 () |
||||
{ |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -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 (); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -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; |
||||
} |
||||
} |
||||
|
||||
@ -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; |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue