]> granicus.if.org Git - clang/commitdiff
MS ABI: Emit HandlerMap entries for C++ catch
authorDavid Majnemer <david.majnemer@gmail.com>
Tue, 17 Mar 2015 20:35:05 +0000 (20:35 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Tue, 17 Mar 2015 20:35:05 +0000 (20:35 +0000)
The HandlerMap describes, to the runtime, what sort of catches surround
the try.  In principle, this structure has to be emitted by the backend
because only it knows the layout of the stack (the runtime needs to know
where on the stack the destination of a copy lives, etc.) but there is
some C++ specific information that the backend can't reason about.

Stick this information in special LLVM globals with the relevant
"const", "volatile", "reference" info mangled into the name.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@232538 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Mangle.h
lib/AST/MicrosoftMangle.cpp
lib/CodeGen/CGCXXABI.h
lib/CodeGen/CGException.cpp
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
lib/CodeGen/ItaniumCXXABI.cpp
lib/CodeGen/MicrosoftCXXABI.cpp
test/CodeGenCXX/microsoft-abi-try-throw.cpp

index aa644b2f0018dbc91c9a9aa6bc41829a68f11e57..23dde6b3f927d1fafafe68705497ac1c1a5e35ea 100644 (file)
@@ -208,6 +208,10 @@ public:
                                       uint32_t NVOffset, int32_t VBPtrOffset,
                                       uint32_t VBIndex, raw_ostream &Out) = 0;
 
+  virtual void mangleCXXHandlerMapEntry(QualType T, bool IsConst,
+                                        bool IsVolatile, bool IsReference,
+                                        raw_ostream &Out) = 0;
+
   virtual void mangleCXXRTTIBaseClassDescriptor(
       const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset,
       uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) = 0;
index 1b10fe3c2ebc3d90fb21961fb08739c46d898951..c402f4abb0d4f0294e3283f0508cd2e64ad39535 100644 (file)
@@ -122,6 +122,8 @@ public:
                               CXXCtorType CT, uint32_t Size, uint32_t NVOffset,
                               int32_t VBPtrOffset, uint32_t VBIndex,
                               raw_ostream &Out) override;
+  void mangleCXXHandlerMapEntry(QualType T, bool IsConst, bool IsVolatile,
+                                bool IsReference, raw_ostream &Out);
   void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
   void mangleCXXRTTIName(QualType T, raw_ostream &Out) override;
   void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
@@ -2339,6 +2341,22 @@ void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T,
   Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
 }
 
+void MicrosoftMangleContextImpl::mangleCXXHandlerMapEntry(QualType T,
+                                                          bool IsConst,
+                                                          bool IsVolatile,
+                                                          bool IsReference,
+                                                          raw_ostream &Out) {
+  MicrosoftCXXNameMangler Mangler(*this, Out);
+  Mangler.getStream() << "llvm.eh.handlermapentry.";
+  if (IsConst)
+    Mangler.getStream() << "const.";
+  if (IsVolatile)
+    Mangler.getStream() << "volatile.";
+  if (IsReference)
+    Mangler.getStream() << "reference.";
+  Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
+}
+
 void MicrosoftMangleContextImpl::mangleCXXThrowInfo(QualType T,
                                                     bool IsConst,
                                                     bool IsVolatile,
index 3a92d05e7e3a850b5e9817b2e68dc53002fde13a..b6a94f9082de541ed6d782fed7c7a0189a11e846 100644 (file)
@@ -225,7 +225,8 @@ public:
                                       llvm::Value *Exn);
 
   virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) = 0;
-  virtual llvm::Constant *getAddrOfCXXCatchDescriptor(QualType Ty) = 0;
+  virtual llvm::Constant *
+  getAddrOfCXXHandlerMapEntry(QualType Ty, QualType CatchHandlerType) = 0;
 
   virtual bool shouldTypeidBeNullChecked(bool IsDeref,
                                          QualType SrcRecordTy) = 0;
index 1a9ebb395fc1a21eb976c237b9ce156b31c78b36..223b8f76d0d3679dacc364416b2a7f42d540ac9c 100644 (file)
@@ -567,7 +567,8 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
       if (CaughtType->isObjCObjectPointerType())
         TypeInfo = CGM.getObjCRuntime().GetEHType(CaughtType);
       else
