Skip to content

Commit d703f54

Browse files
authored
Merge pull request #23746 from slavapestov/objc-resilient-class-stubs-5.1
Implement Swift support for Objective-C resilient class stubs [5.1]
2 parents 6c58acd + 838126e commit d703f54

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+899
-322
lines changed

docs/ABI/Mangling.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ Globals
112112
global ::= nominal-type 'Mn' // nominal type descriptor
113113
global ::= nominal-type 'Mu' // class method lookup function
114114
global ::= nominal-type 'MU' // ObjC metadata update callback function
115+
global ::= nominal-type 'Ms' // ObjC resilient class stub
116+
global ::= nominal-type 'Mt' // Full ObjC resilient class stub (private)
115117
global ::= module 'MXM' // module descriptor
116118
global ::= context 'MXE' // extension descriptor
117119
global ::= context 'MXX' // anonymous context descriptor

include/swift/ABI/Metadata.h

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3683,6 +3683,28 @@ struct TargetResilientSuperclass {
36833683
TargetRelativeDirectPointer<Runtime, const void, /*nullable*/true> Superclass;
36843684
};
36853685

3686+
/// A structure that stores a reference to an Objective-C class stub.
3687+
///
3688+
/// This is not the class stub itself; it is part of a class context
3689+
/// descriptor.
3690+
template <typename Runtime>
3691+
struct TargetObjCResilientClassStubInfo {
3692+
/// A relative pointer to an Objective-C resilient class stub.
3693+
///
3694+
/// We do not declare a struct type for class stubs since the Swift runtime
3695+
/// does not need to interpret them. The class stub struct is part of
3696+
/// the Objective-C ABI, and is laid out as follows:
3697+
/// - isa pointer, always 1
3698+
/// - an update callback, of type 'Class (*)(Class *, objc_class_stub *)'
3699+
///
3700+
/// Class stubs are used for two purposes:
3701+
///
3702+
/// - Objective-C can reference class stubs when calling static methods.
3703+
/// - Objective-C and Swift can reference class stubs when emitting
3704+
/// categories (in Swift, extensions with @objc members).
3705+
TargetRelativeDirectPointer<Runtime, const void> Stub;
3706+
};
3707+
36863708
template <typename Runtime>
36873709
class TargetClassDescriptor final
36883710
: public TargetTypeContextDescriptor<Runtime>,
@@ -3695,7 +3717,8 @@ class TargetClassDescriptor final
36953717
TargetVTableDescriptorHeader<Runtime>,
36963718
TargetMethodDescriptor<Runtime>,
36973719
TargetOverrideTableHeader<Runtime>,
3698-
TargetMethodOverrideDescriptor<Runtime>> {
3720+
TargetMethodOverrideDescriptor<Runtime>,
3721+
TargetObjCResilientClassStubInfo<Runtime>> {
36993722
private:
37003723
using TrailingGenericContextObjects =
37013724
TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
@@ -3706,7 +3729,8 @@ class TargetClassDescriptor final
37063729
TargetVTableDescriptorHeader<Runtime>,
37073730
TargetMethodDescriptor<Runtime>,
37083731
TargetOverrideTableHeader<Runtime>,
3709-
TargetMethodOverrideDescriptor<Runtime>>;
3732+
TargetMethodOverrideDescriptor<Runtime>,
3733+
TargetObjCResilientClassStubInfo<Runtime>>;
37103734

37113735
using TrailingObjects =
37123736
typename TrailingGenericContextObjects::TrailingObjects;
@@ -3722,6 +3746,8 @@ class TargetClassDescriptor final
37223746
TargetForeignMetadataInitialization<Runtime>;
37233747
using SingletonMetadataInitialization =
37243748
TargetSingletonMetadataInitialization<Runtime>;
3749+
using ObjCResilientClassStubInfo =
3750+
TargetObjCResilientClassStubInfo<Runtime>;
37253751

37263752
using StoredPointer = typename Runtime::StoredPointer;
37273753
using StoredPointerDifference = typename Runtime::StoredPointerDifference;
@@ -3759,7 +3785,9 @@ class TargetClassDescriptor final
37593785
/// positive size of metadata objects of this class (in words).
37603786
uint32_t MetadataPositiveSizeInWords;
37613787

3762-
// Maybe add something here that's useful only for resilient types?
3788+
/// Otherwise, these flags are used to do things like indicating
3789+
/// the presence of an Objective-C resilient class stub.
3790+
ExtraClassDescriptorFlags ExtraClassFlags;
37633791
};
37643792

37653793
/// The number of additional members added by this class to the class
@@ -3835,6 +3863,10 @@ class TargetClassDescriptor final
38353863
return getOverrideTable()->NumEntries;
38363864
}
38373865

