Skip to content

Commit e56af29

Browse files
authored
Merge pull request #34766 from slavapestov/emit-stub-for-concrete-subclass-of-generic
Emit Objective-C resilient class stubs for concrete subclasses of generic subclasses of NSObject
2 parents cd8029a + 2390b95 commit e56af29

File tree

6 files changed

+68
-22
lines changed

6 files changed

+68
-22
lines changed

lib/IRGen/GenClass.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2144,13 +2144,17 @@ static llvm::Function *emitObjCMetadataUpdateFunction(IRGenModule &IGM,
21442144
/// ancestry. This lets us attach categories to the class even though it
21452145
/// does not have statically-emitted metadata.
21462146
bool IRGenModule::hasObjCResilientClassStub(ClassDecl *D) {
2147-
assert(getClassMetadataStrategy(D) == ClassMetadataStrategy::Resilient);
2147+
#ifndef NDEBUG
2148+
auto strategy = getClassMetadataStrategy(D);
2149+
assert(strategy == ClassMetadataStrategy::Resilient ||
2150+
strategy == ClassMetadataStrategy::Singleton);
2151+
#endif
2152+
21482153
return ObjCInterop && !D->isGenericContext();
21492154
}
21502155

2151-
void IRGenModule::emitObjCResilientClassStub(ClassDecl *D) {
2152-
assert(hasObjCResilientClassStub(D));
2153-
2156+
llvm::Constant *IRGenModule::emitObjCResilientClassStub(
2157+
ClassDecl *D, bool isPublic) {
21542158
ConstantInitBuilder builder(*this);
21552159
auto fields = builder.beginStruct(ObjCFullResilientClassStubTy);
21562160
fields.addInt(SizeTy, 0); // reserved
@@ -2178,9 +2182,13 @@ void IRGenModule::emitObjCResilientClassStub(ClassDecl *D) {
21782182
objcStub = llvm::ConstantExpr::getPointerCast(objcStub,
21792183
ObjCResilientClassStubTy->getPointerTo());
21802184

2181-
entity = LinkEntity::forObjCResilientClassStub(
2182-
D, TypeMetadataAddress::AddressPoint);
2183-
defineAlias(entity, objcStub);
2185+
if (isPublic) {
2186+
entity = LinkEntity::forObjCResilientClassStub(
2187+
D, TypeMetadataAddress::AddressPoint);
2188+
defineAlias(entity, objcStub);
2189+
}
2190+
2191+
return objcStub;
21842192
}
21852193

21862194
static llvm::Constant *doEmitClassPrivateData(

lib/IRGen/GenMeta.cpp

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3794,23 +3794,44 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
37943794
if (IGM.ObjCInterop) {
37953795
switch (strategy) {
37963796
case ClassMetadataStrategy::Resilient:
3797-
// Even non-@objc classes can have Objective-C categories attached, so
3798-
// we always emit a resilient class stub as long as -enable-objc-interop
3799-
// is set.
3797+
// We always emit a resilient class stub as long as -enable-objc-interop
3798+
// is set. You can define @objc members in an extension of a resilient
3799+
// class across a module boundary, and this category is attached to the
3800+
// class stub.
38003801
if (IGM.hasObjCResilientClassStub(classDecl)) {
3801-
IGM.emitObjCResilientClassStub(classDecl);
3802+
auto *stub = IGM.emitObjCResilientClassStub(
3803+
classDecl, /*isPublic=*/true);
38023804

3803-
if (classDecl->isObjC()) {
3804-
auto *stub = IGM.getAddrOfObjCResilientClassStub(
3805-
classDecl, NotForDefinition,
3806-
TypeMetadataAddress::AddressPoint);
3805+
// If the class has Objective-C ancestry but does *not* have generic
3806+
// ancestry, it appears in the generated header. We emit an Objective-C
3807+
// class symbol aliased to the class stub for Clang to reference.
3808+
if (classDecl->isObjC())
38073809
emitObjCClassSymbol(IGM, classDecl, stub);
38083810

3811+
// Note that if the class has generic ancestry, isObjC() is false.
3812+
// This is because such classes cannot appear in the generated header,
3813+
// because their generic superclasses cannot appear in the generated
3814+
// header either. However, we still want to emit the class stub in
3815+
// the __objc_stublist section of the binary, so that they are visited
3816+
// by objc_copyClassList().
3817+
if (classDecl->checkAncestry(AncestryFlags::ObjC))
38093818
IGM.addObjCClassStub(stub);
3810-
}
38113819
}
38123820
break;
3821+
38133822
case ClassMetadataStrategy::Singleton:
3823+
// If the class has Objective-C ancestry, we emit the class stub and
3824+
// add it to the __obj_stublist. Note that the stub is not public in
3825+
// this case, since there is no reason to reference directly; it only
3826+
// exists so that objc_copyClassList() can find it.
3827+
if (IGM.hasObjCResilientClassStub(classDecl)) {
3828+
if (classDecl->checkAncestry(AncestryFlags::ObjC)) {
3829+
auto *stub = IGM.emitObjCResilientClassStub(
3830+
classDecl, /*isPublic=*/false);
3831+
IGM.addObjCClassStub(stub);
3832+
}
3833+
}
3834+
38143835
break;
38153836

38163837
case ClassMetadataStrategy::Update:
@@ -3820,7 +3841,7 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
38203841
emitObjCClassSymbol(IGM, classDecl, var);
38213842

38223843
IGM.addObjCClass(var,
3823-
classDecl->getAttrs().hasAttribute<ObjCNonLazyRealizationAttr>());
3844+
classDecl->getAttrs().hasAttribute<ObjCNonLazyRealizationAttr>());
38243845
break;
38253846
}
38263847
}

lib/IRGen/GenObjC.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,8 +1085,6 @@ static llvm::Constant *getObjCEncodingForTypes(IRGenModule &IGM,
10851085

10861086
std::string encodingString;
10871087

1088-
auto fnClangTy = fnType->getClangTypeInfo().getType();
1089-
10901088
// Return type.
10911089
{
10921090
auto clangType = IGM.getClangType(resultType.getASTType());

lib/IRGen/IRGenModule.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1636,7 +1636,7 @@ private: \
16361636
bool hasObjCResilientClassStub(ClassDecl *D);
16371637

16381638
/// Emit a resilient class stub.
1639-
void emitObjCResilientClassStub(ClassDecl *D);
1639+
llvm::Constant *emitObjCResilientClassStub(ClassDecl *D, bool isPublic);
16401640

16411641
private:
16421642
llvm::Constant *

test/IRGen/class_update_callback_with_stub.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ import resilient_objc_class
105105
// -- ... but they do appear in the stub list
106106

107107
// CHECK-LABEL: @objc_class_stubs = internal global
108-
// CHECK-SAME: @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMs"
108+
// CHECK-SAME: @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMt"
109109
// CHECK-SAME: , section "__DATA,__objc_stublist,regular,no_dead_strip"
110110

111111
// -- The category list
@@ -128,7 +128,7 @@ import resilient_objc_class
128128

129129

130130
// -- Class symbol for NSObject-derived class points at the class stub
131-
// CHECK: @"OBJC_CLASS_$__TtC31class_update_callback_with_stub25ResilientNSObjectSubclass" = alias %objc_class_stub, %objc_class_stub* @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMs"
131+
// CHECK: @"OBJC_CLASS_$__TtC31class_update_callback_with_stub25ResilientNSObjectSubclass" = alias %objc_class_stub, {{.*}} @"$s31class_update_callback_with_stub25ResilientNSObjectSubclassCMt"
132132

133133

134134
// -- Metadata update callbacks referenced from class stubs
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
// RUN: %empty-directory(%t)
3+
// RUN: %build-irgen-test-overlays
4+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -primary-file %s -emit-ir | %FileCheck %s
5+
6+
// REQUIRES: objc_interop
7+
8+
import Foundation
9+
10+
public class GenericNSObjectSubclass<T> : NSObject {}
11+
12+
public class ConcreteNSObjectSubclass : GenericNSObjectSubclass<Int> {}
13+
14+
// Note the stub here is internal; it's only purpose is to appear in the stub list
15+
// so that it can be realized by objc_copyClassList():
16+
17+
// CHECK-LABEL: @"$s23objc_generic_class_stub24ConcreteNSObjectSubclassCMt" = internal global %objc_full_class_stub { i64 0, i64 1, %objc_class* (%objc_class*, i8*)* @"$s23objc_generic_class_stub24ConcreteNSObjectSubclassCMU" }
18+
19+
// CHECK-LABEL: @objc_class_stubs = internal global {{.*}} @"$s23objc_generic_class_stub24ConcreteNSObjectSubclassCMt" {{.*}}, section "__DATA,__objc_stublist,regular,no_dead_strip"

0 commit comments

Comments
 (0)