-        TypeInfo = CGM.getAddrOfCXXCatchDescriptor(CaughtType);
+        TypeInfo =
+            CGM.getAddrOfCXXHandlerMapEntry(CaughtType, C->getCaughtType());
       CatchScope->setHandler(I, TypeInfo, Handler);
     } else {
       // No exception decl indicates '...', a catch-all.
index 03948d68cdcacd64bf4c0bc87088a9d503d47ffa..c91de6df9e939f11bc458e81d4d5f116010f6512 100644 (file)
@@ -3644,8 +3644,10 @@ llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid) {
   return llvm::ConstantStruct::getAnon(Fields);
 }
 
-llvm::Constant *CodeGenModule::getAddrOfCXXCatchDescriptor(QualType Ty) {
-  return getCXXABI().getAddrOfCXXCatchDescriptor(Ty);
+llvm::Constant *
+CodeGenModule::getAddrOfCXXHandlerMapEntry(QualType Ty,
+                                           QualType CatchHandlerType) {
+  return getCXXABI().getAddrOfCXXHandlerMapEntry(Ty, CatchHandlerType);
 }
 
 llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty,
index 7e5bd7caa5c5f233bb7a34313c71f98ce34fe956..ce540e91dcb514f01e093c6fcb67710030d811ef 100644 (file)
@@ -719,7 +719,8 @@ public:
   /// Get the address of the RTTI descriptor for the given type.
   llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false);
 
-  llvm::Constant *getAddrOfCXXCatchDescriptor(QualType Ty);
+  llvm::Constant *getAddrOfCXXHandlerMapEntry(QualType Ty,
+                                              QualType CatchHandlerType);
 
   /// Get the address of a uuid descriptor .
   llvm::Constant *GetAddrOfUuidDescriptor(const CXXUuidofExpr* E);
index ca9322840eb15874c0201f508d584d7b9956d6b5..73bbfe071ddad38daf2062c4cb6e2797af8c640b 100644 (file)
@@ -126,7 +126,8 @@ public:
   void EmitFundamentalRTTIDescriptor(QualType Type);
   void EmitFundamentalRTTIDescriptors();
   llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
-  llvm::Constant *getAddrOfCXXCatchDescriptor(QualType Ty) {
+  llvm::Constant *getAddrOfCXXHandlerMapEntry(QualType Ty,
+                                              QualType CatchHandlerType) {
     return getAddrOfRTTIDescriptor(Ty);
   }
 
index 7539ad8bdfa675c7b7d235b233d63f794e9e211b..6417b87444d32ea5fcc041671c8ad781650c5660 100644 (file)
@@ -45,7 +45,7 @@ public:
       : CGCXXABI(CGM), BaseClassDescriptorType(nullptr),
         ClassHierarchyDescriptorType(nullptr),
         CompleteObjectLocatorType(nullptr), CatchableTypeType(nullptr),
-        ThrowInfoType(nullptr) {}
+        ThrowInfoType(nullptr), HandlerMapEntryType(nullptr) {}
 
   bool HasThisReturn(GlobalDecl GD) const override;
   bool hasMostDerivedReturn(GlobalDecl GD) const override;
@@ -84,7 +84,8 @@ public:
                                                    const VPtrInfo *Info);
 
   llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
-  llvm::Constant *getAddrOfCXXCatchDescriptor(QualType Ty) override;
+  llvm::Constant *
+  getAddrOfCXXHandlerMapEntry(QualType Ty, QualType CatchHandlerType) override;
 
   bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
   void EmitBadTypeidCall(CodeGenFunction &CGF) override;
@@ -572,6 +573,18 @@ public:
 
   void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override;
 
+  llvm::StructType *getHandlerMapEntryType() {
+    if (!HandlerMapEntryType) {
+      llvm::Type *FieldTypes[] = {
+        CGM.IntTy,                           // Flags
+        getImageRelativeType(CGM.Int8PtrTy), // TypeDescriptor
+      };
+      HandlerMapEntryType = llvm::StructType::create(
+          CGM.getLLVMContext(), FieldTypes, "eh.HandlerMapEntry");
+    }
+    return HandlerMapEntryType;
+  }
+
   llvm::StructType *getCatchableTypeType() {
     if (CatchableTypeType)
       return CatchableTypeType;
@@ -685,6 +698,7 @@ private:
   llvm::StructType *CatchableTypeType;
   llvm::DenseMap<uint32_t, llvm::StructType *> CatchableTypeArrayTypeMap;
   llvm::StructType *ThrowInfoType;
+  llvm::StructType *HandlerMapEntryType;
 };
 
 }
@@ -3186,14 +3200,48 @@ static QualType decomposeTypeForEH(ASTContext &Context, QualType T,
   return T;
 }
 
