Skip to content

[ABI] Use generic environment to handle mangled generic keypath types. #20640

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ The following symbolic reference kinds are currently implemented:
dependent-associated-conformance ::= '\x05' .{4} // Reference points directly to associated conformance descriptor (NOT IMPLEMENTED)
dependent-associated-conformance ::= '\x06' .{4} // Reference points indirectly to associated conformance descriptor (NOT IMPLEMENTED)

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

Globals
~~~~~~~
Expand Down
51 changes: 51 additions & 0 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -2611,6 +2611,57 @@ class TargetGenericRequirementDescriptor {
using GenericRequirementDescriptor =
TargetGenericRequirementDescriptor<InProcess>;

template<typename Runtime>
class TargetGenericEnvironment
: public swift::ABI::TrailingObjects<TargetGenericEnvironment<Runtime>,
uint16_t, GenericParamDescriptor,
TargetGenericRequirementDescriptor<Runtime>> {
using GenericRequirementDescriptor =
TargetGenericRequirementDescriptor<Runtime>;
using TrailingObjects =
swift::ABI::TrailingObjects<TargetGenericEnvironment<Runtime>,
uint16_t, GenericParamDescriptor, GenericRequirementDescriptor>;
friend TrailingObjects;

template<typename T>
using OverloadToken = typename TrailingObjects::template OverloadToken<T>;

size_t numTrailingObjects(OverloadToken<uint16_t>) const {
return Flags.getNumGenericParameterLevels();
}

size_t numTrailingObjects(OverloadToken<GenericParamDescriptor>) const {
return getGenericParameterCounts().back();
}

size_t numTrailingObjects(OverloadToken<GenericRequirementDescriptor>) const {
return Flags.getNumGenericRequirements();
}

GenericEnvironmentFlags Flags;

public:
/// Retrieve the cumulative generic parameter counts at each level of genericity.
ArrayRef<uint16_t> getGenericParameterCounts() const {
return ArrayRef<uint16_t>(this->template getTrailingObjects<uint16_t>(),
Flags.getNumGenericParameterLevels());
}

/// Retrieve the generic parameters descriptors.
ArrayRef<GenericParamDescriptor> getGenericParameters() const {
return ArrayRef<GenericParamDescriptor>(
this->template getTrailingObjects<GenericParamDescriptor>(),
getGenericParameterCounts().back());
}

/// Retrieve the generic requirements.
ArrayRef<GenericRequirementDescriptor> getGenericRequirements() const {
return ArrayRef<GenericRequirementDescriptor>(
this->template getTrailingObjects<GenericRequirementDescriptor>(),
Flags.getNumGenericRequirements());
}
};

/// CRTP class for a context descriptor that includes trailing generic
/// context description.
template<class Self,
Expand Down
39 changes: 39 additions & 0 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -1508,6 +1508,45 @@ enum class GenericRequirementLayoutKind : uint32_t {
Class = 0,
};

class GenericEnvironmentFlags {
uint32_t Value;

enum : uint32_t {
NumGenericParameterLevelsMask = 0xFFF,
NumGenericRequirementsShift = 12,
NumGenericRequirementsMask = 0xFFFF << NumGenericRequirementsShift,
};

constexpr explicit GenericEnvironmentFlags(uint32_t value) : Value(value) { }

public:
constexpr GenericEnvironmentFlags() : Value(0) { }

constexpr GenericEnvironmentFlags
withNumGenericParameterLevels(uint16_t numGenericParameterLevels) const {
return GenericEnvironmentFlags((Value &~ NumGenericParameterLevelsMask)
| numGenericParameterLevels);
}

constexpr GenericEnvironmentFlags
withNumGenericRequirements(uint16_t numGenericRequirements) const {
return GenericEnvironmentFlags((Value &~ NumGenericRequirementsMask)
| (numGenericRequirements << NumGenericRequirementsShift));
}

constexpr unsigned getNumGenericParameterLevels() const {
return Value & NumGenericParameterLevelsMask;
}

constexpr unsigned getNumGenericRequirements() const {
return (Value & NumGenericRequirementsMask) >> NumGenericRequirementsShift;
}

constexpr uint32_t getIntValue() const {
return Value;
}
};

/// Flags used by generic metadata patterns.
class GenericMetadataPatternFlags : public FlagSet<uint32_t> {
enum {
Expand Down
2 changes: 1 addition & 1 deletion lib/Demangling/Demangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ swift::Demangle::makeSymbolicMangledNameStringRef(const char *base) {
// Skip over symbolic references.
if (*end >= '\x01' && *end <= '\x17')
end += sizeof(uint32_t);
if (*end >= '\x18' && *end <= '\x1F')
else if (*end >= '\x18' && *end <= '\x1F')
end += sizeof(void*);
++end;
}
Expand Down
38 changes: 9 additions & 29 deletions lib/IRGen/GenKeyPath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -657,7 +657,7 @@ emitGeneratorForKeyPath(IRGenModule &IGM,
ArrayRef<GenericRequirement> requirements,
llvm::function_ref<void(IRGenFunction&,CanType)> emit) {

return IGM.getAddrOfStringForMetadataRef(name,
return IGM.getAddrOfStringForMetadataRef(name, /*alignment=*/2,
/*shouldSetLowBit=*/true,
[&](ConstantInitBuilder &B) {
// Build a stub that loads the necessary bindings from the key path's
Expand Down Expand Up @@ -707,34 +707,11 @@ emitMetadataGeneratorForKeyPath(IRGenModule &IGM,
CanType type,
GenericEnvironment *genericEnv,
ArrayRef<GenericRequirement> requirements) {
// If we have a non-dependent type, use a normal mangled type name.
if (!type->hasTypeParameter()) {
auto constant = IGM.getTypeRef(type, MangledTypeRefRole::Metadata);
auto bitConstant = llvm::ConstantInt::get(IGM.IntPtrTy, 1);
return llvm::ConstantExpr::getGetElementPtr(nullptr, constant, bitConstant);
}

// Otherwise, create an accessor.
CanGenericSignature genericSig;
if (genericEnv)
genericSig = genericEnv->getGenericSignature()->getCanonicalSignature();

IRGenMangler mangler;
std::string symbolName =
mangler.mangleSymbolNameForKeyPathMetadata(
"keypath_get_type", genericSig, type,
ProtocolConformanceRef::forInvalid());

// TODO: Use the standard metadata accessor when there are no arguments
// and the metadata accessor is defined.
return emitGeneratorForKeyPath(IGM, symbolName, type,
IGM.TypeMetadataPtrTy,
genericEnv, requirements,
[&](IRGenFunction &IGF, CanType substType) {
auto ret = IGF.emitTypeMetadataRef(substType);
IGF.Builder.CreateRet(ret);
});
};
// Produce a mangled name for the type.
auto constant = IGM.getTypeRef(type, MangledTypeRefRole::Metadata);
auto bitConstant = llvm::ConstantInt::get(IGM.IntPtrTy, 1);
return llvm::ConstantExpr::getGetElementPtr(nullptr, constant, bitConstant);
}

static llvm::Constant *
emitWitnessTableGeneratorForKeyPath(IRGenModule &IGM,
Expand Down Expand Up @@ -1171,6 +1148,9 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern,
fields.addInt32(0);
}

// Add the generic environment.
fields.addRelativeAddressOrNull(
getAddrOfGenericEnvironment(pattern->getGenericSignature()));
// Store type references for the root and leaf.
fields.addRelativeAddress(
emitMetadataGeneratorForKeyPath(*this, rootTy, genericEnv, requirements));
Expand Down
56 changes: 56 additions & 0 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
#include "GenericRequirement.h"
#include "IRGenDebugInfo.h"
#include "IRGenFunction.h"
#include "IRGenMangler.h"
#include "IRGenModule.h"
#include "MetadataPath.h"
#include "MetadataRequest.h"
Expand Down Expand Up @@ -3419,3 +3420,58 @@ llvm::Value *irgen::emitProtocolDescriptorRef(IRGenFunction &IGF,

return val;
}

llvm::Constant *IRGenModule::getAddrOfGenericEnvironment(
CanGenericSignature signature) {
if (!signature)
return nullptr;

IRGenMangler mangler;
auto symbolName = mangler.mangleSymbolNameForGenericEnvironment(signature);
return getAddrOfStringForMetadataRef(symbolName, /*alignment=*/0, false,
[&] (ConstantInitBuilder &builder) -> ConstantInitFuture {
/// Collect the cumulative count of parameters at each level.
llvm::SmallVector<uint16_t, 4> genericParamCounts;
unsigned curDepth = 0;
unsigned genericParamCount = 0;
for (const auto gp : signature->getGenericParams()) {
if (curDepth != gp->getDepth()) {
genericParamCounts.push_back(genericParamCount);
curDepth = gp->getDepth();
}

++genericParamCount;
}
genericParamCounts.push_back(genericParamCount);

auto flags = GenericEnvironmentFlags()
.withNumGenericParameterLevels(genericParamCounts.size())
.withNumGenericRequirements(signature->getRequirements().size());

ConstantStructBuilder fields = builder.beginStruct();
fields.setPacked(true);

// Flags
fields.addInt32(flags.getIntValue());

// Parameter counts.
for (auto count : genericParamCounts) {
fields.addInt16(count);
}

// Generic parameters.
signature->forEachParam([&](GenericTypeParamType *param,
bool canonical) {
fields.addInt(Int8Ty,
GenericParamDescriptor(GenericParamKind::Type,
canonical,
false)
.getIntValue());
});

// Generic requirements
irgen::addGenericRequirements(*this, fields, signature,
signature->getRequirements());
return fields.finishAndCreateFuture();
});
}
8 changes: 8 additions & 0 deletions lib/IRGen/IRGenMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,11 @@ std::string IRGenMangler::mangleSymbolNameForKeyPathMetadata(
assert(conformance.isInvalid() && "Unknown protocol conformance");
return finalize();
}

std::string IRGenMangler::mangleSymbolNameForGenericEnvironment(
CanGenericSignature genericSig) {
beginManglingWithoutPrefix();
Buffer << "generic environment ";
appendGenericSignature(genericSig);
return finalize();
}
2 changes: 2 additions & 0 deletions lib/IRGen/IRGenMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,8 @@ class IRGenMangler : public Mangle::ASTMangler {
CanType type,
ProtocolConformanceRef conformance);

std::string mangleSymbolNameForGenericEnvironment(
CanGenericSignature genericSig);
protected:
SymbolicMangling
withSymbolicReferences(IRGenModule &IGM,
Expand Down
3 changes: 3 additions & 0 deletions lib/IRGen/IRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,7 @@ class IRGenModule {
///
/// \param symbolName The name of the symbol that describes the metadata
/// being referenced.
/// \param alignment If non-zero, the alignment of the requested variable.
/// \param shouldSetLowBit Whether to set the low bit of the result
/// constant, which is used by some clients to indicate that the result is
/// a mangled name.
Expand All @@ -1041,6 +1042,7 @@ class IRGenModule {
/// \returns the address of the global variable describing this metadata.
llvm::Constant *getAddrOfStringForMetadataRef(
StringRef symbolName,
unsigned alignment,
bool shouldSetLowBit,
llvm::function_ref<ConstantInitFuture(ConstantInitBuilder &)> body);

Expand Down Expand Up @@ -1276,6 +1278,7 @@ private: \
llvm::Constant *getAddrOfObjCModuleContextDescriptor();
llvm::Constant *getAddrOfClangImporterModuleContextDescriptor();
ConstantReference getAddrOfParentContextDescriptor(DeclContext *from);
llvm::Constant *getAddrOfGenericEnvironment(CanGenericSignature signature);
llvm::Constant *getAddrOfProtocolRequirementsBaseDescriptor(
ProtocolDecl *proto);
llvm::GlobalValue *defineProtocolRequirementsBaseDescriptor(
Expand Down
4 changes: 3 additions & 1 deletion lib/IRGen/MetadataRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ MetadataDependency MetadataDependencyCollector::finish(IRGenFunction &IGF) {

llvm::Constant *IRGenModule::getAddrOfStringForMetadataRef(
StringRef symbolName,
unsigned alignment,
bool shouldSetLowBit,
llvm::function_ref<ConstantInitFuture (ConstantInitBuilder &)> body) {
// Call this to form the return value.
Expand Down Expand Up @@ -251,7 +252,8 @@ llvm::Constant *IRGenModule::getAddrOfStringForMetadataRef(
llvm::GlobalValue::HiddenVisibility,
llvm::GlobalValue::DefaultStorageClass})
.to(var);
var->setAlignment(2);
if (alignment)
var->setAlignment(alignment);
setTrueConstGlobal(var);
var->setSection(getReflectionTypeRefSectionName());

Expand Down
Loading