Skip to content

[ObjC] Expand isClassLayoutKnownStatically to base classes as long as the implementation of it is known #85465

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 4, 2025

Conversation

AZero13
Copy link
Contributor

@AZero13 AZero13 commented Mar 15, 2024

Only NSObject we can trust the layout of won't change even though we cannot directly see its @implementation

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. labels Mar 15, 2024
@llvmbot
Copy link
Member

llvmbot commented Mar 15, 2024

@llvm/pr-subscribers-clang-codegen

Author: AtariDreams (AtariDreams)

Changes

Only NSObject we can trust the layout of won't change even though we cannot directly see its @implementation


Full diff: https://github.com/llvm/llvm-project/pull/85465.diff

2 Files Affected:

  • (modified) clang/lib/CodeGen/CGObjCMac.cpp (+8-1)
  • (modified) clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m (+29-1)
diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index e815e097e1fb48..da47ef786cf816 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -1595,6 +1595,11 @@ class CGObjCNonFragileABIMac : public CGObjCCommonMac {
   bool isClassLayoutKnownStatically(const ObjCInterfaceDecl *ID) {
     // Test a class by checking its superclasses up to
     // its base class if it has one.
+
+    // Cannot check a null class
+    if (!ID)
+      return false;
+
     for (; ID; ID = ID->getSuperClass()) {
       // The layout of base class NSObject
       // is guaranteed to be statically known
@@ -1606,7 +1611,9 @@ class CGObjCNonFragileABIMac : public CGObjCCommonMac {
       if (!ID->getImplementation())
         return false;
     }
-    return false;
+
+    // We know the layout of all the intermediate classes and superclasses.
+    return true;
   }
 
 public:
diff --git a/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m b/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
index 8d55e6c7d23081..ee4034e4b7f205 100644
--- a/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
+++ b/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
@@ -8,6 +8,12 @@
 // CHECK: @"OBJC_IVAR_$_IntermediateClass._intermediateProperty" = hidden constant i64 48
 // CHECK: @"OBJC_IVAR_$_SubClass.subClassIvar" = constant i64 56
 // CHECK: @"OBJC_IVAR_$_SubClass._subClassProperty" = hidden constant i64 64
+
+// CHECK: @"OBJC_IVAR_$_RootClass.these" = constant i64 0
+// CHECK: @"OBJC_IVAR_$_RootClass.dont" = constant i64 4
+// CHECK: @"OBJC_IVAR_$_RootClass.change" = constant i64 4
+// CHECK: @"OBJC_IVAR_$_StillStaticLayout.static_layout_ivar" = hidden global i32 12
+
 // CHECK: @"OBJC_IVAR_$_NotStaticLayout.not_static_layout_ivar" = hidden global i64 12
 
 @interface NSObject {
@@ -120,7 +126,29 @@ -(void)intermediateSubclassVar {
 // CHECK: getelementptr inbounds i8, ptr %1, i64 64
 @end
 
-@interface NotNSObject {
+ __attribute((objc_root_class))  @interface RootClass {
+  int these, dont, change;
+}
+@end
+
+@implementation RootClass 
+@end
+
+@interface StillStaticLayout : RootClass
+@end
+
+@implementation StillStaticLayout {
+  int static_layout_ivar;
+}
+
+// CHECK-LABEL: define internal void @"\01-[StillStaticLayout meth]"
+-(void)meth {
+  static_layout_ivar = 0;
+  // CHECK-NOT: load i64, ptr @"OBJC_IVAR_$StillStaticLayout.static_layout_ivar
+}
+@end
+
+__attribute((objc_root_class))  @interface NotNSObject {
   int these, might, change;
 }
 @end

@llvmbot
Copy link
Member

llvmbot commented Mar 15, 2024

@llvm/pr-subscribers-clang

Author: AtariDreams (AtariDreams)

Changes

Only NSObject we can trust the layout of won't change even though we cannot directly see its @implementation


Full diff: https://github.com/llvm/llvm-project/pull/85465.diff

2 Files Affected:

  • (modified) clang/lib/CodeGen/CGObjCMac.cpp (+8-1)
  • (modified) clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m (+29-1)
diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index e815e097e1fb48..da47ef786cf816 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -1595,6 +1595,11 @@ class CGObjCNonFragileABIMac : public CGObjCCommonMac {
   bool isClassLayoutKnownStatically(const ObjCInterfaceDecl *ID) {
     // Test a class by checking its superclasses up to
     // its base class if it has one.
+
+    // Cannot check a null class
+    if (!ID)
+      return false;
+
     for (; ID; ID = ID->getSuperClass()) {
       // The layout of base class NSObject
       // is guaranteed to be statically known
@@ -1606,7 +1611,9 @@ class CGObjCNonFragileABIMac : public CGObjCCommonMac {
       if (!ID->getImplementation())
         return false;
     }
-    return false;
+
+    // We know the layout of all the intermediate classes and superclasses.
+    return true;
   }
 
 public:
diff --git a/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m b/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
index 8d55e6c7d23081..ee4034e4b7f205 100644
--- a/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
+++ b/clang/test/CodeGenObjC/constant-non-fragile-ivar-offset.m
@@ -8,6 +8,12 @@
 // CHECK: @"OBJC_IVAR_$_IntermediateClass._intermediateProperty" = hidden constant i64 48
 // CHECK: @"OBJC_IVAR_$_SubClass.subClassIvar" = constant i64 56
 // CHECK: @"OBJC_IVAR_$_SubClass._subClassProperty" = hidden constant i64 64
+
+// CHECK: @"OBJC_IVAR_$_RootClass.these" = constant i64 0
+// CHECK: @"OBJC_IVAR_$_RootClass.dont" = constant i64 4
+// CHECK: @"OBJC_IVAR_$_RootClass.change" = constant i64 4
+// CHECK: @"OBJC_IVAR_$_StillStaticLayout.static_layout_ivar" = hidden global i32 12
+
 // CHECK: @"OBJC_IVAR_$_NotStaticLayout.not_static_layout_ivar" = hidden global i64 12
 
 @interface NSObject {
@@ -120,7 +126,29 @@ -(void)intermediateSubclassVar {
 // CHECK: getelementptr inbounds i8, ptr %1, i64 64
 @end
 
-@interface NotNSObject {
+ __attribute((objc_root_class))  @interface RootClass {
+  int these, dont, change;
+}
+@end
+
+@implementation RootClass 
+@end
+
+@interface StillStaticLayout : RootClass
+@end
+
+@implementation StillStaticLayout {
+  int static_layout_ivar;
+}
+
+// CHECK-LABEL: define internal void @"\01-[StillStaticLayout meth]"
+-(void)meth {
+  static_layout_ivar = 0;
+  // CHECK-NOT: load i64, ptr @"OBJC_IVAR_$StillStaticLayout.static_layout_ivar
+}
+@end
+
+__attribute((objc_root_class))  @interface NotNSObject {
   int these, might, change;
 }
 @end

@AZero13
Copy link
Contributor Author

AZero13 commented Nov 17, 2024

Going to ping @rjmccall

@AZero13
Copy link
Contributor Author

AZero13 commented Feb 10, 2025

@adrian-prantl thoughts on this?

@AZero13
Copy link
Contributor Author

AZero13 commented Feb 11, 2025

@davidchisnall thoughts?

Copy link
Collaborator

@ahatanak ahatanak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove the null check when we prove ID is never null.

@AZero13
Copy link
Contributor Author

AZero13 commented Feb 25, 2025

@ahatanak Okay I removed the null check.

@AZero13 AZero13 force-pushed the what-if branch 4 times, most recently from 0572dd0 to 9cb7c41 Compare February 25, 2025 14:39
@AZero13
Copy link
Contributor Author

AZero13 commented Mar 3, 2025

@ahatanak Can we please merge this?

@ahatanak
Copy link
Collaborator

ahatanak commented Mar 3, 2025

Can we assert that ID isn't null at the beginning of isClassLayoutKnownStatically?

… the implementation of it is known

Only NSObject we can trust the layout of won't change even though we cannot directly see its @implementation.
@AZero13
Copy link
Contributor Author

AZero13 commented Mar 4, 2025

Can we assert that ID isn't null at the beginning of isClassLayoutKnownStatically?

Done! @ahatanak!

@ahatanak ahatanak merged commit 6720465 into llvm:main Mar 4, 2025
11 checks passed
@AZero13 AZero13 deleted the what-if branch March 4, 2025 16:54
jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
… the implementation of it is known (llvm#85465)

Only NSObject we can trust the layout of won't change even though we
cannot directly see its @implementation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants