[clang][objc][codegen] Skip emitting ObjC category metadata when the

category is empty

Currently, if we create a category in ObjC that is empty, we still emit
runtime metadata for that category. This is a scenario that could
commonly be run into when using __attribute__((objc_direct_members)),
which elides the need for much of the category metadata. This is
slightly wasteful and can be easily skipped by checking the category
metadata contents during CodeGen.

rdar://66177182

Differential Revision: https://reviews.llvm.org/D113455
This commit is contained in:
Josh Learn 2021-11-12 16:17:18 -08:00 committed by Akira Hatanaka
parent cb0e14ce6d
commit 7611e16fce
3 changed files with 57 additions and 18 deletions

View File

@ -6672,33 +6672,53 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
}
}
values.add(emitMethodList(listName, MethodListType::CategoryInstanceMethods,
instanceMethods));
values.add(emitMethodList(listName, MethodListType::CategoryClassMethods,
classMethods));
auto instanceMethodList = emitMethodList(
listName, MethodListType::CategoryInstanceMethods, instanceMethods);
auto classMethodList = emitMethodList(
listName, MethodListType::CategoryClassMethods, classMethods);
values.add(instanceMethodList);
values.add(classMethodList);
// Keep track of whether we have actual metadata to emit.
bool isEmptyCategory =
instanceMethodList->isNullValue() && classMethodList->isNullValue();
const ObjCCategoryDecl *Category =
Interface->FindCategoryDeclaration(OCD->getIdentifier());
Interface->FindCategoryDeclaration(OCD->getIdentifier());
if (Category) {
SmallString<256> ExtName;
llvm::raw_svector_ostream(ExtName) << Interface->getObjCRuntimeNameAsString() << "_$_"
<< OCD->getName();
values.add(EmitProtocolList("_OBJC_CATEGORY_PROTOCOLS_$_"
+ Interface->getObjCRuntimeNameAsString() + "_$_"
+ Category->getName(),
Category->protocol_begin(),
Category->protocol_end()));
values.add(EmitPropertyList("_OBJC_$_PROP_LIST_" + ExtName.str(),
OCD, Category, ObjCTypes, false));
values.add(EmitPropertyList("_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(),
OCD, Category, ObjCTypes, true));
llvm::raw_svector_ostream(ExtName)
<< Interface->getObjCRuntimeNameAsString() << "_$_" << OCD->getName();
auto protocolList =
EmitProtocolList("_OBJC_CATEGORY_PROTOCOLS_$_" +
Interface->getObjCRuntimeNameAsString() + "_$_" +
Category->getName(),
Category->protocol_begin(), Category->protocol_end());
auto propertyList = EmitPropertyList("_OBJC_$_PROP_LIST_" + ExtName.str(),
OCD, Category, ObjCTypes, false);
auto classPropertyList =
EmitPropertyList("_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(), OCD,
Category, ObjCTypes, true);
values.add(protocolList);
values.add(propertyList);
values.add(classPropertyList);
isEmptyCategory &= protocolList->isNullValue() &&
propertyList->isNullValue() &&
classPropertyList->isNullValue();
} else {
values.addNullPointer(ObjCTypes.ProtocolListnfABIPtrTy);
values.addNullPointer(ObjCTypes.PropertyListPtrTy);
values.addNullPointer(ObjCTypes.PropertyListPtrTy);
}
unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategorynfABITy);
if (isEmptyCategory) {
// Empty category, don't emit any metadata.
values.abandon();
MethodDefinitions.clear();
return;
}
unsigned Size =
CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategorynfABITy);
values.addInt(ObjCTypes.IntTy, Size);
llvm::GlobalVariable *GCATV =

View File

@ -0,0 +1,16 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -O0 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s
// PR7431
// CHECK-NOT: @"OBJC_LABEL_CATEGORY_$" = private global [1 x i8*] [i8* bitcast (%struct._category_t* @"_OBJC_$_CATEGORY_A_$_foo"
@interface A
@end
__attribute__((objc_direct_members))
@interface A(foo)
- (void)foo_myStuff;
@end
@implementation A(foo)
- (void)foo_myStuff {
}
@end

View File

@ -42,4 +42,7 @@ __attribute__((objc_nonlazy_class))
@implementation E @end
__attribute__((objc_nonlazy_class))
@implementation E (MyCat) @end
@implementation E (MyCat)
-(void) load {
}
@end