aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/ItaniumCXXABI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/ItaniumCXXABI.cpp')
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp244
1 files changed, 244 insertions, 0 deletions
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 13768006f4..85a67a437d 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -48,6 +48,8 @@ protected:
return PtrDiffTy;
}
+ bool NeedsArrayCookie(QualType ElementType);
+
public:
ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) :
CGCXXABI(CGM), PtrDiffTy(0), MangleCtx(CGM.getContext(), CGM.getDiags()),
@@ -108,6 +110,15 @@ public:
FunctionArgList &Params);
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
+
+ CharUnits GetArrayCookieSize(QualType ElementType);
+ llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
+ llvm::Value *NewPtr,
+ llvm::Value *NumElements,
+ QualType ElementType);
+ void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
+ QualType ElementType, llvm::Value *&NumElements,
+ llvm::Value *&AllocPtr, CharUnits &CookieSize);
};
class ARMCXXABI : public ItaniumCXXABI {
@@ -132,6 +143,14 @@ public:
void EmitReturnFromThunk(CodeGenFunction &CGF, RValue RV, QualType ResTy);
+ CharUnits GetArrayCookieSize(QualType ElementType);
+ llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF,
+ llvm::Value *NewPtr,
+ llvm::Value *NumElements,
+ QualType ElementType);
+ void ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *Ptr,
+ QualType ElementType, llvm::Value *&NumElements,
+ llvm::Value *&AllocPtr, CharUnits &CookieSize);
private:
/// \brief Returns true if the given instance method is one of the
@@ -777,3 +796,228 @@ void ARMCXXABI::EmitReturnFromThunk(CodeGenFunction &CGF,
RValue Undef = RValue::get(llvm::UndefValue::get(T));
return ItaniumCXXABI::EmitReturnFromThunk(CGF, Undef, ResultType);
}
+
+/************************** Array allocation cookies **************************/
+
+bool ItaniumCXXABI::NeedsArrayCookie(QualType ElementType) {
+ ElementType = CGM.getContext().getBaseElementType(ElementType);
+ const RecordType *RT = ElementType->getAs<RecordType>();
+ if (!RT) return false;
+
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+
+ // If the class has a non-trivial destructor, it always needs a cookie.
+ if (!RD->hasTrivialDestructor()) return true;
+
+ // If the class's usual deallocation function takes two arguments,
+ // it needs a cookie. Otherwise we don't need a cookie.
+ const CXXMethodDecl *UsualDeallocationFunction = 0;
+
+ // Usual deallocation functions of this form are always found on the
+ // class.
+ //
+ // FIXME: what exactly is this code supposed to do if there's an
+ // ambiguity? That's possible with using declarations.
+ DeclarationName OpName =
+ CGM.getContext().DeclarationNames.getCXXOperatorName(OO_Array_Delete);
+ DeclContext::lookup_const_iterator Op, OpEnd;
+ for (llvm::tie(Op, OpEnd) = RD->lookup(OpName); Op != OpEnd; ++Op) {
+ const CXXMethodDecl *Delete =
+ cast<CXXMethodDecl>((*Op)->getUnderlyingDecl());
+
+ if (Delete->isUsualDeallocationFunction()) {
+ UsualDeallocationFunction = Delete;
+ break;
+ }
+ }
+
+ // No usual deallocation function, we don't need a cookie.
+ if (!UsualDeallocationFunction)
+ return false;
+
+ // The usual deallocation function doesn't take a size_t argument,
+ // so we don't need a cookie.
+ if (UsualDeallocationFunction->getNumParams() == 1)
+ return false;
+
+ assert(UsualDeallocationFunction->getNumParams() == 2 &&
+ "Unexpected deallocation function type!");
+ return true;
+}
+
+CharUnits ItaniumCXXABI::GetArrayCookieSize(QualType ElementType) {
+ if (!NeedsArrayCookie(ElementType))
+ return CharUnits::Zero();
+
+ // Padding is the maximum of sizeof(size_t) and alignof(ElementType)
+ ASTContext &Ctx = CGM.getContext();
+ return std::max(Ctx.getTypeSizeInChars(Ctx.getSizeType()),
+ Ctx.getTypeAlignInChars(ElementType));
+}
+
+llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
+ llvm::Value *NewPtr,
+ llvm::Value *NumElements,
+ QualType ElementType) {
+ assert(NeedsArrayCookie(ElementType));
+
+ unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace();
+
+ ASTContext &Ctx = CGM.getContext();
+ QualType SizeTy = Ctx.getSizeType();
+ CharUnits SizeSize = Ctx.getTypeSizeInChars(SizeTy);
+
+ // The size of the cookie.
+ CharUnits CookieSize =
+ std::max(SizeSize, Ctx.getTypeAlignInChars(ElementType));
+
+ // Compute an offset to the cookie.
+ llvm::Value *CookiePtr = NewPtr;
+ CharUnits CookieOffset = CookieSize - SizeSize;
+ if (!CookieOffset.isZero())
+ CookiePtr = CGF.Builder.CreateConstInBoundsGEP1_64(CookiePtr,
+ CookieOffset.getQuantity());
+
+ // Write the number of elements into the appropriate slot.
+ llvm::Value *NumElementsPtr
+ = CGF.Builder.CreateBitCast(CookiePtr,
+ CGF.ConvertType(SizeTy)->getPointerTo(AS));
+ CGF.Builder.CreateStore(NumElements, NumElementsPtr);
+
+ // Finally, compute a pointer to the actual data buffer by skipping
+ // over the cookie completely.
+ return CGF.Builder.CreateConstInBoundsGEP1_64(NewPtr,
+ CookieSize.getQuantity());
+}
+
+void ItaniumCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
+ llvm::Value *Ptr,
+ 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();
+ const llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS);
+
+ // If we don't need an array cookie, bail out early.
+ if (!NeedsArrayCookie(ElementType)) {
+ AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy);
+ NumElements = 0;
+ CookieSize = CharUnits::Zero();
+ return;
+ }
+
+ QualType SizeTy = CGF.getContext().getSizeType();
+ CharUnits SizeSize = CGF.getContext().getTypeSizeInChars(SizeTy);
+ const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
+
+ CookieSize
+ = std::max(SizeSize, CGF.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);
+}
+
+CharUnits ARMCXXABI::GetArrayCookieSize(QualType ElementType) {
+ if (!NeedsArrayCookie(ElementType))
+ return CharUnits::Zero();
+
+ // On ARM, the cookie is always:
+ // struct array_cookie {
+ // std::size_t element_size; // element_size != 0
+ // std::size_t element_count;
+ // };
+ // TODO: what should we do if the allocated type actually wants
+ // greater alignment?
+ return getContext().getTypeSizeInChars(getContext().getSizeType()) * 2;
+}
+
+llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF,
+ llvm::Value *NewPtr,
+ llvm::Value *NumElements,
+ QualType ElementType) {
+ assert(NeedsArrayCookie(ElementType));
+
+ // NewPtr is a char*.
+
+ unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace();
+
+ ASTContext &Ctx = CGM.getContext();
+ CharUnits SizeSize = Ctx.getTypeSizeInChars(Ctx.getSizeType());
+ const llvm::IntegerType *SizeTy =
+ cast<llvm::IntegerType>(CGF.ConvertType(Ctx.getSizeType()));
+
+ // The cookie is always at the start of the buffer.
+ llvm::Value *CookiePtr = NewPtr;
+
+ // The first element is the element size.
+ CookiePtr = CGF.Builder.CreateBitCast(CookiePtr, SizeTy->getPointerTo(AS));
+ llvm::Value *ElementSize = llvm::ConstantInt::get(SizeTy,
+ Ctx.getTypeSizeInChars(ElementType).getQuantity());
+ CGF.Builder.CreateStore(ElementSize, CookiePtr);
+
+ // The second element is the element count.
+ CookiePtr = CGF.Builder.CreateConstInBoundsGEP1_32(CookiePtr, 1);
+ CGF.Builder.CreateStore(NumElements, CookiePtr);
+
+ // Finally, compute a pointer to the actual data buffer by skipping
+ // over the cookie completely.
+ CharUnits CookieSize = 2 * SizeSize;
+ return CGF.Builder.CreateConstInBoundsGEP1_64(NewPtr,
+ CookieSize.getQuantity());
+}
+
+void ARMCXXABI::ReadArrayCookie(CodeGenFunction &CGF,
+ llvm::Value *Ptr,
+ 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();
+ const llvm::Type *CharPtrTy = CGF.Builder.getInt8Ty()->getPointerTo(AS);
+
+ // If we don't need an array cookie, bail out early.
+ if (!NeedsArrayCookie(ElementType)) {
+ AllocPtr = CGF.Builder.CreateBitCast(Ptr, CharPtrTy);
+ NumElements = 0;
+ CookieSize = CharUnits::Zero();
+ return;
+ }
+
+ QualType SizeTy = CGF.getContext().getSizeType();
+ CharUnits SizeSize = CGF.getContext().getTypeSizeInChars(SizeTy);
+ const llvm::Type *SizeLTy = CGF.ConvertType(SizeTy);
+
+ // The cookie size is always 2 * sizeof(size_t).
+ CookieSize = 2 * SizeSize;
+ CharUnits NumElementsOffset = CookieSize - 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);
+}
+