#include "CGCXXABI.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/CodeGenOptions.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
using namespace CodeGen;
bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
if (!getCodeGenOpts().CXXCtorDtorAliases)
return true;
if (getCodeGenOpts().OptimizationLevel == 0)
return true;
if (getCodeGenOpts().SanitizeMemoryUseAfterDtor &&
!D->getParent()->field_empty())
return true;
if (!D->hasTrivialBody())
return true;
const CXXRecordDecl *Class = D->getParent();
if (Class->mayInsertExtraPadding())
return true;
if (Class->getNumVBases()) {
return true;
}
for (const auto *I : Class->fields())
if (I->getType().isDestructedType())
return true;
const CXXRecordDecl *UniqueBase = nullptr;
for (const auto &I : Class->bases()) {
if (I.isVirtual()) continue;
const auto *Base =
cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
if (Base->hasTrivialDestructor()) continue;
if (UniqueBase) return true;
UniqueBase = Base;
}
if (!UniqueBase)
return true;
const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(Class);
if (!ClassLayout.getBaseClassOffset(UniqueBase).isZero())
return true;
const CXXDestructorDecl *BaseD = UniqueBase->getDestructor();
if (BaseD->getType()->castAs<FunctionType>()->getCallConv() !=
D->getType()->castAs<FunctionType>()->getCallConv())
return true;
GlobalDecl AliasDecl(D, Dtor_Base);
GlobalDecl TargetDecl(BaseD, Dtor_Base);
llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl);
if (!llvm::GlobalAlias::isValidLinkage(Linkage))
return true;
llvm::GlobalValue::LinkageTypes TargetLinkage =
getFunctionLinkage(TargetDecl);
StringRef MangledName = getMangledName(AliasDecl);
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
if (Entry && !Entry->isDeclaration())
return false;
if (Replacements.count(MangledName))
return false;
llvm::Type *AliasValueType = getTypes().GetFunctionType(AliasDecl);
llvm::PointerType *AliasType = AliasValueType->getPointerTo();
auto *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
llvm::Constant *Aliasee = Ref;
if (Ref->getType() != AliasType)
Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType);
if (llvm::GlobalValue::isDiscardableIfUnused(Linkage) &&
!(TargetLinkage == llvm::GlobalValue::AvailableExternallyLinkage &&
TargetDecl.getDecl()->hasAttr<AlwaysInlineAttr>())) {
addReplacement(MangledName, Aliasee);
return false;
}
if (llvm::GlobalValue::isWeakForLinker(Linkage) &&
getTriple().isOSBinFormatCOFF()) {
return true;
}
if (Ref->isDeclarationForLinker())
return true;
if (llvm::GlobalValue::isWeakForLinker(TargetLinkage))
return true;
auto *Alias = llvm::GlobalAlias::create(AliasValueType, 0, Linkage, "",
Aliasee, &getModule());
Alias->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
if (Entry) {
assert(Entry->getType() == AliasType &&
"declaration exists with different type");
Alias->takeName(Entry);
Entry->replaceAllUsesWith(Alias);
Entry->eraseFromParent();
} else {
Alias->setName(MangledName);
}
SetCommonAttributes(AliasDecl, Alias);
return false;
}
llvm::Function *CodeGenModule::codegenCXXStructor(GlobalDecl GD) {
const CGFunctionInfo &FnInfo = getTypes().arrangeCXXStructorDeclaration(GD);
auto *Fn = cast<llvm::Function>(
getAddrOfCXXStructor(GD, &FnInfo, nullptr,
true, ForDefinition));
setFunctionLinkage(GD, Fn);
CodeGenFunction(*this).GenerateCode(GD, Fn, FnInfo);
setNonAliasAttributes(GD, Fn);
SetLLVMFunctionAttributesForDefinition(cast<CXXMethodDecl>(GD.getDecl()), Fn);
return Fn;
}
llvm::FunctionCallee CodeGenModule::getAddrAndTypeOfCXXStructor(
GlobalDecl GD, const CGFunctionInfo *FnInfo, llvm::FunctionType *FnType,
bool DontDefer, ForDefinition_t IsForDefinition) {
auto *MD = cast<CXXMethodDecl>(GD.getDecl());
if (isa<CXXDestructorDecl>(MD)) {
if (getTarget().getCXXABI().isMicrosoft() &&
GD.getDtorType() == Dtor_Complete &&
MD->getParent()->getNumVBases() == 0)
GD = GD.getWithDtorType(Dtor_Base);
}
if (!FnType) {
if (!FnInfo)
FnInfo = &getTypes().arrangeCXXStructorDeclaration(GD);
FnType = getTypes().GetFunctionType(*FnInfo);
}
llvm::Constant *Ptr = GetOrCreateLLVMFunction(
getMangledName(GD), FnType, GD, false, DontDefer,
false, llvm::AttributeList(), IsForDefinition);
return {FnType, Ptr};
}
static CGCallee BuildAppleKextVirtualCall(CodeGenFunction &CGF,
GlobalDecl GD,
llvm::Type *Ty,
const CXXRecordDecl *RD) {
assert(!CGF.CGM.getTarget().getCXXABI().isMicrosoft() &&
"No kext in Microsoft ABI");
CodeGenModule &CGM = CGF.CGM;
llvm::Value *VTable = CGM.getCXXABI().getAddrOfVTable(RD, CharUnits());
Ty = Ty->getPointerTo();
VTable = CGF.Builder.CreateBitCast(VTable, Ty->getPointerTo());
assert(VTable && "BuildVirtualCall = kext vtbl pointer is null");
uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD);
const VTableLayout &VTLayout = CGM.getItaniumVTableContext().getVTableLayout(RD);
VTableLayout::AddressPointLocation AddressPoint =
VTLayout.getAddressPoint(BaseSubobject(RD, CharUnits::Zero()));
VTableIndex += VTLayout.getVTableOffset(AddressPoint.VTableIndex) +
AddressPoint.AddressPointIndex;
llvm::Value *VFuncPtr =
CGF.Builder.CreateConstInBoundsGEP1_64(Ty, VTable, VTableIndex, "vfnkxt");
llvm::Value *VFunc = CGF.Builder.CreateAlignedLoad(
Ty, VFuncPtr, llvm::Align(CGF.PointerAlignInBytes));
CGCallee Callee(GD, VFunc);
return Callee;
}
CGCallee
CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD,
NestedNameSpecifier *Qual,
llvm::Type *Ty) {
assert((Qual->getKind() == NestedNameSpecifier::TypeSpec) &&
"BuildAppleKextVirtualCall - bad Qual kind");
const Type *QTy = Qual->getAsType();
QualType T = QualType(QTy, 0);
const RecordType *RT = T->getAs<RecordType>();
assert(RT && "BuildAppleKextVirtualCall - Qual type must be record");
const auto *RD = cast<CXXRecordDecl>(RT->getDecl());
if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD))
return BuildAppleKextVirtualDestructorCall(DD, Dtor_Complete, RD);
return ::BuildAppleKextVirtualCall(*this, MD, Ty, RD);
}
CGCallee
CodeGenFunction::BuildAppleKextVirtualDestructorCall(
const CXXDestructorDecl *DD,
CXXDtorType Type,
const CXXRecordDecl *RD) {
assert(DD->isVirtual() && Type != Dtor_Base);
const CGFunctionInfo &FInfo = CGM.getTypes().arrangeCXXStructorDeclaration(
GlobalDecl(DD, Dtor_Complete));
llvm::Type *Ty = CGM.getTypes().GetFunctionType(FInfo);
return ::BuildAppleKextVirtualCall(*this, GlobalDecl(DD, Type), Ty, RD);
}