Skip to content

Commit

Permalink
[MS-ABI] Implements MS-compatible RTTI
Browse files Browse the repository at this point in the history
Enables the emission of MS-compatible RTTI data structures for use with 
typeid, dynamic_cast and exceptions.  Does not implement dynamic_cast 
or exceptions.  As an artiface, typeid works in some cases but proper 
support an testing will coming in a subsequent patch.

majnemer has fuzzed the results.  Test cases included.

Differential Revision: http://reviews.llvm.org/D3833

llvm-svn: 209523
  • Loading branch information
spiderofmean committed May 23, 2014
1 parent 2be4a28 commit 5c2b4ea
Show file tree
Hide file tree
Showing 9 changed files with 656 additions and 47 deletions.
2 changes: 1 addition & 1 deletion clang/include/clang/AST/Mangle.h
Expand Up @@ -214,7 +214,7 @@ class MicrosoftMangleContext : public MangleContext {
raw_ostream &) = 0;

virtual void mangleCXXRTTIBaseClassDescriptor(
const CXXRecordDecl *Derived, uint32_t NVOffset, uint32_t VBPtrOffset,
const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset,
uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) = 0;

virtual void mangleCXXRTTIBaseClassArray(const CXXRecordDecl *Derived,
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/AST/MicrosoftMangle.cpp
Expand Up @@ -113,7 +113,7 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
void mangleCXXRTTIName(QualType T, raw_ostream &Out) override;
void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
uint32_t NVOffset, uint32_t VBPtrOffset,
uint32_t NVOffset, int32_t VBPtrOffset,
uint32_t VBTableOffset, uint32_t Flags,
raw_ostream &Out) override;
void mangleCXXRTTIBaseClassArray(const CXXRecordDecl *Derived,
Expand Down Expand Up @@ -2258,7 +2258,7 @@ void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T,
}

