Replace nominal type descriptors with a hierarchy of context descriptors.

This new format more efficiently represents existing information, while
more accurately encoding important information about nested generic
contexts with same-type and layout constraints that need to be evaluated
at runtime. It's also designed with an eye to forward- and
backward-compatible expansion for ABI stability with future Swift
versions.
This commit is contained in:
Joe Groff
2017-12-12 09:57:36 -08:00
parent 9ac1dc80b0
commit a7a3b17597
58 changed files with 3418 additions and 1291 deletions

View File

@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
#include "swift/Basic/Range.h"
#include "swift/Runtime/Metadata.h"
#include "swift/Strings.h"
#include "Private.h"
@@ -30,102 +31,6 @@ Demangle::NodePointer
swift::_swift_buildDemanglingForMetadata(const Metadata *type,
Demangle::Demangler &Dem);
static Demangle::NodePointer
_applyGenericArguments(const Metadata * const *genericArgs,
const NominalTypeDescriptor *description,
Demangle::NodePointer node, unsigned depth,
Demangle::Demangler &Dem) {
assert(depth > 0);
auto typeNode = node;
if (typeNode->getKind() == Node::Kind::Type)
typeNode = typeNode->getChild(0);
auto parentNode = typeNode->getChild(0);
// It might be more accurate to keep this sugar, but the old version
// of this function dropped it, and I want to keep things compatible.
if (parentNode->getKind() == Node::Kind::Extension) {
parentNode = parentNode->getChild(1);
}
switch (parentNode->getKind()) {
case Node::Kind::Class:
case Node::Kind::Structure:
case Node::Kind::Enum: {
// The parent type is a nominal type which may have its own generic
// arguments.
auto newParentNode = _applyGenericArguments(genericArgs, description,
parentNode, depth - 1,
Dem);
if (newParentNode == nullptr)
return nullptr;
auto newTypeNode = Dem.createNode(typeNode->getKind());
newTypeNode->addChild(newParentNode, Dem);
newTypeNode->addChild(typeNode->getChild(1), Dem);
typeNode = newTypeNode;
break;
}
default:
// Parent is a local context or module. Leave it as-is, and just apply
// generic arguments below.
break;
}
// See if we have any generic arguments at this depth.
unsigned numArgumentsAtDepth =
description->getGenericContext(depth - 1).NumPrimaryParams;
if (numArgumentsAtDepth == 0) {
// No arguments here, just return the original node (except we may have
// replaced its parent type above).
return typeNode;
}
// Ok, we have generic arguments. Figure out where the arguments for this
// depth begin in the generic type metadata.
unsigned firstArgumentAtDepth = 0;
for (unsigned i = 0; i < depth - 1; i++) {
firstArgumentAtDepth +=
description->getGenericContext(i).NumPrimaryParams;
}
// Demangle them.
auto typeParams = Dem.createNode(Node::Kind::TypeList);
for (unsigned i = firstArgumentAtDepth,
e = firstArgumentAtDepth + numArgumentsAtDepth;
i < e; ++i) {
auto demangling = _swift_buildDemanglingForMetadata(genericArgs[i], Dem);
if (demangling == nullptr)
return nullptr;
typeParams->addChild(demangling, Dem);
}
Node::Kind boundGenericKind;
switch (typeNode->getKind()) {
case Node::Kind::Class:
boundGenericKind = Node::Kind::BoundGenericClass;
break;
case Node::Kind::Structure:
boundGenericKind = Node::Kind::BoundGenericStructure;
break;
case Node::Kind::Enum:
boundGenericKind = Node::Kind::BoundGenericEnum;
break;
default:
return nullptr;
}
auto newNode = Dem.createNode(Node::Kind::Type);
newNode->addChild(typeNode, Dem);
auto genericNode = Dem.createNode(boundGenericKind);
genericNode->addChild(newNode, Dem);
genericNode->addChild(typeParams, Dem);
return genericNode;
}
static Demangle::NodePointer
_buildDemanglerForBuiltinType(const Metadata *type, Demangle::Demangler &Dem) {
#define BUILTIN_TYPE(Symbol, Name) \
@@ -135,14 +40,14 @@ _buildDemanglerForBuiltinType(const Metadata *type, Demangle::Demangler &Dem) {
return nullptr;
}
// Build a demangled type tree for a nominal type.
/// Build a demangled type tree for a nominal type.
static Demangle::NodePointer
_buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {
using namespace Demangle;
const NominalTypeDescriptor *description;
// Get the context descriptor from the type metadata.
const TypeContextDescriptor *description;
// Demangle the parent type, if any.
switch (type->getKind()) {
case MetadataKind::Class: {
auto classType = static_cast<const ClassMetadata *>(type);
@@ -168,18 +73,257 @@ _buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {
default:
return nullptr;
}
// Demangle the generic arguments.
std::vector<NodePointer> demangledGenerics;
bool concretizedGenerics = false;
if (auto generics = description->getGenericContext()) {
auto genericArgs = description->getGenericArguments(type);
for (auto param : generics->getGenericParams()) {
switch (param.getKind()) {
case GenericParamKind::Type:
// We don't know about type parameters with extra arguments.
if (param.hasExtraArgument()) {
genericArgs += param.hasExtraArgument() + param.hasKeyArgument();
goto unknown_param;
}
// Demangle the base name.
auto node = Dem.demangleType(StringRef(description->Name));
assert(node->getKind() == Node::Kind::Type);
// The type should have a key argument unless it's been same-typed to
// another type.
if (param.hasKeyArgument()) {
auto paramType = *genericArgs++;
auto paramDemangling =
_swift_buildDemanglingForMetadata(paramType, Dem);
if (!paramDemangling)
return nullptr;
demangledGenerics.push_back(paramDemangling);
} else {
// Leave a gap for us to fill in by looking at same type info.
demangledGenerics.push_back(nullptr);
concretizedGenerics = true;
}
break;
unknown_param:
default: {
// We don't know about this kind of parameter. Create a placeholder
// mangling.
// ABI TODO: Mangle some kind of unique "unknown parameter"
// representation here.
auto placeholder = Dem.createNode(Node::Kind::Tuple);
auto emptyList = Dem.createNode(Node::Kind::TypeList);
placeholder->addChild(emptyList, Dem);
auto type = Dem.createNode(Node::Kind::Type);
type->addChild(placeholder, Dem);
demangledGenerics.push_back(type);
}
}
}
// If we have concretized generic arguments, check for same type
// requirements to get the argument values.
// ABI TODO
}
unsigned usedDemangledGenerics = 0;
// Walk up the context tree.
std::vector<const ContextDescriptor *> descriptorPath;
{
const ContextDescriptor *parent = description;
while (parent) {
descriptorPath.push_back(parent);
parent = parent->Parent;
}
}
auto typeBytes = reinterpret_cast<const char *>(type);
auto genericArgs = reinterpret_cast<const Metadata * const *>(
typeBytes + sizeof(void*) * description->GenericParams.getOffset(type));
// Build a demangling tree from the context path.
NodePointer node = nullptr;
auto getGenericArgsTypeListForContext =
[&](const ContextDescriptor *context) -> NodePointer {
// ABI TODO: As a hack to maintain existing broken behavior,
// if there were any generic arguments eliminated by same type
// constraints, we don't mangle any of them into intermediate contexts,
// and pile all of the non-concrete arguments into the innermost context.
if (concretizedGenerics)
return nullptr;
auto generics = context->getGenericContext();
if (!generics)
return nullptr;
auto numParams = generics->getGenericContextHeader().NumParams;
if (numParams <= usedDemangledGenerics)
return nullptr;
auto genericArgsList = Dem.createNode(Node::Kind::TypeList);
for (unsigned e = generics->getGenericContextHeader().NumParams;
usedDemangledGenerics < e;
++usedDemangledGenerics) {
genericArgsList->addChild(demangledGenerics[usedDemangledGenerics],
Dem);
}
return genericArgsList;
};
auto innermostComponent = descriptorPath.front();
for (auto component : reversed(descriptorPath)) {
switch (auto kind = component->getKind()) {
case ContextDescriptorKind::Module: {
assert(node == nullptr && "module should be top level");
auto name = llvm::cast<ModuleContextDescriptor>(component)->Name.get();
node = Dem.createNode(Node::Kind::Module, name);
break;
}
case ContextDescriptorKind::Extension: {
auto extension = llvm::cast<ExtensionContextDescriptor>(component);
// Demangle the extension self type.
auto selfType = Dem.demangleType(extension->ExtendedContext.get());
assert(selfType->getKind() == Node::Kind::Type);
selfType = selfType->getChild(0);
// Substitute in the generic arguments.
// TODO: This kludge only kinda works if there are no same-type
// constraints. We'd need to handle those correctly everywhere else too
// though.
auto genericArgsList = getGenericArgsTypeListForContext(component);
if (selfType->getKind() == Node::Kind::BoundGenericEnum
|| selfType->getKind() == Node::Kind::BoundGenericStructure
|| selfType->getKind() == Node::Kind::BoundGenericClass
|| selfType->getKind() == Node::Kind::BoundGenericOtherNominalType) {
if (genericArgsList) {
auto substSelfType = Dem.createNode(selfType->getKind());
substSelfType->addChild(selfType->getChild(0), Dem);
substSelfType->addChild(genericArgsList, Dem);
selfType = substSelfType;
} else {
// TODO: Use the unsubstituted type if we can't handle the
// substitutions yet.
selfType = selfType->getChild(0)->getChild(0);
}
}
auto extNode = Dem.createNode(Node::Kind::Extension);
extNode->addChild(node, Dem);
extNode->addChild(selfType, Dem);
// TODO: Turn the generic signature into a demangling as the third
// generic argument.
node = extNode;
break;
}
return _applyGenericArguments(genericArgs, description, node,
description->GenericParams.NestingDepth,
Dem);
default:
// Form a type context demangling for type contexts.
if (auto type = llvm::dyn_cast<TypeContextDescriptor>(component)) {
auto name = type->Name.get();
Node::Kind nodeKind;
Node::Kind genericNodeKind;
switch (kind) {
case ContextDescriptorKind::Class:
nodeKind = Node::Kind::Class;
genericNodeKind = Node::Kind::BoundGenericClass;
break;
case ContextDescriptorKind::Struct:
nodeKind = Node::Kind::Structure;
genericNodeKind = Node::Kind::BoundGenericStructure;
break;
case ContextDescriptorKind::Enum:
nodeKind = Node::Kind::Enum;
genericNodeKind = Node::Kind::BoundGenericEnum;
break;
default:
// We don't know about this kind of type. Use an "other type" mangling
// for it.
nodeKind = Node::Kind::OtherNominalType;
genericNodeKind = Node::Kind::BoundGenericOtherNominalType;
break;
}
// Override the node kind if this is a Clang-imported type so we give it
// a stable mangling.
auto typeFlags = type->Flags.getKindSpecificFlags();
if (typeFlags & (uint16_t)TypeContextDescriptorFlags::IsCTag) {
nodeKind = Node::Kind::Structure;
} else if (typeFlags & (uint16_t)TypeContextDescriptorFlags::IsCTypedef) {
nodeKind = Node::Kind::TypeAlias;
}
auto typeNode = Dem.createNode(nodeKind);
typeNode->addChild(node, Dem);
auto identifier = Dem.createNode(Node::Kind::Identifier, name);
typeNode->addChild(identifier, Dem);
node = typeNode;
// Apply generic arguments if the context is generic.
if (auto genericArgsList = getGenericArgsTypeListForContext(component)){
auto unspecializedType = Dem.createNode(Node::Kind::Type);
unspecializedType->addChild(node, Dem);
auto genericNode = Dem.createNode(genericNodeKind);
genericNode->addChild(unspecializedType, Dem);
genericNode->addChild(genericArgsList, Dem);
node = genericNode;
}
// ABI TODO: If there were concretized generic arguments, just pile
// all the non-concretized generic arguments into the innermost context.
if (concretizedGenerics && component == innermostComponent) {
auto unspecializedType = Dem.createNode(Node::Kind::Type);
unspecializedType->addChild(node, Dem);
auto genericTypeList = Dem.createNode(Node::Kind::TypeList);
for (auto arg : demangledGenerics) {
if (!arg) continue;
genericTypeList->addChild(arg, Dem);
}
if (genericTypeList->getNumChildren() > 0) {
auto genericNode = Dem.createNode(genericNodeKind);
genericNode->addChild(unspecializedType, Dem);
genericNode->addChild(genericTypeList, Dem);
node = genericNode;
}
}
break;
}
// This runtime doesn't understand this context, or it's a context with
// no richer runtime information available about it (such as an anonymous
// context). Use an unstable mangling to represent the context by its
// pointer identity.
// ABI TODO: extensions fall into this path, but they shouldn't. we
// should try to demangle them accurately.
char addressBuf[sizeof(void*) * 2 + 2 + 1];
snprintf(addressBuf, sizeof(addressBuf), "0x%" PRIxPTR, (uintptr_t)component);
auto anonNode = Dem.createNode(Node::Kind::AnonymousContext);
CharVector addressStr;
addressStr.append(addressBuf, Dem);
auto name = Dem.createNode(Node::Kind::Identifier, addressStr);
anonNode->addChild(name, Dem);
anonNode->addChild(node, Dem);
// Collect generic arguments if the context is generic.
auto genericArgsList = getGenericArgsTypeListForContext(component);
if (!genericArgsList)
genericArgsList = Dem.createNode(Node::Kind::TypeList);
anonNode->addChild(genericArgsList, Dem);
node = anonNode;
break;
}
}
// Wrap the final result in a top-level Type node.
auto top = Dem.createNode(Node::Kind::Type);
top->addChild(node, Dem);
return top;
}
// Build a demangled type tree for a type.