ldc/gen/mangling.cpp
2024-03-03 19:14:00 +01:00

197 lines
5.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- mangling.cpp ------------------------------------------------------===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
//
// Tries to centralize functionality for mangling of symbols.
//
//===----------------------------------------------------------------------===//
#include "gen/mangling.h"
#include "dmd/declaration.h"
#include "dmd/dsymbol.h"
#include "dmd/identifier.h"
#include "dmd/mangle.h"
#include "dmd/module.h"
#include "gen/abi/abi.h"
#include "gen/irstate.h"
#include "gen/to_string.h"
#include "llvm/Support/MD5.h"
using namespace dmd;
namespace {
// TODO: Disable hashing of symbols that are defined in libdruntime and
// libphobos. This would enable hashing thresholds below the largest symbol in
// libdruntime/phobos.
bool shouldHashAggrName(llvm::StringRef name) {
/// Add extra chars to the length of aggregate names to account for
/// the additional D mangling suffix and prefix
return (global.params.hashThreshold != 0) &&
((name.size() + 11) > global.params.hashThreshold);
}
llvm::SmallString<32> hashName(llvm::StringRef name) {
llvm::MD5 hasher;
hasher.update(name);
llvm::MD5::MD5Result result;
hasher.final(result);
llvm::SmallString<32> hashStr;
llvm::MD5::stringifyResult(result, hashStr);
return hashStr;
}
/// Hashes the symbol name and prefixes the hash with some recognizable parts of
/// the full symbol name. The prefixing means that the hashed name may be larger
/// than the input when identifiers are very long and the hash threshold is low.
/// Demangled hashed name is:
/// module.L<line_no>.<hash>.<top aggregate>.<identifier>
std::string hashSymbolName(llvm::StringRef name, Dsymbol *symb) {
std::string ret;
// module
{
auto moddecl = symb->getModule()->md;
assert(moddecl);
for (size_t i = 0; i < moddecl->packages.length; ++i) {
llvm::StringRef str = moddecl->packages.ptr[i]->toChars();
ret += ldc::to_string(str.size());
ret += str;
}
llvm::StringRef str = moddecl->id->toChars();
ret += ldc::to_string(str.size());
ret += str;
}
// source line number
auto lineNo = ldc::to_string(symb->loc.linnum());
ret += ldc::to_string(lineNo.size()+1);
ret += 'L';
ret += lineNo;
// MD5 hash
auto hashedName = hashName(name);
ret += "33_"; // add underscore to delimit the 33 character count
ret += hashedName;
// top aggregate
if (auto agg = symb->isMember()) {
llvm::StringRef topaggr = agg->ident->toChars();
ret += ldc::to_string(topaggr.size());
ret += topaggr;
}
// identifier
llvm::StringRef identifier = symb->toChars();
ret += ldc::to_string(identifier.size());
ret += identifier;
return ret;
}
}
std::string getIRMangledName(FuncDeclaration *fdecl, LINK link) {
std::string mangledName = mangleExact(fdecl);
if (fdecl->adFlags & 4) { // nounderscore
mangledName.insert(0, "\1");
}
// Hash the name if necessary
if (((link == LINK::d) || (link == LINK::default_)) &&
(global.params.hashThreshold != 0) &&
(mangledName.length() > global.params.hashThreshold)) {
auto hashedName = hashSymbolName(mangledName, fdecl);
mangledName = "_D" + hashedName + "Z";
}
// TODO: Cache the result?
return getIRMangledFuncName(std::move(mangledName), link);
}
std::string getIRMangledName(VarDeclaration *vd) {
OutBuffer mangleBuf;
mangleToBuffer(vd, mangleBuf);
// TODO: is hashing of variable names necessary?
// TODO: Cache the result?
return getIRMangledVarName(mangleBuf.peekChars(), vd->resolvedLinkage());
}
std::string getIRMangledFuncName(std::string baseMangle, LINK link) {
return baseMangle[0] == '\1'
? std::move(baseMangle)
: gABI->mangleFunctionForLLVM(std::move(baseMangle), link);
}
std::string getIRMangledVarName(std::string baseMangle, LINK link) {
return baseMangle[0] == '\1'
? std::move(baseMangle)
: gABI->mangleVariableForLLVM(std::move(baseMangle), link);
}
std::string getIRMangledAggregateName(AggregateDeclaration *ad,
const char *suffix) {
std::string ret = "_D";
OutBuffer mangleBuf;
mangleToBuffer(ad, mangleBuf);
llvm::StringRef mangledAggrName = mangleBuf.peekChars();
if (shouldHashAggrName(mangledAggrName)) {
ret += hashSymbolName(mangledAggrName, ad);
} else {
ret += mangledAggrName;
}
if (suffix)
ret += suffix;
return getIRMangledVarName(std::move(ret), LINK::d);
}
std::string getIRMangledInitSymbolName(AggregateDeclaration *aggrdecl) {
return getIRMangledAggregateName(aggrdecl, "6__initZ");
}
std::string getIRMangledVTableSymbolName(AggregateDeclaration *aggrdecl) {
return getIRMangledAggregateName(aggrdecl, "6__vtblZ");
}
std::string getIRMangledClassInfoSymbolName(AggregateDeclaration *aggrdecl) {
const char *suffix =
aggrdecl->isInterfaceDeclaration() ? "11__InterfaceZ" : "7__ClassZ";
return getIRMangledAggregateName(aggrdecl, suffix);
}
std::string getIRMangledInterfaceInfosSymbolName(ClassDeclaration *cd) {
OutBuffer mangledName;
mangledName.writestring("_D");
mangleToBuffer(cd, mangledName);
mangledName.writestring("16__interfaceInfosZ");
return getIRMangledVarName(mangledName.peekChars(), LINK::d);
}
std::string getIRMangledModuleInfoSymbolName(Module *module) {
OutBuffer mangledName;
mangledName.writestring("_D");
mangleToBuffer(module, mangledName);
mangledName.writestring("12__ModuleInfoZ");
return getIRMangledVarName(mangledName.peekChars(), LINK::d);
}
std::string getIRMangledModuleRefSymbolName(const char *moduleMangle) {
return getIRMangledVarName(
(llvm::Twine("_D") + moduleMangle + "11__moduleRefZ").str(), LINK::d);
}