Skip to content

Commit 1ae6946

Browse files
authored
Merge pull request #20790 from slavapestov/windows-class-value-witness-table-fix-5.0
Class metadata fix for Windows [5.0, ABI]
2 parents ddc8208 + f0dd884 commit 1ae6946

File tree

7 files changed

+94
-90
lines changed

7 files changed

+94
-90
lines changed

include/swift/ABI/Metadata.h

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,8 +1059,9 @@ struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
10591059
ConstTargetMetadataPointer<Runtime, TargetClassDescriptor> Description;
10601060

10611061
public:
1062-
/// A function for destroying instance variables, used to clean up
1063-
/// after an early return from a constructor.
1062+
/// A function for destroying instance variables, used to clean up after an
1063+
/// early return from a constructor. If null, no clean up will be performed
1064+
/// and all ivars must be trivial.
10641065
TargetPointer<Runtime, ClassIVarDestroyer> IVarDestroyer;
10651066

10661067
// After this come the class members, laid out as follows:
@@ -3110,7 +3111,8 @@ struct TargetGenericClassMetadataPattern final :
31103111
TargetRelativeDirectPointer<Runtime, HeapObjectDestroyer> Destroy;
31113112

31123113
/// The ivar-destructor function.
3113-
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer> IVarDestroyer;
3114+
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
3115+
IVarDestroyer;
31143116

31153117
/// The class flags.
31163118
ClassFlags Flags;
@@ -3347,13 +3349,18 @@ using MetadataRelocator =
33473349
template <typename Runtime>
33483350
struct TargetResilientClassMetadataPattern {
33493351
/// A function that allocates metadata with the correct size at runtime.
3350-
TargetRelativeDirectPointer<Runtime, MetadataRelocator> RelocationFunction;
3352+
///
3353+
/// If this is null, the runtime instead calls swift_relocateClassMetadata(),
3354+
/// passing in the class descriptor and this pattern.
3355+
TargetRelativeDirectPointer<Runtime, MetadataRelocator, /*nullable*/ true>
3356+
RelocationFunction;
33513357

33523358
/// The heap-destructor function.
33533359
TargetRelativeDirectPointer<Runtime, HeapObjectDestroyer> Destroy;
33543360

33553361
/// The ivar-destructor function.
3356-
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer> IVarDestroyer;
3362+
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
3363+
IVarDestroyer;
33573364

33583365
/// The class flags.
33593366
ClassFlags Flags;
@@ -3407,14 +3414,10 @@ struct TargetSingletonMetadataInitialization {
34073414
classDescription->hasResilientSuperclass());
34083415
}
34093416

3417+
/// This method can only be called from the runtime itself. It is defined
3418+
/// in MetadataCache.h.
34103419
TargetMetadata<Runtime> *allocate(
3411-
const TargetTypeContextDescriptor<Runtime> *description) const {
3412-
if (hasResilientClassPattern(description)) {
3413-
return ResilientPattern->RelocationFunction(description,
3414-
ResilientPattern.get());
3415-
}
3416-
return IncompleteMetadata.get();
3417-
}
3420+
const TargetTypeContextDescriptor<Runtime> *description) const;
34183421
};
34193422

34203423
template <typename Runtime>

