bool Context::isThunkSymbol(llvm::StringRef MangledName) { if (isMangledName(MangledName)) { // First do a quick check if (MangledName.endswith("TA") || // partial application forwarder MangledName.endswith("Ta") || // ObjC partial application forwarder MangledName.endswith("To") || // swift-as-ObjC thunk MangledName.endswith("TO") || // ObjC-as-swift thunk MangledName.endswith("TR") || // reabstraction thunk helper function MangledName.endswith("Tr") || // reabstraction thunk MangledName.endswith("TW") || // protocol witness thunk MangledName.endswith("fC")) { // allocating constructor // To avoid false positives, we need to fully demangle the symbol. NodePointer Nd = D->demangleSymbol(MangledName); if (!Nd || Nd->getKind() != Node::Kind::Global || Nd->getNumChildren() == 0) return false; switch (Nd->getFirstChild()->getKind()) { case Node::Kind::ObjCAttribute: case Node::Kind::NonObjCAttribute: case Node::Kind::PartialApplyObjCForwarder: case Node::Kind::PartialApplyForwarder: case Node::Kind::ReabstractionThunkHelper: case Node::Kind::ReabstractionThunk: case Node::Kind::ProtocolWitness: case Node::Kind::Allocator: return true; default: break; } } return false; } if (MangledName.startswith("_T")) { // Old mangling. StringRef Remaining = MangledName.substr(2); if (Remaining.startswith("To") || // swift-as-ObjC thunk Remaining.startswith("TO") || // ObjC-as-swift thunk Remaining.startswith("PA_") || // partial application forwarder Remaining.startswith("PAo_")) { // ObjC partial application forwarder return true; } } return false; }
// 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; } }