Browse Source

Initial support for calling virtual methods of non-primary base classes

pull/1/head
Alex Corrado 14 years ago
parent
commit
a74d9393e6
  1. 3
      src/Mono.VisualC.Interop/ABI/CppAbi.cs
  2. 2
      src/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs
  3. 64
      src/Mono.VisualC.Interop/ABI/Impl/ItaniumTypeInfo.cs
  4. 62
      src/Mono.VisualC.Interop/CppTypeInfo.cs
  5. 1
      src/Mono.VisualC.Interop/Makefile.am
  6. 1
      src/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj
  7. 53
      src/Mono.VisualC.Interop/Util/LazyGeneratedList.cs
  8. 12
      src/Mono.VisualC.Interop/Util/MethodSignature.cs

3
src/Mono.VisualC.Interop/ABI/CppAbi.cs

@ -343,6 +343,9 @@ namespace Mono.VisualC.Interop.ABI { @@ -343,6 +343,9 @@ namespace Mono.VisualC.Interop.ABI {
return null;
var sig = typeInfo.VirtualMethods [vtableIndex];
if (sig == null)
return null;
var interfaceMethod = sig.OrigMethod;
var targetMethod = FindManagedOverrideTarget (interfaceMethod);
if (targetMethod == null)

2
src/Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs

@ -55,7 +55,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -55,7 +55,7 @@ namespace Mono.VisualC.Interop.ABI {
protected override CppTypeInfo MakeTypeInfo (IEnumerable<PInvokeSignature> methods)
{
return new CppTypeInfo (this, GetVirtualMethodSlots (methods), layout_type, wrapper_type);
return new ItaniumTypeInfo (this, GetVirtualMethodSlots (methods), layout_type, wrapper_type);
}
private IEnumerable<PInvokeSignature> GetVirtualMethodSlots (IEnumerable<PInvokeSignature> methods)

64
src/Mono.VisualC.Interop/ABI/Impl/ItaniumTypeInfo.cs

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
// 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.VisualC.Interop.Util;
namespace Mono.VisualC.Interop.ABI {
public class ItaniumTypeInfo : CppTypeInfo {
public ItaniumTypeInfo (ItaniumAbi abi, IEnumerable<PInvokeSignature> virtualMethods, Type nativeLayout, Type wrapperType)
: base (abi, virtualMethods, nativeLayout, wrapperType)
{
}
// 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
public override void AddBase (CppTypeInfo baseType)
{
if (TypeComplete)
return;
if (BaseClasses.Count > 0 && baseType.VirtualMethods.Any ()) { // already have a primary base
// FIXME: virtual inheritance
virtual_methods.Insert (BaseVTableSlots, null);
virtual_methods.Insert (BaseVTableSlots, null);
BaseVTableSlots += 2;
}
base.AddBase (baseType);
}
}
}

62
src/Mono.VisualC.Interop/CppTypeInfo.cs

@ -91,7 +91,7 @@ namespace Mono.VisualC.Interop { @@ -91,7 +91,7 @@ namespace Mono.VisualC.Interop {
BaseVTableSlots = 0;
TypeComplete = false;
native_size = Marshal.SizeOf (nativeLayout);
native_size = nativeLayout.GetFields ().Any ()? Marshal.SizeOf (nativeLayout) : 0;
field_offset_padding_without_vtptr = 0;
lazy_vtable = null;
@ -104,19 +104,21 @@ namespace Mono.VisualC.Interop { @@ -104,19 +104,21 @@ namespace Mono.VisualC.Interop {
public virtual void AddBase (CppTypeInfo baseType)
{
// by default, do not add another vtable pointer for this new base class
// by default, do not add another vtable for this new base class
AddBase (baseType, false);
}
protected virtual void AddBase (CppTypeInfo baseType, bool addVTablePointer)
protected virtual void AddBase (CppTypeInfo baseType, bool addVTable)
{
if (TypeComplete)
return;
base_classes.Add (baseType);
if (!addVTablePointer) {
// If we're not adding a vtptr, then all this base class's virtual methods go in primary vtable
bool addVTablePointer = addVTable || base_classes.Count > 1;
if (!addVTable) {
// If we're not adding a new vtable, then all this base class's virtual methods go in primary vtable
// Skew the offsets of this subclass's vmethods to account for the new base vmethods.
int newVirtualMethodCount = baseType.virtual_methods.Count;
@ -126,6 +128,9 @@ namespace Mono.VisualC.Interop { @@ -126,6 +128,9 @@ namespace Mono.VisualC.Interop {
BaseVTableSlots += newVirtualMethodCount;
vt_delegate_types.PrependLast (baseType.vt_delegate_types);
vt_overrides.PrependLast (baseType.vt_overrides);
} else {
// FIXME: Implement this when we get around to msvc again ?
}
field_offset_padding_without_vtptr += baseType.native_size +
@ -135,7 +140,32 @@ namespace Mono.VisualC.Interop { @@ -135,7 +140,32 @@ namespace Mono.VisualC.Interop {
public virtual TBase Cast<TBase> (ICppObject instance)
where TBase : ICppObject
{
throw new NotImplementedException ();
var targetType = typeof (TBase);
var found = false;
int offset = 0;
foreach (var baseClass in base_classes) {
if (baseClass.WrapperType.Equals (targetType)) {
found = true;
break;
}
offset += baseClass.NativeSize;
}
if (!found)
throw new InvalidCastException ("Cannot cast an instance of " + instance.GetType () + " to " + targetType);
// Construct a new targetType wrapper, passing in our offset this ptr.
// FIXME: If the object was alloc'd by managed code, the allocating wrapper (i.e. "instance") will still free the memory when
// it is Disposed, even if wrappers created here still exist and are pointing to it. :/
// The casted wrapper created here may be Disposed safely though.
// FIXME: On NET_4_0 use IntPtr.Add
var cppip = new CppInstancePtr (new IntPtr (instance.Native.Native.ToInt64 () + offset));
// Ugh, this requires boxing of cppip AND some slow reflection.. please cache the result of this!
// FIXME: Perhaps Reflection.Emit all possible base casts and eliminate this beast?
return (TBase)Activator.CreateInstance (targetType, cppip);
}
public int CountBases (Func<CppTypeInfo, bool> predicate)
@ -157,24 +187,30 @@ namespace Mono.VisualC.Interop { @@ -157,24 +187,30 @@ namespace Mono.VisualC.Interop {
baseClass.CompleteType ();
TypeComplete = true;
RemoveVTableDuplicates (ms => true);
// Tthis 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.
RemoveVTableDuplicates ((pi1, pi2) => !pi1.OrigMethod.Equals (pi2.OrigMethod));
}
protected virtual void RemoveVTableDuplicates (Predicate<MethodSignature> pred)
protected virtual void RemoveVTableDuplicates (Func<PInvokeSignature,PInvokeSignature,bool> pred)
{
// check that any virtual methods overridden in a subclass are only included once
var vsignatures = new HashSet<MethodSignature> ();
var vsignatures = new Dictionary<MethodSignature,PInvokeSignature> (MethodSignature.EqualityComparer);
for (int i = 0; i < virtual_methods.Count; i++) {
var sig = virtual_methods [i];
if (sig == null)
continue;
if (vsignatures.Contains (sig)) {
if (pred (sig))
PInvokeSignature existing;
if (vsignatures.TryGetValue (sig, out existing)) {
if (pred (sig, existing))
virtual_methods.RemoveAt (i--);
} else {
vsignatures.Add (sig);
vsignatures.Add (sig, sig);
}
}
}
@ -184,8 +220,6 @@ namespace Mono.VisualC.Interop { @@ -184,8 +220,6 @@ namespace Mono.VisualC.Interop {
return VTable.GetVirtualCallDelegate<T> (native, BaseVTableSlots + derivedVirtualMethodIndex);
}
//public virtual long GetFieldOffset (
public virtual VTable VTable {
get {
CompleteType ();

1
src/Mono.VisualC.Interop/Makefile.am

@ -46,6 +46,7 @@ all: $(ASSEMBLY) $(PROGRAMFILES) $(LINUX_PKGCONFIG) @@ -46,6 +46,7 @@ all: $(ASSEMBLY) $(PROGRAMFILES) $(LINUX_PKGCONFIG)
FILES = \
ABI/CppAbi.cs \
ABI/Impl/ItaniumAbi.cs \
ABI/Impl/ItaniumTypeInfo.cs \
ABI/Impl/MsvcAbi.cs \
ABI/Impl/MsvcTypeInfo.cs \
ABI/Impl/VirtualOnlyAbi.cs \

1
src/Mono.VisualC.Interop/Mono.VisualC.Interop.csproj

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

53
src/Mono.VisualC.Interop/Util/LazyGeneratedList.cs

@ -34,11 +34,36 @@ namespace Mono.VisualC.Interop.Util { @@ -34,11 +34,36 @@ namespace Mono.VisualC.Interop.Util {
public class LazyGeneratedList<TItem> : IList<TItem> where TItem : class {
private class Node<TItem> where TItem : class {
public LazyGeneratedList<TItem> List { get; set; }
public Node<TItem> Next { get; set; }
public Node (LazyGeneratedList<TItem> list, Node<TItem> next)
{
this.List = list;
this.Next = next;
}
public void AppendNext (Node<TItem> node)
{
if (Next == null)
Next = node;
else
Next.AppendNext (node);
}
public TItem this [int index] {
get {
if (index >= List.Count)
return Next [index - List.Count];
return List [index];
}
}
}
private TItem [] cache;
private Func<int, TItem> generator;
private LazyGeneratedList<TItem> previous;
private LazyGeneratedList<TItem> next;
private Node<TItem> previous;
private Node<TItem> next;
private int lead, content, follow;
private HashSet<int> removed;
@ -112,39 +137,35 @@ namespace Mono.VisualC.Interop.Util { @@ -112,39 +137,35 @@ namespace Mono.VisualC.Interop.Util {
public void AppendFirst (LazyGeneratedList<TItem> list)
{
follow += list.Count;
if (next != null)
list.AppendLast (next);
next = list;
next = new Node<TItem> (list, next);
}
public void AppendLast (LazyGeneratedList<TItem> list)
{
var node = new Node<TItem> (list, null);
if (next == null)
next = list;
next = node;
else
next.AppendLast (list);
next.AppendNext (node);
follow += list.Count;
}
public void PrependFirst (LazyGeneratedList<TItem> list)
public void PrependLast (LazyGeneratedList<TItem> list)
{
var node = new Node<TItem> (list, null);
if (previous == null)
previous = list;
previous = node;
else
previous.PrependFirst (list);
previous.AppendNext (node);
lead += list.Count;
}
public void PrependLast (LazyGeneratedList<TItem> list)
public void PrependFirst (LazyGeneratedList<TItem> list)
{
lead += list.Count;
if (previous != null)
list.PrependFirst (previous);
previous = list;
previous = new Node<TItem> (list, previous);
}
// FIXME: Should probably implement these 3 at some point

12
src/Mono.VisualC.Interop/Util/MethodSignature.cs

@ -92,6 +92,8 @@ namespace Mono.VisualC.Interop.Util { @@ -92,6 +92,8 @@ namespace Mono.VisualC.Interop.Util {
}
public class MethodSignature : BasicSignature {
public static readonly IEqualityComparer<MethodSignature> EqualityComparer = new MethodSignatureEqualityComparer ();
public string Name { get; set; }
public MethodType Type { get; set; }
@ -116,6 +118,16 @@ namespace Mono.VisualC.Interop.Util { @@ -116,6 +118,16 @@ namespace Mono.VisualC.Interop.Util {
}
}
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 class PInvokeSignature : MethodSignature {

Loading…
Cancel
Save