Experimental support for initing the native vtptr ourselves (enable with -define:INIT_NATIVE_VTABLES)
Doing this ourselves instead of depending on the C++ ctor to do it will allow us to instantiate classes that have vtables and do not explicitly define any constructors (thus only having the C++ implicitly-defined default constructor, which isn't exported as a symbol in the lib).
This commit is contained in:
Родитель
aefe6e0e2a
Коммит
fb85e5a3ed
|
@ -71,6 +71,7 @@ namespace Mono.Cxxi.Abi {
|
|||
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:
|
||||
|
@ -89,6 +90,14 @@ namespace Mono.Cxxi.Abi {
|
|||
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);
|
||||
|
@ -120,7 +129,15 @@ namespace Mono.Cxxi.Abi {
|
|||
DefineProperty (typeInfo, property);
|
||||
|
||||
typeInfo.emit_info.ctor_il.Emit (OpCodes.Ret);
|
||||
return (ICppClass)Activator.CreateInstance (typeInfo.emit_info.type_builder.CreateType (), typeInfo);
|
||||
|
||||
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");
|
||||
|
@ -180,9 +197,10 @@ namespace Mono.Cxxi.Abi {
|
|||
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) });
|
||||
new Type[] { typeof (CppTypeInfo), typeof (IntPtr) });
|
||||
|
||||
var ctor_il = ctor.GetILGenerator ();
|
||||
|
||||
|
@ -191,8 +209,14 @@ namespace Mono.Cxxi.Abi {
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -479,8 +503,8 @@ namespace Mono.Cxxi.Abi {
|
|||
protected virtual void EmitManagedAlloc (CppTypeInfo typeInfo, MethodInfo interfaceMethod)
|
||||
{
|
||||
var il = typeInfo.emit_info.current_il;
|
||||
var cppip = il.DeclareLocal (typeof (CppInstancePtr));
|
||||
|
||||
// this._typeInfo.NativeSize
|
||||
il.Emit (OpCodes.Ldarg_0);
|
||||
il.Emit (OpCodes.Ldfld, typeInfo.emit_info.typeinfo_field);
|
||||
|
||||
|
@ -492,6 +516,22 @@ namespace Mono.Cxxi.Abi {
|
|||
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,
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Mono.Cxxi.Abi {
|
|||
|
||||
public class EmitInfo {
|
||||
public TypeBuilder type_builder;
|
||||
public FieldBuilder typeinfo_field;
|
||||
public FieldBuilder typeinfo_field, native_vtable_field;
|
||||
public ILGenerator ctor_il, current_il;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
// 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
|
||||
|
@ -197,6 +198,26 @@ namespace Mono.Cxxi.Abi {
|
|||
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;
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
//
|
||||
// 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
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -59,9 +59,11 @@ namespace Mono.Cxxi {
|
|||
internal static ModuleBuilder interopModule;
|
||||
|
||||
public CppAbi Abi { get; private set; }
|
||||
public string Name { 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");
|
||||
|
@ -89,7 +91,7 @@ namespace Mono.Cxxi {
|
|||
if (abi == null)
|
||||
throw new ArgumentNullException ("Abi cannot be NULL.");
|
||||
|
||||
this.Name = name;
|
||||
this.name = name;
|
||||
this.Abi = abi;
|
||||
this.InlineMethodPolicy = inlinePolicy;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ FILES = \
|
|||
Abi/Impl/ItaniumTypeInfo.cs \
|
||||
Abi/Impl/MsvcAbi.cs \
|
||||
Abi/MethodType.cs \
|
||||
Abi/SymbolResolver.cs \
|
||||
Abi/VTable.cs \
|
||||
AssemblyInfo.cs \
|
||||
Attributes.cs \
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
<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>
|
||||
|
|
Загрузка…
Ссылка в новой задаче