Skip to content

Commit f972f66

Browse files
committed
[cxx-interop] Runtime support for foreign reference types.
1 parent 9857464 commit f972f66

17 files changed

+215
-85
lines changed

include/swift/ABI/Metadata.h

Lines changed: 33 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,34 @@ struct TargetForeignClassMetadata : public TargetForeignTypeMetadata<Runtime> {
11591164
};
11601165
using ForeignClassMetadata = TargetForeignClassMetadata<InProcess>;
11611166

1167+
template <typename Runtime>
1168+
struct TargetForeignReferenceTypeMetadata : public TargetForeignTypeMetadata<Runtime> {
1169+
using StoredPointer = typename Runtime::StoredPointer;
1170+
1171+
/// An out-of-line description of the type.
1172+
TargetSignedPointer<Runtime, const TargetClassDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
1173+
1174+
/// Reserved space. For now, this should be zero-initialized.
1175+
/// If this is used for anything in the future, at least some of these
1176+
/// first bits should be flags.
1177+
StoredPointer Reserved[1];
1178+
1179+
ConstTargetMetadataPointer<Runtime, TargetClassDescriptor>
1180+
getDescription() const {
1181+
return Description;
1182+
}
1183+
1184+
typename Runtime::StoredSignedPointer
1185+
getDescriptionAsSignedPointer() const {
1186+
return Description;
1187+
}
1188+
1189+
static bool classof(const TargetMetadata<Runtime> *metadata) {
1190+
return metadata->getKind() == MetadataKind::ForeignReferenceType;
1191+
}
1192+
};
1193+
using ForeignReferenceTypeMetadata = TargetForeignReferenceTypeMetadata<InProcess>;
1194+
11621195
/// The common structure of metadata for structs and enums.
11631196
template <typename Runtime>
11641197
struct TargetValueMetadata : public TargetMetadata<Runtime> {

include/swift/ABI/MetadataKind.def

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

56+
METADATAKIND(ForeignReferenceType, 4 | MetadataKindIsNonHeap)
57+
5658
/// A type whose value is not exposed in the metadata system.
5759
METADATAKIND(Opaque, 0 | MetadataKindIsRuntimePrivate | MetadataKindIsNonHeap)
5860

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/GenMeta.cpp

Lines changed: 82 additions & 32 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();
@@ -1788,7 +1787,8 @@ namespace {
17881787
// is a foreign class.
17891788
if ((IGM.IRGen.Opts.ReflectionMetadata !=
17901789
ReflectionMetadataMode::Runtime) ||
1791-
getType()->isForeign()) {
1790+
getType()->isForeign() ||
1791+
getType()->isForeignReferenceType()) {
17921792
B.addInt32(0);
17931793
return;
17941794
}
@@ -2556,15 +2556,6 @@ void irgen::emitLazyTypeContextDescriptor(IRGenModule &IGM,
25562556
void irgen::emitLazyTypeMetadata(IRGenModule &IGM, NominalTypeDecl *type) {
25572557
eraseExistingTypeContextDescriptor(IGM, type);
25582558

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-
25682559
if (requiresForeignTypeMetadata(type)) {
25692560
emitForeignTypeMetadata(IGM, type);
25702561
} else if (auto sd = dyn_cast<StructDecl>(type)) {
@@ -3245,12 +3236,7 @@ static void createNonGenericMetadataAccessFunction(IRGenModule &IGM,
32453236
/// Emit the base-offset variable for the class.
32463237
static void emitClassMetadataBaseOffset(IRGenModule &IGM,
32473238
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-
}
3239+
assert(!classDecl->isForeignReferenceType());
32543240

32553241
// Otherwise, we know the offset at compile time, even if our
32563242
// clients do not, so just emit a constant.
@@ -5425,21 +5411,21 @@ namespace {
54255411
}
54265412
};
54275413

5428-
class ForeignClassMetadataBuilder;
5414+
template<class Impl>
54295415
class ForeignClassMetadataBuilderBase :
5430-
public ForeignClassMetadataVisitor<ForeignClassMetadataBuilder> {
5416+
public ForeignClassMetadataVisitor<Impl> {
54315417
protected:
54325418
ConstantStructBuilder &B;
54335419

54345420
ForeignClassMetadataBuilderBase(IRGenModule &IGM, ClassDecl *target,
54355421
ConstantStructBuilder &B)
5436-
: ForeignClassMetadataVisitor(IGM, target), B(B) {}
5422+
: ForeignClassMetadataVisitor<Impl>(IGM, target), B(B) {}
54375423
};
54385424

54395425
/// A builder for ForeignClassMetadata.
54405426
class ForeignClassMetadataBuilder :
54415427
public ForeignMetadataBuilderBase<ForeignClassMetadataBuilder,
5442-
ForeignClassMetadataBuilderBase> {
5428+
ForeignClassMetadataBuilderBase<ForeignClassMetadataBuilder>> {
54435429
public:
54445430
ForeignClassMetadataBuilder(IRGenModule &IGM, ClassDecl *target,
54455431
ConstantStructBuilder &B)
@@ -5532,6 +5518,60 @@ namespace {
55325518
B.addNullPointer(IGM.Int8PtrTy);
55335519
}
55345520
};
5521+
5522+
/// A builder for ForeignReferenceTypeMetadata.
5523+
class ForeignReferenceTypeMetadataBuilder :
5524+
public ForeignMetadataBuilderBase<ForeignReferenceTypeMetadataBuilder,
5525+
ForeignClassMetadataBuilderBase<ForeignReferenceTypeMetadataBuilder>> {
5526+
public:
5527+
ForeignReferenceTypeMetadataBuilder(IRGenModule &IGM, ClassDecl *target,
5528+
ConstantStructBuilder &B)
5529+
: ForeignMetadataBuilderBase(IGM, target, B) {
5530+
assert(getTargetType()->isForeignReferenceType() &&
5531+
"foreign reference type metadata build must be used on foreign reference types.");
5532+
5533+
if (IGM.getOptions().LazyInitializeClassMetadata)
5534+
CanBeConstant = false;
5535+
}
5536+
5537+
void emitInitializeMetadata(IRGenFunction &IGF, llvm::Value *metadata,
5538+
MetadataDependencyCollector *collector) {
5539+
llvm_unreachable("Not implemented for foreign reference types.");
5540+
}
5541+
5542+
// Visitor methods.
5543+
5544+
void addValueWitnessTable() {
5545+
auto type = getTargetType()->getCanonicalType();
5546+
B.add(irgen::emitValueWitnessTable(IGM, type, false, false).getValue());
5547+
}
5548+
5549+
void addMetadataFlags() {
5550+
B.addInt(IGM.MetadataKindTy, (unsigned) MetadataKind::ForeignReferenceType);
5551+
}
5552+
5553+
void addNominalTypeDescriptor() {
5554+
auto descriptor =
5555+
ClassContextDescriptorBuilder(this->IGM, Target, RequireMetadata).emit();
5556+
B.addSignedPointer(descriptor,
5557+
IGM.getOptions().PointerAuth.TypeDescriptors,
5558+
PointerAuthEntity::Special::TypeDescriptor);
5559+
}
5560+
5561+
void addSuperclass() {
5562+
// Always leave the superclass pointer unfilled. We'll have to
5563+
// unique it during initialization anyway, so we might as well spare
5564+
// ourselves the load-time work.
5565+
B.addNullPointer(IGM.TypeMetadataPtrTy);
5566+
5567+
assert(!Target->hasSuperclass() &&
5568+
"foreign reference types should not have superclasses.");
5569+
}
5570+
5571+
void addReservedWord() {
5572+
B.addNullPointer(IGM.Int8PtrTy);
5573+
}
5574+
};
55355575

55365576
/// A builder for ForeignStructMetadata.
55375577
class ForeignStructMetadataBuilder :
@@ -5598,8 +5638,9 @@ bool irgen::requiresForeignTypeMetadata(CanType type) {
55985638

55995639
bool irgen::requiresForeignTypeMetadata(NominalTypeDecl *decl) {
56005640
if (auto *clazz = dyn_cast<ClassDecl>(decl)) {
5601-
assert(!clazz->isForeignReferenceType());
5602-
5641+
if (clazz->isForeignReferenceType())
5642+
return true;
5643+
56035644
switch (clazz->getForeignClassKind()) {
56045645
case ClassDecl::ForeignKind::Normal:
56055646
case ClassDecl::ForeignKind::RuntimeOnly:
@@ -5623,16 +5664,25 @@ void irgen::emitForeignTypeMetadata(IRGenModule &IGM, NominalTypeDecl *decl) {
56235664
init.setPacked(true);
56245665

56255666
if (auto classDecl = dyn_cast<ClassDecl>(decl)) {
5626-
assert(classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType ||
5627-
classDecl->isForeignReferenceType());
5667+
if (classDecl->isForeignReferenceType()) {
5668+
ForeignReferenceTypeMetadataBuilder builder(IGM, classDecl, init);
5669+
builder.layout();
56285670

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

5632-
IGM.defineTypeMetadata(type, /*isPattern=*/false,
5633-
builder.canBeConstant(),
5634-
init.finishAndCreateFuture());
5635-
builder.createMetadataAccessFunction();
5678+
ForeignClassMetadataBuilder builder(IGM, classDecl, init);
5679+
builder.layout();
5680+
5681+
IGM.defineTypeMetadata(type, /*isPattern=*/false,
5682+
builder.canBeConstant(),
5683+
init.finishAndCreateFuture());
5684+
builder.createMetadataAccessFunction();
5685+
}
56365686
} else if (auto structDecl = dyn_cast<StructDecl>(decl)) {
56375687
assert(isa<ClangModuleUnit>(structDecl->getModuleScopeContext()));
56385688

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)