Skip to content

Commit e6a154d

Browse files
committed
Support for dynamic specialization of generic types
This extends <b5880f3> with the infrastructure necessary to dynamically instantiate generic types by name. In order to do so it extends GenericParameterDescriptor::Parameter with a list of ProtocolDescriptors containing associated type requirements. NB: no support for secondary archetypes yet. NB: this is "plumbing" as we have not defined a Swift API yet to lookup anything beyond a top-level non-generic class. The test suite uses private API taking a mangled type name in order to exercise this new code.
1 parent 8706961 commit e6a154d

File tree

12 files changed

+296
-54
lines changed

12 files changed

+296
-54
lines changed

docs/ABI.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -647,8 +647,14 @@ layout is as follows:
647647
* For each type parameter **n**, the following fields are stored:
648648

649649
+ The **number of witnesses** for the type parameter is stored at
650-
**offset 10+n**. This is the number of witness table pointers that are
651-
stored for the type parameter in the generic parameter vector.
650+
**offset 10+p**. This is the number of witness table pointers that are
651+
stored for the type parameter in the generic parameter vector. The
652+
inner offset **p** is advanced by **1+w** for each parameter, where
653+
**w** is the number of witness tables for the type. This accounts for
654+
the variable length protocol descriptor references below.
655+
+ For each type parameter with protocol contraints that require a witness
656+
table, **n** references to the **protocol descriptors**. References are
657+
stored as an offset relative to the start of the nominal type descriptor.
652658

653659
Note that there is no nominal type descriptor for protocols or protocol types.
654660
See the `protocol descriptor`_ description below.

include/swift/Runtime/Metadata.h

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,8 @@ struct HeapMetadata : Metadata {
11761176
constexpr HeapMetadata(const Metadata &base) : Metadata(base) {}
11771177
};
11781178

1179+
struct ProtocolDescriptor;
1180+
11791181
/// Header for a generic parameter descriptor. This is a variable-sized
11801182
/// structure that describes how to find and parse a generic parameter vector
11811183
/// within the type metadata for an instance of a nominal type.
@@ -1199,15 +1201,33 @@ struct GenericParameterDescriptor {
11991201
struct Parameter {
12001202
/// The number of protocol witness tables required by this type parameter.
12011203
uint32_t NumWitnessTables;
1202-
1203-
// TODO: This is the bare minimum to be able to parse an opaque generic
1204-
// parameter vector. Should we include additional info, such as the
1205-
// required protocols?
1204+
/// The protocols required by this type parameter. If NumWitnessTables is
1205+
/// zero, this is absent.
1206+
RelativeIndirectablePointer<ProtocolDescriptor> Protocols[1];
12061207
};
12071208

12081209
/// The parameter descriptors are in a tail-emplaced array of NumParams
1209-
/// elements.
1210+
/// elements. Because Parameters are variable length, use getParameterAt()
1211+
/// to access them.
12101212
Parameter Parameters[1];
1213+
1214+
const struct Parameter *getParameterAt(uint32_t index) const {
1215+
const struct Parameter *param = Parameters;
1216+
1217+
for (uint32_t i = 0; i < NumParams; ++i) {
1218+
if (i == index)
1219+
return param;
1220+
1221+
auto offset = sizeof(struct Parameter)
1222+
- offsetof(struct Parameter, Protocols);
1223+
offset += param->NumWitnessTables *
1224+
sizeof(RelativeIndirectablePointer<ProtocolDescriptor>);
1225+
auto bytes = reinterpret_cast<const uint8_t *>(param) + offset;
1226+
param = reinterpret_cast<const Parameter *>(bytes);
1227+
}
1228+
1229+
return nullptr;
1230+
}
12111231
};
12121232

