smeenai created this revision.
smeenai added reviewers: DHowett-MSFT, compnerd, majnemer, rjmccall, rnk.

We're implementing funclet-compatible code generation for Obj-C
exceptions when using the MSVC ABI. The idea is that the Obj-C runtime
will wrap Obj-C exceptions inside C++ exceptions, which allows for
interoperability with C++ exceptions (for Obj-C++) and zero-cost
exceptions. This is the approach taken by e.g. WinObjC, and I believe it
to be the best approach for Obj-C exceptions in the MSVC ABI.

The first step is emitting proper RTTI for Obj-C exception types. Since
we're wrapping Obj-C exceptions in C++ exceptions, the RTTI should be
identical, barring the name of the RTTI variable (OBJC_EHTYPE_$_*).
Since the MSVC ABI does not easily allow for cross-DLL data references
from within other data, we instead emit the RTTI locally wherever
needed, which is also how C++ RTTI works on that ABI.

Follow-up diffs will add code generation support for @try itself, but
I'm splitting it up to get early feedback and make review more
manageable.

Worked on with Saleem Abdulrasool <compn...@compnerd.org>.


Repository:
  rC Clang

https://reviews.llvm.org/D47233

Files:
  lib/CodeGen/CGCXXABI.h
  lib/CodeGen/CGObjCMac.cpp
  lib/CodeGen/MicrosoftCXXABI.cpp
  test/CodeGenObjC/dllstorage.m
  test/CodeGenObjC/exceptions-msvc.m

Index: test/CodeGenObjC/exceptions-msvc.m
===================================================================
--- /dev/null
+++ test/CodeGenObjC/exceptions-msvc.m
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -triple i686--windows-msvc -fobjc-runtime=ios-6.0 -fdeclspec -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,X86 %s
+// RUN: %clang_cc1 -triple i686--windows-msvc -fobjc-runtime=ios-6.0 -fobjc-arc -fdeclspec -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,X86 %s
+// RUN: %clang_cc1 -triple x86_64--windows-msvc -fobjc-runtime=ios-6.0 -fdeclspec -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,X64 %s
+// RUN: %clang_cc1 -triple x86_64--windows-msvc -fobjc-runtime=ios-6.0 -fobjc-arc -fdeclspec -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,X64 %s
+
+// CHECK-DAG: $OBJC_EHTYPE_id = comdat any
+// X86-DAG: @OBJC_EHTYPE_id = linkonce_odr global {{%[^ ]+}} { i8** @"??_7type_info@@6B@", i8* null, [18 x i8] c".PAUobjc_object@@\00" }, comdat
+// X64-DAG: @OBJC_EHTYPE_id = linkonce_odr global {{%[^ ]+}} { i8** @"??_7type_info@@6B@", i8* null, [19 x i8] c".PEAUobjc_object@@\00" }, comdat
+
+// CHECK-DAG: $"OBJC_EHTYPE_$_I" = comdat any
+// X86-DAG: @"OBJC_EHTYPE_$_I" = linkonce_odr global {{%[^ ]+}} { i8** @"??_7type_info@@6B@", i8* null, [8 x i8] c".PAUI@@\00" }, comdat
+// X64-DAG: @"OBJC_EHTYPE_$_I" = linkonce_odr global {{%[^ ]+}} { i8** @"??_7type_info@@6B@", i8* null, [9 x i8] c".PEAUI@@\00" }, comdat
+
+// CHECK-DAG: $"OBJC_EHTYPE_$_J" = comdat any
+// X86-DAG: @"OBJC_EHTYPE_$_J" = linkonce_odr global {{%[^ ]+}} { i8** @"??_7type_info@@6B@", i8* null, [8 x i8] c".PAUJ@@\00" }, comdat
+// X64-DAG: @"OBJC_EHTYPE_$_J" = linkonce_odr global {{%[^ ]+}} { i8** @"??_7type_info@@6B@", i8* null, [9 x i8] c".PEAUJ@@\00" }, comdat
+
+// CHECK-DAG: $"OBJC_EHTYPE_$_K" = comdat any
+// X86-DAG: @"OBJC_EHTYPE_$_K" = linkonce_odr global {{%[^ ]+}} { i8** @"??_7type_info@@6B@", i8* null, [8 x i8] c".PAUK@@\00" }, comdat
+// X64-DAG: @"OBJC_EHTYPE_$_K" = linkonce_odr global {{%[^ ]+}} { i8** @"??_7type_info@@6B@", i8* null, [9 x i8] c".PEAUK@@\00" }, comdat
+
+// CHECK-DAG: $"OBJC_EHTYPE_$_NotL" = comdat any
+// X86-DAG: @"OBJC_EHTYPE_$_NotL" = linkonce_odr global {{%[^ ]+}} { i8** @"??_7type_info@@6B@", i8* null, [8 x i8] c".PAUL@@\00" }, comdat
+// X64-DAG: @"OBJC_EHTYPE_$_NotL" = linkonce_odr global {{%[^ ]+}} { i8** @"??_7type_info@@6B@", i8* null, [9 x i8] c".PEAUL@@\00" }, comdat
+
+// CHECK-DAG: $"OBJC_EHTYPE_$_M" = comdat any
+// X86-DAG: @"OBJC_EHTYPE_$_M" = linkonce_odr global {{%[^ ]+}} { i8** @"??_7type_info@@6B@", i8* null, [8 x i8] c".PAUM@@\00" }, comdat
+// X64-DAG: @"OBJC_EHTYPE_$_M" = linkonce_odr global {{%[^ ]+}} { i8** @"??_7type_info@@6B@", i8* null, [9 x i8] c".PEAUM@@\00" }, comdat
+
+#if __has_feature(objc_arc)
+#define WEAK __weak
+#else
+#define WEAK
+#endif
+
+@class I;
+@class J;
+
+// The EHType shouldn't be exported
+__declspec(dllexport)
+__attribute__((objc_root_class))
+@interface K
+@end
+
+@implementation K
+@end
+
+__attribute__((objc_runtime_name("NotL")))
+@interface L
+@end
+
+@class M;
+
+@protocol P;
+
+void f(void);
+
+void g() {
+  @try {
+    f();
+  } @catch (I *) {
+  } @catch (J<P> *) {
+  } @catch (K *) {
+  } @catch (L *) {
+  } @catch (M *WEAK) {
+  } @catch (id) {
+  }
+}
Index: test/CodeGenObjC/dllstorage.m
===================================================================
--- test/CodeGenObjC/dllstorage.m
+++ test/CodeGenObjC/dllstorage.m
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -fdeclspec -fobjc-runtime=ios -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-IR %s
-// RUN: %clang_cc1 -triple i686-windows-itanium -fms-extensions -fobjc-runtime=macosx -fdeclspec -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-IR %s
+// RUN: %clang_cc1 -triple i686-windows-itanium -fms-extensions -fobjc-runtime=macosx -fdeclspec -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-IR -check-prefix CHECK-ITANIUM %s
 // RUN: %clang_cc1 -triple i686-windows-itanium -fms-extensions -fobjc-runtime=objfw -fdeclspec -fobjc-exceptions -S -emit-llvm -o - %s | FileCheck -check-prefix CHECK-FW %s
 
 // CHECK-IR-DAG: @_objc_empty_cache = external dllimport global %struct._objc_cache
