[ObjC] type method metadata `_imp`, messenger routine at callsite with program addres...
authorMatt Jacobson <mhjacobson@me.com>
Mon, 1 Aug 2022 05:59:41 +0000 (01:59 -0400)
committerMatt Jacobson <mhjacobson@me.com>
Thu, 4 Aug 2022 09:40:32 +0000 (05:40 -0400)
On targets with non-default program address space (e.g., Harvard
architectures), clang crashes when emitting Objective-C method metadata,
because the address of the method IMP cannot be bitcast to i8*. It similarly
crashes at messenger callsite with a failed bitcast.

Define the _imp field instead as i8 addrspace(1)* (or whatever the target's
program address space is). And in getMessageSendInfo(), create signatureType by
specifying the program address space.

Add a regression test using the AVR target. Test failed previously and passes
now. Checked codegen of the test for x86_64-apple-darwin19.6.0 and saw no
difference, as expected.

Reviewed By: rjmccall, dylanmckay

Differential Revision: https://reviews.llvm.org/D112113

clang/lib/CodeGen/CGObjCMac.cpp
clang/lib/CodeGen/CGObjCRuntime.cpp
clang/test/CodeGen/avr/objc-method.m [new file with mode: 0644]

index 46e65eb..2d704ce 100644 (file)
@@ -174,6 +174,7 @@ protected:
 public:
   llvm::IntegerType *ShortTy, *IntTy, *LongTy;
   llvm::PointerType *Int8PtrTy, *Int8PtrPtrTy;
+  llvm::PointerType *Int8PtrProgramASTy;
   llvm::Type *IvarOffsetVarTy;
 
   /// ObjectPtrTy - LLVM type for object handles (typeof(id))
@@ -5739,11 +5740,13 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
 {
   CodeGen::CodeGenTypes &Types = CGM.getTypes();
   ASTContext &Ctx = CGM.getContext();
+  unsigned ProgramAS = CGM.getDataLayout().getProgramAddressSpace();
 
   ShortTy = cast<llvm::IntegerType>(Types.ConvertType(Ctx.ShortTy));
   IntTy = CGM.IntTy;
   LongTy = cast<llvm::IntegerType>(Types.ConvertType(Ctx.LongTy));
   Int8PtrTy = CGM.Int8PtrTy;
+  Int8PtrProgramASTy = llvm::PointerType::get(CGM.Int8Ty, ProgramAS);
   Int8PtrPtrTy = CGM.Int8PtrPtrTy;
 
   // arm64 targets use "int" ivar offset variables. All others,
@@ -5812,7 +5815,7 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm)
   //   char *_imp;
   // }
   MethodTy = llvm::StructType::create("struct._objc_method", SelectorPtrTy,
-                                      Int8PtrTy, Int8PtrTy);
+                                      Int8PtrTy, Int8PtrProgramASTy);
 
   // struct _objc_cache *
   CacheTy = llvm::StructType::create(VMContext, "struct._objc_cache");
@@ -6771,11 +6774,11 @@ void CGObjCNonFragileABIMac::emitMethodConstant(ConstantArrayBuilder &builder,
 
   if (forProtocol) {
     // Protocol methods have no implementation. So, this entry is always NULL.
-    method.addNullPointer(ObjCTypes.Int8PtrTy);
+    method.addNullPointer(ObjCTypes.Int8PtrProgramASTy);
   } else {
     llvm::Function *fn = GetMethodDefinition(MD);
     assert(fn && "no definition for method?");
-    method.addBitCast(fn, ObjCTypes.Int8PtrTy);
+    method.addBitCast(fn, ObjCTypes.Int8PtrProgramASTy);
   }
 
   method.finishAndAddTo(builder);
index 550fd3d..7780a61 100644 (file)
@@ -360,13 +360,15 @@ CGObjCRuntime::MessageSendInfo
 CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method,
                                   QualType resultType,
                                   CallArgList &callArgs) {
+  unsigned ProgramAS = CGM.getDataLayout().getProgramAddressSpace();
+
   // If there's a method, use information from that.
   if (method) {
     const CGFunctionInfo &signature =
       CGM.getTypes().arrangeObjCMessageSendSignature(method, callArgs[0].Ty);
 
     llvm::PointerType *signatureType =
-      CGM.getTypes().GetFunctionType(signature)->getPointerTo();
+      CGM.getTypes().GetFunctionType(signature)->getPointerTo(ProgramAS);
 
     const CGFunctionInfo &signatureForCall =
       CGM.getTypes().arrangeCall(signature, callArgs);
@@ -380,7 +382,7 @@ CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method,
 
   // Derive the signature to call from that.
   llvm::PointerType *signatureType =
-    CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo();
+    CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo(ProgramAS);
   return MessageSendInfo(argsInfo, signatureType);
 }
 
diff --git a/clang/test/CodeGen/avr/objc-method.m b/clang/test/CodeGen/avr/objc-method.m
new file mode 100644 (file)
index 0000000..aeafb8e
--- /dev/null
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -triple avr -emit-llvm -fobjc-runtime=macosx %s -o /dev/null
+
+__attribute__((objc_root_class))
+@interface Foo
+
+- (id)foo;
+- (id)bar;
+
+@end
+
+@implementation Foo
+
+- (id)foo {
+  return self;
+}
+
+- (id)bar {
+  return [self foo];
+}
+
+@end