Skip to content

Commit cc2ee16

Browse files
committed
[ABI] Use generic environment to handle mangled generic keypath types.
Always use mangled type names to represent type metadata in keypath patterns. For generic types, use the generic environment to pull substituted types from the instantiation arguments. Finishes the type metadata part of rdar://problem/38038799.
1 parent b206bd6 commit cc2ee16

File tree

8 files changed

+145
-75
lines changed

8 files changed

+145
-75
lines changed

docs/ABI/Mangling.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ The following symbolic reference kinds are currently implemented:
9090
dependent-associated-conformance ::= '\x05' .{4} // Reference points directly to associated conformance descriptor (NOT IMPLEMENTED)
9191
dependent-associated-conformance ::= '\x06' .{4} // Reference points indirectly to associated conformance descriptor (NOT IMPLEMENTED)
9292

93-
associated-conformance-acceess-function ::= '\x07' .{4} // Reference points directly to associated conformance access function relative to the protocol
94-
associated-conformance-acceess-function ::= '\x08' .{4} // Reference points directly to associated conformance access function relative to the conforming type
95-
keypath-metadata-access-function ::= '\x09' {.4} // Reference points directly to keypath type metadata access function
93+
associated-conformance-access-function ::= '\x07' .{4} // Reference points directly to associated conformance access function relative to the protocol
94+
associated-conformance-access-function ::= '\x08' .{4} // Reference points directly to associated conformance access function relative to the conforming type
95+
keypath-metadata-access-function ::= '\x09' {.4} // Reference points directly to keypath conformance access function
9696

9797
Globals
9898
~~~~~~~

lib/IRGen/GenKeyPath.cpp

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -707,34 +707,11 @@ emitMetadataGeneratorForKeyPath(IRGenModule &IGM,
707707
CanType type,
708708
GenericEnvironment *genericEnv,
709709
ArrayRef<GenericRequirement> requirements) {
710-
// If we have a non-dependent type, use a normal mangled type name.
711-
if (!type->hasTypeParameter()) {
712-
auto constant = IGM.getTypeRef(type, MangledTypeRefRole::Metadata);
713-
auto bitConstant = llvm::ConstantInt::get(IGM.IntPtrTy, 1);
714-
return llvm::ConstantExpr::getGetElementPtr(nullptr, constant, bitConstant);
715-
}
716-
717-
// Otherwise, create an accessor.
718-
CanGenericSignature genericSig;
719-
if (genericEnv)
720-
genericSig = genericEnv->getGenericSignature()->getCanonicalSignature();
721-
722-
IRGenMangler mangler;
723-
std::string symbolName =
724-
mangler.mangleSymbolNameForKeyPathMetadata(
725-
"keypath_get_type", genericSig, type,
726-
ProtocolConformanceRef::forInvalid());
727-
728-
// TODO: Use the standard metadata accessor when there are no arguments
729-
// and the metadata accessor is defined.
730-
return emitGeneratorForKeyPath(IGM, symbolName, type,
731-
IGM.TypeMetadataPtrTy,
732-
genericEnv, requirements,
733-
[&](IRGenFunction &IGF, CanType substType) {
734-
auto ret = IGF.emitTypeMetadataRef(substType);
735-
IGF.Builder.CreateRet(ret);
736-
});
737-
};
710+
// Produce a mangled name for the type.
711+
auto constant = IGM.getTypeRef(type, MangledTypeRefRole::Metadata);
712+
auto bitConstant = llvm::ConstantInt::get(IGM.IntPtrTy, 1);
713+
return llvm::ConstantExpr::getGetElementPtr(nullptr, constant, bitConstant);
714+
}
738715

