This commit is contained in:
lat9nq 2023-07-18 21:39:37 -04:00
parent c1e57ad358
commit 1ab3bd5a5e
8 changed files with 2304 additions and 2193 deletions

View file

@ -20,9 +20,7 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <functional> #include <functional>
#include <numeric>
#include <utility> #include <utility>
#include <vector>
using namespace llvm; using namespace llvm;
using namespace llvm::itanium_demangle; using namespace llvm::itanium_demangle;
@ -81,8 +79,8 @@ struct DumpVisitor {
} }
void printStr(const char *S) { fprintf(stderr, "%s", S); } void printStr(const char *S) { fprintf(stderr, "%s", S); }
void print(StringView SV) { void print(std::string_view SV) {
fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.data());
} }
void print(const Node *N) { void print(const Node *N) {
if (N) if (N)
@ -90,14 +88,6 @@ struct DumpVisitor {
else else
printStr("<null>"); printStr("<null>");
} }
void print(NodeOrString NS) {
if (NS.isNode())
print(NS.asNode());
else if (NS.isString())
print(NS.asString());
else
printStr("NodeOrString()");
}
void print(NodeArray A) { void print(NodeArray A) {
++Depth; ++Depth;
printStr("{"); printStr("{");
@ -116,13 +106,11 @@ struct DumpVisitor {
// Overload used when T is exactly 'bool', not merely convertible to 'bool'. // Overload used when T is exactly 'bool', not merely convertible to 'bool'.
void print(bool B) { printStr(B ? "true" : "false"); } void print(bool B) { printStr(B ? "true" : "false"); }
template <class T> template <class T> std::enable_if_t<std::is_unsigned<T>::value> print(T N) {
typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) {
fprintf(stderr, "%llu", (unsigned long long)N); fprintf(stderr, "%llu", (unsigned long long)N);
} }
template <class T> template <class T> std::enable_if_t<std::is_signed<T>::value> print(T N) {
typename std::enable_if<std::is_signed<T>::value>::type print(T N) {
fprintf(stderr, "%lld", (long long)N); fprintf(stderr, "%lld", (long long)N);
} }
@ -185,6 +173,50 @@ struct DumpVisitor {
return printStr("TemplateParamKind::Template"); return printStr("TemplateParamKind::Template");
} }
} }
void print(Node::Prec P) {
switch (P) {
case Node::Prec::Primary:
return printStr("Node::Prec::Primary");
case Node::Prec::Postfix:
return printStr("Node::Prec::Postfix");
case Node::Prec::Unary:
return printStr("Node::Prec::Unary");
case Node::Prec::Cast:
return printStr("Node::Prec::Cast");
case Node::Prec::PtrMem:
return printStr("Node::Prec::PtrMem");
case Node::Prec::Multiplicative:
return printStr("Node::Prec::Multiplicative");
case Node::Prec::Additive:
return printStr("Node::Prec::Additive");
case Node::Prec::Shift:
return printStr("Node::Prec::Shift");
case Node::Prec::Spaceship:
return printStr("Node::Prec::Spaceship");
case Node::Prec::Relational:
return printStr("Node::Prec::Relational");
case Node::Prec::Equality:
return printStr("Node::Prec::Equality");
case Node::Prec::And:
return printStr("Node::Prec::And");
case Node::Prec::Xor:
return printStr("Node::Prec::Xor");
case Node::Prec::Ior:
return printStr("Node::Prec::Ior");
case Node::Prec::AndIf:
return printStr("Node::Prec::AndIf");
case Node::Prec::OrIf:
return printStr("Node::Prec::OrIf");
case Node::Prec::Conditional:
return printStr("Node::Prec::Conditional");
case Node::Prec::Assign:
return printStr("Node::Prec::Assign");
case Node::Prec::Comma:
return printStr("Node::Prec::Comma");
case Node::Prec::Default:
return printStr("Node::Prec::Default");
}
}
void newLine() { void newLine() {
printStr("\n"); printStr("\n");
@ -334,36 +366,21 @@ public:
using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>; using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>;
char *llvm::itaniumDemangle(const char *MangledName, char *Buf, char *llvm::itaniumDemangle(std::string_view MangledName) {
size_t *N, int *Status) { if (MangledName.empty())
if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) {
if (Status)
*Status = demangle_invalid_args;
return nullptr; return nullptr;
}
int InternalStatus = demangle_success;
Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
OutputStream S;
Demangler Parser(MangledName.data(),
MangledName.data() + MangledName.length());
Node *AST = Parser.parse(); Node *AST = Parser.parse();
if (!AST)
return nullptr;
if (AST == nullptr) OutputBuffer OB;
InternalStatus = demangle_invalid_mangled_name; assert(Parser.ForwardTemplateRefs.empty());
else if (!initializeOutputStream(Buf, N, S, 1024)) AST->print(OB);
InternalStatus = demangle_memory_alloc_failure; OB += '\0';
else { return OB.getBuffer();
assert(Parser.ForwardTemplateRefs.empty());
AST->print(S);
S += '\0';
if (N != nullptr)
*N = S.getCurrentPosition();
Buf = S.getBuffer();
}
if (Status)
*Status = InternalStatus;
return InternalStatus == demangle_success ? Buf : nullptr;
} }
ItaniumPartialDemangler::ItaniumPartialDemangler() ItaniumPartialDemangler::ItaniumPartialDemangler()
@ -396,14 +413,12 @@ bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
} }
static char *printNode(const Node *RootNode, char *Buf, size_t *N) { static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
OutputStream S; OutputBuffer OB(Buf, N);
if (!initializeOutputStream(Buf, N, S, 128)) RootNode->print(OB);
return nullptr; OB += '\0';
RootNode->print(S);
S += '\0';
if (N != nullptr) if (N != nullptr)
*N = S.getCurrentPosition(); *N = OB.getCurrentPosition();
return S.getBuffer(); return OB.getBuffer();
} }
char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const { char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
@ -417,8 +432,8 @@ char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
case Node::KAbiTagAttr: case Node::KAbiTagAttr:
Name = static_cast<const AbiTagAttr *>(Name)->Base; Name = static_cast<const AbiTagAttr *>(Name)->Base;
continue; continue;
case Node::KStdQualifiedName: case Node::KModuleEntity:
Name = static_cast<const StdQualifiedName *>(Name)->Child; Name = static_cast<const ModuleEntity *>(Name)->Name;
continue; continue;
case Node::KNestedName: case Node::KNestedName:
Name = static_cast<const NestedName *>(Name)->Name; Name = static_cast<const NestedName *>(Name)->Name;
@ -441,9 +456,7 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
return nullptr; return nullptr;
const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
OutputStream S; OutputBuffer OB(Buf, N);
if (!initializeOutputStream(Buf, N, S, 128))
return nullptr;
KeepGoingLocalFunction: KeepGoingLocalFunction:
while (true) { while (true) {
@ -458,27 +471,27 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
break; break;
} }
if (Name->getKind() == Node::KModuleEntity)
Name = static_cast<const ModuleEntity *>(Name)->Name;
switch (Name->getKind()) { switch (Name->getKind()) {
case Node::KStdQualifiedName:
S += "std";
break;
case Node::KNestedName: case Node::KNestedName:
static_cast<const NestedName *>(Name)->Qual->print(S); static_cast<const NestedName *>(Name)->Qual->print(OB);
break; break;
case Node::KLocalName: { case Node::KLocalName: {
auto *LN = static_cast<const LocalName *>(Name); auto *LN = static_cast<const LocalName *>(Name);
LN->Encoding->print(S); LN->Encoding->print(OB);
S += "::"; OB += "::";
Name = LN->Entity; Name = LN->Entity;
goto KeepGoingLocalFunction; goto KeepGoingLocalFunction;
} }
default: default:
break; break;
} }
S += '\0'; OB += '\0';
if (N != nullptr) if (N != nullptr)
*N = S.getCurrentPosition(); *N = OB.getCurrentPosition();
return S.getBuffer(); return OB.getBuffer();
} }
char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const { char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
@ -494,17 +507,15 @@ char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
return nullptr; return nullptr;
NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams(); NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
OutputStream S; OutputBuffer OB(Buf, N);
if (!initializeOutputStream(Buf, N, S, 128))
return nullptr;
S += '('; OB += '(';
Params.printWithComma(S); Params.printWithComma(OB);
S += ')'; OB += ')';
S += '\0'; OB += '\0';
if (N != nullptr) if (N != nullptr)
*N = S.getCurrentPosition(); *N = OB.getCurrentPosition();
return S.getBuffer(); return OB.getBuffer();
} }
char *ItaniumPartialDemangler::getFunctionReturnType( char *ItaniumPartialDemangler::getFunctionReturnType(
@ -512,18 +523,16 @@ char *ItaniumPartialDemangler::getFunctionReturnType(
if (!isFunction()) if (!isFunction())
return nullptr; return nullptr;
OutputStream S; OutputBuffer OB(Buf, N);
if (!initializeOutputStream(Buf, N, S, 128))
return nullptr;
if (const Node *Ret = if (const Node *Ret =
static_cast<const FunctionEncoding *>(RootNode)->getReturnType()) static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
Ret->print(S); Ret->print(OB);
S += '\0'; OB += '\0';
if (N != nullptr) if (N != nullptr)
*N = S.getCurrentPosition(); *N = OB.getCurrentPosition();
return S.getBuffer(); return OB.getBuffer();
} }
char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const { char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
@ -563,8 +572,8 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const {
case Node::KNestedName: case Node::KNestedName:
N = static_cast<const NestedName *>(N)->Name; N = static_cast<const NestedName *>(N)->Name;
break; break;
case Node::KStdQualifiedName: case Node::KModuleEntity:
N = static_cast<const StdQualifiedName *>(N)->Child; N = static_cast<const ModuleEntity *>(N)->Name;
break; break;
} }
} }