12131233
struct ClassTypeDescriptor;
@@ -1858,8 +1878,6 @@ struct TupleTypeMetadata : public Metadata {
18581878
/// The standard metadata for the empty tuple type.
18591879
extern "C" const FullMetadata<TupleTypeMetadata> _TMT_;
18601880

1861-
struct ProtocolDescriptor;
1862-
18631881
/// An array of protocol descriptors with a header and tail-allocated elements.
18641882
struct ProtocolDescriptorList {
18651883
uintptr_t NumProtocols;

lib/IRGen/GenDecl.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2270,8 +2270,6 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType,
22702270
if (!section.empty())
22712271
var->setSection(section);
22722272

2273-
// Keep type metadata around for all types, although the runtime can currently
2274-
// only perform name lookup of non-generic types.
22752273
addRuntimeResolvableType(concreteType);
22762274

22772275
// For metadata patterns, we're done.
@@ -2477,15 +2475,15 @@ IRGenModule::getAddrOfForeignTypeMetadataCandidate(CanType type) {
24772475
return result;
24782476
}
24792477

2480-
/// Return the address of a nominal type descriptor. Right now, this
2481-
/// must always be for purposes of defining it.
2478+
/// Return the address of a nominal type descriptor.
24822479
llvm::Constant *IRGenModule::getAddrOfNominalTypeDescriptor(NominalTypeDecl *D,
24832480
llvm::Type *definitionType) {
2484-
assert(definitionType && "not defining nominal type descriptor?");
24852481
auto entity = LinkEntity::forNominalTypeDescriptor(D);
2486-
return getAddrOfLLVMVariable(entity, getPointerAlignment(),
2487-
definitionType, definitionType,
2488-
DebugTypeInfo());
2482+
DebugTypeInfo DbgTy(D->getDeclaredType(), NominalTypeDescriptorPtrTy,
2483+
getPointerSize(), getPointerAlignment(),
2484+
nullptr);
2485+
return getAddrOfLLVMVariable(entity, getPointerAlignment(), definitionType,
2486+
NominalTypeDescriptorPtrTy, DbgTy);
24892487
}
24902488

24912489
llvm::Constant *IRGenModule::getAddrOfProtocolDescriptor(ProtocolDecl *D,

lib/IRGen/GenMeta.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,6 +2025,31 @@ namespace {
20252025
class NominalTypeDescriptorBuilderBase : public ConstantBuilder<> {
20262026
Impl &asImpl() { return *static_cast<Impl*>(this); }
20272027

2028+
llvm::Constant *getBaseAddress() {
2029+
return IGM.getAddrOfNominalTypeDescriptor(asImpl().getTarget(), nullptr);
2030+
}
2031+
2032+
llvm::Constant *
2033+
emitRelativeReference(std::pair<llvm::Constant *,
2034+
IRGenModule::DirectOrGOT> target) {
2035+
auto targetAddr = llvm::ConstantExpr::getPtrToInt(target.first, IGM.SizeTy);
2036+
auto offset = llvm::ConstantInt::get(IGM.SizeTy, getNextOffset().getValue());
2037+
// This seems incredibly baroque, we should be creating an LLVM struct?
2038+
// not sure how to define one with nested tail-emplaced values
2039+
auto baseAddr = llvm::ConstantExpr::getPtrToInt(getBaseAddress(), IGM.SizeTy);
2040+
auto currentAddr = llvm::ConstantExpr::getAdd(baseAddr, offset);
2041+
auto relativeAddr = llvm::ConstantExpr::getSub(targetAddr, currentAddr);
2042+
2043+
if (IGM.SizeTy != IGM.RelativeAddressTy)
2044+
relativeAddr = llvm::ConstantExpr::getTrunc(relativeAddr,
2045+
IGM.RelativeAddressTy);
2046+
if (target.second == IRGenModule::DirectOrGOT::GOT)
2047+
relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr,
2048+
llvm::ConstantInt::get(IGM.RelativeAddressTy, 1));
2049+
2050+
return relativeAddr;
2051+
}
2052+
20282053
public:
20292054
NominalTypeDescriptorBuilderBase(IRGenModule &IGM) : ConstantBuilder(IGM) {}
20302055

@@ -2098,6 +2123,17 @@ namespace {
20982123
archetype->getConformsTo().end(),
20992124
Lowering::TypeConverter::protocolRequiresWitnessTable);
21002125
addConstantInt32(count);
2126+
2127+
// ProtocolDescriptor *Protocols[NumWitnessTables];
2128+
for (auto *protocol : archetype->getConformsTo()) {
2129+
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protocol))
2130+
continue;
2131+
assert(!protocol->isObjC());
2132+
auto descriptorRef = IGM.getAddrOfLLVMVariableOrGOTEquivalent(
2133+
LinkEntity::forProtocolDescriptor(protocol),
2134+
IGM.getPointerAlignment(), IGM.ProtocolDescriptorStructTy);
2135+
addInt32(emitRelativeReference(descriptorRef));
2136+
}
21012137
}
21022138
// };
21032139
}

lib/IRGen/IRGenModule.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,10 @@ private: \
839839
/// the binary.
840840
void setTrueConstGlobal(llvm::GlobalVariable *var);
841841

842+
std::pair<llvm::Constant *, DirectOrGOT>
843+
getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity, Alignment alignment,
844+
llvm::Type *defaultType);
845+
842846
private:
843847
llvm::Constant *getAddrOfLLVMVariable(LinkEntity entity,
844848
Alignment alignment,
@@ -851,10 +855,6 @@ private: \
851855
llvm::Type *defaultType,
852856
DebugTypeInfo debugType);
853857

854-
std::pair<llvm::Constant *, DirectOrGOT>
855-
getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity, Alignment alignment,
856-
llvm::Type *defaultType);
857-
858858
void emitLazyPrivateDefinitions();
859859
void addRuntimeResolvableType(CanType type);
860860

stdlib/public/runtime/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ if(SWIFT_HOST_VARIANT MATCHES "${SWIFT_DARWIN_VARIANTS}")
2727
set(swift_runtime_objc_sources
2828
ErrorObject.mm
2929
SwiftObject.mm
30-
Remangle.cpp
3130
Reflection.mm)
3231
else()
3332
endif()
@@ -46,6 +45,7 @@ add_swift_library(swiftRuntime IS_STDLIB IS_STDLIB_CORE
4645
Once.cpp
4746
ProtocolConformance.cpp
4847
Reflection.cpp
48+
Remangle.cpp
4949
SwiftObject.cpp
5050
${swift_runtime_objc_sources}
5151
${swift_runtime_leaks_sources}

stdlib/public/runtime/Metadata.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,9 +1474,9 @@ static void _swift_initializeSuperclass(ClassMetadata *theClass,
14741474
if (genericParams.hasGenericParams()) {
14751475
unsigned numParamWords = 0;
14761476
for (unsigned i = 0; i < genericParams.NumParams; ++i) {
1477+
auto param = genericParams.getParameterAt(i);
14771478
// 1 word for the type metadata, and 1 for every protocol witness
1478-
numParamWords +=
1479-
1 + genericParams.Parameters[i].NumWitnessTables;
1479+
numParamWords += 1 + param->NumWitnessTables;
14801480
}
14811481
memcpy(classWords + genericParams.Offset,
14821482
superWords + genericParams.Offset,

0 commit comments

Comments
 (0)