3866+
size_t numTrailingObjects(OverloadToken<ObjCResilientClassStubInfo>) const {
3867+
return hasObjCResilientClassStub() ? 1 : 0;
3868+
}
3869+
38383870
public:
38393871
const TargetRelativeDirectPointer<Runtime, const void, /*nullable*/true> &
38403872
getResilientSuperclass() const {
@@ -3954,7 +3986,24 @@ class TargetClassDescriptor final
39543986
&& i < numTrailingObjects(OverloadToken<MethodDescriptor>{}));
39553987
return getMethodDescriptors()[i].Impl.get();
39563988
}
3957-
3989+
3990+
/// Whether this context descriptor references an Objective-C resilient
3991+
/// class stub. See the above description of TargetObjCResilientClassStubInfo
3992+
/// for details.
3993+
bool hasObjCResilientClassStub() const {
3994+
if (!hasResilientSuperclass())
3995+
return false;
3996+
return ExtraClassFlags.hasObjCResilientClassStub();
3997+
}
3998+
3999+
const void *getObjCResilientClassStub() const {
4000+
if (!hasObjCResilientClassStub())
4001+
return nullptr;
4002+
4003+
return this->template getTrailingObjects<ObjCResilientClassStubInfo>()
4004+
->Stub.get();
4005+
}
4006+
39584007
static bool classof(const TargetContextDescriptor<Runtime> *cd) {
39594008
return cd->getKind() == ContextDescriptorKind::Class;
39604009
}

include/swift/ABI/MetadataValues.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,28 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
13091309
class_setResilientSuperclassReferenceKind)
13101310
};
13111311

