void Remangler::mangleGenericArgs(Node *node, EntityContext &ctx) { switch (node->getKind()) { case Node::Kind::Structure: case Node::Kind::Enum: case Node::Kind::Class: { NodePointer parentOrModule = node->getChild(0); mangleGenericArgs(parentOrModule.get(), ctx); // No generic arguments at this level Out << '_'; break; } case Node::Kind::BoundGenericStructure: case Node::Kind::BoundGenericEnum: case Node::Kind::BoundGenericClass: { NodePointer unboundType = node->getChild(0); assert(unboundType->getKind() == Node::Kind::Type); NodePointer nominalType = unboundType->getChild(0); NodePointer parentOrModule = nominalType->getChild(0); mangleGenericArgs(parentOrModule.get(), ctx); mangleTypeList(node->getChild(1).get()); break; } default: break; } }
void Remangler::mangleSILBoxTypeWithLayout(Node *node) { assert(node->getKind() == Node::Kind::SILBoxTypeWithLayout); assert(node->getNumChildren() == 1 || node->getNumChildren() == 3); Out << "XB"; auto layout = node->getChild(0); assert(layout->getKind() == Node::Kind::SILBoxLayout); NodePointer genericArgs = nullptr; if (node->getNumChildren() == 3) { NodePointer signature = node->getChild(1); assert(signature->getKind() == Node::Kind::DependentGenericSignature); genericArgs = node->getChild(2); assert(genericArgs->getKind() == Node::Kind::TypeList); Out << 'G'; mangleDependentGenericSignature(signature); } mangleSILBoxLayout(layout); if (genericArgs) { for (unsigned i = 0; i < genericArgs->getNumChildren(); ++i) { auto type = genericArgs->getChild(i); assert(genericArgs->getKind() == Node::Kind::Type); mangleType(type); } Out << '_'; } }
NodePointer Remangler::getUnspecialized(Node *node) { switch (node->getKind()) { case Node::Kind::Structure: case Node::Kind::Enum: case Node::Kind::Class: { NodePointer result = NodeFactory::create(node->getKind()); NodePointer parentOrModule = node->getChild(0); if (isSpecialized(parentOrModule.get())) result->addChild(getUnspecialized(parentOrModule.get())); else result->addChild(parentOrModule); result->addChild(node->getChild(1)); return result; } case Node::Kind::BoundGenericStructure: case Node::Kind::BoundGenericEnum: case Node::Kind::BoundGenericClass: { NodePointer unboundType = node->getChild(0); assert(unboundType->getKind() == Node::Kind::Type); NodePointer nominalType = unboundType->getChild(0); if (isSpecialized(nominalType.get())) return getUnspecialized(nominalType.get()); else return nominalType; } default: unreachable("bad nominal type kind"); } }
static const TypeContextDescriptor * _findNominalTypeDescriptor(Demangle::NodePointer node, Demangle::Demangler &Dem) { const TypeContextDescriptor *foundNominal = nullptr; auto &T = TypeMetadataRecords.get(); // If we have a symbolic reference to a context, resolve it immediately. NodePointer symbolicNode = node; if (symbolicNode->getKind() == Node::Kind::Type) symbolicNode = symbolicNode->getChild(0); if (symbolicNode->getKind() == Node::Kind::SymbolicReference) return cast<TypeContextDescriptor>( (const ContextDescriptor *)symbolicNode->getIndex()); auto mangledName = Demangle::mangleNode(node, [&](const void *context) -> NodePointer { return _buildDemanglingForContext( (const ContextDescriptor *) context, {}, false, Dem); }); // Look for an existing entry. // Find the bucket for the metadata entry. if (auto Value = T.NominalCache.find(mangledName)) return Value->getDescription(); // Check type metadata records foundNominal = _searchTypeMetadataRecords(T, node); // Check protocol conformances table. Note that this has no support for // resolving generic types yet. if (!foundNominal) foundNominal = _searchConformancesByMangledTypeName(node); if (foundNominal) { T.NominalCache.getOrInsert(mangledName, foundNominal); } return foundNominal; }
static const ProtocolDescriptor * _findProtocolDescriptor(const Demangle::NodePointer &node, Demangle::Demangler &Dem, std::string &mangledName) { const ProtocolDescriptor *foundProtocol = nullptr; auto &T = Protocols.get(); // If we have a symbolic reference to a context, resolve it immediately. NodePointer symbolicNode = node; if (symbolicNode->getKind() == Node::Kind::Type) symbolicNode = symbolicNode->getChild(0); if (symbolicNode->getKind() == Node::Kind::SymbolicReference) return cast<ProtocolDescriptor>( (const ContextDescriptor *)symbolicNode->getIndex()); mangledName = Demangle::mangleNode(node, [&](const void *context) -> NodePointer { return _buildDemanglingForContext( (const ContextDescriptor *) context, {}, Dem); }); // Look for an existing entry. // Find the bucket for the metadata entry. if (auto Value = T.ProtocolCache.find(mangledName)) return Value->getDescription(); // Check type metadata records foundProtocol = _searchProtocolRecords(T, node); if (foundProtocol) { T.ProtocolCache.getOrInsert(mangledName, foundProtocol); } return foundProtocol; }
// Build a demangled type tree for a type. Demangle::NodePointer swift::_swift_buildDemanglingForMetadata(const Metadata *type, Demangle::Demangler &Dem) { using namespace Demangle; switch (type->getKind()) { case MetadataKind::Class: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Struct: return _buildDemanglingForNominalType(type, Dem); case MetadataKind::ObjCClassWrapper: { #if SWIFT_OBJC_INTEROP auto objcWrapper = static_cast<const ObjCClassWrapperMetadata *>(type); const char *className = class_getName(objcWrapper->getObjCClassObject()); // ObjC classes mangle as being in the magic "__ObjC" module. auto module = Dem.createNode(Node::Kind::Module, "__ObjC"); auto node = Dem.createNode(Node::Kind::Class); node->addChild(module, Dem); node->addChild(Dem.createNode(Node::Kind::Identifier, llvm::StringRef(className)), Dem); return node; #else assert(false && "no ObjC interop"); return nullptr; #endif } case MetadataKind::ForeignClass: { auto foreign = static_cast<const ForeignClassMetadata *>(type); return Dem.demangleType(foreign->getName()); } case MetadataKind::Existential: { auto exis = static_cast<const ExistentialTypeMetadata *>(type); std::vector<const ProtocolDescriptor *> protocols; protocols.reserve(exis->Protocols.NumProtocols); for (unsigned i = 0, e = exis->Protocols.NumProtocols; i < e; ++i) protocols.push_back(exis->Protocols[i]); auto type_list = Dem.createNode(Node::Kind::TypeList); auto proto_list = Dem.createNode(Node::Kind::ProtocolList); proto_list->addChild(type_list, Dem); // The protocol descriptors should be pre-sorted since the compiler will // only ever make a swift_getExistentialTypeMetadata invocation using // its canonical ordering of protocols. for (auto *protocol : protocols) { // The protocol name is mangled as a type symbol, with the _Tt prefix. StringRef ProtoName(protocol->Name); NodePointer protocolNode = Dem.demangleSymbol(ProtoName); // ObjC protocol names aren't mangled. if (!protocolNode) { auto module = Dem.createNode(Node::Kind::Module, MANGLING_MODULE_OBJC); auto node = Dem.createNode(Node::Kind::Protocol); node->addChild(module, Dem); node->addChild(Dem.createNode(Node::Kind::Identifier, llvm::StringRef(protocol->Name)), Dem); auto typeNode = Dem.createNode(Node::Kind::Type); typeNode->addChild(node, Dem); type_list->addChild(typeNode, Dem); continue; } // FIXME: We have to dig through a ridiculous number of nodes to get // to the Protocol node here. protocolNode = protocolNode->getChild(0); // Global -> TypeMangling protocolNode = protocolNode->getChild(0); // TypeMangling -> Type protocolNode = protocolNode->getChild(0); // Type -> ProtocolList protocolNode = protocolNode->getChild(0); // ProtocolList -> TypeList protocolNode = protocolNode->getChild(0); // TypeList -> Type assert(protocolNode->getKind() == Node::Kind::Type); assert(protocolNode->getChild(0)->getKind() == Node::Kind::Protocol); type_list->addChild(protocolNode, Dem); } if (auto superclass = exis->getSuperclassConstraint()) { // If there is a superclass constraint, we mangle it specially. auto result = Dem.createNode(Node::Kind::ProtocolListWithClass); auto superclassNode = _swift_buildDemanglingForMetadata(superclass, Dem); result->addChild(proto_list, Dem); result->addChild(superclassNode, Dem); return result; } if (exis->isClassBounded()) { // Check if the class constraint is implied by any of our // protocols. bool requiresClassImplicit = false; for (auto *protocol : protocols) { if (protocol->Flags.getClassConstraint() == ProtocolClassConstraint::Class) requiresClassImplicit = true; } // If it was implied, we don't do anything special. if (requiresClassImplicit) return proto_list; // If the existential type has an explicit AnyObject constraint, // we must mangle it as such. auto result = Dem.createNode(Node::Kind::ProtocolListWithAnyObject); result->addChild(proto_list, Dem); return result; } // Just a simple composition of protocols. return proto_list; } case MetadataKind::ExistentialMetatype: { auto metatype = static_cast<const ExistentialMetatypeMetadata *>(type); auto instance = _swift_buildDemanglingForMetadata(metatype->InstanceType, Dem); auto node = Dem.createNode(Node::Kind::ExistentialMetatype); node->addChild(instance, Dem); return node; } case MetadataKind::Function: { auto func = static_cast<const FunctionTypeMetadata *>(type); Node::Kind kind; switch (func->getConvention()) { case FunctionMetadataConvention::Swift: kind = Node::Kind::FunctionType; break; case FunctionMetadataConvention::Block: kind = Node::Kind::ObjCBlock; break; case FunctionMetadataConvention::CFunctionPointer: kind = Node::Kind::CFunctionPointer; break; case FunctionMetadataConvention::Thin: kind = Node::Kind::ThinFunctionType; break; } std::vector<NodePointer> inputs; for (unsigned i = 0, e = func->getNumParameters(); i < e; ++i) { auto param = func->getParameter(i); auto flags = func->getParameterFlags(i); auto input = _swift_buildDemanglingForMetadata(param, Dem); if (flags.isInOut()) { NodePointer inout = Dem.createNode(Node::Kind::InOut); inout->addChild(input, Dem); input = inout; } else if (flags.isShared()) { NodePointer shared = Dem.createNode(Node::Kind::Shared); shared->addChild(input, Dem); input = shared; } inputs.push_back(input); } NodePointer totalInput = nullptr; switch (inputs.size()) { case 1: totalInput = inputs.front(); break; // This covers both none and multiple parameters. default: auto tuple = Dem.createNode(Node::Kind::Tuple); for (auto &input : inputs) tuple->addChild(input, Dem); totalInput = tuple; break; } NodePointer args = Dem.createNode(Node::Kind::ArgumentTuple); args->addChild(totalInput, Dem); NodePointer resultTy = _swift_buildDemanglingForMetadata(func->ResultType, Dem); NodePointer result = Dem.createNode(Node::Kind::ReturnType); result->addChild(resultTy, Dem); auto funcNode = Dem.createNode(kind); if (func->throws()) funcNode->addChild(Dem.createNode(Node::Kind::ThrowsAnnotation), Dem); funcNode->addChild(args, Dem); funcNode->addChild(result, Dem); return funcNode; } case MetadataKind::Metatype: { auto metatype = static_cast<const MetatypeMetadata *>(type); auto instance = _swift_buildDemanglingForMetadata(metatype->InstanceType, Dem); auto typeNode = Dem.createNode(Node::Kind::Type); typeNode->addChild(instance, Dem); auto node = Dem.createNode(Node::Kind::Metatype); node->addChild(typeNode, Dem); return node; } case MetadataKind::Tuple: { auto tuple = static_cast<const TupleTypeMetadata *>(type); const char *labels = tuple->Labels; auto tupleNode = Dem.createNode(Node::Kind::Tuple); for (unsigned i = 0, e = tuple->NumElements; i < e; ++i) { auto elt = Dem.createNode(Node::Kind::TupleElement); // Add a label child if applicable: if (labels) { // Look for the next space in the labels string. if (const char *space = strchr(labels, ' ')) { // If there is one, and the label isn't empty, add a label child. if (labels != space) { auto eltName = Dem.createNode(Node::Kind::TupleElementName, llvm::StringRef(labels, space - labels)); elt->addChild(eltName, Dem); } // Skip past the space. labels = space + 1; } } // Add the element type child. auto eltType = _swift_buildDemanglingForMetadata(tuple->getElement(i).Type, Dem); elt->addChild(eltType, Dem); // Add the completed element to the tuple. tupleNode->addChild(elt, Dem); } return tupleNode; } case MetadataKind::Opaque: // FIXME: Some opaque types do have manglings, but we don't have enough info // to figure them out. case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: break; } // Not a type. return nullptr; }
void swift::gatherWrittenGenericArgs( const Metadata *metadata, const TypeContextDescriptor *description, std::vector<const Metadata *> &allGenericArgs) { auto generics = description->getGenericContext(); if (!generics) return; bool missingWrittenArguments = false; auto genericArgs = description->getGenericArguments(metadata); for (auto param : generics->getGenericParams()) { switch (param.getKind()) { case GenericParamKind::Type: // The type should have a key argument unless it's been same-typed to // another type. if (param.hasKeyArgument()) { auto genericArg = *genericArgs++; allGenericArgs.push_back(genericArg); } else { // Leave a gap for us to fill in by looking at same type info. allGenericArgs.push_back(nullptr); missingWrittenArguments = true; } // We don't know about type parameters with extra arguments. Leave // a hole for it. if (param.hasExtraArgument()) { allGenericArgs.push_back(nullptr); ++genericArgs; } break; default: // We don't know about this kind of parameter. Create placeholders where // needed. if (param.hasKeyArgument()) { allGenericArgs.push_back(nullptr); ++genericArgs; } if (param.hasExtraArgument()) { allGenericArgs.push_back(nullptr); ++genericArgs; } break; } } // If there is no follow-up work to do, we're done. if (!missingWrittenArguments) return; // We have generic arguments that would be written, but have been // canonicalized away. Use same-type requirements to reconstitute them. // Retrieve the mapping information needed for depth/index -> flat index. std::vector<unsigned> genericParamCounts; (void)_gatherGenericParameterCounts(description, genericParamCounts); // Walk through the generic requirements to evaluate same-type // constraints that are needed to fill in missing generic arguments. for (const auto &req : generics->getGenericRequirements()) { // We only care about same-type constraints. if (req.Flags.getKind() != GenericRequirementKind::SameType) continue; // Where the left-hand side is a generic parameter. if (req.Param.begin() != req.Param.end()) continue; // If we don't yet have an argument for this parameter, it's a // same-type-to-concrete constraint. unsigned lhsFlatIndex = req.Param.getRootParamIndex(); if (lhsFlatIndex >= allGenericArgs.size()) continue; if (!allGenericArgs[lhsFlatIndex]) { // Substitute into the right-hand side. SubstGenericParametersFromWrittenArgs substitutions(allGenericArgs, genericParamCounts); allGenericArgs[lhsFlatIndex] = _getTypeByMangledName(req.getMangledTypeName(), substitutions); continue; } // If we do have an argument for this parameter, it might be that // the right-hand side is itself a generic parameter, which means // we have a same-type constraint A == B where A is already filled in. Demangler demangler; NodePointer node = demangler.demangleType(req.getMangledTypeName()); if (!node) continue; // Find the flat index that the right-hand side refers to. if (node->getKind() == Demangle::Node::Kind::Type) node = node->getChild(0); if (node->getKind() != Demangle::Node::Kind::DependentGenericParamType) continue; auto rhsFlatIndex = _depthIndexToFlatIndex(node->getChild(0)->getIndex(), node->getChild(1)->getIndex(), genericParamCounts); if (!rhsFlatIndex || *rhsFlatIndex >= allGenericArgs.size()) continue; if (allGenericArgs[*rhsFlatIndex] || !allGenericArgs[lhsFlatIndex]) continue; allGenericArgs[*rhsFlatIndex] = allGenericArgs[lhsFlatIndex]; } }
NodePointer Demangle::stripGenericArgsFromContextNode(NodePointer node, NodeFactory &factory) { switch (node->getKind()) { case Demangle::Node::Kind::BoundGenericClass: case Demangle::Node::Kind::BoundGenericEnum: case Demangle::Node::Kind::BoundGenericStructure: case Demangle::Node::Kind::BoundGenericOtherNominalType: // Bound generic types have a 'Type' node under them, whose child is // the non-generic reference. If we don't see that structure, do nothing. if (node->getNumChildren() < 2 || node->getChild(0)->getKind() != Demangle::Node::Kind::Type || node->getChild(0)->getNumChildren() < 1) return node; // Strip generic arguments from that child, then return it. return stripGenericArgsFromContextNode(node->getChild(0)->getChild(0), factory); case Demangle::Node::Kind::Class: case Demangle::Node::Kind::Enum: case Demangle::Node::Kind::Structure: case Demangle::Node::Kind::OtherNominalType: { if (node->getNumChildren() < 2) return node; auto newContext = stripGenericArgsFromContextNode(node->getChild(0), factory); if (newContext == node->getChild(0)) return node; auto newNode = factory.createNode(node->getKind()); newNode->addChild(newContext, factory); for (unsigned i = 1, n = node->getNumChildren(); i != n; ++i) newNode->addChild(node->getChild(i), factory); return newNode; } case Demangle::Node::Kind::Extension: { // Strip generic arguments from the extended type. if (node->getNumChildren() < 2) return node; auto newExtended = stripGenericArgsFromContextNode(node->getChild(1), factory); if (newExtended == node->getChild(1)) return node; auto newNode = factory.createNode(Node::Kind::Extension); newNode->addChild(node->getChild(0), factory); newNode->addChild(newExtended, factory); if (node->getNumChildren() == 3) newNode->addChild(node->getChild(2), factory); return newNode; } case Demangle::Node::Kind::Module: // Modules terminate the recursion. return node; default: // FIXME: Handle local contexts. return node; } }