]> granicus.if.org Git - clang/commitdiff
Fix Obj-C super sends inside class methods.
authorDaniel Dunbar <daniel@zuster.org>
Mon, 25 Aug 2008 08:19:24 +0000 (08:19 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Mon, 25 Aug 2008 08:19:24 +0000 (08:19 +0000)
 - NeXT loads the super class at runtime; this required changing the
   runtime interface to pass more information down.

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

lib/CodeGen/CGObjC.cpp
lib/CodeGen/CGObjCGNU.cpp
lib/CodeGen/CGObjCMac.cpp
lib/CodeGen/CGObjCRuntime.h

index b086f4f10c39e539e94b01c9a963d64944b8584b..ddd7c8119be4ff8551b10684aead8f621197c0ef 100644 (file)
@@ -50,6 +50,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
   CGObjCRuntime &Runtime = CGM.getObjCRuntime();
   const Expr *ReceiverExpr = E->getReceiver();
   bool isSuperMessage = false;
+  bool isClassMessage = false;
   // Find the receiver
   llvm::Value *Receiver;
   if (!ReceiverExpr) {
@@ -60,11 +61,13 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
     if (!OID) {
       assert(!strcmp(E->getClassName()->getName(), "super") &&
              "Unexpected missing class interface in message send.");
-      OID = E->getMethodDecl()->getClassInterface();
       isSuperMessage = true;
+      Receiver = LoadObjCSelf();
+    } else {
+      Receiver = Runtime.GetClass(Builder, OID);
     }
-
-    Receiver = Runtime.GetClass(Builder, OID);   
+    
+    isClassMessage = true;
   } else if (const PredefinedExpr *PDE =
                dyn_cast<PredefinedExpr>(E->getReceiver())) {
     assert(PDE->getIdentType() == PredefinedExpr::ObjCSuper);
@@ -78,10 +81,11 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E) {
     // super is only valid in an Objective-C method
     const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
     return Runtime.GenerateMessageSendSuper(*this, E,
-                                            OMD->getClassInterface()->getSuperClass(),
-                                            Receiver);
+                                            OMD->getClassInterface(),
+                                            Receiver,
+                                            isClassMessage);
   }
-  return Runtime.GenerateMessageSend(*this, E, Receiver);
+  return Runtime.GenerateMessageSend(*this, E, Receiver, isClassMessage);
 }
 
 /// Generate an Objective-C method.  An Objective-C method is a C function with
index b64f365832ddc1f7af83f1ca0dd166680dd1a75d..1b254c0a2652825a90e92878e500e5a68e6bde8e 100644 (file)
@@ -97,12 +97,14 @@ public:
   virtual CodeGen::RValue 
   GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
                       const ObjCMessageExpr *E,
-                      llvm::Value *Receiver);
+                      llvm::Value *Receiver,
+                      bool IsClassMessage);
   virtual CodeGen::RValue 
   GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
                            const ObjCMessageExpr *E,
-                           const ObjCInterfaceDecl *Super,
-                           llvm::Value *Receiver);
+                           const ObjCInterfaceDecl *Class,
+                           llvm::Value *Receiver,
+                           bool IsClassMessage);
   virtual llvm::Value *GetClass(llvm::IRBuilder<> &Builder,
                                 const ObjCInterfaceDecl *OID);
   virtual llvm::Value *GetSelector(llvm::IRBuilder<> &Builder, Selector Sel);
@@ -236,8 +238,10 @@ llvm::Constant *CGObjCGNU::GenerateConstantString(const std::string &Str) {
 CodeGen::RValue
 CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
                                     const ObjCMessageExpr *E,
-                                    const ObjCInterfaceDecl *SuperClass,
-                                    llvm::Value *Receiver) {
+                                    const ObjCInterfaceDecl *Class,
+                                    llvm::Value *Receiver,
+                                    bool IsClassMessage) {
+  const ObjCInterfaceDecl *SuperClass = Class->getSuperClass();
   const llvm::Type *ReturnTy = CGM.getTypes().ConvertType(E->getType());
   // TODO: This should be cached, not looked up every time.
   llvm::Value *ReceiverClass = GetClass(CGF.Builder, SuperClass);
@@ -280,7 +284,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
 CodeGen::RValue
 CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
                                const ObjCMessageExpr *E,
-                               llvm::Value *Receiver) {
+                               llvm::Value *Receiver,
+                               bool IsClassMessage) {
   const llvm::Type *ReturnTy = CGM.getTypes().ConvertType(E->getType());
   llvm::Value *cmd = GetSelector(CGF.Builder, E->getSelector());
 
index 518c574d02dd75ed1e5636f7104b6cd125186a42..4223709786370e32565f335039218b49c41e7475 100644 (file)
@@ -220,9 +220,14 @@ private:
   llvm::Constant *EmitIvarList(const ObjCImplementationDecl *ID,
                                bool ForClass,
                                const llvm::Type *InterfaceTy);
-  
+
+  /// EmitMetaClass - Emit a forward reference to the class structure
+  /// for the metaclass of the given interface. The return value has
+  /// type ClassPtrTy.
+  llvm::Constant *EmitMetaClassRef(const ObjCInterfaceDecl *ID);
+
   /// EmitMetaClass - Emit a class structure for the metaclass of the
-  /// given implementation. return value has type ClassPtrTy.
+  /// given implementation. The return value has type ClassPtrTy.
   llvm::Constant *EmitMetaClass(const ObjCImplementationDecl *ID,
                                 llvm::Constant *Protocols,
                                 const llvm::Type *InterfaceTy);
@@ -316,13 +321,15 @@ public:
 
   virtual CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
                                               const ObjCMessageExpr *E,
-                                              llvm::Value *Receiver);
+                                              llvm::Value *Receiver,
+                                              bool IsClassMessage);
 
   virtual CodeGen::RValue 
   GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
                            const ObjCMessageExpr *E,
