Skip to content

Commit b192ced

Browse files
committed
[Keypaths] Use mangled names to reference type and witness table accessors.
Switch key path metadata over to mangled names for each of the places it refers to either a type metadata accessor or a witness table accessor. For now, the mangled name is a symbolic reference to the existing accessors. Part of rdar://problem/38038799.
1 parent 9334458 commit b192ced

File tree

9 files changed

+274
-119
lines changed

9 files changed

+274
-119
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ The following symbolic reference kinds are currently implemented:
9292

9393
associated-conformance-acceess-function ::= '\x07' .{4} // Reference points directly to associated conformance access function relative to the protocol
9494
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
9596

9697
Globals
9798
~~~~~~~

lib/IRGen/GenKeyPath.cpp

Lines changed: 69 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "GenericRequirement.h"
2929
#include "IRGenDebugInfo.h"
3030
#include "IRGenFunction.h"
31+
#include "IRGenMangler.h"
3132
#include "IRGenModule.h"
3233
#include "MetadataLayout.h"
3334
#include "ProtocolInfo.h"
@@ -649,53 +650,77 @@ getInitializerForComputedComponent(IRGenModule &IGM,
649650
/// protocol conformance metadata record.
650651
/// TODO: It would be much better to emit typeref strings and use runtime
651652
/// demangling here.
652-
static llvm::Function *
653+
static llvm::Constant *
653654
emitGeneratorForKeyPath(IRGenModule &IGM,
654655
StringRef name, CanType type, llvm::Type *returnType,
655656
GenericEnvironment *genericEnv,
656657
ArrayRef<GenericRequirement> requirements,
657658
llvm::function_ref<void(IRGenFunction&,CanType)> emit) {
658-
// TODO: Use the standard metadata accessor when there are no arguments
659-
// and the metadata accessor is defined.
660659

661-
// Build a stub that loads the necessary bindings from the key path's
662-
// argument buffer then fetches the metadata.
663-
auto fnTy = llvm::FunctionType::get(returnType,
664-
{IGM.Int8PtrTy}, /*vararg*/ false);
665-
auto accessorThunk = llvm::Function::Create(fnTy,
666-
llvm::GlobalValue::PrivateLinkage,
667-
name, IGM.getModule());
668-
accessorThunk->setAttributes(IGM.constructInitialAttributes());
669-
{
670-
IRGenFunction IGF(IGM, accessorThunk);
671-
if (IGM.DebugInfo)
672-
IGM.DebugInfo->emitArtificialFunction(IGF, accessorThunk);
673-
674-
if (type->hasTypeParameter()) {
675-
auto bindingsBufPtr = IGF.collectParameters().claimNext();
676-
677-
bindFromGenericRequirementsBuffer(IGF, requirements,
678-
Address(bindingsBufPtr, IGM.getPointerAlignment()),
679-
MetadataState::Complete,
680-
[&](CanType t) {
681-
return genericEnv->mapTypeIntoContext(t)->getCanonicalType();
682-
});
683-
684-
type = genericEnv->mapTypeIntoContext(type)->getCanonicalType();
685-
}
686-
emit(IGF, type);
687-
}
688-
return accessorThunk;
660+
return IGM.getAddrOfStringForMetadataRef(name,
661+
/*shouldSetLowBit=*/true,
662+
[&](ConstantInitBuilder &B) {
663+
// Build a stub that loads the necessary bindings from the key path's
664+
// argument buffer then fetches the metadata.
665+
auto fnTy = llvm::FunctionType::get(returnType,
666+
{IGM.Int8PtrTy}, /*vararg*/ false);
667+
auto accessorThunk =
668+
llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage,
669+
name, IGM.getModule());
670+
accessorThunk->setAttributes(IGM.constructInitialAttributes());
671+
{
672+
IRGenFunction IGF(IGM, accessorThunk);
673+
if (IGM.DebugInfo)
674+
IGM.DebugInfo->emitArtificialFunction(IGF, accessorThunk);
675+
676+
if (type->hasTypeParameter()) {
677+
auto bindingsBufPtr = IGF.collectParameters().claimNext();
678+
679+
bindFromGenericRequirementsBuffer(IGF, requirements,
680+
Address(bindingsBufPtr, IGM.getPointerAlignment()),
681+
MetadataState::Complete,
682+
[&](CanType t) {
683+
return genericEnv->mapTypeIntoContext(t)->getCanonicalType();
684+
});
685+
686+
type = genericEnv->mapTypeIntoContext(type)->getCanonicalType();
687+
}
688+
emit(IGF, type);
689+
}
690+
691+
// Form the mangled name with its relative reference.
692+
auto S = B.beginStruct();
693+
S.setPacked(true);
694+
S.add(llvm::ConstantInt::get(IGM.Int8Ty, 9));
695+
S.addRelativeAddress(accessorThunk);
696+
697+
// And a null terminator!
698+
S.addInt(IGM.Int8Ty, 0);
699+
700+
return S.finishAndCreateFuture();
701+
});
689702
}
690703

