Skip to content

Commit fd52592

Browse files
authored
Merge pull request #59439 from zoecarver/frt-metatdata-runtime
[cxx-interop] Runtime support for foreign reference types.
2 parents a4a6d09 + bdc37c9 commit fd52592

18 files changed

+247
-80
lines changed

include/swift/ABI/Metadata.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ template <typename Runtime> struct TargetStructMetadata;
5555
template <typename Runtime> struct TargetOpaqueMetadata;
5656
template <typename Runtime> struct TargetValueMetadata;
5757
template <typename Runtime> struct TargetForeignClassMetadata;
58+
template <typename Runtime> struct TargetForeignReferenceTypeMetadata;
5859
template <typename Runtime> struct TargetContextDescriptor;
5960
template <typename Runtime> class TargetTypeContextDescriptor;
6061
template <typename Runtime> class TargetClassDescriptor;
@@ -258,6 +259,7 @@ struct TargetMetadata {
258259
case MetadataKind::Class:
259260
case MetadataKind::ObjCClassWrapper:
260261
case MetadataKind::ForeignClass:
262+
case MetadataKind::ForeignReferenceType:
261263
return true;
262264

263265
default:
@@ -375,6 +377,9 @@ struct TargetMetadata {
375377
case MetadataKind::ForeignClass:
376378
return static_cast<const TargetForeignClassMetadata<Runtime> *>(this)
377379
->Description;
380+
case MetadataKind::ForeignReferenceType:
381+
return static_cast<const TargetForeignReferenceTypeMetadata<Runtime> *>(this)
382+
->Description;
378383
default:
379384
return nullptr;
380385
}
@@ -1159,6 +1164,44 @@ struct TargetForeignClassMetadata : public TargetForeignTypeMetadata<Runtime> {
11591164
};
11601165
using ForeignClassMetadata = TargetForeignClassMetadata<InProcess>;
11611166

1167+
/// The structure of metadata objects for foreign reference types.
1168+
/// A foreign reference type is a non-Swift, non-Objective-C foreign type with
1169+
/// reference semantics. Foreign reference types are pointers/reference to
1170+
/// value types marked with the "import_as_ref" attribute.
1171+
///
1172+
/// Foreign reference types may have *custom* reference counting operations, or
1173+
/// they may be immortal (and therefore trivial).
1174+
///
1175+
/// We assume for now that foreign reference types are entirely opaque
1176+
/// to Swift introspection.
1177+
template <typename Runtime>
1178+
struct TargetForeignReferenceTypeMetadata : public TargetForeignTypeMetadata<Runtime> {
1179+
using StoredPointer = typename Runtime::StoredPointer;
1180+
1181+
/// An out-of-line description of the type.
1182+
TargetSignedPointer<Runtime, const TargetClassDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
1183+
1184+
/// Reserved space. For now, this should be zero-initialized.
1185+
/// If this is used for anything in the future, at least some of these
1186+
/// first bits should be flags.
1187+
StoredPointer Reserved[1];
1188+
1189+
ConstTargetMetadataPointer<Runtime, TargetClassDescriptor>
1190+
getDescription() const {
1191+
return Description;
1192+
}
1193+
1194+
typename Runtime::StoredSignedPointer
1195+
getDescriptionAsSignedPointer() const {
1196+
return Description;
1197+
}
1198+
1199+
static bool classof(const TargetMetadata<Runtime> *metadata) {
1200+
return metadata->getKind() == MetadataKind::ForeignReferenceType;
1201+
}
1202+
};
1203+
using ForeignReferenceTypeMetadata = TargetForeignReferenceTypeMetadata<InProcess>;
1204+
11621205
/// The common structure of metadata for structs and enums.
11631206
template <typename Runtime>
11641207
struct TargetValueMetadata : public TargetMetadata<Runtime> {

include/swift/ABI/MetadataKind.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ NOMINALTYPEMETADATAKIND(Optional, 2 | MetadataKindIsNonHeap)
5353
/// A foreign class, such as a Core Foundation class.
5454
METADATAKIND(ForeignClass, 3 | MetadataKindIsNonHeap)
5555

56+
/// A non-Swift non-Objective-C class type.
57+
METADATAKIND(ForeignReferenceType, 4 | MetadataKindIsNonHeap)
58+
5659
/// A type whose value is not exposed in the metadata system.
5760
METADATAKIND(Opaque, 0 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
5861

include/swift/Remote/MetadataReader.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,7 @@ class MetadataReader {
10361036
TypeCache[MetadataAddress] = BuiltExist;
10371037
return BuiltExist;
10381038
}
1039+
case MetadataKind::ForeignReferenceType:
10391040
case MetadataKind::ForeignClass: {
10401041
auto descriptorAddr = readAddressOfNominalTypeDescriptor(Meta);
10411042
if (!descriptorAddr)
@@ -1978,6 +1979,8 @@ class MetadataReader {
19781979
return _readMetadata<TargetExtendedExistentialTypeMetadata>(address);
19791980
case MetadataKind::ForeignClass:
19801981
return _readMetadata<TargetForeignClassMetadata>(address);
1982+
case MetadataKind::ForeignReferenceType:
1983+
return _readMetadata<TargetForeignReferenceTypeMetadata>(address);
19811984
case MetadataKind::Function: {
19821985
StoredSize flagsValue;
19831986
auto flagsAddr =
@@ -2093,6 +2096,13 @@ class MetadataReader {
20932096
return descriptorAddress;
20942097
}
20952098

2099+
case MetadataKind::ForeignReferenceType: {
2100+
auto foreignMeta = cast<TargetForeignReferenceTypeMetadata<Runtime>>(metadata);
2101+
StoredSignedPointer descriptorAddressSigned = foreignMeta->getDescriptionAsSignedPointer();
2102+
StoredPointer descriptorAddress = stripSignedPointer(descriptorAddressSigned);
2103+
return descriptorAddress;
2104+
}
2105+
20962106
default:
20972107
return 0;
20982108
}

lib/IRGen/ForeignClassMetadataVisitor.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,28 @@ class ForeignClassMetadataScanner : public ForeignClassMetadataVisitor<Impl> {
7171
}
7272
};
7373

74+
template <class Impl>
75+
class ForeignReferenceTypeMetadataVisitor
76+
: public NominalMetadataVisitor<Impl> {
77+
using super = NominalMetadataVisitor<Impl>;
78+
protected:
79+
ClassDecl *Target;
80+
using super::asImpl;
81+
public:
82+
ForeignReferenceTypeMetadataVisitor(IRGenModule &IGM, ClassDecl *target)
83+
: super(IGM), Target(target) {}
84+
85+
void layout() {
86+
super::layout();
87+
asImpl().addNominalTypeDescriptor();
88+
asImpl().addReservedWord();
89+
}
90+
91+
CanType getTargetType() const {
92+
return Target->getDeclaredType()->getCanonicalType();
93+
}
94+
};
95+
7496
} // end namespace irgen
7597
} // end namespace swift
7698

lib/IRGen/GenMeta.cpp

Lines changed: 80 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,7 +1688,7 @@ namespace {
16881688
VTable(IGM.getSILModule().lookUpVTable(getType())),
16891689
Resilient(IGM.hasResilientMetadata(Type, ResilienceExpansion::Minimal)) {
16901690

1691-
if (getType()->isForeign() || Type->isForeignReferenceType())
1691+
if (getType()->isForeign())
16921692
return;
16931693

16941694
MetadataLayout = &IGM.getClassMetadataLayout(Type);
@@ -1719,7 +1719,6 @@ namespace {
17191719
}
17201720

17211721
void layout() {
1722-
assert(!getType()->isForeignReferenceType());
17231722
super::layout();
17241723
addVTable();
17251724
addOverrideTable();
@@ -2556,15 +2555,6 @@ void irgen::emitLazyTypeContextDescriptor(IRGenModule &IGM,
25562555
void irgen::emitLazyTypeMetadata(IRGenModule &IGM, NominalTypeDecl *type) {
25572556
eraseExistingTypeContextDescriptor(IGM, type);
25582557

2559-
// Special case, UFOs are opaque pointers for now.
2560-
if (auto cd = dyn_cast<ClassDecl>(type)) {
2561-
if (cd->isForeignReferenceType()) {
2562-
auto sd = cast<StructDecl>(type->getASTContext().getOpaquePointerDecl());
2563-
emitStructMetadata(IGM, sd);
2564-
return;
2565-
}
2566-
}
2567-
25682558
if (requiresForeignTypeMetadata(type)) {
25692559
emitForeignTypeMetadata(IGM, type);
25702560
} else if (auto sd = dyn_cast<StructDecl>(type)) {
@@ -3245,12 +3235,7 @@ static void createNonGenericMetadataAccessFunction(IRGenModule &IGM,
32453235
/// Emit the base-offset variable for the class.
32463236
static void emitClassMetadataBaseOffset(IRGenModule &IGM,
32473237
ClassDecl *classDecl) {
3248-
if (classDecl->isForeignReferenceType()) {
3249-
classDecl->getASTContext().Diags.diagnose(
3250-
classDecl->getLoc(), diag::foreign_reference_types_unsupported.ID,
3251-
{});
3252-
exit(1);
3253-
}
3238+
assert(!classDecl->isForeignReferenceType());
32543239

32553240
// Otherwise, we know the offset at compile time, even if our
32563241
// clients do not, so just emit a constant.
@@ -5444,6 +5429,9 @@ namespace {
54445429
ForeignClassMetadataBuilder(IRGenModule &IGM, ClassDecl *target,
54455430
ConstantStructBuilder &B)
54465431
: ForeignMetadataBuilderBase(IGM, target, B) {
5432+
assert(!getTargetType()->isForeignReferenceType() &&
5433+
"foreign reference type metadata must be built with the ForeignReferenceTypeMetadataBuilder");
5434+
54475435
if (IGM.getOptions().LazyInitializeClassMetadata)
54485436
CanBeConstant = false;
54495437
}
@@ -5532,6 +5520,61 @@ namespace {
55325520
B.addNullPointer(IGM.Int8PtrTy);
55335521
}
55345522
};
5523+
5524+
class ForeignReferenceTypeMetadataBuilder;
5525+
class ForeignReferenceTypeMetadataBuilderBase :
5526+
public ForeignReferenceTypeMetadataVisitor<ForeignReferenceTypeMetadataBuilder> {
5527+
protected:
5528+
ConstantStructBuilder &B;
5529+
5530+
ForeignReferenceTypeMetadataBuilderBase(IRGenModule &IGM, ClassDecl *target,
5531+
ConstantStructBuilder &B)
5532+
: ForeignReferenceTypeMetadataVisitor(IGM, target), B(B) {}
5533+
};
5534+
5535+
/// A builder for ForeignReferenceTypeMetadata.
5536+
class ForeignReferenceTypeMetadataBuilder :
5537+
public ForeignMetadataBuilderBase<ForeignReferenceTypeMetadataBuilder,
5538+
ForeignReferenceTypeMetadataBuilderBase> {
5539+
public:
5540+
ForeignReferenceTypeMetadataBuilder(IRGenModule &IGM, ClassDecl *target,
5541+
ConstantStructBuilder &B)
5542+
: ForeignMetadataBuilderBase(IGM, target, B) {
5543+
assert(getTargetType()->isForeignReferenceType() &&
5544+
"foreign reference type metadata build must be used on foreign reference types.");
5545+
5546+
if (IGM.getOptions().LazyInitializeClassMetadata)
5547+
CanBeConstant = false;
5548+
}
5549+
5550+
void emitInitializeMetadata(IRGenFunction &IGF, llvm::Value *metadata,
5551+
MetadataDependencyCollector *collector) {
5552+
llvm_unreachable("Not implemented for foreign reference types.");
5553+
}
5554+
5555+
// Visitor methods.
5556+
5557+
void addValueWitnessTable() {
5558+
auto type = getTargetType()->getCanonicalType();
5559+
B.add(irgen::emitValueWitnessTable(IGM, type, false, false).getValue());
5560+
}
5561+
5562+
void addMetadataFlags() {
5563+
B.addInt(IGM.MetadataKindTy, (unsigned) MetadataKind::ForeignReferenceType);
5564+
}
5565+
5566+
void addNominalTypeDescriptor() {
5567+
auto descriptor =
5568+
ClassContextDescriptorBuilder(this->IGM, Target, RequireMetadata).emit();
5569+
B.addSignedPointer(descriptor,
5570+
IGM.getOptions().PointerAuth.TypeDescriptors,
5571+
PointerAuthEntity::Special::TypeDescriptor);
5572+
}
5573+
5574+
void addReservedWord() {
5575+
B.addNullPointer(IGM.Int8PtrTy);
5576+
}
5577+
};
55355578

55365579
/// A builder for ForeignStructMetadata.
55375580
class ForeignStructMetadataBuilder :
@@ -5598,8 +5641,9 @@ bool irgen::requiresForeignTypeMetadata(CanType type) {
55985641

55995642
bool irgen::requiresForeignTypeMetadata(NominalTypeDecl *decl) {
56005643
if (auto *clazz = dyn_cast<ClassDecl>(decl)) {
5601-
assert(!clazz->isForeignReferenceType());
5602-
5644+
if (clazz->isForeignReferenceType())
5645+
return true;
5646+
56035647
switch (clazz->getForeignClassKind()) {
56045648
case ClassDecl::ForeignKind::Normal:
56055649
case ClassDecl::ForeignKind::RuntimeOnly:
@@ -5623,16 +5667,25 @@ void irgen::emitForeignTypeMetadata(IRGenModule &IGM, NominalTypeDecl *decl) {
56235667
init.setPacked(true);
56245668

56255669
if (auto classDecl = dyn_cast<ClassDecl>(decl)) {
5626-
assert(classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType ||
5627-
classDecl->isForeignReferenceType());
5670+
if (classDecl->isForeignReferenceType()) {
5671+
ForeignReferenceTypeMetadataBuilder builder(IGM, classDecl, init);
5672+
builder.layout();
56285673

5629-
ForeignClassMetadataBuilder builder(IGM, classDecl, init);
5630-
builder.layout();
5674+
IGM.defineTypeMetadata(type, /*isPattern=*/false,
5675+
builder.canBeConstant(),
5676+
init.finishAndCreateFuture());
5677+
builder.createMetadataAccessFunction();
5678+
} else {
5679+
assert(classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType);
56315680

5632-
IGM.defineTypeMetadata(type, /*isPattern=*/false,
5633-
builder.canBeConstant(),
5634-
init.finishAndCreateFuture());
5635-
builder.createMetadataAccessFunction();
5681+
ForeignClassMetadataBuilder builder(IGM, classDecl, init);
5682+
builder.layout();
5683+
5684+
IGM.defineTypeMetadata(type, /*isPattern=*/false,
5685+
builder.canBeConstant(),
5686+
init.finishAndCreateFuture());
5687+
builder.createMetadataAccessFunction();
5688+
}
56365689
} else if (auto structDecl = dyn_cast<StructDecl>(decl)) {
56375690
assert(isa<ClangModuleUnit>(structDecl->getModuleScopeContext()));
56385691

lib/IRGen/GenProto.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,15 +1495,6 @@ llvm::Constant *IRGenModule::getAssociatedTypeWitness(Type type,
14951495
GenericSignature sig,
14961496
bool inProtocolContext) {
14971497
// FIXME: If we can directly reference constant type metadata, do so.
1498-
1499-
if (type->isForeignReferenceType()) {
1500-
type->getASTContext().Diags.diagnose(
1501-
type->lookThroughAllOptionalTypes()
1502-
->getClassOrBoundGenericClass()
1503-
->getLoc(),
1504-
diag::foreign_reference_types_unsupported.ID, {});
1505-
exit(1);
1506-
}
15071498

15081499
// Form a reference to the mangled name for this type.
15091500
assert(!type->hasArchetype() && "type cannot contain archetypes");

lib/IRGen/GenReflection.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,8 +577,6 @@ class ReflectionMetadataBuilder {
577577
CanGenericSignature sig,
578578
MangledTypeRefRole role =
579579
MangledTypeRefRole::Reflection) {
580-
assert(!type->isForeignReferenceType());
581-
582580
B.addRelativeAddress(IGM.getTypeRef(type, sig, role).first);
583581
addBuiltinTypeRefs(type);
584582
}

lib/IRGen/MetadataRequest.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,9 @@ MetadataAccessStrategy irgen::getTypeMetadataAccessStrategy(CanType type) {
10901090
assert(type->hasUnboundGenericType());
10911091
}
10921092

1093+
if (type->isForeignReferenceType())
1094+
return MetadataAccessStrategy::PublicUniqueAccessor;
1095+
10931096
if (requiresForeignTypeMetadata(nominal))
10941097
return MetadataAccessStrategy::ForeignAccessor;
10951098

@@ -3081,15 +3084,6 @@ llvm::Value *IRGenFunction::emitTypeMetadataRef(CanType type) {
30813084
MetadataResponse
30823085
IRGenFunction::emitTypeMetadataRef(CanType type,
30833086
DynamicMetadataRequest request) {
3084-
if (type->isForeignReferenceType()) {
3085-
type->getASTContext().Diags.diagnose(
3086-
type->lookThroughAllOptionalTypes()
3087-
->getClassOrBoundGenericClass()
3088-
->getLoc(),
3089-
diag::foreign_reference_types_unsupported.ID, {});
3090-
exit(1);
3091-
}
3092-
30933087
type = IGM.getRuntimeReifiedType(type);
30943088
// Look through any opaque types we're allowed to.
30953089
type = IGM.substOpaqueTypesWithUnderlyingTypes(type);

stdlib/public/runtime/AnyHashableSupport.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ void _swift_makeAnyHashableUpcastingToHashableBaseType(
155155
switch (type->getKind()) {
156156
case MetadataKind::Class:
157157
case MetadataKind::ObjCClassWrapper:
158-
case MetadataKind::ForeignClass: {
158+
case MetadataKind::ForeignClass:
159+
case MetadataKind::ForeignReferenceType: {
159160
#if SWIFT_OBJC_INTEROP
160161
id srcObject;
161162
memcpy(&srcObject, value, sizeof(id));

0 commit comments

Comments
 (0)