Skip to content

Commit 176386c

Browse files
authored
Merge pull request #20499 from DougGregor/keypath-metadata-mangling
2 parents c34779c + 7b8bbcd commit 176386c

File tree

9 files changed

+316
-119
lines changed

9 files changed

+316
-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: 75 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,83 @@ 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+
// If we have a non-dependent type, use a normal mangled type name.
710+
if (!type->hasTypeParameter()) {
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+
}
715+
716+
// Otherwise, create an accessor.
717+
CanGenericSignature genericSig;
718+
if (genericEnv)
719+
genericSig = genericEnv->getGenericSignature()->getCanonicalSignature();
720+
721+
IRGenMangler mangler;
722+
std::string symbolName =
723+
mangler.mangleSymbolNameForKeyPathMetadata(
724+
"keypath_get_type", genericSig, type,
725+
ProtocolConformanceRef::forInvalid());
726+
696727
// TODO: Use the standard metadata accessor when there are no arguments
697728
// and the metadata accessor is defined.
698-
return emitGeneratorForKeyPath(IGM, "keypath_get_type", type,
729+
return emitGeneratorForKeyPath(IGM, symbolName, type,
699730
IGM.TypeMetadataPtrTy,
700731
genericEnv, requirements,
701732
[&](IRGenFunction &IGF, CanType substType) {
@@ -704,15 +735,24 @@ emitMetadataGeneratorForKeyPath(IRGenModule &IGM,
704735
});
705736
};
706737

707-
static llvm::Function *
738+
static llvm::Constant *
708739
emitWitnessTableGeneratorForKeyPath(IRGenModule &IGM,
709740
CanType type,
710741
ProtocolConformanceRef conformance,
711742
GenericEnvironment *genericEnv,
712743
ArrayRef<GenericRequirement> requirements) {
744+
CanGenericSignature genericSig;
745+
if (genericEnv)
746+
genericSig = genericEnv->getGenericSignature()->getCanonicalSignature();
747+
748+
IRGenMangler mangler;
749+
std::string symbolName =
750+
mangler.mangleSymbolNameForKeyPathMetadata(
751+
"keypath_get_witness_table", genericSig, type, conformance);
752+
713753
// TODO: Use the standard conformance accessor when there are no arguments
714754
// and the conformance accessor is defined.
715-
return emitGeneratorForKeyPath(IGM, "keypath_get_witness_table", type,
755+
return emitGeneratorForKeyPath(IGM, symbolName, type,
716756
IGM.WitnessTablePtrTy,
717757
genericEnv, requirements,
718758
[&](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: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,52 @@ 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+
// Call this to form the return value.
226+
auto returnValue = [&](llvm::Constant *addr) {
227+
if (!shouldSetLowBit)
228+
return addr;
229+
230+
auto bitConstant = llvm::ConstantInt::get(IntPtrTy, 1);
231+
return llvm::ConstantExpr::getGetElementPtr(nullptr, addr, bitConstant);
232+
};
233+
234+
// Check whether we already have an entry with this name.
235+
auto &entry = StringsForTypeRef[symbolName];
236+
if (entry.second) {
237+
return returnValue(entry.second);
238+
}
239+
240+
// Construct the initializer.
241+
ConstantInitBuilder builder(*this);
242+
auto finished = body(builder);
243+
244+
auto var = new llvm::GlobalVariable(Module, finished.getType(),
245+
/*constant*/ true,
246+
llvm::GlobalValue::LinkOnceODRLinkage,
247+
nullptr,
248+
symbolName);
249+
250+
ApplyIRLinkage({llvm::GlobalValue::LinkOnceODRLinkage,
251+
llvm::GlobalValue::HiddenVisibility,
252+
llvm::GlobalValue::DefaultStorageClass})
253+
.to(var);
254+
var->setAlignment(2);
255+
setTrueConstGlobal(var);
256+
var->setSection(getReflectionTypeRefSectionName());
257+
258+
finished.installInGlobal(var);
259+
260+
// Drill down to the i8* at the beginning of the constant.
261+
auto addr = llvm::ConstantExpr::getBitCast(var, Int8PtrTy);
262+
StringsForTypeRef[symbolName] = { var, addr };
263+
264+
return returnValue(addr);
265+
}
266+
221267
llvm::Constant *IRGenModule::getAddrOfStringForTypeRef(StringRef str,
222268
MangledTypeRefRole role){
223269
return getAddrOfStringForTypeRef(SymbolicMangling{str, {}}, role);

0 commit comments

Comments
 (0)