mirror of https://github.com/mono/CppSharp.git
25 changed files with 0 additions and 5123 deletions
@ -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 @@ |
|||||||
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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
|
|
||||||
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 @@ |
|||||||
<?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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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 @@ |
|||||||
//
|
|
||||||
// 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