forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			182 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===------- MicrosoftCXXABI.cpp - AST support for the Microsoft C++ ABI --===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This provides C++ AST support targeting the Microsoft Visual C++
 | |
| // ABI.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "CXXABI.h"
 | |
| #include "clang/AST/Attr.h"
 | |
| #include "clang/AST/ASTContext.h"
 | |
| #include "clang/AST/DeclCXX.h"
 | |
| #include "clang/AST/RecordLayout.h"
 | |
| #include "clang/AST/Type.h"
 | |
| #include "clang/Basic/TargetInfo.h"
 | |
| 
 | |
| using namespace clang;
 | |
| 
 | |
| namespace {
 | |
| class MicrosoftCXXABI : public CXXABI {
 | |
|   ASTContext &Context;
 | |
| public:
 | |
|   MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
 | |
| 
 | |
|   std::pair<uint64_t, unsigned>
 | |
|   getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const;
 | |
| 
 | |
|   CallingConv getDefaultMethodCallConv(bool isVariadic) const {
 | |
|     if (!isVariadic &&
 | |
|         Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
 | |
|       return CC_X86ThisCall;
 | |
|     return CC_C;
 | |
|   }
 | |
| 
 | |
|   bool isNearlyEmpty(const CXXRecordDecl *RD) const {
 | |
|     // FIXME: Audit the corners
 | |
|     if (!RD->isDynamicClass())
 | |
|       return false;
 | |
| 
 | |
|     const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
 | |
|     
 | |
|     // In the Microsoft ABI, classes can have one or two vtable pointers.
 | |
|     CharUnits PointerSize = 
 | |
|       Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
 | |
|     return Layout.getNonVirtualSize() == PointerSize ||
 | |
|       Layout.getNonVirtualSize() == PointerSize * 2;
 | |
|   }    
 | |
| };
 | |
| }
 | |
| 
 | |
| // getNumBases() seems to only give us the number of direct bases, and not the
 | |
| // total.  This function tells us if we inherit from anybody that uses MI, or if
 | |
| // we have a non-primary base class, which uses the multiple inheritance model.
 | |
| static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {
 | |
|   while (RD->getNumBases() > 0) {
 | |
|     if (RD->getNumBases() > 1)
 | |
|       return true;
 | |
|     assert(RD->getNumBases() == 1);
 | |
|     const CXXRecordDecl *Base =
 | |
|         RD->bases_begin()->getType()->getAsCXXRecordDecl();
 | |
|     if (RD->isPolymorphic() && !Base->isPolymorphic())
 | |
|       return true;
 | |
|     RD = Base;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| static MSInheritanceModel MSInheritanceAttrToModel(attr::Kind Kind) {
 | |
|   switch (Kind) {
 | |
|   default: llvm_unreachable("expected MS inheritance attribute");
 | |
|   case attr::SingleInheritance:      return MSIM_Single;
 | |
|   case attr::MultipleInheritance:    return MSIM_Multiple;
 | |
|   case attr::VirtualInheritance:     return MSIM_Virtual;
 | |
|   case attr::UnspecifiedInheritance: return MSIM_Unspecified;
 | |
|   }
 | |
| }
 | |
| 
 | |
| MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const {
 | |
|   if (Attr *IA = this->getAttr<MSInheritanceAttr>())
 | |
|     return MSInheritanceAttrToModel(IA->getKind());
 | |
|   // If there was no explicit attribute, the record must be defined already, and
 | |
|   // we can figure out the inheritance model from its other properties.
 | |
|   if (this->getNumVBases() > 0)
 | |
|     return MSIM_Virtual;
 | |
|   if (usesMultipleInheritanceModel(this))
 | |
|     return this->isPolymorphic() ? MSIM_MultiplePolymorphic : MSIM_Multiple;
 | |
|   return this->isPolymorphic() ? MSIM_SinglePolymorphic : MSIM_Single;
 | |
| }
 | |
| 
 | |
| // Returns the number of pointer and integer slots used to represent a member
 | |
| // pointer in the MS C++ ABI.
 | |
| //
 | |
| // Member function pointers have the following general form;  however, fields
 | |
| // are dropped as permitted (under the MSVC interpretation) by the inheritance
 | |
| // model of the actual class.
 | |
| //
 | |
| //   struct {
 | |
| //     // A pointer to the member function to call.  If the member function is
 | |
| //     // virtual, this will be a thunk that forwards to the appropriate vftable
 | |
| //     // slot.
 | |
| //     void *FunctionPointerOrVirtualThunk;
 | |
| //
 | |
| //     // An offset to add to the address of the vbtable pointer after (possibly)
 | |
| //     // selecting the virtual base but before resolving and calling the function.
 | |
| //     // Only needed if the class has any virtual bases or bases at a non-zero
 | |
| //     // offset.
 | |
| //     int NonVirtualBaseAdjustment;
 | |
| //
 | |
| //     // An offset within the vb-table that selects the virtual base containing
 | |
| //     // the member.  Loading from this offset produces a new offset that is
 | |
| //     // added to the address of the vb-table pointer to produce the base.
 | |
| //     int VirtualBaseAdjustmentOffset;
 | |
| //
 | |
| //     // The offset of the vb-table pointer within the object.  Only needed for
 | |
| //     // incomplete types.
 | |
| //     int VBPtrOffset;
 | |
| //   };
 | |
| static std::pair<unsigned, unsigned>
 | |
| getMSMemberPointerSlots(const MemberPointerType *MPT) {
 | |
|   const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
 | |
|   MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
 | |
|   unsigned Ptrs;
 | |
|   unsigned Ints = 0;
 | |
|   if (MPT->isMemberFunctionPointer()) {
 | |
|     // Member function pointers are a struct of a function pointer followed by a
 | |
|     // variable number of ints depending on the inheritance model used.  The
 | |
|     // function pointer is a real function if it is non-virtual and a vftable
 | |
|     // slot thunk if it is virtual.  The ints select the object base passed for
 | |
|     // the 'this' pointer.
 | |
|     Ptrs = 1;  // First slot is always a function pointer.
 | |
|     switch (Inheritance) {
 | |
|     case MSIM_Unspecified: ++Ints;  // VBTableOffset
 | |
|     case MSIM_Virtual:     ++Ints;  // VirtualBaseAdjustmentOffset
 | |
|     case MSIM_MultiplePolymorphic:
 | |
|     case MSIM_Multiple:    ++Ints;  // NonVirtualBaseAdjustment
 | |
|     case MSIM_SinglePolymorphic:
 | |
|     case MSIM_Single:      break;   // Nothing
 | |
|     }
 | |
|   } else {
 | |
|     // Data pointers are an aggregate of ints.  The first int is an offset
 | |
|     // followed by vbtable-related offsets.
 | |
|     Ptrs = 0;
 | |
|     switch (Inheritance) {
 | |
|     case MSIM_Unspecified: ++Ints;  // VBTableOffset
 | |
|     case MSIM_Virtual:     ++Ints;  // VirtualBaseAdjustmentOffset
 | |
|     case MSIM_MultiplePolymorphic:
 | |
|     case MSIM_Multiple:             // Nothing
 | |
|     case MSIM_SinglePolymorphic:
 | |
|     case MSIM_Single:      ++Ints;  // Field offset
 | |
|     }
 | |
|   }
 | |
|   return std::make_pair(Ptrs, Ints);
 | |
| }
 | |
| 
 | |
| std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign(
 | |
|     const MemberPointerType *MPT) const {
 | |
|   const TargetInfo &Target = Context.getTargetInfo();
 | |
|   assert(Target.getTriple().getArch() == llvm::Triple::x86 ||
 | |
|          Target.getTriple().getArch() == llvm::Triple::x86_64);
 | |
|   unsigned Ptrs, Ints;
 | |
|   llvm::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT);
 | |
|   // The nominal struct is laid out with pointers followed by ints and aligned
 | |
|   // to a pointer width if any are present and an int width otherwise.
 | |
|   unsigned PtrSize = Target.getPointerWidth(0);
 | |
|   unsigned IntSize = Target.getIntWidth();
 | |
|   uint64_t Width = Ptrs * PtrSize + Ints * IntSize;
 | |
|   unsigned Align = Ptrs > 0 ? Target.getPointerAlign(0) : Target.getIntAlign();
 | |
|   Width = llvm::RoundUpToAlignment(Width, Align);
 | |
|   return std::make_pair(Width, Align);
 | |
| }
 | |
| 
 | |
| CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) {
 | |
|   return new MicrosoftCXXABI(Ctx);
 | |
| }
 | |
| 
 |