View file

@ -12,6 +12,7 @@
#include <cstddef> #include <cstddef>
#include <string> #include <string>
#include <string_view>
namespace llvm { namespace llvm {
/// This is a llvm local version of __cxa_demangle. Other than the name and /// This is a llvm local version of __cxa_demangle. Other than the name and
@ -29,9 +30,10 @@ enum : int {
demangle_success = 0, demangle_success = 0,
}; };
char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n, /// Returns a non-NULL pointer to a NUL-terminated C style string
int *status); /// that should be explicitly freed, if successful. Otherwise, may return
/// nullptr if mangled_name is not a valid mangling or is nullptr.
char *itaniumDemangle(std::string_view mangled_name);
enum MSDemangleFlags { enum MSDemangleFlags {
MSDF_None = 0, MSDF_None = 0,
@ -40,10 +42,34 @@ enum MSDemangleFlags {
MSDF_NoCallingConvention = 1 << 2, MSDF_NoCallingConvention = 1 << 2,
MSDF_NoReturnType = 1 << 3, MSDF_NoReturnType = 1 << 3,
MSDF_NoMemberType = 1 << 4, MSDF_NoMemberType = 1 << 4,
MSDF_NoVariableType = 1 << 5,
}; };
char *microsoftDemangle(const char *mangled_name, char *buf, size_t *n,
/// Demangles the Microsoft symbol pointed at by mangled_name and returns it.
/// Returns a pointer to the start of a null-terminated demangled string on
/// success, or nullptr on error.
/// If n_read is non-null and demangling was successful, it receives how many
/// bytes of the input string were consumed.
/// status receives one of the demangle_ enum entries above if it's not nullptr.
/// Flags controls various details of the demangled representation.
char *microsoftDemangle(std::string_view mangled_name, size_t *n_read,
int *status, MSDemangleFlags Flags = MSDF_None); int *status, MSDemangleFlags Flags = MSDF_None);
// Demangles a Rust v0 mangled symbol.
char *rustDemangle(std::string_view MangledName);
// Demangles a D mangled symbol.
char *dlangDemangle(std::string_view MangledName);
/// Attempt to demangle a string using different demangling schemes.
/// The function uses heuristics to determine which demangling scheme to use.
/// \param MangledName - reference to string to demangle.
/// \returns - the demangled string, or a copy of the input string if no
/// demangling occurred.
std::string demangle(std::string_view MangledName);
bool nonMicrosoftDemangle(std::string_view MangledName, std::string &Result);
/// "Partial" demangler. This supports demangling a string into an AST /// "Partial" demangler. This supports demangling a string into an AST
/// (typically an intermediate stage in itaniumDemangle) and querying certain /// (typically an intermediate stage in itaniumDemangle) and querying certain
/// properties or partially printing the demangled name. /// properties or partially printing the demangled name.
@ -59,7 +85,7 @@ struct ItaniumPartialDemangler {
bool partialDemangle(const char *MangledName); bool partialDemangle(const char *MangledName);
/// Just print the entire mangled name into Buf. Buf and N behave like the /// Just print the entire mangled name into Buf. Buf and N behave like the
/// second and third parameters to itaniumDemangle. /// second and third parameters to __cxa_demangle.
char *finishDemangle(char *Buf, size_t *N) const; char *finishDemangle(char *Buf, size_t *N) const;
/// Get the base name of a function. This doesn't include trailing template /// Get the base name of a function. This doesn't include trailing template
@ -95,6 +121,7 @@ struct ItaniumPartialDemangler {
bool isSpecialName() const; bool isSpecialName() const;
~ItaniumPartialDemangler(); ~ItaniumPartialDemangler();
private: private:
void *RootNode; void *RootNode;
void *Context; void *Context;

View file

@ -13,8 +13,8 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#ifndef LLVM_DEMANGLE_COMPILER_H #ifndef LLVM_DEMANGLE_DEMANGLECONFIG_H
#define LLVM_DEMANGLE_COMPILER_H #define LLVM_DEMANGLE_DEMANGLECONFIG_H
#ifndef __has_feature #ifndef __has_feature
#define __has_feature(x) 0 #define __has_feature(x) 0

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,96 @@
//===--- ItaniumNodes.def ------------*- mode:c++;eval:(read-only-mode) -*-===//
// Do not edit! See README.txt.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Define the demangler's node names
#ifndef NODE
#error Define NODE to handle nodes
#endif
NODE(NodeArrayNode)
NODE(DotSuffix)
NODE(VendorExtQualType)
NODE(QualType)
NODE(ConversionOperatorType)
NODE(PostfixQualifiedType)
NODE(ElaboratedTypeSpefType)
NODE(NameType)
NODE(AbiTagAttr)
NODE(EnableIfAttr)
NODE(ObjCProtoName)
NODE(PointerType)
NODE(ReferenceType)
NODE(PointerToMemberType)
NODE(ArrayType)
NODE(FunctionType)
NODE(NoexceptSpec)
NODE(DynamicExceptionSpec)
NODE(FunctionEncoding)
NODE(LiteralOperator)
NODE(SpecialName)
NODE(CtorVtableSpecialName)
NODE(QualifiedName)
NODE(NestedName)
NODE(LocalName)
NODE(ModuleName)
NODE(ModuleEntity)
NODE(VectorType)
NODE(PixelVectorType)
NODE(BinaryFPType)
NODE(BitIntType)
NODE(SyntheticTemplateParamName)
NODE(TypeTemplateParamDecl)
NODE(NonTypeTemplateParamDecl)
NODE(TemplateTemplateParamDecl)
NODE(TemplateParamPackDecl)
NODE(ParameterPack)
NODE(TemplateArgumentPack)
NODE(ParameterPackExpansion)
NODE(TemplateArgs)
NODE(ForwardTemplateReference)
NODE(NameWithTemplateArgs)
NODE(GlobalQualifiedName)
NODE(ExpandedSpecialSubstitution)
NODE(SpecialSubstitution)
NODE(CtorDtorName)
NODE(DtorName)
NODE(UnnamedTypeName)
NODE(ClosureTypeName)
NODE(StructuredBindingName)
NODE(BinaryExpr)
NODE(ArraySubscriptExpr)
NODE(PostfixExpr)
NODE(ConditionalExpr)
NODE(MemberExpr)
NODE(SubobjectExpr)
NODE(EnclosingExpr)
NODE(CastExpr)
NODE(SizeofParamPackExpr)
NODE(CallExpr)
NODE(NewExpr)
NODE(DeleteExpr)
NODE(PrefixExpr)
NODE(FunctionParam)
NODE(ConversionExpr)
NODE(PointerToMemberConversionExpr)
NODE(InitListExpr)
NODE(FoldExpr)
NODE(ThrowExpr)
NODE(BoolExpr)
NODE(StringLiteral)
NODE(LambdaExpr)
NODE(EnumLiteral)
NODE(IntegerLiteral)
NODE(FloatLiteral)
NODE(DoubleLiteral)
NODE(LongDoubleLiteral)
NODE(BracedExpr)
NODE(BracedRangeExpr)
#undef NODE

View file

@ -1,5 +1,5 @@
//===--- StringView.h -------------------------------------------*- C++ -*-===// //===--- StringView.h ----------------*- mode:c++;eval:(read-only-mode) -*-===//
// // Do not edit! See README.txt.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information. // See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project // SPDX-FileCopyrightText: Part of the LLVM Project
@ -8,6 +8,9 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// FIXME: Use std::string_view instead when we support C++17. // FIXME: Use std::string_view instead when we support C++17.
// There are two copies of this file in the source tree. The one under
// libcxxabi is the original and the one under llvm is the copy. Use
// cp-to-llvm.sh to update the copy. See README.txt for more details.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -15,7 +18,6 @@
#define DEMANGLE_STRINGVIEW_H #define DEMANGLE_STRINGVIEW_H
#include "DemangleConfig.h" #include "DemangleConfig.h"
#include <algorithm>
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
@ -37,29 +39,23 @@ public:
StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {} StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
StringView() : First(nullptr), Last(nullptr) {} StringView() : First(nullptr), Last(nullptr) {}
StringView substr(size_t From) const { StringView substr(size_t Pos, size_t Len = npos) const {
return StringView(begin() + From, size() - From); assert(Pos <= size());
if (Len > size() - Pos)
Len = size() - Pos;
return StringView(begin() + Pos, Len);
} }
size_t find(char C, size_t From = 0) const { size_t find(char C, size_t From = 0) const {
size_t FindBegin = std::min(From, size());
// Avoid calling memchr with nullptr. // Avoid calling memchr with nullptr.
if (FindBegin < size()) { if (From < size()) {
// Just forward to memchr, which is faster than a hand-rolled loop. // Just forward to memchr, which is faster than a hand-rolled loop.
if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin)) if (const void *P = ::memchr(First + From, C, size() - From))
return size_t(static_cast<const char *>(P) - First); return size_t(static_cast<const char *>(P) - First);
} }
return npos; return npos;
} }
StringView substr(size_t From, size_t To) const {
if (To >= size())
To = size() - 1;
if (From >= size())
From = size() - 1;
return StringView(First + From, First + To);
}
StringView dropFront(size_t N = 1) const { StringView dropFront(size_t N = 1) const {
if (N >= size()) if (N >= size())
N = size(); N = size();
@ -106,7 +102,7 @@ public:
bool startsWith(StringView Str) const { bool startsWith(StringView Str) const {
if (Str.size() > size()) if (Str.size() > size())
return false; return false;
return std::equal(Str.begin(), Str.end(), begin()); return std::strncmp(Str.begin(), begin(), Str.size()) == 0;
} }
const char &operator[](size_t Idx) const { return *(begin() + Idx); } const char &operator[](size_t Idx) const { return *(begin() + Idx); }
@ -119,7 +115,7 @@ public:
inline bool operator==(const StringView &LHS, const StringView &RHS) { inline bool operator==(const StringView &LHS, const StringView &RHS) {
return LHS.size() == RHS.size() && return LHS.size() == RHS.size() &&
std::equal(LHS.begin(), LHS.end(), RHS.begin()); std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0;
} }
DEMANGLE_NAMESPACE_END DEMANGLE_NAMESPACE_END

View file

@ -0,0 +1,39 @@
//===--- StringViewExtras.h ----------*- mode:c++;eval:(read-only-mode) -*-===//
// Do not edit! See README.txt.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// There are two copies of this file in the source tree. The one under
// libcxxabi is the original and the one under llvm is the copy. Use
// cp-to-llvm.sh to update the copy. See README.txt for more details.
//
//===----------------------------------------------------------------------===//
#ifndef DEMANGLE_STRINGVIEW_H
#define DEMANGLE_STRINGVIEW_H
#include "DemangleConfig.h"
#include <string_view>
DEMANGLE_NAMESPACE_BEGIN
inline bool starts_with(std::string_view self, char C) noexcept {
return !self.empty() && *self.begin() == C;
}
inline bool starts_with(std::string_view haystack,
std::string_view needle) noexcept {
if (needle.size() > haystack.size())
return false;
haystack.remove_suffix(haystack.size() - needle.size());
return haystack == needle;
}
DEMANGLE_NAMESPACE_END
#endif

View file

@ -1,5 +1,5 @@
//===--- Utility.h ----------------------------------------------*- C++ -*-===// //===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===//
// // Do not edit! See README.txt.
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information. // See https://llvm.org/LICENSE.txt for license information.
// SPDX-FileCopyrightText: Part of the LLVM Project // SPDX-FileCopyrightText: Part of the LLVM Project
@ -7,70 +7,83 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// Provide some utility classes for use in the demangler(s). // Provide some utility classes for use in the demangler.
// There are two copies of this file in the source tree. The one in libcxxabi
// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update
// the copy. See README.txt for more details.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#ifndef DEMANGLE_UTILITY_H #ifndef DEMANGLE_UTILITY_H
#define DEMANGLE_UTILITY_H #define DEMANGLE_UTILITY_H
#include "StringView.h" #include "DemangleConfig.h"
#include <array>
#include <cassert>
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <iterator> #include <exception>
#include <limits> #include <limits>
#include <string_view>
DEMANGLE_NAMESPACE_BEGIN DEMANGLE_NAMESPACE_BEGIN
// Stream that AST nodes write their string representation into after the AST // Stream that AST nodes write their string representation into after the AST
// has been parsed. // has been parsed.
class OutputStream { class OutputBuffer {
char *Buffer; char *Buffer = nullptr;
size_t CurrentPosition; size_t CurrentPosition = 0;
size_t BufferCapacity; size_t BufferCapacity = 0;
// Ensure there is at least n more positions in buffer. // Ensure there are at least N more positions in the buffer.
void grow(size_t N) { void grow(size_t N) {
if (N + CurrentPosition >= BufferCapacity) { size_t Need = N + CurrentPosition;
if (Need > BufferCapacity) {
// Reduce the number of reallocations, with a bit of hysteresis. The
// number here is chosen so the first allocation will more-than-likely not
// allocate more than 1K.
Need += 1024 - 32;
BufferCapacity *= 2; BufferCapacity *= 2;
if (BufferCapacity < N + CurrentPosition) if (BufferCapacity < Need)
BufferCapacity = N + CurrentPosition; BufferCapacity = Need;
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
if (Buffer == nullptr) if (Buffer == nullptr)
std::terminate(); std::terminate();
} }
} }
void writeUnsigned(uint64_t N, bool isNeg = false) { OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
// Handle special case... std::array<char, 21> Temp;
if (N == 0) { char *TempPtr = Temp.data() + Temp.size();
*this << '0';
return;
}
char Temp[21]; // Output at least one character.
char *TempPtr = std::end(Temp); do {
*--TempPtr = char('0' + N % 10);
while (N) {
*--TempPtr = '0' + char(N % 10);
N /= 10; N /= 10;
} } while (N);
// Add negative sign... // Add negative sign.
if (isNeg) if (isNeg)
*--TempPtr = '-'; *--TempPtr = '-';
this->operator<<(StringView(TempPtr, std::end(Temp)));
return operator+=(
std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr));
} }
public: public:
OutputStream(char *StartBuf, size_t Size) OutputBuffer(char *StartBuf, size_t Size)
: Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} : Buffer(StartBuf), BufferCapacity(Size) {}
OutputStream() = default; OutputBuffer(char *StartBuf, size_t *SizePtr)
void reset(char *Buffer_, size_t BufferCapacity_) { : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {}
CurrentPosition = 0; OutputBuffer() = default;
Buffer = Buffer_; // Non-copyable
BufferCapacity = BufferCapacity_; OutputBuffer(const OutputBuffer &) = delete;
OutputBuffer &operator=(const OutputBuffer &) = delete;
operator std::string_view() const {
return std::string_view(Buffer, CurrentPosition);
} }
/// If a ParameterPackExpansion (or similar type) is encountered, the offset /// If a ParameterPackExpansion (or similar type) is encountered, the offset
@ -78,115 +91,116 @@ public:
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
OutputStream &operator+=(StringView R) { /// When zero, we're printing template args and '>' needs to be parenthesized.
size_t Size = R.size(); /// Use a counter so we can simply increment inside parentheses.
if (Size == 0) unsigned GtIsGt = 1;
return *this;
grow(Size); bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
std::memmove(Buffer + CurrentPosition, R.begin(), Size);
CurrentPosition += Size; void printOpen(char Open = '(') {
GtIsGt++;
*this += Open;
}
void printClose(char Close = ')') {
GtIsGt--;
*this += Close;
}
OutputBuffer &operator+=(std::string_view R) {
if (size_t Size = R.size()) {
grow(Size);
std::memcpy(Buffer + CurrentPosition, &*R.begin(), Size);
CurrentPosition += Size;
}
return *this; return *this;
} }
OutputStream &operator+=(char C) { OutputBuffer &operator+=(char C) {
grow(1); grow(1);
Buffer[CurrentPosition++] = C; Buffer[CurrentPosition++] = C;
return *this; return *this;
} }
OutputStream &operator<<(StringView R) { return (*this += R); } OutputBuffer &prepend(std::string_view R) {
size_t Size = R.size();
OutputStream &operator<<(char C) { return (*this += C); } grow(Size);
std::memmove(Buffer + Size, Buffer, CurrentPosition);
std::memcpy(Buffer, &*R.begin(), Size);
CurrentPosition += Size;
OutputStream &operator<<(long long N) {
if (N < 0)
writeUnsigned(static_cast<unsigned long long>(-N), true);
else
writeUnsigned(static_cast<unsigned long long>(N));
return *this; return *this;
} }
OutputStream &operator<<(unsigned long long N) { OutputBuffer &operator<<(std::string_view R) { return (*this += R); }
writeUnsigned(N, false);
return *this; OutputBuffer &operator<<(char C) { return (*this += C); }
OutputBuffer &operator<<(long long N) {
return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
} }
OutputStream &operator<<(long N) { OutputBuffer &operator<<(unsigned long long N) {
return writeUnsigned(N, false);
}
OutputBuffer &operator<<(long N) {
return this->operator<<(static_cast<long long>(N)); return this->operator<<(static_cast<long long>(N));
} }
OutputStream &operator<<(unsigned long N) { OutputBuffer &operator<<(unsigned long N) {
return this->operator<<(static_cast<unsigned long long>(N)); return this->operator<<(static_cast<unsigned long long>(N));
} }
OutputStream &operator<<(int N) { OutputBuffer &operator<<(int N) {
return this->operator<<(static_cast<long long>(N)); return this->operator<<(static_cast<long long>(N));
} }
OutputStream &operator<<(unsigned int N) { OutputBuffer &operator<<(unsigned int N) {
return this->operator<<(static_cast<unsigned long long>(N)); return this->operator<<(static_cast<unsigned long long>(N));
} }
void insert(size_t Pos, const char *S, size_t N) {
assert(Pos <= CurrentPosition);
if (N == 0)
return;
grow(N);
std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
std::memcpy(Buffer + Pos, S, N);
CurrentPosition += N;
}
size_t getCurrentPosition() const { return CurrentPosition; } size_t getCurrentPosition() const { return CurrentPosition; }
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
char back() const { char back() const {
return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; assert(CurrentPosition);
return Buffer[CurrentPosition - 1];
} }
bool empty() const { return CurrentPosition == 0; } bool empty() const { return CurrentPosition == 0; }
char *getBuffer() { return Buffer; } char *getBuffer() { return Buffer; }
char *getBufferEnd() { return Buffer + CurrentPosition - 1; } char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
size_t getBufferCapacity() { return BufferCapacity; } size_t getBufferCapacity() const { return BufferCapacity; }
}; };
template <class T> class SwapAndRestore { template <class T> class ScopedOverride {
T &Restore; T &Loc;
T OriginalValue; T Original;
bool ShouldRestore = true;
public: public:
SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
SwapAndRestore(T &Restore_, T NewVal) ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
: Restore(Restore_), OriginalValue(Restore) { Loc_ = std::move(NewVal);
Restore = std::move(NewVal);
}
~SwapAndRestore() {
if (ShouldRestore)
Restore = std::move(OriginalValue);
} }
~ScopedOverride() { Loc = std::move(Original); }
void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } ScopedOverride(const ScopedOverride &) = delete;
ScopedOverride &operator=(const ScopedOverride &) = delete;
void restoreNow(bool Force) {
if (!Force && !ShouldRestore)
return;
Restore = std::move(OriginalValue);
ShouldRestore = false;
}
SwapAndRestore(const SwapAndRestore &) = delete;
SwapAndRestore &operator=(const SwapAndRestore &) = delete;
}; };
inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
size_t InitSize) {
size_t BufferSize;
if (Buf == nullptr) {
Buf = static_cast<char *>(std::malloc(InitSize));
if (Buf == nullptr)
return false;
BufferSize = InitSize;
} else
BufferSize = *N;
S.reset(Buf, BufferSize);
return true;
}
DEMANGLE_NAMESPACE_END DEMANGLE_NAMESPACE_END
#endif #endif