Files
swift-mirror/lib/Basic/Mangler.cpp
Erik Eckstein 684092d7d1 Mangling: mangler, demangler and remangler classes for the new mangling scheme.
Following classes provide symbol mangling for specific purposes:
*) Mangler: the base mangler class, just providing some basic utilities
*) ASTMangler: for mangling AST declarations
*) SpecializationMangler: to be used in the optimizer for mangling specialized function names
*) IRGenMangler: mangling all kind of symbols in IRGen

All those classes are not used yet, so it’s basically a NFC.

Another change is that some demangler node types are added (either because they were missing or the new demangler needs them).
Those new nodes also need to be handled in the old demangler, but this should also be a NFC as those nodes are not created by the old demangler.

My plan is to keep the old and new mangling implementation in parallel for some time. After that we can remove the old mangler.
Currently the new implementation is scoped in the NewMangling namespace. This namespace should be renamed after the old mangler is removed.
2016-12-02 15:55:30 -08:00

319 lines
9.0 KiB
C++

//===--- Mangler.cpp - Base class for Swift name mangling -----------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#define CHECK_MANGLING_AGAINST_OLD
#include "swift/Basic/Mangler.h"
#include "swift/Basic/Punycode.h"
#include "swift/Basic/ManglingMacros.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/CommandLine.h"
#ifdef CHECK_MANGLING_AGAINST_OLD
#include "swift/Basic/Demangle.h"
#include "swift/Basic/DemangleWrappers.h"
#endif
#include <algorithm>
using namespace swift;
using namespace NewMangling;
bool NewMangling::useNewMangling() {
#ifdef USE_NEW_MANGLING
return true;
#else
return false;
#endif
}
#ifndef NDEBUG
llvm::cl::opt<bool> PrintSwiftManglingStats(
"print-swift-mangling-stats", llvm::cl::init(false),
llvm::cl::desc("Print statistics about Swift symbol mangling"));
namespace {
#ifdef CHECK_MANGLING_AGAINST_OLD
static bool areTreesEqual(Demangle::NodePointer Old, Demangle::NodePointer New) {
if ((Old != nullptr) != (New != nullptr))
return false;
if (!Old)
return true;
if (Old->getKind() == Demangle::Node::Kind::CurryThunk)
Old = Old->getFirstChild();
if (New->getKind() == Demangle::Node::Kind::CurryThunk)
New = New->getFirstChild();
if (Old->getKind() != New->getKind()) {
if (Old->getKind() != Demangle::Node::Kind::UncurriedFunctionType ||
New->getKind() != Demangle::Node::Kind::FunctionType)
return false;
}
if (Old->hasText() != New->hasText())
return false;
if (Old->hasIndex() != New->hasIndex())
return false;
if (Old->hasText() && Old->getText() != New->getText())
return false;
if (Old->hasIndex() && Old->getIndex() != New->getIndex())
return false;
size_t OldNum = Old->getNumChildren();
size_t NewNum = New->getNumChildren();
if (OldNum >= 1 && NewNum == 1 &&
Old->getChild(OldNum - 1)->getKind() == Demangle::Node::Kind::Suffix) {
switch (New->getFirstChild()->getKind()) {
case Demangle::Node::Kind::ReflectionMetadataBuiltinDescriptor:
case Demangle::Node::Kind::ReflectionMetadataFieldDescriptor:
case Demangle::Node::Kind::ReflectionMetadataAssocTypeDescriptor:
case Demangle::Node::Kind::ReflectionMetadataSuperclassDescriptor:
return true;
default:
return false;
}
}
if (Old->getKind() == Demangle::Node::Kind::DependentAssociatedTypeRef &&
OldNum + NewNum == 1) {
OldNum = 0;
NewNum = 0;
}
if (Old->getKind() == Demangle::Node::Kind::GenericSpecializationParam &&
OldNum > 1 && NewNum == 1)
OldNum = 1;
if (OldNum != NewNum) {
return false;
}
for (unsigned Idx = 0, End = OldNum; Idx < End; ++Idx) {
if (!areTreesEqual(Old->getChild(Idx), New->getChild(Idx)))
return false;
}
return true;
}
static bool containsDependentAssociatedTypeRef(Demangle::NodePointer Nd) {
if (Nd->getKind() == Demangle::Node::Kind::DependentAssociatedTypeRef)
return true;
for (auto Child : *Nd) {
if (containsDependentAssociatedTypeRef(Child))
return true;
}
return false;
}
#endif // CHECK_MANGLING_AGAINST_OLD
struct SizeStatEntry {
int sizeDiff;
std::string Old;
std::string New;
};
static std::vector<SizeStatEntry> 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;
struct OpStatEntry {
OpStatEntry() : num(0), size(0) { }
int num;
int size;
};
static llvm::StringMap<OpStatEntry> 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
std::string NewMangling::selectMangling(const std::string &Old,
const std::string &New) {
#ifndef NDEBUG
#ifdef CHECK_MANGLING_AGAINST_OLD
static int numCmp = 0;
using namespace Demangle;
NodePointer OldNode = demangleSymbolAsNode(Old);
NodePointer NewNode = demangleSymbolAsNode(New);
if (OldNode) {
if (!areTreesEqual(OldNode, NewNode)) {
llvm::errs() << "Mangling differs at #" << numCmp << ":\n"
"old: " << Old << "\n"
"new: " << New << "\n\n"
"### old tree: ###\n";
demangle_wrappers::NodeDumper(OldNode).print(llvm::errs());
llvm::errs() << "\n### new tree: ###\n";
demangle_wrappers::NodeDumper(NewNode).print(llvm::errs());
llvm::errs() << '\n';
assert(false);
}
if (StringRef(New).startswith(MANGLING_PREFIX_STR)) {
std::string Remangled = mangleNodeNew(NewNode);
if (New != Remangled) {
bool isEqual = false;
if (containsDependentAssociatedTypeRef(NewNode)) {
NodePointer RemangledNode = demangleSymbolAsNode(Remangled);
isEqual = areTreesEqual(RemangledNode, NewNode);
}
if (!isEqual) {
llvm::errs() << "Remangling failed at #" << numCmp << ":\n"
"original: " << New << "\n"
"remangled: " << Remangled << "\n";
assert(false);
}
}
}
}
numCmp++;
#endif // CHECK_MANGLING_AGAINST_OLD
if (PrintSwiftManglingStats) {
int OldSize = (int)Old.size();
int NewSize = (int)New.size();
if (NewSize > OldSize) {
numLarger++;
SizeStats.push_back({NewSize - OldSize, Old, New});
} else if (OldSize > NewSize) {
numSmaller++;
} else {
numEqual++;
}
totalOldSize += OldSize;
totalNewSize += NewSize;
}
#endif // NDEBUG
return useNewMangling() ? New : Old;
}
void NewMangling::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<OpStatEntry> MapEntry;
std::vector<const MapEntry *> 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';
#endif
}
void Mangler::beginMangling() {
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();
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());
}
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("<identifier>", 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)
return appendOperator("A", Index(Idx - 26));
char c = Idx + 'A';
if (lastSubstIdx == (int)Storage.size() - 1) {
assert(isUpperLetter(Storage[lastSubstIdx]));
Storage[lastSubstIdx] = Storage[lastSubstIdx] - 'A' + 'a';
Buffer << c;
#ifndef NDEBUG
mergedSubsts++;
#endif
} else {
appendOperator("A", StringRef(&c, 1));
}
lastSubstIdx = (int)Storage.size() - 1;
}