Skip to content

Commit 63d98e6

Browse files
authored
Merge pull request #13704 from DougGregor/runtime-foreign-class-metadata
[Runtime] Improvements to foreign class metadata
2 parents b6ecf9c + 12a774a commit 63d98e6

File tree

10 files changed

+298
-75
lines changed

10 files changed

+298
-75
lines changed

docs/ABI/TypeMetadata.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,19 @@ parameter vector contains witness tables for those protocols, as if laid out::
273273
AnsibleWitnessTable *U_Ansible;
274274
};
275275

276+
Foreign Class Metadata
277+
~~~~~~~~~~~~~~~~~~~~~~
278+
279+
Foreign class metadata describes "foreign" class types, which support Swift
280+
reference counting but are otherwise opaque to the Swift runtime.
281+
282+
- The `nominal type descriptor`_ for the most-derived class type is stored at
283+
**offset 0**.
284+
- The **super pointer** pointing to the metadata record for the superclass is
285+
stored at **offset 1**. If the class is a root class, it is null.
286+
- Three **pointer-sized fields**, starting at **offset 2**, are reserved for
287+
future use.
288+
276289
Nominal Type Descriptor
277290
~~~~~~~~~~~~~~~~~~~~~~~
278291

include/swift/Runtime/Metadata.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,7 @@ template <typename Runtime> struct TargetClassMetadata;
729729
template <typename Runtime> struct TargetStructMetadata;
730730
template <typename Runtime> struct TargetOpaqueMetadata;
731731
template <typename Runtime> struct TargetValueMetadata;
732+
template <typename Runtime> struct TargetForeignClassMetadata;
732733

