Browse Source

Fix vtable layout for classes derived from classes with non-primary bases

pull/1/head
Alexander Corrado 14 years ago
parent
commit
9b4206c960
  1. 6
      src/Mono.Cxxi/Abi/Impl/ItaniumTypeInfo.cs
  2. 63
      src/Mono.Cxxi/CppTypeInfo.cs

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

@ -43,8 +43,8 @@ namespace Mono.Cxxi.Abi {
: base (lib, typeName, interfaceType, nativeLayout, wrapperType) : base (lib, typeName, interfaceType, nativeLayout, wrapperType)
{ {
} }
/*
protected override void AddBase (CppTypeInfo baseType, bool addVTable) protected override void AddBase (CppTypeInfo baseType, BaseVirtualMethods location)
{ {
if (TypeComplete) if (TypeComplete)
return; return;
@ -64,7 +64,7 @@ namespace Mono.Cxxi.Abi {
base.AddBase (baseType, addVTable); base.AddBase (baseType, addVTable);
} }
*/
protected override bool OnVTableDuplicate (ref int iter, PInvokeSignature sig, PInvokeSignature dup) protected override bool OnVTableDuplicate (ref int iter, PInvokeSignature sig, PInvokeSignature dup)
{ {
var isOverride = base.OnVTableDuplicate (ref iter, sig, dup); var isOverride = base.OnVTableDuplicate (ref iter, sig, dup);

63
src/Mono.Cxxi/CppTypeInfo.cs

@ -40,6 +40,19 @@ using Mono.Cxxi.Util;
namespace Mono.Cxxi { 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. // NOTE: As AddBase is called, properties change.
// TypeComplete indicates when the dust has settled. // TypeComplete indicates when the dust has settled.
public class CppTypeInfo { public class CppTypeInfo {
@ -143,69 +156,63 @@ namespace Mono.Cxxi {
public void AddBase (CppTypeInfo baseType) public void AddBase (CppTypeInfo baseType)
{ {
// by default, only the primary base shares the subclass's primary vtable // by default, only the primary base shares the subclass's primary vtable
AddBase (baseType, base_classes.Count >= 1); AddBase (baseType, base_classes.Count == 0 ? BaseVirtualMethods.PrependPrimary : BaseVirtualMethods.NewVTable);
} }
protected virtual void AddBase (CppTypeInfo baseType, bool addVTable) protected virtual void AddBase (CppTypeInfo baseType, BaseVirtualMethods location)
{ {
if (TypeComplete) if (TypeComplete)
return; return;
bool nonPrimary = base_classes.Count >= 1;
// by default, only the primary base shares the subclass's vtable ptr
var addVTablePointer = addVTable || nonPrimary;
var baseVMethodCount = baseType.virtual_methods.Count; var baseVMethodCount = baseType.virtual_methods.Count;
if (addVTable) { switch (location) {
// If we are adding a new vtable, don't skew the offsets of the of this subclass's methods.
// Instead append the new virtual methods to the end. case BaseVirtualMethods.PrependPrimary:
for (int i = 0; i < baseVMethodCount; i++) for (int i = 0; i < baseVMethodCount; i++)
virtual_methods.Add (baseType.virtual_methods [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_delegate_types.Add (baseVMethodCount);
vt_overrides.Add (baseVMethodCount); vt_overrides.Add (baseVMethodCount);
break;
case BaseVirtualMethods.AppendPrimary:
} else { for (int i = 0; i < baseVMethodCount; i++)
virtual_methods.Add (baseType.virtual_methods [i]);
// If we're not adding a new vtable, then all this base class's virtual methods go in primary vtable gchandle_offset_delta = baseType.gchandle_offset_delta;
// Skew the offsets of this subclass's vmethods to account for the new base vmethods.
for (int i = 0; i < baseVMethodCount; i++)
virtual_methods.Insert (BaseVTableSlots + i, baseType.virtual_methods [i]);
BaseVTableSlots += baseVMethodCount;
vt_delegate_types.Add (baseVMethodCount); vt_delegate_types.Add (baseVMethodCount);
vt_overrides.Add (baseVMethodCount); vt_overrides.Add (baseVMethodCount);
} break;
if (nonPrimary) { case BaseVirtualMethods.NewVTable:
// Create a base-in-derived type info w/ a new vtable object
// if this is a non-primary base
baseType = baseType.Clone (); baseType = baseType.Clone ();
baseType.IsPrimaryBase = false; baseType.IsPrimaryBase = (base_classes.Count == 0);
// offset all previously added bases // offset all previously added bases
foreach (var previousBase in base_classes) { foreach (var previousBase in base_classes)
previousBase.gchandle_offset_delta += baseType.NativeSize; previousBase.gchandle_offset_delta += baseType.NativeSize;
}
// offset derived (this) type's gchandle // offset derived (this) type's gchandle
gchandle_offset_delta += baseType.GCHandleOffset; gchandle_offset_delta += baseType.GCHandleOffset;
baseType.gchandle_offset_delta += native_size_without_padding + CountBases (b => !b.IsPrimaryBase) * IntPtr.Size; baseType.gchandle_offset_delta += native_size_without_padding + CountBases (b => !b.IsPrimaryBase) * IntPtr.Size;
baseType.vt_overrides = baseType.vt_overrides.Clone (); // managed override tramps will be regenerated with correct gchandle offset baseType.vt_overrides = baseType.vt_overrides.Clone (); // managed override tramps will be regenerated with correct gchandle offset
} else { baseType.lazy_vtable = new VTable (baseType);
gchandle_offset_delta = baseType.gchandle_offset_delta; break;
} }
base_classes.Add (baseType); base_classes.Add (baseType);
field_offset_padding_without_vtptr += baseType.native_size_without_padding + field_offset_padding_without_vtptr += baseType.native_size_without_padding +
(addVTablePointer? baseType.FieldOffsetPadding : baseType.field_offset_padding_without_vtptr); (location == BaseVirtualMethods.NewVTable? baseType.FieldOffsetPadding : baseType.field_offset_padding_without_vtptr);
} }
public virtual void CompleteType () public virtual void CompleteType ()
@ -380,7 +387,7 @@ namespace Mono.Cxxi {
public CppTypeInfo BaseTypeInfo { get; set; } public CppTypeInfo BaseTypeInfo { get; set; }
protected override void AddBase (CppTypeInfo baseType, bool addVT) protected override void AddBase (CppTypeInfo baseType, BaseVirtualMethods location)
{ {
BaseTypeInfo = baseType; BaseTypeInfo = baseType;
} }

Loading…
Cancel
Save