Skip to content

Commit d245831

Browse files
authored
Merge pull request #18694 from slavapestov/in-place-class-metadata-init
In-place class metadata initialization
2 parents 7fa4f1d + 1eed99d commit d245831

36 files changed

+959
-763
lines changed

include/swift/ABI/Metadata.h

+85-42
Original file line numberDiff line numberDiff line change
@@ -3301,6 +3301,69 @@ struct TargetForeignMetadataInitialization {
33013301
CompletionFunction;
33023302
};
33033303

3304+
/// The cache structure for non-trivial initialization of singleton value
3305+
/// metadata.
3306+
template <typename Runtime>
3307+
struct TargetInPlaceValueMetadataCache {
3308+
/// The metadata pointer. Clients can do dependency-ordered loads
3309+
/// from this, and if they see a non-zero value, it's a Complete
3310+
/// metadata.
3311+
std::atomic<TargetMetadataPointer<Runtime, TargetMetadata>> Metadata;
3312+
3313+
/// The private cache data.
3314+
std::atomic<TargetPointer<Runtime, void>> Private;
3315+
};
3316+
using InPlaceValueMetadataCache =
3317+
TargetInPlaceValueMetadataCache<InProcess>;
3318+
3319+
/// An instantiation pattern for non-generic resilient class metadata.
3320+
/// Used in conjunction with InPlaceValueMetadataInitialization.
3321+
using MetadataRelocator =
3322+
Metadata *(const TargetTypeContextDescriptor<InProcess> *description);
3323+
3324+
/// The control structure for performing non-trivial initialization of
3325+
/// singleton value metadata, which is required when e.g. a non-generic
3326+
/// value type has a resilient component type.
3327+
template <typename Runtime>
3328+
struct TargetInPlaceValueMetadataInitialization {
3329+
/// The initialization cache. Out-of-line because mutable.
3330+
TargetRelativeDirectPointer<Runtime,
3331+
TargetInPlaceValueMetadataCache<Runtime>>
3332+
InitializationCache;
3333+
3334+
union {
3335+
/// The incomplete metadata, for structs, enums and classes without
3336+
/// resilient ancestry.
3337+
TargetRelativeDirectPointer<Runtime, TargetMetadata<Runtime>>
3338+
IncompleteMetadata;
3339+
3340+
/// If the class descriptor's hasResilientSuperclass() flag is set,
3341+
/// this field instead points at a function that allocates metadata
3342+
/// with the correct size at runtime.
3343+
TargetRelativeDirectPointer<Runtime, MetadataRelocator>
3344+
RelocationFunction;
3345+
};
3346+
3347+
/// The completion function. The pattern will always be null.
3348+
TargetRelativeDirectPointer<Runtime, MetadataCompleter>
3349+
CompletionFunction;
3350+
3351+
bool hasRelocationFunction(
3352+
const TargetTypeContextDescriptor<Runtime> *description) const {
3353+
auto *classDescription =
3354+
dyn_cast<TargetClassDescriptor<Runtime>>(description);
3355+
return (classDescription != nullptr &&
3356+
classDescription->hasResilientSuperclass());
3357+
}
3358+
3359+
TargetMetadata<Runtime> *allocate(
3360+
const TargetTypeContextDescriptor<Runtime> *description) const {
3361+
if (hasRelocationFunction(description))
3362+
return RelocationFunction(description);
3363+
return IncompleteMetadata.get();
3364+
}
3365+
};
3366+
33043367
template <typename Runtime>
33053368
class TargetTypeContextDescriptor
33063369
: public TargetContextDescriptor<Runtime> {
@@ -3355,8 +3418,11 @@ class TargetTypeContextDescriptor
33553418
const TargetForeignMetadataInitialization<Runtime> &
33563419
getForeignMetadataInitialization() const;
33573420

3421+
const TargetInPlaceValueMetadataInitialization<Runtime> &
3422+
getInPlaceMetadataInitialization() const;
3423+
33583424
const TargetTypeGenericContextDescriptorHeader<Runtime> &
3359-
getFullGenericContextHeader() const;
3425+
getFullGenericContextHeader() const;
33603426

33613427
const TargetGenericContextDescriptorHeader<Runtime> &
33623428
getGenericContextHeader() const {
@@ -3479,13 +3545,15 @@ class TargetClassDescriptor final
34793545
TargetTypeGenericContextDescriptorHeader,
34803546
/*additional trailing objects:*/
34813547
TargetForeignMetadataInitialization<Runtime>,
3548+
TargetInPlaceValueMetadataInitialization<Runtime>,
34823549
TargetVTableDescriptorHeader<Runtime>,
34833550
TargetMethodDescriptor<Runtime>> {
34843551
private:
34853552
using TrailingGenericContextObjects =
34863553
TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
34873554
TargetTypeGenericContextDescriptorHeader,
34883555
TargetForeignMetadataInitialization<Runtime>,
3556+
TargetInPlaceValueMetadataInitialization<Runtime>,
34893557
TargetVTableDescriptorHeader<Runtime>,
34903558
TargetMethodDescriptor<Runtime>>;
34913559

@@ -3498,6 +3566,8 @@ class TargetClassDescriptor final
34983566
using VTableDescriptorHeader = TargetVTableDescriptorHeader<Runtime>;
34993567
using ForeignMetadataInitialization =
35003568
TargetForeignMetadataInitialization<Runtime>;
3569+
using InPlaceMetadataInitialization =
3570+
TargetInPlaceValueMetadataInitialization<Runtime>;
35013571

35023572
using StoredPointer = typename Runtime::StoredPointer;
35033573
using StoredPointerDifference = typename Runtime::StoredPointerDifference;
@@ -3589,6 +3659,10 @@ class TargetClassDescriptor final
35893659
return this->hasForeignMetadataInitialization() ? 1 : 0;
35903660
}
35913661

3662+
size_t numTrailingObjects(OverloadToken<InPlaceMetadataInitialization>) const{
3663+
return this->hasInPlaceMetadataInitialization() ? 1 : 0;
3664+
}
3665+
35923666
size_t numTrailingObjects(OverloadToken<VTableDescriptorHeader>) const {
35933667
return hasVTable() ? 1 : 0;
35943668
}
@@ -3606,6 +3680,11 @@ class TargetClassDescriptor final
36063680
return *this->template getTrailingObjects<ForeignMetadataInitialization>();
36073681
}
36083682

3683+
const InPlaceMetadataInitialization &getInPlaceMetadataInitialization() const{
3684+
assert(this->hasInPlaceMetadataInitialization());
3685+
return *this->template getTrailingObjects<InPlaceMetadataInitialization>();
3686+
}
3687+
36093688
/// True if metadata records for this type have a field offset vector for
36103689
/// its stored properties.
36113690
bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
@@ -3698,49 +3777,10 @@ class TargetClassDescriptor final
36983777

36993778
using ClassDescriptor = TargetClassDescriptor<InProcess>;
37003779

3701-
/// The cache structure for non-trivial initialization of singleton value
3702-
/// metadata.
3703-
template <typename Runtime>
3704-
struct TargetInPlaceValueMetadataCache {
3705-
/// The metadata pointer. Clients can do dependency-ordered loads
3706-
/// from this, and if they see a non-zero value, it's a Complete
3707-
/// metadata.
3708-
std::atomic<TargetMetadataPointer<Runtime, TargetMetadata>> Metadata;
3709-
3710-
/// The private cache data.
3711-
std::atomic<TargetPointer<Runtime, void>> Private;
3712-
};
3713-
using InPlaceValueMetadataCache =
3714-
TargetInPlaceValueMetadataCache<InProcess>;
3715-
3716-
/// The control structure for performing non-trivial initialization of
3717-
/// singleton value metadata, which is required when e.g. a non-generic
3718-
/// value type has a resilient component type.
3719-
template <typename Runtime>
3720-
struct TargetInPlaceValueMetadataInitialization {
3721-
/// The initialization cache. Out-of-line because mutable.
3722-
TargetRelativeDirectPointer<Runtime,
3723-
TargetInPlaceValueMetadataCache<Runtime>>
3724-
InitializationCache;
3725-
3726-
/// The incomplete metadata.
3727-
TargetRelativeDirectPointer<Runtime, TargetMetadata<Runtime>>
3728-
IncompleteMetadata;
3729-
3730-
/// The completion function. The pattern will always be null.
3731-
TargetRelativeDirectPointer<Runtime, MetadataCompleter>
3732-
CompletionFunction;
3733-
};
3734-
37353780
template <typename Runtime>
37363781
class TargetValueTypeDescriptor
37373782
: public TargetTypeContextDescriptor<Runtime> {
37383783
public:
3739-
using InPlaceMetadataInitialization =
3740-
TargetInPlaceValueMetadataInitialization<Runtime>;
3741-
3742-
const InPlaceMetadataInitialization &getInPlaceMetadataInitialization() const;
3743-
37443784
static bool classof(const TargetContextDescriptor<Runtime> *cd) {
37453785
return cd->getKind() == ContextDescriptorKind::Struct ||
37463786
cd->getKind() == ContextDescriptorKind::Enum;
@@ -4015,16 +4055,19 @@ TargetTypeContextDescriptor<Runtime>::getForeignMetadataInitialization() const {
40154055

40164056
template<typename Runtime>
40174057
inline const TargetInPlaceValueMetadataInitialization<Runtime> &
4018-
TargetValueTypeDescriptor<Runtime>::getInPlaceMetadataInitialization() const {
4058+
TargetTypeContextDescriptor<Runtime>::getInPlaceMetadataInitialization() const {
40194059
switch (this->getKind()) {
40204060
case ContextDescriptorKind::Enum:
40214061
return llvm::cast<TargetEnumDescriptor<Runtime>>(this)
40224062
->getInPlaceMetadataInitialization();
40234063
case ContextDescriptorKind::Struct:
40244064
return llvm::cast<TargetStructDescriptor<Runtime>>(this)
40254065
->getInPlaceMetadataInitialization();
4066+
case ContextDescriptorKind::Class:
4067+
return llvm::cast<TargetClassDescriptor<Runtime>>(this)
4068+
->getInPlaceMetadataInitialization();
40264069
default:
4027-
swift_runtime_unreachable("Not a value type descriptor.");
4070+
swift_runtime_unreachable("Not a enum, struct or class type descriptor.");
40284071
}
40294072
}
40304073

include/swift/ABI/MetadataValues.h

+9
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,12 @@ enum class ClassLayoutFlags : uintptr_t {
10391039

10401040
/// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5.
10411041
Swift5Algorithm = 0x00,
1042+
1043+
/// If true, the vtable for this class and all of its superclasses was emitted
1044+
/// statically in the class metadata. If false, the superclass vtable is
1045+
/// copied from superclass metadata, and the immediate class vtable is
1046+
/// initialized from the type context descriptor.
1047+
HasStaticVTable = 0x100,
10421048
};
10431049
static inline ClassLayoutFlags operator|(ClassLayoutFlags lhs,
10441050
ClassLayoutFlags rhs) {
@@ -1052,6 +1058,9 @@ static inline ClassLayoutFlags getLayoutAlgorithm(ClassLayoutFlags flags) {
10521058
return ClassLayoutFlags(uintptr_t(flags)
10531059
& uintptr_t(ClassLayoutFlags::AlgorithmMask));
10541060
}
1061+
static inline bool hasStaticVTable(ClassLayoutFlags flags) {
1062+
return uintptr_t(flags) & uintptr_t(ClassLayoutFlags::HasStaticVTable);
1063+
}
10551064

10561065
/// Flags for enum layout.
10571066
enum class EnumLayoutFlags : uintptr_t {

include/swift/AST/Decl.h

-17
Original file line numberDiff line numberDiff line change
@@ -3625,23 +3625,6 @@ class ClassDecl final : public NominalTypeDecl {
36253625
/// might have implicitly @objc members, but will never itself be @objc.
36263626
ObjCClassKind checkObjCAncestry() const;
36273627

3628-
/// \brief Whether this class or its superclasses has some form of generic
3629-
/// context.
3630-
///
3631-
/// For example, given
3632-
///
3633-
/// class A<X> {}
3634-
/// class B : A<Int> {}
3635-
/// struct C<T> {
3636-
/// struct Inner {}
3637-
/// }
3638-
/// class D {}
3639-
/// class E: D {}
3640-
///
3641-
/// Calling hasGenericAncestry() on `B` returns `A<Int>`, on `C<T>.Inner`
3642-
/// returns `C<T>.Inner`, but on `E` it returns null.
3643-
ClassDecl *getGenericAncestor() const;
3644-
36453628
/// The type of metaclass to use for a class.
36463629
enum class MetaclassKind : uint8_t {
36473630
ObjC,

include/swift/AST/DiagnosticsSema.def

+6-4
Original file line numberDiff line numberDiff line change
@@ -1576,9 +1576,9 @@ ERROR(objc_protocol_cannot_have_conditional_conformance,none,
15761576
(Type, Type))
15771577
ERROR(objc_protocol_in_generic_extension,none,
15781578
"conformance of "
1579-
"%select{|subclass of a }2%select{class from generic context|generic class}3"
1580-
" %0 to @objc protocol %1 cannot be in an extension",
1581-
(Type, Type, bool, bool))
1579+
"%select{class from generic context|generic class}0 "
1580+
"%1 to @objc protocol %2 cannot be in an extension",
1581+
(bool, Type, Type))
15821582
ERROR(conditional_conformances_cannot_imply_conformances,none,
15831583
"conditional conformance of type %0 to protocol %1 does not imply conformance to "
15841584
"inherited protocol %2",
@@ -3545,7 +3545,9 @@ ERROR(invalid_nonobjc_extension,none,
35453545
ERROR(objc_in_extension_context,none,
35463546
"members of constrained extensions cannot be declared @objc", ())
35473547
ERROR(objc_in_generic_extension,none,
3548-
"@objc is not supported within extensions of generic classes or classes that inherit from generic classes", ())
3548+
"members of extensions of "
3549+
"%select{classes from generic context|generic classes}0 "
3550+
"cannot be declared @objc", (bool))
35493551
ERROR(objc_operator, none,
35503552
"operator methods cannot be declared @objc", ())
35513553
ERROR(objc_operator_proto, none,

include/swift/Basic/RelativePointer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ class RelativeDirectPointer<RetTy (ArgTy...), Nullable, Offset> :
491491
return this->get();
492492
}
493493

494-
RetTy operator()(ArgTy...arg) {
494+
RetTy operator()(ArgTy...arg) const {
495495
return this->get()(std::forward<ArgTy>(arg)...);
496496
}
497497

include/swift/Runtime/Metadata.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -580,14 +580,15 @@ void swift_initStructMetadata(StructMetadata *self,
580580
/// members.
581581
SWIFT_RUNTIME_EXPORT
582582
ClassMetadata *
583-
swift_relocateClassMetadata(ClassMetadata *self,
584-
size_t templateSize,
585-
size_t numImmediateMembers);
583+
swift_relocateClassMetadata(ClassDescriptor *descriptor,
584+
ClassMetadata *pattern,
585+
size_t patternSize);
586586

587587
/// Initialize the field offset vector for a dependent-layout class, using the
588588
/// "Universal" layout strategy.
589589
SWIFT_RUNTIME_EXPORT
590590
void swift_initClassMetadata(ClassMetadata *self,
591+
ClassMetadata *super,
591592
ClassLayoutFlags flags,
592593
size_t numFields,
593594
const TypeLayout * const *fieldTypes,

include/swift/Runtime/RuntimeFunctions.def

+6-5
Original file line numberDiff line numberDiff line change
@@ -808,25 +808,26 @@ FUNCTION(GetExistentialMetadata,
808808
ProtocolDescriptorRefTy->getPointerTo()),
809809
ATTRS(NoUnwind, ReadOnly))
810810

811-
// Metadata *swift_relocateClassMetadata(Metadata *self,
812-
// size_t templateSize,
813-
// size_t numImmediateMembers);
811+
// Metadata *swift_relocateClassMetadata(TypeContextDescriptor *descriptor,
812+
// Metadata *pattern,
813+
// size_t patternSize);
814814
FUNCTION(RelocateClassMetadata,
815815
swift_relocateClassMetadata, C_CC,
816816
RETURNS(TypeMetadataPtrTy),
817-
ARGS(TypeMetadataPtrTy, SizeTy, SizeTy),
817+
ARGS(TypeContextDescriptorPtrTy, TypeMetadataPtrTy, SizeTy),
818818
ATTRS(NoUnwind))
819819

820820
// struct FieldInfo { size_t Size; size_t AlignMask; };
821821
// void swift_initClassMetadata(Metadata *self,
822+
// Metadata *super,
822823
// ClassLayoutFlags flags,
823824
// size_t numFields,
824825
// TypeLayout * const *fieldTypes,
825826
// size_t *fieldOffsets);
826827
FUNCTION(InitClassMetadata,
827828
swift_initClassMetadata, C_CC,
828829
RETURNS(VoidTy),
829-
ARGS(TypeMetadataPtrTy, SizeTy, SizeTy,
830+
ARGS(TypeMetadataPtrTy, TypeMetadataPtrTy, SizeTy, SizeTy,
830831
Int8PtrPtrTy->getPointerTo(),
831832
SizeTy->getPointerTo()),
832833
ATTRS(NoUnwind))

lib/AST/Decl.cpp

-13
Original file line numberDiff line numberDiff line change
@@ -3431,19 +3431,6 @@ ClassDecl::findImplementingMethod(const AbstractFunctionDecl *Method) const {
34313431
return nullptr;
34323432
}
34333433

3434-
ClassDecl *ClassDecl::getGenericAncestor() const {
3435-
ClassDecl *current = const_cast<ClassDecl *>(this);
3436-
3437-
while (current) {
3438-
if (current->isGenericContext())
3439-
return current;
3440-
3441-
current = current->getSuperclassDecl();
3442-
}
3443-
3444-
return nullptr;
3445-
}
3446-
34473434
EnumCaseDecl *EnumCaseDecl::create(SourceLoc CaseLoc,
34483435
ArrayRef<EnumElementDecl *> Elements,
34493436
DeclContext *DC) {

lib/IRGen/ClassLayout.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ using namespace irgen;
2626

2727
ClassLayout::ClassLayout(const StructLayoutBuilder &builder,
2828
bool isFixedSize,
29-
bool metadataRequiresDynamicInitialization,
29+
bool metadataRequiresInitialization,
30+
bool metadataRequiresRelocation,
3031
llvm::Type *classTy,
3132
ArrayRef<VarDecl *> allStoredProps,
3233
ArrayRef<FieldAccess> allFieldAccesses,
@@ -35,7 +36,8 @@ ClassLayout::ClassLayout(const StructLayoutBuilder &builder,
3536
MinimumSize(builder.getSize()),
3637
IsFixedLayout(builder.isFixedLayout()),
3738
IsFixedSize(isFixedSize),
38-
MetadataRequiresDynamicInitialization(metadataRequiresDynamicInitialization),
39+
MetadataRequiresInitialization(metadataRequiresInitialization),
40+
MetadataRequiresRelocation(metadataRequiresRelocation),
3941
Ty(classTy),
4042
AllStoredProperties(allStoredProps),
4143
AllFieldAccesses(allFieldAccesses),

0 commit comments

Comments
 (0)