[cfe-dev] CGRecordLayoutBuilder for MS ABI

r4start r4start at gmail.com
Wed Nov 2 01:32:15 PDT 2011


On 02/11/2011 10:12, John McCall wrote:
> On Oct 30, 2011, at 11:56 PM, r4start wrote:
>> Please review new patch.
>> I added the generation of padding bytes between vfptr&  vbptr.
> +  } else if (Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft&&
> +             !PrimaryBase&&  RD->isPolymorphic()&&
> +             (RD->getNumVBases() == 0 || HasNewVirtualFunction(RD))) {
> +
>
> Please add the following comment:
>    // In the MS ABI, we need a vfptr if this class defines new virtual
>    // functions but has no primary base.  The AST doesn't tell us
>    // directly that a class has new virtual functions, and checking for it
>    // is a bit expensive, but we can avoid the full check in some important
>    // cases:  non-polymorphic classes have no virtual functions by
>    // definition, whereas polymorphic classes must either declare new
>    // virtual functions or inherit them from some base, and if that base
>    // were non-virtual then there would be a primary base.
>
> -    if (HasNewVirtualFunction(RD)&&
> -        (!PrimaryBase || !BaseHasVFPtr(PrimaryBase))) {
> -      EnsureVTablePointerAlignment(PtrAlign);
> -      VFPtrOffset = getSize();
> -      setSize(getSize() + PtrWidth);
> -      setDataSize(getSize());
> -    }
> -    if (RD->getNumVBases()&&
> +    if (HasDirectVirtualBases&&
>           (!PrimaryBase || !PrimaryBase->getNumVBases())) {
>
> I'm sorry if I've asked this before, but have you verified that this is the
> correct condition?  Specifically, does the ABI not re-use vbptrs from
> non-primary non-virtual bases?
>
> For example, consider this hierarchy:
>    class A { int a; };
>    class B { int b; virtual void foo(); };
>    class C : public virtual A { int c; };
>    class D { int d; };
>    class E : public B, public virtual D { int e; };
>
> Does class E ultimately have two vbptrs or one?
In this test E will be have one vbptr. But if class E was declared like 
this "class E : public C, public virtual D" my code will generate 2 vbptr.
I fix it.
>
> +    } else if (Layout.getVFPtrOffset() != CharUnits::fromQuantity(-1)) {
> +        llvm::Type *FunctionType =
> +          llvm::FunctionType::get(llvm::Type::getInt32Ty(Types.getLLVMContext()),
> +          /*isVarArg=*/true);
> +        llvm::Type *VTableTy = FunctionType->getPointerTo();
> +
> +        assert(NextFieldOffset.isZero()&&
> +          "VTable pointer must come first!");
> +        AppendField(Layout.getVFPtrOffset(), VTableTy->getPointerTo());
>
> Indentation.
>
> +
> +  if (Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1)) {
> +    CharUnits VBPtrOffset = Layout.getVBPtrOffset();
> +    if (NextFieldOffset<  VBPtrOffset) {
> +      AppendBytes(VBPtrOffset - NextFieldOffset);
> +    }
> +    llvm::Type *Vbptr = llvm::Type::getInt32PtrTy(Types.getLLVMContext());
> +    AppendField(VBPtrOffset, Vbptr);
> +  }
>
> I'm still not sure why this is necessary.  AppendField should already
> be adding padding to bring NextFieldOffset up to VBPtrOffset.  The
> only time it doesn't add that padding explicitly is when the ABI
> alignment of the field type being added would implicitly introduce it.
As you can see AppendField just does :
1. Save field type in types;
2. Renew NextField offset (NextField = fieldOffset + fieldSize).

>
> +  if (alignedNextFieldOffset<  fieldOffset ||
> +      (!Packed&&  (fieldOffset != NextFieldOffset))) {
class D {
public:
   virtual void b(){}
   double a;
};
struct I : public virtual D
{
   virtual ~I(){}
   double q;
};
For this example, we see that fieldOffset = 0x10 for q and 
alignedNextFieldOffset = 0x10, but NextFieldOffset = 0x0c.
Second condition wrong for MS ABI and useless for other ABI.
I think this condition may look like
if (alignedNextFieldOffset < fieldOffset)
else if ((ABI == MS ABI) && (alignedNextFieldOffset < fieldOffset 
||fieldOffset !=  NextFieldOffset))

  - Dmitry.



More information about the cfe-dev mailing list