-                           const ObjCInterfaceDecl *SuperClass,
-                           llvm::Value *Receiver);
+                           const ObjCInterfaceDecl *Class,
+                           llvm::Value *Receiver,
+                           bool IsClassMessage);
   
   virtual llvm::Value *GetClass(llvm::IRBuilder<> &Builder,
                                 const ObjCInterfaceDecl *ID);
@@ -403,12 +410,9 @@ llvm::Constant *CGObjCMac::GenerateConstantString(const std::string &String) {
 CodeGen::RValue
 CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
                                     const ObjCMessageExpr *E,
-                                    const ObjCInterfaceDecl *SuperClass,
-                                    llvm::Value *Receiver) {
-  // FIXME: This should be cached, not looked up every time. Meh. We
-  // should just make sure the optimizer hits it.
-  llvm::Value *ReceiverClass = EmitClassRef(CGF.Builder, SuperClass);
-  
+                                    const ObjCInterfaceDecl *Class,
+                                    llvm::Value *Receiver,
+                                    bool IsClassMessage) {
   // Create and init a super structure; this is a (receiver, class)
   // pair we will pass to objc_msgSendSuper.
   llvm::Value *ObjCSuper = 
@@ -417,16 +421,28 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
     CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
   CGF.Builder.CreateStore(ReceiverAsObject, 
                           CGF.Builder.CreateStructGEP(ObjCSuper, 0));
-  CGF.Builder.CreateStore(ReceiverClass, 
-                          CGF.Builder.CreateStructGEP(ObjCSuper, 1));
 
+  // If this is a class message the metaclass is passed as the target.
+  llvm::Value *Target;
+  if (IsClassMessage) {
+    llvm::Value *MetaClassPtr = EmitMetaClassRef(Class);
+    llvm::Value *SuperPtr = CGF.Builder.CreateStructGEP(MetaClassPtr, 1);
+    llvm::Value *Super = CGF.Builder.CreateLoad(SuperPtr);
+    Target = Super;
+  } else {
+    Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
+  }
+  CGF.Builder.CreateStore(Target, 
+                          CGF.Builder.CreateStructGEP(ObjCSuper, 1));
+    
   return EmitMessageSend(CGF, E, ObjCSuper, true);
 }
                                            
 /// Generate code for a message send expression.  
 CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
                                                const ObjCMessageExpr *E,
-                                               llvm::Value *Receiver) {
+                                               llvm::Value *Receiver,
+                                               bool IsClassMessage) {
   llvm::Value *Arg0 = 
     CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy, "tmp");
   return EmitMessageSend(CGF, E, Arg0, false);
@@ -972,12 +988,22 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
   llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
                                                    Values);
 
-  llvm::GlobalVariable *GV = 
-    new llvm::GlobalVariable(ObjCTypes.ClassTy, false,
-                             llvm::GlobalValue::InternalLinkage,
-                             Init,
-                             std::string("\01L_OBJC_METACLASS_")+ClassName,
-                             &CGM.getModule());
+  std::string Name("\01L_OBJC_METACLASS_");
+  Name += ClassName;
+
+  // Check for a forward reference.
+  llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+  if (GV) {
+    assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
+           "Forward metaclass reference has incorrect type.");
+    GV->setLinkage(llvm::GlobalValue::InternalLinkage);
+    GV->setInitializer(Init);
+  } else {
+    GV = new llvm::GlobalVariable(ObjCTypes.ClassTy, false,
+                                  llvm::GlobalValue::InternalLinkage,
+                                  Init, Name,
+                                  &CGM.getModule());
+  }
   GV->setSection("__OBJC,__meta_class,regular,no_dead_strip");
   UsedGlobals.push_back(GV);
   // FIXME: Why?
@@ -986,6 +1012,31 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
   return GV;
 }
 
+llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {  
+  std::string Name("\01L_OBJC_METACLASS_");
+  Name += ID->getName();
+
+  // FIXME: Should we look these up somewhere other than the
+  // module. Its a bit silly since we only generate these while
+  // processing an implementation, so exactly one pointer would work
+  // if know when we entered/exitted an implementation block.
+
+  // Check for an existing forward reference.
+  if (llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name)) {
+    assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
+           "Forward metaclass reference has incorrect type.");
+    return GV;
+  } else {
+    // Generate as an external reference to keep a consistent
+    // module. This will be patched up when we emit the metaclass.
+    return new llvm::GlobalVariable(ObjCTypes.ClassTy, false,
+                                    llvm::GlobalValue::ExternalLinkage,
+                                    0,
+                                    Name,
+                                    &CGM.getModule());
+  }
+}
+
 /*
   struct objc_class_ext {
     uint32_t size;
index 4a1acda546712a9063914bffd7584670f4fe9fae..e373ef20a7227ba6d832db30bec388db8bddfed6 100644 (file)
@@ -80,15 +80,18 @@ public:
   virtual CodeGen::RValue 
   GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
                       const ObjCMessageExpr *E,
-                      llvm::Value *Receiver) = 0;
+                      llvm::Value *Receiver,
+                      bool IsClassMessage) = 0;
 
   /// Generate an Objective-C message send operation to the super
-  /// class.
+  /// class initiated in a method for Class and with the given Self
+  /// object.
   virtual CodeGen::RValue
   GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
                            const ObjCMessageExpr *E,
-                           const ObjCInterfaceDecl *SuperClass,
-                           llvm::Value *Receiver) = 0;
+                           const ObjCInterfaceDecl *Class,
+                           llvm::Value *Self,
+                           bool IsClassMessage) = 0;
 
   /// Emit the code to return the named protocol as an object, as in a
   /// @protocol expression.