]> granicus.if.org Git - clang/commitdiff
[OBJC] Add attribute to mark Objective C class as non-lazy
authorJoe Daniels <joseph_daniels@apple.com>
Mon, 4 Feb 2019 23:32:55 +0000 (23:32 +0000)
committerJoe Daniels <joseph_daniels@apple.com>
Mon, 4 Feb 2019 23:32:55 +0000 (23:32 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@353116 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/Attr.td
include/clang/Basic/AttrDocs.td
lib/CodeGen/CGObjCMac.cpp
lib/Sema/SemaDeclAttr.cpp
test/CodeGenObjC/non-lazy-classes.m
test/Misc/pragma-attribute-supported-attributes-list.test
test/SemaObjC/attr-objc-non-lazy.m [new file with mode: 0644]

index 3b7b0b0d53bf8cd2f0b0cb91a2ccc845131a1765..8b99efcf317020a23f12e9d82e7136e3a13b2fe9 100644 (file)
@@ -1758,6 +1758,13 @@ def ObjCRootClass : InheritableAttr {
   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 {
   let Spellings = [Clang<"objc_subclassing_restricted">];
   let Subjects = SubjectList<[ObjCInterface], ErrorDiag>;
index d316993223a4e85b436f7db4fcb53d47e43b23e5..7f927a918409ee1ebdf3598a3e961d49acaa40b2 100644 (file)
@@ -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 {
   let Category = DocCatType;
index 20b5a86cae4a4b88b0d38e1d89972ae25d5ff2f5..7822a95285bd2de5aac2611302a07a20ee8a3a31 100644 (file)
@@ -6261,9 +6261,10 @@ CGObjCNonFragileABIMac::BuildClassObject(const ObjCInterfaceDecl *CI,
   return GV;
 }
 
-bool
-CGObjCNonFragileABIMac::ImplementationIsNonLazy(const ObjCImplDecl *OD) const {
-  return OD->getClassMethod(GetNullarySelector("load")) != nullptr;
+bool CGObjCNonFragileABIMac::ImplementationIsNonLazy(
+    const ObjCImplDecl *OD) const {
+  return OD->getClassMethod(GetNullarySelector("load")) != nullptr ||
+         OD->getClassInterface()->hasAttr<ObjCNonLazyClassAttr>();
 }
 
 void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID,
index 7eafdcccc3d3a224bb6ed7fda156e58a59c2ff03..bb69070b2645e701c1b029a16e5b547ea023cf47 100644 (file)
@@ -6832,6 +6832,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
   case ParsedAttr::AT_ObjCRootClass:
     handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL);
     break;
+  case ParsedAttr::AT_ObjCNonLazyClass:
+    handleSimpleAttribute<ObjCNonLazyClassAttr>(S, D, AL);
+    break;
   case ParsedAttr::AT_ObjCSubclassingRestricted:
     handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, AL);
     break;
index b04b020e20ee797baf350d517895c3c4a1686c55..aeb2a0dd9cb76dcd22c2ee57aba708ead7a2552d 100644 (file)
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -Wno-objc-root-class -emit-llvm -o - %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
 
 @interface A @end
@@ -30,3 +30,8 @@
 @interface C : A @end
 @implementation C
 @end
+
+__attribute__((objc_nonlazy_class))
+@interface D @end
+
+@implementation D @end
index 0fe7ef464b0fb5b886e6e8b15865e11853c6658b..2dc03a4188ebc265eba050fe1a710799c940e9cc 100644 (file)
 // CHECK-NEXT: ObjCExplicitProtocolImpl (SubjectMatchRule_objc_protocol)
 // CHECK-NEXT: ObjCExternallyRetained (SubjectMatchRule_variable_not_is_parameter, SubjectMatchRule_function, SubjectMatchRule_block, SubjectMatchRule_objc_method)
 // CHECK-NEXT: ObjCMethodFamily (SubjectMatchRule_objc_method)
+// CHECK-NEXT: ObjCNonLazyClass (SubjectMatchRule_objc_interface)
 // CHECK-NEXT: ObjCPreciseLifetime (SubjectMatchRule_variable)
 // CHECK-NEXT: ObjCRequiresPropertyDefs (SubjectMatchRule_objc_interface)
 // CHECK-NEXT: ObjCRequiresSuper (SubjectMatchRule_objc_method)
diff --git a/test/SemaObjC/attr-objc-non-lazy.m b/test/SemaObjC/attr-objc-non-lazy.m
new file mode 100644 (file)
index 0000000..5dc88f7
--- /dev/null
@@ -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