зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
8af9c78c7e
Коммит
f56f1913e9
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче