Fix Obj-C super sends inside class methods.
- 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
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 518c574..4223709 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -220,9 +220,14 @@
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 @@
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 @@
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 @@
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 *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 @@
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;