Objective-C vtables are not taking the world by storm; call them

out as "v-table" message sends and stop calling normal messages "legacy"
message sends.

Also, fix some comments to reveal the true state of affairs.

llvm-svn: 131335
This commit is contained in:
John McCall 2011-05-14 03:10:52 +00:00
parent 2a48f525cd
commit 9e8bb000d8
1 changed files with 136 additions and 118 deletions

View File

@ -869,16 +869,16 @@ protected:
unsigned Align,
bool AddToUsed);
CodeGen::RValue EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
llvm::Value *Sel,
llvm::Value *Arg0,
QualType Arg0Ty,
bool IsSuper,
const CallArgList &CallArgs,
const ObjCMethodDecl *OMD,
const ObjCCommonTypesHelper &ObjCTypes);
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
llvm::Value *Sel,
llvm::Value *Arg0,
QualType Arg0Ty,
bool IsSuper,
const CallArgList &CallArgs,
const ObjCMethodDecl *OMD,
const ObjCCommonTypesHelper &ObjCTypes);
/// EmitImageInfo - Emit the image info marker used to encode some module
/// level information.
@ -1114,16 +1114,16 @@ private:
/// EHTypeReferences - uniqued class ehtype references.
llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> EHTypeReferences;
/// NonLegacyDispatchMethods - List of methods for which we do *not* generate
/// legacy messaging dispatch.
llvm::DenseSet<Selector> NonLegacyDispatchMethods;
/// VTableDispatchMethods - List of methods for which we generate
/// vtable-based message dispatch.
llvm::DenseSet<Selector> VTableDispatchMethods;
/// DefinedMetaClasses - List of defined meta-classes.
std::vector<llvm::GlobalValue*> DefinedMetaClasses;
/// LegacyDispatchedSelector - Returns true if SEL is not in the list of
/// NonLegacyDispatchMethods; false otherwise.
bool LegacyDispatchedSelector(Selector Sel);
/// isVTableDispatchedSelector - Returns true if SEL is a
/// vtable-based selector.
bool isVTableDispatchedSelector(Selector Sel);
/// FinishNonFragileABIModule - Write out global data structures at the end of
/// processing a translation unit.
@ -1182,15 +1182,15 @@ private:
ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end);
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
QualType Arg0Ty,
bool IsSuper,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
CodeGen::RValue EmitVTableMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
Selector Sel,
llvm::Value *Receiver,
QualType Arg0Ty,
bool IsSuper,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method);
/// GetClassGlobal - Return the global variable for the Objective-C
/// class of the given name.
@ -1491,10 +1491,10 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
CGF.Builder.CreateStore(Target,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
return EmitLegacyMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes);
return EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes);
}
/// Generate code for a message send expression.
@ -1506,23 +1506,23 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
return EmitLegacyMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes);
return EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes);
}
CodeGen::RValue
CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
llvm::Value *Sel,
llvm::Value *Arg0,
QualType Arg0Ty,
bool IsSuper,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method,
const ObjCCommonTypesHelper &ObjCTypes) {
CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
llvm::Value *Sel,
llvm::Value *Arg0,
QualType Arg0Ty,
bool IsSuper,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method,
const ObjCCommonTypesHelper &ObjCTypes) {
CallArgList ActualArgs;
if (!IsSuper)
Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp");
@ -4662,56 +4662,68 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
EmitImageInfo();
}
/// LegacyDispatchedSelector - Returns true if SEL is not in the list of
/// NonLegacyDispatchMethods; false otherwise. What this means is that
/// isVTableDispatchedSelector - Returns true if SEL is not in the list of
/// VTableDispatchMethods; false otherwise. What this means is that
/// except for the 19 selectors in the list, we generate 32bit-style
/// message dispatch call for all the rest.
///
bool CGObjCNonFragileABIMac::LegacyDispatchedSelector(Selector Sel) {
bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
// At various points we've experimented with using vtable-based
// dispatch for all methods.
switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) {
default:
assert(0 && "Invalid dispatch method!");
llvm_unreachable("Invalid dispatch method!");
case CodeGenOptions::Legacy:
return true;
case CodeGenOptions::NonLegacy:
return false;
case CodeGenOptions::NonLegacy:
return true;
case CodeGenOptions::Mixed:
break;
}
// If so, see whether this selector is in the white-list of things which must
// use the new dispatch convention. We lazily build a dense set for this.
if (NonLegacyDispatchMethods.empty()) {
NonLegacyDispatchMethods.insert(GetNullarySelector("alloc"));
NonLegacyDispatchMethods.insert(GetNullarySelector("class"));
NonLegacyDispatchMethods.insert(GetNullarySelector("self"));
NonLegacyDispatchMethods.insert(GetNullarySelector("isFlipped"));
NonLegacyDispatchMethods.insert(GetNullarySelector("length"));
NonLegacyDispatchMethods.insert(GetNullarySelector("count"));
NonLegacyDispatchMethods.insert(GetNullarySelector("retain"));
NonLegacyDispatchMethods.insert(GetNullarySelector("release"));
NonLegacyDispatchMethods.insert(GetNullarySelector("autorelease"));
NonLegacyDispatchMethods.insert(GetNullarySelector("hash"));
if (VTableDispatchMethods.empty()) {
VTableDispatchMethods.insert(GetNullarySelector("alloc"));
VTableDispatchMethods.insert(GetNullarySelector("class"));
VTableDispatchMethods.insert(GetNullarySelector("self"));
VTableDispatchMethods.insert(GetNullarySelector("isFlipped"));
VTableDispatchMethods.insert(GetNullarySelector("length"));
VTableDispatchMethods.insert(GetNullarySelector("count"));
NonLegacyDispatchMethods.insert(GetUnarySelector("allocWithZone"));
NonLegacyDispatchMethods.insert(GetUnarySelector("isKindOfClass"));
NonLegacyDispatchMethods.insert(GetUnarySelector("respondsToSelector"));
NonLegacyDispatchMethods.insert(GetUnarySelector("objectForKey"));
NonLegacyDispatchMethods.insert(GetUnarySelector("objectAtIndex"));
NonLegacyDispatchMethods.insert(GetUnarySelector("isEqualToString"));
NonLegacyDispatchMethods.insert(GetUnarySelector("isEqual"));
NonLegacyDispatchMethods.insert(GetUnarySelector("addObject"));
// "countByEnumeratingWithState:objects:count"
IdentifierInfo *KeyIdents[] = {
&CGM.getContext().Idents.get("countByEnumeratingWithState"),
&CGM.getContext().Idents.get("objects"),
&CGM.getContext().Idents.get("count")
};
NonLegacyDispatchMethods.insert(
CGM.getContext().Selectors.getSelector(3, KeyIdents));
// These are vtable-based if GC is disabled.
// Optimistically use vtable dispatch for hybrid compiles.
if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) {
VTableDispatchMethods.insert(GetNullarySelector("retain"));
VTableDispatchMethods.insert(GetNullarySelector("release"));
VTableDispatchMethods.insert(GetNullarySelector("autorelease"));
}
VTableDispatchMethods.insert(GetUnarySelector("allocWithZone"));
VTableDispatchMethods.insert(GetUnarySelector("isKindOfClass"));
VTableDispatchMethods.insert(GetUnarySelector("respondsToSelector"));
VTableDispatchMethods.insert(GetUnarySelector("objectForKey"));
VTableDispatchMethods.insert(GetUnarySelector("objectAtIndex"));
VTableDispatchMethods.insert(GetUnarySelector("isEqualToString"));
VTableDispatchMethods.insert(GetUnarySelector("isEqual"));
// These are vtable-based if GC is enabled.
// Optimistically use vtable dispatch for hybrid compiles.
if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) {
VTableDispatchMethods.insert(GetNullarySelector("hash"));
VTableDispatchMethods.insert(GetUnarySelector("addObject"));
// "countByEnumeratingWithState:objects:count"
IdentifierInfo *KeyIdents[] = {
&CGM.getContext().Idents.get("countByEnumeratingWithState"),
&CGM.getContext().Idents.get("objects"),
&CGM.getContext().Idents.get("count")
};
VTableDispatchMethods.insert(
CGM.getContext().Selectors.getSelector(3, KeyIdents));
}
}
return (NonLegacyDispatchMethods.count(Sel) == 0);
return VTableDispatchMethods.count(Sel);
}
// Metadata flags
@ -5540,32 +5552,36 @@ static void appendSelectorForMessageRefTable(std::string &buffer,
}
}
/// Emit a message send for the non-fragile ABI.
///
/// Note that we intentionally don't emit a call to objc_msgSend*
/// directly because doing so will require the call to go through a
/// lazy call stub. In general, that overhead is considered
/// worthwhile because it
RValue CGObjCNonFragileABIMac::EmitMessageSend(CodeGenFunction &CGF,
ReturnValueSlot returnSlot,
QualType resultType,
Selector selector,
llvm::Value *receiver,
QualType receiverType,
bool isSuper,
const CallArgList &formalArgs,
const ObjCMethodDecl *method) {
/// Emit a "v-table" message send. We emit a weak hidden-visibility
/// struct, initially containing the selector pointer and a pointer to
/// a "fixup" variant of the appropriate objc_msgSend. To call, we
/// load and call the function pointer, passing the address of the
/// struct as the second parameter. The runtime determines whether
/// the selector is currently emitted using vtable dispatch; if so, it
/// substitutes a stub function which simply tail-calls through the
/// appropriate vtable slot, and if not, it substitues a stub function
/// which tail-calls objc_msgSend. Both stubs adjust the selector
/// argument to correctly point to the selector.
RValue
CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
ReturnValueSlot returnSlot,
QualType resultType,
Selector selector,
llvm::Value *arg0,
QualType arg0Type,
bool isSuper,
const CallArgList &formalArgs,
const ObjCMethodDecl *method) {
// Compute the actual arguments.
CallArgList args;
// First argument: the receiver.
// FIXME: this method doesn't really support super receivers anyway.
// First argument: the receiver / super-call structure.
if (!isSuper)
receiver = CGF.Builder.CreateBitCast(receiver, ObjCTypes.ObjectPtrTy);
args.add(RValue::get(receiver), receiverType);
arg0 = CGF.Builder.CreateBitCast(arg0, ObjCTypes.ObjectPtrTy);
args.add(RValue::get(arg0), arg0Type);
// Second argument: a message reference pointer. Leave the actual
// r-value blank for now.
// Second argument: a pointer to the message ref structure. Leave
// the actual argument value blank for now.
args.add(RValue::get(0), ObjCTypes.MessageRefCPtrTy);
args.insert(args.end(), formalArgs.begin(), formalArgs.end());
@ -5574,8 +5590,13 @@ RValue CGObjCNonFragileABIMac::EmitMessageSend(CodeGenFunction &CGF,
CGM.getTypes().getFunctionInfo(resultType, args,
FunctionType::ExtInfo());
// Find the function to call and the name of the message ref table
// entry.
// Find the function to call and the mangled name for the message
// ref structure. Using a different mangled name wouldn't actually
// be a problem; it would just be a waste.
//
// The runtime currently never uses vtable dispatch for anything
// except normal, non-super message-sends.
// FIXME: don't use this for that.
llvm::Constant *fn = 0;
std::string messageRefName("\01l_");
if (CGM.ReturnTypeUsesSRet(fnInfo)) {
@ -5609,10 +5630,7 @@ RValue CGObjCNonFragileABIMac::EmitMessageSend(CodeGenFunction &CGF,
llvm::GlobalVariable *messageRef
= CGM.getModule().getGlobalVariable(messageRefName);
if (!messageRef) {
// Build the message ref table entry. It needs to be non-constant
// because otherwise the optimizer will elide the load, which we
// don't want --- in fact, the whole point of this exercise is to
// get an indirect call.
// Build the message ref structure.
llvm::Constant *values[] = { fn, GetMethodVarName(selector) };
llvm::Constant *init =
llvm::ConstantStruct::get(VMContext, values, 2, false);
@ -5629,7 +5647,7 @@ RValue CGObjCNonFragileABIMac::EmitMessageSend(CodeGenFunction &CGF,
llvm::Value *mref =
CGF.Builder.CreateBitCast(messageRef, ObjCTypes.MessageRefPtrTy);
// Update the message reference in the arguments.
// Update the message ref argument.
args[1].RV = RValue::get(mref);
// Load the function to call from the message ref table.
@ -5655,14 +5673,14 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
const CallArgList &CallArgs,
const ObjCInterfaceDecl *Class,
const ObjCMethodDecl *Method) {
return LegacyDispatchedSelector(Sel)
? EmitLegacyMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
return isVTableDispatchedSelector(Sel)
? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method, ObjCTypes)
: EmitMessageSend(CGF, Return, ResultType, Sel,
false, CallArgs, Method)
: EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
Receiver, CGF.getContext().getObjCIdType(),
false, CallArgs, Method);
false, CallArgs, Method, ObjCTypes);
}
llvm::GlobalVariable *
@ -5809,14 +5827,14 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateStore(Target,
CGF.Builder.CreateStructGEP(ObjCSuper, 1));
return (LegacyDispatchedSelector(Sel))
? EmitLegacyMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
return (isVTableDispatchedSelector(Sel))
? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method, ObjCTypes)
: EmitMessageSend(CGF, Return, ResultType, Sel,
true, CallArgs, Method)
: EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF.Builder, Sel),
ObjCSuper, ObjCTypes.SuperPtrCTy,
true, CallArgs, Method);
true, CallArgs, Method, ObjCTypes);
}
llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,