691-
static llvm::Function *
704+
static llvm::Constant *
692705
emitMetadataGeneratorForKeyPath(IRGenModule &IGM,
693706
CanType type,
694707
GenericEnvironment *genericEnv,
695708
ArrayRef<GenericRequirement> requirements) {
709+
// TODO: Use a mangled name when we can.
710+
711+
CanGenericSignature genericSig;
712+
if (genericEnv)
713+
genericSig = genericEnv->getGenericSignature()->getCanonicalSignature();
714+
715+
IRGenMangler mangler;
716+
std::string symbolName =
717+
mangler.mangleSymbolNameForKeyPathMetadata(
718+
"keypath_get_type", genericSig, type,
719+
ProtocolConformanceRef::forInvalid());
720+
696721
// TODO: Use the standard metadata accessor when there are no arguments
697722
// and the metadata accessor is defined.
698-
return emitGeneratorForKeyPath(IGM, "keypath_get_type", type,
723+
return emitGeneratorForKeyPath(IGM, symbolName, type,
699724
IGM.TypeMetadataPtrTy,
700725
genericEnv, requirements,
701726
[&](IRGenFunction &IGF, CanType substType) {
@@ -704,15 +729,24 @@ emitMetadataGeneratorForKeyPath(IRGenModule &IGM,
704729
});
705730
};
706731

707-
static llvm::Function *
732+
static llvm::Constant *
708733
emitWitnessTableGeneratorForKeyPath(IRGenModule &IGM,
709734
CanType type,
710735
ProtocolConformanceRef conformance,
711736
GenericEnvironment *genericEnv,
712737
ArrayRef<GenericRequirement> requirements) {
738+
CanGenericSignature genericSig;
739+
if (genericEnv)
740+
genericSig = genericEnv->getGenericSignature()->getCanonicalSignature();
741+
742+
IRGenMangler mangler;
743+
std::string symbolName =
744+
mangler.mangleSymbolNameForKeyPathMetadata(
745+
"keypath_get_witness_table", genericSig, type, conformance);
746+
713747
// TODO: Use the standard conformance accessor when there are no arguments
714748
// and the conformance accessor is defined.
715-
return emitGeneratorForKeyPath(IGM, "keypath_get_witness_table", type,
749+
return emitGeneratorForKeyPath(IGM, symbolName, type,
716750
IGM.WitnessTablePtrTy,
717751
genericEnv, requirements,
718752
[&](IRGenFunction &IGF, CanType substType) {

lib/IRGen/GenReflection.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ llvm::Constant *IRGenModule::getMangledAssociatedConformance(
198198
// See if we emitted the constant already.
199199
auto &entry = StringsForTypeRef[symbolName];
200200
if (entry.second) {
201-
202201
return entry.second;
203202
}
204203

lib/IRGen/IRGenMangler.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,26 @@ std::string IRGenMangler::mangleSymbolNameForAssociatedConformanceWitness(
257257
appendProtocolName(proto);
258258
return finalize();
259259
}
260+
261+
std::string IRGenMangler::mangleSymbolNameForKeyPathMetadata(
262+
const char *kind,
263+
CanGenericSignature genericSig,
264+
CanType type,
265+
ProtocolConformanceRef conformance) {
266+
beginManglingWithoutPrefix();
267+
Buffer << kind << " ";
268+
269+
if (genericSig)
270+
appendGenericSignature(genericSig);
271+
272+
if (type)
273+
appendType(type);
274+
275+
if (conformance.isConcrete())
276+
appendConcreteProtocolConformance(conformance.getConcrete());
277+
else if (conformance.isAbstract())
278+
appendProtocolName(conformance.getAbstract());
279+
else
280+
assert(conformance.isInvalid() && "Unknown protocol conformance");
281+
return finalize();
282+
}

lib/IRGen/IRGenMangler.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,13 @@ class IRGenMangler : public Mangle::ASTMangler {
418418
const NormalProtocolConformance *conformance,
419419
CanType associatedType,
420420
const ProtocolDecl *proto);
421+
422+
std::string mangleSymbolNameForKeyPathMetadata(
423+
const char *kind,
424+
CanGenericSignature genericSig,
425+
CanType type,
426+
ProtocolConformanceRef conformance);
427+
421428
protected:
422429
SymbolicMangling
423430
withSymbolicReferences(IRGenModule &IGM,

lib/IRGen/IRGenModule.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ namespace irgen {
110110
class ClangTypeConverter;
111111
class ClassMetadataLayout;
112112
class ConformanceInfo;
113+
class ConstantInitBuilder;
113114
struct ConstantIntegerLiteral;
114115
class ConstantIntegerLiteralMap;
115116
class DebugTypeInfo;
@@ -1072,6 +1073,24 @@ class IRGenModule {
10721073
MangledTypeRefRole role);
10731074
llvm::Constant *getAddrOfStringForTypeRef(const SymbolicMangling &mangling,
10741075
MangledTypeRefRole role);
1076+
1077+
/// Retrieve the address of a mangled string used for some kind of metadata
1078+
/// reference.
1079+
///
1080+
/// \param symbolName The name of the symbol that describes the metadata
1081+
/// being referenced.
1082+
/// \param shouldSetLowBit Whether to set the low bit of the result
1083+
/// constant, which is used by some clients to indicate that the result is
1084+
/// a mangled name.
1085+
/// \param body The body of a function that will create the metadata value
1086+
/// itself, given a constant building and producing a future for the
1087+
/// initializer.
1088+
/// \returns the address of the global variable describing this metadata.
1089+
llvm::Constant *getAddrOfStringForMetadataRef(
1090+
StringRef symbolName,
1091+
bool shouldSetLowBit,
1092+
llvm::function_ref<ConstantInitFuture(ConstantInitBuilder &)> body);
1093+
10751094
llvm::Constant *getAddrOfFieldName(StringRef Name);
10761095
llvm::Constant *getAddrOfCaptureDescriptor(SILFunction &caller,
10771096
CanSILFunctionType origCalleeType,

lib/IRGen/MetadataRequest.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,50 @@ MetadataDependency MetadataDependencyCollector::finish(IRGenFunction &IGF) {
218218
}
219219

220220

221+
llvm::Constant *IRGenModule::getAddrOfStringForMetadataRef(
222+
StringRef symbolName,
223+
bool shouldSetLowBit,
224+
llvm::function_ref<ConstantInitFuture (ConstantInitBuilder &)> body) {
225+
// Check whether we already have an entry with this name.
226+
auto &entry = StringsForTypeRef[symbolName];
227+
if (entry.second) {
228+
return entry.second;
229+
}
230+
231+
// Construct the initializer.
232+
ConstantInitBuilder builder(*this);
233+
auto finished = body(builder);
234+
235+
auto var = new llvm::GlobalVariable(Module, finished.getType(),
236+
/*constant*/ true,
237+
llvm::GlobalValue::LinkOnceODRLinkage,
238+
nullptr,
239+
symbolName);
240+
241+
ApplyIRLinkage({llvm::GlobalValue::LinkOnceODRLinkage,
242+
llvm::GlobalValue::HiddenVisibility,
243+
llvm::GlobalValue::DefaultStorageClass})
244+
.to(var);
245+
var->setAlignment(2);
246+
setTrueConstGlobal(var);
247+
var->setSection(getReflectionTypeRefSectionName());
248+
249+
finished.installInGlobal(var);
250+
251+
// Drill down to the i8* at the beginning of the constant.
252+
auto addr = llvm::ConstantExpr::getBitCast(var, Int8PtrTy);
253+
254+
// If requested, set the low bit.
255+
if (shouldSetLowBit) {
256+
auto bitConstant = llvm::ConstantInt::get(IntPtrTy, 1);
257+
addr = llvm::ConstantExpr::getGetElementPtr(nullptr, addr, bitConstant);
258+
}
259+
260+
StringsForTypeRef[symbolName] = { var, addr };
261+
262+
return addr;
263+
}
264+
221265
llvm::Constant *IRGenModule::getAddrOfStringForTypeRef(StringRef str,
222266
MangledTypeRefRole role){
223267
return getAddrOfStringForTypeRef(SymbolicMangling{str, {}}, role);

0 commit comments

Comments
 (0)