//===--- Mangler.cpp - Base class for Swift name mangling -----------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/Basic/Mangler.h" #include "swift/Demangling/Demangler.h" #include "swift/Demangling/Punycode.h" #include "swift/Demangling/ManglingMacros.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/CommandLine.h" #include using namespace swift; using namespace Mangle; #ifndef NDEBUG llvm::cl::opt PrintSwiftManglingStats( "print-swift-mangling-stats", llvm::cl::init(false), llvm::cl::desc("Print statistics about Swift symbol mangling")); namespace { struct SizeStatEntry { int sizeDiff; std::string Old; std::string New; }; static std::vector SizeStats; static int numSmaller = 0; static int numEqual = 0; static int numLarger = 0; static int totalOldSize = 0; static int totalNewSize = 0; static int mergedSubsts = 0; static int numLargeSubsts = 0; struct OpStatEntry { OpStatEntry() : num(0), size(0) { } int num; int size; }; static llvm::StringMap OpStats; } // end anonymous namespace void Mangler::recordOpStatImpl(StringRef op, size_t OldPos) { if (PrintSwiftManglingStats) { OpStatEntry &E = OpStats[op]; E.num++; E.size += Storage.size() - OldPos; } } #endif // NDEBUG void Mangle::printManglingStats() { #ifndef NDEBUG if (!PrintSwiftManglingStats) return; std::sort(SizeStats.begin(), SizeStats.end(), [](const SizeStatEntry &LHS, const SizeStatEntry &RHS) { return LHS.sizeDiff < RHS.sizeDiff; }); llvm::outs() << "Mangling size stats:\n" " num smaller: " << numSmaller << "\n" " num larger: " << numLarger << "\n" " num equal: " << numEqual << "\n" " total old size: " << totalOldSize << "\n" " total new size: " << totalNewSize << "\n" " new - old size: " << (totalNewSize - totalOldSize) << "\n" "List or larger:\n"; for (const SizeStatEntry &E : SizeStats) { llvm::outs() << " delta " << E.sizeDiff << ": " << E.Old << " - " << E.New << '\n'; } llvm::outs() << "Mangling operator stats:\n"; typedef llvm::StringMapEntry MapEntry; std::vector SortedOpStats; for (const MapEntry &ME : OpStats) { SortedOpStats.push_back(&ME); } std::sort(SortedOpStats.begin(), SortedOpStats.end(), [](const MapEntry *LHS, const MapEntry *RHS) { return LHS->getKey() < RHS->getKey(); }); for (const MapEntry *E : SortedOpStats) { llvm::outs() << " " << E->getKey() << ": num = " << E->getValue().num << ", size = " << E->getValue().size << '\n'; } llvm::outs() << " merged substitutions: " << mergedSubsts << "\n" " large substitutions: " << numLargeSubsts << "\n"; #endif } void Mangler::beginMangling() { Storage.clear(); Substitutions.clear(); StringSubstitutions.clear(); Words.clear(); SubstMerging.clear(); Buffer << MANGLING_PREFIX_STR; } /// Finish the mangling of the symbol and return the mangled name. std::string Mangler::finalize() { assert(Storage.size() && "Mangling an empty name"); std::string result = std::string(Storage.data(), Storage.size()); Storage.clear(); verify(result); return result; } /// Finish the mangling of the symbol and write the mangled name into /// \p stream. void Mangler::finalize(llvm::raw_ostream &stream) { std::string result = finalize(); stream.write(result.data(), result.size()); } static bool treeContains(Demangle::NodePointer Nd, Demangle::Node::Kind Kind) { if (Nd->getKind() == Kind) return true; for (auto Child : *Nd) { if (treeContains(Child, Kind)) return true; } return false; } void Mangler::verify(const std::string &mangledName) { #ifndef NDEBUG StringRef nameStr = mangledName; if (!nameStr.startswith(MANGLING_PREFIX_STR)) return; Demangler Dem; NodePointer Root = Dem.demangleSymbol(nameStr); if (!Root || treeContains(Root, Node::Kind::Suffix)) { llvm::errs() << "Can't demangle: " << nameStr << '\n'; abort(); } std::string Remangled = mangleNode(Root); if (Remangled == mangledName) return; if (treeContains(Root, Demangle::Node::Kind::DependentAssociatedTypeRef)) { // There are cases where dependent associated types results in different // remangled names. See ASTMangler::appendAssociatedTypeName. // This is no problem for the compiler, but we have to exclude this case // for the check. Instead we try to re-de-mangle the remangled name. nameStr = Remangled; NodePointer RootOfRemangled = Dem.demangleSymbol(nameStr); if (Remangled == mangleNode(RootOfRemangled)) return; } llvm::errs() << "Remangling failed:\n" "original = " << nameStr << "\n" "remangled = " << Remangled << '\n'; abort(); #endif } void Mangler::appendIdentifier(StringRef ident) { auto Iter = StringSubstitutions.find(ident); if (Iter != StringSubstitutions.end()) return mangleSubstitution(Iter->second); size_t OldPos = Storage.size(); addSubstitution(ident); mangleIdentifier(*this, ident); recordOpStat("", OldPos); } bool Mangler::tryMangleSubstitution(const void *ptr) { auto ir = Substitutions.find(ptr); if (ir == Substitutions.end()) return false; mangleSubstitution(ir->second); return true; } void Mangler::mangleSubstitution(unsigned Idx) { if (Idx >= 26) { #ifndef NDEBUG numLargeSubsts++; #endif return appendOperator("A", Index(Idx - 26)); } char Subst = Idx + 'A'; if (SubstMerging.tryMergeSubst(*this, Subst, /*isStandardSubst*/ false)) { #ifndef NDEBUG mergedSubsts++; #endif } else { appendOperator("A", StringRef(&Subst, 1)); } }