1312+
/// Extra flags for resilient classes, since we need more than 16 bits of
1313+
/// flags there.
1314+
class ExtraClassDescriptorFlags : public FlagSet<uint32_t> {
1315+
enum {
1316+
/// Set if the context descriptor includes a pointer to an Objective-C
1317+
/// resilient class stub structure. See the description of
1318+
/// TargetObjCResilientClassStubInfo in Metadata.h for details.
1319+
///
1320+
/// Only meaningful for class descriptors when Objective-C interop is
1321+
/// enabled.
1322+
HasObjCResilientClassStub = 0,
1323+
};
1324+
1325+
public:
1326+
explicit ExtraClassDescriptorFlags(uint32_t bits) : FlagSet(bits) {}
1327+
constexpr ExtraClassDescriptorFlags() {}
1328+
1329+
FLAGSET_DEFINE_FLAG_ACCESSORS(HasObjCResilientClassStub,
1330+
hasObjCResilientClassStub,
1331+
setObjCResilientClassStub)
1332+
};
1333+
13121334
/// Flags for protocol context descriptors. These values are used as the
13131335
/// kindSpecificFlags of the ContextDescriptorFlags for the protocol.
13141336
class ProtocolContextDescriptorFlags : public FlagSet<uint16_t> {

include/swift/AST/Decl.h

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ class alignas(1 << DeclAlignInBits) Decl {
533533
NumRequirementsInSignature : 16
534534
);
535535

536-
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+2+1+2+1+3+1+1+1+1,
536+
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+2+1+2+1+6+1+1+1,
537537
/// Whether this class requires all of its instance variables to
538538
/// have in-class initializers.
539539
RequiresStoredPropertyInits : 1,
@@ -554,12 +554,11 @@ class alignas(1 << DeclAlignInBits) Decl {
554554
/// control inserting the implicit destructor.
555555
HasDestructorDecl : 1,
556556

557-
/// Whether the class has @objc ancestry.
558-
ObjCKind : 3,
557+
/// Information about the class's ancestry.
558+
Ancestry : 6,
559559

560-
/// Whether this class has @objc members.
561-
HasObjCMembersComputed : 1,
562-
HasObjCMembers : 1,
560+
/// Whether we have computed the above field or not.
561+
AncestryComputed : 1,
563562

564563
HasMissingDesignatedInitializers : 1,
565564
HasMissingVTableEntries : 1
@@ -3536,21 +3535,33 @@ enum class ArtificialMainKind : uint8_t {
35363535
UIApplicationMain,
35373536
};
35383537

3539-
enum class ObjCClassKind : uint8_t {
3540-
/// Neither the class nor any of its superclasses are @objc.
3541-
NonObjC,
3542-
/// One of the superclasses is @objc but another superclass or the
3543-
/// class itself has generic parameters, so while it cannot be
3544-
/// directly represented in Objective-C, it has implicitly @objc
3545-
/// members.
3546-
ObjCMembers,
3547-
/// The top-level ancestor of this class is not @objc, but the
3548-
/// class itself is.
3549-
ObjCWithSwiftRoot,
3550-
/// The class is bona-fide @objc.
3551-
ObjC,
3538+
/// This is the base type for AncestryOptions. Each flag describes possible
3539+
/// interesting kinds of superclasses that a class may have.
3540+
enum class AncestryFlags : uint8_t {
3541+
/// The class or one of its superclasses is @objc.
3542+
ObjC = (1<<0),
3543+
3544+
/// The class or one of its superclasses is @objcMembers.
3545+
ObjCMembers = (1<<1),
3546+
3547+
/// The class or one of its superclasses is generic.
3548+
Generic = (1<<2),
3549+
3550+
/// The class or one of its superclasses is resilient.
3551+
Resilient = (1<<3),
3552+
3553+
/// The class or one of its superclasses has resilient metadata and is in a
3554+
/// different resilience domain.
3555+
ResilientOther = (1<<4),
3556+
3557+
/// The class or one of its superclasses is imported from Clang.
3558+
ClangImported = (1<<5),
35523559
};
35533560

3561+
/// Return type of ClassDecl::checkAncestry(). Describes a set of interesting
3562+
/// kinds of superclasses that a class may have.
3563+
using AncestryOptions = OptionSet<AncestryFlags>;
3564+
35543565
/// ClassDecl - This is the declaration of a class, for example:
35553566
///
35563567
/// class Complex { var R : Double, I : Double }
@@ -3580,8 +3591,6 @@ class ClassDecl final : public NominalTypeDecl {
35803591
friend class SuperclassTypeRequest;
35813592
friend class TypeChecker;
35823593

3583-
bool hasObjCMembersSlow();
3584-
35853594
public:
35863595
ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
35873596
MutableArrayRef<TypeLoc> Inherited,
@@ -3613,6 +3622,9 @@ class ClassDecl final : public NominalTypeDecl {
36133622
/// is no superclass.
36143623
ClassDecl *getSuperclassDecl() const;
36153624

3625+
/// Check if this class is a superclass or equal to the given class.
3626+
bool isSuperclassOf(ClassDecl *other) const;
3627+
36163628
/// Set the superclass of this class.
36173629
void setSuperclass(Type superclass);
36183630

@@ -3753,18 +3765,13 @@ class ClassDecl final : public NominalTypeDecl {
37533765
Bits.ClassDecl.InheritsSuperclassInits = true;
37543766
}
37553767

3756-
/// Returns if this class has any @objc ancestors, or if it is directly
3757-
/// visible to Objective-C. The latter is a stronger condition which is only
3758-
/// true if the class does not have any generic ancestry.
3759-
ObjCClassKind checkObjCAncestry() const;
3760-
3761-
/// Returns if the class has implicitly @objc members. This is true if any
3762-
/// ancestor class has the @objcMembers attribute.
3763-
bool hasObjCMembers() const {
3764-
if (Bits.ClassDecl.HasObjCMembersComputed)
3765-
return Bits.ClassDecl.HasObjCMembers;
3768+
/// Walks the class hierarchy starting from this class, checking various
3769+
/// conditions.
3770+
AncestryOptions checkAncestry() const;
37663771

3767-
return const_cast<ClassDecl *>(this)->hasObjCMembersSlow();
3772+
/// Check if the class has ancestry of the given kind.
3773+
bool checkAncestry(AncestryFlags flag) const {
3774+
return checkAncestry().contains(flag);
37683775
}
37693776

37703777
/// The type of metaclass to use for a class.

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3592,9 +3592,11 @@ ERROR(invalid_nonobjc_extension,none,
35923592
ERROR(objc_in_extension_context,none,
35933593
"members of constrained extensions cannot be declared @objc", ())
35943594
ERROR(objc_in_generic_extension,none,
3595-
"members of extensions of "
3596-
"%select{classes from generic context|generic classes}0 "
3597-
"cannot be declared @objc", (bool))
3595+
"extensions of %select{classes from generic context|generic classes}0 "
3596+
"cannot contain '@objc' members", (bool))
3597+
ERROR(objc_in_resilient_extension,none,
3598+
"extensions of classes built with library evolution support "
3599+
"cannot contain '@objc' members", ())
35983600
ERROR(objc_operator, none,
35993601
"operator methods cannot be declared @objc", ())
36003602
ERROR(objc_operator_proto, none,
@@ -3615,6 +3617,10 @@ NOTE(objc_inference_swift3_addnonobjc,none,
36153617
ERROR(objc_for_generic_class,none,
36163618
"generic subclasses of '@objc' classes cannot have an explicit '@objc' "
36173619
"because they are not directly visible from Objective-C", ())
3620+
ERROR(objc_for_resilient_class,none,
3621+
"classes built with library evolution support cannot have explicit "
3622+
"'@objc' subclasses because they are not directly "
3623+
"visible from Objective-C", ())
36183624
ERROR(objc_getter_for_nonobjc_property,none,
36193625
"'@objc' getter for non-'@objc' property", ())
36203626
ERROR(objc_getter_for_nonobjc_subscript,none,

include/swift/AST/Module.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,10 @@ class ModuleDecl : public DeclContext, public TypeDecl {
324324
Bits.ModuleDecl.RawResilienceStrategy = unsigned(strategy);
325325
}
326326

327+
bool isResilient() const {
328+
return getResilienceStrategy() != ResilienceStrategy::Default;
329+
}
330+
327331
/// Look up a (possibly overloaded) value set at top-level scope
328332
/// (but with the specified access path, which may come from an import decl)
329333
/// within the current module.

include/swift/Basic/LangOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,11 @@ namespace swift {
296296
/// set to true.
297297
bool ExperimentalDependenciesIncludeIntrafileOnes = false;
298298

299+
/// Enable experimental support for emitting Objective-C resilient class
300+
/// stubs. This is a language option since it also determines if we admit
301+
/// @objc members in extensions of classes with resilient ancestry.
302+
bool EnableObjCResilientClassStubs = false;
303+
299304
/// Sets the target we are building for and updates platform conditions
300305
/// to match.
301306
///

include/swift/Demangling/DemangleNodes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ NODE(MetatypeRepresentation)
134134
NODE(Metaclass)
135135
NODE(MethodLookupFunction)
136136
NODE(ObjCMetadataUpdateFunction)
137+
NODE(ObjCResilientClassStub)
138+
NODE(FullObjCResilientClassStub)
137139
CONTEXT_NODE(ModifyAccessor)
138140
CONTEXT_NODE(Module)
139141
CONTEXT_NODE(NativeOwningAddressor)

include/swift/IRGen/Linking.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class LinkEntity {
106106
// This field appears in the ValueWitness kind.
107107
ValueWitnessShift = 8, ValueWitnessMask = 0xFF00,
108108

109-
// This field appears in the TypeMetadata kind.
109+
// This field appears in the TypeMetadata and ObjCResilientClassStub kinds.
110110
MetadataAddressShift = 8, MetadataAddressMask = 0x0300,
111111

112112
// This field appears in associated type access functions.
@@ -174,6 +174,12 @@ class LinkEntity {
174174
/// ClassMetadataStrategy::Update or ::FixedOrUpdate.
175175
ObjCMetadataUpdateFunction,
176176

177+
/// A stub that we emit to allow Clang-generated code to statically refer
178+
/// to Swift classes with resiliently-sized metadata, since the metadata
179+
/// is not statically-emitted. Used when getClassMetadataStrategy() is
180+
/// equal to ClassMetadataStrategy::Resilient.
181+
ObjCResilientClassStub,
182+
177183
/// A class metadata base offset global variable. This stores the offset
178184
/// of the immediate members of a class (generic parameters, field offsets,
179185
/// vtable offsets) in the class's metadata. The immediate members begin
@@ -623,13 +629,19 @@ class LinkEntity {
623629
return entity;
624630
}
625631

632+
static LinkEntity forObjCResilientClassStub(ClassDecl *decl,
633+
TypeMetadataAddress addr) {
634+
LinkEntity entity;
635+
entity.setForDecl(Kind::ObjCResilientClassStub, decl);
636+
entity.Data |= LINKENTITY_SET_FIELD(MetadataAddress, unsigned(addr));
637+
return entity;
638+
}
639+
626640
static LinkEntity forTypeMetadata(CanType concreteType,
627641
TypeMetadataAddress addr) {
628642
LinkEntity entity;
629-
entity.Pointer = concreteType.getPointer();
630-
entity.SecondaryPointer = nullptr;
631-
entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::TypeMetadata))
632-
| LINKENTITY_SET_FIELD(MetadataAddress, unsigned(addr));
643+
entity.setForType(Kind::TypeMetadata, concreteType);
644+
entity.Data |= LINKENTITY_SET_FIELD(MetadataAddress, unsigned(addr));
633645
return entity;
634646
}
635647

@@ -1031,7 +1043,8 @@ class LinkEntity {
10311043
return ValueWitness(LINKENTITY_GET_FIELD(Data, ValueWitness));
10321044
}
10331045
TypeMetadataAddress getMetadataAddress() const {
1034-
assert(getKind() == Kind::TypeMetadata);
1046+
assert(getKind() == Kind::TypeMetadata ||
1047+
getKind() == Kind::ObjCResilientClassStub);
10351048
return (TypeMetadataAddress)LINKENTITY_GET_FIELD(Data, MetadataAddress);
10361049
}
10371050
bool isForeignTypeMetadataCandidate() const {

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,4 +558,8 @@ def type_info_dump_filter_EQ : Joined<["-"], "type-info-dump-filter=">,
558558
Flags<[FrontendOption]>,
559559
HelpText<"One of 'all', 'resilient' or 'fragile'">;
560560

561+
def enable_objc_resilient_class_stubs : Flag<["-"], "enable-resilient-objc-class-stubs">,
562+
HelpText<"Emit Objective-C resilient class stubs for classes with "
563+
"resiliently-sized metadata">;
564+
561565
} // end let Flags = [FrontendOption, NoDriverOption, HelpHidden]

0 commit comments

Comments
 (0)