mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
of associated types in protocol witness tables. We use the global access functions when the result isn't dependent, and a simple accessor when the result can be cheaply recovered from the conforming metadata. Otherwise, we add a cache slot to a private section of the witness table, forcing an instantiation per conformance. Like generic type metadata, concrete instantiations of generic conformances are memoized. There's a fair amount of code in this patch that can't be dynamically tested at the moment because of the widespread reliance on recursive expansion of archetypes / dependent types. That's something we're now theoretically in a position to change, and as we do so, we'll test more of this code.
1605 lines
46 KiB
C++
1605 lines
46 KiB
C++
//===--- Remangle.cpp - Swift re-mangling from a demangling tree ---------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 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
|
|
//
|
|
//===---------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the remangler, which turns a demangling parse
|
|
// tree back into a mangled string. This is useful for tools which
|
|
// want to extract subtrees from mangled strings.
|
|
//
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
#include "swift/Basic/Demangle.h"
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "swift/Basic/Punycode.h"
|
|
#include "swift/Basic/Range.h"
|
|
#include "swift/Basic/UUID.h"
|
|
#include "swift/Strings.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include <vector>
|
|
#include <cstdlib>
|
|
#include <unordered_map>
|
|
|
|
using namespace swift;
|
|
using namespace Demangle;
|
|
|
|
[[noreturn]]
|
|
static void unreachable(const char *Message) {
|
|
fprintf(stderr, "fatal error: %s\n", Message);
|
|
std::abort();
|
|
}
|
|
|
|
/// Translate the given operator character into its mangled form.
|
|
///
|
|
/// Current operator characters: @/=-+*%<>!&|^~ and the special operator '..'
|
|
static char mangleOperatorChar(char op) {
|
|
switch (op) {
|
|
case '&': return 'a'; // 'and'
|
|
case '@': return 'c'; // 'commercial at sign'
|
|
case '/': return 'd'; // 'divide'
|
|
case '=': return 'e'; // 'equal'
|
|
case '>': return 'g'; // 'greater'
|
|
case '<': return 'l'; // 'less'
|
|
case '*': return 'm'; // 'multiply'
|
|
case '!': return 'n'; // 'negate'
|
|
case '|': return 'o'; // 'or'
|
|
case '+': return 'p'; // 'plus'
|
|
case '?': return 'q'; // 'question'
|
|
case '%': return 'r'; // 'remainder'
|
|
case '-': return 's'; // 'subtract'
|
|
case '~': return 't'; // 'tilde'
|
|
case '^': return 'x'; // 'xor'
|
|
case '.': return 'z'; // 'zperiod' (the z is silent)
|
|
default:
|
|
return op;
|
|
}
|
|
}
|
|
|
|
static bool isNonAscii(StringRef str) {
|
|
for (unsigned char c : str) {
|
|
if (c >= 0x80)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void mangleIdentifier(StringRef ident, OperatorKind operatorKind,
|
|
bool usePunycode, DemanglerPrinter &out) {
|
|
std::string punycodeBuf;
|
|
if (usePunycode) {
|
|
// If the identifier contains non-ASCII character, we mangle
|
|
// with an initial X and Punycode the identifier string.
|
|
if (isNonAscii(ident)) {
|
|
out << 'X';
|
|
Punycode::encodePunycodeUTF8(ident, punycodeBuf);
|
|
ident = punycodeBuf;
|
|
}
|
|
}
|
|
|
|
// Mangle normal identifiers as
|
|
// count identifier-char+
|
|
// where the count is the number of characters in the identifier,
|
|
// and where individual identifier characters represent themselves.
|
|
if (operatorKind == OperatorKind::NotOperator) {
|
|
out << ident.size() << ident;
|
|
return;
|
|
}
|
|
|
|
// Mangle operator identifiers as
|
|
// operator ::= 'o' operator-fixity count operator-char+
|
|
// operator-fixity ::= 'p' // prefix
|
|
// operator-fixity ::= 'P' // postfix
|
|
// operator-fixity ::= 'i' // infix
|
|
// where the count is the number of characters in the operator,
|
|
// and where the individual operator characters are translated.
|
|
out << 'o' << [=] {
|
|
switch (operatorKind) {
|
|
case OperatorKind::NotOperator: unreachable("invalid");
|
|
case OperatorKind::Infix: return 'i';
|
|
case OperatorKind::Prefix: return 'p';
|
|
case OperatorKind::Postfix: return 'P';
|
|
}
|
|
unreachable("invalid");
|
|
}();
|
|
|
|
// Mangle ASCII operators directly.
|
|
out << ident.size();
|
|
for (char ch : ident) {
|
|
out << mangleOperatorChar(ch);
|
|
}
|
|
}
|
|
|
|
void Demangle::mangleIdentifier(const char *data, size_t length,
|
|
OperatorKind operatorKind,
|
|
std::string &out, bool usePunycode) {
|
|
DemanglerPrinter printer(out);
|
|
return ::mangleIdentifier(StringRef(data, length), operatorKind,
|
|
usePunycode, printer);
|
|
}
|
|
|
|
namespace {
|
|
struct DeepHasher {
|
|
size_t value = 0;
|
|
|
|
void combine(size_t newValue) {
|
|
value = 33 * value + newValue;
|
|
}
|
|
|
|
void hash(Node *node) {
|
|
combine((size_t) node->getKind());
|
|
if (node->hasIndex()) {
|
|
combine(node->getIndex());
|
|
} else if (node->hasText()) {
|
|
StringRef text = node->getText();
|
|
for (char c : text) {
|
|
combine((unsigned char) c);
|
|
}
|
|
}
|
|
for (const auto &child : *node) {
|
|
hash(child.get());
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
static size_t deepHash(Node *node) {
|
|
DeepHasher hasher;
|
|
hasher.hash(node);
|
|
return hasher.value;
|
|
}
|
|
|
|
static bool deepEquals(Node *lhs, Node *rhs) {
|
|
if (lhs->getKind() != rhs->getKind())
|
|
return false;
|
|
if (lhs->hasIndex()) {
|
|
if (!rhs->hasIndex())
|
|
return false;
|
|
if (lhs->getIndex() != rhs->getIndex())
|
|
return false;
|
|
} else if (lhs->hasText()) {
|
|
if (!rhs->hasText())
|
|
return false;
|
|
if (lhs->getText() != rhs->getText())
|
|
return false;
|
|
} else if (rhs->hasIndex() || rhs->hasText()) {
|
|
return false;
|
|
}
|
|
|
|
if (lhs->getNumChildren() != rhs->getNumChildren())
|
|
return false;
|
|
|
|
for (auto li = lhs->begin(), ri = lhs->begin(), le = lhs->end();
|
|
li != le; ++li, ++ri) {
|
|
if (!deepEquals(li->get(), ri->get()))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
namespace {
|
|
struct SubstitutionEntry {
|
|
Node *TheNode;
|
|
size_t StoredHash;
|
|
|
|
// Note that the constructor leaves this uninitialized.
|
|
|
|
struct Hasher {
|
|
size_t operator()(const SubstitutionEntry &entry) const {
|
|
return entry.StoredHash;
|
|
}
|
|
};
|
|
friend bool operator==(const SubstitutionEntry &lhs,
|
|
const SubstitutionEntry &rhs) {
|
|
return (lhs.StoredHash == rhs.StoredHash &&
|
|
deepEquals(lhs.TheNode, lhs.TheNode));
|
|
}
|
|
};
|
|
|
|
class Remangler {
|
|
struct ArchetypeInfo {
|
|
Node::IndexType Index;
|
|
Node::IndexType AbsoluteDepth;
|
|
};
|
|
|
|
DemanglerPrinter &Out;
|
|
std::unordered_map<std::string, ArchetypeInfo> Archetypes;
|
|
unsigned AbsoluteArchetypeDepth = 0;
|
|
|
|
std::unordered_map<SubstitutionEntry, unsigned,
|
|
SubstitutionEntry::Hasher> Substitutions;
|
|
public:
|
|
Remangler(DemanglerPrinter &out) : Out(out) {}
|
|
|
|
class EntityContext {
|
|
Remangler &R;
|
|
unsigned SavedAbsoluteDepth;
|
|
bool AsContext = false;
|
|
public:
|
|
EntityContext(Remangler &R)
|
|
: R(R), SavedAbsoluteDepth(R.AbsoluteArchetypeDepth) {
|
|
}
|
|
|
|
~EntityContext() {
|
|
assert(R.AbsoluteArchetypeDepth >= SavedAbsoluteDepth);
|
|
R.AbsoluteArchetypeDepth = SavedAbsoluteDepth;
|
|
}
|
|
|
|
bool isAsContext() const {
|
|
return AsContext;
|
|
}
|
|
|
|
class ManglingContextRAII {
|
|
EntityContext &Ctx;
|
|
bool SavedValue;
|
|
public:
|
|
ManglingContextRAII(EntityContext &ctx)
|
|
: Ctx(ctx), SavedValue(ctx.AsContext) {
|
|
ctx.AsContext = true;
|
|
}
|
|
|
|
~ManglingContextRAII() {
|
|
Ctx.AsContext = SavedValue;
|
|
}
|
|
};
|
|
};
|
|
|
|
void mangle(Node *node) {
|
|
switch (node->getKind()) {
|
|
#define NODE(ID) case Node::Kind::ID: return mangle##ID(node);
|
|
#include "swift/Basic/DemangleNodes.def"
|
|
}
|
|
unreachable("bad demangling tree node");
|
|
}
|
|
|
|
#define NODE(ID) \
|
|
void mangle##ID(Node *node);
|
|
#define CONTEXT_NODE(ID) \
|
|
void mangle##ID(Node *node); \
|
|
void mangle##ID(Node *node, EntityContext &ctx);
|
|
#include "swift/Basic/DemangleNodes.def"
|
|
|
|
void mangleIndex(Node::IndexType index);
|
|
void mangleIdentifier(StringRef name, OperatorKind operatorKind);
|
|
|
|
void mangleChildNodes(Node *node) { mangleNodes(node->begin(), node->end()); }
|
|
void mangleNodes(Node::iterator i, Node::iterator e) {
|
|
for (; i != e; ++i) {
|
|
mangle(i->get());
|
|
}
|
|
}
|
|
void mangleSingleChildNode(Node *node) {
|
|
assert(node->getNumChildren() == 1);
|
|
mangle(node->begin()->get());
|
|
}
|
|
void mangleChildNode(Node *node, unsigned index) {
|
|
assert(index < node->getNumChildren());
|
|
mangle(node->begin()[index].get());
|
|
}
|
|
|
|
void mangleSimpleEntity(Node *node, char basicKind, StringRef entityKind,
|
|
EntityContext &ctx);
|
|
void mangleNamedEntity(Node *node, char basicKind, StringRef entityKind,
|
|
EntityContext &ctx);
|
|
void mangleTypedEntity(Node *node, char basicKind, StringRef entityKind,
|
|
EntityContext &ctx);
|
|
void mangleNamedAndTypedEntity(Node *node, char basicKind,
|
|
StringRef entityKind,
|
|
EntityContext &ctx);
|
|
void mangleNominalType(Node *node, char basicKind, EntityContext &ctx);
|
|
|
|
void mangleProtocolWithoutPrefix(Node *node);
|
|
void mangleProtocolListWithoutPrefix(Node *node);
|
|
|
|
void mangleEntityContext(Node *node, EntityContext &ctx);
|
|
void mangleEntityType(Node *node, EntityContext &ctx);
|
|
void mangleEntityGenericType(Node *node, EntityContext &ctx);
|
|
void mangleGenerics(Node *node, EntityContext &ctx);
|
|
|
|
bool trySubstitution(Node *node, SubstitutionEntry &entry);
|
|
void addSubstitution(const SubstitutionEntry &entry);
|
|
void resetSubstitutions();
|
|
|
|
void mangleDependentGenericParamIndex(Node *node);
|
|
void mangleConstrainedType(Node *node);
|
|
};
|
|
}
|
|
|
|
#define NODE(ID)
|
|
#define CONTEXT_NODE(ID) \
|
|
void Remangler::mangle##ID(Node *node) { \
|
|
EntityContext ctx(*this); \
|
|
mangle##ID(node, ctx); \
|
|
}
|
|
#include "swift/Basic/DemangleNodes.def"
|
|
|
|
/// Reset the currently-active set of substitutions. This is useful
|
|
/// when part of the mangling is done independently, e.g. when an
|
|
/// optimization pass modifies a pass.
|
|
void Remangler::resetSubstitutions() {
|
|
Substitutions.clear();
|
|
}
|
|
|
|
bool Remangler::trySubstitution(Node *node, SubstitutionEntry &entry) {
|
|
auto isInSwiftModule = [](Node *node) -> bool {
|
|
auto context = node->begin()->get();
|
|
return (context->getKind() == Node::Kind::Module &&
|
|
context->getText() == STDLIB_NAME);
|
|
};
|
|
|
|
// Look for known substitutions.
|
|
switch (node->getKind()) {
|
|
#define SUCCESS_IF_IS(VALUE, EXPECTED, SUBSTITUTION) \
|
|
do { \
|
|
if ((VALUE) == (EXPECTED)) { \
|
|
Out << SUBSTITUTION; \
|
|
return true; \
|
|
} \
|
|
} while (0)
|
|
#define SUCCESS_IF_TEXT_IS(EXPECTED, SUBSTITUTION) \
|
|
SUCCESS_IF_IS(node->getText(), EXPECTED, SUBSTITUTION)
|
|
#define SUCCESS_IF_DECLNAME_IS(EXPECTED, SUBSTITUTION) \
|
|
SUCCESS_IF_IS(node->getChild(1)->getText(), EXPECTED, SUBSTITUTION)
|
|
|
|
case Node::Kind::Module:
|
|
SUCCESS_IF_TEXT_IS(STDLIB_NAME, "s");
|
|
SUCCESS_IF_TEXT_IS(MANGLING_MODULE_OBJC, "So");
|
|
SUCCESS_IF_TEXT_IS(MANGLING_MODULE_C, "SC");
|
|
break;
|
|
case Node::Kind::Structure:
|
|
if (isInSwiftModule(node)) {
|
|
SUCCESS_IF_DECLNAME_IS("Array", "Sa");
|
|
SUCCESS_IF_DECLNAME_IS("Bool", "Sb");
|
|
SUCCESS_IF_DECLNAME_IS("UnicodeScalar", "Sc");
|
|
SUCCESS_IF_DECLNAME_IS("Double", "Sd");
|
|
SUCCESS_IF_DECLNAME_IS("Float", "Sf");
|
|
SUCCESS_IF_DECLNAME_IS("Int", "Si");
|
|
SUCCESS_IF_DECLNAME_IS("UnsafePointer", "SP");
|
|
SUCCESS_IF_DECLNAME_IS("UnsafeMutablePointer", "Sp");
|
|
SUCCESS_IF_DECLNAME_IS("UnsafeBufferPointer", "SR");
|
|
SUCCESS_IF_DECLNAME_IS("UnsafeMutableBufferPointer", "Sr");
|
|
SUCCESS_IF_DECLNAME_IS("String", "SS");
|
|
SUCCESS_IF_DECLNAME_IS("UInt", "Su");
|
|
}
|
|
break;
|
|
case Node::Kind::Enum:
|
|
if (isInSwiftModule(node)) {
|
|
SUCCESS_IF_DECLNAME_IS("Optional", "Sq");
|
|
SUCCESS_IF_DECLNAME_IS("ImplicitlyUnwrappedOptional", "SQ");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
#undef SUCCESS_IF_DECLNAME_IS
|
|
#undef SUCCESS_IF_TEXT_IS
|
|
#undef SUCCESS_IF_IS
|
|
}
|
|
|
|
// Go ahead and initialize the substitution entry.
|
|
entry.TheNode = node;
|
|
entry.StoredHash = deepHash(node);
|
|
|
|
auto it = Substitutions.find(entry);
|
|
if (it == Substitutions.end())
|
|
return false;
|
|
|
|
Out << 'S';
|
|
mangleIndex(it->second);
|
|
return true;
|
|
}
|
|
|
|
void Remangler::addSubstitution(const SubstitutionEntry &entry) {
|
|
auto result = Substitutions.insert({entry, Substitutions.size()});
|
|
assert(result.second);
|
|
(void) result;
|
|
}
|
|
|
|
void Remangler::mangleIdentifier(Node *node) {
|
|
mangleIdentifier(node->getText(), OperatorKind::NotOperator);
|
|
}
|
|
void Remangler::manglePrefixOperator(Node *node) {
|
|
mangleIdentifier(node->getText(), OperatorKind::Prefix);
|
|
}
|
|
void Remangler::manglePostfixOperator(Node *node) {
|
|
mangleIdentifier(node->getText(), OperatorKind::Postfix);
|
|
}
|
|
void Remangler::mangleInfixOperator(Node *node) {
|
|
mangleIdentifier(node->getText(), OperatorKind::Infix);
|
|
}
|
|
void Remangler::mangleIdentifier(StringRef ident, OperatorKind operatorKind) {
|
|
::mangleIdentifier(ident, operatorKind, /*usePunycode*/ true, Out);
|
|
}
|
|
|
|
void Remangler::mangleNumber(Node *node) {
|
|
mangleIndex(node->getIndex());
|
|
}
|
|
void Remangler::mangleIndex(Node::IndexType value) {
|
|
if (value == 0) {
|
|
Out << '_';
|
|
} else {
|
|
Out << (value - 1) << '_';
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleGlobal(Node *node) {
|
|
Out << "_T";
|
|
mangleChildNodes(node);
|
|
}
|
|
|
|
void Remangler::mangleSuffix(Node *node) {
|
|
// Just add the suffix back on.
|
|
Out << node->getText();
|
|
}
|
|
|
|
void Remangler::mangleGenericSpecialization(Node *node) {
|
|
Out << "TSg";
|
|
mangleChildNodes(node); // GenericSpecializationParams
|
|
|
|
// Specializations are just prepended to already-mangled names.
|
|
resetSubstitutions();
|
|
|
|
// Start another mangled name.
|
|
Out << "__T";
|
|
}
|
|
void Remangler::mangleGenericSpecializationParam(Node *node) {
|
|
// Should be a type followed by a series of protocol conformances.
|
|
mangleChildNodes(node);
|
|
Out << '_';
|
|
}
|
|
|
|
void Remangler::mangleFunctionSignatureSpecialization(Node *node) {
|
|
Out << "TSf";
|
|
mangleChildNodes(node); // FunctionSignatureSpecializationParams
|
|
|
|
// Specializations are just prepended to already-mangled names.
|
|
resetSubstitutions();
|
|
|
|
// Start another mangled name.
|
|
Out << "__T";
|
|
}
|
|
|
|
void Remangler::mangleSpecializationPassID(Node *node) {
|
|
Out << node->getIndex();
|
|
}
|
|
|
|
void Remangler::mangleFunctionSignatureSpecializationParam(Node *node) {
|
|
if (!node->hasChildren()) {
|
|
Out << "n_";
|
|
return;
|
|
}
|
|
|
|
// The first child is always a kind that specifies the type of param that we
|
|
// have.
|
|
NodePointer firstChild = node->getChild(0);
|
|
unsigned kindValue = firstChild->getIndex();
|
|
auto kind = FunctionSigSpecializationParamKind(kindValue);
|
|
|
|
switch (kind) {
|
|
case FunctionSigSpecializationParamKind::ConstantPropFunction:
|
|
Out << "cpfr";
|
|
mangleIdentifier(node->getChild(1).get());
|
|
Out << '_';
|
|
return;
|
|
case FunctionSigSpecializationParamKind::ConstantPropGlobal:
|
|
Out << "cpg";
|
|
mangleIdentifier(node->getChild(1).get());
|
|
Out << '_';
|
|
return;
|
|
case FunctionSigSpecializationParamKind::ConstantPropInteger:
|
|
Out << "cpi" << node->getChild(1)->getText() << '_';
|
|
return;
|
|
case FunctionSigSpecializationParamKind::ConstantPropFloat:
|
|
Out << "cpfl" << node->getChild(1)->getText() << '_';
|
|
return;
|
|
case FunctionSigSpecializationParamKind::ConstantPropString: {
|
|
Out << "cpse";
|
|
StringRef encodingStr = node->getChild(1)->getText();
|
|
if (encodingStr == "u8")
|
|
Out << '0';
|
|
else if (encodingStr == "u16")
|
|
Out << '1';
|
|
else
|
|
unreachable("Unknown encoding");
|
|
Out << 'v';
|
|
mangleIdentifier(node->getChild(2).get());
|
|
Out << '_';
|
|
return;
|
|
}
|
|
case FunctionSigSpecializationParamKind::ClosureProp:
|
|
Out << "cl";
|
|
mangleIdentifier(node->getChild(1).get());
|
|
for (unsigned i = 2, e = node->getNumChildren(); i != e; ++i) {
|
|
mangleType(node->getChild(i).get());
|
|
}
|
|
Out << '_';
|
|
return;
|
|
case FunctionSigSpecializationParamKind::BoxToValue:
|
|
Out << "i_";
|
|
return;
|
|
case FunctionSigSpecializationParamKind::BoxToStack:
|
|
Out << "k_";
|
|
return;
|
|
default:
|
|
if (kindValue &
|
|
unsigned(FunctionSigSpecializationParamKind::Dead))
|
|
Out << 'd';
|
|
if (kindValue &
|
|
unsigned(FunctionSigSpecializationParamKind::OwnedToGuaranteed))
|
|
Out << 'g';
|
|
if (kindValue & unsigned(FunctionSigSpecializationParamKind::SROA))
|
|
Out << 's';
|
|
Out << '_';
|
|
return;
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleFunctionSignatureSpecializationParamPayload(Node *node) {
|
|
// This should never be called since mangling parameter payloads require
|
|
// knowing what the parameter kind is.
|
|
unreachable("This should never be called");
|
|
}
|
|
|
|
void Remangler::mangleFunctionSignatureSpecializationParamKind(Node *node) {
|
|
// This should never be called since mangling parameter kinds have influence
|
|
// on the payloads.
|
|
unreachable("This should never be called");
|
|
}
|
|
|
|
void Remangler::mangleProtocolConformance(Node *node) {
|
|
// type, protocol name, context
|
|
assert(node->getNumChildren() == 3);
|
|
mangleChildNode(node, 0);
|
|
mangleProtocolWithoutPrefix(node->begin()[1].get());
|
|
mangleChildNode(node, 2);
|
|
}
|
|
|
|
void Remangler::mangleObjCAttribute(Node *node) {
|
|
Out << "To";
|
|
}
|
|
|
|
void Remangler::mangleNonObjCAttribute(Node *node) {
|
|
Out << "TO";
|
|
}
|
|
|
|
void Remangler::mangleDirectMethodReferenceAttribute(Node *node) {
|
|
Out << "Td";
|
|
}
|
|
|
|
void Remangler::mangleDynamicAttribute(Node *node) {
|
|
Out << "TD";
|
|
}
|
|
|
|
void Remangler::mangleVTableAttribute(Node *node) {
|
|
Out << "TV";
|
|
}
|
|
|
|
void Remangler::mangleGenericTypeMetadataPattern(Node *node) {
|
|
Out << "MP";
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleTypeMetadataAccessFunction(Node *node) {
|
|
Out << "Ma";
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleTypeMetadataLazyCache(Node *node) {
|
|
Out << "ML";
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleMetaclass(Node *node) {
|
|
Out << "Mm";
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleNominalTypeDescriptor(Node *node) {
|
|
Out << "Mn";
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleTypeMetadata(Node *node) {
|
|
Out << "M";
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleFullTypeMetadata(Node *node) {
|
|
Out << "Mf";
|
|
mangleChildNodes(node); // type
|
|
}
|
|
|
|
void Remangler::mangleProtocolDescriptor(Node *node) {
|
|
Out << "Mp";
|
|
mangleProtocolWithoutPrefix(node->begin()[0].get());
|
|
}
|
|
|
|
void Remangler::manglePartialApplyForwarder(Node *node) {
|
|
Out << "PA__T";
|
|
mangleSingleChildNode(node); // global
|
|
}
|
|
|
|
void Remangler::manglePartialApplyObjCForwarder(Node *node) {
|
|
Out << "PAo__T";
|
|
mangleSingleChildNode(node); // global
|
|
}
|
|
|
|
void Remangler::mangleDirectness(Node *node) {
|
|
auto getChar = [](Directness d) -> char {
|
|
switch (d) {
|
|
case Directness::Direct: return 'd';
|
|
case Directness::Indirect: return 'i';
|
|
}
|
|
unreachable("bad directness kind");
|
|
};
|
|
Out << getChar(Directness(node->getIndex()));
|
|
}
|
|
|
|
void Remangler::mangleValueWitness(Node *node) {
|
|
auto getString = [](ValueWitnessKind kind) -> StringRef {
|
|
switch (kind) {
|
|
case ValueWitnessKind::AllocateBuffer: return "al";
|
|
case ValueWitnessKind::AssignWithCopy: return "ca";
|
|
case ValueWitnessKind::AssignWithTake: return "ta";
|
|
case ValueWitnessKind::DeallocateBuffer: return "de";
|
|
case ValueWitnessKind::Destroy: return "xx";
|
|
case ValueWitnessKind::DestroyBuffer: return "XX";
|
|
case ValueWitnessKind::InitializeBufferWithCopyOfBuffer: return "CP";
|
|
case ValueWitnessKind::InitializeBufferWithCopy: return "Cp";
|
|
case ValueWitnessKind::InitializeWithCopy: return "cp";
|
|
case ValueWitnessKind::InitializeBufferWithTake: return "Tk";
|
|
case ValueWitnessKind::InitializeWithTake: return "tk";
|
|
case ValueWitnessKind::ProjectBuffer: return "pr";
|
|
case ValueWitnessKind::InitializeBufferWithTakeOfBuffer: return "TK";
|
|
case ValueWitnessKind::DestroyArray: return "Xx";
|
|
case ValueWitnessKind::InitializeArrayWithCopy: return "Cc";
|
|
case ValueWitnessKind::InitializeArrayWithTakeFrontToBack: return "Tt";
|
|
case ValueWitnessKind::InitializeArrayWithTakeBackToFront: return "tT";
|
|
case ValueWitnessKind::StoreExtraInhabitant: return "xs";
|
|
case ValueWitnessKind::GetExtraInhabitantIndex: return "xg";
|
|
case ValueWitnessKind::GetEnumTag: return "ug";
|
|
case ValueWitnessKind::DestructiveProjectEnumData: return "up";
|
|
}
|
|
unreachable("bad value witness kind");
|
|
};
|
|
Out << 'w' << getString(ValueWitnessKind(node->getIndex()));
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleValueWitnessTable(Node *node) {
|
|
Out << "WV";
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleWitnessTableOffset(Node *node) {
|
|
Out << "Wo";
|
|
mangleSingleChildNode(node); // entity
|
|
}
|
|
|
|
void Remangler::mangleThrowsAnnotation(Node *node) {
|
|
Out << "z";
|
|
}
|
|
|
|
void Remangler::mangleFieldOffset(Node *node) {
|
|
Out << "Wv";
|
|
mangleChildNodes(node); // directness, entity
|
|
}
|
|
|
|
void Remangler::mangleProtocolWitnessTable(Node *node) {
|
|
Out << "WP";
|
|
mangleSingleChildNode(node); // protocol conformance
|
|
}
|
|
|
|
void Remangler::mangleGenericProtocolWitnessTable(Node *node) {
|
|
Out << "WG";
|
|
mangleSingleChildNode(node); // protocol conformance
|
|
}
|
|
|
|
void Remangler::mangleGenericProtocolWitnessTableInstantiationFunction(
|
|
Node *node) {
|
|
Out << "WI";
|
|
mangleSingleChildNode(node); // protocol conformance
|
|
}
|
|
|
|
void Remangler::mangleProtocolWitnessTableAccessor(Node *node) {
|
|
Out << "Wa";
|
|
mangleSingleChildNode(node); // protocol conformance
|
|
}
|
|
|
|
void Remangler::mangleLazyProtocolWitnessTableAccessor(Node *node) {
|
|
Out << "Wl";
|
|
mangleChildNodes(node); // type, protocol conformance
|
|
}
|
|
|
|
void Remangler::mangleLazyProtocolWitnessTableCacheVariable(Node *node) {
|
|
Out << "WL";
|
|
mangleChildNodes(node); // type, protocol conformance
|
|
}
|
|
|
|
void Remangler::mangleAssociatedTypeMetadataAccessor(Node *node) {
|
|
Out << "Wt";
|
|
mangleChildNodes(node); // protocol conformance, identifier
|
|
}
|
|
|
|
void Remangler::mangleAssociatedTypeWitnessTableAccessor(Node *node) {
|
|
Out << "WT";
|
|
assert(node->getNumChildren() == 3);
|
|
mangleChildNode(node, 0); // protocol conformance
|
|
mangleChildNode(node, 1); // identifier
|
|
mangleProtocolWithoutPrefix(node->begin()[2].get()); // type
|
|
}
|
|
|
|
void Remangler::mangleReabstractionThunkHelper(Node *node) {
|
|
Out << "TR";
|
|
if (node->getNumChildren() == 3) Out << 'G';
|
|
mangleChildNodes(node); // generic signature?, type, type
|
|
}
|
|
|
|
void Remangler::mangleReabstractionThunk(Node *node) {
|
|
Out << "Tr";
|
|
if (node->getNumChildren() == 3) Out << 'G';
|
|
mangleChildNodes(node); // generic signature?, type, type
|
|
}
|
|
|
|
void Remangler::mangleProtocolWitness(Node *node) {
|
|
Out << "TW";
|
|
mangleChildNodes(node); // protocol conformance, entity
|
|
}
|
|
|
|
void Remangler::mangleFunction(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "", ctx);
|
|
}
|
|
|
|
void Remangler::mangleVariable(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'v', "", ctx);
|
|
}
|
|
|
|
void Remangler::mangleSubscript(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'i', "", ctx);
|
|
}
|
|
|
|
void Remangler::mangleInitializer(Node *node, EntityContext &ctx) {
|
|
mangleSimpleEntity(node, 'I', "i", ctx);
|
|
}
|
|
|
|
void Remangler::mangleDefaultArgumentInitializer(Node *node,
|
|
EntityContext &ctx) {
|
|
mangleNamedEntity(node, 'I', "A", ctx);
|
|
}
|
|
|
|
void Remangler::mangleDeallocator(Node *node, EntityContext &ctx) {
|
|
mangleSimpleEntity(node, 'F', "D", ctx);
|
|
}
|
|
|
|
void Remangler::mangleDestructor(Node *node, EntityContext &ctx) {
|
|
mangleSimpleEntity(node, 'F', "d", ctx);
|
|
}
|
|
|
|
void Remangler::mangleAllocator(Node *node, EntityContext &ctx) {
|
|
mangleTypedEntity(node, 'F', "C", ctx);
|
|
}
|
|
|
|
void Remangler::mangleConstructor(Node *node, EntityContext &ctx) {
|
|
mangleTypedEntity(node, 'F', "c", ctx);
|
|
}
|
|
|
|
void Remangler::mangleIVarInitializer(Node *node, EntityContext &ctx) {
|
|
mangleSimpleEntity(node, 'F', "e", ctx);
|
|
}
|
|
|
|
void Remangler::mangleIVarDestroyer(Node *node, EntityContext &ctx) {
|
|
mangleSimpleEntity(node, 'F', "E", ctx);
|
|
}
|
|
|
|
void Remangler::mangleGetter(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "g", ctx);
|
|
}
|
|
|
|
void Remangler::mangleGlobalGetter(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "G", ctx);
|
|
}
|
|
|
|
void Remangler::mangleSetter(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "s", ctx);
|
|
}
|
|
|
|
void Remangler::mangleMaterializeForSet(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "m", ctx);
|
|
}
|
|
|
|
void Remangler::mangleWillSet(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "w", ctx);
|
|
}
|
|
|
|
void Remangler::mangleDidSet(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "W", ctx);
|
|
}
|
|
|
|
void Remangler::mangleOwningMutableAddressor(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "aO", ctx);
|
|
}
|
|
|
|
void Remangler::mangleNativeOwningMutableAddressor(Node *node,
|
|
EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "ao", ctx);
|
|
}
|
|
|
|
void Remangler::mangleNativePinningMutableAddressor(Node *node,
|
|
EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "ap", ctx);
|
|
}
|
|
|
|
void Remangler::mangleUnsafeMutableAddressor(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "au", ctx);
|
|
}
|
|
|
|
void Remangler::mangleOwningAddressor(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "lO", ctx);
|
|
}
|
|
|
|
void Remangler::mangleNativeOwningAddressor(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "lo", ctx);
|
|
}
|
|
|
|
void Remangler::mangleNativePinningAddressor(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "lp", ctx);
|
|
}
|
|
|
|
void Remangler::mangleUnsafeAddressor(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "lu", ctx);
|
|
}
|
|
|
|
void Remangler::mangleExplicitClosure(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "U", ctx); // name is index
|
|
}
|
|
|
|
void Remangler::mangleImplicitClosure(Node *node, EntityContext &ctx) {
|
|
mangleNamedAndTypedEntity(node, 'F', "u", ctx); // name is index
|
|
}
|
|
|
|
void Remangler::mangleStatic(Node *node, EntityContext &ctx) {
|
|
Out << 'Z';
|
|
mangleEntityContext(node->getChild(0).get(), ctx);
|
|
}
|
|
|
|
void Remangler::mangleSimpleEntity(Node *node, char basicKind,
|
|
StringRef entityKind,
|
|
EntityContext &ctx) {
|
|
assert(node->getNumChildren() == 1);
|
|
Out << basicKind;
|
|
mangleEntityContext(node->begin()[0].get(), ctx);
|
|
Out << entityKind;
|
|
}
|
|
|
|
void Remangler::mangleNamedEntity(Node *node, char basicKind,
|
|
StringRef entityKind,
|
|
EntityContext &ctx) {
|
|
assert(node->getNumChildren() == 2);
|
|
if (basicKind != '\0') Out << basicKind;
|
|
mangleEntityContext(node->begin()[0].get(), ctx);
|
|
Out << entityKind;
|
|
mangleChildNode(node, 1); // decl name / index
|
|
}
|
|
|
|
void Remangler::mangleTypedEntity(Node *node, char basicKind,
|
|
StringRef entityKind,
|
|
EntityContext &ctx) {
|
|
assert(node->getNumChildren() == 2);
|
|
Out << basicKind;
|
|
mangleEntityContext(node->begin()[0].get(), ctx);
|
|
Out << entityKind;
|
|
mangleEntityType(node->begin()[1].get(), ctx);
|
|
}
|
|
|
|
void Remangler::mangleNamedAndTypedEntity(Node *node, char basicKind,
|
|
StringRef entityKind,
|
|
EntityContext &ctx) {
|
|
assert(node->getNumChildren() == 3);
|
|
Out << basicKind;
|
|
mangleEntityContext(node->begin()[0].get(), ctx);
|
|
Out << entityKind;
|
|
mangleChildNode(node, 1); // decl name / index
|
|
mangleEntityType(node->begin()[2].get(), ctx);
|
|
}
|
|
|
|
void Remangler::mangleEntityContext(Node *node, EntityContext &ctx) {
|
|
// Remember that we're mangling a context.
|
|
EntityContext::ManglingContextRAII raii(ctx);
|
|
|
|
switch (node->getKind()) {
|
|
#define NODE(ID) \
|
|
case Node::Kind::ID:
|
|
#define CONTEXT_NODE(ID)
|
|
#include "swift/Basic/DemangleNodes.def"
|
|
unreachable("not a context node");
|
|
|
|
#define NODE(ID)
|
|
#define CONTEXT_NODE(ID) \
|
|
case Node::Kind::ID: \
|
|
return mangle##ID(node, ctx);
|
|
#include "swift/Basic/DemangleNodes.def"
|
|
}
|
|
unreachable("bad node kind");
|
|
}
|
|
|
|
void Remangler::mangleEntityType(Node *node, EntityContext &ctx) {
|
|
assert(node->getKind() == Node::Kind::Type);
|
|
assert(node->getNumChildren() == 1);
|
|
node = node->begin()[0].get();
|
|
|
|
// Expand certain kinds of type within the entity context.
|
|
switch (node->getKind()) {
|
|
case Node::Kind::GenericType:
|
|
mangleEntityGenericType(node, ctx);
|
|
return;
|
|
case Node::Kind::FunctionType:
|
|
case Node::Kind::UncurriedFunctionType: {
|
|
Out << (node->getKind() == Node::Kind::FunctionType ? 'F' : 'f');
|
|
unsigned inputIndex = node->getNumChildren() - 2;
|
|
assert(inputIndex <= 1);
|
|
for (unsigned i = 0; i <= inputIndex; ++i)
|
|
mangle(node->begin()[i].get());
|
|
auto returnType = node->begin()[inputIndex+1].get();
|
|
assert(returnType->getKind() == Node::Kind::ReturnType);
|
|
assert(returnType->getNumChildren() == 1);
|
|
mangleEntityType(returnType->begin()[0].get(), ctx);
|
|
return;
|
|
}
|
|
default:
|
|
mangle(node);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleLocalDeclName(Node *node) {
|
|
Out << 'L';
|
|
mangleChildNodes(node); // index, identifier
|
|
}
|
|
|
|
void Remangler::manglePrivateDeclName(Node *node) {
|
|
Out << 'P';
|
|
mangleChildNodes(node); // identifier, identifier
|
|
}
|
|
|
|
void Remangler::mangleTypeMangling(Node *node) {
|
|
Out << 't';
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleType(Node *node) {
|
|
mangleSingleChildNode(node);
|
|
}
|
|
|
|
template <size_t N>
|
|
static bool stripPrefix(StringRef &string, const char (&data)[N]) {
|
|
constexpr size_t prefixLength = N - 1;
|
|
if (!string.startswith(StringRef(data, prefixLength)))
|
|
return false;
|
|
string = string.drop_front(prefixLength);
|
|
return true;
|
|
}
|
|
|
|
void Remangler::mangleBuiltinTypeName(Node *node) {
|
|
Out << 'B';
|
|
StringRef text = node->getText();
|
|
|
|
if (text == "Builtin.BridgeObject") {
|
|
Out << 'b';
|
|
} else if (text == "Builtin.UnsafeValueBuffer") {
|
|
Out << 'B';
|
|
} else if (text == "Builtin.UnknownObject") {
|
|
Out << 'O';
|
|
} else if (text == "Builtin.NativeObject") {
|
|
Out << 'o';
|
|
} else if (text == "Builtin.RawPointer") {
|
|
Out << 'p';
|
|
} else if (text == "Builtin.Word") {
|
|
Out << 'w';
|
|
} else if (stripPrefix(text, "Builtin.Int")) {
|
|
Out << 'i' << text << '_';
|
|
} else if (stripPrefix(text, "Builtin.Float")) {
|
|
Out << 'f' << text << '_';
|
|
} else if (stripPrefix(text, "Builtin.Vec")) {
|
|
auto split = text.split('x');
|
|
Out << 'v' << split.first << 'B';
|
|
if (split.second == "RawPointer") {
|
|
Out << 'p';
|
|
} else if (stripPrefix(split.second, "Float")) {
|
|
Out << 'f' << split.second << '_';
|
|
} else if (stripPrefix(split.second, "Int")) {
|
|
Out << 'i' << split.second << '_';
|
|
} else {
|
|
unreachable("unexpected builtin vector type");
|
|
}
|
|
} else {
|
|
unreachable("unexpected builtin type");
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleTypeAlias(Node *node) {
|
|
SubstitutionEntry entry;
|
|
if (trySubstitution(node, entry)) return;
|
|
Out << 'a';
|
|
mangleChildNodes(node); // context, identifier
|
|
addSubstitution(entry);
|
|
}
|
|
|
|
void Remangler::mangleFunctionType(Node *node) {
|
|
Out << 'F';
|
|
mangleChildNodes(node); // argument tuple, result type
|
|
}
|
|
|
|
void Remangler::mangleUncurriedFunctionType(Node *node) {
|
|
Out << 'f';
|
|
mangleChildNodes(node); // argument tuple, result type
|
|
}
|
|
|
|
void Remangler::mangleObjCBlock(Node *node) {
|
|
Out << 'b';
|
|
mangleChildNodes(node); // argument tuple, result type
|
|
}
|
|
|
|
void Remangler::mangleCFunctionPointer(Node *node) {
|
|
Out << 'c';
|
|
mangleChildNodes(node); // argument tuple, result type
|
|
}
|
|
|
|
void Remangler::mangleAutoClosureType(Node *node) {
|
|
Out << 'K';
|
|
mangleChildNodes(node); // argument tuple, result type
|
|
}
|
|
|
|
void Remangler::mangleThinFunctionType(Node *node) {
|
|
Out << "Xf";
|
|
mangleChildNodes(node); // argument tuple, result type
|
|
}
|
|
|
|
void Remangler::mangleArgumentTuple(Node *node) {
|
|
mangleSingleChildNode(node);
|
|
}
|
|
|
|
void Remangler::mangleReturnType(Node *node) {
|
|
mangleSingleChildNode(node);
|
|
}
|
|
|
|
void Remangler::mangleImplFunctionType(Node *node) {
|
|
Out << "XF";
|
|
auto i = node->begin(), e = node->end();
|
|
if (i != e && i->get()->getKind() == Node::Kind::ImplConvention) {
|
|
StringRef text = (i++)->get()->getText();
|
|
if (text == "@callee_unowned") {
|
|
Out << 'd';
|
|
} else if (text == "@callee_guaranteed") {
|
|
Out << 'g';
|
|
} else if (text == "@callee_owned") {
|
|
Out << 'o';
|
|
} else {
|
|
unreachable("bad callee convention");
|
|
}
|
|
} else {
|
|
Out << 't';
|
|
}
|
|
for (; i != e &&
|
|
i->get()->getKind() == Node::Kind::ImplFunctionAttribute; ++i) {
|
|
mangle(i->get()); // impl function attribute
|
|
}
|
|
EntityContext ctx(*this);
|
|
if (i != e && i->get()->getKind() == Node::Kind::Generics) {
|
|
mangleGenerics((i++)->get(), ctx);
|
|
}
|
|
Out << '_';
|
|
for (; i != e && i->get()->getKind() == Node::Kind::ImplParameter; ++i) {
|
|
mangleImplParameter(i->get());
|
|
}
|
|
Out << '_';
|
|
mangleNodes(i, e); // impl results
|
|
Out << '_';
|
|
}
|
|
|
|
void Remangler::mangleImplFunctionAttribute(Node *node) {
|
|
StringRef text = node->getText();
|
|
if (text == "@convention(block)") {
|
|
Out << "Cb";
|
|
} else if (text == "@convention(c)") {
|
|
Out << "Cc";
|
|
} else if (text == "@convention(method)") {
|
|
Out << "Cm";
|
|
} else if (text == "@convention(objc_method)") {
|
|
Out << "CO";
|
|
} else if (text == "@convention(witness_method)") {
|
|
Out << "Cw";
|
|
} else if (text == "@noreturn") {
|
|
Out << "CN";
|
|
} else {
|
|
unreachable("bad impl-function-attribute");
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleImplParameter(Node *node) {
|
|
assert(node->getNumChildren() == 2);
|
|
mangleChildNodes(node); // impl convention, type
|
|
}
|
|
|
|
void Remangler::mangleImplErrorResult(Node *node) {
|
|
assert(node->getNumChildren() == 2);
|
|
Out << 'z';
|
|
mangleChildNodes(node); // impl convention, type
|
|
}
|
|
|
|
void Remangler::mangleImplResult(Node *node) {
|
|
assert(node->getNumChildren() == 2);
|
|
mangleChildNodes(node); // impl convention, type
|
|
}
|
|
|
|
void Remangler::mangleImplConvention(Node *node) {
|
|
assert(node->getKind() == Node::Kind::ImplConvention);
|
|
StringRef text = node->getText();
|
|
if (text == "@autoreleased") {
|
|
Out << 'a';
|
|
} else if (text == "@unowned") {
|
|
Out << 'd';
|
|
} else if (text == "@unowned_inner_pointer") {
|
|
Out << 'd'; // only in results
|
|
} else if (text == "@guaranteed") {
|
|
Out << 'g';
|
|
} else if (text == "@deallocating") {
|
|
Out << 'e';
|
|
} else if (text == "@in") {
|
|
Out << 'i'; // only in parameters
|
|
} else if (text == "@out") {
|
|
Out << 'i'; // only in results
|
|
} else if (text == "@inout") {
|
|
Out << 'l';
|
|
} else if (text == "@owned") {
|
|
Out << 'o';
|
|
} else {
|
|
unreachable("invalid impl convention");
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleDynamicSelf(Node *node) {
|
|
Out << 'D';
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleErrorType(Node *node) {
|
|
Out << "ERR";
|
|
}
|
|
|
|
void Remangler::mangleSILBoxType(Node *node) {
|
|
Out << 'X' << 'b';
|
|
mangleSingleChildNode(node);
|
|
}
|
|
|
|
void Remangler::mangleMetatype(Node *node) {
|
|
if (node->getNumChildren() == 1) {
|
|
Out << 'M';
|
|
mangleSingleChildNode(node); // type
|
|
} else {
|
|
assert(node->getNumChildren() == 2);
|
|
Out << "XM";
|
|
mangleChildNodes(node); // metatype representation, type
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleExistentialMetatype(Node *node) {
|
|
if (node->getNumChildren() == 1) {
|
|
Out << "PM";
|
|
mangleSingleChildNode(node); // type
|
|
} else {
|
|
assert(node->getNumChildren() == 2);
|
|
Out << "XPM";
|
|
mangleChildNodes(node); // metatype representation, type
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleMetatypeRepresentation(Node *node) {
|
|
StringRef text = node->getText();
|
|
if (text == "@thin") {
|
|
Out << 't';
|
|
} else if (text == "@thick") {
|
|
Out << 'T';
|
|
} else if (text == "@objc_metatype") {
|
|
Out << 'o';
|
|
} else {
|
|
unreachable("bad metatype representation");
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleProtocolList(Node *node) {
|
|
// In its usual use as a type, this gets a prefix 'P'.
|
|
Out << 'P';
|
|
mangleProtocolListWithoutPrefix(node);
|
|
}
|
|
|
|
void Remangler::mangleProtocolListWithoutPrefix(Node *node) {
|
|
assert(node->getKind() == Node::Kind::ProtocolList);
|
|
assert(node->getNumChildren() == 1);
|
|
auto typeList = node->begin()[0].get();
|
|
assert(typeList->getKind() == Node::Kind::TypeList);
|
|
for (auto &child : *typeList) {
|
|
mangleProtocolWithoutPrefix(child.get());
|
|
}
|
|
Out << '_';
|
|
}
|
|
|
|
void Remangler::mangleUnowned(Node *node) {
|
|
Out << "Xo";
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleUnmanaged(Node *node) {
|
|
Out << "Xu";
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleWeak(Node *node) {
|
|
Out << "Xw";
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleInOut(Node *node) {
|
|
Out << 'R';
|
|
mangleSingleChildNode(node); // type
|
|
}
|
|
|
|
void Remangler::mangleNonVariadicTuple(Node *node) {
|
|
Out << 'T';
|
|
mangleChildNodes(node); // tuple elements
|
|
Out << '_';
|
|
}
|
|
|
|
void Remangler::mangleVariadicTuple(Node *node) {
|
|
Out << 't';
|
|
mangleChildNodes(node); // tuple elements
|
|
Out << '_';
|
|
}
|
|
|
|
void Remangler::mangleTupleElement(Node *node) {
|
|
mangleChildNodes(node); // tuple element name?, type
|
|
}
|
|
|
|
void Remangler::mangleTupleElementName(Node *node) {
|
|
mangleIdentifier(node->getText(), OperatorKind::NotOperator);
|
|
}
|
|
|
|
void Remangler::mangleDependentGenericType(Node *node) {
|
|
Out << 'u';
|
|
mangleChildNodes(node); // generic signature, type
|
|
}
|
|
|
|
void Remangler::mangleGenericType(Node *node) {
|
|
EntityContext ctx(*this);
|
|
mangleEntityGenericType(node, ctx);
|
|
}
|
|
|
|
void Remangler::mangleEntityGenericType(Node *node, EntityContext &ctx) {
|
|
assert(node->getKind() == Node::Kind::GenericType);
|
|
|
|
Out << 'U';
|
|
assert(node->getNumChildren() == 2);
|
|
|
|
mangleGenerics(node->begin()[0].get(), ctx);
|
|
mangleEntityType(node->begin()[1].get(), ctx);
|
|
}
|
|
|
|
void Remangler::mangleDependentGenericSignature(Node *node) {
|
|
auto i = node->begin(), e = node->end();
|
|
|
|
// If there's only one generic param, mangle nothing.
|
|
if (node->getNumChildren() >= 1
|
|
&& node->getChild(0)->getKind() == Node::Kind::DependentGenericParamCount
|
|
&& node->getChild(0)->getIndex() == 1
|
|
&& (node->getNumChildren() == 1
|
|
|| node->getChild(1)->getKind() != Node::Kind::DependentGenericParamCount))
|
|
{
|
|
++i;
|
|
goto mangle_requirements;
|
|
}
|
|
|
|
// Remangle generic params.
|
|
for (; i != e &&
|
|
i->get()->getKind() == Node::Kind::DependentGenericParamCount; ++i) {
|
|
auto count = i->get();
|
|
if (count->getIndex() > 0)
|
|
mangleIndex(count->getIndex() - 1);
|
|
else
|
|
Out << 'z';
|
|
}
|
|
|
|
mangle_requirements:
|
|
if (i == e) { // no generic requirements
|
|
Out << 'r';
|
|
return;
|
|
}
|
|
|
|
Out << 'R';
|
|
mangleNodes(i, e); // generic requirements
|
|
Out << 'r';
|
|
}
|
|
|
|
void Remangler::mangleDependentGenericParamCount(Node *node) {
|
|
unreachable("handled inline in DependentGenericSignature");
|
|
}
|
|
|
|
void Remangler::mangleDependentGenericConformanceRequirement(Node *node) {
|
|
mangleConstrainedType(node->getChild(0).get());
|
|
// If the constraint represents a protocol, use the shorter mangling.
|
|
if (node->getNumChildren() == 2
|
|
&& node->getChild(1)->getKind() == Node::Kind::Type
|
|
&& node->getChild(1)->getNumChildren() == 1
|
|
&& node->getChild(1)->getChild(0)->getKind() == Node::Kind::Protocol) {
|
|
mangleProtocolWithoutPrefix(node->getChild(1)->getChild(0).get());
|
|
return;
|
|
}
|
|
|
|
mangle(node->getChild(1).get());
|
|
}
|
|
|
|
void Remangler::mangleDependentGenericSameTypeRequirement(Node *node) {
|
|
mangleConstrainedType(node->getChild(0).get());
|
|
Out << 'z';
|
|
mangle(node->getChild(1).get());
|
|
}
|
|
|
|
void Remangler::mangleConstrainedType(Node *node) {
|
|
if (node->getFirstChild()->getKind()
|
|
== Node::Kind::DependentGenericParamType) {
|
|
// Can be mangled without an introducer.
|
|
mangleDependentGenericParamIndex(node->getFirstChild().get());
|
|
} else {
|
|
mangle(node);
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleGenerics(Node *node) {
|
|
unreachable("found independent generics node?");
|
|
}
|
|
|
|
void Remangler::mangleGenerics(Node *node, EntityContext &ctx) {
|
|
assert(node->getKind() == Node::Kind::Generics);
|
|
|
|
unsigned absoluteDepth = ++AbsoluteArchetypeDepth;
|
|
|
|
auto i = node->begin(), e = node->end();
|
|
unsigned index = 0;
|
|
for (; i != e && i->get()->getKind() == Node::Kind::Archetype; ++i) {
|
|
auto child = i->get();
|
|
Archetypes[child->getText()] = ArchetypeInfo{index++, absoluteDepth};
|
|
mangle(child); // archetype
|
|
}
|
|
if (i != e) {
|
|
Out << 'U';
|
|
mangleNodes(i, e); // associated types
|
|
Out << '_';
|
|
} else {
|
|
Out << '_';
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleArchetype(Node *node) {
|
|
if (node->hasChildren()) {
|
|
assert(node->getNumChildren() == 1);
|
|
mangleProtocolListWithoutPrefix(node->begin()->get());
|
|
} else {
|
|
Out << '_';
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleAssociatedType(Node *node) {
|
|
if (node->hasChildren()) {
|
|
assert(node->getNumChildren() == 1);
|
|
mangleProtocolListWithoutPrefix(node->begin()->get());
|
|
} else {
|
|
Out << '_';
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleSelfTypeRef(Node *node) {
|
|
SubstitutionEntry entry;
|
|
if (trySubstitution(node, entry)) return;
|
|
Out << "QP";
|
|
assert(node->getNumChildren() == 1);
|
|
mangleProtocolWithoutPrefix(node->begin()[0].get());
|
|
addSubstitution(entry);
|
|
}
|
|
|
|
void Remangler::mangleArchetypeRef(Node *node) {
|
|
Node::IndexType relativeDepth = node->getChild(0)->getIndex();
|
|
Node::IndexType index = node->getChild(1)->getIndex();
|
|
|
|
Out << 'Q';
|
|
if (relativeDepth != 0) {
|
|
Out << 'd';
|
|
mangleIndex(relativeDepth - 1);
|
|
}
|
|
mangleIndex(index);
|
|
}
|
|
|
|
void Remangler::mangleQualifiedArchetype(Node *node) {
|
|
Out << "Qq";
|
|
mangleChildNodes(node); // index, declcontext
|
|
}
|
|
|
|
void Remangler::mangleDeclContext(Node *node) {
|
|
mangleSingleChildNode(node);
|
|
}
|
|
|
|
void Remangler::mangleExtension(Node *node, EntityContext &ctx) {
|
|
assert(node->getNumChildren() == 2 || node->getNumChildren() == 3);
|
|
if (node->getNumChildren() == 3) {
|
|
Out << 'e';
|
|
} else {
|
|
Out << 'E';
|
|
}
|
|
mangleEntityContext(node->begin()[0].get(), ctx); // module
|
|
if (node->getNumChildren() == 3) {
|
|
mangleDependentGenericSignature(node->begin()[2].get()); // generic sig
|
|
}
|
|
mangleEntityContext(node->begin()[1].get(), ctx); // context
|
|
}
|
|
|
|
void Remangler::mangleModule(Node *node, EntityContext &ctx) {
|
|
SubstitutionEntry entry;
|
|
if (trySubstitution(node, entry)) return;
|
|
|
|
// Module types get an M prefix, but module contexts don't.
|
|
if (!ctx.isAsContext()) Out << 'M';
|
|
mangleIdentifier(node->getText(), OperatorKind::NotOperator);
|
|
addSubstitution(entry);
|
|
}
|
|
|
|
void Remangler::mangleAssociatedTypeRef(Node *node) {
|
|
SubstitutionEntry entry;
|
|
if (trySubstitution(node, entry)) return;
|
|
Out << "Q";
|
|
mangleChildNodes(node); // type, identifier
|
|
addSubstitution(entry);
|
|
}
|
|
|
|
void Remangler::mangleDependentMemberType(Node *node) {
|
|
std::vector<Node *> members;
|
|
Node *base = node;
|
|
do {
|
|
members.push_back(base);
|
|
base = base->getFirstChild()->getFirstChild().get();
|
|
} while (base->getKind() == Node::Kind::DependentMemberType);
|
|
|
|
assert(base->getKind() == Node::Kind::DependentGenericParamType
|
|
&& "dependent members not based on a generic param are non-canonical"
|
|
" and shouldn't need remangling");
|
|
assert(members.size() >= 1);
|
|
if (members.size() == 1) {
|
|
Out << 'w';
|
|
mangleDependentGenericParamIndex(base);
|
|
mangle(members[0]->getChild(1).get());
|
|
} else {
|
|
Out << 'W';
|
|
mangleDependentGenericParamIndex(base);
|
|
|
|
for (auto *member : reversed(members)) {
|
|
mangle(member->getChild(1).get());
|
|
}
|
|
Out << '_';
|
|
}
|
|
}
|
|
|
|
void Remangler::mangleDependentAssociatedTypeRef(Node *node) {
|
|
SubstitutionEntry entry;
|
|
if (trySubstitution(node, entry)) return;
|
|
|
|
if (node->getNumChildren() > 0) {
|
|
Out << 'P';
|
|
mangleProtocolWithoutPrefix(node->getFirstChild().get());
|
|
}
|
|
mangleIdentifier(node);
|
|
|
|
addSubstitution(entry);
|
|
}
|
|
|
|
void Remangler::mangleDependentGenericParamIndex(Node *node) {
|
|
auto depth = node->getChild(0)->getIndex();
|
|
auto index = node->getChild(1)->getIndex();
|
|
|
|
if (depth != 0) {
|
|
Out << 'd';
|
|
mangleIndex(depth - 1);
|
|
mangleIndex(index);
|
|
return;
|
|
}
|
|
if (index != 0) {
|
|
mangleIndex(index - 1);
|
|
return;
|
|
}
|
|
|
|
// depth == index == 0
|
|
Out << 'x';
|
|
}
|
|
|
|
void Remangler::mangleDependentGenericParamType(Node *node) {
|
|
if (node->getChild(0)->getIndex() == 0
|
|
&& node->getChild(1)->getIndex() == 0) {
|
|
Out << 'x';
|
|
return;
|
|
}
|
|
|
|
Out << 'q';
|
|
mangleDependentGenericParamIndex(node);
|
|
}
|
|
|
|
void Remangler::mangleIndex(Node *node) {
|
|
mangleIndex(node->getIndex());
|
|
}
|
|
|
|
void Remangler::mangleProtocol(Node *node, EntityContext &ctx) {
|
|
mangleNominalType(node, 'P', ctx);
|
|
}
|
|
|
|
void Remangler::mangleProtocolWithoutPrefix(Node *node) {
|
|
if (node->getKind() == Node::Kind::Type) {
|
|
assert(node->getNumChildren() == 1);
|
|
node = node->begin()[0].get();
|
|
}
|
|
|
|
assert(node->getKind() == Node::Kind::Protocol);
|
|
EntityContext ctx(*this);
|
|
mangleNominalType(node, '\0', ctx);
|
|
}
|
|
|
|
void Remangler::mangleStructure(Node *node, EntityContext &ctx) {
|
|
mangleNominalType(node, 'V', ctx);
|
|
}
|
|
|
|
void Remangler::mangleEnum(Node *node, EntityContext &ctx) {
|
|
mangleNominalType(node, 'O', ctx);
|
|
}
|
|
|
|
void Remangler::mangleClass(Node *node, EntityContext &ctx) {
|
|
mangleNominalType(node, 'C', ctx);
|
|
}
|
|
|
|
void Remangler::mangleNominalType(Node *node, char kind, EntityContext &ctx) {
|
|
SubstitutionEntry entry;
|
|
if (trySubstitution(node, entry)) return;
|
|
mangleNamedEntity(node, kind, "", ctx);
|
|
addSubstitution(entry);
|
|
}
|
|
|
|
void Remangler::mangleBoundGenericClass(Node *node) {
|
|
Out << 'G';
|
|
mangleChildNodes(node); // type, type list
|
|
}
|
|
|
|
void Remangler::mangleBoundGenericStructure(Node *node) {
|
|
Out << 'G';
|
|
mangleChildNodes(node); // type, type list
|
|
}
|
|
|
|
void Remangler::mangleBoundGenericEnum(Node *node) {
|
|
Out << 'G';
|
|
mangleChildNodes(node); // type, type list
|
|
}
|
|
|
|
void Remangler::mangleTypeList(Node *node) {
|
|
mangleChildNodes(node); // all types
|
|
Out << '_';
|
|
}
|
|
|
|
/// The top-level interface to the remangler.
|
|
std::string Demangle::mangleNode(const NodePointer &node) {
|
|
if (!node) return "";
|
|
|
|
std::string str;
|
|
DemanglerPrinter printer(str);
|
|
Remangler(printer).mangle(node.get());
|
|
return str;
|
|
}
|