Skip to content

Class metadata fix for Windows [5.0, ABI] #20790

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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -1059,8 +1059,9 @@ struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
ConstTargetMetadataPointer<Runtime, TargetClassDescriptor> Description;

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

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

/// The ivar-destructor function.
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer> IVarDestroyer;
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
IVarDestroyer;

/// The class flags.
ClassFlags Flags;
Expand Down Expand Up @@ -3347,13 +3349,18 @@ using MetadataRelocator =
template <typename Runtime>
struct TargetResilientClassMetadataPattern {
/// A function that allocates metadata with the correct size at runtime.
TargetRelativeDirectPointer<Runtime, MetadataRelocator> RelocationFunction;
///
/// If this is null, the runtime instead calls swift_relocateClassMetadata(),
/// passing in the class descriptor and this pattern.
TargetRelativeDirectPointer<Runtime, MetadataRelocator, /*nullable*/ true>
RelocationFunction;

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

/// The ivar-destructor function.
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer> IVarDestroyer;
TargetRelativeDirectPointer<Runtime, ClassIVarDestroyer, /*nullable*/ true>
IVarDestroyer;

/// The class flags.
ClassFlags Flags;
Expand Down Expand Up @@ -3407,14 +3414,10 @@ struct TargetSingletonMetadataInitialization {
classDescription->hasResilientSuperclass());
}

/// This method can only be called from the runtime itself. It is defined
/// in MetadataCache.h.
TargetMetadata<Runtime> *allocate(
const TargetTypeContextDescriptor<Runtime> *description) const {
if (hasResilientClassPattern(description)) {
return ResilientPattern->RelocationFunction(description,
ResilientPattern.get());
}
return IncompleteMetadata.get();
}
const TargetTypeContextDescriptor<Runtime> *description) const;
};