733734
// FIXME: https://bugs.swift.org/browse/SR-1155
734735
#pragma clang diagnostic push
@@ -907,6 +908,8 @@ struct TargetMetadata {
907908
return static_cast<const TargetValueMetadata<Runtime> *>(this)
908909
->Description;
909910
case MetadataKind::ForeignClass:
911+
return static_cast<const TargetForeignClassMetadata<Runtime> *>(this)
912+
->Description;
910913
case MetadataKind::Opaque:
911914
case MetadataKind::Tuple:
912915
case MetadataKind::Function:
@@ -1812,9 +1815,12 @@ struct TargetForeignClassMetadata
18121815
: public TargetForeignTypeMetadata<Runtime> {
18131816
using StoredPointer = typename Runtime::StoredPointer;
18141817

1818+
/// An out-of-line description of the type.
1819+
const TargetNominalTypeDescriptor<Runtime> *Description;
1820+
18151821
/// The superclass of the foreign class, if any.
18161822
ConstTargetMetadataPointer<Runtime, swift::TargetForeignClassMetadata>
1817-
SuperClass;
1823+
SuperClass;
18181824

18191825
/// Reserved space. For now, these should be zero-initialized.
18201826
StoredPointer Reserved[3];
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//===-- ForeignClassMetadataVisitor.h - foreign class metadata -*- C++ --*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// A CRTP class useful for laying out foreign class metadata.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_IRGEN_FOREIGNCLASSMETADATAVISITOR_H
18+
#define SWIFT_IRGEN_FOREIGNCLASSMETADATAVISITOR_H
19+
20+
#include "NominalMetadataVisitor.h"
21+
22+
namespace swift {
23+
namespace irgen {
24+
25+
/// A CRTP layout class for foreign class metadata.
26+
template <class Impl>
27+
class ForeignClassMetadataVisitor
28+
: public NominalMetadataVisitor<Impl> {
29+
using super = NominalMetadataVisitor<Impl>;
30+
protected:
31+
ClassDecl *Target;
32+
using super::asImpl;
33+
public:
34+
ForeignClassMetadataVisitor(IRGenModule &IGM, ClassDecl *target)
35+
: super(IGM), Target(target) {}
36+
37+
void layout() {
38+
super::layout();
39+
asImpl().addNominalTypeDescriptor();
40+
asImpl().noteStartOfSuperClass();
41+
asImpl().addSuperClass();
42+
asImpl().addReservedWord();
43+
asImpl().addReservedWord();
44+
asImpl().addReservedWord();
45+
}
46+
47+
bool requiresInitializationFunction() {
48+
return Target->getSuperclassDecl() &&
49+
Target->getSuperclassDecl()->isForeign();
50+
}
51+
52+
CanType getTargetType() const {
53+
return Target->getDeclaredType()->getCanonicalType();
54+
}
55+
};
56+
57+
/// An "implementation" of ForeignClassMetadataVisitor that just scans through
58+
/// the metadata layout, maintaining the offset of the next field.
59+
template <class Impl>
60+
class ForeignClassMetadataScanner : public ForeignClassMetadataVisitor<Impl> {
61+
typedef ForeignClassMetadataVisitor<Impl> super;
62+
protected:
63+
Size NextOffset = Size(0);
64+
65+
ForeignClassMetadataScanner(IRGenModule &IGM, ClassDecl *target)
66+
: super(IGM, target) {}
67+
68+
public:
69+
void addMetadataFlags() { addPointer(); }
70+
void addValueWitnessTable() { addPointer(); }
71+
void addNominalTypeDescriptor() { addPointer(); }
72+
void addSuperClass() { addPointer(); }
73+
void addReservedWord() { addPointer(); }
74+
75+
private:
76+
void addPointer() {
77+
NextOffset += super::IGM.getPointerSize();
78+
}
79+
};
80+
81+
} // end namespace irgen
82+
} // end namespace swift
83+
84+
#endif // SWIFT_IRGEN_FOREIGNCLASSMETADATAVISITOR_H

lib/IRGen/GenKeyPath.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -903,11 +903,11 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern,
903903
} else {
904904
idKind = KeyPathComponentHeader::VTableOffset;
905905
auto dc = declRef.getDecl()->getDeclContext();
906-
if (isa<ClassDecl>(dc)) {
906+
if (isa<ClassDecl>(dc) && !cast<ClassDecl>(dc)->isForeign()) {
907907
auto overridden = declRef.getOverriddenVTableEntry();
908908
auto declaringClass =
909909
cast<ClassDecl>(overridden.getDecl()->getDeclContext());
910-
auto &metadataLayout = getMetadataLayout(declaringClass);
910+
auto &metadataLayout = getClassMetadataLayout(declaringClass);
911911
// FIXME: Resilience. We don't want vtable layout to be ABI, so this
912912
// should be encoded as a reference to the method dispatch thunk
913913
// instead.

lib/IRGen/GenMeta.cpp

Lines changed: 68 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "ConstantBuilder.h"
4242
#include "EnumMetadataVisitor.h"
4343
#include "FixedTypeInfo.h"
44+
#include "ForeignClassMetadataVisitor.h"
4445
#include "GenArchetype.h"
4546
#include "GenClass.h"
4647
#include "GenDecl.h"
@@ -296,18 +297,24 @@ llvm::Value *irgen::emitObjCHeapMetadataRef(IRGenFunction &IGF,
296297
}
297298

298299
/// Emit a reference to the type metadata for a foreign type.
299-
static llvm::Value *emitForeignTypeMetadataRef(IRGenFunction &IGF,
300-
CanType type) {
301-
llvm::Value *candidate = IGF.IGM.getAddrOfForeignTypeMetadataCandidate(type);
300+
static llvm::Value *uniqueForeignTypeMetadataRef(IRGenFunction &IGF,
301+
llvm::Value *candidate) {
302302
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetForeignTypeMetadataFn(),
303-
candidate);
303+
candidate);
304304
call->addAttribute(llvm::AttributeList::FunctionIndex,
305305
llvm::Attribute::NoUnwind);
306306
call->addAttribute(llvm::AttributeList::FunctionIndex,
307307
llvm::Attribute::ReadNone);
308308
return call;
309309
}
310310

311+
/// Emit a reference to the type metadata for a foreign type.
312+
static llvm::Value *emitForeignTypeMetadataRef(IRGenFunction &IGF,
313+
CanType type) {
314+
llvm::Value *candidate = IGF.IGM.getAddrOfForeignTypeMetadataCandidate(type);
315+
return uniqueForeignTypeMetadataRef(IGF, candidate);
316+
}
317+
311318
/// Returns a metadata reference for a nominal type.
312319
///
313320
/// This is only valid in a couple of special cases:
@@ -2189,11 +2196,13 @@ namespace {
21892196
// GenericParameterDescriptorFlags Flags;
21902197
GenericParameterDescriptorFlags flags;
21912198
if (auto *cd = dyn_cast<ClassDecl>(ntd)) {
2192-
auto &layout = IGM.getMetadataLayout(cd);
2193-
if (layout.getVTableSize() > 0)
2194-
flags = flags.withHasVTable(true);
2195-
if (layout.hasResilientSuperclass())
2196-
flags = flags.withHasResilientSuperclass(true);
2199+
if (!cd->isForeign()) {
2200+
auto &layout = IGM.getClassMetadataLayout(cd);
2201+
if (layout.getVTableSize() > 0)
2202+
flags = flags.withHasVTable(true);
2203+
if (layout.hasResilientSuperclass())
2204+
flags = flags.withHasResilientSuperclass(true);
2205+
}
21972206
}
21982207

21992208
// Calculate the number of generic parameters at each nesting depth.
@@ -2428,7 +2437,13 @@ namespace {
24282437
ClassDecl *c)
24292438
: super(IGM), Target(c)
24302439
{
2431-
auto &layout = IGM.getMetadataLayout(Target);
2440+
if (Target->isForeign()) {
2441+
VTable = nullptr;
2442+
VTableSize = 0;
2443+
return;
2444+
}
2445+
2446+
auto &layout = IGM.getClassMetadataLayout(Target);
24322447

24332448
VTable = IGM.getSILModule().lookUpVTable(Target);
24342449
VTableSize = layout.getVTableSize();
@@ -2834,7 +2849,7 @@ namespace {
28342849
// fill indexes are word-indexed.
28352850
auto *metadataWords = IGF.Builder.CreateBitCast(metadataValue, IGM.Int8PtrPtrTy);
28362851

2837-
auto genericReqtOffset = IGM.getMetadataLayout(Target)
2852+
auto genericReqtOffset = IGM.getNominalMetadataLayout(Target)
28382853
.getGenericRequirementsOffset(IGF);
28392854

28402855
for (auto &fillOp : FillOps) {
@@ -3145,7 +3160,7 @@ namespace {
31453160
auto fn = entry.Method;
31463161

31473162
auto *classDecl = cast<ClassDecl>(fn.getDecl()->getDeclContext());
3148-
auto &layout = IGM.getMetadataLayout(classDecl);
3163+
auto &layout = IGM.getClassMetadataLayout(classDecl);
31493164

31503165
auto offset = layout.getMethodInfo(IGF, fn).getOffset();
31513166

@@ -3493,7 +3508,7 @@ namespace {
34933508
if (!HasResilientSuperclass)
34943509
return;
34953510

3496-
auto &layout = IGM.getMetadataLayout(Target);
3511+
auto &layout = IGM.getClassMetadataLayout(Target);
34973512

34983513
// Load the size of the superclass metadata.
34993514
Address metadataAsBytes(
@@ -3747,7 +3762,7 @@ namespace {
37473762
if (doesClassMetadataRequireDynamicInitialization(IGM, Target)) {
37483763
auto templateSize = IGM.getSize(Size(B.getNextOffsetFromGlobal()));
37493764
auto numImmediateMembers = IGM.getSize(
3750-
Size(IGM.getMetadataLayout(Target).getNumImmediateMembers()));
3765+
Size(IGM.getClassMetadataLayout(Target).getNumImmediateMembers()));
37513766
metadata = IGF.Builder.CreateCall(IGF.IGM.getRelocateClassMetadataFn(),
37523767
{metadata, templateSize,
37533768
numImmediateMembers});
@@ -3838,7 +3853,7 @@ namespace {
38383853
}
38393854

38403855
auto numImmediateMembers =
3841-
IGM.getSize(Size(IGM.getMetadataLayout(Target).getNumImmediateMembers()));
3856+
IGM.getSize(Size(IGM.getClassMetadataLayout(Target).getNumImmediateMembers()));
38423857

38433858
return IGF.Builder.CreateCall(IGM.getAllocateGenericClassMetadataFn(),
38443859
{metadataPattern, arguments, superMetadata,
@@ -4230,7 +4245,7 @@ std::pair<llvm::Value *, llvm::Value *>
42304245
irgen::emitClassResilientInstanceSizeAndAlignMask(IRGenFunction &IGF,
42314246
ClassDecl *theClass,
42324247
llvm::Value *metadata) {
4233-
auto &layout = IGF.IGM.getMetadataLayout(theClass);
4248+
auto &layout = IGF.IGM.getClassMetadataLayout(theClass);
42344249

42354250
Address metadataAsBytes(IGF.Builder.CreateBitCast(metadata, IGF.IGM.Int8PtrTy),
42364251
IGF.IGM.getPointerAlignment());
@@ -4487,7 +4502,7 @@ FunctionPointer irgen::emitVirtualMethodValue(IRGenFunction &IGF,
44874502
auto declaringClass = cast<ClassDecl>(overridden.getDecl()->getDeclContext());
44884503

44894504
auto methodInfo =
4490-
IGF.IGM.getMetadataLayout(declaringClass).getMethodInfo(IGF, overridden);
4505+
IGF.IGM.getClassMetadataLayout(declaringClass).getMethodInfo(IGF, overridden);
44914506
auto offset = methodInfo.getOffset();
44924507

44934508
auto slot = IGF.emitAddressAtOffset(metadata, offset,
@@ -4887,36 +4902,6 @@ llvm::Value *IRGenFunction::emitObjCSelectorRefLoad(StringRef selector) {
48874902
//===----------------------------------------------------------------------===//
48884903

48894904
namespace {
4890-
/// A CRTP layout class for foreign class metadata.
4891-
template <class Impl>
4892-
class ForeignClassMetadataVisitor
4893-
: public NominalMetadataVisitor<Impl> {
4894-
using super = NominalMetadataVisitor<Impl>;
4895-
protected:
4896-
ClassDecl *Target;
4897-
using super::asImpl;
4898-
public:
4899-
ForeignClassMetadataVisitor(IRGenModule &IGM, ClassDecl *target)
4900-
: super(IGM), Target(target) {}
4901-
4902-
void layout() {
4903-
super::layout();
4904-
asImpl().addSuperClass();
4905-
asImpl().addReservedWord();
4906-
asImpl().addReservedWord();
4907-
asImpl().addReservedWord();
4908-
}
4909-
4910-
bool requiresInitializationFunction() {
4911-
// TODO: superclasses?
4912-
return false;
4913-
}
4914-
4915-
CanType getTargetType() const {
4916-
return Target->getDeclaredType()->getCanonicalType();
4917-
}
4918-
};
4919-
49204905
/// An adapter that turns a metadata layout class into a foreign metadata
49214906
/// layout class.
49224907
///
@@ -5033,8 +5018,23 @@ namespace {
50335018
: ForeignMetadataBuilderBase(IGM, target, B) {}
50345019

50355020
void emitInitialization(IRGenFunction &IGF, llvm::Value *metadata) {
5036-
// TODO: superclasses?
5037-
llvm_unreachable("no supported forms of initialization");
5021+
// Dig out the address of the superclass field.
5022+
auto &layout = IGF.IGM.getForeignMetadataLayout(Target);
5023+
Address metadataWords(IGF.Builder.CreateBitCast(metadata,
5024+
IGM.Int8PtrPtrTy),
5025+
IGM.getPointerAlignment());
5026+
auto superclassField =
5027+
createPointerSizedGEP(IGF, metadataWords,
5028+
layout.getSuperClassOffset().getStaticOffset());
5029+
superclassField =
5030+
IGF.Builder.CreateBitCast(
5031+
superclassField,
5032+
llvm::PointerType::get(IGM.TypeMetadataPtrTy, 0));
5033+
5034+
// Unique the superclass field and write it back.
5035+
auto superclass = IGF.Builder.CreateLoad(superclassField);
5036+
auto uniquedSuperclass = uniqueForeignTypeMetadataRef(IGF, superclass);
5037+
IGF.Builder.CreateStore(uniquedSuperclass, superclassField);
50385038
}
50395039

50405040
// Visitor methods.
@@ -5053,9 +5053,26 @@ namespace {
50535053
B.addInt(IGM.MetadataKindTy, (unsigned) MetadataKind::ForeignClass);
50545054
}
50555055

5056+
void addNominalTypeDescriptor() {
5057+
auto descriptor = ClassNominalTypeDescriptorBuilder(this->IGM, Target).emit();
5058+
B.add(descriptor);
5059+
}
5060+
5061+
void noteStartOfSuperClass() { }
5062+
50565063
void addSuperClass() {
5057-
// TODO: superclasses
5058-
B.addNullPointer(IGM.TypeMetadataPtrTy);
5064+
auto superclassDecl = Target->getSuperclassDecl();
5065+
if (!superclassDecl || !superclassDecl->isForeign()) {
5066+
B.addNullPointer(IGM.TypeMetadataPtrTy);
5067+
return;
5068+
}
5069+
5070+
auto superclassType =
5071+
superclassDecl->swift::TypeDecl::getDeclaredInterfaceType()
5072+
->getCanonicalType();
5073+
auto superclass =
5074+
IGM.getAddrOfForeignTypeMetadataCandidate(superclassType);
5075+
B.add(superclass);
50595076
}
50605077

50615078
void addReservedWord() {

lib/IRGen/IRGenModule.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ namespace irgen {
110110
class EnumMetadataLayout;
111111
class ExplosionSchema;
112112
class FixedTypeInfo;
113+
class ForeignClassMetadataLayout;
113114
class ForeignFunctionInfo;
114115
class FormalType;
115116
class HeapLayout;
@@ -667,10 +668,12 @@ class IRGenModule {
667668

668669
SpareBitVector getSpareBitsForType(llvm::Type *scalarTy, Size size);
669670

670-
NominalMetadataLayout &getMetadataLayout(NominalTypeDecl *decl);
671+
MetadataLayout &getMetadataLayout(NominalTypeDecl *decl);
672+
NominalMetadataLayout &getNominalMetadataLayout(NominalTypeDecl *decl);
671673
StructMetadataLayout &getMetadataLayout(StructDecl *decl);
672-
ClassMetadataLayout &getMetadataLayout(ClassDecl *decl);
674+
ClassMetadataLayout &getClassMetadataLayout(ClassDecl *decl);
673675
EnumMetadataLayout &getMetadataLayout(EnumDecl *decl);
676+
ForeignClassMetadataLayout &getForeignMetadataLayout(ClassDecl *decl);
674677

675678
private:
676679
TypeConverter &Types;

0 commit comments

Comments
 (0)