void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassDescriptor(
const CXXRecordDecl *Derived, uint32_t NVOffset, uint32_t VBPtrOffset,
const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset,
uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) {
MicrosoftCXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "\01??_R1";
Expand All @@ -2267,23 +2267,23 @@ void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassDescriptor(
Mangler.mangleNumber(VBTableOffset);
Mangler.mangleNumber(Flags);
Mangler.mangleName(Derived);
Mangler.getStream() << "@8";
Mangler.getStream() << "8";
}

void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassArray(
const CXXRecordDecl *Derived, raw_ostream &Out) {
MicrosoftCXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "\01??_R2";
Mangler.mangleName(Derived);
Mangler.getStream() << "@8";
Mangler.getStream() << "8";
}

void MicrosoftMangleContextImpl::mangleCXXRTTIClassHierarchyDescriptor(
const CXXRecordDecl *Derived, raw_ostream &Out) {
MicrosoftCXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "\01??_R3";
Mangler.mangleName(Derived);
Mangler.getStream() << "@8";
Mangler.getStream() << "8";
}

void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator(
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/CGExpr.cpp
Expand Up @@ -2086,7 +2086,7 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) {
/// integer, 1 for a floating point value, and -1 for anything else.
llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
// Only emit each type's descriptor once.
if (llvm::Constant *C = CGM.getTypeDescriptor(T))
if (llvm::Constant *C = CGM.getTypeDescriptorFromMap(T))
return C;

uint16_t TypeKind = -1;
Expand Down Expand Up @@ -2121,7 +2121,7 @@ llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) {
GV->setUnnamedAddr(true);

// Remember the descriptor for this type.
CGM.setTypeDescriptor(T, GV);
CGM.setTypeDescriptorInMap(T, GV);

return GV;
}
Expand Down
71 changes: 38 additions & 33 deletions clang/lib/CodeGen/CGRTTI.cpp
Expand Up @@ -22,7 +22,7 @@ using namespace clang;
using namespace CodeGen;

namespace {
class RTTIBuilder {
class ItaniumRTTIBuilder {
CodeGenModule &CGM; // Per-module state.
llvm::LLVMContext &VMContext;

Expand Down Expand Up @@ -62,7 +62,7 @@ class RTTIBuilder {
void BuildPointerToMemberTypeInfo(const MemberPointerType *Ty);

public:
RTTIBuilder(CodeGenModule &CGM) : CGM(CGM),
ItaniumRTTIBuilder(CodeGenModule &CGM) : CGM(CGM),
VMContext(CGM.getModule().getContext()) { }

// Pointer type info flags.
Expand Down Expand Up @@ -110,7 +110,7 @@ class RTTIBuilder {
}

llvm::GlobalVariable *
RTTIBuilder::GetAddrOfTypeName(QualType Ty,
ItaniumRTTIBuilder::GetAddrOfTypeName(QualType Ty,
llvm::GlobalVariable::LinkageTypes Linkage) {
SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
Expand All @@ -132,7 +132,8 @@ RTTIBuilder::GetAddrOfTypeName(QualType Ty,
return GV;
}

llvm::Constant *RTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
llvm::Constant *
ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
// Mangle the RTTI name.
SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
Expand Down Expand Up @@ -317,8 +318,8 @@ static bool ContainsIncompleteClassType(QualType Ty) {

/// getTypeInfoLinkage - Return the linkage that the type info and type info
/// name constants should have for the given type.
static llvm::GlobalVariable::LinkageTypes
getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
llvm::GlobalVariable::LinkageTypes
CodeGenModule::getTypeInfoLinkage(QualType Ty) {
// Itanium C++ ABI 2.9.5p7:
// In addition, it and all of the intermediate abi::__pointer_type_info
// structs in the chain down to the abi::__class_type_info for the
Expand All @@ -339,7 +340,7 @@ getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {

case VisibleNoLinkage:
case ExternalLinkage:
if (!CGM.getLangOpts().RTTI) {
if (!getLangOpts().RTTI) {
// RTTI is not enabled, which means that this type info struct is going
// to be used for exception handling. Give it linkonce_odr linkage.
return llvm::GlobalValue::LinkOnceODRLinkage;
Expand All @@ -350,7 +351,7 @@ getTypeInfoLinkage(CodeGenModule &CGM, QualType Ty) {
if (RD->hasAttr<WeakAttr>())
return llvm::GlobalValue::WeakODRLinkage;
if (RD->isDynamicClass())
return CGM.getVTableLinkage(RD);
return getVTableLinkage(RD);
}

return llvm::GlobalValue::LinkOnceODRLinkage;
Expand Down Expand Up @@ -388,7 +389,7 @@ static bool CanUseSingleInheritance(const CXXRecordDecl *RD) {
return true;
}

void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
// abi::__class_type_info.
static const char * const ClassTypeInfo =
"_ZTVN10__cxxabiv117__class_type_infoE";
Expand Down Expand Up @@ -509,7 +510,7 @@ void RTTIBuilder::BuildVTablePointer(const Type *Ty) {
Fields.push_back(VTable);
}

llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
// We want to operate on the canonical type.
Ty = CGM.getContext().getCanonicalType(Ty);

Expand Down Expand Up @@ -538,7 +539,7 @@ llvm::Constant *RTTIBuilder::BuildTypeInfo(QualType Ty, bool Force) {
if (IsStdLib)
Linkage = llvm::GlobalValue::ExternalLinkage;
else
Linkage = getTypeInfoLinkage(CGM, Ty);
Linkage = CGM.getTypeInfoLinkage(Ty);

// Add the vtable pointer.
BuildVTablePointer(cast<Type>(Ty));
Expand Down Expand Up @@ -699,18 +700,18 @@ static unsigned ComputeQualifierFlags(Qualifiers Quals) {
unsigned Flags = 0;

if (Quals.hasConst())
Flags |= RTTIBuilder::PTI_Const;
Flags |= ItaniumRTTIBuilder::PTI_Const;
if (Quals.hasVolatile())
Flags |= RTTIBuilder::PTI_Volatile;
Flags |= ItaniumRTTIBuilder::PTI_Volatile;
if (Quals.hasRestrict())
Flags |= RTTIBuilder::PTI_Restrict;
Flags |= ItaniumRTTIBuilder::PTI_Restrict;

return Flags;
}

/// BuildObjCObjectTypeInfo - Build the appropriate kind of type_info
/// for the given Objective-C object type.
void RTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) {
void ItaniumRTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) {
// Drop qualifiers.
const Type *T = OT->getBaseType().getTypePtr();
assert(isa<BuiltinType>(T) || isa<ObjCInterfaceType>(T));
Expand All @@ -728,18 +729,18 @@ void RTTIBuilder::BuildObjCObjectTypeInfo(const ObjCObjectType *OT) {
QualType SuperTy = CGM.getContext().getObjCInterfaceType(Super);

// Everything else is single inheritance.
llvm::Constant *BaseTypeInfo = RTTIBuilder(CGM).BuildTypeInfo(SuperTy);
llvm::Constant *BaseTypeInfo = ItaniumRTTIBuilder(CGM).BuildTypeInfo(SuperTy);
Fields.push_back(BaseTypeInfo);
}

/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
/// inheritance, according to the Itanium C++ ABI, 2.95p6b.
void RTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
void ItaniumRTTIBuilder::BuildSIClassTypeInfo(const CXXRecordDecl *RD) {
// Itanium C++ ABI 2.9.5p6b:
// It adds to abi::__class_type_info a single member pointing to the
// type_info structure for the base type,
llvm::Constant *BaseTypeInfo =
RTTIBuilder(CGM).BuildTypeInfo(RD->bases_begin()->getType());
ItaniumRTTIBuilder(CGM).BuildTypeInfo(RD->bases_begin()->getType());
Fields.push_back(BaseTypeInfo);
}

Expand Down Expand Up @@ -768,20 +769,20 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base,
if (!Bases.VirtualBases.insert(BaseDecl)) {
// If this virtual base has been seen before, then the class is diamond
// shaped.
Flags |= RTTIBuilder::VMI_DiamondShaped;
Flags |= ItaniumRTTIBuilder::VMI_DiamondShaped;
} else {
if (Bases.NonVirtualBases.count(BaseDecl))
Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
Flags |= ItaniumRTTIBuilder::VMI_NonDiamondRepeat;
}
} else {
// Mark the non-virtual base as seen.
if (!Bases.NonVirtualBases.insert(BaseDecl)) {
// If this non-virtual base has been seen before, then the class has non-
// diamond shaped repeated inheritance.
Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
Flags |= ItaniumRTTIBuilder::VMI_NonDiamondRepeat;
} else {
if (Bases.VirtualBases.count(BaseDecl))
Flags |= RTTIBuilder::VMI_NonDiamondRepeat;
Flags |= ItaniumRTTIBuilder::VMI_NonDiamondRepeat;
}
}

Expand All @@ -806,7 +807,7 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *RD) {
/// BuildVMIClassTypeInfo - Build an abi::__vmi_class_type_info, used for
/// classes with bases that do not satisfy the abi::__si_class_type_info
/// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
void ItaniumRTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
llvm::Type *UnsignedIntLTy =
CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy);

Expand Down Expand Up @@ -847,7 +848,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {
// };
for (const auto &Base : RD->bases()) {
// The __base_type member points to the RTTI for the base type.
Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(Base.getType()));
Fields.push_back(ItaniumRTTIBuilder(CGM).BuildTypeInfo(Base.getType()));

const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
Expand Down Expand Up @@ -882,7 +883,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) {

/// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct,
/// used for pointer types.
void RTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) {
void ItaniumRTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) {
Qualifiers Quals;
QualType UnqualifiedPointeeTy =
CGM.getContext().getUnqualifiedArrayType(PointeeTy, Quals);
Expand All @@ -906,13 +907,14 @@ void RTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) {
// __pointee is a pointer to the std::type_info derivation for the
// unqualified type being pointed to.
llvm::Constant *PointeeTypeInfo =
RTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy);
ItaniumRTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy);
Fields.push_back(PointeeTypeInfo);
}

/// BuildPointerToMemberTypeInfo - Build an abi::__pointer_to_member_type_info
/// struct, used for member pointer types.
void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
void
ItaniumRTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
QualType PointeeTy = Ty->getPointeeType();

Qualifiers Quals;
Expand Down Expand Up @@ -943,14 +945,15 @@ void RTTIBuilder::BuildPointerToMemberTypeInfo(const MemberPointerType *Ty) {
// __pointee is a pointer to the std::type_info derivation for the
// unqualified type being pointed to.
llvm::Constant *PointeeTypeInfo =
RTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy);
ItaniumRTTIBuilder(CGM).BuildTypeInfo(UnqualifiedPointeeTy);
Fields.push_back(PointeeTypeInfo);

// Itanium C++ ABI 2.9.5p9:
// __context is a pointer to an abi::__class_type_info corresponding to the
// class type containing the member pointed to
// (e.g., the "A" in "int A::*").
Fields.push_back(RTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0)));
Fields.push_back(
ItaniumRTTIBuilder(CGM).BuildTypeInfo(QualType(ClassType, 0)));
}

llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
Expand All @@ -965,15 +968,17 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
LangOpts.ObjCRuntime.isGNUFamily())
return ObjCRuntime->GetEHType(Ty);

return RTTIBuilder(*this).BuildTypeInfo(Ty);
if (getTarget().getCXXABI().isMicrosoft())
return getMSTypeDescriptor(Ty);
return ItaniumRTTIBuilder(*this).BuildTypeInfo(Ty);
}

void CodeGenModule::EmitFundamentalRTTIDescriptor(QualType Type) {
QualType PointerType = Context.getPointerType(Type);
QualType PointerTypeConst = Context.getPointerType(Type.withConst());
RTTIBuilder(*this).BuildTypeInfo(Type, true);
RTTIBuilder(*this).BuildTypeInfo(PointerType, true);
RTTIBuilder(*this).BuildTypeInfo(PointerTypeConst, true);
ItaniumRTTIBuilder(*this).BuildTypeInfo(Type, true);
ItaniumRTTIBuilder(*this).BuildTypeInfo(PointerType, true);
ItaniumRTTIBuilder(*this).BuildTypeInfo(PointerTypeConst, true);
}

void CodeGenModule::EmitFundamentalRTTIDescriptors() {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CMakeLists.txt
Expand Up @@ -60,6 +60,7 @@ add_clang_library(clangCodeGen
CodeGenTypes.cpp
ItaniumCXXABI.cpp
MicrosoftCXXABI.cpp
MicrosoftRTTI.cpp
ModuleBuilder.cpp
TargetInfo.cpp

Expand Down
13 changes: 11 additions & 2 deletions clang/lib/CodeGen/CodeGenModule.h
Expand Up @@ -528,10 +528,10 @@ class CodeGenModule : public CodeGenTypeCache {
AtomicGetterHelperFnMap[Ty] = Fn;
}

llvm::Constant *getTypeDescriptor(QualType Ty) {
llvm::Constant *getTypeDescriptorFromMap(QualType Ty) {
return TypeDescriptorMap[Ty];
}
void setTypeDescriptor(QualType Ty, llvm::Constant *C) {
void setTypeDescriptorInMap(QualType Ty, llvm::Constant *C) {
TypeDescriptorMap[Ty] = C;
}

Expand Down Expand Up @@ -710,6 +710,12 @@ class CodeGenModule : public CodeGenTypeCache {
/// The type of a generic block literal.
llvm::Type *getGenericBlockLiteralType();

/// \brief Gets or a creats a Microsoft TypeDescriptor.
llvm::Constant *getMSTypeDescriptor(QualType Ty);
/// \brief Gets or a creats a Microsoft CompleteObjectLocator.
llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl *RD,
const VPtrInfo *Info);

/// Gets the address of a block which requires no captures.
llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *);

Expand Down Expand Up @@ -945,6 +951,9 @@ class CodeGenModule : public CodeGenTypeCache {
F->setLinkage(getFunctionLinkage(GD));
}

/// \brief Returns the appropriate linkage for the TypeInfo struct for a type.
llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(QualType Ty);

/// Return the appropriate linkage for the vtable, VTT, and type information
/// of the given class.
llvm::GlobalVariable::LinkageTypes getVTableLinkage(const CXXRecordDecl *RD);
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/CodeGen/MicrosoftCXXABI.cpp
Expand Up @@ -897,14 +897,15 @@ void MicrosoftCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
VPtrInfoVector VFPtrs = VFTContext.getVFPtrOffsets(RD);
llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);

for (VPtrInfoVector::iterator I = VFPtrs.begin(), E = VFPtrs.end(); I != E;
++I) {
llvm::GlobalVariable *VTable = getAddrOfVTable(RD, (*I)->FullOffsetInMDC);
for (VPtrInfo *Info : VFPtrs) {
llvm::GlobalVariable *VTable = getAddrOfVTable(RD, Info->FullOffsetInMDC);
if (VTable->hasInitializer())
continue;
if (getContext().getLangOpts().RTTI)
CGM.getMSCompleteObjectLocator(RD, Info);

const VTableLayout &VTLayout =
VFTContext.getVFTableLayout(RD, (*I)->FullOffsetInMDC);
VFTContext.getVFTableLayout(RD, Info->FullOffsetInMDC);
llvm::Constant *Init = CGVT.CreateVTableInitializer(
RD, VTLayout.vtable_component_begin(),
VTLayout.getNumVTableComponents(), VTLayout.vtable_thunk_begin(),
Expand Down

0 comments on commit 5c2b4ea

Please sign in to comment.