include/swift/Runtime/Metadata.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -610,8 +610,8 @@ void swift_initStructMetadata(StructMetadata *self,
610610
/// swift_initClassMetadata().
611611
SWIFT_RUNTIME_EXPORT
612612
ClassMetadata *
613-
swift_relocateClassMetadata(ClassDescriptor *descriptor,
614-
ResilientClassMetadataPattern *pattern);
613+
swift_relocateClassMetadata(const ClassDescriptor *descriptor,
614+
const ResilientClassMetadataPattern *pattern);
615615

616616
/// Initialize various fields of the class metadata.
617617
///
@@ -667,9 +667,9 @@ void swift_updateClassMetadata(ClassMetadata *self,
667667
/// the same class or a subclass of the descriptor.
668668
SWIFT_RUNTIME_EXPORT
669669
void *
670-
swift_lookUpClassMethod(ClassMetadata *metadata,
671-
MethodDescriptor *method,
672-
ClassDescriptor *description);
670+
swift_lookUpClassMethod(const ClassMetadata *metadata,
671+
const MethodDescriptor *method,
672+
const ClassDescriptor *description);
673673

674674
/// \brief Fetch a uniqued metadata for a metatype type.
675675
SWIFT_RUNTIME_EXPORT

lib/IRGen/GenMeta.cpp

Lines changed: 16 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,17 +2478,6 @@ namespace {
24782478
B.add(metadata);
24792479
}
24802480

2481-
/// The runtime provides a value witness table for Builtin.NativeObject.
2482-
void addValueWitnessTable() {
2483-
ClassDecl *cls = Target;
2484-
2485-
auto type = (cls->checkObjCAncestry() != ObjCClassKind::NonObjC
2486-
? IGM.Context.TheUnknownObjectType
2487-
: IGM.Context.TheNativeObjectType);
2488-
auto wtable = IGM.getAddrOfValueWitnessTable(type);
2489-
B.add(wtable);
2490-
}
2491-
24922481
void addDestructorFunction() {
24932482
if (auto ptr = getAddrOfDestructorFunction(IGM, Target)) {
24942483
B.add(*ptr);
@@ -2658,6 +2647,14 @@ namespace {
26582647
B.addInt(IGM.SizeTy, getClassFieldOffset(IGM, baseType, var).getValue());
26592648
}
26602649

2650+
void addValueWitnessTable() {
2651+
auto type = (Target->checkObjCAncestry() != ObjCClassKind::NonObjC
2652+
? IGM.Context.TheUnknownObjectType
2653+
: IGM.Context.TheNativeObjectType);
2654+
auto wtable = IGM.getAddrOfValueWitnessTable(type);
2655+
B.add(wtable);
2656+
}
2657+
26612658
void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {
26622659
llvm_unreachable("Fixed class metadata cannot have missing members");
26632660
}
@@ -2691,6 +2688,11 @@ namespace {
26912688
B.addInt(IGM.SizeTy, 0);
26922689
}
26932690

2691+
void addValueWitnessTable() {
2692+
// The runtime fills in the value witness table for us.
2693+
B.add(llvm::ConstantPointerNull::get(IGM.WitnessTablePtrTy));
2694+
}
2695+
26942696
void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {
26952697
for (unsigned i = 0,
26962698
e = placeholder->getNumberOfFieldOffsetVectorEntries();
@@ -2742,9 +2744,9 @@ namespace {
27422744
}
27432745

27442746
void addRelocationFunction() {
2745-
auto function = IGM.getAddrOfTypeMetadataInstantiationFunction(
2746-
Target, NotForDefinition);
2747-
B.addRelativeAddress(function);
2747+
// We don't use this yet, but it's available as a future customization
2748+
// point.
2749+
B.addRelativeAddressOrNull(nullptr);
27482750
}
27492751

27502752
void addDestructorFunction() {
@@ -2792,39 +2794,6 @@ namespace {
27922794
emitInitializeClassMetadata(IGF, Target, FieldLayout, metadata,
27932795
collector);
27942796
});
2795-
2796-
emitRelocationFunction();
2797-
}
2798-
2799-
private:
2800-
/// Emit the create function for a class with resilient ancestry.
2801-
void emitRelocationFunction() {
2802-
// using MetadataRelocator =
2803-
// Metadata *(TypeContextDescriptor *type, void *pattern);
2804-
llvm::Function *f =
2805-
IGM.getAddrOfTypeMetadataInstantiationFunction(Target, ForDefinition);
2806-
f->setAttributes(IGM.constructInitialAttributes());
2807-
2808-
IRGenFunction IGF(IGM, f);
2809-
2810-
// Skip instrumentation when building for TSan to avoid false positives.
2811-
// The synchronization for this happens in the Runtime and we do not see it.
2812-
if (IGM.IRGen.Opts.Sanitizers & SanitizerKind::Thread)
2813-
f->removeFnAttr(llvm::Attribute::SanitizeThread);
2814-
2815-
if (IGM.DebugInfo)
2816-
IGM.DebugInfo->emitArtificialFunction(IGF, f);
2817-
2818-
Explosion params = IGF.collectParameters();
2819-
llvm::Value *descriptor = params.claimNext();
2820-
llvm::Value *pattern = params.claimNext();
2821-
2822-
// Allocate class metadata using the pattern we emitted.
2823-
llvm::Value *metadata =
2824-
IGF.Builder.CreateCall(IGF.IGM.getRelocateClassMetadataFn(),
2825-
{descriptor, pattern});
2826-
2827-
IGF.Builder.CreateRet(metadata);
28282797
}
28292798
};
28302799

stdlib/public/runtime/Metadata.cpp

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,48 @@
7272
using namespace swift;
7373
using namespace metadataimpl;
7474

75+
template<>
76+
Metadata *TargetSingletonMetadataInitialization<InProcess>::allocate(
77+
const TypeContextDescriptor *description) const {
78+
// If this class has resilient ancestry, the size of the metadata is not known
79+
// at compile time, so we allocate it dynamically, filling it in from a
80+
// pattern.
81+
if (hasResilientClassPattern(description)) {
82+
auto *pattern = ResilientPattern.get();
83+
84+
// If there is a relocation function, call it.
85+
if (auto *fn = ResilientPattern->RelocationFunction.get())
86+
return fn(description, pattern);
87+
88+
// Otherwise, use the default behavior.
89+
auto *classDescription = cast<ClassDescriptor>(description);
90+
return swift_relocateClassMetadata(classDescription, pattern);
91+
}
92+
93+
// Otherwise, we have a static template that we can initialize in-place.
94+
auto *metadata = IncompleteMetadata.get();
95+
96+
// If this is a class, we have to initialize the value witness table early
97+
// so that two-phase initialization can proceed as if this metadata is
98+
// complete for layout purposes when it appears as part of an aggregate type.
99+
if (auto *classMetadata = dyn_cast<ClassMetadata>(metadata)) {
100+
auto *fullMetadata = asFullMetadata(metadata);
101+
102+
// Begin by initializing the value witness table; everything else is
103+
// initialized by swift_initClassMetadata().
104+
#if SWIFT_OBJC_INTEROP
105+
fullMetadata->ValueWitnesses =
106+
(classMetadata->Flags & ClassFlags::UsesSwiftRefcounting)
107+
? &VALUE_WITNESS_SYM(Bo)
108+
: &VALUE_WITNESS_SYM(BO);
109+
#else
110+
fullMetadata->ValueWitnesses = &VALUE_WITNESS_SYM(Bo);
111+
#endif
112+
}
113+
114+
return metadata;
115+
}
116+
75117
/// Copy the generic arguments into place in a newly-allocated metadata.
76118
static void installGenericArguments(Metadata *metadata,
77119
const TypeContextDescriptor *description,
@@ -2024,8 +2066,8 @@ static MetadataAllocator &getResilientMetadataAllocator() {
20242066
}
20252067

20262068
ClassMetadata *
2027-
swift::swift_relocateClassMetadata(ClassDescriptor *description,
2028-
ResilientClassMetadataPattern *pattern) {
2069+
swift::swift_relocateClassMetadata(const ClassDescriptor *description,
2070+
const ResilientClassMetadataPattern *pattern) {
20292071
auto bounds = description->getMetadataBounds();
20302072

20312073
auto metadata = reinterpret_cast<ClassMetadata *>(
@@ -2695,7 +2737,7 @@ swift::swift_updateClassMetadata(ClassMetadata *self,
26952737

26962738
#ifndef NDEBUG
26972739
static bool isAncestorOf(const ClassMetadata *metadata,
2698-
ClassDescriptor *description) {
2740+
const ClassDescriptor *description) {
26992741
auto ancestor = metadata;
27002742
while (ancestor && ancestor->isTypeMetadata()) {
27012743
if (ancestor->getDescription() == description)
@@ -2707,9 +2749,9 @@ static bool isAncestorOf(const ClassMetadata *metadata,
27072749
#endif
27082750

27092751
void *
2710-
swift::swift_lookUpClassMethod(ClassMetadata *metadata,
2711-
MethodDescriptor *method,
2712-
ClassDescriptor *description) {
2752+
swift::swift_lookUpClassMethod(const ClassMetadata *metadata,
2753+
const MethodDescriptor *method,
2754+
const ClassDescriptor *description) {
27132755
assert(metadata->isTypeMetadata());
27142756

27152757
assert(isAncestorOf(metadata, description));
@@ -2722,7 +2764,7 @@ swift::swift_lookUpClassMethod(ClassMetadata *metadata,
27222764
assert(index < methods.size());
27232765

27242766
auto vtableOffset = vtable->getVTableOffset(description) + index;
2725-
auto *words = reinterpret_cast<void **>(metadata);
2767+
auto *words = reinterpret_cast<void * const *>(metadata);
27262768

27272769
return *(words + vtableOffset);
27282770
}

test/IRGen/class_resilience.swift

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383

8484
// CHECK: @"$s16class_resilience14ResilientChildCMP" = internal constant <{{.*}}> <{
8585
// -- instantiation function:
86-
// CHECK-SAME: @"$s16class_resilience14ResilientChildCMi"
86+
// CHECK-SAME: i32 0,
8787
// -- destructor:
8888
// CHECK-SAME: @"$s16class_resilience14ResilientChildCfD"
8989
// -- ivar destroyer:
@@ -525,14 +525,6 @@ extension ResilientGenericOutsideParent {
525525
// CHECK-NEXT: ret void
526526

527527

528-
// ResilientChild metadata relocation function
529-
530-
// CHECK-LABEL: define internal %swift.type* @"$s16class_resilience14ResilientChildCMi"(%swift.type_descriptor*, i8*)
531-
// CHECK-NEXT: entry:
532-
// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_relocateClassMetadata(%swift.type_descriptor* %0, i8* %1)
533-
// CHECK-NEXT: ret %swift.type* [[METADATA]]
534-
535-
536528
// FixedLayoutChild metadata initialization function
537529

538530
// CHECK-LABEL: define internal swiftcc %swift.metadata_response @"$s16class_resilience16FixedLayoutChildCMr"(%swift.type*, i8*, i8**)
@@ -541,14 +533,6 @@ extension ResilientGenericOutsideParent {
541533
// CHECK: call void @swift_initClassMetadata(%swift.type* %0, [[INT]] 0, [[INT]] 1, i8*** {{%.*}}, [[INT]]* {{%.*}})
542534

543535

544-
// FixedLayoutChild metadata relocation function
545-
546-
// CHECK-LABEL: define internal %swift.type* @"$s16class_resilience16FixedLayoutChildCMi"(%swift.type_descriptor*, i8*)
547-
// CHECK-NEXT: entry:
548-
// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_relocateClassMetadata(%swift.type_descriptor* %0, i8* %1)
549-
// CHECK-NEXT: ret %swift.type* [[METADATA]]
550-
551-
552536
// ResilientGenericChild metadata initialization function
553537

554538
// CHECK-LABEL: define internal %swift.type* @"$s16class_resilience21ResilientGenericChildCMi"(%swift.type_descriptor*, i8**, i8*)

test/IRGen/dllimport.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,12 @@ public func g() {
4242
// CHECK-NO-OPT-DAG: declare dllimport %swift.refcounted* @swift_retain(%swift.refcounted* returned)
4343
// CHECK-NO-OPT-DAG: @"$s9dllexport1pMp" = external dllimport global %swift.protocol
4444
// CHECK-NO-OPT-DAG: @"$sytN" = external dllimport global %swift.full_type
45-
// CHECK-NO-OPT-DAG: @"$sBoWV" = external dllimport global i8*
4645
// CHECK-NO-OPT-DAG: declare dllimport swiftcc i8* @"$s9dllexport2ciAA1cCvau"()
4746
// CHECK-NO-OPT-DAG: declare dllimport swiftcc %swift.refcounted* @"$s9dllexport1cCfd"(%T9dllexport1cC* swiftself)
4847
// CHECK-NO-OPT-DAG: declare dllimport swiftcc %swift.metadata_response @"$s9dllexport1cCMa"(i32)
4948
// CHECK-NO-OPT-DAG: declare dllimport void @swift_deallocClassInstance(%swift.refcounted*, i32, i32)
5049

5150
// CHECK-OPT-DAG: declare dllimport %swift.refcounted* @swift_retain(%swift.refcounted* returned) local_unnamed_addr
52-
// CHECK-OPT-DAG: @"$sBoWV" = external dllimport global i8*
5351
// CHECK-OPT-DAG: @"__imp_$s9dllexport1pMp" = external externally_initialized constant %swift.protocol*
5452
// CHECK-OPT-DAG: declare dllimport swiftcc i8* @"$s9dllexport2ciAA1cCvau"()
5553
// CHECK-OPT-DAG: declare dllimport swiftcc %swift.metadata_response @"$s9dllexport1cCMa"(i32)

test/IRGen/generic_vtable.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ public class Concrete : Derived<Int> {
3838
//// Type metadata for 'Base' has a static vtable.
3939

4040
// CHECK-LABEL: @"$s14generic_vtable4BaseCMf" = internal global
41+
// -- destructor
42+
// CHECK-SAME: void (%T14generic_vtable4BaseC*)* @"$s14generic_vtable4BaseCfD"
43+
// -- value witness table
44+
// CHECK-SAME: i8** @"$sBoWV"
4145
// -- vtable entry for 'm1()'
4246
// CHECK-SAME: void (%T14generic_vtable4BaseC*)* @"$s14generic_vtable4BaseC2m1yyF"
4347
// -- vtable entry for 'm2()'
@@ -110,6 +114,10 @@ public class Concrete : Derived<Int> {
110114
//// Type metadata for 'Concrete' has a static vtable.
111115

112116
// CHECK-LABEL: @"$s14generic_vtable8ConcreteCMf" = internal global <{{.*}}> <{
117+
// -- destructor
118+
// CHECK-SAME: void (%T14generic_vtable8ConcreteC*)* @"$s14generic_vtable8ConcreteCfD",
119+
// -- value witness table is filled in at runtime
120+
// CHECK-SAME: i8** null,
113121
// -- nominal type descriptor
114122
// CHECK-SAME: @"$s14generic_vtable8ConcreteCMn",
115123
// -- vtable entry for 'm1()'

0 commit comments

Comments
 (0)