diff options
Diffstat (limited to 'lib/CodeGen/ItaniumCXXABI.cpp')
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 257 |
1 files changed, 109 insertions, 148 deletions
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 98f67f3..0b7ce36 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -20,6 +20,7 @@ #include "CGCXXABI.h" #include "CGRecordLayout.h" +#include "CGVTables.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include <clang/AST/Mangle.h> @@ -48,10 +49,6 @@ protected: return PtrDiffTy; } - bool NeedsArrayCookie(const CXXNewExpr *expr); - bool NeedsArrayCookie(const CXXDeleteExpr *expr, - QualType elementType); - public: ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) : CGCXXABI(CGM), PtrDiffTy(0), IsARM(IsARM) { } @@ -111,19 +108,24 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); - CharUnits GetArrayCookieSize(const CXXNewExpr *expr); + StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; } + + CharUnits getArrayCookieSizeImpl(QualType elementType); llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF, llvm::Value *NewPtr, llvm::Value *NumElements, const CXXNewExpr *expr, QualType ElementType); - void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, - const CXXDeleteExpr *expr, - QualType ElementType, llvm::Value *&NumElements, - llvm::Value *&AllocPtr, CharUnits &CookieSize); + llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, + llvm::Value *allocPtr, + CharUnits cookieSize); void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, llvm::GlobalVariable *DeclPtr, bool PerformInit); + void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor, + llvm::Constant *addr); + + void EmitVTables(const CXXRecordDecl *Class); }; class ARMCXXABI : public ItaniumCXXABI { @@ -148,16 +150,14 @@ public: void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy); - CharUnits GetArrayCookieSize(const CXXNewExpr *expr); + CharUnits getArrayCookieSizeImpl(QualType elementType); llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF, llvm::Value *NewPtr, llvm::Value *NumElements, const CXXNewExpr *expr, QualType ElementType); - void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr, - const CXXDeleteExpr *expr, - QualType ElementType, llvm::Value *&NumElements, - llvm::Value *&AllocPtr, CharUnits &CookieSize); + llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr, + CharUnits cookieSize); private: /// \brief Returns true if the given instance method is one of the @@ -796,54 +796,11 @@ void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF, /************************** Array allocation cookies **************************/ -bool ItaniumCXXABI::NeedsArrayCookie(const CXXNewExpr *expr) { - // If the class's usual deallocation function takes two arguments, - // it needs a cookie. - if (expr->doesUsualArrayDeleteWantSize()) - return true; - - // Automatic Reference Counting: - // We need an array cookie for pointers with strong or weak lifetime. - QualType AllocatedType = expr->getAllocatedType(); - if (getContext().getLangOpts().ObjCAutoRefCount && - AllocatedType->isObjCLifetimeType()) { - switch (AllocatedType.getObjCLifetime()) { - case Qualifiers::OCL_None: - case Qualifiers::OCL_ExplicitNone: - case Qualifiers::OCL_Autoreleasing: - return false; - - case Qualifiers::OCL_Strong: - case Qualifiers::OCL_Weak: - return true; - } - } - - // Otherwise, if the class has a non-trivial destructor, it always - // needs a cookie. - const CXXRecordDecl *record = - AllocatedType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); - return (record && !record->hasTrivialDestructor()); -} - -bool ItaniumCXXABI::NeedsArrayCookie(const CXXDeleteExpr *expr, - QualType elementType) { - // If the class's usual deallocation function takes two arguments, - // it needs a cookie. - if (expr->doesUsualArrayDeleteWantSize()) - return true; - - return elementType.isDestructedType(); -} - -CharUnits ItaniumCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) { - if (!NeedsArrayCookie(expr)) - return CharUnits::Zero(); - - // Padding is the maximum of sizeof(size_t) and alignof(elementType) - ASTContext &Ctx = getContext(); - return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()), - Ctx.getTypeAlignInChars(expr->getAllocatedType())); +CharUnits ItaniumCXXABI::getArrayCookieSizeImpl(QualType elementType) { + // The array cookie is a size_t; pad that up to the element alignment. + // The cookie is actually right-justified in that space. + return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes), + CGM.getContext().getTypeAlignInChars(elementType)); } llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, @@ -851,7 +808,7 @@ llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, llvm::Value *NumElements, const CXXNewExpr *expr, QualType ElementType) { - assert(NeedsArrayCookie(expr)); + assert(requiresArrayCookie(expr)); unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace(); @@ -862,6 +819,7 @@ llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, // The size of the cookie. CharUnits CookieSize = std::max(SizeSize, Ctx.getTypeAlignInChars(ElementType)); + assert(CookieSize == getArrayCookieSizeImpl(ElementType)); // Compute an offset to the cookie. llvm::Value *CookiePtr = NewPtr; @@ -882,53 +840,25 @@ llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, CookieSize.getQuantity()); } -void ItaniumCXXABI::ReadArrayCookie(CodeGenFunction &CGF, - llvm::Value *Ptr, - const CXXDeleteExpr *expr, - QualType ElementType, - llvm::Value *&NumElements, - llvm::Value *&AllocPtr, - CharUnits &CookieSize) { - // Derive a char* in the same address space as the pointer. - unsigned AS = cast<llvm::PointerType>(Ptr->getType())->getAddressSpace(); - llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS); - - // If we don't need an array cookie, bail out early. - if (!NeedsArrayCookie(expr, ElementType)) { - AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy); - NumElements = 0; - CookieSize = CharUnits::Zero(); - return; - } - - QualType SizeTy = getContext().getSizeType(); - CharUnits SizeSize = getContext().getTypeSizeInChars(SizeTy); - llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); - - CookieSize - = std::max(SizeSize, getContext().getTypeAlignInChars(ElementType)); - - CharUnits NumElementsOffset = CookieSize - SizeSize; - - // Compute the allocated pointer. - AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy); - AllocPtr = CGF.Builder.CreateConstInBoundsGEP1_64(AllocPtr, - -CookieSize.getQuantity()); - - llvm::Value *NumElementsPtr = AllocPtr; - if (!NumElementsOffset.isZero()) - NumElementsPtr = - CGF.Builder.CreateConstInBoundsGEP1_64(NumElementsPtr, - NumElementsOffset.getQuantity()); - NumElementsPtr = - CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo(AS)); - NumElements = CGF.Builder.CreateLoad(NumElementsPtr); +llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, + llvm::Value *allocPtr, + CharUnits cookieSize) { + // The element size is right-justified in the cookie. + llvm::Value *numElementsPtr = allocPtr; + CharUnits numElementsOffset = + cookieSize - CharUnits::fromQuantity(CGF.SizeSizeInBytes); + if (!numElementsOffset.isZero()) + numElementsPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(numElementsPtr, + numElementsOffset.getQuantity()); + + unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace(); + numElementsPtr = + CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS)); + return CGF.Builder.CreateLoad(numElementsPtr); } -CharUnits ARMCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) { - if (!NeedsArrayCookie(expr)) - return CharUnits::Zero(); - +CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) { // On ARM, the cookie is always: // struct array_cookie { // std::size_t element_size; // element_size != 0 @@ -936,7 +866,7 @@ CharUnits ARMCXXABI::GetArrayCookieSize(const CXXNewExpr *expr) { // }; // TODO: what should we do if the allocated type actually wants // greater alignment? - return getContext().getTypeSizeInChars(getContext().getSizeType()) * 2; + return CharUnits::fromQuantity(2 * CGM.SizeSizeInBytes); } llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, @@ -944,7 +874,7 @@ llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, llvm::Value *NumElements, const CXXNewExpr *expr, QualType ElementType) { - assert(NeedsArrayCookie(expr)); + assert(requiresArrayCookie(expr)); // NewPtr is a char*. @@ -975,44 +905,18 @@ llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, CookieSize.getQuantity()); } -void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF, - llvm::Value *Ptr, - const CXXDeleteExpr *expr, - QualType ElementType, - llvm::Value *&NumElements, - llvm::Value *&AllocPtr, - CharUnits &CookieSize) { - // Derive a char* in the same address space as the pointer. - unsigned AS = cast<llvm::PointerType>(Ptr->getType())->getAddressSpace(); - llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS); - - // If we don't need an array cookie, bail out early. - if (!NeedsArrayCookie(expr, ElementType)) { - AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy); - NumElements = 0; - CookieSize = CharUnits::Zero(); - return; - } - - QualType SizeTy = getContext().getSizeType(); - CharUnits SizeSize = getContext().getTypeSizeInChars(SizeTy); - llvm::Type *SizeLTy = CGF.ConvertType(SizeTy); - - // The cookie size is always 2 * sizeof(size_t). - CookieSize = 2 * SizeSize; - - // The allocated pointer is the input ptr, minus that amount. - AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy); - AllocPtr = CGF.Builder.CreateConstInBoundsGEP1_64(AllocPtr, - -CookieSize.getQuantity()); - - // The number of elements is at offset sizeof(size_t) relative to that. - llvm::Value *NumElementsPtr - = CGF.Builder.CreateConstInBoundsGEP1_64(AllocPtr, - SizeSize.getQuantity()); - NumElementsPtr = - CGF.Builder.CreateBitCast(NumElementsPtr, SizeLTy->getPointerTo(AS)); - NumElements = CGF.Builder.CreateLoad(NumElementsPtr); +llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, + llvm::Value *allocPtr, + CharUnits cookieSize) { + // The number of elements is at offset sizeof(size_t) relative to + // the allocated pointer. + llvm::Value *numElementsPtr + = CGF.Builder.CreateConstInBoundsGEP1_64(allocPtr, CGF.SizeSizeInBytes); + + unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace(); + numElementsPtr = + CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS)); + return CGF.Builder.CreateLoad(numElementsPtr); } /*********************** Static local initialization **************************/ @@ -1200,3 +1104,60 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, CGF.EmitBlock(EndBlock); } + +/// Register a global destructor using __cxa_atexit. +static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF, + llvm::Constant *dtor, + llvm::Constant *addr) { + // We're assuming that the destructor function is something we can + // reasonably call with the default CC. Go ahead and cast it to the + // right prototype. + llvm::Type *dtorTy = + llvm::FunctionType::get(CGF.VoidTy, CGF.Int8PtrTy, false)->getPointerTo(); + + // extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d); + llvm::Type *paramTys[] = { dtorTy, CGF.Int8PtrTy, CGF.Int8PtrTy }; + llvm::FunctionType *atexitTy = + llvm::FunctionType::get(CGF.IntTy, paramTys, false); + + // Fetch the actual function. + llvm::Constant *atexit = + CGF.CGM.CreateRuntimeFunction(atexitTy, "__cxa_atexit"); + if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit)) + fn->setDoesNotThrow(); + + // Create a variable that binds the atexit to this shared object. + llvm::Constant *handle = + CGF.CGM.CreateRuntimeVariable(CGF.Int8Ty, "__dso_handle"); + + llvm::Value *args[] = { + llvm::ConstantExpr::getBitCast(dtor, dtorTy), + llvm::ConstantExpr::getBitCast(addr, CGF.Int8PtrTy), + handle + }; + CGF.Builder.CreateCall(atexit, args)->setDoesNotThrow(); +} + +/// Register a global destructor as best as we know how. +void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF, + llvm::Constant *dtor, + llvm::Constant *addr) { + // Use __cxa_atexit if available. + if (CGM.getCodeGenOpts().CXAAtExit) { + return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr); + } + + // In Apple kexts, we want to add a global destructor entry. + // FIXME: shouldn't this be guarded by some variable? + if (CGM.getContext().getLangOpts().AppleKext) { + // Generate a global destructor entry. + return CGM.AddCXXDtorEntry(dtor, addr); + } + + CGF.registerGlobalDtorWithAtExit(dtor, addr); +} + +/// Generate and emit virtual tables for the given class. +void ItaniumCXXABI::EmitVTables(const CXXRecordDecl *Class) { + CGM.getVTables().GenerateClassData(CGM.getVTableLinkage(Class), Class); +} |