template <typename Runtime>
Expand Down
10 changes: 5 additions & 5 deletions include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -610,8 +610,8 @@ void swift_initStructMetadata(StructMetadata *self,
/// swift_initClassMetadata().
SWIFT_RUNTIME_EXPORT
ClassMetadata *
swift_relocateClassMetadata(ClassDescriptor *descriptor,
ResilientClassMetadataPattern *pattern);
swift_relocateClassMetadata(const ClassDescriptor *descriptor,
const ResilientClassMetadataPattern *pattern);

/// Initialize various fields of the class metadata.
///
Expand Down Expand Up @@ -667,9 +667,9 @@ void swift_updateClassMetadata(ClassMetadata *self,
/// the same class or a subclass of the descriptor.
SWIFT_RUNTIME_EXPORT
void *
swift_lookUpClassMethod(ClassMetadata *metadata,
MethodDescriptor *method,
ClassDescriptor *description);
swift_lookUpClassMethod(const ClassMetadata *metadata,
const MethodDescriptor *method,
const ClassDescriptor *description);

/// \brief Fetch a uniqued metadata for a metatype type.
SWIFT_RUNTIME_EXPORT
Expand Down
63 changes: 16 additions & 47 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2478,17 +2478,6 @@ namespace {
B.add(metadata);
}

/// The runtime provides a value witness table for Builtin.NativeObject.
void addValueWitnessTable() {
ClassDecl *cls = Target;

auto type = (cls->checkObjCAncestry() != ObjCClassKind::NonObjC
? IGM.Context.TheUnknownObjectType
: IGM.Context.TheNativeObjectType);
auto wtable = IGM.getAddrOfValueWitnessTable(type);
B.add(wtable);
}

void addDestructorFunction() {
if (auto ptr = getAddrOfDestructorFunction(IGM, Target)) {
B.add(*ptr);
Expand Down Expand Up @@ -2658,6 +2647,14 @@ namespace {
B.addInt(IGM.SizeTy, getClassFieldOffset(IGM, baseType, var).getValue());
}

void addValueWitnessTable() {
auto type = (Target->checkObjCAncestry() != ObjCClassKind::NonObjC
? IGM.Context.TheUnknownObjectType
: IGM.Context.TheNativeObjectType);
auto wtable = IGM.getAddrOfValueWitnessTable(type);
B.add(wtable);
}

void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {
llvm_unreachable("Fixed class metadata cannot have missing members");
}
Expand Down Expand Up @@ -2691,6 +2688,11 @@ namespace {
B.addInt(IGM.SizeTy, 0);
}

void addValueWitnessTable() {
// The runtime fills in the value witness table for us.
B.add(llvm::ConstantPointerNull::get(IGM.WitnessTablePtrTy));
}

void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {
for (unsigned i = 0,
e = placeholder->getNumberOfFieldOffsetVectorEntries();
Expand Down Expand Up @@ -2742,9 +2744,9 @@ namespace {
}

void addRelocationFunction() {
auto function = IGM.getAddrOfTypeMetadataInstantiationFunction(
Target, NotForDefinition);
B.addRelativeAddress(function);
// We don't use this yet, but it's available as a future customization
// point.
B.addRelativeAddressOrNull(nullptr);
}

void addDestructorFunction() {
Expand Down Expand Up @@ -2792,39 +2794,6 @@ namespace {
emitInitializeClassMetadata(IGF, Target, FieldLayout, metadata,
collector);
});

emitRelocationFunction();
}

private:
/// Emit the create function for a class with resilient ancestry.
void emitRelocationFunction() {
// using MetadataRelocator =
// Metadata *(TypeContextDescriptor *type, void *pattern);
llvm::Function *f =
IGM.getAddrOfTypeMetadataInstantiationFunction(Target, ForDefinition);
f->setAttributes(IGM.constructInitialAttributes());

IRGenFunction IGF(IGM, f);

// Skip instrumentation when building for TSan to avoid false positives.
// The synchronization for this happens in the Runtime and we do not see it.
if (IGM.IRGen.Opts.Sanitizers & SanitizerKind::Thread)
f->removeFnAttr(llvm::Attribute::SanitizeThread);

if (IGM.DebugInfo)
IGM.DebugInfo->emitArtificialFunction(IGF, f);

Explosion params = IGF.collectParameters();
llvm::Value *descriptor = params.claimNext();
llvm::Value *pattern = params.claimNext();

// Allocate class metadata using the pattern we emitted.
llvm::Value *metadata =
IGF.Builder.CreateCall(IGF.IGM.getRelocateClassMetadataFn(),
{descriptor, pattern});

IGF.Builder.CreateRet(metadata);
}
};

Expand Down
56 changes: 49 additions & 7 deletions stdlib/public/runtime/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,48 @@
using namespace swift;
using namespace metadataimpl;

template<>
Metadata *TargetSingletonMetadataInitialization<InProcess>::allocate(
const TypeContextDescriptor *description) const {
// If this class has resilient ancestry, the size of the metadata is not known
// at compile time, so we allocate it dynamically, filling it in from a
// pattern.
if (hasResilientClassPattern(description)) {
auto *pattern = ResilientPattern.get();

// If there is a relocation function, call it.
if (auto *fn = ResilientPattern->RelocationFunction.get())
return fn(description, pattern);

// Otherwise, use the default behavior.
auto *classDescription = cast<ClassDescriptor>(description);
return swift_relocateClassMetadata(classDescription, pattern);
}

// Otherwise, we have a static template that we can initialize in-place.
auto *metadata = IncompleteMetadata.get();

// If this is a class, we have to initialize the value witness table early
// so that two-phase initialization can proceed as if this metadata is
// complete for layout purposes when it appears as part of an aggregate type.
if (auto *classMetadata = dyn_cast<ClassMetadata>(metadata)) {
auto *fullMetadata = asFullMetadata(metadata);

// Begin by initializing the value witness table; everything else is
// initialized by swift_initClassMetadata().
#if SWIFT_OBJC_INTEROP
fullMetadata->ValueWitnesses =
(classMetadata->Flags & ClassFlags::UsesSwiftRefcounting)
? &VALUE_WITNESS_SYM(Bo)
: &VALUE_WITNESS_SYM(BO);
#else
fullMetadata->ValueWitnesses = &VALUE_WITNESS_SYM(Bo);
#endif
}

return metadata;
}

/// Copy the generic arguments into place in a newly-allocated metadata.
static void installGenericArguments(Metadata *metadata,
const TypeContextDescriptor *description,
Expand Down Expand Up @@ -2024,8 +2066,8 @@ static MetadataAllocator &getResilientMetadataAllocator() {
}

ClassMetadata *
swift::swift_relocateClassMetadata(ClassDescriptor *description,
ResilientClassMetadataPattern *pattern) {
swift::swift_relocateClassMetadata(const ClassDescriptor *description,
const ResilientClassMetadataPattern *pattern) {
auto bounds = description->getMetadataBounds();

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

#ifndef NDEBUG
static bool isAncestorOf(const ClassMetadata *metadata,
ClassDescriptor *description) {
const ClassDescriptor *description) {
auto ancestor = metadata;
while (ancestor && ancestor->isTypeMetadata()) {
if (ancestor->getDescription() == description)
Expand All @@ -2707,9 +2749,9 @@ static bool isAncestorOf(const ClassMetadata *metadata,
#endif

void *
swift::swift_lookUpClassMethod(ClassMetadata *metadata,
MethodDescriptor *method,
ClassDescriptor *description) {
swift::swift_lookUpClassMethod(const ClassMetadata *metadata,
const MethodDescriptor *method,
const ClassDescriptor *description) {
assert(metadata->isTypeMetadata());

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

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

return *(words + vtableOffset);
}
Expand Down
18 changes: 1 addition & 17 deletions test/IRGen/class_resilience.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@

// CHECK: @"$s16class_resilience14ResilientChildCMP" = internal constant <{{.*}}> <{
// -- instantiation function:
// CHECK-SAME: @"$s16class_resilience14ResilientChildCMi"
// CHECK-SAME: i32 0,
// -- destructor:
// CHECK-SAME: @"$s16class_resilience14ResilientChildCfD"
// -- ivar destroyer:
Expand Down Expand Up @@ -525,14 +525,6 @@ extension ResilientGenericOutsideParent {
// CHECK-NEXT: ret void


// ResilientChild metadata relocation function

// CHECK-LABEL: define internal %swift.type* @"$s16class_resilience14ResilientChildCMi"(%swift.type_descriptor*, i8*)
// CHECK-NEXT: entry:
// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_relocateClassMetadata(%swift.type_descriptor* %0, i8* %1)
// CHECK-NEXT: ret %swift.type* [[METADATA]]


// FixedLayoutChild metadata initialization function

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


// FixedLayoutChild metadata relocation function

// CHECK-LABEL: define internal %swift.type* @"$s16class_resilience16FixedLayoutChildCMi"(%swift.type_descriptor*, i8*)
// CHECK-NEXT: entry:
// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_relocateClassMetadata(%swift.type_descriptor* %0, i8* %1)
// CHECK-NEXT: ret %swift.type* [[METADATA]]


// ResilientGenericChild metadata initialization function

// CHECK-LABEL: define internal %swift.type* @"$s16class_resilience21ResilientGenericChildCMi"(%swift.type_descriptor*, i8**, i8*)
Expand Down
2 changes: 0 additions & 2 deletions test/IRGen/dllimport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,12 @@ public func g() {
// CHECK-NO-OPT-DAG: declare dllimport %swift.refcounted* @swift_retain(%swift.refcounted* returned)
// CHECK-NO-OPT-DAG: @"$s9dllexport1pMp" = external dllimport global %swift.protocol
// CHECK-NO-OPT-DAG: @"$sytN" = external dllimport global %swift.full_type
// CHECK-NO-OPT-DAG: @"$sBoWV" = external dllimport global i8*
// CHECK-NO-OPT-DAG: declare dllimport swiftcc i8* @"$s9dllexport2ciAA1cCvau"()
// CHECK-NO-OPT-DAG: declare dllimport swiftcc %swift.refcounted* @"$s9dllexport1cCfd"(%T9dllexport1cC* swiftself)
// CHECK-NO-OPT-DAG: declare dllimport swiftcc %swift.metadata_response @"$s9dllexport1cCMa"(i32)
// CHECK-NO-OPT-DAG: declare dllimport void @swift_deallocClassInstance(%swift.refcounted*, i32, i32)

// CHECK-OPT-DAG: declare dllimport %swift.refcounted* @swift_retain(%swift.refcounted* returned) local_unnamed_addr
// CHECK-OPT-DAG: @"$sBoWV" = external dllimport global i8*
// CHECK-OPT-DAG: @"__imp_$s9dllexport1pMp" = external externally_initialized constant %swift.protocol*
// CHECK-OPT-DAG: declare dllimport swiftcc i8* @"$s9dllexport2ciAA1cCvau"()
// CHECK-OPT-DAG: declare dllimport swiftcc %swift.metadata_response @"$s9dllexport1cCMa"(i32)
Expand Down
8 changes: 8 additions & 0 deletions test/IRGen/generic_vtable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ public class Concrete : Derived<Int> {
//// Type metadata for 'Base' has a static vtable.

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

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