@@ -100,20 +100,20 @@
 @implementation N : I
 @end
 
-// CHECK-IR-DAG: @"OBJC_EHTYPE_$_N" = dso_local dllexport global %struct._objc_typeinfo
+// CHECK-ITANIUM-DAG: @"OBJC_EHTYPE_$_N" = dso_local dllexport global %struct._objc_typeinfo
 
 __declspec(dllimport)
 __attribute__((__objc_exception__))
 @interface O : I
 @end
 
-// CHECK-IR-DAG: @"OBJC_EHTYPE_$_O" = external dllimport global %struct._objc_typeinfo
+// CHECK-ITANIUM-DAG: @"OBJC_EHTYPE_$_O" = external dllimport global %struct._objc_typeinfo
 
 __attribute__((__objc_exception__))
 @interface P : I
 @end
 
-// CHECK-IR-DAG: @"OBJC_EHTYPE_$_P" = external dso_local global %struct._objc_typeinfo
+// CHECK-ITANIUM-DAG: @"OBJC_EHTYPE_$_P" = external dso_local global %struct._objc_typeinfo
 
 @interface Q : M
 @end
@@ -153,9 +153,9 @@
   return 0;
 }
 
-// CHECK-IR-DAG: @OBJC_EHTYPE_id = external dllimport global %struct._objc_typeinfo
-// CHECK-IR-DAG: @"OBJC_EHTYPE_$_I" = weak global %struct._objc_typeinfo
-// CHECK-IR-DAG: @"OBJC_EHTYPE_$_K" = weak global %struct._objc_typeinfo
-// CHECK-IR-DAG: @"OBJC_EHTYPE_$_L" = weak global %struct._objc_typeinfo
-// CHECK-IR-DAG: @"OBJC_EHTYPE_$_M" = weak global %struct._objc_typeinfo
+// CHECK-ITANIUM-DAG: @OBJC_EHTYPE_id = external dllimport global %struct._objc_typeinfo
+// CHECK-ITANIUM-DAG: @"OBJC_EHTYPE_$_I" = weak global %struct._objc_typeinfo
+// CHECK-ITANIUM-DAG: @"OBJC_EHTYPE_$_K" = weak global %struct._objc_typeinfo
+// CHECK-ITANIUM-DAG: @"OBJC_EHTYPE_$_L" = weak global %struct._objc_typeinfo
+// CHECK-ITANIUM-DAG: @"OBJC_EHTYPE_$_M" = weak global %struct._objc_typeinfo
 
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -126,6 +126,8 @@
                                                    const VPtrInfo &Info);
 
   llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) override;