-llvm::Constant *MicrosoftCXXABI::getAddrOfCXXCatchDescriptor(QualType Type) {
-  // TypeDescriptors for exceptions never has qualified pointer types,
+llvm::Constant *
+MicrosoftCXXABI::getAddrOfCXXHandlerMapEntry(QualType Type,
+                                             QualType CatchHandlerType) {
+  // TypeDescriptors for exceptions never have qualified pointer types,
   // qualifiers are stored seperately in order to support qualification
   // conversions.
   bool IsConst, IsVolatile;
   Type = decomposeTypeForEH(getContext(), Type, IsConst, IsVolatile);
 
-  return getAddrOfRTTIDescriptor(Type);
+  bool IsReference = CatchHandlerType->isReferenceType();
+
+  SmallString<256> MangledName;
+  {
+    llvm::raw_svector_ostream Out(MangledName);
+    getMangleContext().mangleCXXHandlerMapEntry(Type, IsConst, IsVolatile,
+                                                IsReference, Out);
+  }
+
+  if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
+    return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
+
+  uint32_t Flags = 0;
+  if (IsConst)
+    Flags |= 1;
+  if (IsVolatile)
+    Flags |= 2;
+  if (IsReference)
+    Flags |= 8;
+
+  llvm::Constant *Fields[] = {
+      llvm::ConstantInt::get(CGM.IntTy, Flags),                // Flags
+      getImageRelativeConstant(getAddrOfRTTIDescriptor(Type)), // TypeDescriptor
+  };
+  llvm::StructType *HandlerMapEntryType = getHandlerMapEntryType();
+  auto *Var = new llvm::GlobalVariable(
+      CGM.getModule(), HandlerMapEntryType, /*Constant=*/true,
+      llvm::GlobalValue::PrivateLinkage,
+      llvm::ConstantStruct::get(HandlerMapEntryType, Fields),
+      StringRef(MangledName));
+  Var->setUnnamedAddr(true);
+  Var->setSection("llvm.metadata");
+  return Var;
 }
 
 /// \brief Gets a TypeDescriptor.  Returns a llvm::Constant * rather than a
@@ -3201,7 +3249,7 @@ llvm::Constant *MicrosoftCXXABI::getAddrOfCXXCatchDescriptor(QualType Type) {
 /// types, and need to be abstracted.  They are abstracting by casting the
 /// address to an Int8PtrTy.
 llvm::Constant *MicrosoftCXXABI::getAddrOfRTTIDescriptor(QualType Type) {
-  SmallString<256> MangledName, TypeInfoString;
+  SmallString<256> MangledName;
   {
     llvm::raw_svector_ostream Out(MangledName);
     getMangleContext().mangleCXXRTTI(Type, Out);
@@ -3212,6 +3260,7 @@ llvm::Constant *MicrosoftCXXABI::getAddrOfRTTIDescriptor(QualType Type) {
     return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
 
   // Compute the fields for the TypeDescriptor.
+  SmallString<256> TypeInfoString;
   {
     llvm::raw_svector_ostream Out(TypeInfoString);
     getMangleContext().mangleCXXRTTIName(Type, Out);
index 8aecab4f6559880b213d876c041cdb6cbaef5b30..c7bbcf28888589c19e11385a0f085d8c76766c24 100644 (file)
@@ -6,6 +6,8 @@
 // THROW-DAG: @_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0H@84"] }, section ".xdata", comdat
 // THROW-DAG: @_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* null, i8* null, i8* bitcast (%eh.CatchableTypeArray.1* @_CTA1H to i8*) }, section ".xdata", comdat
 
+// TRY-DAG: @llvm.eh.handlermapentry.const.PAH = private unnamed_addr constant %eh.HandlerMapEntry { i32 1, i8* bitcast (%rtti.TypeDescriptor4* @"\01??_R0PAH@8" to i8*) }, section "llvm.metadata"
+
 void external();
 
 inline void not_emitted() {
@@ -39,7 +41,7 @@ void qual_catch() {
     external();
   } catch (const int *) {
   }
-  // TRY: catch i8* bitcast (%rtti.TypeDescriptor4* @"\01??_R0PAH@8" to i8*)
-  // TRY: call i32 @llvm.eh.typeid.for(i8* bitcast (%rtti.TypeDescriptor4* @"\01??_R0PAH@8" to i8*))
+  // TRY: catch %eh.HandlerMapEntry* @llvm.eh.handlermapentry.const.PAH
+  // TRY: call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.HandlerMapEntry* @llvm.eh.handlermapentry.const.PAH to i8*))
 }
 #endif