[OBJC] Add attribute to mark Objective C class as non-lazy
A non-lazy class will be initialized eagerly when the Objective-C runtime is loaded. This is required for certain system classes which have instances allocated in non-standard ways, such as the classes for blocks and constant strings. Adding this attribute is essentially equivalent to providing a trivial +load method but avoids the (fairly small) load-time overheads associated with defining and calling such a method. Differential Revision: https://reviews.llvm.org/D56555 llvm-svn: 353116
This commit is contained in:
parent
3062887c99
commit
f7393d2a3e
|
@ -1758,6 +1758,13 @@ def ObjCRootClass : InheritableAttr {
|
||||||
let Documentation = [Undocumented];
|
let Documentation = [Undocumented];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def ObjCNonLazyClass : Attr {
|
||||||
|
let Spellings = [Clang<"objc_nonlazy_class">];
|
||||||
|
let Subjects = SubjectList<[ObjCInterface], ErrorDiag>;
|
||||||
|
let LangOpts = [ObjC];
|
||||||
|
let Documentation = [ObjCNonLazyClassDocs];
|
||||||
|
}
|
||||||
|
|
||||||
def ObjCSubclassingRestricted : InheritableAttr {
|
def ObjCSubclassingRestricted : InheritableAttr {
|
||||||
let Spellings = [Clang<"objc_subclassing_restricted">];
|
let Spellings = [Clang<"objc_subclassing_restricted">];
|
||||||
let Subjects = SubjectList<[ObjCInterface], ErrorDiag>;
|
let Subjects = SubjectList<[ObjCInterface], ErrorDiag>;
|
||||||
|
|
|
@ -3699,6 +3699,19 @@ ensure that this class cannot be subclassed.
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def ObjCNonLazyClassDocs : Documentation {
|
||||||
|
let Category = DocCatType;
|
||||||
|
let Content = [{
|
||||||
|
This attribute can be added to an Objective-C ``@interface`` declaration to
|
||||||
|
add the class to the list of non-lazily initialized classes. A non-lazy class
|
||||||
|
will be initialized eagerly when the Objective-C runtime is loaded. This is
|
||||||
|
required for certain system classes which have instances allocated in
|
||||||
|
non-standard ways, such as the classes for blocks and constant strings. Adding
|
||||||
|
this attribute is essentially equivalent to providing a trivial `+load` method
|
||||||
|
but avoids the (fairly small) load-time overheads associated with defining and
|
||||||
|
calling such a method.
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
def SelectAnyDocs : Documentation {
|
def SelectAnyDocs : Documentation {
|
||||||
let Category = DocCatType;
|
let Category = DocCatType;
|
||||||
|
|
|
@ -6261,9 +6261,10 @@ CGObjCNonFragileABIMac::BuildClassObject(const ObjCInterfaceDecl *CI,
|
||||||
return GV;
|
return GV;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool CGObjCNonFragileABIMac::ImplementationIsNonLazy(
|
||||||
CGObjCNonFragileABIMac::ImplementationIsNonLazy(const ObjCImplDecl *OD) const {
|
const ObjCImplDecl *OD) const {
|
||||||
return OD->getClassMethod(GetNullarySelector("load")) != nullptr;
|
return OD->getClassMethod(GetNullarySelector("load")) != nullptr ||
|
||||||
|
OD->getClassInterface()->hasAttr<ObjCNonLazyClassAttr>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
|
void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
|
||||||
|
|
|
@ -6832,6 +6832,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
||||||
case ParsedAttr::AT_ObjCRootClass:
|
case ParsedAttr::AT_ObjCRootClass:
|
||||||
handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL);
|
handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL);
|
||||||
break;
|
break;
|
||||||
|
case ParsedAttr::AT_ObjCNonLazyClass:
|
||||||
|
handleSimpleAttribute<ObjCNonLazyClassAttr>(S, D, AL);
|
||||||
|
break;
|
||||||
case ParsedAttr::AT_ObjCSubclassingRestricted:
|
case ParsedAttr::AT_ObjCSubclassingRestricted:
|
||||||
handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, AL);
|
handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, AL);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wno-objc-root-class -emit-llvm -o - %s | \
|
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wno-objc-root-class -emit-llvm -o - %s | \
|
||||||
// RUN: FileCheck %s
|
// RUN: FileCheck %s
|
||||||
// CHECK: @"OBJC_LABEL_NONLAZY_CLASS_$" = private global [1 x {{.*}}] {{.*}}@"OBJC_CLASS_$_A"{{.*}}, section "__DATA,__objc_nlclslist,regular,no_dead_strip", align 8
|
// CHECK: @"OBJC_LABEL_NONLAZY_CLASS_$" = private global [2 x {{.*}}]{{.*}}@"OBJC_CLASS_$_A"{{.*}},{{.*}}@"OBJC_CLASS_$_D"{{.*}} section "__DATA,__objc_nlclslist,regular,no_dead_strip", align 8
|
||||||
// CHECK: @"OBJC_LABEL_NONLAZY_CATEGORY_$" = private global [1 x {{.*}}] {{.*}}@"\01l_OBJC_$_CATEGORY_A_$_Cat"{{.*}}, section "__DATA,__objc_nlcatlist,regular,no_dead_strip", align 8
|
// CHECK: @"OBJC_LABEL_NONLAZY_CATEGORY_$" = private global [1 x {{.*}}] {{.*}}@"\01l_OBJC_$_CATEGORY_A_$_Cat"{{.*}}, section "__DATA,__objc_nlcatlist,regular,no_dead_strip", align 8
|
||||||
|
|
||||||
@interface A @end
|
@interface A @end
|
||||||
|
@ -30,3 +30,8 @@
|
||||||
@interface C : A @end
|
@interface C : A @end
|
||||||
@implementation C
|
@implementation C
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
__attribute__((objc_nonlazy_class))
|
||||||
|
@interface D @end
|
||||||
|
|
||||||
|
@implementation D @end
|
||||||
|
|
|
@ -100,6 +100,7 @@
|
||||||
// CHECK-NEXT: ObjCExplicitProtocolImpl (SubjectMatchRule_objc_protocol)
|
// CHECK-NEXT: ObjCExplicitProtocolImpl (SubjectMatchRule_objc_protocol)
|
||||||
// CHECK-NEXT: ObjCExternallyRetained (SubjectMatchRule_variable_not_is_parameter, SubjectMatchRule_function, SubjectMatchRule_block, SubjectMatchRule_objc_method)
|
// CHECK-NEXT: ObjCExternallyRetained (SubjectMatchRule_variable_not_is_parameter, SubjectMatchRule_function, SubjectMatchRule_block, SubjectMatchRule_objc_method)
|
||||||
// CHECK-NEXT: ObjCMethodFamily (SubjectMatchRule_objc_method)
|
// CHECK-NEXT: ObjCMethodFamily (SubjectMatchRule_objc_method)
|
||||||
|
// CHECK-NEXT: ObjCNonLazyClass (SubjectMatchRule_objc_interface)
|
||||||
// CHECK-NEXT: ObjCPreciseLifetime (SubjectMatchRule_variable)
|
// CHECK-NEXT: ObjCPreciseLifetime (SubjectMatchRule_variable)
|
||||||
// CHECK-NEXT: ObjCRequiresPropertyDefs (SubjectMatchRule_objc_interface)
|
// CHECK-NEXT: ObjCRequiresPropertyDefs (SubjectMatchRule_objc_interface)
|
||||||
// CHECK-NEXT: ObjCRequiresSuper (SubjectMatchRule_objc_method)
|
// CHECK-NEXT: ObjCRequiresSuper (SubjectMatchRule_objc_method)
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
// RUN: %clang_cc1 -verify -Wno-objc-root-class -fsyntax-only %s
|
||||||
|
|
||||||
|
__attribute__((objc_nonlazy_class))
|
||||||
|
@interface A
|
||||||
|
@end
|
||||||
|
@implementation A
|
||||||
|
@end
|
||||||
|
|
||||||
|
__attribute__((objc_nonlazy_class)) int X; // expected-error {{'objc_nonlazy_class' attribute only applies to Objective-C interfaces}}
|
||||||
|
|
||||||
|
__attribute__((objc_nonlazy_class()))
|
||||||
|
@interface B
|
||||||
|
@end
|
||||||
|
@implementation B
|
||||||
|
@end
|
||||||
|
|
||||||
|
__attribute__((objc_nonlazy_class("foo"))) // expected-error{{'objc_nonlazy_class' attribute takes no arguments}}
|
||||||
|
@interface C
|
||||||
|
@end
|
||||||
|
@implementation C
|
||||||
|
@end
|
||||||
|
|
||||||
|
__attribute__((objc_nonlazy_class)) // expected-error {{'objc_nonlazy_class' attribute only applies to Objective-C interfaces}}
|
||||||
|
@protocol B
|
||||||
|
@end
|
||||||
|
|
||||||
|
__attribute__((objc_nonlazy_class)) // expected-error {{'objc_nonlazy_class' attribute only applies to Objective-C interfaces}}
|
||||||
|
void foo();
|
||||||
|
|
||||||
|
@interface E
|
||||||
|
@end
|
||||||
|
__attribute__((objc_nonlazy_class))
|
||||||
|
@implementation E // expected-error {{prefix attribute must be followed by an interface or protocol}}
|
||||||
|
@end
|
Loading…
Reference in New Issue