+  llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty,
+                                          StringRef MangledName) override;
   CatchTypeInfo
   getAddrOfCXXCatchHandlerType(QualType Ty, QualType CatchHandlerType) override;
 
@@ -3773,7 +3775,11 @@
     llvm::raw_svector_ostream Out(MangledName);
     getMangleContext().mangleCXXRTTI(Type, Out);
   }
+  return getAddrOfRTTIDescriptor(Type, MangledName);
+}
 
+llvm::Constant *
+MicrosoftCXXABI::getAddrOfRTTIDescriptor(QualType Type, StringRef MangledName) {
   // Check to see if we've already declared this TypeDescriptor.
   if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(MangledName))
     return llvm::ConstantExpr::getBitCast(GV, CGM.Int8PtrTy);
Index: lib/CodeGen/CGObjCMac.cpp
===================================================================
--- lib/CodeGen/CGObjCMac.cpp
+++ lib/CodeGen/CGObjCMac.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CGBlocks.h"
+#include "CGCXXABI.h"
 #include "CGCleanup.h"
 #include "CGObjCRuntime.h"
 #include "CGRecordLayout.h"
@@ -7456,6 +7457,10 @@
 CGObjCNonFragileABIMac::GetEHType(QualType T) {
   // There's a particular fixed type info for 'id'.
   if (T->isObjCIdType() || T->isObjCQualifiedIdType()) {
+    if (CGM.getTriple().isWindowsMSVCEnvironment())
+      return CGM.getCXXABI().getAddrOfRTTIDescriptor(
+          T.getLocalUnqualifiedType(), "OBJC_EHTYPE_id");
+
     auto *IDEHType = CGM.getModule().getGlobalVariable("OBJC_EHTYPE_id");
     if (!IDEHType) {
       IDEHType =
@@ -7475,7 +7480,15 @@
   const ObjCInterfaceType *IT = PT->getInterfaceType();
   assert(IT && "Invalid @catch type.");
 
-  return GetInterfaceEHType(IT->getDecl(), NotForDefinition);
+  const ObjCInterfaceDecl *ID = IT->getDecl();
+  if (CGM.getTriple().isWindowsMSVCEnvironment()) {
+    const ASTContext &Ctx = CGM.getContext();
+    return CGM.getCXXABI().getAddrOfRTTIDescriptor(
+        Ctx.getObjCObjectPointerType(IT->stripObjCKindOfTypeAndQuals(Ctx)),
+        ("OBJC_EHTYPE_$_" + ID->getObjCRuntimeNameAsString()).str());
+  }
+
+  return GetInterfaceEHType(ID, NotForDefinition);
 }
 
 void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
Index: lib/CodeGen/CGCXXABI.h
===================================================================
--- lib/CodeGen/CGCXXABI.h
+++ lib/CodeGen/CGCXXABI.h
@@ -249,6 +249,10 @@
                                       llvm::Value *Exn);
 
   virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty) = 0;
+  virtual llvm::Constant *getAddrOfRTTIDescriptor(QualType Ty,
+                                                  StringRef MangledName) {
+    llvm_unreachable("Only needed for the Microsoft ABI");
+  }
   virtual CatchTypeInfo
   getAddrOfCXXCatchHandlerType(QualType Ty, QualType CatchHandlerType) = 0;
   virtual CatchTypeInfo getCatchAllTypeInfo();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to