739716
static llvm::Constant *
740717
emitWitnessTableGeneratorForKeyPath(IRGenModule &IGM,

stdlib/public/core/KeyPath.swift

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -723,9 +723,9 @@ internal final class NonmutatingWritebackBuffer<CurValue, NewValue> {
723723
}
724724

725725
internal typealias KeyPathComputedArgumentLayoutFn = @convention(thin)
726-
(_ patternArguments: UnsafeRawPointer) -> (size: Int, alignmentMask: Int)
726+
(_ patternArguments: UnsafeRawPointer?) -> (size: Int, alignmentMask: Int)
727727
internal typealias KeyPathComputedArgumentInitializerFn = @convention(thin)
728-
(_ patternArguments: UnsafeRawPointer,
728+
(_ patternArguments: UnsafeRawPointer?,
729729
_ instanceArguments: UnsafeMutableRawPointer) -> ()
730730

731731
internal enum KeyPathComputedIDKind {
@@ -2397,8 +2397,10 @@ internal func _getSymbolicMangledNameLength(_ base: UnsafeRawPointer) -> Int {
23972397
}
23982398

23992399
// Resolve the given generic argument reference to a generic argument.
2400-
internal func _resolveKeyPathGenericArgReference(_ reference: UnsafeRawPointer,
2401-
arguments: UnsafeRawPointer)
2400+
internal func _resolveKeyPathGenericArgReference(
2401+
_ reference: UnsafeRawPointer,
2402+
genericEnvironment: UnsafeRawPointer?,
2403+
arguments: UnsafeRawPointer?)
24022404
-> UnsafeRawPointer {
24032405
// If the low bit is clear, it's a direct reference to the argument.
24042406
if (UInt(bitPattern: reference) & 0x01 == 0) {
@@ -2412,7 +2414,7 @@ internal func _resolveKeyPathGenericArgReference(_ reference: UnsafeRawPointer,
24122414
let first = referenceStart.load(as: UInt8.self)
24132415
if first == 255 && reference.load(as: UInt8.self) == 9 {
24142416
typealias MetadataAccessor =
2415-
@convention(c) (UnsafeRawPointer) -> UnsafeRawPointer
2417+
@convention(c) (UnsafeRawPointer?) -> UnsafeRawPointer
24162418

24172419
// Unaligned load of the offset.
24182420
let pointerReference = reference + 1
@@ -2428,7 +2430,10 @@ internal func _resolveKeyPathGenericArgReference(_ reference: UnsafeRawPointer,
24282430
let namePtr = referenceStart.bindMemory(to: UInt8.self,
24292431
capacity: nameLength + 1)
24302432
// FIXME: Could extract this information from the mangled name.
2431-
guard let result = _getTypeByMangledName(namePtr, UInt(nameLength))
2433+
guard let result =
2434+
_getTypeByMangledName(namePtr, UInt(nameLength),
2435+
genericEnvironment: genericEnvironment,
2436+
genericArguments: arguments)
24322437
else {
24332438
let nameStr = String._fromUTF8Repairing(
24342439
UnsafeBufferPointer(start: namePtr, count: nameLength)
@@ -2441,11 +2446,16 @@ internal func _resolveKeyPathGenericArgReference(_ reference: UnsafeRawPointer,
24412446
}
24422447

24432448
// Resolve the given metadata reference to (type) metadata.
2444-
internal func _resolveKeyPathMetadataReference(_ reference: UnsafeRawPointer,
2445-
arguments: UnsafeRawPointer)
2449+
internal func _resolveKeyPathMetadataReference(
2450+
_ reference: UnsafeRawPointer,
2451+
genericEnvironment: UnsafeRawPointer?,
2452+
arguments: UnsafeRawPointer?)
24462453
-> Any.Type {
24472454
return unsafeBitCast(
2448-
_resolveKeyPathGenericArgReference(reference, arguments: arguments),
2455+
_resolveKeyPathGenericArgReference(
2456+
reference,
2457+
genericEnvironment: genericEnvironment,
2458+
arguments: arguments),
24492459
to: Any.Type.self)
24502460
}
24512461

@@ -2797,9 +2807,10 @@ internal struct GetKeyPathClassAndInstanceSizeFromPattern
27972807
var didChain: Bool = false
27982808
var root: Any.Type!
27992809
var leaf: Any.Type!
2800-
let patternArgs: UnsafeRawPointer
2810+
var genericEnvironment: UnsafeRawPointer?
2811+
let patternArgs: UnsafeRawPointer?
28012812

2802-
init(patternArgs: UnsafeRawPointer) {
2813+
init(patternArgs: UnsafeRawPointer?) {
28032814
self.patternArgs = patternArgs
28042815
}
28052816

@@ -2811,12 +2822,17 @@ internal struct GetKeyPathClassAndInstanceSizeFromPattern
28112822
rootMetadataRef: MetadataReference,
28122823
leafMetadataRef: MetadataReference,
28132824
kvcCompatibilityString: UnsafeRawPointer?) {
2825+
self.genericEnvironment = genericEnvironment
28142826
// Get the root and leaf type metadata so we can form the class type
28152827
// for the entire key path.
2816-
root = _resolveKeyPathMetadataReference(rootMetadataRef,
2817-
arguments: patternArgs)
2818-
leaf = _resolveKeyPathMetadataReference(leafMetadataRef,
2819-
arguments: patternArgs)
2828+
root = _resolveKeyPathMetadataReference(
2829+
rootMetadataRef,
2830+
genericEnvironment: genericEnvironment,
2831+
arguments: patternArgs)
2832+
leaf = _resolveKeyPathMetadataReference(
2833+
leafMetadataRef,
2834+
genericEnvironment: genericEnvironment,
2835+
arguments: patternArgs)
28202836
}
28212837

28222838
mutating func visitStoredComponent(kind: KeyPathStructOrClass,
@@ -2997,11 +3013,12 @@ internal func _getKeyPathClassAndInstanceSizeFromPattern(
29973013

29983014
internal struct InstantiateKeyPathBuffer : KeyPathPatternVisitor {
29993015
var destData: UnsafeMutableRawBufferPointer
3000-
let patternArgs: UnsafeRawPointer
3016+
var genericEnvironment: UnsafeRawPointer?
3017+
let patternArgs: UnsafeRawPointer?
30013018
var base: Any.Type
30023019

30033020
init(destData: UnsafeMutableRawBufferPointer,
3004-
patternArgs: UnsafeRawPointer,
3021+
patternArgs: UnsafeRawPointer?,
30053022
root: Any.Type) {
30063023
self.destData = destData
30073024
self.patternArgs = patternArgs
@@ -3044,6 +3061,7 @@ internal struct InstantiateKeyPathBuffer : KeyPathPatternVisitor {
30443061
rootMetadataRef: MetadataReference,
30453062
leafMetadataRef: MetadataReference,
30463063
kvcCompatibilityString: UnsafeRawPointer?) {
3064+
self.genericEnvironment = genericEnvironment
30473065
}
30483066

30493067
mutating func visitStoredComponent(kind: KeyPathStructOrClass,
@@ -3213,8 +3231,10 @@ internal struct InstantiateKeyPathBuffer : KeyPathPatternVisitor {
32133231
let base = externalArgs.baseAddress.unsafelyUnwrapped + i
32143232
let offset = base.pointee
32153233
let metadataRef = UnsafeRawPointer(base) + Int(offset)
3216-
let result = _resolveKeyPathGenericArgReference(metadataRef,
3217-
arguments: patternArgs)
3234+
let result = _resolveKeyPathGenericArgReference(
3235+
metadataRef,
3236+
genericEnvironment: genericEnvironment,
3237+
arguments: patternArgs)
32183238
pushDest(result)
32193239
}
32203240
}
@@ -3238,8 +3258,10 @@ internal struct InstantiateKeyPathBuffer : KeyPathPatternVisitor {
32383258

32393259
mutating func visitIntermediateComponentType(metadataRef: MetadataReference) {
32403260
// Get the metadata for the intermediate type.
3241-
let metadata = _resolveKeyPathMetadataReference(metadataRef,
3242-
arguments: patternArgs)
3261+
let metadata = _resolveKeyPathMetadataReference(
3262+
metadataRef,
3263+
genericEnvironment: genericEnvironment,
3264+
arguments: patternArgs)
32433265
pushDest(metadata)
32443266
base = metadata
32453267
}

stdlib/public/core/Misc.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,16 @@ func _typeByName(_ name: String) -> Any.Type? {
8585
let nameUTF8 = Array(name.utf8)
8686
return nameUTF8.withUnsafeBufferPointer { (nameUTF8) in
8787
return _getTypeByMangledName(nameUTF8.baseAddress!,
88-
UInt(nameUTF8.endIndex))
88+
UInt(nameUTF8.endIndex),
89+
genericEnvironment: nil,
90+
genericArguments: nil)
8991
}
9092
}
9193

9294
@_silgen_name("swift_stdlib_getTypeByMangledName")
9395
internal func _getTypeByMangledName(
9496
_ name: UnsafePointer<UInt8>,
95-
_ nameLength: UInt)
97+
_ nameLength: UInt,
98+
genericEnvironment: UnsafeRawPointer?,
99+
genericArguments: UnsafeRawPointer?)
96100
-> Any.Type?

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,15 +1270,15 @@ TypeInfo swift_getTypeByMangledNameImpl(
12701270

12711271
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
12721272
const Metadata * _Nullable
1273-
swift_stdlib_getTypeByMangledName(const char *typeNameStart,
1274-
size_t typeNameLength) {
1273+
swift_stdlib_getTypeByMangledName(
1274+
const char *typeNameStart,
1275+
size_t typeNameLength,
1276+
const TargetGenericEnvironment<InProcess> *environment,
1277+
const void * const *genericArgs) {
12751278
llvm::StringRef typeName(typeNameStart, typeNameLength);
1276-
auto metadata =
1277-
swift_getTypeByMangledName(
1278-
typeName,
1279-
[](unsigned depth, unsigned index) { return nullptr; },
1280-
[](const Metadata *type, unsigned index) { return nullptr; });
1281-
1279+
SubstGenericParametersFromMetadata substitutions(environment, genericArgs);
1280+
auto metadata = swift_getTypeByMangledName(typeName, substitutions,
1281+
substitutions);
12821282
if (!metadata) return nullptr;
12831283

12841284
return swift_checkMetadataState(MetadataState::Complete, metadata).Value;
@@ -1318,12 +1318,58 @@ buildDescriptorPath(const ContextDescriptor *context) const {
13181318
return numKeyGenericParamsInParent + numKeyGenericParamsHere;
13191319
}
13201320

1321+
/// Builds a path from the generic environment.
1322+
unsigned SubstGenericParametersFromMetadata::
1323+
buildEnvironmentPath(
1324+
const TargetGenericEnvironment<InProcess> *environment) const {
1325+
unsigned totalParamCount = 0;
1326+
unsigned totalKeyParamCount = 0;
1327+
auto genericParams = environment->getGenericParameters();
1328+
for (unsigned numLocalParams : environment->getGenericParameterCounts()) {
1329+
// Get the local generic parameters.
1330+
auto localGenericParams = genericParams.slice(0, numLocalParams);
1331+
genericParams = genericParams.slice(numLocalParams);
1332+
1333+
// Count the parameters.
1334+
unsigned numKeyGenericParamsInParent = totalKeyParamCount;
1335+
unsigned numKeyGenericParamsHere = 0;
1336+
bool hasNonKeyGenericParams = false;
1337+
for (const auto &genericParam : localGenericParams) {
1338+
if (genericParam.hasKeyArgument())
1339+
++numKeyGenericParamsHere;
1340+
else
1341+
hasNonKeyGenericParams = true;
1342+
}
1343+
1344+
// Update totals.
1345+
totalParamCount += numLocalParams;
1346+
totalKeyParamCount += numKeyGenericParamsHere;
1347+
1348+
// Add to the descriptor path.
1349+
descriptorPath.push_back(PathElement{localGenericParams,
1350+
totalParamCount,
1351+
numKeyGenericParamsInParent,
1352+
numKeyGenericParamsHere,
1353+
hasNonKeyGenericParams});
1354+
}
1355+
1356+
return totalKeyParamCount;
1357+
}
1358+
13211359
void SubstGenericParametersFromMetadata::setup() const {
1322-
if (!descriptorPath.empty() || !base)
1360+
if (!descriptorPath.empty())
13231361
return;
13241362

1325-
auto descriptor = base->getTypeContextDescriptor();
1326-
numKeyGenericParameters = buildDescriptorPath(descriptor);
1363+
if (sourceIsMetadata && base) {
1364+
auto descriptor = base->getTypeContextDescriptor();
1365+
numKeyGenericParameters = buildDescriptorPath(descriptor);
1366+
return;
1367+
}
1368+
1369+
if (!sourceIsMetadata && environment) {
1370+
numKeyGenericParameters = buildEnvironmentPath(environment);
1371+
return;
1372+
}
13271373
}
13281374

13291375
const Metadata *

stdlib/public/runtime/Private.h

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,13 @@ class TypeInfo {
241241
/// Use with \c _getTypeByMangledName to decode potentially-generic
242242
/// types.
243243
class SWIFT_RUNTIME_LIBRARY_VISIBILITY SubstGenericParametersFromMetadata {
244-
const Metadata *base;
244+
/// Whether the source is metadata (vs. a generic environment);
245+
const bool sourceIsMetadata;
246+
247+
union {
248+
const Metadata *base;
249+
const TargetGenericEnvironment<InProcess> *environment;
250+
};
245251

246252
/// The generic arguments.
247253
const void * const *genericArgs;
@@ -277,16 +283,28 @@ class TypeInfo {
277283
/// the path up to this point.
278284
unsigned buildDescriptorPath(const ContextDescriptor *context) const;
279285

286+
/// Builds a path from the generic environment.
287+
unsigned buildEnvironmentPath(
288+
const TargetGenericEnvironment<InProcess> *environment) const;
289+
280290
// Set up the state we need to compute substitutions.
281291
void setup() const;
282292

283293
public:
284294
/// Produce substitutions entirely from the given metadata.
285295
explicit SubstGenericParametersFromMetadata(const Metadata *base)
286-
: base(base),
296+
: sourceIsMetadata(true), base(base),
287297
genericArgs(base ? (const void * const *)base->getGenericArgs()
288298
: nullptr) { }
289299

300+
/// Produce substitutions from the given instantiation arguments for the
301+
/// given generic environment.
302+
explicit SubstGenericParametersFromMetadata(
303+
const TargetGenericEnvironment<InProcess> *environment,
304+
const void * const *arguments)
305+
: sourceIsMetadata(false), environment(environment),
306+
genericArgs(arguments) { }
307+
290308
const Metadata *operator()(unsigned depth, unsigned index) const;
291309
const WitnessTable *operator()(const Metadata *type, unsigned index) const;
292310
};

test/IRGen/keypaths.sil

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,9 @@ sil_vtable C2 {}
183183
// -- %i: Gen<A>.x
184184
// CHECK: [[KP_I:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
185185
// CHECK-SAME: i32 0
186-
// CHECK-SAME: @"keypath_get_type
187-
// CHECK-SAME: @"keypath_get_type
186+
// CHECK-SAME: @"generic environment l"
187+
// CHECK-SAME: @"symbolic 8keypaths3GenVyxxG"
188+
// CHECK-SAME: @"symbolic x"
188189
// -- size 8
189190
// CHECK-SAME: i32 8,
190191
// -- struct with runtime-resolved offset, mutable
@@ -196,8 +197,8 @@ sil_vtable C2 {}
196197
// CHECK: [[KP_J:@keypath(\..*)?]] = private global <{ {{.*}} }> <{
197198
// CHECK-SAME: i32 0
198199
// CHECK-SAME: @"generic environment l"
199-
// CHECK-SAME: @"keypath_get_type
200-
// CHECK-SAME: @"keypath_get_type
200+
// CHECK-SAME: @"symbolic 8keypaths3GenVyxxG"
201+
// CHECK-SAME: @"symbolic x"
201202
// -- size 8
202203
// CHECK-SAME: i32 8,
203204
// -- struct with runtime-resolved offset
@@ -210,14 +211,14 @@ sil_vtable C2 {}
210211

211212
// -- %t
212213
// CHECK: [[KP_T:@keypath(\..*)?]] = private global <{ {{.*}} }> <{ {{.*}} i32 1, {{.*}} @"got.$s8keypaths1GV1xxvpMV"
213-
// CHECK-SAME: @"keypath_get_type
214+
// CHECK-SAME: @"symbolic x"
214215
// -- computed get-only property, identified by indirect pointer
215216
// CHECK-SAME: <i32 0x0208_0002>
216217

217218
// -- %u
218219
// CHECK: [[KP_U:@keypath(\..*)?]] = private global <{ {{.*}} }> <{ {{.*}} i32 3, {{.*}} @"got.$s8keypaths1GVyxqd__cSHRd__luipMV"
219-
// CHECK-SAME: @"keypath_get_type
220-
// CHECK-SAME: @"keypath_get_type
220+
// CHECK-SAME: @"symbolic q_"
221+
// CHECK-SAME: @"symbolic x"
221222
// CHECK-SAME: @"keypath_get_witness_table
222223
// -- computed get-only property, identified by indirect pointer
223224
// CHECK-SAME: <i32 0x0208_0002>

0 commit comments

Comments
 (0)