MicrosoftCXXABI.cpp revision 263508
1//===------- MicrosoftCXXABI.cpp - AST support for the Microsoft C++ ABI --===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This provides C++ AST support targeting the Microsoft Visual C++ 11// ABI. 12// 13//===----------------------------------------------------------------------===// 14 15#include "CXXABI.h" 16#include "clang/AST/Attr.h" 17#include "clang/AST/ASTContext.h" 18#include "clang/AST/DeclCXX.h" 19#include "clang/AST/MangleNumberingContext.h" 20#include "clang/AST/RecordLayout.h" 21#include "clang/AST/Type.h" 22#include "clang/Basic/TargetInfo.h" 23 24using namespace clang; 25 26namespace { 27 28/// \brief Numbers things which need to correspond across multiple TUs. 29/// Typically these are things like static locals, lambdas, or blocks. 30class MicrosoftNumberingContext : public MangleNumberingContext { 31 unsigned NumStaticLocals; 32 33public: 34 MicrosoftNumberingContext() : NumStaticLocals(0) { } 35 36 /// Static locals are numbered by source order. 37 virtual unsigned getManglingNumber(const VarDecl *VD) { 38 assert(VD->isStaticLocal()); 39 return ++NumStaticLocals; 40 } 41}; 42 43class MicrosoftCXXABI : public CXXABI { 44 ASTContext &Context; 45public: 46 MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { } 47 48 std::pair<uint64_t, unsigned> 49 getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const; 50 51 CallingConv getDefaultMethodCallConv(bool isVariadic) const { 52 if (!isVariadic && 53 Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86) 54 return CC_X86ThisCall; 55 return CC_C; 56 } 57 58 bool isNearlyEmpty(const CXXRecordDecl *RD) const { 59 // FIXME: Audit the corners 60 if (!RD->isDynamicClass()) 61 return false; 62 63 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); 64 65 // In the Microsoft ABI, classes can have one or two vtable pointers. 66 CharUnits PointerSize = 67 Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); 68 return Layout.getNonVirtualSize() == PointerSize || 69 Layout.getNonVirtualSize() == PointerSize * 2; 70 } 71 72 MangleNumberingContext *createMangleNumberingContext() const { 73 return new MicrosoftNumberingContext(); 74 } 75}; 76} 77 78// getNumBases() seems to only give us the number of direct bases, and not the 79// total. This function tells us if we inherit from anybody that uses MI, or if 80// we have a non-primary base class, which uses the multiple inheritance model. 81static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) { 82 while (RD->getNumBases() > 0) { 83 if (RD->getNumBases() > 1) 84 return true; 85 assert(RD->getNumBases() == 1); 86 const CXXRecordDecl *Base = 87 RD->bases_begin()->getType()->getAsCXXRecordDecl(); 88 if (RD->isPolymorphic() && !Base->isPolymorphic()) 89 return true; 90 RD = Base; 91 } 92 return false; 93} 94 95static MSInheritanceModel MSInheritanceAttrToModel(attr::Kind Kind) { 96 switch (Kind) { 97 default: llvm_unreachable("expected MS inheritance attribute"); 98 case attr::SingleInheritance: return MSIM_Single; 99 case attr::MultipleInheritance: return MSIM_Multiple; 100 case attr::VirtualInheritance: return MSIM_Virtual; 101 case attr::UnspecifiedInheritance: return MSIM_Unspecified; 102 } 103} 104 105MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const { 106 if (Attr *IA = this->getAttr<MSInheritanceAttr>()) 107 return MSInheritanceAttrToModel(IA->getKind()); 108 // If there was no explicit attribute, the record must be defined already, and 109 // we can figure out the inheritance model from its other properties. 110 if (this->getNumVBases() > 0) 111 return MSIM_Virtual; 112 if (usesMultipleInheritanceModel(this)) 113 return this->isPolymorphic() ? MSIM_MultiplePolymorphic : MSIM_Multiple; 114 return this->isPolymorphic() ? MSIM_SinglePolymorphic : MSIM_Single; 115} 116 117// Returns the number of pointer and integer slots used to represent a member 118// pointer in the MS C++ ABI. 119// 120// Member function pointers have the following general form; however, fields 121// are dropped as permitted (under the MSVC interpretation) by the inheritance 122// model of the actual class. 123// 124// struct { 125// // A pointer to the member function to call. If the member function is 126// // virtual, this will be a thunk that forwards to the appropriate vftable 127// // slot. 128// void *FunctionPointerOrVirtualThunk; 129// 130// // An offset to add to the address of the vbtable pointer after (possibly) 131// // selecting the virtual base but before resolving and calling the function. 132// // Only needed if the class has any virtual bases or bases at a non-zero 133// // offset. 134// int NonVirtualBaseAdjustment; 135// 136// // An offset within the vb-table that selects the virtual base containing 137// // the member. Loading from this offset produces a new offset that is 138// // added to the address of the vb-table pointer to produce the base. 139// int VirtualBaseAdjustmentOffset; 140// 141// // The offset of the vb-table pointer within the object. Only needed for 142// // incomplete types. 143// int VBPtrOffset; 144// }; 145static std::pair<unsigned, unsigned> 146getMSMemberPointerSlots(const MemberPointerType *MPT) { 147 const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); 148 MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); 149 unsigned Ptrs; 150 unsigned Ints = 0; 151 if (MPT->isMemberFunctionPointer()) { 152 // Member function pointers are a struct of a function pointer followed by a 153 // variable number of ints depending on the inheritance model used. The 154 // function pointer is a real function if it is non-virtual and a vftable 155 // slot thunk if it is virtual. The ints select the object base passed for 156 // the 'this' pointer. 157 Ptrs = 1; // First slot is always a function pointer. 158 switch (Inheritance) { 159 case MSIM_Unspecified: ++Ints; // VBTableOffset 160 case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset 161 case MSIM_MultiplePolymorphic: 162 case MSIM_Multiple: ++Ints; // NonVirtualBaseAdjustment 163 case MSIM_SinglePolymorphic: 164 case MSIM_Single: break; // Nothing 165 } 166 } else { 167 // Data pointers are an aggregate of ints. The first int is an offset 168 // followed by vbtable-related offsets. 169 Ptrs = 0; 170 switch (Inheritance) { 171 case MSIM_Unspecified: ++Ints; // VBTableOffset 172 case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset 173 case MSIM_MultiplePolymorphic: 174 case MSIM_Multiple: // Nothing 175 case MSIM_SinglePolymorphic: 176 case MSIM_Single: ++Ints; // Field offset 177 } 178 } 179 return std::make_pair(Ptrs, Ints); 180} 181 182std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign( 183 const MemberPointerType *MPT) const { 184 const TargetInfo &Target = Context.getTargetInfo(); 185 assert(Target.getTriple().getArch() == llvm::Triple::x86 || 186 Target.getTriple().getArch() == llvm::Triple::x86_64); 187 unsigned Ptrs, Ints; 188 llvm::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT); 189 // The nominal struct is laid out with pointers followed by ints and aligned 190 // to a pointer width if any are present and an int width otherwise. 191 unsigned PtrSize = Target.getPointerWidth(0); 192 unsigned IntSize = Target.getIntWidth(); 193 uint64_t Width = Ptrs * PtrSize + Ints * IntSize; 194 unsigned Align = Ptrs > 0 ? Target.getPointerAlign(0) : Target.getIntAlign(); 195 Width = llvm::RoundUpToAlignment(Width, Align); 196 return std::make_pair(Width, Align); 197} 198 199CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) { 200 return new MicrosoftCXXABI(Ctx); 201} 202 203