diff options
96 files changed, 2937 insertions, 2645 deletions
diff --git a/.ci/scripts/linux/docker.sh b/.ci/scripts/linux/docker.sh index 7f6d2ad1b..e5d83d4b9 100755 --- a/.ci/scripts/linux/docker.sh +++ b/.ci/scripts/linux/docker.sh @@ -35,7 +35,7 @@ DESTDIR="$PWD/AppDir" ninja install rm -vf AppDir/usr/bin/yuzu-cmd AppDir/usr/bin/yuzu-tester # Download tools needed to build an AppImage -wget -nc https://raw.githubusercontent.com/yuzu-emu/ext-linux-bin/main/gcc/deploy-linux.sh +wget -nc https://raw.githubusercontent.com/yuzu-emu/ext-linux-bin/main/appimage/deploy-linux.sh wget -nc https://raw.githubusercontent.com/yuzu-emu/AppImageKit-checkrt/old/AppRun.sh wget -nc https://github.com/yuzu-emu/ext-linux-bin/raw/main/appimage/exec-x86_64.so # Set executable bit diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml index d069fa9c3..1e259df05 100644 --- a/.ci/templates/build-msvc.yml +++ b/.ci/templates/build-msvc.yml @@ -12,7 +12,7 @@ steps: inputs: targetType: 'filePath' filePath: './.ci/scripts/windows/install-vulkan-sdk.ps1' -- script: refreshenv && glslangValidator --version && mkdir build && cd build && cmake -E env CXXFLAGS="/Gw /GA /Gr /Ob2" cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_DEFAULT_CMP0069=NEW -DYUZU_ENABLE_LTO=ON -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd .. +- script: refreshenv && glslangValidator --version && mkdir build && cd build && cmake -E env CXXFLAGS="/Gw" cmake -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_DEFAULT_CMP0069=NEW -DYUZU_ENABLE_LTO=ON -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd .. displayName: 'Configure CMake' - task: MSBuild@1 displayName: 'Build' diff --git a/CMakeLists.txt b/CMakeLists.txt index 9023d2072..af9f394f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -136,6 +136,22 @@ if (YUZU_USE_BUNDLED_VCPKG) endif() endif() + if (MSVC) + set(VCPKG_DOWNLOADS_PATH ${PROJECT_SOURCE_DIR}/externals/vcpkg/downloads) + set(NASM_VERSION "2.16.01") + set(NASM_DESTINATION_PATH ${VCPKG_DOWNLOADS_PATH}/nasm-${NASM_VERSION}-win64.zip) + set(NASM_DOWNLOAD_URL "https://github.com/yuzu-emu/ext-windows-bin/raw/master/nasm/nasm-${NASM_VERSION}-win64.zip") + + if (NOT EXISTS ${NASM_DESTINATION_PATH}) + file(DOWNLOAD ${NASM_DOWNLOAD_URL} ${NASM_DESTINATION_PATH} SHOW_PROGRESS STATUS NASM_STATUS) + + if (NOT NASM_STATUS EQUAL 0) + # Warn and not fail since vcpkg is supposed to download this package for us in the first place + message(WARNING "External nasm vcpkg package download from ${NASM_DOWNLOAD_URL} failed with status ${NASM_STATUS}") + endif() + endif() + endif() + if (YUZU_TESTS) list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests") endif() @@ -289,7 +305,7 @@ find_package(Boost 1.79.0 REQUIRED context) find_package(enet 1.3 MODULE) find_package(fmt 9 REQUIRED) find_package(inih 52 MODULE COMPONENTS INIReader) -find_package(LLVM MODULE COMPONENTS Demangle) +find_package(LLVM 17 MODULE COMPONENTS Demangle) find_package(lz4 REQUIRED) find_package(nlohmann_json 3.8 REQUIRED) find_package(Opus 1.3 MODULE) diff --git a/externals/demangle/ItaniumDemangle.cpp b/externals/demangle/ItaniumDemangle.cpp index b055a2fd7..47dd5d301 100644 --- a/externals/demangle/ItaniumDemangle.cpp +++ b/externals/demangle/ItaniumDemangle.cpp @@ -20,9 +20,7 @@ #include <cstdlib> #include <cstring> #include <functional> -#include <numeric> #include <utility> -#include <vector> using namespace llvm; using namespace llvm::itanium_demangle; @@ -81,8 +79,8 @@ struct DumpVisitor { } void printStr(const char *S) { fprintf(stderr, "%s", S); } - void print(StringView SV) { - fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.begin()); + void print(std::string_view SV) { + fprintf(stderr, "\"%.*s\"", (int)SV.size(), SV.data()); } void print(const Node *N) { if (N) @@ -90,14 +88,6 @@ struct DumpVisitor { else 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) { ++Depth; printStr("{"); @@ -116,13 +106,11 @@ struct DumpVisitor { // Overload used when T is exactly 'bool', not merely convertible to 'bool'. void print(bool B) { printStr(B ? "true" : "false"); } - template <class T> - typename std::enable_if<std::is_unsigned<T>::value>::type print(T N) { + template <class T> std::enable_if_t<std::is_unsigned<T>::value> print(T N) { fprintf(stderr, "%llu", (unsigned long long)N); } - template <class T> - typename std::enable_if<std::is_signed<T>::value>::type print(T N) { + template <class T> std::enable_if_t<std::is_signed<T>::value> print(T N) { fprintf(stderr, "%lld", (long long)N); } @@ -185,6 +173,50 @@ struct DumpVisitor { 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() { printStr("\n"); @@ -334,36 +366,21 @@ public: using Demangler = itanium_demangle::ManglingParser<DefaultAllocator>; -char *llvm::itaniumDemangle(const char *MangledName, char *Buf, - size_t *N, int *Status) { - if (MangledName == nullptr || (Buf != nullptr && N == nullptr)) { - if (Status) - *Status = demangle_invalid_args; +char *llvm::itaniumDemangle(std::string_view MangledName) { + if (MangledName.empty()) 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(); + if (!AST) + return nullptr; - if (AST == nullptr) - InternalStatus = demangle_invalid_mangled_name; - else if (!initializeOutputStream(Buf, N, S, 1024)) - InternalStatus = demangle_memory_alloc_failure; - else { - 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; + OutputBuffer OB; + assert(Parser.ForwardTemplateRefs.empty()); + AST->print(OB); + OB += '\0'; + return OB.getBuffer(); } ItaniumPartialDemangler::ItaniumPartialDemangler() @@ -396,14 +413,12 @@ bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) { } static char *printNode(const Node *RootNode, char *Buf, size_t *N) { - OutputStream S; - if (!initializeOutputStream(Buf, N, S, 128)) - return nullptr; - RootNode->print(S); - S += '\0'; + OutputBuffer OB(Buf, N); + RootNode->print(OB); + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - return S.getBuffer(); + *N = OB.getCurrentPosition(); + return OB.getBuffer(); } 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: Name = static_cast<const AbiTagAttr *>(Name)->Base; continue; - case Node::KStdQualifiedName: - Name = static_cast<const StdQualifiedName *>(Name)->Child; + case Node::KModuleEntity: + Name = static_cast<const ModuleEntity *>(Name)->Name; continue; case Node::KNestedName: Name = static_cast<const NestedName *>(Name)->Name; @@ -441,9 +456,7 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, return nullptr; const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName(); - OutputStream S; - if (!initializeOutputStream(Buf, N, S, 128)) - return nullptr; + OutputBuffer OB(Buf, N); KeepGoingLocalFunction: while (true) { @@ -458,27 +471,27 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf, break; } + if (Name->getKind() == Node::KModuleEntity) + Name = static_cast<const ModuleEntity *>(Name)->Name; + switch (Name->getKind()) { - case Node::KStdQualifiedName: - S += "std"; - break; case Node::KNestedName: - static_cast<const NestedName *>(Name)->Qual->print(S); + static_cast<const NestedName *>(Name)->Qual->print(OB); break; case Node::KLocalName: { auto *LN = static_cast<const LocalName *>(Name); - LN->Encoding->print(S); - S += "::"; + LN->Encoding->print(OB); + OB += "::"; Name = LN->Entity; goto KeepGoingLocalFunction; } default: break; } - S += '\0'; + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - return S.getBuffer(); + *N = OB.getCurrentPosition(); + return OB.getBuffer(); } char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const { @@ -494,17 +507,15 @@ char *ItaniumPartialDemangler::getFunctionParameters(char *Buf, return nullptr; NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams(); - OutputStream S; - if (!initializeOutputStream(Buf, N, S, 128)) - return nullptr; + OutputBuffer OB(Buf, N); - S += '('; - Params.printWithComma(S); - S += ')'; - S += '\0'; + OB += '('; + Params.printWithComma(OB); + OB += ')'; + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - return S.getBuffer(); + *N = OB.getCurrentPosition(); + return OB.getBuffer(); } char *ItaniumPartialDemangler::getFunctionReturnType( @@ -512,18 +523,16 @@ char *ItaniumPartialDemangler::getFunctionReturnType( if (!isFunction()) return nullptr; - OutputStream S; - if (!initializeOutputStream(Buf, N, S, 128)) - return nullptr; + OutputBuffer OB(Buf, N); if (const Node *Ret = static_cast<const FunctionEncoding *>(RootNode)->getReturnType()) - Ret->print(S); + Ret->print(OB); - S += '\0'; + OB += '\0'; if (N != nullptr) - *N = S.getCurrentPosition(); - return S.getBuffer(); + *N = OB.getCurrentPosition(); + return OB.getBuffer(); } char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const { @@ -563,8 +572,8 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const { case Node::KNestedName: N = static_cast<const NestedName *>(N)->Name; break; - case Node::KStdQualifiedName: - N = static_cast<const StdQualifiedName *>(N)->Child; + case Node::KModuleEntity: + N = static_cast<const ModuleEntity *>(N)->Name; break; } } diff --git a/externals/demangle/llvm/Demangle/Demangle.h b/externals/demangle/llvm/Demangle/Demangle.h index 5b673e4e1..1552a501a 100644 --- a/externals/demangle/llvm/Demangle/Demangle.h +++ b/externals/demangle/llvm/Demangle/Demangle.h @@ -12,6 +12,7 @@ #include <cstddef> #include <string> +#include <string_view> namespace llvm { /// This is a llvm local version of __cxa_demangle. Other than the name and @@ -29,9 +30,10 @@ enum : int { demangle_success = 0, }; -char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n, - int *status); - +/// Returns a non-NULL pointer to a NUL-terminated C style string +/// 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 { MSDF_None = 0, @@ -40,10 +42,34 @@ enum MSDemangleFlags { MSDF_NoCallingConvention = 1 << 2, MSDF_NoReturnType = 1 << 3, 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); +// 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 /// (typically an intermediate stage in itaniumDemangle) and querying certain /// properties or partially printing the demangled name. @@ -59,7 +85,7 @@ struct ItaniumPartialDemangler { bool partialDemangle(const char *MangledName); /// 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; /// Get the base name of a function. This doesn't include trailing template @@ -95,6 +121,7 @@ struct ItaniumPartialDemangler { bool isSpecialName() const; ~ItaniumPartialDemangler(); + private: void *RootNode; void *Context; diff --git a/externals/demangle/llvm/Demangle/DemangleConfig.h b/externals/demangle/llvm/Demangle/DemangleConfig.h index a8aef9df1..c7f86d766 100644 --- a/externals/demangle/llvm/Demangle/DemangleConfig.h +++ b/externals/demangle/llvm/Demangle/DemangleConfig.h @@ -13,8 +13,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_DEMANGLE_COMPILER_H -#define LLVM_DEMANGLE_COMPILER_H +#ifndef LLVM_DEMANGLE_DEMANGLECONFIG_H +#define LLVM_DEMANGLE_DEMANGLECONFIG_H #ifndef __has_feature #define __has_feature(x) 0 diff --git a/externals/demangle/llvm/Demangle/ItaniumDemangle.h b/externals/demangle/llvm/Demangle/ItaniumDemangle.h index 64b35c142..0dc3d7337 100644 --- a/externals/demangle/llvm/Demangle/ItaniumDemangle.h +++ b/externals/demangle/llvm/Demangle/ItaniumDemangle.h @@ -1,5 +1,5 @@ -//===------------------------- ItaniumDemangle.h ----------------*- C++ -*-===// -// +//===--- ItaniumDemangle.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 @@ -7,144 +7,220 @@ // //===----------------------------------------------------------------------===// // -// Generic itanium demangler library. This file has two byte-per-byte identical -// copies in the source tree, one in libcxxabi, and the other in llvm. +// Generic itanium demangler library. +// 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_ITANIUMDEMANGLE_H #define DEMANGLE_ITANIUMDEMANGLE_H -// FIXME: (possibly) incomplete list of features that clang mangles that this -// file does not yet support: -// - C++ modules TS - #include "DemangleConfig.h" -#include "StringView.h" +#include "StringViewExtras.h" #include "Utility.h" +#include <algorithm> #include <cassert> #include <cctype> #include <cstdio> #include <cstdlib> #include <cstring> -#include <numeric> +#include <limits> +#include <new> +#include <string_view> +#include <type_traits> #include <utility> -#define FOR_EACH_NODE_KIND(X) \ - X(NodeArrayNode) \ - X(DotSuffix) \ - X(VendorExtQualType) \ - X(QualType) \ - X(ConversionOperatorType) \ - X(PostfixQualifiedType) \ - X(ElaboratedTypeSpefType) \ - X(NameType) \ - X(AbiTagAttr) \ - X(EnableIfAttr) \ - X(ObjCProtoName) \ - X(PointerType) \ - X(ReferenceType) \ - X(PointerToMemberType) \ - X(ArrayType) \ - X(FunctionType) \ - X(NoexceptSpec) \ - X(DynamicExceptionSpec) \ - X(FunctionEncoding) \ - X(LiteralOperator) \ - X(SpecialName) \ - X(CtorVtableSpecialName) \ - X(QualifiedName) \ - X(NestedName) \ - X(LocalName) \ - X(VectorType) \ - X(PixelVectorType) \ - X(SyntheticTemplateParamName) \ - X(TypeTemplateParamDecl) \ - X(NonTypeTemplateParamDecl) \ - X(TemplateTemplateParamDecl) \ - X(TemplateParamPackDecl) \ - X(ParameterPack) \ - X(TemplateArgumentPack) \ - X(ParameterPackExpansion) \ - X(TemplateArgs) \ - X(ForwardTemplateReference) \ - X(NameWithTemplateArgs) \ - X(GlobalQualifiedName) \ - X(StdQualifiedName) \ - X(ExpandedSpecialSubstitution) \ - X(SpecialSubstitution) \ - X(CtorDtorName) \ - X(DtorName) \ - X(UnnamedTypeName) \ - X(ClosureTypeName) \ - X(StructuredBindingName) \ - X(BinaryExpr) \ - X(ArraySubscriptExpr) \ - X(PostfixExpr) \ - X(ConditionalExpr) \ - X(MemberExpr) \ - X(EnclosingExpr) \ - X(CastExpr) \ - X(SizeofParamPackExpr) \ - X(CallExpr) \ - X(NewExpr) \ - X(DeleteExpr) \ - X(PrefixExpr) \ - X(FunctionParam) \ - X(ConversionExpr) \ - X(InitListExpr) \ - X(FoldExpr) \ - X(ThrowExpr) \ - X(UUIDOfExpr) \ - X(BoolExpr) \ - X(StringLiteral) \ - X(LambdaExpr) \ - X(IntegerCastExpr) \ - X(IntegerLiteral) \ - X(FloatLiteral) \ - X(DoubleLiteral) \ - X(LongDoubleLiteral) \ - X(BracedExpr) \ - X(BracedRangeExpr) - DEMANGLE_NAMESPACE_BEGIN +template <class T, size_t N> class PODSmallVector { + static_assert(std::is_pod<T>::value, + "T is required to be a plain old data type"); + + T *First = nullptr; + T *Last = nullptr; + T *Cap = nullptr; + T Inline[N] = {0}; + + bool isInline() const { return First == Inline; } + + void clearInline() { + First = Inline; + Last = Inline; + Cap = Inline + N; + } + + void reserve(size_t NewCap) { + size_t S = size(); + if (isInline()) { + auto *Tmp = static_cast<T *>(std::malloc(NewCap * sizeof(T))); + if (Tmp == nullptr) + std::terminate(); + std::copy(First, Last, Tmp); + First = Tmp; + } else { + First = static_cast<T *>(std::realloc(First, NewCap * sizeof(T))); + if (First == nullptr) + std::terminate(); + } + Last = First + S; + Cap = First + NewCap; + } + +public: + PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} + + PODSmallVector(const PODSmallVector &) = delete; + PODSmallVector &operator=(const PODSmallVector &) = delete; + + PODSmallVector(PODSmallVector &&Other) : PODSmallVector() { + if (Other.isInline()) { + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return; + } + + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + } + + PODSmallVector &operator=(PODSmallVector &&Other) { + if (Other.isInline()) { + if (!isInline()) { + std::free(First); + clearInline(); + } + std::copy(Other.begin(), Other.end(), First); + Last = First + Other.size(); + Other.clear(); + return *this; + } + + if (isInline()) { + First = Other.First; + Last = Other.Last; + Cap = Other.Cap; + Other.clearInline(); + return *this; + } + + std::swap(First, Other.First); + std::swap(Last, Other.Last); + std::swap(Cap, Other.Cap); + Other.clear(); + return *this; + } + + // NOLINTNEXTLINE(readability-identifier-naming) + void push_back(const T &Elem) { + if (Last == Cap) + reserve(size() * 2); + *Last++ = Elem; + } + + // NOLINTNEXTLINE(readability-identifier-naming) + void pop_back() { + assert(Last != First && "Popping empty vector!"); + --Last; + } + + void dropBack(size_t Index) { + assert(Index <= size() && "dropBack() can't expand!"); + Last = First + Index; + } + + T *begin() { return First; } + T *end() { return Last; } + + bool empty() const { return First == Last; } + size_t size() const { return static_cast<size_t>(Last - First); } + T &back() { + assert(Last != First && "Calling back() on empty vector!"); + return *(Last - 1); + } + T &operator[](size_t Index) { + assert(Index < size() && "Invalid access!"); + return *(begin() + Index); + } + void clear() { Last = First; } + + ~PODSmallVector() { + if (!isInline()) + std::free(First); + } +}; + // Base class of all AST nodes. The AST is built by the parser, then is // traversed by the printLeft/Right functions to produce a demangled string. class Node { public: enum Kind : unsigned char { -#define ENUMERATOR(NodeKind) K ## NodeKind, - FOR_EACH_NODE_KIND(ENUMERATOR) -#undef ENUMERATOR +#define NODE(NodeKind) K##NodeKind, +#include "ItaniumNodes.def" }; /// Three-way bool to track a cached value. Unknown is possible if this node /// has an unexpanded parameter pack below it that may affect this cache. enum class Cache : unsigned char { Yes, No, Unknown, }; + /// Operator precedence for expression nodes. Used to determine required + /// parens in expression emission. + enum class Prec { + Primary, + Postfix, + Unary, + Cast, + PtrMem, + Multiplicative, + Additive, + Shift, + Spaceship, + Relational, + Equality, + And, + Xor, + Ior, + AndIf, + OrIf, + Conditional, + Assign, + Comma, + Default, + }; + private: Kind K; + Prec Precedence : 6; + // FIXME: Make these protected. public: /// Tracks if this node has a component on its right side, in which case we /// need to call printRight. - Cache RHSComponentCache; + Cache RHSComponentCache : 2; /// Track if this node is a (possibly qualified) array type. This can affect /// how we format the output string. - Cache ArrayCache; + Cache ArrayCache : 2; /// Track if this node is a (possibly qualified) function type. This can /// affect how we format the output string. - Cache FunctionCache; + Cache FunctionCache : 2; public: - Node(Kind K_, Cache RHSComponentCache_ = Cache::No, - Cache ArrayCache_ = Cache::No, Cache FunctionCache_ = Cache::No) - : K(K_), RHSComponentCache(RHSComponentCache_), ArrayCache(ArrayCache_), - FunctionCache(FunctionCache_) {} + Node(Kind K_, Prec Precedence_ = Prec::Primary, + Cache RHSComponentCache_ = Cache::No, Cache ArrayCache_ = Cache::No, + Cache FunctionCache_ = Cache::No) + : K(K_), Precedence(Precedence_), RHSComponentCache(RHSComponentCache_), + ArrayCache(ArrayCache_), FunctionCache(FunctionCache_) {} + Node(Kind K_, Cache RHSComponentCache_, Cache ArrayCache_ = Cache::No, + Cache FunctionCache_ = Cache::No) + : Node(K_, Prec::Primary, RHSComponentCache_, ArrayCache_, + FunctionCache_) {} /// Visit the most-derived object corresponding to this object. template<typename Fn> void visit(Fn F) const; @@ -155,52 +231,65 @@ public: // would construct an equivalent node. //template<typename Fn> void match(Fn F) const; - bool hasRHSComponent(OutputStream &S) const { + bool hasRHSComponent(OutputBuffer &OB) const { if (RHSComponentCache != Cache::Unknown) return RHSComponentCache == Cache::Yes; - return hasRHSComponentSlow(S); + return hasRHSComponentSlow(OB); } - bool hasArray(OutputStream &S) const { + bool hasArray(OutputBuffer &OB) const { if (ArrayCache != Cache::Unknown) return ArrayCache == Cache::Yes; - return hasArraySlow(S); + return hasArraySlow(OB); } - bool hasFunction(OutputStream &S) const { + bool hasFunction(OutputBuffer &OB) const { if (FunctionCache != Cache::Unknown) return FunctionCache == Cache::Yes; - return hasFunctionSlow(S); + return hasFunctionSlow(OB); } Kind getKind() const { return K; } - virtual bool hasRHSComponentSlow(OutputStream &) const { return false; } - virtual bool hasArraySlow(OutputStream &) const { return false; } - virtual bool hasFunctionSlow(OutputStream &) const { return false; } + Prec getPrecedence() const { return Precedence; } + + virtual bool hasRHSComponentSlow(OutputBuffer &) const { return false; } + virtual bool hasArraySlow(OutputBuffer &) const { return false; } + virtual bool hasFunctionSlow(OutputBuffer &) const { return false; } // Dig through "glue" nodes like ParameterPack and ForwardTemplateReference to // get at a node that actually represents some concrete syntax. - virtual const Node *getSyntaxNode(OutputStream &) const { - return this; - } - - void print(OutputStream &S) const { - printLeft(S); + virtual const Node *getSyntaxNode(OutputBuffer &) const { return this; } + + // Print this node as an expression operand, surrounding it in parentheses if + // its precedence is [Strictly] weaker than P. + void printAsOperand(OutputBuffer &OB, Prec P = Prec::Default, + bool StrictlyWorse = false) const { + bool Paren = + unsigned(getPrecedence()) >= unsigned(P) + unsigned(StrictlyWorse); + if (Paren) + OB.printOpen(); + print(OB); + if (Paren) + OB.printClose(); + } + + void print(OutputBuffer &OB) const { + printLeft(OB); if (RHSComponentCache != Cache::No) - printRight(S); + printRight(OB); } - // Print the "left" side of this Node into OutputStream. - virtual void printLeft(OutputStream &) const = 0; + // Print the "left" side of this Node into OutputBuffer. + virtual void printLeft(OutputBuffer &) const = 0; // Print the "right". This distinction is necessary to represent C++ types // that appear on the RHS of their subtype, such as arrays or functions. // Since most types don't have such a component, provide a default // implementation. - virtual void printRight(OutputStream &) const {} + virtual void printRight(OutputBuffer &) const {} - virtual StringView getBaseName() const { return StringView(); } + virtual std::string_view getBaseName() const { return {}; } // Silence compiler warnings, this dtor will never be called. virtual ~Node() = default; @@ -227,19 +316,19 @@ public: Node *operator[](size_t Idx) const { return Elements[Idx]; } - void printWithComma(OutputStream &S) const { + void printWithComma(OutputBuffer &OB) const { bool FirstElement = true; for (size_t Idx = 0; Idx != NumElements; ++Idx) { - size_t BeforeComma = S.getCurrentPosition(); + size_t BeforeComma = OB.getCurrentPosition(); if (!FirstElement) - S += ", "; - size_t AfterComma = S.getCurrentPosition(); - Elements[Idx]->print(S); + OB += ", "; + size_t AfterComma = OB.getCurrentPosition(); + Elements[Idx]->printAsOperand(OB, Node::Prec::Comma); // Elements[Idx] is an empty parameter pack expansion, we should erase the // comma we just printed. - if (AfterComma == S.getCurrentPosition()) { - S.setCurrentPosition(BeforeComma); + if (AfterComma == OB.getCurrentPosition()) { + OB.setCurrentPosition(BeforeComma); continue; } @@ -254,43 +343,48 @@ struct NodeArrayNode : Node { template<typename Fn> void match(Fn F) const { F(Array); } - void printLeft(OutputStream &S) const override { - Array.printWithComma(S); - } + void printLeft(OutputBuffer &OB) const override { Array.printWithComma(OB); } }; class DotSuffix final : public Node { const Node *Prefix; - const StringView Suffix; + const std::string_view Suffix; public: - DotSuffix(const Node *Prefix_, StringView Suffix_) + DotSuffix(const Node *Prefix_, std::string_view Suffix_) : Node(KDotSuffix), Prefix(Prefix_), Suffix(Suffix_) {} template<typename Fn> void match(Fn F) const { F(Prefix, Suffix); } - void printLeft(OutputStream &s) const override { - Prefix->print(s); - s += " ("; - s += Suffix; - s += ")"; + void printLeft(OutputBuffer &OB) const override { + Prefix->print(OB); + OB += " ("; + OB += Suffix; + OB += ")"; } }; class VendorExtQualType final : public Node { const Node *Ty; - StringView Ext; + std::string_view Ext; + const Node *TA; public: - VendorExtQualType(const Node *Ty_, StringView Ext_) - : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_) {} + VendorExtQualType(const Node *Ty_, std::string_view Ext_, const Node *TA_) + : Node(KVendorExtQualType), Ty(Ty_), Ext(Ext_), TA(TA_) {} + + const Node *getTy() const { return Ty; } + std::string_view getExt() const { return Ext; } + const Node *getTA() const { return TA; } - template<typename Fn> void match(Fn F) const { F(Ty, Ext); } + template <typename Fn> void match(Fn F) const { F(Ty, Ext, TA); } - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += " "; - S += Ext; + void printLeft(OutputBuffer &OB) const override { + Ty->print(OB); + OB += " "; + OB += Ext; + if (TA != nullptr) + TA->print(OB); } }; @@ -316,13 +410,13 @@ protected: const Qualifiers Quals; const Node *Child; - void printQuals(OutputStream &S) const { + void printQuals(OutputBuffer &OB) const { if (Quals & QualConst) - S += " const"; + OB += " const"; if (Quals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (Quals & QualRestrict) - S += " restrict"; + OB += " restrict"; } public: @@ -331,24 +425,27 @@ public: Child_->ArrayCache, Child_->FunctionCache), Quals(Quals_), Child(Child_) {} + Qualifiers getQuals() const { return Quals; } + const Node *getChild() const { return Child; } + template<typename Fn> void match(Fn F) const { F(Child, Quals); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Child->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Child->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { - return Child->hasArray(S); + bool hasArraySlow(OutputBuffer &OB) const override { + return Child->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { - return Child->hasFunction(S); + bool hasFunctionSlow(OutputBuffer &OB) const override { + return Child->hasFunction(OB); } - void printLeft(OutputStream &S) const override { - Child->printLeft(S); - printQuals(S); + void printLeft(OutputBuffer &OB) const override { + Child->printLeft(OB); + printQuals(OB); } - void printRight(OutputStream &S) const override { Child->printRight(S); } + void printRight(OutputBuffer &OB) const override { Child->printRight(OB); } }; class ConversionOperatorType final : public Node { @@ -360,74 +457,96 @@ public: template<typename Fn> void match(Fn F) const { F(Ty); } - void printLeft(OutputStream &S) const override { - S += "operator "; - Ty->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "operator "; + Ty->print(OB); } }; class PostfixQualifiedType final : public Node { const Node *Ty; - const StringView Postfix; + const std::string_view Postfix; public: - PostfixQualifiedType(Node *Ty_, StringView Postfix_) + PostfixQualifiedType(const Node *Ty_, std::string_view Postfix_) : Node(KPostfixQualifiedType), Ty(Ty_), Postfix(Postfix_) {} template<typename Fn> void match(Fn F) const { F(Ty, Postfix); } - void printLeft(OutputStream &s) const override { - Ty->printLeft(s); - s += Postfix; + void printLeft(OutputBuffer &OB) const override { + Ty->printLeft(OB); + OB += Postfix; } }; class NameType final : public Node { - const StringView Name; + const std::string_view Name; public: - NameType(StringView Name_) : Node(KNameType), Name(Name_) {} + NameType(std::string_view Name_) : Node(KNameType), Name(Name_) {} template<typename Fn> void match(Fn F) const { F(Name); } - StringView getName() const { return Name; } - StringView getBaseName() const override { return Name; } + std::string_view getName() const { return Name; } + std::string_view getBaseName() const override { return Name; } + + void printLeft(OutputBuffer &OB) const override { OB += Name; } +}; + +class BitIntType final : public Node { + const Node *Size; + bool Signed; + +public: + BitIntType(const Node *Size_, bool Signed_) + : Node(KBitIntType), Size(Size_), Signed(Signed_) {} + + template <typename Fn> void match(Fn F) const { F(Size, Signed); } - void printLeft(OutputStream &s) const override { s += Name; } + void printLeft(OutputBuffer &OB) const override { + if (!Signed) + OB += "unsigned "; + OB += "_BitInt"; + OB.printOpen(); + Size->printAsOperand(OB); + OB.printClose(); + } }; class ElaboratedTypeSpefType : public Node { - StringView Kind; + std::string_view Kind; Node *Child; public: - ElaboratedTypeSpefType(StringView Kind_, Node *Child_) + ElaboratedTypeSpefType(std::string_view Kind_, Node *Child_) : Node(KElaboratedTypeSpefType), Kind(Kind_), Child(Child_) {} template<typename Fn> void match(Fn F) const { F(Kind, Child); } - void printLeft(OutputStream &S) const override { - S += Kind; - S += ' '; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += Kind; + OB += ' '; + Child->print(OB); } }; struct AbiTagAttr : Node { Node *Base; - StringView Tag; + std::string_view Tag; - AbiTagAttr(Node* Base_, StringView Tag_) - : Node(KAbiTagAttr, Base_->RHSComponentCache, - Base_->ArrayCache, Base_->FunctionCache), + AbiTagAttr(Node *Base_, std::string_view Tag_) + : Node(KAbiTagAttr, Base_->RHSComponentCache, Base_->ArrayCache, + Base_->FunctionCache), Base(Base_), Tag(Tag_) {} template<typename Fn> void match(Fn F) const { F(Base, Tag); } - void printLeft(OutputStream &S) const override { - Base->printLeft(S); - S += "[abi:"; - S += Tag; - S += "]"; + std::string_view getBaseName() const override { return Base->getBaseName(); } + + void printLeft(OutputBuffer &OB) const override { + Base->printLeft(OB); + OB += "[abi:"; + OB += Tag; + OB += "]"; } }; @@ -439,21 +558,21 @@ public: template<typename Fn> void match(Fn F) const { F(Conditions); } - void printLeft(OutputStream &S) const override { - S += " [enable_if:"; - Conditions.printWithComma(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += " [enable_if:"; + Conditions.printWithComma(OB); + OB += ']'; } }; class ObjCProtoName : public Node { const Node *Ty; - StringView Protocol; + std::string_view Protocol; friend class PointerType; public: - ObjCProtoName(const Node *Ty_, StringView Protocol_) + ObjCProtoName(const Node *Ty_, std::string_view Protocol_) : Node(KObjCProtoName), Ty(Ty_), Protocol(Protocol_) {} template<typename Fn> void match(Fn F) const { F(Ty, Protocol); } @@ -463,11 +582,11 @@ public: static_cast<const NameType *>(Ty)->getName() == "objc_object"; } - void printLeft(OutputStream &S) const override { - Ty->print(S); - S += "<"; - S += Protocol; - S += ">"; + void printLeft(OutputBuffer &OB) const override { + Ty->print(OB); + OB += "<"; + OB += Protocol; + OB += ">"; } }; @@ -479,36 +598,38 @@ public: : Node(KPointerType, Pointee_->RHSComponentCache), Pointee(Pointee_) {} + const Node *getPointee() const { return Pointee; } + template<typename Fn> void match(Fn F) const { F(Pointee); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Pointee->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { // We rewrite objc_object<SomeProtocol>* into id<SomeProtocol>. if (Pointee->getKind() != KObjCProtoName || !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { - Pointee->printLeft(s); - if (Pointee->hasArray(s)) - s += " "; - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += "("; - s += "*"; + Pointee->printLeft(OB); + if (Pointee->hasArray(OB)) + OB += " "; + if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) + OB += "("; + OB += "*"; } else { const auto *objcProto = static_cast<const ObjCProtoName *>(Pointee); - s += "id<"; - s += objcProto->Protocol; - s += ">"; + OB += "id<"; + OB += objcProto->Protocol; + OB += ">"; } } - void printRight(OutputStream &s) const override { + void printRight(OutputBuffer &OB) const override { if (Pointee->getKind() != KObjCProtoName || !static_cast<const ObjCProtoName *>(Pointee)->isObjCObject()) { - if (Pointee->hasArray(s) || Pointee->hasFunction(s)) - s += ")"; - Pointee->printRight(s); + if (Pointee->hasArray(OB) || Pointee->hasFunction(OB)) + OB += ")"; + Pointee->printRight(OB); } } }; @@ -528,15 +649,30 @@ class ReferenceType : public Node { // Dig through any refs to refs, collapsing the ReferenceTypes as we go. The // rule here is rvalue ref to rvalue ref collapses to a rvalue ref, and any // other combination collapses to a lvalue ref. - std::pair<ReferenceKind, const Node *> collapse(OutputStream &S) const { + // + // A combination of a TemplateForwardReference and a back-ref Substitution + // from an ill-formed string may have created a cycle; use cycle detection to + // avoid looping forever. + std::pair<ReferenceKind, const Node *> collapse(OutputBuffer &OB) const { auto SoFar = std::make_pair(RK, Pointee); + // Track the chain of nodes for the Floyd's 'tortoise and hare' + // cycle-detection algorithm, since getSyntaxNode(S) is impure + PODSmallVector<const Node *, 8> Prev; for (;;) { - const Node *SN = SoFar.second->getSyntaxNode(S); + const Node *SN = SoFar.second->getSyntaxNode(OB); if (SN->getKind() != KReferenceType) break; auto *RT = static_cast<const ReferenceType *>(SN); SoFar.second = RT->Pointee; SoFar.first = std::min(SoFar.first, RT->RK); + + // The middle of Prev is the 'slow' pointer moving at half speed + Prev.push_back(SoFar.second); + if (Prev.size() > 1 && SoFar.second == Prev[(Prev.size() - 1) / 2]) { + // Cycle detected + SoFar.second = nullptr; + break; + } } return SoFar; } @@ -548,31 +684,35 @@ public: template<typename Fn> void match(Fn F) const { F(Pointee, RK); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return Pointee->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return Pointee->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { + void printLeft(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore<bool> SavePrinting(Printing, true); - std::pair<ReferenceKind, const Node *> Collapsed = collapse(s); - Collapsed.second->printLeft(s); - if (Collapsed.second->hasArray(s)) - s += " "; - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += "("; + ScopedOverride<bool> SavePrinting(Printing, true); + std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB); + if (!Collapsed.second) + return; + Collapsed.second->printLeft(OB); + if (Collapsed.second->hasArray(OB)) + OB += " "; + if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) + OB += "("; - s += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); + OB += (Collapsed.first == ReferenceKind::LValue ? "&" : "&&"); } - void printRight(OutputStream &s) const override { + void printRight(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore<bool> SavePrinting(Printing, true); - std::pair<ReferenceKind, const Node *> Collapsed = collapse(s); - if (Collapsed.second->hasArray(s) || Collapsed.second->hasFunction(s)) - s += ")"; - Collapsed.second->printRight(s); + ScopedOverride<bool> SavePrinting(Printing, true); + std::pair<ReferenceKind, const Node *> Collapsed = collapse(OB); + if (!Collapsed.second) + return; + if (Collapsed.second->hasArray(OB) || Collapsed.second->hasFunction(OB)) + OB += ")"; + Collapsed.second->printRight(OB); } }; @@ -587,69 +727,33 @@ public: template<typename Fn> void match(Fn F) const { F(ClassType, MemberType); } - bool hasRHSComponentSlow(OutputStream &S) const override { - return MemberType->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + return MemberType->hasRHSComponent(OB); } - void printLeft(OutputStream &s) const override { - MemberType->printLeft(s); - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += "("; + void printLeft(OutputBuffer &OB) const override { + MemberType->printLeft(OB); + if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) + OB += "("; else - s += " "; - ClassType->print(s); - s += "::*"; - } - - void printRight(OutputStream &s) const override { - if (MemberType->hasArray(s) || MemberType->hasFunction(s)) - s += ")"; - MemberType->printRight(s); - } -}; - -class NodeOrString { - const void *First; - const void *Second; - -public: - /* implicit */ NodeOrString(StringView Str) { - const char *FirstChar = Str.begin(); - const char *SecondChar = Str.end(); - if (SecondChar == nullptr) { - assert(FirstChar == SecondChar); - ++FirstChar, ++SecondChar; - } - First = static_cast<const void *>(FirstChar); - Second = static_cast<const void *>(SecondChar); + OB += " "; + ClassType->print(OB); + OB += "::*"; } - /* implicit */ NodeOrString(Node *N) - : First(static_cast<const void *>(N)), Second(nullptr) {} - NodeOrString() : First(nullptr), Second(nullptr) {} - - bool isString() const { return Second && First; } - bool isNode() const { return First && !Second; } - bool isEmpty() const { return !First && !Second; } - - StringView asString() const { - assert(isString()); - return StringView(static_cast<const char *>(First), - static_cast<const char *>(Second)); - } - - const Node *asNode() const { - assert(isNode()); - return static_cast<const Node *>(First); + void printRight(OutputBuffer &OB) const override { + if (MemberType->hasArray(OB) || MemberType->hasFunction(OB)) + OB += ")"; + MemberType->printRight(OB); } }; class ArrayType final : public Node { const Node *Base; - NodeOrString Dimension; + Node *Dimension; public: - ArrayType(const Node *Base_, NodeOrString Dimension_) + ArrayType(const Node *Base_, Node *Dimension_) : Node(KArrayType, /*RHSComponentCache=*/Cache::Yes, /*ArrayCache=*/Cache::Yes), @@ -657,21 +761,19 @@ public: template<typename Fn> void match(Fn F) const { F(Base, Dimension); } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasArraySlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasArraySlow(OutputBuffer &) const override { return true; } - void printLeft(OutputStream &S) const override { Base->printLeft(S); } + void printLeft(OutputBuffer &OB) const override { Base->printLeft(OB); } - void printRight(OutputStream &S) const override { - if (S.back() != ']') - S += " "; - S += "["; - if (Dimension.isString()) - S += Dimension.asString(); - else if (Dimension.isNode()) - Dimension.asNode()->print(S); - S += "]"; - Base->printRight(S); + void printRight(OutputBuffer &OB) const override { + if (OB.back() != ']') + OB += " "; + OB += "["; + if (Dimension) + Dimension->print(OB); + OB += "]"; + Base->printRight(OB); } }; @@ -695,8 +797,8 @@ public: F(Ret, Params, CVQuals, RefQual, ExceptionSpec); } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasFunctionSlow(OutputBuffer &) const override { return true; } // Handle C++'s ... quirky decl grammar by using the left & right // distinction. Consider: @@ -705,32 +807,32 @@ public: // that takes a char and returns an int. If we're trying to print f, start // by printing out the return types's left, then print our parameters, then // finally print right of the return type. - void printLeft(OutputStream &S) const override { - Ret->printLeft(S); - S += " "; + void printLeft(OutputBuffer &OB) const override { + Ret->printLeft(OB); + OB += " "; } - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; - Ret->printRight(S); + void printRight(OutputBuffer &OB) const override { + OB.printOpen(); + Params.printWithComma(OB); + OB.printClose(); + Ret->printRight(OB); if (CVQuals & QualConst) - S += " const"; + OB += " const"; if (CVQuals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (CVQuals & QualRestrict) - S += " restrict"; + OB += " restrict"; if (RefQual == FrefQualLValue) - S += " &"; + OB += " &"; else if (RefQual == FrefQualRValue) - S += " &&"; + OB += " &&"; if (ExceptionSpec != nullptr) { - S += ' '; - ExceptionSpec->print(S); + OB += ' '; + ExceptionSpec->print(OB); } } }; @@ -742,10 +844,11 @@ public: template<typename Fn> void match(Fn F) const { F(E); } - void printLeft(OutputStream &S) const override { - S += "noexcept("; - E->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "noexcept"; + OB.printOpen(); + E->printAsOperand(OB); + OB.printClose(); } }; @@ -757,10 +860,11 @@ public: template<typename Fn> void match(Fn F) const { F(Types); } - void printLeft(OutputStream &S) const override { - S += "throw("; - Types.printWithComma(S); - S += ')'; + void printLeft(OutputBuffer &OB) const override { + OB += "throw"; + OB.printOpen(); + Types.printWithComma(OB); + OB.printClose(); } }; @@ -791,41 +895,41 @@ public: NodeArray getParams() const { return Params; } const Node *getReturnType() const { return Ret; } - bool hasRHSComponentSlow(OutputStream &) const override { return true; } - bool hasFunctionSlow(OutputStream &) const override { return true; } + bool hasRHSComponentSlow(OutputBuffer &) const override { return true; } + bool hasFunctionSlow(OutputBuffer &) const override { return true; } const Node *getName() const { return Name; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Ret) { - Ret->printLeft(S); - if (!Ret->hasRHSComponent(S)) - S += " "; + Ret->printLeft(OB); + if (!Ret->hasRHSComponent(OB)) + OB += " "; } - Name->print(S); + Name->print(OB); } - void printRight(OutputStream &S) const override { - S += "("; - Params.printWithComma(S); - S += ")"; + void printRight(OutputBuffer &OB) const override { + OB.printOpen(); + Params.printWithComma(OB); + OB.printClose(); if (Ret) - Ret->printRight(S); + Ret->printRight(OB); if (CVQuals & QualConst) - S += " const"; + OB += " const"; if (CVQuals & QualVolatile) - S += " volatile"; + OB += " volatile"; if (CVQuals & QualRestrict) - S += " restrict"; + OB += " restrict"; if (RefQual == FrefQualLValue) - S += " &"; + OB += " &"; else if (RefQual == FrefQualRValue) - S += " &&"; + OB += " &&"; if (Attrs != nullptr) - Attrs->print(S); + Attrs->print(OB); } }; @@ -838,25 +942,25 @@ public: template<typename Fn> void match(Fn F) const { F(OpName); } - void printLeft(OutputStream &S) const override { - S += "operator\"\" "; - OpName->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "operator\"\" "; + OpName->print(OB); } }; class SpecialName final : public Node { - const StringView Special; + const std::string_view Special; const Node *Child; public: - SpecialName(StringView Special_, const Node *Child_) + SpecialName(std::string_view Special_, const Node *Child_) : Node(KSpecialName), Special(Special_), Child(Child_) {} template<typename Fn> void match(Fn F) const { F(Special, Child); } - void printLeft(OutputStream &S) const override { - S += Special; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += Special; + Child->print(OB); } }; @@ -871,11 +975,11 @@ public: template<typename Fn> void match(Fn F) const { F(FirstType, SecondType); } - void printLeft(OutputStream &S) const override { - S += "construction vtable for "; - FirstType->print(S); - S += "-in-"; - SecondType->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "construction vtable for "; + FirstType->print(OB); + OB += "-in-"; + SecondType->print(OB); } }; @@ -888,12 +992,52 @@ struct NestedName : Node { template<typename Fn> void match(Fn F) const { F(Qual, Name); } - StringView getBaseName() const override { return Name->getBaseName(); } + std::string_view getBaseName() const override { return Name->getBaseName(); } + + void printLeft(OutputBuffer &OB) const override { + Qual->print(OB); + OB += "::"; + Name->print(OB); + } +}; + +struct ModuleName : Node { + ModuleName *Parent; + Node *Name; + bool IsPartition; + + ModuleName(ModuleName *Parent_, Node *Name_, bool IsPartition_ = false) + : Node(KModuleName), Parent(Parent_), Name(Name_), + IsPartition(IsPartition_) {} + + template <typename Fn> void match(Fn F) const { + F(Parent, Name, IsPartition); + } + + void printLeft(OutputBuffer &OB) const override { + if (Parent) + Parent->print(OB); + if (Parent || IsPartition) + OB += IsPartition ? ':' : '.'; + Name->print(OB); + } +}; + +struct ModuleEntity : Node { + ModuleName *Module; + Node *Name; + + ModuleEntity(ModuleName *Module_, Node *Name_) + : Node(KModuleEntity), Module(Module_), Name(Name_) {} + + template <typename Fn> void match(Fn F) const { F(Module, Name); } + + std::string_view getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Qual->print(S); - S += "::"; - Name->print(S); + void printLeft(OutputBuffer &OB) const override { + Name->print(OB); + OB += '@'; + Module->print(OB); } }; @@ -906,10 +1050,10 @@ struct LocalName : Node { template<typename Fn> void match(Fn F) const { F(Encoding, Entity); } - void printLeft(OutputStream &S) const override { - Encoding->print(S); - S += "::"; - Entity->print(S); + void printLeft(OutputBuffer &OB) const override { + Encoding->print(OB); + OB += "::"; + Entity->print(OB); } }; @@ -924,51 +1068,66 @@ public: template<typename Fn> void match(Fn F) const { F(Qualifier, Name); } - StringView getBaseName() const override { return Name->getBaseName(); } + std::string_view getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Qualifier->print(S); - S += "::"; - Name->print(S); + void printLeft(OutputBuffer &OB) const override { + Qualifier->print(OB); + OB += "::"; + Name->print(OB); } }; class VectorType final : public Node { const Node *BaseType; - const NodeOrString Dimension; + const Node *Dimension; public: - VectorType(const Node *BaseType_, NodeOrString Dimension_) - : Node(KVectorType), BaseType(BaseType_), - Dimension(Dimension_) {} + VectorType(const Node *BaseType_, const Node *Dimension_) + : Node(KVectorType), BaseType(BaseType_), Dimension(Dimension_) {} + + const Node *getBaseType() const { return BaseType; } + const Node *getDimension() const { return Dimension; } template<typename Fn> void match(Fn F) const { F(BaseType, Dimension); } - void printLeft(OutputStream &S) const override { - BaseType->print(S); - S += " vector["; - if (Dimension.isNode()) - Dimension.asNode()->print(S); - else if (Dimension.isString()) - S += Dimension.asString(); - S += "]"; + void printLeft(OutputBuffer &OB) const override { + BaseType->print(OB); + OB += " vector["; + if (Dimension) + Dimension->print(OB); + OB += "]"; } }; class PixelVectorType final : public Node { - const NodeOrString Dimension; + const Node *Dimension; public: - PixelVectorType(NodeOrString Dimension_) + PixelVectorType(const Node *Dimension_) : Node(KPixelVectorType), Dimension(Dimension_) {} template<typename Fn> void match(Fn F) const { F(Dimension); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { // FIXME: This should demangle as "vector pixel". - S += "pixel vector["; - S += Dimension.asString(); - S += "]"; + OB += "pixel vector["; + Dimension->print(OB); + OB += "]"; + } +}; + +class BinaryFPType final : public Node { + const Node *Dimension; + +public: + BinaryFPType(const Node *Dimension_) + : Node(KBinaryFPType), Dimension(Dimension_) {} + + template<typename Fn> void match(Fn F) const { F(Dimension); } + + void printLeft(OutputBuffer &OB) const override { + OB += "_Float"; + Dimension->print(OB); } }; @@ -990,20 +1149,20 @@ public: template<typename Fn> void match(Fn F) const { F(Kind, Index); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { switch (Kind) { case TemplateParamKind::Type: - S += "$T"; + OB += "$T"; break; case TemplateParamKind::NonType: - S += "$N"; + OB += "$N"; break; case TemplateParamKind::Template: - S += "$TT"; + OB += "$TT"; break; } if (Index > 0) - S << Index - 1; + OB << Index - 1; } }; @@ -1017,13 +1176,9 @@ public: template<typename Fn> void match(Fn F) const { F(Name); } - void printLeft(OutputStream &S) const override { - S += "typename "; - } + void printLeft(OutputBuffer &OB) const override { OB += "typename "; } - void printRight(OutputStream &S) const override { - Name->print(S); - } + void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A non-type template parameter declaration, 'int N'. @@ -1037,15 +1192,15 @@ public: template<typename Fn> void match(Fn F) const { F(Name, Type); } - void printLeft(OutputStream &S) const override { - Type->printLeft(S); - if (!Type->hasRHSComponent(S)) - S += " "; + void printLeft(OutputBuffer &OB) const override { + Type->printLeft(OB); + if (!Type->hasRHSComponent(OB)) + OB += " "; } - void printRight(OutputStream &S) const override { - Name->print(S); - Type->printRight(S); + void printRight(OutputBuffer &OB) const override { + Name->print(OB); + Type->printRight(OB); } }; @@ -1062,15 +1217,14 @@ public: template<typename Fn> void match(Fn F) const { F(Name, Params); } - void printLeft(OutputStream &S) const override { - S += "template<"; - Params.printWithComma(S); - S += "> typename "; + void printLeft(OutputBuffer &OB) const override { + ScopedOverride<unsigned> LT(OB.GtIsGt, 0); + OB += "template<"; + Params.printWithComma(OB); + OB += "> typename "; } - void printRight(OutputStream &S) const override { - Name->print(S); - } + void printRight(OutputBuffer &OB) const override { Name->print(OB); } }; /// A template parameter pack declaration, 'typename ...T'. @@ -1083,14 +1237,12 @@ public: template<typename Fn> void match(Fn F) const { F(Param); } - void printLeft(OutputStream &S) const override { - Param->printLeft(S); - S += "..."; + void printLeft(OutputBuffer &OB) const override { + Param->printLeft(OB); + OB += "..."; } - void printRight(OutputStream &S) const override { - Param->printRight(S); - } + void printRight(OutputBuffer &OB) const override { Param->printRight(OB); } }; /// An unexpanded parameter pack (either in the expression or type context). If @@ -1104,11 +1256,12 @@ public: class ParameterPack final : public Node { NodeArray Data; - // Setup OutputStream for a pack expansion unless we're already expanding one. - void initializePackExpansion(OutputStream &S) const { - if (S.CurrentPackMax == std::numeric_limits<unsigned>::max()) { - S.CurrentPackMax = static_cast<unsigned>(Data.size()); - S.CurrentPackIndex = 0; + // Setup OutputBuffer for a pack expansion, unless we're already expanding + // one. + void initializePackExpansion(OutputBuffer &OB) const { + if (OB.CurrentPackMax == std::numeric_limits<unsigned>::max()) { + OB.CurrentPackMax = static_cast<unsigned>(Data.size()); + OB.CurrentPackIndex = 0; } } @@ -1131,38 +1284,38 @@ public: template<typename Fn> void match(Fn F) const { F(Data); } - bool hasRHSComponentSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasRHSComponent(S); + bool hasRHSComponentSlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasArray(S); + bool hasArraySlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() && Data[Idx]->hasFunction(S); + bool hasFunctionSlow(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() && Data[Idx]->hasFunction(OB); } - const Node *getSyntaxNode(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; - return Idx < Data.size() ? Data[Idx]->getSyntaxNode(S) : this; + const Node *getSyntaxNode(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; + return Idx < Data.size() ? Data[Idx]->getSyntaxNode(OB) : this; } - void printLeft(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; + void printLeft(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) - Data[Idx]->printLeft(S); + Data[Idx]->printLeft(OB); } - void printRight(OutputStream &S) const override { - initializePackExpansion(S); - size_t Idx = S.CurrentPackIndex; + void printRight(OutputBuffer &OB) const override { + initializePackExpansion(OB); + size_t Idx = OB.CurrentPackIndex; if (Idx < Data.size()) - Data[Idx]->printRight(S); + Data[Idx]->printRight(OB); } }; @@ -1181,8 +1334,8 @@ public: NodeArray getElements() const { return Elements; } - void printLeft(OutputStream &S) const override { - Elements.printWithComma(S); + void printLeft(OutputBuffer &OB) const override { + Elements.printWithComma(OB); } }; @@ -1199,35 +1352,35 @@ public: const Node *getChild() const { return Child; } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { constexpr unsigned Max = std::numeric_limits<unsigned>::max(); - SwapAndRestore<unsigned> SavePackIdx(S.CurrentPackIndex, Max); - SwapAndRestore<unsigned> SavePackMax(S.CurrentPackMax, Max); - size_t StreamPos = S.getCurrentPosition(); + ScopedOverride<unsigned> SavePackIdx(OB.CurrentPackIndex, Max); + ScopedOverride<unsigned> SavePackMax(OB.CurrentPackMax, Max); + size_t StreamPos = OB.getCurrentPosition(); // Print the first element in the pack. If Child contains a ParameterPack, // it will set up S.CurrentPackMax and print the first element. - Child->print(S); + Child->print(OB); // No ParameterPack was found in Child. This can occur if we've found a pack // expansion on a <function-param>. - if (S.CurrentPackMax == Max) { - S += "..."; + if (OB.CurrentPackMax == Max) { + OB += "..."; return; } // We found a ParameterPack, but it has no elements. Erase whatever we may // of printed. - if (S.CurrentPackMax == 0) { - S.setCurrentPosition(StreamPos); + if (OB.CurrentPackMax == 0) { + OB.setCurrentPosition(StreamPos); return; } // Else, iterate through the rest of the elements in the pack. - for (unsigned I = 1, E = S.CurrentPackMax; I < E; ++I) { - S += ", "; - S.CurrentPackIndex = I; - Child->print(S); + for (unsigned I = 1, E = OB.CurrentPackMax; I < E; ++I) { + OB += ", "; + OB.CurrentPackIndex = I; + Child->print(OB); } } }; @@ -1242,12 +1395,11 @@ public: NodeArray getParams() { return Params; } - void printLeft(OutputStream &S) const override { - S += "<"; - Params.printWithComma(S); - if (S.back() == '>') - S += " "; - S += ">"; + void printLeft(OutputBuffer &OB) const override { + ScopedOverride<unsigned> LT(OB.GtIsGt, 0); + OB += "<"; + Params.printWithComma(OB); + OB += ">"; } }; @@ -1289,42 +1441,42 @@ struct ForwardTemplateReference : Node { // special handling. template<typename Fn> void match(Fn F) const = delete; - bool hasRHSComponentSlow(OutputStream &S) const override { + bool hasRHSComponentSlow(OutputBuffer &OB) const override { if (Printing) return false; - SwapAndRestore<bool> SavePrinting(Printing, true); - return Ref->hasRHSComponent(S); + ScopedOverride<bool> SavePrinting(Printing, true); + return Ref->hasRHSComponent(OB); } - bool hasArraySlow(OutputStream &S) const override { + bool hasArraySlow(OutputBuffer &OB) const override { if (Printing) return false; - SwapAndRestore<bool> SavePrinting(Printing, true); - return Ref->hasArray(S); + ScopedOverride<bool> SavePrinting(Printing, true); + return Ref->hasArray(OB); } - bool hasFunctionSlow(OutputStream &S) const override { + bool hasFunctionSlow(OutputBuffer &OB) const override { if (Printing) return false; - SwapAndRestore<bool> SavePrinting(Printing, true); - return Ref->hasFunction(S); + ScopedOverride<bool> SavePrinting(Printing, true); + return Ref->hasFunction(OB); } - const Node *getSyntaxNode(OutputStream &S) const override { + const Node *getSyntaxNode(OutputBuffer &OB) const override { if (Printing) return this; - SwapAndRestore<bool> SavePrinting(Printing, true); - return Ref->getSyntaxNode(S); + ScopedOverride<bool> SavePrinting(Printing, true); + return Ref->getSyntaxNode(OB); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore<bool> SavePrinting(Printing, true); - Ref->printLeft(S); + ScopedOverride<bool> SavePrinting(Printing, true); + Ref->printLeft(OB); } - void printRight(OutputStream &S) const override { + void printRight(OutputBuffer &OB) const override { if (Printing) return; - SwapAndRestore<bool> SavePrinting(Printing, true); - Ref->printRight(S); + ScopedOverride<bool> SavePrinting(Printing, true); + Ref->printRight(OB); } }; @@ -1338,11 +1490,11 @@ struct NameWithTemplateArgs : Node { template<typename Fn> void match(Fn F) const { F(Name, TemplateArgs); } - StringView getBaseName() const override { return Name->getBaseName(); } + std::string_view getBaseName() const override { return Name->getBaseName(); } - void printLeft(OutputStream &S) const override { - Name->print(S); - TemplateArgs->print(S); + void printLeft(OutputBuffer &OB) const override { + Name->print(OB); + TemplateArgs->print(OB); } }; @@ -1355,26 +1507,11 @@ public: template<typename Fn> void match(Fn F) const { F(Child); } - StringView getBaseName() const override { return Child->getBaseName(); } + std::string_view getBaseName() const override { return Child->getBaseName(); } - void printLeft(OutputStream &S) const override { - S += "::"; - Child->print(S); - } -}; - -struct StdQualifiedName : Node { - Node *Child; - - StdQualifiedName(Node *Child_) : Node(KStdQualifiedName), Child(Child_) {} - - template<typename Fn> void match(Fn F) const { F(Child); } - - StringView getBaseName() const override { return Child->getBaseName(); } - - void printLeft(OutputStream &S) const override { - S += "std::"; - Child->print(S); + void printLeft(OutputBuffer &OB) const override { + OB += "::"; + Child->print(OB); } }; @@ -1387,109 +1524,81 @@ enum class SpecialSubKind { iostream, }; -class ExpandedSpecialSubstitution final : public Node { +class SpecialSubstitution; +class ExpandedSpecialSubstitution : public Node { +protected: SpecialSubKind SSK; + ExpandedSpecialSubstitution(SpecialSubKind SSK_, Kind K_) + : Node(K_), SSK(SSK_) {} public: ExpandedSpecialSubstitution(SpecialSubKind SSK_) - : Node(KExpandedSpecialSubstitution), SSK(SSK_) {} + : ExpandedSpecialSubstitution(SSK_, KExpandedSpecialSubstitution) {} + inline ExpandedSpecialSubstitution(SpecialSubstitution const *); template<typename Fn> void match(Fn F) const { F(SSK); } - StringView getBaseName() const override { +protected: + bool isInstantiation() const { + return unsigned(SSK) >= unsigned(SpecialSubKind::string); + } + + std::string_view getBaseName() const override { switch (SSK) { case SpecialSubKind::allocator: - return StringView("allocator"); + return {"allocator"}; case SpecialSubKind::basic_string: - return StringView("basic_string"); + return {"basic_string"}; case SpecialSubKind::string: - return StringView("basic_string"); + return {"basic_string"}; case SpecialSubKind::istream: - return StringView("basic_istream"); + return {"basic_istream"}; case SpecialSubKind::ostream: - return StringView("basic_ostream"); + return {"basic_ostream"}; case SpecialSubKind::iostream: - return StringView("basic_iostream"); + return {"basic_iostream"}; } DEMANGLE_UNREACHABLE; } - void printLeft(OutputStream &S) const override { - switch (SSK) { - case SpecialSubKind::allocator: - S += "std::allocator"; - break; - case SpecialSubKind::basic_string: - S += "std::basic_string"; - break; - case SpecialSubKind::string: - S += "std::basic_string<char, std::char_traits<char>, " - "std::allocator<char> >"; - break; - case SpecialSubKind::istream: - S += "std::basic_istream<char, std::char_traits<char> >"; - break; - case SpecialSubKind::ostream: - S += "std::basic_ostream<char, std::char_traits<char> >"; - break; - case SpecialSubKind::iostream: - S += "std::basic_iostream<char, std::char_traits<char> >"; - break; +private: + void printLeft(OutputBuffer &OB) const override { + OB << "std::" << getBaseName(); + if (isInstantiation()) { + OB << "<char, std::char_traits<char>"; + if (SSK == SpecialSubKind::string) + OB << ", std::allocator<char>"; + OB << ">"; } } }; -class SpecialSubstitution final : public Node { +class SpecialSubstitution final : public ExpandedSpecialSubstitution { public: - SpecialSubKind SSK; - SpecialSubstitution(SpecialSubKind SSK_) - : Node(KSpecialSubstitution), SSK(SSK_) {} + : ExpandedSpecialSubstitution(SSK_, KSpecialSubstitution) {} template<typename Fn> void match(Fn F) const { F(SSK); } - StringView getBaseName() const override { - switch (SSK) { - case SpecialSubKind::allocator: - return StringView("allocator"); - case SpecialSubKind::basic_string: - return StringView("basic_string"); - case SpecialSubKind::string: - return StringView("string"); - case SpecialSubKind::istream: - return StringView("istream"); - case SpecialSubKind::ostream: - return StringView("ostream"); - case SpecialSubKind::iostream: - return StringView("iostream"); + std::string_view getBaseName() const override { + std::string_view SV = ExpandedSpecialSubstitution::getBaseName(); + if (isInstantiation()) { + // The instantiations are typedefs that drop the "basic_" prefix. + assert(llvm::itanium_demangle::starts_with(SV, "basic_")); + SV.remove_prefix(sizeof("basic_") - 1); } - DEMANGLE_UNREACHABLE; + return SV; } - void printLeft(OutputStream &S) const override { - switch (SSK) { - case SpecialSubKind::allocator: - S += "std::allocator"; - break; - case SpecialSubKind::basic_string: - S += "std::basic_string"; - break; - case SpecialSubKind::string: - S += "std::string"; - break; - case SpecialSubKind::istream: - S += "std::istream"; - break; - case SpecialSubKind::ostream: - S += "std::ostream"; - break; - case SpecialSubKind::iostream: - S += "std::iostream"; - break; - } + void printLeft(OutputBuffer &OB) const override { + OB << "std::" << getBaseName(); } }; +inline ExpandedSpecialSubstitution::ExpandedSpecialSubstitution( + SpecialSubstitution const *SS) + : ExpandedSpecialSubstitution(SS->SSK) {} + class CtorDtorName final : public Node { const Node *Basename; const bool IsDtor; @@ -1502,10 +1611,10 @@ public: template<typename Fn> void match(Fn F) const { F(Basename, IsDtor, Variant); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsDtor) - S += "~"; - S += Basename->getBaseName(); + OB += "~"; + OB += Basename->getBaseName(); } }; @@ -1517,35 +1626,36 @@ public: template<typename Fn> void match(Fn F) const { F(Base); } - void printLeft(OutputStream &S) const override { - S += "~"; - Base->printLeft(S); + void printLeft(OutputBuffer &OB) const override { + OB += "~"; + Base->printLeft(OB); } }; class UnnamedTypeName : public Node { - const StringView Count; + const std::string_view Count; public: - UnnamedTypeName(StringView Count_) : Node(KUnnamedTypeName), Count(Count_) {} + UnnamedTypeName(std::string_view Count_) + : Node(KUnnamedTypeName), Count(Count_) {} template<typename Fn> void match(Fn F) const { F(Count); } - void printLeft(OutputStream &S) const override { - S += "'unnamed"; - S += Count; - S += "\'"; + void printLeft(OutputBuffer &OB) const override { + OB += "'unnamed"; + OB += Count; + OB += "\'"; } }; class ClosureTypeName : public Node { NodeArray TemplateParams; NodeArray Params; - StringView Count; + std::string_view Count; public: ClosureTypeName(NodeArray TemplateParams_, NodeArray Params_, - StringView Count_) + std::string_view Count_) : Node(KClosureTypeName), TemplateParams(TemplateParams_), Params(Params_), Count(Count_) {} @@ -1553,22 +1663,23 @@ public: F(TemplateParams, Params, Count); } - void printDeclarator(OutputStream &S) const { + void printDeclarator(OutputBuffer &OB) const { if (!TemplateParams.empty()) { - S += "<"; - TemplateParams.printWithComma(S); - S += ">"; + ScopedOverride<unsigned> LT(OB.GtIsGt, 0); + OB += "<"; + TemplateParams.printWithComma(OB); + OB += ">"; } - S += "("; - Params.printWithComma(S); - S += ")"; + OB.printOpen(); + Params.printWithComma(OB); + OB.printClose(); } - void printLeft(OutputStream &S) const override { - S += "\'lambda"; - S += Count; - S += "\'"; - printDeclarator(S); + void printLeft(OutputBuffer &OB) const override { + OB += "\'lambda"; + OB += Count; + OB += "\'"; + printDeclarator(OB); } }; @@ -1580,10 +1691,10 @@ public: template<typename Fn> void match(Fn F) const { F(Bindings); } - void printLeft(OutputStream &S) const override { - S += '['; - Bindings.printWithComma(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB.printOpen('['); + Bindings.printWithComma(OB); + OB.printClose(']'); } }; @@ -1591,32 +1702,35 @@ public: class BinaryExpr : public Node { const Node *LHS; - const StringView InfixOperator; + const std::string_view InfixOperator; const Node *RHS; public: - BinaryExpr(const Node *LHS_, StringView InfixOperator_, const Node *RHS_) - : Node(KBinaryExpr), LHS(LHS_), InfixOperator(InfixOperator_), RHS(RHS_) { - } - - template<typename Fn> void match(Fn F) const { F(LHS, InfixOperator, RHS); } - - void printLeft(OutputStream &S) const override { - // might be a template argument expression, then we need to disambiguate - // with parens. - if (InfixOperator == ">") - S += "("; - - S += "("; - LHS->print(S); - S += ") "; - S += InfixOperator; - S += " ("; - RHS->print(S); - S += ")"; - - if (InfixOperator == ">") - S += ")"; + BinaryExpr(const Node *LHS_, std::string_view InfixOperator_, + const Node *RHS_, Prec Prec_) + : Node(KBinaryExpr, Prec_), LHS(LHS_), InfixOperator(InfixOperator_), + RHS(RHS_) {} + + template <typename Fn> void match(Fn F) const { + F(LHS, InfixOperator, RHS, getPrecedence()); + } + + void printLeft(OutputBuffer &OB) const override { + bool ParenAll = OB.isGtInsideTemplateArgs() && + (InfixOperator == ">" || InfixOperator == ">>"); + if (ParenAll) + OB.printOpen(); + // Assignment is right associative, with special LHS precedence. + bool IsAssign = getPrecedence() == Prec::Assign; + LHS->printAsOperand(OB, IsAssign ? Prec::OrIf : getPrecedence(), !IsAssign); + // No space before comma operator + if (!(InfixOperator == ",")) + OB += " "; + OB += InfixOperator; + OB += " "; + RHS->printAsOperand(OB, getPrecedence(), IsAssign); + if (ParenAll) + OB.printClose(); } }; @@ -1625,35 +1739,36 @@ class ArraySubscriptExpr : public Node { const Node *Op2; public: - ArraySubscriptExpr(const Node *Op1_, const Node *Op2_) - : Node(KArraySubscriptExpr), Op1(Op1_), Op2(Op2_) {} + ArraySubscriptExpr(const Node *Op1_, const Node *Op2_, Prec Prec_) + : Node(KArraySubscriptExpr, Prec_), Op1(Op1_), Op2(Op2_) {} - template<typename Fn> void match(Fn F) const { F(Op1, Op2); } + template <typename Fn> void match(Fn F) const { + F(Op1, Op2, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Op1->print(S); - S += ")["; - Op2->print(S); - S += "]"; + void printLeft(OutputBuffer &OB) const override { + Op1->printAsOperand(OB, getPrecedence()); + OB.printOpen('['); + Op2->printAsOperand(OB); + OB.printClose(']'); } }; class PostfixExpr : public Node { const Node *Child; - const StringView Operator; + const std::string_view Operator; public: - PostfixExpr(const Node *Child_, StringView Operator_) - : Node(KPostfixExpr), Child(Child_), Operator(Operator_) {} + PostfixExpr(const Node *Child_, std::string_view Operator_, Prec Prec_) + : Node(KPostfixExpr, Prec_), Child(Child_), Operator(Operator_) {} - template<typename Fn> void match(Fn F) const { F(Child, Operator); } + template <typename Fn> void match(Fn F) const { + F(Child, Operator, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Child->print(S); - S += ")"; - S += Operator; + void printLeft(OutputBuffer &OB) const override { + Child->printAsOperand(OB, getPrecedence(), true); + OB += Operator; } }; @@ -1663,78 +1778,128 @@ class ConditionalExpr : public Node { const Node *Else; public: - ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_) - : Node(KConditionalExpr), Cond(Cond_), Then(Then_), Else(Else_) {} + ConditionalExpr(const Node *Cond_, const Node *Then_, const Node *Else_, + Prec Prec_) + : Node(KConditionalExpr, Prec_), Cond(Cond_), Then(Then_), Else(Else_) {} - template<typename Fn> void match(Fn F) const { F(Cond, Then, Else); } + template <typename Fn> void match(Fn F) const { + F(Cond, Then, Else, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Cond->print(S); - S += ") ? ("; - Then->print(S); - S += ") : ("; - Else->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + Cond->printAsOperand(OB, getPrecedence()); + OB += " ? "; + Then->printAsOperand(OB); + OB += " : "; + Else->printAsOperand(OB, Prec::Assign, true); } }; class MemberExpr : public Node { const Node *LHS; - const StringView Kind; + const std::string_view Kind; const Node *RHS; public: - MemberExpr(const Node *LHS_, StringView Kind_, const Node *RHS_) - : Node(KMemberExpr), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} + MemberExpr(const Node *LHS_, std::string_view Kind_, const Node *RHS_, + Prec Prec_) + : Node(KMemberExpr, Prec_), LHS(LHS_), Kind(Kind_), RHS(RHS_) {} + + template <typename Fn> void match(Fn F) const { + F(LHS, Kind, RHS, getPrecedence()); + } + + void printLeft(OutputBuffer &OB) const override { + LHS->printAsOperand(OB, getPrecedence(), true); + OB += Kind; + RHS->printAsOperand(OB, getPrecedence(), false); + } +}; + +class SubobjectExpr : public Node { + const Node *Type; + const Node *SubExpr; + std::string_view Offset; + NodeArray UnionSelectors; + bool OnePastTheEnd; - template<typename Fn> void match(Fn F) const { F(LHS, Kind, RHS); } +public: + SubobjectExpr(const Node *Type_, const Node *SubExpr_, + std::string_view Offset_, NodeArray UnionSelectors_, + bool OnePastTheEnd_) + : Node(KSubobjectExpr), Type(Type_), SubExpr(SubExpr_), Offset(Offset_), + UnionSelectors(UnionSelectors_), OnePastTheEnd(OnePastTheEnd_) {} - void printLeft(OutputStream &S) const override { - LHS->print(S); - S += Kind; - RHS->print(S); + template<typename Fn> void match(Fn F) const { + F(Type, SubExpr, Offset, UnionSelectors, OnePastTheEnd); + } + + void printLeft(OutputBuffer &OB) const override { + SubExpr->print(OB); + OB += ".<"; + Type->print(OB); + OB += " at offset "; + if (Offset.empty()) { + OB += "0"; + } else if (Offset[0] == 'n') { + OB += "-"; + OB += std::string_view(Offset.data() + 1, Offset.size() - 1); + } else { + OB += Offset; + } + OB += ">"; } }; class EnclosingExpr : public Node { - const StringView Prefix; + const std::string_view Prefix; const Node *Infix; - const StringView Postfix; + const std::string_view Postfix; public: - EnclosingExpr(StringView Prefix_, Node *Infix_, StringView Postfix_) - : Node(KEnclosingExpr), Prefix(Prefix_), Infix(Infix_), - Postfix(Postfix_) {} + EnclosingExpr(std::string_view Prefix_, const Node *Infix_, + Prec Prec_ = Prec::Primary) + : Node(KEnclosingExpr, Prec_), Prefix(Prefix_), Infix(Infix_) {} - template<typename Fn> void match(Fn F) const { F(Prefix, Infix, Postfix); } + template <typename Fn> void match(Fn F) const { + F(Prefix, Infix, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += Prefix; - Infix->print(S); - S += Postfix; + void printLeft(OutputBuffer &OB) const override { + OB += Prefix; + OB.printOpen(); + Infix->print(OB); + OB.printClose(); + OB += Postfix; } }; class CastExpr : public Node { // cast_kind<to>(from) - const StringView CastKind; + const std::string_view CastKind; const Node *To; const Node *From; public: - CastExpr(StringView CastKind_, const Node *To_, const Node *From_) - : Node(KCastExpr), CastKind(CastKind_), To(To_), From(From_) {} + CastExpr(std::string_view CastKind_, const Node *To_, const Node *From_, + Prec Prec_) + : Node(KCastExpr, Prec_), CastKind(CastKind_), To(To_), From(From_) {} - template<typename Fn> void match(Fn F) const { F(CastKind, To, From); } + template <typename Fn> void match(Fn F) const { + F(CastKind, To, From, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += CastKind; - S += "<"; - To->printLeft(S); - S += ">("; - From->printLeft(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += CastKind; + { + ScopedOverride<unsigned> LT(OB.GtIsGt, 0); + OB += "<"; + To->printLeft(OB); + OB += ">"; + } + OB.printOpen(); + From->printAsOperand(OB); + OB.printClose(); } }; @@ -1747,11 +1912,12 @@ public: template<typename Fn> void match(Fn F) const { F(Pack); } - void printLeft(OutputStream &S) const override { - S += "sizeof...("; + void printLeft(OutputBuffer &OB) const override { + OB += "sizeof..."; + OB.printOpen(); ParameterPackExpansion PPE(Pack); - PPE.printLeft(S); - S += ")"; + PPE.printLeft(OB); + OB.printClose(); } }; @@ -1760,16 +1926,18 @@ class CallExpr : public Node { NodeArray Args; public: - CallExpr(const Node *Callee_, NodeArray Args_) - : Node(KCallExpr), Callee(Callee_), Args(Args_) {} + CallExpr(const Node *Callee_, NodeArray Args_, Prec Prec_) + : Node(KCallExpr, Prec_), Callee(Callee_), Args(Args_) {} - template<typename Fn> void match(Fn F) const { F(Callee, Args); } + template <typename Fn> void match(Fn F) const { + F(Callee, Args, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - Callee->print(S); - S += "("; - Args.printWithComma(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + Callee->print(OB); + OB.printOpen(); + Args.printWithComma(OB); + OB.printClose(); } }; @@ -1782,33 +1950,32 @@ class NewExpr : public Node { bool IsArray; // new[] ? public: NewExpr(NodeArray ExprList_, Node *Type_, NodeArray InitList_, bool IsGlobal_, - bool IsArray_) - : Node(KNewExpr), ExprList(ExprList_), Type(Type_), InitList(InitList_), - IsGlobal(IsGlobal_), IsArray(IsArray_) {} + bool IsArray_, Prec Prec_) + : Node(KNewExpr, Prec_), ExprList(ExprList_), Type(Type_), + InitList(InitList_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} template<typename Fn> void match(Fn F) const { - F(ExprList, Type, InitList, IsGlobal, IsArray); + F(ExprList, Type, InitList, IsGlobal, IsArray, getPrecedence()); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsGlobal) - S += "::operator "; - S += "new"; + OB += "::"; + OB += "new"; if (IsArray) - S += "[]"; - S += ' '; + OB += "[]"; if (!ExprList.empty()) { - S += "("; - ExprList.printWithComma(S); - S += ")"; + OB.printOpen(); + ExprList.printWithComma(OB); + OB.printClose(); } - Type->print(S); + OB += " "; + Type->print(OB); if (!InitList.empty()) { - S += "("; - InitList.printWithComma(S); - S += ")"; + OB.printOpen(); + InitList.printWithComma(OB); + OB.printClose(); } - } }; @@ -1818,50 +1985,55 @@ class DeleteExpr : public Node { bool IsArray; public: - DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_) - : Node(KDeleteExpr), Op(Op_), IsGlobal(IsGlobal_), IsArray(IsArray_) {} + DeleteExpr(Node *Op_, bool IsGlobal_, bool IsArray_, Prec Prec_) + : Node(KDeleteExpr, Prec_), Op(Op_), IsGlobal(IsGlobal_), + IsArray(IsArray_) {} - template<typename Fn> void match(Fn F) const { F(Op, IsGlobal, IsArray); } + template <typename Fn> void match(Fn F) const { + F(Op, IsGlobal, IsArray, getPrecedence()); + } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsGlobal) - S += "::"; - S += "delete"; + OB += "::"; + OB += "delete"; if (IsArray) - S += "[] "; - Op->print(S); + OB += "[]"; + OB += ' '; + Op->print(OB); } }; class PrefixExpr : public Node { - StringView Prefix; + std::string_view Prefix; Node *Child; public: - PrefixExpr(StringView Prefix_, Node *Child_) - : Node(KPrefixExpr), Prefix(Prefix_), Child(Child_) {} + PrefixExpr(std::string_view Prefix_, Node *Child_, Prec Prec_) + : Node(KPrefixExpr, Prec_), Prefix(Prefix_), Child(Child_) {} - template<typename Fn> void match(Fn F) const { F(Prefix, Child); } + template <typename Fn> void match(Fn F) const { + F(Prefix, Child, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += Prefix; - S += "("; - Child->print(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB += Prefix; + Child->printAsOperand(OB, getPrecedence()); } }; class FunctionParam : public Node { - StringView Number; + std::string_view Number; public: - FunctionParam(StringView Number_) : Node(KFunctionParam), Number(Number_) {} + FunctionParam(std::string_view Number_) + : Node(KFunctionParam), Number(Number_) {} template<typename Fn> void match(Fn F) const { F(Number); } - void printLeft(OutputStream &S) const override { - S += "fp"; - S += Number; + void printLeft(OutputBuffer &OB) const override { + OB += "fp"; + OB += Number; } }; @@ -1870,17 +2042,45 @@ class ConversionExpr : public Node { NodeArray Expressions; public: - ConversionExpr(const Node *Type_, NodeArray Expressions_) - : Node(KConversionExpr), Type(Type_), Expressions(Expressions_) {} + ConversionExpr(const Node *Type_, NodeArray Expressions_, Prec Prec_) + : Node(KConversionExpr, Prec_), Type(Type_), Expressions(Expressions_) {} + + template <typename Fn> void match(Fn F) const { + F(Type, Expressions, getPrecedence()); + } + + void printLeft(OutputBuffer &OB) const override { + OB.printOpen(); + Type->print(OB); + OB.printClose(); + OB.printOpen(); + Expressions.printWithComma(OB); + OB.printClose(); + } +}; + +class PointerToMemberConversionExpr : public Node { + const Node *Type; + const Node *SubExpr; + std::string_view Offset; + +public: + PointerToMemberConversionExpr(const Node *Type_, const Node *SubExpr_, + std::string_view Offset_, Prec Prec_) + : Node(KPointerToMemberConversionExpr, Prec_), Type(Type_), + SubExpr(SubExpr_), Offset(Offset_) {} - template<typename Fn> void match(Fn F) const { F(Type, Expressions); } + template <typename Fn> void match(Fn F) const { + F(Type, SubExpr, Offset, getPrecedence()); + } - void printLeft(OutputStream &S) const override { - S += "("; - Type->print(S); - S += ")("; - Expressions.printWithComma(S); - S += ")"; + void printLeft(OutputBuffer &OB) const override { + OB.printOpen(); + Type->print(OB); + OB.printClose(); + OB.printOpen(); + SubExpr->print(OB); + OB.printClose(); } }; @@ -1893,12 +2093,12 @@ public: template<typename Fn> void match(Fn F) const { F(Ty, Inits); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Ty) - Ty->print(S); - S += '{'; - Inits.printWithComma(S); - S += '}'; + Ty->print(OB); + OB += '{'; + Inits.printWithComma(OB); + OB += '}'; } }; @@ -1912,18 +2112,18 @@ public: template<typename Fn> void match(Fn F) const { F(Elem, Init, IsArray); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (IsArray) { - S += '['; - Elem->print(S); - S += ']'; + OB += '['; + Elem->print(OB); + OB += ']'; } else { - S += '.'; - Elem->print(S); + OB += '.'; + Elem->print(OB); } if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + OB += " = "; + Init->print(OB); } }; @@ -1937,25 +2137,25 @@ public: template<typename Fn> void match(Fn F) const { F(First, Last, Init); } - void printLeft(OutputStream &S) const override { - S += '['; - First->print(S); - S += " ... "; - Last->print(S); - S += ']'; + void printLeft(OutputBuffer &OB) const override { + OB += '['; + First->print(OB); + OB += " ... "; + Last->print(OB); + OB += ']'; if (Init->getKind() != KBracedExpr && Init->getKind() != KBracedRangeExpr) - S += " = "; - Init->print(S); + OB += " = "; + Init->print(OB); } }; class FoldExpr : public Node { const Node *Pack, *Init; - StringView OperatorName; + std::string_view OperatorName; bool IsLeftFold; public: - FoldExpr(bool IsLeftFold_, StringView OperatorName_, const Node *Pack_, + FoldExpr(bool IsLeftFold_, std::string_view OperatorName_, const Node *Pack_, const Node *Init_) : Node(KFoldExpr), Pack(Pack_), Init(Init_), OperatorName(OperatorName_), IsLeftFold(IsLeftFold_) {} @@ -1964,43 +2164,35 @@ public: F(IsLeftFold, OperatorName, Pack, Init); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { auto PrintPack = [&] { - S += '('; - ParameterPackExpansion(Pack).print(S); - S += ')'; + OB.printOpen(); + ParameterPackExpansion(Pack).print(OB); + OB.printClose(); }; - S += '('; - - if (IsLeftFold) { - // init op ... op pack - if (Init != nullptr) { - Init->print(S); - S += ' '; - S += OperatorName; - S += ' '; - } - // ... op pack - S += "... "; - S += OperatorName; - S += ' '; - PrintPack(); - } else { // !IsLeftFold - // pack op ... - PrintPack(); - S += ' '; - S += OperatorName; - S += " ..."; - // pack op ... op init - if (Init != nullptr) { - S += ' '; - S += OperatorName; - S += ' '; - Init->print(S); - } + OB.printOpen(); + // Either '[init op ]... op pack' or 'pack op ...[ op init]' + // Refactored to '[(init|pack) op ]...[ op (pack|init)]' + // Fold expr operands are cast-expressions + if (!IsLeftFold || Init != nullptr) { + // '(init|pack) op ' + if (IsLeftFold) + Init->printAsOperand(OB, Prec::Cast, true); + else + PrintPack(); + OB << " " << OperatorName << " "; + } + OB << "..."; + if (IsLeftFold || Init != nullptr) { + // ' op (init|pack)' + OB << " " << OperatorName << " "; + if (IsLeftFold) + PrintPack(); + else + Init->printAsOperand(OB, Prec::Cast, true); } - S += ')'; + OB.printClose(); } }; @@ -2012,24 +2204,9 @@ public: template<typename Fn> void match(Fn F) const { F(Op); } - void printLeft(OutputStream &S) const override { - S += "throw "; - Op->print(S); - } -}; - -// MSVC __uuidof extension, generated by clang in -fms-extensions mode. -class UUIDOfExpr : public Node { - Node *Operand; -public: - UUIDOfExpr(Node *Operand_) : Node(KUUIDOfExpr), Operand(Operand_) {} - - template<typename Fn> void match(Fn F) const { F(Operand); } - - void printLeft(OutputStream &S) const override { - S << "__uuidof("; - Operand->print(S); - S << ")"; + void printLeft(OutputBuffer &OB) const override { + OB += "throw "; + Op->print(OB); } }; @@ -2041,8 +2218,8 @@ public: template<typename Fn> void match(Fn F) const { F(Value); } - void printLeft(OutputStream &S) const override { - S += Value ? StringView("true") : StringView("false"); + void printLeft(OutputBuffer &OB) const override { + OB += Value ? std::string_view("true") : std::string_view("false"); } }; @@ -2054,10 +2231,10 @@ public: template<typename Fn> void match(Fn F) const { F(Type); } - void printLeft(OutputStream &S) const override { - S += "\"<"; - Type->print(S); - S += ">\""; + void printLeft(OutputBuffer &OB) const override { + OB += "\"<"; + Type->print(OB); + OB += ">\""; } }; @@ -2069,58 +2246,61 @@ public: template<typename Fn> void match(Fn F) const { F(Type); } - void printLeft(OutputStream &S) const override { - S += "[]"; + void printLeft(OutputBuffer &OB) const override { + OB += "[]"; if (Type->getKind() == KClosureTypeName) - static_cast<const ClosureTypeName *>(Type)->printDeclarator(S); - S += "{...}"; + static_cast<const ClosureTypeName *>(Type)->printDeclarator(OB); + OB += "{...}"; } }; -class IntegerCastExpr : public Node { +class EnumLiteral : public Node { // ty(integer) const Node *Ty; - StringView Integer; + std::string_view Integer; public: - IntegerCastExpr(const Node *Ty_, StringView Integer_) - : Node(KIntegerCastExpr), Ty(Ty_), Integer(Integer_) {} + EnumLiteral(const Node *Ty_, std::string_view Integer_) + : Node(KEnumLiteral), Ty(Ty_), Integer(Integer_) {} template<typename Fn> void match(Fn F) const { F(Ty, Integer); } - void printLeft(OutputStream &S) const override { - S += "("; - Ty->print(S); - S += ")"; - S += Integer; + void printLeft(OutputBuffer &OB) const override { + OB.printOpen(); + Ty->print(OB); + OB.printClose(); + + if (Integer[0] == 'n') + OB << '-' << std::string_view(Integer.data() + 1, Integer.size() - 1); + else + OB << Integer; } }; class IntegerLiteral : public Node { - StringView Type; - StringView Value; + std::string_view Type; + std::string_view Value; public: - IntegerLiteral(StringView Type_, StringView Value_) + IntegerLiteral(std::string_view Type_, std::string_view Value_) : Node(KIntegerLiteral), Type(Type_), Value(Value_) {} template<typename Fn> void match(Fn F) const { F(Type, Value); } - void printLeft(OutputStream &S) const override { + void printLeft(OutputBuffer &OB) const override { if (Type.size() > 3) { - S += "("; - S += Type; - S += ")"; + OB.printOpen(); + OB += Type; + OB.printClose(); } - if (Value[0] == 'n') { - S += "-"; - S += Value.dropFront(1); - } else - S += Value; + if (Value[0] == 'n') + OB << '-' << std::string_view(Value.data() + 1, Value.size() - 1); + else + OB += Value; if (Type.size() <= 3) - S += Type; + OB += Type; } }; @@ -2139,29 +2319,26 @@ constexpr Node::Kind getFloatLiteralKind(long double *) { } template <class Float> class FloatLiteralImpl : public Node { - const StringView Contents; + const std::string_view Contents; static constexpr Kind KindForClass = float_literal_impl::getFloatLiteralKind((Float *)nullptr); public: - FloatLiteralImpl(StringView Contents_) + FloatLiteralImpl(std::string_view Contents_) : Node(KindForClass), Contents(Contents_) {} template<typename Fn> void match(Fn F) const { F(Contents); } - void printLeft(OutputStream &s) const override { - const char *first = Contents.begin(); - const char *last = Contents.end() + 1; - + void printLeft(OutputBuffer &OB) const override { const size_t N = FloatData<Float>::mangled_size; - if (static_cast<std::size_t>(last - first) > N) { - last = first + N; + if (Contents.size() >= N) { union { Float value; char buf[sizeof(Float)]; }; - const char *t = first; + const char *t = Contents.data(); + const char *last = t + N; char *e = buf; for (; t != last; ++t, ++e) { unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') @@ -2176,7 +2353,7 @@ public: #endif char num[FloatData<Float>::max_demangled_size] = {0}; int n = snprintf(num, sizeof(num), FloatData<Float>::spec, value); - s += StringView(num, num + n); + OB += std::string_view(num, n); } } }; @@ -2190,143 +2367,22 @@ using LongDoubleLiteral = FloatLiteralImpl<long double>; template<typename Fn> void Node::visit(Fn F) const { switch (K) { -#define CASE(X) case K ## X: return F(static_cast<const X*>(this)); - FOR_EACH_NODE_KIND(CASE) -#undef CASE +#define NODE(X) \ + case K##X: \ + return F(static_cast<const X *>(this)); +#include "ItaniumNodes.def" } assert(0 && "unknown mangling node kind"); } /// Determine the kind of a node from its type. template<typename NodeT> struct NodeKind; -#define SPECIALIZATION(X) \ - template<> struct NodeKind<X> { \ - static constexpr Node::Kind Kind = Node::K##X; \ - static constexpr const char *name() { return #X; } \ +#define NODE(X) \ + template <> struct NodeKind<X> { \ + static constexpr Node::Kind Kind = Node::K##X; \ + static constexpr const char *name() { return #X; } \ }; -FOR_EACH_NODE_KIND(SPECIALIZATION) -#undef SPECIALIZATION - -#undef FOR_EACH_NODE_KIND - -template <class T, size_t N> -class PODSmallVector { - static_assert(std::is_pod<T>::value, - "T is required to be a plain old data type"); - - T* First; - T* Last; - T* Cap; - T Inline[N]; - - bool isInline() const { return First == Inline; } - - void clearInline() { - First = Inline; - Last = Inline; - Cap = Inline + N; - } - - void reserve(size_t NewCap) { - size_t S = size(); - if (isInline()) { - auto* Tmp = static_cast<T*>(std::malloc(NewCap * sizeof(T))); - if (Tmp == nullptr) - std::terminate(); - std::copy(First, Last, Tmp); - First = Tmp; - } else { - First = static_cast<T*>(std::realloc(First, NewCap * sizeof(T))); - if (First == nullptr) - std::terminate(); - } - Last = First + S; - Cap = First + NewCap; - } - -public: - PODSmallVector() : First(Inline), Last(First), Cap(Inline + N) {} - - PODSmallVector(const PODSmallVector&) = delete; - PODSmallVector& operator=(const PODSmallVector&) = delete; - - PODSmallVector(PODSmallVector&& Other) : PODSmallVector() { - if (Other.isInline()) { - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return; - } - - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - } - - PODSmallVector& operator=(PODSmallVector&& Other) { - if (Other.isInline()) { - if (!isInline()) { - std::free(First); - clearInline(); - } - std::copy(Other.begin(), Other.end(), First); - Last = First + Other.size(); - Other.clear(); - return *this; - } - - if (isInline()) { - First = Other.First; - Last = Other.Last; - Cap = Other.Cap; - Other.clearInline(); - return *this; - } - - std::swap(First, Other.First); - std::swap(Last, Other.Last); - std::swap(Cap, Other.Cap); - Other.clear(); - return *this; - } - - void push_back(const T& Elem) { - if (Last == Cap) - reserve(size() * 2); - *Last++ = Elem; - } - - void pop_back() { - assert(Last != First && "Popping empty vector!"); - --Last; - } - - void dropBack(size_t Index) { - assert(Index <= size() && "dropBack() can't expand!"); - Last = First + Index; - } - - T* begin() { return First; } - T* end() { return Last; } - - bool empty() const { return First == Last; } - size_t size() const { return static_cast<size_t>(Last - First); } - T& back() { - assert(Last != First && "Calling back() on empty vector!"); - return *(Last - 1); - } - T& operator[](size_t Index) { - assert(Index < size() && "Invalid access!"); - return *(begin() + Index); - } - void clear() { Last = First; } - - ~PODSmallVector() { - if (!isInline()) - std::free(First); - } -}; +#include "ItaniumNodes.def" template <typename Derived, typename Alloc> struct AbstractManglingParser { const char *First; @@ -2350,9 +2406,9 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { TemplateParamList Params; public: - ScopedTemplateParamList(AbstractManglingParser *Parser) - : Parser(Parser), - OldNumTemplateParamLists(Parser->TemplateParams.size()) { + ScopedTemplateParamList(AbstractManglingParser *TheParser) + : Parser(TheParser), + OldNumTemplateParamLists(TheParser->TemplateParams.size()) { Parser->TemplateParams.push_back(&Params); } ~ScopedTemplateParamList() { @@ -2424,8 +2480,9 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { return res; } - bool consumeIf(StringView S) { - if (StringView(First, Last).startsWith(S)) { + bool consumeIf(std::string_view S) { + if (llvm::itanium_demangle::starts_with( + std::string_view(First, Last - First), S)) { First += S.size(); return true; } @@ -2442,7 +2499,7 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { char consume() { return First != Last ? *First++ : '\0'; } - char look(unsigned Lookahead = 0) { + char look(unsigned Lookahead = 0) const { if (static_cast<size_t>(Last - First) <= Lookahead) return '\0'; return First[Lookahead]; @@ -2450,10 +2507,10 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { size_t numLeft() const { return static_cast<size_t>(Last - First); } - StringView parseNumber(bool AllowNegative = false); + std::string_view parseNumber(bool AllowNegative = false); Qualifiers parseCVQualifiers(); bool parsePositiveInteger(size_t *Out); - StringView parseBareSourceName(); + std::string_view parseBareSourceName(); bool parseSeqId(size_t *Out); Node *parseSubstitution(); @@ -2464,16 +2521,17 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { /// Parse the <expr> production. Node *parseExpr(); - Node *parsePrefixExpr(StringView Kind); - Node *parseBinaryExpr(StringView Kind); - Node *parseIntegerLiteral(StringView Lit); + Node *parsePrefixExpr(std::string_view Kind, Node::Prec Prec); + Node *parseBinaryExpr(std::string_view Kind, Node::Prec Prec); + Node *parseIntegerLiteral(std::string_view Lit); Node *parseExprPrimary(); template <class Float> Node *parseFloatingLiteral(); Node *parseFunctionParam(); - Node *parseNewExpr(); Node *parseConversionExpr(); Node *parseBracedExpr(); Node *parseFoldExpr(); + Node *parsePointerToMemberConversionExpr(Node::Prec Prec); + Node *parseSubobjectExpr(); /// Parse the <type> production. Node *parseType(); @@ -2520,17 +2578,81 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser { Node *parseName(NameState *State = nullptr); Node *parseLocalName(NameState *State); Node *parseOperatorName(NameState *State); - Node *parseUnqualifiedName(NameState *State); + bool parseModuleNameOpt(ModuleName *&Module); + Node *parseUnqualifiedName(NameState *State, Node *Scope, ModuleName *Module); Node *parseUnnamedTypeName(NameState *State); Node *parseSourceName(NameState *State); - Node *parseUnscopedName(NameState *State); + Node *parseUnscopedName(NameState *State, bool *isSubstName); Node *parseNestedName(NameState *State); Node *parseCtorDtorName(Node *&SoFar, NameState *State); Node *parseAbiTags(Node *N); + struct OperatorInfo { + enum OIKind : unsigned char { + Prefix, // Prefix unary: @ expr + Postfix, // Postfix unary: expr @ + Binary, // Binary: lhs @ rhs + Array, // Array index: lhs [ rhs ] + Member, // Member access: lhs @ rhs + New, // New + Del, // Delete + Call, // Function call: expr (expr*) + CCast, // C cast: (type)expr + Conditional, // Conditional: expr ? expr : expr + NameOnly, // Overload only, not allowed in expression. + // Below do not have operator names + NamedCast, // Named cast, @<type>(expr) + OfIdOp, // alignof, sizeof, typeid + + Unnameable = NamedCast, + }; + char Enc[2]; // Encoding + OIKind Kind; // Kind of operator + bool Flag : 1; // Entry-specific flag + Node::Prec Prec : 7; // Precedence + const char *Name; // Spelling + + public: + constexpr OperatorInfo(const char (&E)[3], OIKind K, bool F, Node::Prec P, + const char *N) + : Enc{E[0], E[1]}, Kind{K}, Flag{F}, Prec{P}, Name{N} {} + + public: + bool operator<(const OperatorInfo &Other) const { + return *this < Other.Enc; + } + bool operator<(const char *Peek) const { + return Enc[0] < Peek[0] || (Enc[0] == Peek[0] && Enc[1] < Peek[1]); + } + bool operator==(const char *Peek) const { + return Enc[0] == Peek[0] && Enc[1] == Peek[1]; + } + bool operator!=(const char *Peek) const { return !this->operator==(Peek); } + + public: + std::string_view getSymbol() const { + std::string_view Res = Name; + if (Kind < Unnameable) { + assert(llvm::itanium_demangle::starts_with(Res, "operator") && + "operator name does not start with 'operator'"); + Res.remove_prefix(sizeof("operator") - 1); + if (llvm::itanium_demangle::starts_with(Res, ' ')) + Res.remove_prefix(1); + } + return Res; + } + std::string_view getName() const { return Name; } + OIKind getKind() const { return Kind; } + bool getFlag() const { return Flag; } + Node::Prec getPrecedence() const { return Prec; } + }; + static const OperatorInfo Ops[]; + static const size_t NumOps; + const OperatorInfo *parseOperatorEncoding(); + /// Parse the <unresolved-name> production. - Node *parseUnresolvedName(); + Node *parseUnresolvedName(bool Global); Node *parseSimpleId(); Node *parseBaseUnresolvedName(); Node *parseUnresolvedType(); @@ -2551,41 +2673,35 @@ const char* parse_discriminator(const char* first, const char* last); // ::= <substitution> template <typename Derived, typename Alloc> Node *AbstractManglingParser<Derived, Alloc>::parseName(NameState *State) { - consumeIf('L'); // extension - if (look() == 'N') return getDerived().parseNestedName(State); if (look() == 'Z') return getDerived().parseLocalName(State); - // ::= <unscoped-template-name> <template-args> - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (S == nullptr) - return nullptr; - if (look() != 'I') - return nullptr; - Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make<NameWithTemplateArgs>(S, TA); - } + Node *Result = nullptr; + bool IsSubst = false; - Node *N = getDerived().parseUnscopedName(State); - if (N == nullptr) + Result = getDerived().parseUnscopedName(State, &IsSubst); + if (!Result) return nullptr; - // ::= <unscoped-template-name> <template-args> + if (look() == 'I') { - Subs.push_back(N); + // ::= <unscoped-template-name> <template-args> + if (!IsSubst) + // An unscoped-template-name is substitutable. + Subs.push_back(Result); Node *TA = getDerived().parseTemplateArgs(State != nullptr); if (TA == nullptr) return nullptr; - if (State) State->EndsWithTemplateArgs = true; - return make<NameWithTemplateArgs>(N, TA); + if (State) + State->EndsWithTemplateArgs = true; + Result = make<NameWithTemplateArgs>(Result, TA); + } else if (IsSubst) { + // The substitution case must be followed by <template-args>. + return nullptr; } - // ::= <unscoped-name> - return N; + + return Result; } // <local-name> := Z <function encoding> E <entity name> [<discriminator>] @@ -2626,34 +2742,63 @@ Node *AbstractManglingParser<Derived, Alloc>::parseLocalName(NameState *State) { // <unscoped-name> ::= <unqualified-name> // ::= St <unqualified-name> # ::std:: -// extension ::= StL<unqualified-name> +// [*] extension template <typename Derived, typename Alloc> Node * -AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State) { - if (consumeIf("StL") || consumeIf("St")) { - Node *R = getDerived().parseUnqualifiedName(State); - if (R == nullptr) +AbstractManglingParser<Derived, Alloc>::parseUnscopedName(NameState *State, + bool *IsSubst) { + + Node *Std = nullptr; + if (consumeIf("St")) { + Std = make<NameType>("std"); + if (Std == nullptr) return nullptr; - return make<StdQualifiedName>(R); } - return getDerived().parseUnqualifiedName(State); + + Node *Res = nullptr; + ModuleName *Module = nullptr; + if (look() == 'S') { + Node *S = getDerived().parseSubstitution(); + if (!S) + return nullptr; + if (S->getKind() == Node::KModuleName) + Module = static_cast<ModuleName *>(S); + else if (IsSubst && Std == nullptr) { + Res = S; + *IsSubst = true; + } else { + return nullptr; + } + } + + if (Res == nullptr || Std != nullptr) { + Res = getDerived().parseUnqualifiedName(State, Std, Module); + } + + return Res; } -// <unqualified-name> ::= <operator-name> [abi-tags] -// ::= <ctor-dtor-name> -// ::= <source-name> -// ::= <unnamed-type-name> -// ::= DC <source-name>+ E # structured binding declaration +// <unqualified-name> ::= [<module-name>] L? <operator-name> [<abi-tags>] +// ::= [<module-name>] <ctor-dtor-name> [<abi-tags>] +// ::= [<module-name>] L? <source-name> [<abi-tags>] +// ::= [<module-name>] L? <unnamed-type-name> [<abi-tags>] +// # structured binding declaration +// ::= [<module-name>] L? DC <source-name>+ E template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) { - // <ctor-dtor-name>s are special-cased in parseNestedName(). +Node *AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName( + NameState *State, Node *Scope, ModuleName *Module) { + if (getDerived().parseModuleNameOpt(Module)) + return nullptr; + + consumeIf('L'); + Node *Result; - if (look() == 'U') - Result = getDerived().parseUnnamedTypeName(State); - else if (look() >= '1' && look() <= '9') + if (look() >= '1' && look() <= '9') { Result = getDerived().parseSourceName(State); - else if (consumeIf("DC")) { + } else if (look() == 'U') { + Result = getDerived().parseUnnamedTypeName(State); + } else if (consumeIf("DC")) { + // Structured binding size_t BindingsBegin = Names.size(); do { Node *Binding = getDerived().parseSourceName(State); @@ -2662,13 +2807,46 @@ AbstractManglingParser<Derived, Alloc>::parseUnqualifiedName(NameState *State) { Names.push_back(Binding); } while (!consumeIf('E')); Result = make<StructuredBindingName>(popTrailingNodeArray(BindingsBegin)); - } else + } else if (look() == 'C' || look() == 'D') { + // A <ctor-dtor-name>. + if (Scope == nullptr || Module != nullptr) + return nullptr; + Result = getDerived().parseCtorDtorName(Scope, State); + } else { Result = getDerived().parseOperatorName(State); + } + + if (Result != nullptr && Module != nullptr) + Result = make<ModuleEntity>(Module, Result); if (Result != nullptr) Result = getDerived().parseAbiTags(Result); + if (Result != nullptr && Scope != nullptr) + Result = make<NestedName>(Scope, Result); + return Result; } +// <module-name> ::= <module-subname> +// ::= <module-name> <module-subname> +// ::= <substitution> # passed in by caller +// <module-subname> ::= W <source-name> +// ::= W P <source-name> +template <typename Derived, typename Alloc> +bool AbstractManglingParser<Derived, Alloc>::parseModuleNameOpt( + ModuleName *&Module) { + while (consumeIf('W')) { + bool IsPartition = consumeIf('P'); + Node *Sub = getDerived().parseSourceName(nullptr); + if (!Sub) + return true; + Module = + static_cast<ModuleName *>(make<ModuleName>(Module, Sub, IsPartition)); + Subs.push_back(Module); + } + + return false; +} + // <unnamed-type-name> ::= Ut [<nonnegative number>] _ // ::= <closure-type-name> // @@ -2684,19 +2862,19 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) { TemplateParams.clear(); if (consumeIf("Ut")) { - StringView Count = parseNumber(); + std::string_view Count = parseNumber(); if (!consumeIf('_')) return nullptr; return make<UnnamedTypeName>(Count); } if (consumeIf("Ul")) { - SwapAndRestore<size_t> SwapParams(ParsingLambdaParamsAtLevel, + ScopedOverride<size_t> SwapParams(ParsingLambdaParamsAtLevel, TemplateParams.size()); ScopedTemplateParamList LambdaTemplateParams(this); size_t ParamsBegin = Names.size(); while (look() == 'T' && - StringView("yptn").find(look(1)) != StringView::npos) { + std::string_view("yptn").find(look(1)) != std::string_view::npos) { Node *T = parseTemplateParamDecl(); if (!T) return nullptr; @@ -2739,7 +2917,7 @@ AbstractManglingParser<Derived, Alloc>::parseUnnamedTypeName(NameState *State) { } NodeArray Params = popTrailingNodeArray(ParamsBegin); - StringView Count = parseNumber(); + std::string_view Count = parseNumber(); if (!consumeIf('_')) return nullptr; return make<ClosureTypeName>(TempParams, Params, Count); @@ -2761,104 +2939,138 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) { return nullptr; if (numLeft() < Length || Length == 0) return nullptr; - StringView Name(First, First + Length); + std::string_view Name(First, Length); First += Length; - if (Name.startsWith("_GLOBAL__N")) + if (llvm::itanium_demangle::starts_with(Name, "_GLOBAL__N")) return make<NameType>("(anonymous namespace)"); return make<NameType>(Name); } -// <operator-name> ::= aa # && -// ::= ad # & (unary) -// ::= an # & -// ::= aN # &= -// ::= aS # = -// ::= cl # () -// ::= cm # , -// ::= co # ~ -// ::= cv <type> # (cast) -// ::= da # delete[] -// ::= de # * (unary) -// ::= dl # delete -// ::= dv # / -// ::= dV # /= -// ::= eo # ^ -// ::= eO # ^= -// ::= eq # == -// ::= ge # >= -// ::= gt # > -// ::= ix # [] -// ::= le # <= +// Operator encodings +template <typename Derived, typename Alloc> +const typename AbstractManglingParser< + Derived, Alloc>::OperatorInfo AbstractManglingParser<Derived, + Alloc>::Ops[] = { + // Keep ordered by encoding + {"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="}, + {"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="}, + {"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"}, + {"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"}, + {"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"}, + {"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "alignof "}, + {"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary, + "operator co_await"}, + {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "}, + {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"}, + {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"}, + {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"}, + {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"}, + {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast + {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="}, + {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary, + "operator delete[]"}, + {"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "dynamic_cast"}, + {"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"}, + {"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary, + "operator delete"}, + {"ds", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem, + "operator.*"}, + {"dt", OperatorInfo::Member, /*Named*/ false, Node::Prec::Postfix, + "operator."}, + {"dv", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/"}, + {"eO", OperatorInfo::Binary, false, Node::Prec::Assign, "operator^="}, + {"eo", OperatorInfo::Binary, false, Node::Prec::Xor, "operator^"}, + {"eq", OperatorInfo::Binary, false, Node::Prec::Equality, "operator=="}, + {"ge", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>="}, + {"gt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator>"}, + {"ix", OperatorInfo::Array, false, Node::Prec::Postfix, "operator[]"}, + {"lS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator<<="}, + {"le", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<="}, + {"ls", OperatorInfo::Binary, false, Node::Prec::Shift, "operator<<"}, + {"lt", OperatorInfo::Binary, false, Node::Prec::Relational, "operator<"}, + {"mI", OperatorInfo::Binary, false, Node::Prec::Assign, "operator-="}, + {"mL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator*="}, + {"mi", OperatorInfo::Binary, false, Node::Prec::Additive, "operator-"}, + {"ml", OperatorInfo::Binary, false, Node::Prec::Multiplicative, + "operator*"}, + {"mm", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator--"}, + {"na", OperatorInfo::New, /*Ary*/ true, Node::Prec::Unary, + "operator new[]"}, + {"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="}, + {"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"}, + {"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"}, + {"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, "operator new"}, + {"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="}, + {"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"}, + {"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"}, + {"pL", OperatorInfo::Binary, false, Node::Prec::Assign, "operator+="}, + {"pl", OperatorInfo::Binary, false, Node::Prec::Additive, "operator+"}, + {"pm", OperatorInfo::Member, /*Named*/ false, Node::Prec::PtrMem, + "operator->*"}, + {"pp", OperatorInfo::Postfix, false, Node::Prec::Postfix, "operator++"}, + {"ps", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator+"}, + {"pt", OperatorInfo::Member, /*Named*/ true, Node::Prec::Postfix, + "operator->"}, + {"qu", OperatorInfo::Conditional, false, Node::Prec::Conditional, + "operator?"}, + {"rM", OperatorInfo::Binary, false, Node::Prec::Assign, "operator%="}, + {"rS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator>>="}, + {"rc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, + "reinterpret_cast"}, + {"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative, + "operator%"}, + {"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"}, + {"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "static_cast"}, + {"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"}, + {"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "}, + {"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "sizeof "}, + {"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix, + "typeid "}, + {"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, "typeid "}, +}; +template <typename Derived, typename Alloc> +const size_t AbstractManglingParser<Derived, Alloc>::NumOps = sizeof(Ops) / + sizeof(Ops[0]); + +// If the next 2 chars are an operator encoding, consume them and return their +// OperatorInfo. Otherwise return nullptr. +template <typename Derived, typename Alloc> +const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo * +AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() { + if (numLeft() < 2) + return nullptr; + + // We can't use lower_bound as that can link to symbols in the C++ library, + // and this must remain independant of that. + size_t lower = 0u, upper = NumOps - 1; // Inclusive bounds. + while (upper != lower) { + size_t middle = (upper + lower) / 2; + if (Ops[middle] < First) + lower = middle + 1; + else + upper = middle; + } + if (Ops[lower] != First) + return nullptr; + + First += 2; + return &Ops[lower]; +} + +// <operator-name> ::= See parseOperatorEncoding() // ::= li <source-name> # operator "" -// ::= ls # << -// ::= lS # <<= -// ::= lt # < -// ::= mi # - -// ::= mI # -= -// ::= ml # * -// ::= mL # *= -// ::= mm # -- (postfix in <expression> context) -// ::= na # new[] -// ::= ne # != -// ::= ng # - (unary) -// ::= nt # ! -// ::= nw # new -// ::= oo # || -// ::= or # | -// ::= oR # |= -// ::= pm # ->* -// ::= pl # + -// ::= pL # += -// ::= pp # ++ (postfix in <expression> context) -// ::= ps # + (unary) -// ::= pt # -> -// ::= qu # ? -// ::= rm # % -// ::= rM # %= -// ::= rs # >> -// ::= rS # >>= -// ::= ss # <=> C++2a -// ::= v <digit> <source-name> # vendor extended operator +// ::= v <digit> <source-name> # vendor extended operator template <typename Derived, typename Alloc> Node * AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) { - switch (look()) { - case 'a': - switch (look(1)) { - case 'a': - First += 2; - return make<NameType>("operator&&"); - case 'd': - case 'n': - First += 2; - return make<NameType>("operator&"); - case 'N': - First += 2; - return make<NameType>("operator&="); - case 'S': - First += 2; - return make<NameType>("operator="); - } - return nullptr; - case 'c': - switch (look(1)) { - case 'l': - First += 2; - return make<NameType>("operator()"); - case 'm': - First += 2; - return make<NameType>("operator,"); - case 'o': - First += 2; - return make<NameType>("operator~"); - // ::= cv <type> # (cast) - case 'v': { - First += 2; - SwapAndRestore<bool> SaveTemplate(TryToParseTemplateArgs, false); + if (const auto *Op = parseOperatorEncoding()) { + if (Op->getKind() == OperatorInfo::CCast) { + // ::= cv <type> # (cast) + ScopedOverride<bool> SaveTemplate(TryToParseTemplateArgs, false); // If we're parsing an encoding, State != nullptr and the conversion // operators' <type> could have a <template-param> that refers to some // <template-arg>s further ahead in the mangled name. - SwapAndRestore<bool> SavePermit(PermitForwardTemplateReferences, + ScopedOverride<bool> SavePermit(PermitForwardTemplateReferences, PermitForwardTemplateReferences || State != nullptr); Node *Ty = getDerived().parseType(); @@ -2867,185 +3079,29 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) { if (State) State->CtorDtorConversion = true; return make<ConversionOperatorType>(Ty); } - } - return nullptr; - case 'd': - switch (look(1)) { - case 'a': - First += 2; - return make<NameType>("operator delete[]"); - case 'e': - First += 2; - return make<NameType>("operator*"); - case 'l': - First += 2; - return make<NameType>("operator delete"); - case 'v': - First += 2; - return make<NameType>("operator/"); - case 'V': - First += 2; - return make<NameType>("operator/="); - } - return nullptr; - case 'e': - switch (look(1)) { - case 'o': - First += 2; - return make<NameType>("operator^"); - case 'O': - First += 2; - return make<NameType>("operator^="); - case 'q': - First += 2; - return make<NameType>("operator=="); - } - return nullptr; - case 'g': - switch (look(1)) { - case 'e': - First += 2; - return make<NameType>("operator>="); - case 't': - First += 2; - return make<NameType>("operator>"); - } - return nullptr; - case 'i': - if (look(1) == 'x') { - First += 2; - return make<NameType>("operator[]"); - } - return nullptr; - case 'l': - switch (look(1)) { - case 'e': - First += 2; - return make<NameType>("operator<="); + + if (Op->getKind() >= OperatorInfo::Unnameable) + /* Not a nameable operator. */ + return nullptr; + if (Op->getKind() == OperatorInfo::Member && !Op->getFlag()) + /* Not a nameable MemberExpr */ + return nullptr; + + return make<NameType>(Op->getName()); + } + + if (consumeIf("li")) { // ::= li <source-name> # operator "" - case 'i': { - First += 2; - Node *SN = getDerived().parseSourceName(State); - if (SN == nullptr) - return nullptr; - return make<LiteralOperator>(SN); - } - case 's': - First += 2; - return make<NameType>("operator<<"); - case 'S': - First += 2; - return make<NameType>("operator<<="); - case 't': - First += 2; - return make<NameType>("operator<"); - } - return nullptr; - case 'm': - switch (look(1)) { - case 'i': - First += 2; - return make<NameType>("operator-"); - case 'I': - First += 2; - return make<NameType>("operator-="); - case 'l': - First += 2; - return make<NameType>("operator*"); - case 'L': - First += 2; - return make<NameType>("operator*="); - case 'm': - First += 2; - return make<NameType>("operator--"); - } - return nullptr; - case 'n': - switch (look(1)) { - case 'a': - First += 2; - return make<NameType>("operator new[]"); - case 'e': - First += 2; - return make<NameType>("operator!="); - case 'g': - First += 2; - return make<NameType>("operator-"); - case 't': - First += 2; - return make<NameType>("operator!"); - case 'w': - First += 2; - return make<NameType>("operator new"); - } - return nullptr; - case 'o': - switch (look(1)) { - case 'o': - First += 2; - return make<NameType>("operator||"); - case 'r': - First += 2; - return make<NameType>("operator|"); - case 'R': - First += 2; - return make<NameType>("operator|="); - } - return nullptr; - case 'p': - switch (look(1)) { - case 'm': - First += 2; - return make<NameType>("operator->*"); - case 'l': - First += 2; - return make<NameType>("operator+"); - case 'L': - First += 2; - return make<NameType>("operator+="); - case 'p': - First += 2; - return make<NameType>("operator++"); - case 's': - First += 2; - return make<NameType>("operator+"); - case 't': - First += 2; - return make<NameType>("operator->"); - } - return nullptr; - case 'q': - if (look(1) == 'u') { - First += 2; - return make<NameType>("operator?"); - } - return nullptr; - case 'r': - switch (look(1)) { - case 'm': - First += 2; - return make<NameType>("operator%"); - case 'M': - First += 2; - return make<NameType>("operator%="); - case 's': - First += 2; - return make<NameType>("operator>>"); - case 'S': - First += 2; - return make<NameType>("operator>>="); - } - return nullptr; - case 's': - if (look(1) == 's') { - First += 2; - return make<NameType>("operator<=>"); - } - return nullptr; - // ::= v <digit> <source-name> # vendor extended operator - case 'v': - if (std::isdigit(look(1))) { - First += 2; + Node *SN = getDerived().parseSourceName(State); + if (SN == nullptr) + return nullptr; + return make<LiteralOperator>(SN); + } + + if (consumeIf('v')) { + // ::= v <digit> <source-name> # vendor extended operator + if (look() >= '0' && look() <= '9') { + First++; Node *SN = getDerived().parseSourceName(State); if (SN == nullptr) return nullptr; @@ -3053,6 +3109,7 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorName(NameState *State) { } return nullptr; } + return nullptr; } @@ -3071,19 +3128,11 @@ Node * AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar, NameState *State) { if (SoFar->getKind() == Node::KSpecialSubstitution) { - auto SSK = static_cast<SpecialSubstitution *>(SoFar)->SSK; - switch (SSK) { - case SpecialSubKind::string: - case SpecialSubKind::istream: - case SpecialSubKind::ostream: - case SpecialSubKind::iostream: - SoFar = make<ExpandedSpecialSubstitution>(SSK); - if (!SoFar) - return nullptr; - break; - default: - break; - } + // Expand the special substitution. + SoFar = make<ExpandedSpecialSubstitution>( + static_cast<SpecialSubstitution *>(SoFar)); + if (!SoFar) + return nullptr; } if (consumeIf('C')) { @@ -3112,8 +3161,10 @@ AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar, return nullptr; } -// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E -// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E +// <nested-name> ::= N [<CV-Qualifiers>] [<ref-qualifier>] <prefix> +// <unqualified-name> E +// ::= N [<CV-Qualifiers>] [<ref-qualifier>] <template-prefix> +// <template-args> E // // <prefix> ::= <prefix> <unqualified-name> // ::= <template-prefix> <template-args> @@ -3122,7 +3173,7 @@ AbstractManglingParser<Derived, Alloc>::parseCtorDtorName(Node *&SoFar, // ::= # empty // ::= <substitution> // ::= <prefix> <data-member-prefix> -// extension ::= L +// [*] extension // // <data-member-prefix> := <member source-name> [<template-args>] M // @@ -3142,90 +3193,76 @@ AbstractManglingParser<Derived, Alloc>::parseNestedName(NameState *State) { if (State) State->ReferenceQualifier = FrefQualRValue; } else if (consumeIf('R')) { if (State) State->ReferenceQualifier = FrefQualLValue; - } else + } else { if (State) State->ReferenceQualifier = FrefQualNone; - - Node *SoFar = nullptr; - auto PushComponent = [&](Node *Comp) { - if (!Comp) return false; - if (SoFar) SoFar = make<NestedName>(SoFar, Comp); - else SoFar = Comp; - if (State) State->EndsWithTemplateArgs = false; - return SoFar != nullptr; - }; - - if (consumeIf("St")) { - SoFar = make<NameType>("std"); - if (!SoFar) - return nullptr; } + Node *SoFar = nullptr; while (!consumeIf('E')) { - consumeIf('L'); // extension + if (State) + // Only set end-with-template on the case that does that. + State->EndsWithTemplateArgs = false; - // <data-member-prefix> := <member source-name> [<template-args>] M - if (consumeIf('M')) { - if (SoFar == nullptr) - return nullptr; - continue; - } - - // ::= <template-param> if (look() == 'T') { - if (!PushComponent(getDerived().parseTemplateParam())) - return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= <template-prefix> <template-args> - if (look() == 'I') { + // ::= <template-param> + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + SoFar = getDerived().parseTemplateParam(); + } else if (look() == 'I') { + // ::= <template-prefix> <template-args> + if (SoFar == nullptr) + return nullptr; // Must have a prefix. Node *TA = getDerived().parseTemplateArgs(State != nullptr); - if (TA == nullptr || SoFar == nullptr) - return nullptr; - SoFar = make<NameWithTemplateArgs>(SoFar, TA); - if (!SoFar) - return nullptr; - if (State) State->EndsWithTemplateArgs = true; - Subs.push_back(SoFar); - continue; - } - - // ::= <decltype> - if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { - if (!PushComponent(getDerived().parseDecltype())) + if (TA == nullptr) return nullptr; - Subs.push_back(SoFar); - continue; - } - - // ::= <substitution> - if (look() == 'S' && look(1) != 't') { - Node *S = getDerived().parseSubstitution(); - if (!PushComponent(S)) + if (SoFar->getKind() == Node::KNameWithTemplateArgs) + // Semantically <template-args> <template-args> cannot be generated by a + // C++ entity. There will always be [something like] a name between + // them. return nullptr; - if (SoFar != S) - Subs.push_back(S); - continue; - } + if (State) + State->EndsWithTemplateArgs = true; + SoFar = make<NameWithTemplateArgs>(SoFar, TA); + } else if (look() == 'D' && (look(1) == 't' || look(1) == 'T')) { + // ::= <decltype> + if (SoFar != nullptr) + return nullptr; // Cannot have a prefix. + SoFar = getDerived().parseDecltype(); + } else { + ModuleName *Module = nullptr; + + if (look() == 'S') { + // ::= <substitution> + Node *S = nullptr; + if (look(1) == 't') { + First += 2; + S = make<NameType>("std"); + } else { + S = getDerived().parseSubstitution(); + } + if (!S) + return nullptr; + if (S->getKind() == Node::KModuleName) { + Module = static_cast<ModuleName *>(S); + } else if (SoFar != nullptr) { + return nullptr; // Cannot have a prefix. + } else { + SoFar = S; + continue; // Do not push a new substitution. + } + } - // Parse an <unqualified-name> thats actually a <ctor-dtor-name>. - if (look() == 'C' || (look() == 'D' && look(1) != 'C')) { - if (SoFar == nullptr) - return nullptr; - if (!PushComponent(getDerived().parseCtorDtorName(SoFar, State))) - return nullptr; - SoFar = getDerived().parseAbiTags(SoFar); - if (SoFar == nullptr) - return nullptr; - Subs.push_back(SoFar); - continue; + // ::= [<prefix>] <unqualified-name> + SoFar = getDerived().parseUnqualifiedName(State, SoFar, Module); } - // ::= <prefix> <unqualified-name> - if (!PushComponent(getDerived().parseUnqualifiedName(State))) + if (SoFar == nullptr) return nullptr; Subs.push_back(SoFar); + + // No longer used. + // <data-member-prefix> := <member source-name> [<template-args>] M + consumeIf('M'); } if (SoFar == nullptr || Subs.empty()) @@ -3320,6 +3357,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseBaseUnresolvedName() { // ::= [gs] <base-unresolved-name> # x or (with "gs") ::x // ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> // # A::x, N::y, A<T>::z; "gs" means leading "::" +// [gs] has been parsed by caller. // ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x // extension ::= sr <unresolved-type> <template-args> <base-unresolved-name> // # T::N::x /decltype(p)::N::x @@ -3327,7 +3365,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseBaseUnresolvedName() { // // <unresolved-qualifier-level> ::= <simple-id> template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() { +Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName(bool Global) { Node *SoFar = nullptr; // srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> @@ -3361,8 +3399,6 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() { return make<QualifiedName>(SoFar, Base); } - bool Global = consumeIf("gs"); - // [gs] <base-unresolved-name> # x or (with "gs") ::x if (!consumeIf("sr")) { SoFar = getDerived().parseBaseUnresolvedName(); @@ -3419,7 +3455,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseUnresolvedName() { template <typename Derived, typename Alloc> Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) { while (consumeIf('B')) { - StringView SN = parseBareSourceName(); + std::string_view SN = parseBareSourceName(); if (SN.empty()) return nullptr; N = make<AbiTagAttr>(N, SN); @@ -3431,16 +3467,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseAbiTags(Node *N) { // <number> ::= [n] <non-negative decimal integer> template <typename Alloc, typename Derived> -StringView +std::string_view AbstractManglingParser<Alloc, Derived>::parseNumber(bool AllowNegative) { const char *Tmp = First; if (AllowNegative) consumeIf('n'); if (numLeft() == 0 || !std::isdigit(*First)) - return StringView(); + return std::string_view(); while (numLeft() != 0 && std::isdigit(*First)) ++First; - return StringView(Tmp, First); + return std::string_view(Tmp, First - Tmp); } // <positive length number> ::= [0-9]* @@ -3457,11 +3493,11 @@ bool AbstractManglingParser<Alloc, Derived>::parsePositiveInteger(size_t *Out) { } template <typename Alloc, typename Derived> -StringView AbstractManglingParser<Alloc, Derived>::parseBareSourceName() { +std::string_view AbstractManglingParser<Alloc, Derived>::parseBareSourceName() { size_t Int = 0; if (parsePositiveInteger(&Int) || numLeft() < Int) - return StringView(); - StringView R(First, First + Int); + return {}; + std::string_view R(First, Int); First += Int; return R; } @@ -3549,7 +3585,9 @@ Node *AbstractManglingParser<Derived, Alloc>::parseVectorType() { if (!consumeIf("Dv")) return nullptr; if (look() >= '1' && look() <= '9') { - StringView DimensionNumber = parseNumber(); + Node *DimensionNumber = make<NameType>(parseNumber()); + if (!DimensionNumber) + return nullptr; if (!consumeIf('_')) return nullptr; if (consumeIf('p')) @@ -3574,7 +3612,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseVectorType() { Node *ElemType = getDerived().parseType(); if (!ElemType) return nullptr; - return make<VectorType>(ElemType, StringView()); + return make<VectorType>(ElemType, /*Dimension=*/nullptr); } // <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x) @@ -3590,7 +3628,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseDecltype() { return nullptr; if (!consumeIf('E')) return nullptr; - return make<EnclosingExpr>("decltype(", E, ")"); + return make<EnclosingExpr>("decltype", E); } // <array-type> ::= A <positive dimension number> _ <element type> @@ -3600,10 +3638,12 @@ Node *AbstractManglingParser<Derived, Alloc>::parseArrayType() { if (!consumeIf('A')) return nullptr; - NodeOrString Dimension; + Node *Dimension = nullptr; if (std::isdigit(look())) { - Dimension = parseNumber(); + Dimension = make<NameType>(parseNumber()); + if (!Dimension) + return nullptr; if (!consumeIf('_')) return nullptr; } else if (!consumeIf('_')) { @@ -3641,7 +3681,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parsePointerToMemberType() { // ::= Te <name> # dependent elaborated type specifier using 'enum' template <typename Derived, typename Alloc> Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() { - StringView ElabSpef; + std::string_view ElabSpef; if (consumeIf("Ts")) ElabSpef = "struct"; else if (consumeIf("Tu")) @@ -3665,19 +3705,18 @@ Node *AbstractManglingParser<Derived, Alloc>::parseClassEnumType() { template <typename Derived, typename Alloc> Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() { if (consumeIf('U')) { - StringView Qual = parseBareSourceName(); + std::string_view Qual = parseBareSourceName(); if (Qual.empty()) return nullptr; - // FIXME parse the optional <template-args> here! - // extension ::= U <objc-name> <objc-type> # objc-type<identifier> - if (Qual.startsWith("objcproto")) { - StringView ProtoSourceName = Qual.dropFront(std::strlen("objcproto")); - StringView Proto; + if (llvm::itanium_demangle::starts_with(Qual, "objcproto")) { + constexpr size_t Len = sizeof("objcproto") - 1; + std::string_view ProtoSourceName(Qual.data() + Len, Qual.size() - Len); + std::string_view Proto; { - SwapAndRestore<const char *> SaveFirst(First, ProtoSourceName.begin()), - SaveLast(Last, ProtoSourceName.end()); + ScopedOverride<const char *> SaveFirst(First, ProtoSourceName.data()), + SaveLast(Last, &*ProtoSourceName.rbegin() + 1); Proto = parseBareSourceName(); } if (Proto.empty()) @@ -3688,10 +3727,17 @@ Node *AbstractManglingParser<Derived, Alloc>::parseQualifiedType() { return make<ObjCProtoName>(Child, Proto); } + Node *TA = nullptr; + if (look() == 'I') { + TA = getDerived().parseTemplateArgs(); + if (TA == nullptr) + return nullptr; + } + Node *Child = getDerived().parseQualifiedType(); if (Child == nullptr) return nullptr; - return make<VendorExtQualType>(Child, Qual); + return make<VendorExtQualType>(Child, Qual, TA); } Qualifiers Quals = parseCVQualifiers(); @@ -3838,7 +3884,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() { // <builtin-type> ::= u <source-name> # vendor extended type case 'u': { ++First; - StringView Res = parseBareSourceName(); + std::string_view Res = parseBareSourceName(); if (Res.empty()) return nullptr; // Typically, <builtin-type>s are not considered substitution candidates, @@ -3864,7 +3910,33 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() { // ::= Dh # IEEE 754r half-precision floating point (16 bits) case 'h': First += 2; - return make<NameType>("decimal16"); + return make<NameType>("half"); + // ::= DF <number> _ # ISO/IEC TS 18661 binary floating point (N bits) + case 'F': { + First += 2; + Node *DimensionNumber = make<NameType>(parseNumber()); + if (!DimensionNumber) + return nullptr; + if (!consumeIf('_')) + return nullptr; + return make<BinaryFPType>(DimensionNumber); + } + // ::= DB <number> _ # C23 signed _BitInt(N) + // ::= DB <instantiation-dependent expression> _ # C23 signed _BitInt(N) + // ::= DU <number> _ # C23 unsigned _BitInt(N) + // ::= DU <instantiation-dependent expression> _ # C23 unsigned _BitInt(N) + case 'B': + case 'U': { + bool Signed = look(1) == 'B'; + First += 2; + Node *Size = std::isdigit(look()) ? make<NameType>(parseNumber()) + : getDerived().parseExpr(); + if (!Size) + return nullptr; + if (!consumeIf('_')) + return nullptr; + return make<BitIntType>(Size, Signed); + } // ::= Di # char32_t case 'i': First += 2; @@ -4012,9 +4084,10 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() { } // ::= <substitution> # See Compression below case 'S': { - if (look(1) && look(1) != 't') { - Node *Sub = getDerived().parseSubstitution(); - if (Sub == nullptr) + if (look(1) != 't') { + bool IsSubst = false; + Result = getDerived().parseUnscopedName(nullptr, &IsSubst); + if (!Result) return nullptr; // Sub could be either of: @@ -4027,17 +4100,19 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() { // If this is followed by some <template-args>, and we're permitted to // parse them, take the second production. - if (TryToParseTemplateArgs && look() == 'I') { + if (look() == 'I' && (!IsSubst || TryToParseTemplateArgs)) { + if (!IsSubst) + Subs.push_back(Result); Node *TA = getDerived().parseTemplateArgs(); if (TA == nullptr) return nullptr; - Result = make<NameWithTemplateArgs>(Sub, TA); - break; + Result = make<NameWithTemplateArgs>(Result, TA); + } else if (IsSubst) { + // If all we parsed was a substitution, don't re-insert into the + // substitution table. + return Result; } - - // If all we parsed was a substitution, don't re-insert into the - // substitution table. - return Sub; + break; } DEMANGLE_FALLTHROUGH; } @@ -4057,28 +4132,32 @@ Node *AbstractManglingParser<Derived, Alloc>::parseType() { } template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(StringView Kind) { +Node * +AbstractManglingParser<Derived, Alloc>::parsePrefixExpr(std::string_view Kind, + Node::Prec Prec) { Node *E = getDerived().parseExpr(); if (E == nullptr) return nullptr; - return make<PrefixExpr>(Kind, E); + return make<PrefixExpr>(Kind, E, Prec); } template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(StringView Kind) { +Node * +AbstractManglingParser<Derived, Alloc>::parseBinaryExpr(std::string_view Kind, + Node::Prec Prec) { Node *LHS = getDerived().parseExpr(); if (LHS == nullptr) return nullptr; Node *RHS = getDerived().parseExpr(); if (RHS == nullptr) return nullptr; - return make<BinaryExpr>(LHS, Kind, RHS); + return make<BinaryExpr>(LHS, Kind, RHS, Prec); } template <typename Derived, typename Alloc> -Node * -AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral(StringView Lit) { - StringView Tmp = parseNumber(true); +Node *AbstractManglingParser<Derived, Alloc>::parseIntegerLiteral( + std::string_view Lit) { + std::string_view Tmp = parseNumber(true); if (!Tmp.empty() && consumeIf('E')) return make<IntegerLiteral>(Lit, Tmp); return nullptr; @@ -4101,11 +4180,14 @@ Qualifiers AbstractManglingParser<Alloc, Derived>::parseCVQualifiers() { // ::= fp <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters // ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> _ # L > 0, first parameter // ::= fL <L-1 non-negative number> p <top-level CV-Qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters +// ::= fpT # 'this' expression (not part of standard?) template <typename Derived, typename Alloc> Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() { + if (consumeIf("fpT")) + return make<NameType>("this"); if (consumeIf("fp")) { parseCVQualifiers(); - StringView Num = parseNumber(); + std::string_view Num = parseNumber(); if (!consumeIf('_')) return nullptr; return make<FunctionParam>(Num); @@ -4116,7 +4198,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() { if (!consumeIf('p')) return nullptr; parseCVQualifiers(); - StringView Num = parseNumber(); + std::string_view Num = parseNumber(); if (!consumeIf('_')) return nullptr; return make<FunctionParam>(Num); @@ -4124,43 +4206,6 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFunctionParam() { return nullptr; } -// [gs] nw <expression>* _ <type> E # new (expr-list) type -// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) -// [gs] na <expression>* _ <type> E # new[] (expr-list) type -// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) -// <initializer> ::= pi <expression>* E # parenthesized initialization -template <typename Derived, typename Alloc> -Node *AbstractManglingParser<Derived, Alloc>::parseNewExpr() { - bool Global = consumeIf("gs"); - bool IsArray = look(1) == 'a'; - if (!consumeIf("nw") && !consumeIf("na")) - return nullptr; - size_t Exprs = Names.size(); - while (!consumeIf('_')) { - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return nullptr; - Names.push_back(Ex); - } - NodeArray ExprList = popTrailingNodeArray(Exprs); - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - if (consumeIf("pi")) { - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Init = getDerived().parseExpr(); - if (Init == nullptr) - return Init; - Names.push_back(Init); - } - NodeArray Inits = popTrailingNodeArray(InitsBegin); - return make<NewExpr>(ExprList, Ty, Inits, Global, IsArray); - } else if (!consumeIf('E')) - return nullptr; - return make<NewExpr>(ExprList, Ty, NodeArray(), Global, IsArray); -} - // cv <type> <expression> # conversion with one argument // cv <type> _ <expression>* E # conversion with a different number of arguments template <typename Derived, typename Alloc> @@ -4169,7 +4214,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseConversionExpr() { return nullptr; Node *Ty; { - SwapAndRestore<bool> SaveTemp(TryToParseTemplateArgs, false); + ScopedOverride<bool> SaveTemp(TryToParseTemplateArgs, false); Ty = getDerived().parseType(); } @@ -4262,7 +4307,13 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() { return getDerived().template parseFloatingLiteral<double>(); case 'e': ++First; +#if defined(__powerpc__) || defined(__s390__) + // Handle cases where long doubles encoded with e have the same size + // and representation as doubles. + return getDerived().template parseFloatingLiteral<double>(); +#else return getDerived().template parseFloatingLiteral<long double>(); +#endif case '_': if (consumeIf("_Z")) { Node *R = getDerived().parseEncoding(); @@ -4280,7 +4331,7 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() { return nullptr; } case 'D': - if (consumeIf("DnE")) + if (consumeIf("Dn") && (consumeIf('0'), consumeIf('E'))) return make<NameType>("nullptr"); return nullptr; case 'T': @@ -4301,12 +4352,12 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExprPrimary() { Node *T = getDerived().parseType(); if (T == nullptr) return nullptr; - StringView N = parseNumber(); + std::string_view N = parseNumber(/*AllowNegative=*/true); if (N.empty()) return nullptr; if (!consumeIf('E')) return nullptr; - return make<IntegerCastExpr>(T, N); + return make<EnumLiteral>(T, N); } } } @@ -4367,55 +4418,38 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() { if (!consumeIf('f')) return nullptr; - char FoldKind = look(); - bool IsLeftFold, HasInitializer; - HasInitializer = FoldKind == 'L' || FoldKind == 'R'; - if (FoldKind == 'l' || FoldKind == 'L') - IsLeftFold = true; - else if (FoldKind == 'r' || FoldKind == 'R') - IsLeftFold = false; - else + bool IsLeftFold = false, HasInitializer = false; + switch (look()) { + default: return nullptr; + case 'L': + IsLeftFold = true; + HasInitializer = true; + break; + case 'R': + HasInitializer = true; + break; + case 'l': + IsLeftFold = true; + break; + case 'r': + break; + } ++First; - // FIXME: This map is duplicated in parseOperatorName and parseExpr. - StringView OperatorName; - if (consumeIf("aa")) OperatorName = "&&"; - else if (consumeIf("an")) OperatorName = "&"; - else if (consumeIf("aN")) OperatorName = "&="; - else if (consumeIf("aS")) OperatorName = "="; - else if (consumeIf("cm")) OperatorName = ","; - else if (consumeIf("ds")) OperatorName = ".*"; - else if (consumeIf("dv")) OperatorName = "/"; - else if (consumeIf("dV")) OperatorName = "/="; - else if (consumeIf("eo")) OperatorName = "^"; - else if (consumeIf("eO")) OperatorName = "^="; - else if (consumeIf("eq")) OperatorName = "=="; - else if (consumeIf("ge")) OperatorName = ">="; - else if (consumeIf("gt")) OperatorName = ">"; - else if (consumeIf("le")) OperatorName = "<="; - else if (consumeIf("ls")) OperatorName = "<<"; - else if (consumeIf("lS")) OperatorName = "<<="; - else if (consumeIf("lt")) OperatorName = "<"; - else if (consumeIf("mi")) OperatorName = "-"; - else if (consumeIf("mI")) OperatorName = "-="; - else if (consumeIf("ml")) OperatorName = "*"; - else if (consumeIf("mL")) OperatorName = "*="; - else if (consumeIf("ne")) OperatorName = "!="; - else if (consumeIf("oo")) OperatorName = "||"; - else if (consumeIf("or")) OperatorName = "|"; - else if (consumeIf("oR")) OperatorName = "|="; - else if (consumeIf("pl")) OperatorName = "+"; - else if (consumeIf("pL")) OperatorName = "+="; - else if (consumeIf("rm")) OperatorName = "%"; - else if (consumeIf("rM")) OperatorName = "%="; - else if (consumeIf("rs")) OperatorName = ">>"; - else if (consumeIf("rS")) OperatorName = ">>="; - else return nullptr; - - Node *Pack = getDerived().parseExpr(), *Init = nullptr; + const auto *Op = parseOperatorEncoding(); + if (!Op) + return nullptr; + if (!(Op->getKind() == OperatorInfo::Binary + || (Op->getKind() == OperatorInfo::Member + && Op->getName().back() == '*'))) + return nullptr; + + Node *Pack = getDerived().parseExpr(); if (Pack == nullptr) return nullptr; + + Node *Init = nullptr; if (HasInitializer) { Init = getDerived().parseExpr(); if (Init == nullptr) @@ -4425,7 +4459,53 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() { if (IsLeftFold && Init) std::swap(Pack, Init); - return make<FoldExpr>(IsLeftFold, OperatorName, Pack, Init); + return make<FoldExpr>(IsLeftFold, Op->getSymbol(), Pack, Init); +} + +// <expression> ::= mc <parameter type> <expr> [<offset number>] E +// +// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 +template <typename Derived, typename Alloc> +Node * +AbstractManglingParser<Derived, Alloc>::parsePointerToMemberConversionExpr( + Node::Prec Prec) { + Node *Ty = getDerived().parseType(); + if (!Ty) + return nullptr; + Node *Expr = getDerived().parseExpr(); + if (!Expr) + return nullptr; + std::string_view Offset = getDerived().parseNumber(true); + if (!consumeIf('E')) + return nullptr; + return make<PointerToMemberConversionExpr>(Ty, Expr, Offset, Prec); +} + +// <expression> ::= so <referent type> <expr> [<offset number>] <union-selector>* [p] E +// <union-selector> ::= _ [<number>] +// +// Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/47 +template <typename Derived, typename Alloc> +Node *AbstractManglingParser<Derived, Alloc>::parseSubobjectExpr() { + Node *Ty = getDerived().parseType(); + if (!Ty) + return nullptr; + Node *Expr = getDerived().parseExpr(); + if (!Expr) + return nullptr; + std::string_view Offset = getDerived().parseNumber(true); + size_t SelectorsBegin = Names.size(); + while (consumeIf('_')) { + Node *Selector = make<NameType>(parseNumber()); + if (!Selector) + return nullptr; + Names.push_back(Selector); + } + bool OnePastTheEnd = consumeIf('p'); + if (!consumeIf('E')) + return nullptr; + return make<SubobjectExpr>( + Ty, Expr, Offset, popTrailingNodeArray(SelectorsBegin), OnePastTheEnd); } // <expression> ::= <unary operator-name> <expression> @@ -4475,313 +4555,127 @@ Node *AbstractManglingParser<Derived, Alloc>::parseFoldExpr() { template <typename Derived, typename Alloc> Node *AbstractManglingParser<Derived, Alloc>::parseExpr() { bool Global = consumeIf("gs"); - if (numLeft() < 2) - return nullptr; - switch (*First) { - case 'L': - return getDerived().parseExprPrimary(); - case 'T': - return getDerived().parseTemplateParam(); - case 'f': { - // Disambiguate a fold expression from a <function-param>. - if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2)))) - return getDerived().parseFunctionParam(); - return getDerived().parseFoldExpr(); - } - case 'a': - switch (First[1]) { - case 'a': - First += 2; - return getDerived().parseBinaryExpr("&&"); - case 'd': - First += 2; - return getDerived().parsePrefixExpr("&"); - case 'n': - First += 2; - return getDerived().parseBinaryExpr("&"); - case 'N': - First += 2; - return getDerived().parseBinaryExpr("&="); - case 'S': - First += 2; - return getDerived().parseBinaryExpr("="); - case 't': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return nullptr; - return make<EnclosingExpr>("alignof (", Ty, ")"); - } - case 'z': { - First += 2; - Node *Ty = getDerived().parseExpr(); - if (Ty == nullptr) - return nullptr; - return make<EnclosingExpr>("alignof (", Ty, ")"); - } - } - return nullptr; - case 'c': - switch (First[1]) { - // cc <type> <expression> # const_cast<type>(expression) - case 'c': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<CastExpr>("const_cast", Ty, Ex); - } - // cl <expression>+ E # call - case 'l': { - First += 2; - Node *Callee = getDerived().parseExpr(); - if (Callee == nullptr) - return Callee; - size_t ExprsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return E; - Names.push_back(E); - } - return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin)); - } - case 'm': - First += 2; - return getDerived().parseBinaryExpr(","); - case 'o': - First += 2; - return getDerived().parsePrefixExpr("~"); - case 'v': - return getDerived().parseConversionExpr(); - } - return nullptr; - case 'd': - switch (First[1]) { - case 'a': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<DeleteExpr>(Ex, Global, /*is_array=*/true); - } - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; + const auto *Op = parseOperatorEncoding(); + if (Op) { + auto Sym = Op->getSymbol(); + switch (Op->getKind()) { + case OperatorInfo::Binary: + // Binary operator: lhs @ rhs + return getDerived().parseBinaryExpr(Sym, Op->getPrecedence()); + case OperatorInfo::Prefix: + // Prefix unary operator: @ expr + return getDerived().parsePrefixExpr(Sym, Op->getPrecedence()); + case OperatorInfo::Postfix: { + // Postfix unary operator: expr @ + if (consumeIf('_')) + return getDerived().parsePrefixExpr(Sym, Op->getPrecedence()); Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) - return Ex; - return make<CastExpr>("dynamic_cast", T, Ex); - } - case 'e': - First += 2; - return getDerived().parsePrefixExpr("*"); - case 'l': { - First += 2; - Node *E = getDerived().parseExpr(); - if (E == nullptr) - return E; - return make<DeleteExpr>(E, Global, /*is_array=*/false); + return nullptr; + return make<PostfixExpr>(Ex, Sym, Op->getPrecedence()); } - case 'n': - return getDerived().parseUnresolvedName(); - case 's': { - First += 2; - Node *LHS = getDerived().parseExpr(); - if (LHS == nullptr) + case OperatorInfo::Array: { + // Array Index: lhs [ rhs ] + Node *Base = getDerived().parseExpr(); + if (Base == nullptr) return nullptr; - Node *RHS = getDerived().parseExpr(); - if (RHS == nullptr) + Node *Index = getDerived().parseExpr(); + if (Index == nullptr) return nullptr; - return make<MemberExpr>(LHS, ".*", RHS); + return make<ArraySubscriptExpr>(Base, Index, Op->getPrecedence()); } - case 't': { - First += 2; + case OperatorInfo::Member: { + // Member access lhs @ rhs Node *LHS = getDerived().parseExpr(); if (LHS == nullptr) - return LHS; + return nullptr; Node *RHS = getDerived().parseExpr(); if (RHS == nullptr) return nullptr; - return make<MemberExpr>(LHS, ".", RHS); - } - case 'v': - First += 2; - return getDerived().parseBinaryExpr("/"); - case 'V': - First += 2; - return getDerived().parseBinaryExpr("/="); - } - return nullptr; - case 'e': - switch (First[1]) { - case 'o': - First += 2; - return getDerived().parseBinaryExpr("^"); - case 'O': - First += 2; - return getDerived().parseBinaryExpr("^="); - case 'q': - First += 2; - return getDerived().parseBinaryExpr("=="); - } - return nullptr; - case 'g': - switch (First[1]) { - case 'e': - First += 2; - return getDerived().parseBinaryExpr(">="); - case 't': - First += 2; - return getDerived().parseBinaryExpr(">"); - } - return nullptr; - case 'i': - switch (First[1]) { - case 'x': { - First += 2; - Node *Base = getDerived().parseExpr(); - if (Base == nullptr) + return make<MemberExpr>(LHS, Sym, RHS, Op->getPrecedence()); + } + case OperatorInfo::New: { + // New + // # new (expr-list) type [(init)] + // [gs] nw <expression>* _ <type> [pi <expression>*] E + // # new[] (expr-list) type [(init)] + // [gs] na <expression>* _ <type> [pi <expression>*] E + size_t Exprs = Names.size(); + while (!consumeIf('_')) { + Node *Ex = getDerived().parseExpr(); + if (Ex == nullptr) + return nullptr; + Names.push_back(Ex); + } + NodeArray ExprList = popTrailingNodeArray(Exprs); + Node *Ty = getDerived().parseType(); + if (Ty == nullptr) return nullptr; - Node *Index = getDerived().parseExpr(); - if (Index == nullptr) - return Index; - return make<ArraySubscriptExpr>(Base, Index); - } - case 'l': { - First += 2; + bool HaveInits = consumeIf("pi"); size_t InitsBegin = Names.size(); while (!consumeIf('E')) { - Node *E = getDerived().parseBracedExpr(); - if (E == nullptr) + if (!HaveInits) return nullptr; - Names.push_back(E); + Node *Init = getDerived().parseExpr(); + if (Init == nullptr) + return Init; + Names.push_back(Init); } - return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin)); - } + NodeArray Inits = popTrailingNodeArray(InitsBegin); + return make<NewExpr>(ExprList, Ty, Inits, Global, + /*IsArray=*/Op->getFlag(), Op->getPrecedence()); } - return nullptr; - case 'l': - switch (First[1]) { - case 'e': - First += 2; - return getDerived().parseBinaryExpr("<="); - case 's': - First += 2; - return getDerived().parseBinaryExpr("<<"); - case 'S': - First += 2; - return getDerived().parseBinaryExpr("<<="); - case 't': - First += 2; - return getDerived().parseBinaryExpr("<"); - } - return nullptr; - case 'm': - switch (First[1]) { - case 'i': - First += 2; - return getDerived().parseBinaryExpr("-"); - case 'I': - First += 2; - return getDerived().parseBinaryExpr("-="); - case 'l': - First += 2; - return getDerived().parseBinaryExpr("*"); - case 'L': - First += 2; - return getDerived().parseBinaryExpr("*="); - case 'm': - First += 2; - if (consumeIf('_')) - return getDerived().parsePrefixExpr("--"); + case OperatorInfo::Del: { + // Delete Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) return nullptr; - return make<PostfixExpr>(Ex, "--"); - } - return nullptr; - case 'n': - switch (First[1]) { - case 'a': - case 'w': - return getDerived().parseNewExpr(); - case 'e': - First += 2; - return getDerived().parseBinaryExpr("!="); - case 'g': - First += 2; - return getDerived().parsePrefixExpr("-"); - case 't': - First += 2; - return getDerived().parsePrefixExpr("!"); - case 'x': - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<EnclosingExpr>("noexcept (", Ex, ")"); - } - return nullptr; - case 'o': - switch (First[1]) { - case 'n': - return getDerived().parseUnresolvedName(); - case 'o': - First += 2; - return getDerived().parseBinaryExpr("||"); - case 'r': - First += 2; - return getDerived().parseBinaryExpr("|"); - case 'R': - First += 2; - return getDerived().parseBinaryExpr("|="); + return make<DeleteExpr>(Ex, Global, /*IsArray=*/Op->getFlag(), + Op->getPrecedence()); } - return nullptr; - case 'p': - switch (First[1]) { - case 'm': - First += 2; - return getDerived().parseBinaryExpr("->*"); - case 'l': - First += 2; - return getDerived().parseBinaryExpr("+"); - case 'L': - First += 2; - return getDerived().parseBinaryExpr("+="); - case 'p': { - First += 2; - if (consumeIf('_')) - return getDerived().parsePrefixExpr("++"); - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<PostfixExpr>(Ex, "++"); + case OperatorInfo::Call: { + // Function Call + Node *Callee = getDerived().parseExpr(); + if (Callee == nullptr) + return nullptr; + size_t ExprsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = getDerived().parseExpr(); + if (E == nullptr) + return nullptr; + Names.push_back(E); + } + return make<CallExpr>(Callee, popTrailingNodeArray(ExprsBegin), + Op->getPrecedence()); } - case 's': - First += 2; - return getDerived().parsePrefixExpr("+"); - case 't': { - First += 2; - Node *L = getDerived().parseExpr(); - if (L == nullptr) + case OperatorInfo::CCast: { + // C Cast: (type)expr + Node *Ty; + { + ScopedOverride<bool> SaveTemp(TryToParseTemplateArgs, false); + Ty = getDerived().parseType(); + } + if (Ty == nullptr) return nullptr; - Node *R = getDerived().parseExpr(); - if (R == nullptr) + + size_t ExprsBegin = Names.size(); + bool IsMany = consumeIf('_'); + while (!consumeIf('E')) { + Node *E = getDerived().parseExpr(); + if (E == nullptr) + return E; + Names.push_back(E); + if (!IsMany) + break; + } + NodeArray Exprs = popTrailingNodeArray(ExprsBegin); + if (!IsMany && Exprs.size() != 1) return nullptr; - return make<MemberExpr>(L, "->", R); + return make<ConversionExpr>(Ty, Exprs, Op->getPrecedence()); } - } - return nullptr; - case 'q': - if (First[1] == 'u') { - First += 2; + case OperatorInfo::Conditional: { + // Conditional operator: expr ? expr : expr Node *Cond = getDerived().parseExpr(); if (Cond == nullptr) return nullptr; @@ -4791,169 +4685,158 @@ Node *AbstractManglingParser<Derived, Alloc>::parseExpr() { Node *RHS = getDerived().parseExpr(); if (RHS == nullptr) return nullptr; - return make<ConditionalExpr>(Cond, LHS, RHS); - } - return nullptr; - case 'r': - switch (First[1]) { - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<CastExpr>("reinterpret_cast", T, Ex); + return make<ConditionalExpr>(Cond, LHS, RHS, Op->getPrecedence()); } - case 'm': - First += 2; - return getDerived().parseBinaryExpr("%"); - case 'M': - First += 2; - return getDerived().parseBinaryExpr("%="); - case 's': - First += 2; - return getDerived().parseBinaryExpr(">>"); - case 'S': - First += 2; - return getDerived().parseBinaryExpr(">>="); - } - return nullptr; - case 's': - switch (First[1]) { - case 'c': { - First += 2; - Node *T = getDerived().parseType(); - if (T == nullptr) - return T; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<CastExpr>("static_cast", T, Ex); - } - case 'p': { - First += 2; - Node *Child = getDerived().parseExpr(); - if (Child == nullptr) - return nullptr; - return make<ParameterPackExpansion>(Child); - } - case 'r': - return getDerived().parseUnresolvedName(); - case 't': { - First += 2; + case OperatorInfo::NamedCast: { + // Named cast operation, @<type>(expr) Node *Ty = getDerived().parseType(); if (Ty == nullptr) - return Ty; - return make<EnclosingExpr>("sizeof (", Ty, ")"); - } - case 'z': { - First += 2; + return nullptr; Node *Ex = getDerived().parseExpr(); if (Ex == nullptr) - return Ex; - return make<EnclosingExpr>("sizeof (", Ex, ")"); - } - case 'Z': - First += 2; - if (look() == 'T') { - Node *R = getDerived().parseTemplateParam(); - if (R == nullptr) - return nullptr; - return make<SizeofParamPackExpr>(R); - } else if (look() == 'f') { - Node *FP = getDerived().parseFunctionParam(); - if (FP == nullptr) - return nullptr; - return make<EnclosingExpr>("sizeof... (", FP, ")"); - } - return nullptr; - case 'P': { - First += 2; - size_t ArgsBegin = Names.size(); - while (!consumeIf('E')) { - Node *Arg = getDerived().parseTemplateArg(); - if (Arg == nullptr) - return nullptr; - Names.push_back(Arg); - } - auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin)); - if (!Pack) return nullptr; - return make<EnclosingExpr>("sizeof... (", Pack, ")"); + return make<CastExpr>(Sym, Ty, Ex, Op->getPrecedence()); } + case OperatorInfo::OfIdOp: { + // [sizeof/alignof/typeid] ( <type>|<expr> ) + Node *Arg = + Op->getFlag() ? getDerived().parseType() : getDerived().parseExpr(); + if (!Arg) + return nullptr; + return make<EnclosingExpr>(Sym, Arg, Op->getPrecedence()); } - return nullptr; - case 't': - switch (First[1]) { - case 'e': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) - return Ex; - return make<EnclosingExpr>("typeid (", Ex, ")"); + case OperatorInfo::NameOnly: { + // Not valid as an expression operand. + return nullptr; } - case 'i': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) - return Ty; - return make<EnclosingExpr>("typeid (", Ty, ")"); } - case 'l': { - First += 2; - Node *Ty = getDerived().parseType(); - if (Ty == nullptr) + DEMANGLE_UNREACHABLE; + } + + if (numLeft() < 2) + return nullptr; + + if (look() == 'L') + return getDerived().parseExprPrimary(); + if (look() == 'T') + return getDerived().parseTemplateParam(); + if (look() == 'f') { + // Disambiguate a fold expression from a <function-param>. + if (look(1) == 'p' || (look(1) == 'L' && std::isdigit(look(2)))) + return getDerived().parseFunctionParam(); + return getDerived().parseFoldExpr(); + } + if (consumeIf("il")) { + size_t InitsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = getDerived().parseBracedExpr(); + if (E == nullptr) return nullptr; - size_t InitsBegin = Names.size(); - while (!consumeIf('E')) { - Node *E = getDerived().parseBracedExpr(); - if (E == nullptr) - return nullptr; - Names.push_back(E); - } - return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin)); + Names.push_back(E); } - case 'r': - First += 2; - return make<NameType>("throw"); - case 'w': { - First += 2; - Node *Ex = getDerived().parseExpr(); - if (Ex == nullptr) + return make<InitListExpr>(nullptr, popTrailingNodeArray(InitsBegin)); + } + if (consumeIf("mc")) + return parsePointerToMemberConversionExpr(Node::Prec::Unary); + if (consumeIf("nx")) { + Node *Ex = getDerived().parseExpr(); + if (Ex == nullptr) + return Ex; + return make<EnclosingExpr>("noexcept ", Ex, Node::Prec::Unary); + } + if (consumeIf("so")) + return parseSubobjectExpr(); + if (consumeIf("sp")) { + Node *Child = getDerived().parseExpr(); + if (Child == nullptr) + return nullptr; + return make<ParameterPackExpansion>(Child); + } + if (consumeIf("sZ")) { + if (look() == 'T') { + Node *R = getDerived().parseTemplateParam(); + if (R == nullptr) return nullptr; - return make<ThrowExpr>(Ex); + return make<SizeofParamPackExpr>(R); } + Node *FP = getDerived().parseFunctionParam(); + if (FP == nullptr) + return nullptr; + return make<EnclosingExpr>("sizeof... ", FP); + } + if (consumeIf("sP")) { + size_t ArgsBegin = Names.size(); + while (!consumeIf('E')) { + Node *Arg = getDerived().parseTemplateArg(); + if (Arg == nullptr) + return nullptr; + Names.push_back(Arg); } - return nullptr; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return getDerived().parseUnresolvedName(); - } - - if (consumeIf("u8__uuidoft")) { + auto *Pack = make<NodeArrayNode>(popTrailingNodeArray(ArgsBegin)); + if (!Pack) + return nullptr; + return make<EnclosingExpr>("sizeof... ", Pack); + } + if (consumeIf("tl")) { Node *Ty = getDerived().parseType(); - if (!Ty) + if (Ty == nullptr) return nullptr; - return make<UUIDOfExpr>(Ty); + size_t InitsBegin = Names.size(); + while (!consumeIf('E')) { + Node *E = getDerived().parseBracedExpr(); + if (E == nullptr) + return nullptr; + Names.push_back(E); + } + return make<InitListExpr>(Ty, popTrailingNodeArray(InitsBegin)); } - - if (consumeIf("u8__uuidofz")) { + if (consumeIf("tr")) + return make<NameType>("throw"); + if (consumeIf("tw")) { Node *Ex = getDerived().parseExpr(); - if (!Ex) + if (Ex == nullptr) return nullptr; - return make<UUIDOfExpr>(Ex); + return make<ThrowExpr>(Ex); + } + if (consumeIf('u')) { + Node *Name = getDerived().parseSourceName(/*NameState=*/nullptr); + if (!Name) + return nullptr; + // Special case legacy __uuidof mangling. The 't' and 'z' appear where the + // standard encoding expects a <template-arg>, and would be otherwise be + // interpreted as <type> node 'short' or 'ellipsis'. However, neither + // __uuidof(short) nor __uuidof(...) can actually appear, so there is no + // actual conflict here. + bool IsUUID = false; + Node *UUID = nullptr; + if (Name->getBaseName() == "__uuidof") { + if (consumeIf('t')) { + UUID = getDerived().parseType(); + IsUUID = true; + } else if (consumeIf('z')) { + UUID = getDerived().parseExpr(); + IsUUID = true; + } + } + size_t ExprsBegin = Names.size(); + if (IsUUID) { + if (UUID == nullptr) + return nullptr; + Names.push_back(UUID); + } else { + while (!consumeIf('E')) { + Node *E = getDerived().parseTemplateArg(); + if (E == nullptr) + return E; + Names.push_back(E); + } + } + return make<CallExpr>(Name, popTrailingNodeArray(ExprsBegin), + Node::Prec::Postfix); } - return nullptr; + // Only unresolved names remain. + return getDerived().parseUnresolvedName(Global); } // <call-offset> ::= h <nv-offset> _ @@ -4986,19 +4869,32 @@ bool AbstractManglingParser<Alloc, Derived>::parseCallOffset() { // # second call-offset is result adjustment // ::= T <call-offset> <base encoding> // # base is the nominal target function of thunk -// ::= GV <object name> # Guard variable for one-time initialization +// # Guard variable for one-time initialization +// ::= GV <object name> // # No <type> // ::= TW <object name> # Thread-local wrapper // ::= TH <object name> # Thread-local initialization // ::= GR <object name> _ # First temporary // ::= GR <object name> <seq-id> _ # Subsequent temporaries -// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first +// # construction vtable for second-in-first +// extension ::= TC <first type> <number> _ <second type> // extension ::= GR <object name> # reference temporary for object +// extension ::= GI <module name> # module global initializer template <typename Derived, typename Alloc> Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() { switch (look()) { case 'T': switch (look(1)) { + // TA <template-arg> # template parameter object + // + // Not yet in the spec: https://github.com/itanium-cxx-abi/cxx-abi/issues/63 + case 'A': { + First += 2; + Node *Arg = getDerived().parseTemplateArg(); + if (Arg == nullptr) + return nullptr; + return make<SpecialName>("template parameter object for ", Arg); + } // TV <type> # virtual table case 'V': { First += 2; @@ -5110,6 +5006,16 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() { return nullptr; return make<SpecialName>("reference temporary for ", Name); } + // GI <module-name> v + case 'I': { + First += 2; + ModuleName *Module = nullptr; + if (getDerived().parseModuleNameOpt(Module)) + return nullptr; + if (Module == nullptr) + return nullptr; + return make<SpecialName>("initializer for module ", Module); + } } } return nullptr; @@ -5120,6 +5026,26 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSpecialName() { // ::= <special-name> template <typename Derived, typename Alloc> Node *AbstractManglingParser<Derived, Alloc>::parseEncoding() { + // The template parameters of an encoding are unrelated to those of the + // enclosing context. + class SaveTemplateParams { + AbstractManglingParser *Parser; + decltype(TemplateParams) OldParams; + decltype(OuterTemplateParams) OldOuterParams; + + public: + SaveTemplateParams(AbstractManglingParser *TheParser) : Parser(TheParser) { + OldParams = std::move(Parser->TemplateParams); + OldOuterParams = std::move(Parser->OuterTemplateParams); + Parser->TemplateParams.clear(); + Parser->OuterTemplateParams.clear(); + } + ~SaveTemplateParams() { + Parser->TemplateParams = std::move(OldParams); + Parser->OuterTemplateParams = std::move(OldOuterParams); + } + } SaveTemplateParams(this); + if (look() == 'G' || look() == 'T') return getDerived().parseSpecialName(); @@ -5204,14 +5130,19 @@ template <> struct FloatData<long double> { #if defined(__mips__) && defined(__mips_n64) || defined(__aarch64__) || \ - defined(__wasm__) + defined(__wasm__) || defined(__riscv) || defined(__loongarch__) static const size_t mangled_size = 32; #elif defined(__arm__) || defined(__mips__) || defined(__hexagon__) static const size_t mangled_size = 16; #else static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms #endif - static const size_t max_demangled_size = 40; + // `-0x1.ffffffffffffffffffffffffffffp+16383` + 'L' + '\0' == 42 bytes. + // 28 'f's * 4 bits == 112 bits, which is the number of mantissa bits. + // Negatives are one character longer than positives. + // `0x1.` and `p` are constant, and exponents `+16383` and `-16382` are the + // same length. 1 sign bit, 112 mantissa bits, and 15 exponent bits == 128. + static const size_t max_demangled_size = 42; static constexpr const char *spec = "%LaL"; }; @@ -5221,7 +5152,7 @@ Node *AbstractManglingParser<Alloc, Derived>::parseFloatingLiteral() { const size_t N = FloatData<Float>::mangled_size; if (numLeft() <= N) return nullptr; - StringView Data(First, First + N); + std::string_view Data(First, N); for (char C : Data) if (!std::isxdigit(C)) return nullptr; @@ -5264,43 +5195,41 @@ bool AbstractManglingParser<Alloc, Derived>::parseSeqId(size_t *Out) { // <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> > // <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> > // <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > +// The St case is handled specially in parseNestedName. template <typename Derived, typename Alloc> Node *AbstractManglingParser<Derived, Alloc>::parseSubstitution() { if (!consumeIf('S')) return nullptr; - if (std::islower(look())) { - Node *SpecialSub; + if (look() >= 'a' && look() <= 'z') { + SpecialSubKind Kind; switch (look()) { case 'a': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::allocator); + Kind = SpecialSubKind::allocator; break; case 'b': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::basic_string); + Kind = SpecialSubKind::basic_string; break; - case 's': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::string); + case 'd': + Kind = SpecialSubKind::iostream; break; case 'i': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::istream); + Kind = SpecialSubKind::istream; break; case 'o': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::ostream); + Kind = SpecialSubKind::ostream; break; - case 'd': - ++First; - SpecialSub = make<SpecialSubstitution>(SpecialSubKind::iostream); + case 's': + Kind = SpecialSubKind::string; break; default: return nullptr; } + ++First; + auto *SpecialSub = make<SpecialSubstitution>(Kind); if (!SpecialSub) return nullptr; + // Itanium C++ ABI 5.1.2: If a name that would use a built-in <substitution> // has ABI tags, the tags are appended to the substitution; the result is a // substitutable component. @@ -5543,7 +5472,8 @@ Node *AbstractManglingParser<Derived, Alloc>::parse() { if (Encoding == nullptr) return nullptr; if (look() == '.') { - Encoding = make<DotSuffix>(Encoding, StringView(First, Last)); + Encoding = + make<DotSuffix>(Encoding, std::string_view(First, Last - First)); First = Last; } if (numLeft() != 0) diff --git a/externals/demangle/llvm/Demangle/ItaniumNodes.def b/externals/demangle/llvm/Demangle/ItaniumNodes.def new file mode 100644 index 000000000..5985769ef --- /dev/null +++ b/externals/demangle/llvm/Demangle/ItaniumNodes.def @@ -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 diff --git a/externals/demangle/llvm/Demangle/StringView.h b/externals/demangle/llvm/Demangle/StringView.h index 44d2b18a3..76b215252 100644 --- a/externals/demangle/llvm/Demangle/StringView.h +++ b/externals/demangle/llvm/Demangle/StringView.h @@ -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. // See https://llvm.org/LICENSE.txt for license information. // SPDX-FileCopyrightText: Part of the LLVM Project @@ -8,6 +8,9 @@ //===----------------------------------------------------------------------===// // // 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 #include "DemangleConfig.h" -#include <algorithm> #include <cassert> #include <cstring> @@ -37,29 +39,23 @@ public: StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {} StringView() : First(nullptr), Last(nullptr) {} - StringView substr(size_t From) const { - return StringView(begin() + From, size() - From); + StringView substr(size_t Pos, size_t Len = npos) const { + 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 FindBegin = std::min(From, size()); // Avoid calling memchr with nullptr. - if (FindBegin < size()) { + if (From < size()) { // 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 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 { if (N >= size()) N = size(); @@ -106,7 +102,7 @@ public: bool startsWith(StringView Str) const { if (Str.size() > size()) 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); } @@ -119,7 +115,7 @@ public: inline bool operator==(const StringView &LHS, const StringView &RHS) { 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 diff --git a/externals/demangle/llvm/Demangle/StringViewExtras.h b/externals/demangle/llvm/Demangle/StringViewExtras.h new file mode 100644 index 000000000..83685c304 --- /dev/null +++ b/externals/demangle/llvm/Demangle/StringViewExtras.h @@ -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 diff --git a/externals/demangle/llvm/Demangle/Utility.h b/externals/demangle/llvm/Demangle/Utility.h index 50d05c6b1..30dfbfc8d 100644 --- a/externals/demangle/llvm/Demangle/Utility.h +++ b/externals/demangle/llvm/Demangle/Utility.h @@ -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. // See https://llvm.org/LICENSE.txt for license information. // 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 #define DEMANGLE_UTILITY_H -#include "StringView.h" +#include "DemangleConfig.h" + +#include <array> +#include <cassert> #include <cstdint> #include <cstdlib> #include <cstring> -#include <iterator> +#include <exception> #include <limits> +#include <string_view> DEMANGLE_NAMESPACE_BEGIN // Stream that AST nodes write their string representation into after the AST // has been parsed. -class OutputStream { - char *Buffer; - size_t CurrentPosition; - size_t BufferCapacity; +class OutputBuffer { + char *Buffer = nullptr; + size_t CurrentPosition = 0; + 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) { - 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; - if (BufferCapacity < N + CurrentPosition) - BufferCapacity = N + CurrentPosition; + if (BufferCapacity < Need) + BufferCapacity = Need; Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity)); if (Buffer == nullptr) std::terminate(); } } - void writeUnsigned(uint64_t N, bool isNeg = false) { - // Handle special case... - if (N == 0) { - *this << '0'; - return; - } - - char Temp[21]; - char *TempPtr = std::end(Temp); + OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) { + std::array<char, 21> Temp; + char *TempPtr = Temp.data() + Temp.size(); - while (N) { - *--TempPtr = '0' + char(N % 10); + // Output at least one character. + do { + *--TempPtr = char('0' + N % 10); N /= 10; - } + } while (N); - // Add negative sign... + // Add negative sign. if (isNeg) *--TempPtr = '-'; - this->operator<<(StringView(TempPtr, std::end(Temp))); + + return operator+=( + std::string_view(TempPtr, Temp.data() + Temp.size() - TempPtr)); } public: - OutputStream(char *StartBuf, size_t Size) - : Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {} - OutputStream() = default; - void reset(char *Buffer_, size_t BufferCapacity_) { - CurrentPosition = 0; - Buffer = Buffer_; - BufferCapacity = BufferCapacity_; + OutputBuffer(char *StartBuf, size_t Size) + : Buffer(StartBuf), BufferCapacity(Size) {} + OutputBuffer(char *StartBuf, size_t *SizePtr) + : OutputBuffer(StartBuf, StartBuf ? *SizePtr : 0) {} + OutputBuffer() = default; + // Non-copyable + 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 @@ -78,115 +91,116 @@ public: unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max(); unsigned CurrentPackMax = std::numeric_limits<unsigned>::max(); - OutputStream &operator+=(StringView R) { - size_t Size = R.size(); - if (Size == 0) - return *this; - grow(Size); - std::memmove(Buffer + CurrentPosition, R.begin(), Size); - CurrentPosition += Size; + /// When zero, we're printing template args and '>' needs to be parenthesized. + /// Use a counter so we can simply increment inside parentheses. + unsigned GtIsGt = 1; + + bool isGtInsideTemplateArgs() const { return GtIsGt == 0; } + + 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; } - OutputStream &operator+=(char C) { + OutputBuffer &operator+=(char C) { grow(1); Buffer[CurrentPosition++] = C; 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; } - OutputStream &operator<<(unsigned long long N) { - writeUnsigned(N, false); - return *this; + OutputBuffer &operator<<(std::string_view R) { return (*this += R); } + + 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)); } - OutputStream &operator<<(unsigned long N) { + OutputBuffer &operator<<(unsigned 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)); } - OutputStream &operator<<(unsigned int N) { + OutputBuffer &operator<<(unsigned int 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; } void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; } char back() const { - return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0'; + assert(CurrentPosition); + return Buffer[CurrentPosition - 1]; } bool empty() const { return CurrentPosition == 0; } char *getBuffer() { return Buffer; } char *getBufferEnd() { return Buffer + CurrentPosition - 1; } - size_t getBufferCapacity() { return BufferCapacity; } + size_t getBufferCapacity() const { return BufferCapacity; } }; -template <class T> class SwapAndRestore { - T &Restore; - T OriginalValue; - bool ShouldRestore = true; +template <class T> class ScopedOverride { + T &Loc; + T Original; public: - SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {} - - SwapAndRestore(T &Restore_, T NewVal) - : Restore(Restore_), OriginalValue(Restore) { - Restore = std::move(NewVal); - } - ~SwapAndRestore() { - if (ShouldRestore) - Restore = std::move(OriginalValue); - } + ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {} - void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; } - - void restoreNow(bool Force) { - if (!Force && !ShouldRestore) - return; - - Restore = std::move(OriginalValue); - ShouldRestore = false; + ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) { + Loc_ = std::move(NewVal); } + ~ScopedOverride() { Loc = std::move(Original); } - SwapAndRestore(const SwapAndRestore &) = delete; - SwapAndRestore &operator=(const SwapAndRestore &) = delete; + ScopedOverride(const ScopedOverride &) = delete; + ScopedOverride &operator=(const ScopedOverride &) = 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 #endif diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 8bc6a4a04..c23b2f19e 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -449,7 +449,7 @@ private: loader->ReadTitle(entry.title); loader->ReadIcon(entry.icon); if (loader->GetFileType() == Loader::FileType::NRO) { - jauto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get()); + jauto loader_nro = reinterpret_cast<Loader::AppLoader_NRO*>(loader.get()); entry.isHomebrew = loader_nro->IsHomebrew(); } else { entry.isHomebrew = false; diff --git a/src/common/demangle.cpp b/src/common/demangle.cpp index 3310faf86..6e117cb41 100644 --- a/src/common/demangle.cpp +++ b/src/common/demangle.cpp @@ -23,7 +23,7 @@ std::string DemangleSymbol(const std::string& mangled) { SCOPE_EXIT({ std::free(demangled); }); if (is_itanium(mangled)) { - demangled = llvm::itaniumDemangle(mangled.c_str(), nullptr, nullptr, nullptr); + demangled = llvm::itaniumDemangle(mangled.c_str()); } if (!demangled) { diff --git a/src/common/detached_tasks.cpp b/src/common/detached_tasks.cpp index da64848da..f2ed795cc 100644 --- a/src/common/detached_tasks.cpp +++ b/src/common/detached_tasks.cpp @@ -30,8 +30,8 @@ DetachedTasks::~DetachedTasks() { void DetachedTasks::AddTask(std::function<void()> task) { std::unique_lock lock{instance->mutex}; ++instance->count; - std::thread([task{std::move(task)}]() { - task(); + std::thread([task_{std::move(task)}]() { + task_(); std::unique_lock thread_lock{instance->mutex}; --instance->count; std::notify_all_at_thread_exit(instance->cv, std::move(thread_lock)); diff --git a/src/common/page_table.h b/src/common/page_table.h index fec8378f3..e653d52ad 100644 --- a/src/common/page_table.h +++ b/src/common/page_table.h @@ -51,7 +51,7 @@ struct PageTable { class PageInfo { public: /// Returns the page pointer - [[nodiscard]] u8* Pointer() const noexcept { + [[nodiscard]] uintptr_t Pointer() const noexcept { return ExtractPointer(raw.load(std::memory_order_relaxed)); } @@ -61,7 +61,7 @@ struct PageTable { } /// Returns the page pointer and attribute pair, extracted from the same atomic read - [[nodiscard]] std::pair<u8*, PageType> PointerType() const noexcept { + [[nodiscard]] std::pair<uintptr_t, PageType> PointerType() const noexcept { const uintptr_t non_atomic_raw = raw.load(std::memory_order_relaxed); return {ExtractPointer(non_atomic_raw), ExtractType(non_atomic_raw)}; } @@ -73,13 +73,13 @@ struct PageTable { } /// Write a page pointer and type pair atomically - void Store(u8* pointer, PageType type) noexcept { - raw.store(reinterpret_cast<uintptr_t>(pointer) | static_cast<uintptr_t>(type)); + void Store(uintptr_t pointer, PageType type) noexcept { + raw.store(pointer | static_cast<uintptr_t>(type)); } /// Unpack a pointer from a page info raw representation - [[nodiscard]] static u8* ExtractPointer(uintptr_t raw) noexcept { - return reinterpret_cast<u8*>(raw & (~uintptr_t{0} << ATTRIBUTE_BITS)); + [[nodiscard]] static uintptr_t ExtractPointer(uintptr_t raw) noexcept { + return raw & (~uintptr_t{0} << ATTRIBUTE_BITS); } /// Unpack a page type from a page info raw representation diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 5972480e5..d4e55f988 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -26,7 +26,8 @@ std::string GetTimeZoneString() { std::string location_name; if (time_zone_index == 0) { // Auto -#if __cpp_lib_chrono >= 201907L +#if __cpp_lib_chrono >= 201907L && !defined(MINGW) + // Disabled for MinGW -- tzdb always returns Etc/UTC try { const struct std::chrono::tzdb& time_zone_data = std::chrono::get_tzdb(); const std::chrono::time_zone* current_zone = time_zone_data.current_zone(); diff --git a/src/common/time_zone.cpp b/src/common/time_zone.cpp index d8d7896c6..69e728a9d 100644 --- a/src/common/time_zone.cpp +++ b/src/common/time_zone.cpp @@ -4,13 +4,13 @@ #include <chrono> #include <exception> #include <iomanip> +#include <map> #include <sstream> #include <stdexcept> #include <fmt/chrono.h> #include <fmt/core.h> #include "common/logging/log.h" -#include "common/settings.h" #include "common/time_zone.h" namespace Common::TimeZone { @@ -33,32 +33,29 @@ std::string GetDefaultTimeZone() { return "GMT"; } -static std::string GetOsTimeZoneOffset() { - const std::time_t t{std::time(nullptr)}; - const std::tm tm{*std::localtime(&t)}; - - return fmt::format("{:%z}", tm); -} - -static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) { - try { - return std::stoi(timezone); - } catch (const std::invalid_argument&) { - LOG_CRITICAL(Common, "invalid_argument with {}!", timezone); - return 0; - } catch (const std::out_of_range&) { - LOG_CRITICAL(Common, "out_of_range with {}!", timezone); - return 0; - } +// Results are not comparable to seconds since Epoch +static std::time_t TmSpecToSeconds(const struct std::tm& spec) { + const int year = spec.tm_year - 1; // Years up to now + const int leap_years = year / 4 - year / 100; + std::time_t cumulative = spec.tm_year; + cumulative = cumulative * 365 + leap_years + spec.tm_yday; // Years to days + cumulative = cumulative * 24 + spec.tm_hour; // Days to hours + cumulative = cumulative * 60 + spec.tm_min; // Hours to minutes + cumulative = cumulative * 60 + spec.tm_sec; // Minutes to seconds + return cumulative; } std::chrono::seconds GetCurrentOffsetSeconds() { - const int offset{ConvertOsTimeZoneOffsetToInt(GetOsTimeZoneOffset())}; + const std::time_t t{std::time(nullptr)}; + const std::tm local{*std::localtime(&t)}; + const std::tm gmt{*std::gmtime(&t)}; - int seconds{(offset / 100) * 60 * 60}; // Convert hour component to seconds - seconds += (offset % 100) * 60; // Convert minute component to seconds + // gmt_seconds is a different offset than time(nullptr) + const auto gmt_seconds = TmSpecToSeconds(gmt); + const auto local_seconds = TmSpecToSeconds(local); + const auto seconds_offset = local_seconds - gmt_seconds; - return std::chrono::seconds{seconds}; + return std::chrono::seconds{seconds_offset}; } // Key is [Hours * 100 + Minutes], multiplied by 100 if DST @@ -71,11 +68,6 @@ const static std::map<s64, const char*> off_timezones = { }; std::string FindSystemTimeZone() { -#if defined(MINGW) - // MinGW has broken strftime -- https://sourceforge.net/p/mingw-w64/bugs/793/ - // e.g. fmt::format("{:%z}") -- returns "Eastern Daylight Time" when it should be "-0400" - return timezones[0]; -#else const s64 seconds = static_cast<s64>(GetCurrentOffsetSeconds().count()); const s64 minutes = seconds / 60; @@ -97,7 +89,6 @@ std::string FindSystemTimeZone() { } } return fmt::format("Etc/GMT{:s}{:d}", hours > 0 ? "-" : "+", std::abs(hours)); -#endif } } // namespace Common::TimeZone diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index aa0eb9791..0c012f094 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -217,8 +217,8 @@ void ARM_Interface::Run() { } } -void ARM_Interface::LoadWatchpointArray(const WatchpointArray& wp) { - watchpoints = ℘ +void ARM_Interface::LoadWatchpointArray(const WatchpointArray* wp) { + watchpoints = wp; } const Kernel::DebugWatchpoint* ARM_Interface::MatchingWatchpoint( diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index d5f2fa09a..3d866ff6f 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -186,7 +186,7 @@ public: virtual void SaveContext(ThreadContext64& ctx) const = 0; virtual void LoadContext(const ThreadContext32& ctx) = 0; virtual void LoadContext(const ThreadContext64& ctx) = 0; - void LoadWatchpointArray(const WatchpointArray& wp); + void LoadWatchpointArray(const WatchpointArray* wp); /// Clears the exclusive monitor's state. virtual void ClearExclusiveState() = 0; diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 3b82fb73c..c97158a71 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -346,11 +346,11 @@ void ARM_Dynarmic_32::RewindBreakpointInstruction() { } ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, - ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_) + DynarmicExclusiveMonitor& exclusive_monitor_, + std::size_t core_index_) : ARM_Interface{system_, uses_wall_clock_}, cb(std::make_unique<DynarmicCallbacks32>(*this)), cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_}, - exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)}, - null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {} + exclusive_monitor{exclusive_monitor_}, null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {} ARM_Dynarmic_32::~ARM_Dynarmic_32() = default; diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index a990845cb..92fb3f836 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -12,7 +12,7 @@ #include "common/common_types.h" #include "common/hash.h" #include "core/arm/arm_interface.h" -#include "core/arm/exclusive_monitor.h" +#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" namespace Core::Memory { class Memory; @@ -28,8 +28,8 @@ class System; class ARM_Dynarmic_32 final : public ARM_Interface { public: - ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, - std::size_t core_index_); + ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, + DynarmicExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); ~ARM_Dynarmic_32() override; void SetPC(u64 pc) override; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index bb97ed5bc..791d466ca 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -405,11 +405,11 @@ void ARM_Dynarmic_64::RewindBreakpointInstruction() { } ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, - ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_) + DynarmicExclusiveMonitor& exclusive_monitor_, + std::size_t core_index_) : ARM_Interface{system_, uses_wall_clock_}, cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_}, - exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)}, - null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {} + exclusive_monitor{exclusive_monitor_}, null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {} ARM_Dynarmic_64::~ARM_Dynarmic_64() = default; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index af2aa1f1c..2b88a08e2 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -11,7 +11,7 @@ #include "common/common_types.h" #include "common/hash.h" #include "core/arm/arm_interface.h" -#include "core/arm/exclusive_monitor.h" +#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" namespace Core::Memory { class Memory; @@ -25,8 +25,8 @@ class System; class ARM_Dynarmic_64 final : public ARM_Interface { public: - ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, - std::size_t core_index_); + ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, + DynarmicExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); ~ARM_Dynarmic_64() override; void SetPC(u64 pc) override; diff --git a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h index 57e6dd0d0..fbfcd8d95 100644 --- a/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h +++ b/src/core/arm/dynarmic/dynarmic_exclusive_monitor.h @@ -6,8 +6,6 @@ #include <dynarmic/interface/exclusive_monitor.h> #include "common/common_types.h" -#include "core/arm/dynarmic/arm_dynarmic_32.h" -#include "core/arm/dynarmic/arm_dynarmic_64.h" #include "core/arm/exclusive_monitor.h" namespace Core::Memory { @@ -16,6 +14,9 @@ class Memory; namespace Core { +class ARM_Dynarmic_32; +class ARM_Dynarmic_64; + class DynarmicExclusiveMonitor final : public ExclusiveMonitor { public: explicit DynarmicExclusiveMonitor(Memory::Memory& memory_, std::size_t core_count_); diff --git a/src/core/core.cpp b/src/core/core.cpp index 9e3eb3795..48233d7c8 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -880,6 +880,14 @@ const FileSys::ContentProvider& System::GetContentProvider() const { return *impl->content_provider; } +FileSys::ContentProviderUnion& System::GetContentProviderUnion() { + return *impl->content_provider; +} + +const FileSys::ContentProviderUnion& System::GetContentProviderUnion() const { + return *impl->content_provider; +} + Service::FileSystem::FileSystemController& System::GetFileSystemController() { return impl->fs_controller; } diff --git a/src/core/core.h b/src/core/core.h index 14b2f7785..c70ea1965 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -381,6 +381,9 @@ public: [[nodiscard]] FileSys::ContentProvider& GetContentProvider(); [[nodiscard]] const FileSys::ContentProvider& GetContentProvider() const; + [[nodiscard]] FileSys::ContentProviderUnion& GetContentProviderUnion(); + [[nodiscard]] const FileSys::ContentProviderUnion& GetContentProviderUnion() const; + [[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController(); [[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const; diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index e2a13bbd2..0f839d5b4 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp @@ -261,10 +261,8 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction const size_t addr{static_cast<size_t>(strtoll(command.data(), nullptr, 16))}; const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))}; - if (system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { - std::vector<u8> mem(size); - system.ApplicationMemory().ReadBlock(addr, mem.data(), size); - + std::vector<u8> mem(size); + if (system.ApplicationMemory().ReadBlock(addr, mem.data(), size)) { SendReply(Common::HexToString(mem)); } else { SendReply(GDB_STUB_REPLY_ERR); @@ -281,8 +279,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction const auto mem_substr{std::string_view(command).substr(mem_sep)}; const auto mem{Common::HexStringToVector(mem_substr, false)}; - if (system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { - system.ApplicationMemory().WriteBlock(addr, mem.data(), size); + if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) { system.InvalidateCpuInstructionCacheRange(addr, size); SendReply(GDB_STUB_REPLY_OK); } else { @@ -556,7 +553,7 @@ void GDBStub::HandleQuery(std::string_view command) { } else { SendReply(fmt::format( "TextSeg={:x}", - GetInteger(system.ApplicationProcess()->PageTable().GetCodeRegionStart()))); + GetInteger(system.ApplicationProcess()->GetPageTable().GetCodeRegionStart()))); } } else if (command.starts_with("Xfer:libraries:read::")) { Loader::AppLoader::Modules modules; @@ -731,7 +728,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { std::string reply; auto* process = system.ApplicationProcess(); - auto& page_table = process->PageTable(); + auto& page_table = process->GetPageTable(); const char* commands = "Commands:\n" " get fastmem\n" diff --git a/src/core/hle/kernel/k_auto_object.cpp b/src/core/hle/kernel/k_auto_object.cpp index 0ae42c95c..9cd7a9fd5 100644 --- a/src/core/hle/kernel/k_auto_object.cpp +++ b/src/core/hle/kernel/k_auto_object.cpp @@ -15,8 +15,8 @@ void KAutoObject::RegisterWithKernel() { m_kernel.RegisterKernelObject(this); } -void KAutoObject::UnregisterWithKernel() { - m_kernel.UnregisterKernelObject(this); +void KAutoObject::UnregisterWithKernel(KernelCore& kernel, KAutoObject* self) { + kernel.UnregisterKernelObject(self); } } // namespace Kernel diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h index f384b1568..8d4e0df44 100644 --- a/src/core/hle/kernel/k_auto_object.h +++ b/src/core/hle/kernel/k_auto_object.h @@ -159,14 +159,15 @@ public: // If ref count hits zero, destroy the object. if (cur_ref_count - 1 == 0) { + KernelCore& kernel = m_kernel; this->Destroy(); - this->UnregisterWithKernel(); + KAutoObject::UnregisterWithKernel(kernel, this); } } private: void RegisterWithKernel(); - void UnregisterWithKernel(); + static void UnregisterWithKernel(KernelCore& kernel, KAutoObject* self); protected: KernelCore& m_kernel; diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp index 3583bee44..7454be55c 100644 --- a/src/core/hle/kernel/k_code_memory.cpp +++ b/src/core/hle/kernel/k_code_memory.cpp @@ -25,7 +25,7 @@ Result KCodeMemory::Initialize(Core::DeviceMemory& device_memory, KProcessAddres m_owner = GetCurrentProcessPointer(m_kernel); // Get the owner page table. - auto& page_table = m_owner->PageTable(); + auto& page_table = m_owner->GetPageTable(); // Construct the page group. m_page_group.emplace(m_kernel, page_table.GetBlockInfoManager()); @@ -53,7 +53,7 @@ void KCodeMemory::Finalize() { // Unlock. if (!m_is_mapped && !m_is_owner_mapped) { const size_t size = m_page_group->GetNumPages() * PageSize; - m_owner->PageTable().UnlockForCodeMemory(m_address, size, *m_page_group); + m_owner->GetPageTable().UnlockForCodeMemory(m_address, size, *m_page_group); } // Close the page group. @@ -75,7 +75,7 @@ Result KCodeMemory::Map(KProcessAddress address, size_t size) { R_UNLESS(!m_is_mapped, ResultInvalidState); // Map the memory. - R_TRY(GetCurrentProcess(m_kernel).PageTable().MapPageGroup( + R_TRY(GetCurrentProcess(m_kernel).GetPageTable().MapPageGroup( address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite)); // Mark ourselves as mapped. @@ -92,8 +92,8 @@ Result KCodeMemory::Unmap(KProcessAddress address, size_t size) { KScopedLightLock lk(m_lock); // Unmap the memory. - R_TRY(GetCurrentProcess(m_kernel).PageTable().UnmapPageGroup(address, *m_page_group, - KMemoryState::CodeOut)); + R_TRY(GetCurrentProcess(m_kernel).GetPageTable().UnmapPageGroup(address, *m_page_group, + KMemoryState::CodeOut)); // Mark ourselves as unmapped. m_is_mapped = false; @@ -126,8 +126,8 @@ Result KCodeMemory::MapToOwner(KProcessAddress address, size_t size, Svc::Memory } // Map the memory. - R_TRY(m_owner->PageTable().MapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode, - k_perm)); + R_TRY(m_owner->GetPageTable().MapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode, + k_perm)); // Mark ourselves as mapped. m_is_owner_mapped = true; @@ -143,7 +143,8 @@ Result KCodeMemory::UnmapFromOwner(KProcessAddress address, size_t size) { KScopedLightLock lk(m_lock); // Unmap the memory. - R_TRY(m_owner->PageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode)); + R_TRY(m_owner->GetPageTable().UnmapPageGroup(address, *m_page_group, + KMemoryState::GeneratedCode)); // Mark ourselves as unmapped. m_is_owner_mapped = false; diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 022d15f35..b9e8c6042 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -388,39 +388,6 @@ public: constexpr size_t GetHeapSize() const { return m_current_heap_end - m_heap_region_start; } - constexpr bool IsInsideAddressSpace(KProcessAddress address, size_t size) const { - return m_address_space_start <= address && address + size - 1 <= m_address_space_end - 1; - } - constexpr bool IsOutsideAliasRegion(KProcessAddress address, size_t size) const { - return m_alias_region_start > address || address + size - 1 > m_alias_region_end - 1; - } - constexpr bool IsOutsideStackRegion(KProcessAddress address, size_t size) const { - return m_stack_region_start > address || address + size - 1 > m_stack_region_end - 1; - } - constexpr bool IsInvalidRegion(KProcessAddress address, size_t size) const { - return address + size - 1 > GetAliasCodeRegionStart() + GetAliasCodeRegionSize() - 1; - } - constexpr bool IsInsideHeapRegion(KProcessAddress address, size_t size) const { - return address + size > m_heap_region_start && m_heap_region_end > address; - } - constexpr bool IsInsideAliasRegion(KProcessAddress address, size_t size) const { - return address + size > m_alias_region_start && m_alias_region_end > address; - } - constexpr bool IsOutsideASLRRegion(KProcessAddress address, size_t size) const { - if (IsInvalidRegion(address, size)) { - return true; - } - if (IsInsideHeapRegion(address, size)) { - return true; - } - if (IsInsideAliasRegion(address, size)) { - return true; - } - return {}; - } - constexpr bool IsInsideASLRRegion(KProcessAddress address, size_t size) const { - return !IsOutsideASLRRegion(address, size); - } constexpr size_t GetNumGuardPages() const { return IsKernel() ? 1 : 4; } @@ -436,6 +403,14 @@ public: return m_address_space_start <= addr && addr < addr + size && addr + size - 1 <= m_address_space_end - 1; } + constexpr bool IsInAliasRegion(KProcessAddress addr, size_t size) const { + return this->Contains(addr, size) && m_alias_region_start <= addr && + addr + size - 1 <= m_alias_region_end - 1; + } + constexpr bool IsInHeapRegion(KProcessAddress addr, size_t size) const { + return this->Contains(addr, size) && m_heap_region_start <= addr && + addr + size - 1 <= m_heap_region_end - 1; + } public: static KVirtualAddress GetLinearMappedVirtualAddress(const KMemoryLayout& layout, diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index efe86ad27..44c7cb22f 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -38,7 +38,7 @@ namespace { */ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, KProcessAddress stack_top) { - const KProcessAddress entry_point = owner_process.PageTable().GetCodeRegionStart(); + const KProcessAddress entry_point = owner_process.GetPageTable().GetCodeRegionStart(); ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::ThreadCountMax, 1)); KThread* thread = KThread::Create(system.Kernel()); diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index 925981d06..c9b37e138 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -110,16 +110,6 @@ public: ProcessType type, KResourceLimit* res_limit); /// Gets a reference to the process' page table. - KPageTable& PageTable() { - return m_page_table; - } - - /// Gets const a reference to the process' page table. - const KPageTable& PageTable() const { - return m_page_table; - } - - /// Gets a reference to the process' page table. KPageTable& GetPageTable() { return m_page_table; } diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 75ce5a23c..d8143c650 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -510,11 +510,12 @@ void KScheduler::Unload(KThread* thread) { void KScheduler::Reload(KThread* thread) { auto& cpu_core = m_kernel.System().ArmInterface(m_core_id); + auto* process = thread->GetOwnerProcess(); cpu_core.LoadContext(thread->GetContext32()); cpu_core.LoadContext(thread->GetContext64()); cpu_core.SetTlsAddress(GetInteger(thread->GetTlsAddress())); cpu_core.SetTPIDR_EL0(thread->GetTpidrEl0()); - cpu_core.LoadWatchpointArray(thread->GetOwnerProcess()->GetWatchpoints()); + cpu_core.LoadWatchpointArray(process ? &process->GetWatchpoints() : nullptr); cpu_core.ClearExclusiveState(); } diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp index efb5699de..f713968f6 100644 --- a/src/core/hle/kernel/k_shared_memory.cpp +++ b/src/core/hle/kernel/k_shared_memory.cpp @@ -90,8 +90,8 @@ Result KSharedMemory::Map(KProcess& target_process, KProcessAddress address, std R_UNLESS(map_perm == test_perm, ResultInvalidNewMemoryPermission); } - R_RETURN(target_process.PageTable().MapPageGroup(address, *m_page_group, KMemoryState::Shared, - ConvertToKMemoryPermission(map_perm))); + R_RETURN(target_process.GetPageTable().MapPageGroup( + address, *m_page_group, KMemoryState::Shared, ConvertToKMemoryPermission(map_perm))); } Result KSharedMemory::Unmap(KProcess& target_process, KProcessAddress address, @@ -100,7 +100,7 @@ Result KSharedMemory::Unmap(KProcess& target_process, KProcessAddress address, R_UNLESS(m_size == unmap_size, ResultInvalidSize); R_RETURN( - target_process.PageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::Shared)); + target_process.GetPageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::Shared)); } } // namespace Kernel diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index adb6ec581..7df8fd7f7 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -129,7 +129,7 @@ Result KThread::Initialize(KThreadFunction func, uintptr_t arg, KProcessAddress case ThreadType::User: ASSERT(((owner == nullptr) || (owner->GetCoreMask() | (1ULL << virt_core)) == owner->GetCoreMask())); - ASSERT(((owner == nullptr) || + ASSERT(((owner == nullptr) || (prio > Svc::LowestThreadPriority) || (owner->GetPriorityMask() | (1ULL << prio)) == owner->GetPriorityMask())); break; case ThreadType::Kernel: @@ -302,12 +302,12 @@ Result KThread::InitializeServiceThread(Core::System& system, KThread* thread, std::function<void()>&& func, s32 prio, s32 virt_core, KProcess* owner) { system.Kernel().GlobalSchedulerContext().AddThread(thread); - std::function<void()> func2{[&system, func{std::move(func)}] { + std::function<void()> func2{[&system, func_{std::move(func)}] { // Similar to UserModeThreadStarter. system.Kernel().CurrentScheduler()->OnThreadStart(); // Run the guest function. - func(); + func_(); // Exit. Svc::ExitThread(system); diff --git a/src/core/hle/kernel/k_thread_local_page.cpp b/src/core/hle/kernel/k_thread_local_page.cpp index b4a1e3cdb..2c45b4232 100644 --- a/src/core/hle/kernel/k_thread_local_page.cpp +++ b/src/core/hle/kernel/k_thread_local_page.cpp @@ -25,9 +25,9 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) { // Map the address in. const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf); - R_TRY(m_owner->PageTable().MapPages(std::addressof(m_virt_addr), 1, PageSize, phys_addr, - KMemoryState::ThreadLocal, - KMemoryPermission::UserReadWrite)); + R_TRY(m_owner->GetPageTable().MapPages(std::addressof(m_virt_addr), 1, PageSize, phys_addr, + KMemoryState::ThreadLocal, + KMemoryPermission::UserReadWrite)); // We succeeded. page_buf_guard.Cancel(); @@ -37,11 +37,11 @@ Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) { Result KThreadLocalPage::Finalize() { // Get the physical address of the page. - const KPhysicalAddress phys_addr = m_owner->PageTable().GetPhysicalAddr(m_virt_addr); + const KPhysicalAddress phys_addr = m_owner->GetPageTable().GetPhysicalAddr(m_virt_addr); ASSERT(phys_addr); // Unmap the page. - R_TRY(m_owner->PageTable().UnmapPages(this->GetAddress(), 1, KMemoryState::ThreadLocal)); + R_TRY(m_owner->GetPageTable().UnmapPages(this->GetAddress(), 1, KMemoryState::ThreadLocal)); // Free the page. KPageBuffer::Free(*m_kernel, KPageBuffer::FromPhysicalAddress(m_kernel->System(), phys_addr)); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f33600ca5..ebe7582c6 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -1089,15 +1089,15 @@ static std::jthread RunHostThreadFunc(KernelCore& kernel, KProcess* process, KThread::Register(kernel, thread); return std::jthread( - [&kernel, thread, thread_name{std::move(thread_name)}, func{std::move(func)}] { + [&kernel, thread, thread_name_{std::move(thread_name)}, func_{std::move(func)}] { // Set the thread name. - Common::SetCurrentThreadName(thread_name.c_str()); + Common::SetCurrentThreadName(thread_name_.c_str()); // Set the thread as current. kernel.RegisterHostThread(thread); // Run the callback. - func(); + func_(); // Close the thread. // This will free the process if it is the last reference. diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 2e0c36129..5ee869fa2 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -17,7 +17,9 @@ PhysicalCore::PhysicalCore(std::size_t core_index, Core::System& system, KSchedu // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager. auto& kernel = system.Kernel(); m_arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( - system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), m_core_index); + system, kernel.IsMulticore(), + reinterpret_cast<Core::DynarmicExclusiveMonitor&>(kernel.GetExclusiveMonitor()), + m_core_index); #else #error Platform not supported yet. #endif @@ -31,7 +33,9 @@ void PhysicalCore::Initialize(bool is_64_bit) { if (!is_64_bit) { // We already initialized a 64-bit core, replace with a 32-bit one. m_arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( - m_system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), m_core_index); + m_system, kernel.IsMulticore(), + reinterpret_cast<Core::DynarmicExclusiveMonitor&>(kernel.GetExclusiveMonitor()), + m_core_index); } #else #error Platform not supported yet. diff --git a/src/core/hle/kernel/svc/svc_cache.cpp b/src/core/hle/kernel/svc/svc_cache.cpp index 082942dab..c2c8be10f 100644 --- a/src/core/hle/kernel/svc/svc_cache.cpp +++ b/src/core/hle/kernel/svc/svc_cache.cpp @@ -42,7 +42,7 @@ Result FlushProcessDataCache(Core::System& system, Handle process_handle, u64 ad R_UNLESS(process.IsNotNull(), ResultInvalidHandle); // Verify the region is within range. - auto& page_table = process->PageTable(); + auto& page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); // Perform the operation. diff --git a/src/core/hle/kernel/svc/svc_code_memory.cpp b/src/core/hle/kernel/svc/svc_code_memory.cpp index 687baff82..bae4cb0cd 100644 --- a/src/core/hle/kernel/svc/svc_code_memory.cpp +++ b/src/core/hle/kernel/svc/svc_code_memory.cpp @@ -48,7 +48,7 @@ Result CreateCodeMemory(Core::System& system, Handle* out, u64 address, uint64_t SCOPE_EXIT({ code_mem->Close(); }); // Verify that the region is in range. - R_UNLESS(GetCurrentProcess(system.Kernel()).PageTable().Contains(address, size), + R_UNLESS(GetCurrentProcess(system.Kernel()).GetPageTable().Contains(address, size), ResultInvalidCurrentMemory); // Initialize the code memory. @@ -92,7 +92,7 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, case CodeMemoryOperation::Map: { // Check that the region is in range. R_UNLESS(GetCurrentProcess(system.Kernel()) - .PageTable() + .GetPageTable() .CanContain(address, size, KMemoryState::CodeOut), ResultInvalidMemoryRegion); @@ -105,7 +105,7 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, case CodeMemoryOperation::Unmap: { // Check that the region is in range. R_UNLESS(GetCurrentProcess(system.Kernel()) - .PageTable() + .GetPageTable() .CanContain(address, size, KMemoryState::CodeOut), ResultInvalidMemoryRegion); @@ -117,8 +117,8 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, } break; case CodeMemoryOperation::MapToOwner: { // Check that the region is in range. - R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size, - KMemoryState::GeneratedCode), + R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size, + KMemoryState::GeneratedCode), ResultInvalidMemoryRegion); // Check the memory permission. @@ -129,8 +129,8 @@ Result ControlCodeMemory(Core::System& system, Handle code_memory_handle, } break; case CodeMemoryOperation::UnmapFromOwner: { // Check that the region is in range. - R_UNLESS(code_mem->GetOwner()->PageTable().CanContain(address, size, - KMemoryState::GeneratedCode), + R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size, + KMemoryState::GeneratedCode), ResultInvalidMemoryRegion); // Check the memory permission. diff --git a/src/core/hle/kernel/svc/svc_device_address_space.cpp b/src/core/hle/kernel/svc/svc_device_address_space.cpp index ec3143e67..42add9473 100644 --- a/src/core/hle/kernel/svc/svc_device_address_space.cpp +++ b/src/core/hle/kernel/svc/svc_device_address_space.cpp @@ -107,7 +107,7 @@ Result MapDeviceAddressSpaceByForce(Core::System& system, Handle das_handle, Han R_UNLESS(process.IsNotNull(), ResultInvalidHandle); // Validate that the process address is within range. - auto& page_table = process->PageTable(); + auto& page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory); // Map. @@ -148,7 +148,7 @@ Result MapDeviceAddressSpaceAligned(Core::System& system, Handle das_handle, Han R_UNLESS(process.IsNotNull(), ResultInvalidHandle); // Validate that the process address is within range. - auto& page_table = process->PageTable(); + auto& page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory); // Map. @@ -180,7 +180,7 @@ Result UnmapDeviceAddressSpace(Core::System& system, Handle das_handle, Handle p R_UNLESS(process.IsNotNull(), ResultInvalidHandle); // Validate that the process address is within range. - auto& page_table = process->PageTable(); + auto& page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(process_address, size), ResultInvalidCurrentMemory); R_RETURN(das->Unmap(std::addressof(page_table), process_address, size, device_address)); diff --git a/src/core/hle/kernel/svc/svc_info.cpp b/src/core/hle/kernel/svc/svc_info.cpp index 445cdd87b..f99964028 100644 --- a/src/core/hle/kernel/svc/svc_info.cpp +++ b/src/core/hle/kernel/svc/svc_info.cpp @@ -54,35 +54,35 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle R_SUCCEED(); case InfoType::AliasRegionAddress: - *result = GetInteger(process->PageTable().GetAliasRegionStart()); + *result = GetInteger(process->GetPageTable().GetAliasRegionStart()); R_SUCCEED(); case InfoType::AliasRegionSize: - *result = process->PageTable().GetAliasRegionSize(); + *result = process->GetPageTable().GetAliasRegionSize(); R_SUCCEED(); case InfoType::HeapRegionAddress: - *result = GetInteger(process->PageTable().GetHeapRegionStart()); + *result = GetInteger(process->GetPageTable().GetHeapRegionStart()); R_SUCCEED(); case InfoType::HeapRegionSize: - *result = process->PageTable().GetHeapRegionSize(); + *result = process->GetPageTable().GetHeapRegionSize(); R_SUCCEED(); case InfoType::AslrRegionAddress: - *result = GetInteger(process->PageTable().GetAliasCodeRegionStart()); + *result = GetInteger(process->GetPageTable().GetAliasCodeRegionStart()); R_SUCCEED(); case InfoType::AslrRegionSize: - *result = process->PageTable().GetAliasCodeRegionSize(); + *result = process->GetPageTable().GetAliasCodeRegionSize(); R_SUCCEED(); case InfoType::StackRegionAddress: - *result = GetInteger(process->PageTable().GetStackRegionStart()); + *result = GetInteger(process->GetPageTable().GetStackRegionStart()); R_SUCCEED(); case InfoType::StackRegionSize: - *result = process->PageTable().GetStackRegionSize(); + *result = process->GetPageTable().GetStackRegionSize(); R_SUCCEED(); case InfoType::TotalMemorySize: diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp index bb94f6934..373ae7c8d 100644 --- a/src/core/hle/kernel/svc/svc_ipc.cpp +++ b/src/core/hle/kernel/svc/svc_ipc.cpp @@ -8,6 +8,7 @@ #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" namespace Kernel::Svc { @@ -49,14 +50,10 @@ Result ReplyAndReceive(Core::System& system, s32* out_index, uint64_t handles_ad // Copy user handles. if (num_handles > 0) { - // Ensure we can try to get the handles. - R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange( - handles_addr, static_cast<u64>(sizeof(Handle) * num_handles)), - ResultInvalidPointer); - // Get the handles. - GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), - sizeof(Handle) * num_handles); + R_UNLESS(GetCurrentMemory(kernel).ReadBlock(handles_addr, handles.data(), + sizeof(Handle) * num_handles), + ResultInvalidPointer); // Convert the handles to objects. R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>( diff --git a/src/core/hle/kernel/svc/svc_memory.cpp b/src/core/hle/kernel/svc/svc_memory.cpp index 5dcb7f045..2cab74127 100644 --- a/src/core/hle/kernel/svc/svc_memory.cpp +++ b/src/core/hle/kernel/svc/svc_memory.cpp @@ -63,36 +63,13 @@ Result MapUnmapMemorySanityChecks(const KPageTable& manager, u64 dst_addr, u64 s R_THROW(ResultInvalidCurrentMemory); } - if (!manager.IsInsideAddressSpace(src_addr, size)) { + if (!manager.Contains(src_addr, size)) { LOG_ERROR(Kernel_SVC, "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", src_addr, size); R_THROW(ResultInvalidCurrentMemory); } - if (manager.IsOutsideStackRegion(dst_addr, size)) { - LOG_ERROR(Kernel_SVC, - "Destination is not within the stack region, addr=0x{:016X}, size=0x{:016X}", - dst_addr, size); - R_THROW(ResultInvalidMemoryRegion); - } - - if (manager.IsInsideHeapRegion(dst_addr, size)) { - LOG_ERROR(Kernel_SVC, - "Destination does not fit within the heap region, addr=0x{:016X}, " - "size=0x{:016X}", - dst_addr, size); - R_THROW(ResultInvalidMemoryRegion); - } - - if (manager.IsInsideAliasRegion(dst_addr, size)) { - LOG_ERROR(Kernel_SVC, - "Destination does not fit within the map region, addr=0x{:016X}, " - "size=0x{:016X}", - dst_addr, size); - R_THROW(ResultInvalidMemoryRegion); - } - R_SUCCEED(); } @@ -112,7 +89,7 @@ Result SetMemoryPermission(Core::System& system, u64 address, u64 size, MemoryPe R_UNLESS(IsValidSetMemoryPermission(perm), ResultInvalidNewMemoryPermission); // Validate that the region is in range for the current process. - auto& page_table = GetCurrentProcess(system.Kernel()).PageTable(); + auto& page_table = GetCurrentProcess(system.Kernel()).GetPageTable(); R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); // Set the memory attribute. @@ -136,7 +113,7 @@ Result SetMemoryAttribute(Core::System& system, u64 address, u64 size, u32 mask, R_UNLESS((mask | attr | SupportedMask) == SupportedMask, ResultInvalidCombination); // Validate that the region is in range for the current process. - auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()}; + auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()}; R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); // Set the memory attribute. @@ -148,7 +125,7 @@ Result MapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) { LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); - auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()}; + auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()}; if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)}; result.IsError()) { @@ -163,7 +140,7 @@ Result UnmapMemory(Core::System& system, u64 dst_addr, u64 src_addr, u64 size) { LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, src_addr, size); - auto& page_table{GetCurrentProcess(system.Kernel()).PageTable()}; + auto& page_table{GetCurrentProcess(system.Kernel()).GetPageTable()}; if (const Result result{MapUnmapMemorySanityChecks(page_table, dst_addr, src_addr, size)}; result.IsError()) { diff --git a/src/core/hle/kernel/svc/svc_physical_memory.cpp b/src/core/hle/kernel/svc/svc_physical_memory.cpp index c2fbfb59a..d3545f232 100644 --- a/src/core/hle/kernel/svc/svc_physical_memory.cpp +++ b/src/core/hle/kernel/svc/svc_physical_memory.cpp @@ -16,7 +16,7 @@ Result SetHeapSize(Core::System& system, u64* out_address, u64 size) { R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize); // Set the heap size. - R_RETURN(GetCurrentProcess(system.Kernel()).PageTable().SetHeapSize(out_address, size)); + R_RETURN(GetCurrentProcess(system.Kernel()).GetPageTable().SetHeapSize(out_address, size)); } /// Maps memory at a desired address @@ -44,21 +44,21 @@ Result MapPhysicalMemory(Core::System& system, u64 addr, u64 size) { } KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())}; - auto& page_table{current_process->PageTable()}; + auto& page_table{current_process->GetPageTable()}; if (current_process->GetSystemResourceSize() == 0) { LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); R_THROW(ResultInvalidState); } - if (!page_table.IsInsideAddressSpace(addr, size)) { + if (!page_table.Contains(addr, size)) { LOG_ERROR(Kernel_SVC, "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, size); R_THROW(ResultInvalidMemoryRegion); } - if (page_table.IsOutsideAliasRegion(addr, size)) { + if (!page_table.IsInAliasRegion(addr, size)) { LOG_ERROR(Kernel_SVC, "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, size); @@ -93,21 +93,21 @@ Result UnmapPhysicalMemory(Core::System& system, u64 addr, u64 size) { } KProcess* const current_process{GetCurrentProcessPointer(system.Kernel())}; - auto& page_table{current_process->PageTable()}; + auto& page_table{current_process->GetPageTable()}; if (current_process->GetSystemResourceSize() == 0) { LOG_ERROR(Kernel_SVC, "System Resource Size is zero"); R_THROW(ResultInvalidState); } - if (!page_table.IsInsideAddressSpace(addr, size)) { + if (!page_table.Contains(addr, size)) { LOG_ERROR(Kernel_SVC, "Address is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, size); R_THROW(ResultInvalidMemoryRegion); } - if (page_table.IsOutsideAliasRegion(addr, size)) { + if (!page_table.IsInAliasRegion(addr, size)) { LOG_ERROR(Kernel_SVC, "Address is not within the alias region, addr=0x{:016X}, size=0x{:016X}", addr, size); diff --git a/src/core/hle/kernel/svc/svc_process.cpp b/src/core/hle/kernel/svc/svc_process.cpp index 619ed16a3..caa8bee9a 100644 --- a/src/core/hle/kernel/svc/svc_process.cpp +++ b/src/core/hle/kernel/svc/svc_process.cpp @@ -66,8 +66,8 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc auto& kernel = system.Kernel(); const auto total_copy_size = out_process_ids_size * sizeof(u64); - if (out_process_ids_size > 0 && !GetCurrentProcess(kernel).PageTable().IsInsideAddressSpace( - out_process_ids, total_copy_size)) { + if (out_process_ids_size > 0 && + !GetCurrentProcess(kernel).GetPageTable().Contains(out_process_ids, total_copy_size)) { LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}", out_process_ids, out_process_ids + total_copy_size); R_THROW(ResultInvalidCurrentMemory); diff --git a/src/core/hle/kernel/svc/svc_process_memory.cpp b/src/core/hle/kernel/svc/svc_process_memory.cpp index aee0f2f36..07cd48175 100644 --- a/src/core/hle/kernel/svc/svc_process_memory.cpp +++ b/src/core/hle/kernel/svc/svc_process_memory.cpp @@ -49,7 +49,7 @@ Result SetProcessMemoryPermission(Core::System& system, Handle process_handle, u R_UNLESS(process.IsNotNull(), ResultInvalidHandle); // Validate that the address is in range. - auto& page_table = process->PageTable(); + auto& page_table = process->GetPageTable(); R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); // Set the memory permission. @@ -77,8 +77,8 @@ Result MapProcessMemory(Core::System& system, u64 dst_address, Handle process_ha R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle); // Get the page tables. - auto& dst_pt = dst_process->PageTable(); - auto& src_pt = src_process->PageTable(); + auto& dst_pt = dst_process->GetPageTable(); + auto& src_pt = src_process->GetPageTable(); // Validate that the mapping is in range. R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory); @@ -118,8 +118,8 @@ Result UnmapProcessMemory(Core::System& system, u64 dst_address, Handle process_ R_UNLESS(src_process.IsNotNull(), ResultInvalidHandle); // Get the page tables. - auto& dst_pt = dst_process->PageTable(); - auto& src_pt = src_process->PageTable(); + auto& dst_pt = dst_process->GetPageTable(); + auto& src_pt = src_process->GetPageTable(); // Validate that the mapping is in range. R_UNLESS(src_pt.Contains(src_address, size), ResultInvalidCurrentMemory); @@ -178,8 +178,8 @@ Result MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst R_THROW(ResultInvalidHandle); } - auto& page_table = process->PageTable(); - if (!page_table.IsInsideAddressSpace(src_address, size)) { + auto& page_table = process->GetPageTable(); + if (!page_table.Contains(src_address, size)) { LOG_ERROR(Kernel_SVC, "Source address range is not within the address space (src_address=0x{:016X}, " "size=0x{:016X}).", @@ -187,14 +187,6 @@ Result MapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst R_THROW(ResultInvalidCurrentMemory); } - if (!page_table.IsInsideASLRRegion(dst_address, size)) { - LOG_ERROR(Kernel_SVC, - "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " - "size=0x{:016X}).", - dst_address, size); - R_THROW(ResultInvalidMemoryRegion); - } - R_RETURN(page_table.MapCodeMemory(dst_address, src_address, size)); } @@ -246,8 +238,8 @@ Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 d R_THROW(ResultInvalidHandle); } - auto& page_table = process->PageTable(); - if (!page_table.IsInsideAddressSpace(src_address, size)) { + auto& page_table = process->GetPageTable(); + if (!page_table.Contains(src_address, size)) { LOG_ERROR(Kernel_SVC, "Source address range is not within the address space (src_address=0x{:016X}, " "size=0x{:016X}).", @@ -255,14 +247,6 @@ Result UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 d R_THROW(ResultInvalidCurrentMemory); } - if (!page_table.IsInsideASLRRegion(dst_address, size)) { - LOG_ERROR(Kernel_SVC, - "Destination address range is not within the ASLR region (dst_address=0x{:016X}, " - "size=0x{:016X}).", - dst_address, size); - R_THROW(ResultInvalidMemoryRegion); - } - R_RETURN(page_table.UnmapCodeMemory(dst_address, src_address, size, KPageTable::ICacheInvalidationStrategy::InvalidateAll)); } diff --git a/src/core/hle/kernel/svc/svc_query_memory.cpp b/src/core/hle/kernel/svc/svc_query_memory.cpp index 4d9fcd25f..51af06e97 100644 --- a/src/core/hle/kernel/svc/svc_query_memory.cpp +++ b/src/core/hle/kernel/svc/svc_query_memory.cpp @@ -31,7 +31,7 @@ Result QueryProcessMemory(Core::System& system, uint64_t out_memory_info, PageIn } auto& current_memory{GetCurrentMemory(system.Kernel())}; - const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()}; + const auto memory_info{process->GetPageTable().QueryInfo(address).GetSvcMemoryInfo()}; current_memory.WriteBlock(out_memory_info, std::addressof(memory_info), sizeof(memory_info)); diff --git a/src/core/hle/kernel/svc/svc_shared_memory.cpp b/src/core/hle/kernel/svc/svc_shared_memory.cpp index a698596aa..012b1ae2b 100644 --- a/src/core/hle/kernel/svc/svc_shared_memory.cpp +++ b/src/core/hle/kernel/svc/svc_shared_memory.cpp @@ -43,7 +43,7 @@ Result MapSharedMemory(Core::System& system, Handle shmem_handle, u64 address, u // Get the current process. auto& process = GetCurrentProcess(system.Kernel()); - auto& page_table = process.PageTable(); + auto& page_table = process.GetPageTable(); // Get the shared memory. KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); @@ -73,7 +73,7 @@ Result UnmapSharedMemory(Core::System& system, Handle shmem_handle, u64 address, // Get the current process. auto& process = GetCurrentProcess(system.Kernel()); - auto& page_table = process.PageTable(); + auto& page_table = process.GetPageTable(); // Get the shared memory. KScopedAutoObject shmem = process.GetHandleTable().GetObject<KSharedMemory>(shmem_handle); diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp index f02d03f30..366e8ed4a 100644 --- a/src/core/hle/kernel/svc/svc_synchronization.cpp +++ b/src/core/hle/kernel/svc/svc_synchronization.cpp @@ -7,6 +7,7 @@ #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/svc.h" +#include "core/hle/kernel/svc_results.h" namespace Kernel::Svc { @@ -64,14 +65,10 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha // Copy user handles. if (num_handles > 0) { - // Ensure we can try to get the handles. - R_UNLESS(GetCurrentMemory(kernel).IsValidVirtualAddressRange( - user_handles, static_cast<u64>(sizeof(Handle) * num_handles)), - ResultInvalidPointer); - // Get the handles. - GetCurrentMemory(kernel).ReadBlock(user_handles, handles.data(), - sizeof(Handle) * num_handles); + R_UNLESS(GetCurrentMemory(kernel).ReadBlock(user_handles, handles.data(), + sizeof(Handle) * num_handles), + ResultInvalidPointer); // Convert the handles to objects. R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>( diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp index 36b94e6bf..92bcea72b 100644 --- a/src/core/hle/kernel/svc/svc_thread.cpp +++ b/src/core/hle/kernel/svc/svc_thread.cpp @@ -236,7 +236,7 @@ Result GetThreadList(Core::System& system, s32* out_num_threads, u64 out_thread_ const auto total_copy_size = out_thread_ids_size * sizeof(u64); if (out_thread_ids_size > 0 && - !current_process->PageTable().IsInsideAddressSpace(out_thread_ids, total_copy_size)) { + !current_process->GetPageTable().Contains(out_thread_ids, total_copy_size)) { LOG_ERROR(Kernel_SVC, "Address range outside address space. begin=0x{:016X}, end=0x{:016X}", out_thread_ids, out_thread_ids + total_copy_size); R_THROW(ResultInvalidCurrentMemory); diff --git a/src/core/hle/kernel/svc/svc_transfer_memory.cpp b/src/core/hle/kernel/svc/svc_transfer_memory.cpp index 82d469a37..7d94e7f09 100644 --- a/src/core/hle/kernel/svc/svc_transfer_memory.cpp +++ b/src/core/hle/kernel/svc/svc_transfer_memory.cpp @@ -55,7 +55,7 @@ Result CreateTransferMemory(Core::System& system, Handle* out, u64 address, u64 SCOPE_EXIT({ trmem->Close(); }); // Ensure that the region is in range. - R_UNLESS(process.PageTable().Contains(address, size), ResultInvalidCurrentMemory); + R_UNLESS(process.GetPageTable().Contains(address, size), ResultInvalidCurrentMemory); // Initialize the transfer memory. R_TRY(trmem->Initialize(address, size, map_perm)); diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 6c29cb613..2632cd3ef 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -496,8 +496,9 @@ public: void LoadIdTokenCache(HLERequestContext& ctx) { LOG_WARNING(Service_ACC, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); + rb.Push(0); } protected: diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index a2375508a..4f400d341 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -506,8 +506,8 @@ void ISelfController::SetHandlesRequestToDisplay(HLERequestContext& ctx) { void ISelfController::SetIdleTimeDetectionExtension(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; idle_time_detection_extension = rp.Pop<u32>(); - LOG_WARNING(Service_AM, "(STUBBED) called idle_time_detection_extension={}", - idle_time_detection_extension); + LOG_DEBUG(Service_AM, "(STUBBED) called idle_time_detection_extension={}", + idle_time_detection_extension); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/glue/ectx.cpp b/src/core/hle/service/glue/ectx.cpp index 1bd9314ae..6f71b62f3 100644 --- a/src/core/hle/service/glue/ectx.cpp +++ b/src/core/hle/service/glue/ectx.cpp @@ -2,13 +2,48 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/service/glue/ectx.h" +#include "core/hle/service/ipc_helpers.h" namespace Service::Glue { +// This is nn::err::context::IContextRegistrar +class IContextRegistrar : public ServiceFramework<IContextRegistrar> { +public: + IContextRegistrar(Core::System& system_) : ServiceFramework{system_, "IContextRegistrar"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &IContextRegistrar::Complete, "Complete"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + + ~IContextRegistrar() override = default; + +private: + void Complete(HLERequestContext& ctx) { + struct InputParameters { + u32 unk; + }; + struct OutputParameters { + u32 unk; + }; + + IPC::RequestParser rp{ctx}; + [[maybe_unused]] auto input = rp.PopRaw<InputParameters>(); + [[maybe_unused]] auto value = ctx.ReadBuffer(); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); + } +}; + ECTX_AW::ECTX_AW(Core::System& system_) : ServiceFramework{system_, "ectx:aw"} { // clang-format off static const FunctionInfo functions[] = { - {0, nullptr, "CreateContextRegistrar"}, + {0, &ECTX_AW::CreateContextRegistrar, "CreateContextRegistrar"}, {1, nullptr, "CommitContext"}, }; // clang-format on @@ -18,4 +53,10 @@ ECTX_AW::ECTX_AW(Core::System& system_) : ServiceFramework{system_, "ectx:aw"} { ECTX_AW::~ECTX_AW() = default; +void ECTX_AW::CreateContextRegistrar(HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IContextRegistrar>(std::make_shared<IContextRegistrar>(system)); +} + } // namespace Service::Glue diff --git a/src/core/hle/service/glue/ectx.h b/src/core/hle/service/glue/ectx.h index a608de053..ffa74d8d3 100644 --- a/src/core/hle/service/glue/ectx.h +++ b/src/core/hle/service/glue/ectx.h @@ -15,6 +15,9 @@ class ECTX_AW final : public ServiceFramework<ECTX_AW> { public: explicit ECTX_AW(Core::System& system_); ~ECTX_AW() override; + +private: + void CreateContextRegistrar(HLERequestContext& ctx); }; } // namespace Service::Glue diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index c42489ff9..055c0a2db 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -318,15 +318,15 @@ public: return false; } - if (!page_table.IsInsideAddressSpace(out_addr, size)) { + if (!page_table.Contains(out_addr, size)) { return false; } - if (page_table.IsInsideHeapRegion(out_addr, size)) { + if (page_table.IsInHeapRegion(out_addr, size)) { return false; } - if (page_table.IsInsideAliasRegion(out_addr, size)) { + if (page_table.IsInAliasRegion(out_addr, size)) { return false; } @@ -358,7 +358,7 @@ public: } ResultVal<VAddr> MapProcessCodeMemory(Kernel::KProcess* process, VAddr base_addr, u64 size) { - auto& page_table{process->PageTable()}; + auto& page_table{process->GetPageTable()}; VAddr addr{}; for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { @@ -382,7 +382,7 @@ public: ResultVal<VAddr> MapNro(Kernel::KProcess* process, VAddr nro_addr, std::size_t nro_size, VAddr bss_addr, std::size_t bss_size, std::size_t size) { for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) { - auto& page_table{process->PageTable()}; + auto& page_table{process->GetPageTable()}; VAddr addr{}; CASCADE_RESULT(addr, MapProcessCodeMemory(process, nro_addr, nro_size)); @@ -437,12 +437,12 @@ public: CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start, nro_header.segment_headers[DATA_INDEX].memory_size); - CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( + CASCADE_CODE(process->GetPageTable().SetProcessMemoryPermission( text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute)); - CASCADE_CODE(process->PageTable().SetProcessMemoryPermission( + CASCADE_CODE(process->GetPageTable().SetProcessMemoryPermission( ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read)); - return process->PageTable().SetProcessMemoryPermission( + return process->GetPageTable().SetProcessMemoryPermission( data_start, bss_end_addr - data_start, Kernel::Svc::MemoryPermission::ReadWrite); } @@ -571,7 +571,7 @@ public: Result UnmapNro(const NROInfo& info) { // Each region must be unmapped separately to validate memory state - auto& page_table{system.ApplicationProcess()->PageTable()}; + auto& page_table{system.ApplicationProcess()->GetPageTable()}; if (info.bss_size != 0) { CASCADE_CODE(page_table.UnmapCodeMemory( @@ -643,7 +643,7 @@ public: initialized = true; current_map_addr = - GetInteger(system.ApplicationProcess()->PageTable().GetAliasCodeRegionStart()); + GetInteger(system.ApplicationProcess()->GetPageTable().GetAliasCodeRegionStart()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/nfc/common/amiibo_crypto.cpp b/src/core/hle/service/nfc/common/amiibo_crypto.cpp index bc232c334..9556e9193 100644 --- a/src/core/hle/service/nfc/common/amiibo_crypto.cpp +++ b/src/core/hle/service/nfc/common/amiibo_crypto.cpp @@ -180,7 +180,7 @@ std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed } void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key, - const std::vector<u8>& seed) { + std::span<const u8> seed) { // Initialize context ctx.used = false; ctx.counter = 0; diff --git a/src/core/hle/service/nfc/common/amiibo_crypto.h b/src/core/hle/service/nfc/common/amiibo_crypto.h index 6a3e0841e..2cc0e4d51 100644 --- a/src/core/hle/service/nfc/common/amiibo_crypto.h +++ b/src/core/hle/service/nfc/common/amiibo_crypto.h @@ -75,7 +75,7 @@ std::vector<u8> GenerateInternalKey(const InternalKey& key, const HashSeed& seed // Initializes mbedtls context void CryptoInit(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, const HmacKey& hmac_key, - const std::vector<u8>& seed); + std::span<const u8> seed); // Feeds data to mbedtls context to generate the derived key void CryptoStep(CryptoCtx& ctx, mbedtls_md_context_t& hmac_ctx, DrgbOutput& output); diff --git a/src/core/hle/service/nfc/common/device.cpp b/src/core/hle/service/nfc/common/device.cpp index 2d633b03f..49446bc42 100644 --- a/src/core/hle/service/nfc/common/device.cpp +++ b/src/core/hle/service/nfc/common/device.cpp @@ -34,8 +34,6 @@ #include "core/hle/service/nfc/mifare_result.h" #include "core/hle/service/nfc/nfc_result.h" #include "core/hle/service/time/time_manager.h" -#include "core/hle/service/time/time_zone_content_manager.h" -#include "core/hle/service/time/time_zone_types.h" namespace Service::NFC { NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, @@ -1486,6 +1484,7 @@ DeviceState NfcDevice::GetCurrentState() const { } Result NfcDevice::GetNpadId(Core::HID::NpadIdType& out_npad_id) const { + // TODO: This should get the npad id from nn::hid::system::GetXcdHandleForNpadWithNfc out_npad_id = npad_id; return ResultSuccess; } diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp index 562f3a28e..a71d26157 100644 --- a/src/core/hle/service/nfc/common/device_manager.cpp +++ b/src/core/hle/service/nfc/common/device_manager.cpp @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later +#include <algorithm> + #include "common/logging/log.h" #include "core/core.h" #include "core/hid/hid_types.h" @@ -10,6 +12,7 @@ #include "core/hle/service/nfc/common/device_manager.h" #include "core/hle/service/nfc/nfc_result.h" #include "core/hle/service/time/clock_types.h" +#include "core/hle/service/time/time_manager.h" namespace Service::NFC { @@ -51,22 +54,53 @@ Result DeviceManager::Finalize() { return ResultSuccess; } -Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, - std::size_t max_allowed_devices) const { +Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices, + bool skip_fatal_errors) const { + std::scoped_lock lock{mutex}; + if (max_allowed_devices < 1) { + return ResultInvalidArgument; + } + + Result result = IsNfcParameterSet(); + if (result.IsError()) { + return result; + } + + result = IsNfcEnabled(); + if (result.IsError()) { + return result; + } + + result = IsNfcInitialized(); + if (result.IsError()) { + return result; + } + for (auto& device : devices) { if (nfp_devices.size() >= max_allowed_devices) { continue; } - if (device->GetCurrentState() != DeviceState::Unavailable) { - nfp_devices.push_back(device->GetHandle()); + if (skip_fatal_errors) { + constexpr u64 MinimumRecoveryTime = 60; + auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; + const u64 elapsed_time = standard_steady_clock.GetCurrentTimePoint(system).time_point - + time_since_last_error; + + if (time_since_last_error != 0 && elapsed_time < MinimumRecoveryTime) { + continue; + } } + if (device->GetCurrentState() == DeviceState::Unavailable) { + continue; + } + nfp_devices.push_back(device->GetHandle()); } if (nfp_devices.empty()) { return ResultDeviceNotFound; } - return ResultSuccess; + return result; } DeviceState DeviceManager::GetDeviceState(u64 device_handle) const { @@ -79,10 +113,10 @@ DeviceState DeviceManager::GetDeviceState(u64 device_handle) const { return device->GetCurrentState(); } - return DeviceState::Unavailable; + return DeviceState::Finalized; } -Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const { +Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) { std::scoped_lock lock{mutex}; std::shared_ptr<NfcDevice> device = nullptr; @@ -128,7 +162,7 @@ Result DeviceManager::StopDetection(u64 device_handle) { return result; } -Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const { +Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) { std::scoped_lock lock{mutex}; std::shared_ptr<NfcDevice> device = nullptr; @@ -142,24 +176,46 @@ Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info) const { return result; } -Kernel::KReadableEvent& DeviceManager::AttachActivateEvent(u64 device_handle) const { - std::scoped_lock lock{mutex}; - +Result DeviceManager::AttachActivateEvent(Kernel::KReadableEvent** out_event, + u64 device_handle) const { + std::vector<u64> nfp_devices; std::shared_ptr<NfcDevice> device = nullptr; - GetDeviceFromHandle(device_handle, device, false); + Result result = ListDevices(nfp_devices, 9, false); - // TODO: Return proper error code on failure - return device->GetActivateEvent(); -} + if (result.IsSuccess()) { + result = CheckHandleOnList(device_handle, nfp_devices); + } -Kernel::KReadableEvent& DeviceManager::AttachDeactivateEvent(u64 device_handle) const { - std::scoped_lock lock{mutex}; + if (result.IsSuccess()) { + result = GetDeviceFromHandle(device_handle, device, false); + } + + if (result.IsSuccess()) { + *out_event = &device->GetActivateEvent(); + } + + return result; +} +Result DeviceManager::AttachDeactivateEvent(Kernel::KReadableEvent** out_event, + u64 device_handle) const { + std::vector<u64> nfp_devices; std::shared_ptr<NfcDevice> device = nullptr; - GetDeviceFromHandle(device_handle, device, false); + Result result = ListDevices(nfp_devices, 9, false); - // TODO: Return proper error code on failure - return device->GetDeactivateEvent(); + if (result.IsSuccess()) { + result = CheckHandleOnList(device_handle, nfp_devices); + } + + if (result.IsSuccess()) { + result = GetDeviceFromHandle(device_handle, device, false); + } + + if (result.IsSuccess()) { + *out_event = &device->GetDeactivateEvent(); + } + + return result; } Result DeviceManager::ReadMifare(u64 device_handle, @@ -253,7 +309,7 @@ Result DeviceManager::OpenApplicationArea(u64 device_handle, u32 access_id) { return result; } -Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) const { +Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) { std::scoped_lock lock{mutex}; std::shared_ptr<NfcDevice> device = nullptr; @@ -324,7 +380,7 @@ Result DeviceManager::CreateApplicationArea(u64 device_handle, u32 access_id, return result; } -Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const { +Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) { std::scoped_lock lock{mutex}; std::shared_ptr<NfcDevice> device = nullptr; @@ -338,7 +394,7 @@ Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& regi return result; } -Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const { +Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) { std::scoped_lock lock{mutex}; std::shared_ptr<NfcDevice> device = nullptr; @@ -352,7 +408,7 @@ Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_i return result; } -Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const { +Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) { std::scoped_lock lock{mutex}; std::shared_ptr<NfcDevice> device = nullptr; @@ -399,7 +455,7 @@ Result DeviceManager::Format(u64 device_handle) { return result; } -Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const { +Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) { std::scoped_lock lock{mutex}; std::shared_ptr<NfcDevice> device = nullptr; @@ -414,7 +470,7 @@ Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info } Result DeviceManager::GetRegisterInfoPrivate(u64 device_handle, - NFP::RegisterInfoPrivate& register_info) const { + NFP::RegisterInfoPrivate& register_info) { std::scoped_lock lock{mutex}; std::shared_ptr<NfcDevice> device = nullptr; @@ -471,7 +527,7 @@ Result DeviceManager::DeleteApplicationArea(u64 device_handle) { return result; } -Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) const { +Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) { std::scoped_lock lock{mutex}; std::shared_ptr<NfcDevice> device = nullptr; @@ -485,7 +541,7 @@ Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_applica return result; } -Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) const { +Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) { std::scoped_lock lock{mutex}; std::shared_ptr<NfcDevice> device = nullptr; @@ -541,7 +597,7 @@ Result DeviceManager::BreakTag(u64 device_handle, NFP::BreakType break_type) { return result; } -Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) const { +Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) { std::scoped_lock lock{mutex}; std::shared_ptr<NfcDevice> device = nullptr; @@ -593,6 +649,19 @@ Result DeviceManager::WriteNtf(u64 device_handle, NFP::WriteType, std::span<cons return result; } +Result DeviceManager::CheckHandleOnList(u64 device_handle, + const std::span<const u64> device_list) const { + if (device_list.size() < 1) { + return ResultDeviceNotFound; + } + + if (std::find(device_list.begin(), device_list.end(), device_handle) != device_list.end()) { + return ResultSuccess; + } + + return ResultDeviceNotFound; +} + Result DeviceManager::GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& nfc_device, bool check_state) const { if (check_state) { @@ -647,7 +716,7 @@ Result DeviceManager::GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& de } Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device, - Result operation_result) const { + Result operation_result) { if (operation_result.IsSuccess()) { return operation_result; } @@ -669,6 +738,12 @@ Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device, return device_state; } + if (operation_result == ResultUnknown112 || operation_result == ResultUnknown114 || + operation_result == ResultUnknown115) { + auto& standard_steady_clock{system.GetTimeManager().GetStandardSteadyClockCore()}; + time_since_last_error = standard_steady_clock.GetCurrentTimePoint(system).time_point; + } + return operation_result; } diff --git a/src/core/hle/service/nfc/common/device_manager.h b/src/core/hle/service/nfc/common/device_manager.h index c61ba0cf3..c9f038e32 100644 --- a/src/core/hle/service/nfc/common/device_manager.h +++ b/src/core/hle/service/nfc/common/device_manager.h @@ -27,15 +27,16 @@ public: // Nfc device manager Result Initialize(); Result Finalize(); - Result ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices) const; + Result ListDevices(std::vector<u64>& nfp_devices, std::size_t max_allowed_devices, + bool skip_fatal_errors) const; DeviceState GetDeviceState(u64 device_handle) const; - Result GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const; + Result GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id); Kernel::KReadableEvent& AttachAvailabilityChangeEvent() const; Result StartDetection(u64 device_handle, NfcProtocol tag_protocol); Result StopDetection(u64 device_handle); - Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info) const; - Kernel::KReadableEvent& AttachActivateEvent(u64 device_handle) const; - Kernel::KReadableEvent& AttachDeactivateEvent(u64 device_handle) const; + Result GetTagInfo(u64 device_handle, NFP::TagInfo& tag_info); + Result AttachActivateEvent(Kernel::KReadableEvent** event, u64 device_handle) const; + Result AttachDeactivateEvent(Kernel::KReadableEvent** event, u64 device_handle) const; Result ReadMifare(u64 device_handle, const std::span<const MifareReadBlockParameter> read_parameters, std::span<MifareReadBlockData> read_data); @@ -48,28 +49,28 @@ public: Result Mount(u64 device_handle, NFP::ModelType model_type, NFP::MountTarget mount_target); Result Unmount(u64 device_handle); Result OpenApplicationArea(u64 device_handle, u32 access_id); - Result GetApplicationArea(u64 device_handle, std::span<u8> data) const; + Result GetApplicationArea(u64 device_handle, std::span<u8> data); Result SetApplicationArea(u64 device_handle, std::span<const u8> data); Result Flush(u64 device_handle); Result Restore(u64 device_handle); Result CreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data); - Result GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const; - Result GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const; - Result GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const; + Result GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info); + Result GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info); + Result GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info); u32 GetApplicationAreaSize() const; Result RecreateApplicationArea(u64 device_handle, u32 access_id, std::span<const u8> data); Result Format(u64 device_handle); - Result GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const; - Result GetRegisterInfoPrivate(u64 device_handle, NFP::RegisterInfoPrivate& register_info) const; + Result GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info); + Result GetRegisterInfoPrivate(u64 device_handle, NFP::RegisterInfoPrivate& register_info); Result SetRegisterInfoPrivate(u64 device_handle, const NFP::RegisterInfoPrivate& register_info); Result DeleteRegisterInfo(u64 device_handle); Result DeleteApplicationArea(u64 device_handle); - Result ExistsApplicationArea(u64 device_handle, bool& has_application_area) const; - Result GetAll(u64 device_handle, NFP::NfpData& nfp_data) const; + Result ExistsApplicationArea(u64 device_handle, bool& has_application_area); + Result GetAll(u64 device_handle, NFP::NfpData& nfp_data); Result SetAll(u64 device_handle, const NFP::NfpData& nfp_data); Result FlushDebug(u64 device_handle); Result BreakTag(u64 device_handle, NFP::BreakType break_type); - Result ReadBackupData(u64 device_handle, std::span<u8> data) const; + Result ReadBackupData(u64 device_handle, std::span<u8> data); Result WriteBackupData(u64 device_handle, std::span<const u8> data); Result WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data); @@ -78,17 +79,20 @@ private: Result IsNfcParameterSet() const; Result IsNfcInitialized() const; + Result CheckHandleOnList(u64 device_handle, std::span<const u64> device_list) const; + Result GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& device, bool check_state) const; Result GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const; - Result VerifyDeviceResult(std::shared_ptr<NfcDevice> device, Result operation_result) const; + Result VerifyDeviceResult(std::shared_ptr<NfcDevice> device, Result operation_result); Result CheckDeviceState(std::shared_ptr<NfcDevice> device) const; std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle); const std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle) const; bool is_initialized = false; + u64 time_since_last_error = 0; mutable std::mutex mutex; std::array<std::shared_ptr<NfcDevice>, 10> devices{}; diff --git a/src/core/hle/service/nfc/nfc_interface.cpp b/src/core/hle/service/nfc/nfc_interface.cpp index e7ca7582e..179c7ba2c 100644 --- a/src/core/hle/service/nfc/nfc_interface.cpp +++ b/src/core/hle/service/nfc/nfc_interface.cpp @@ -79,7 +79,7 @@ void NfcInterface::ListDevices(HLERequestContext& ctx) { const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>(); LOG_DEBUG(Service_NFC, "called"); - auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices); + auto result = GetManager()->ListDevices(nfp_devices, max_allowed_devices, true); result = TranslateResultToServiceError(result); if (result.IsError()) { @@ -190,9 +190,13 @@ void NfcInterface::AttachActivateEvent(HLERequestContext& ctx) { const auto device_handle{rp.Pop<u64>()}; LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); + Kernel::KReadableEvent* out_event = nullptr; + auto result = GetManager()->AttachActivateEvent(&out_event, device_handle); + result = TranslateResultToServiceError(result); + IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(GetManager()->AttachActivateEvent(device_handle)); + rb.Push(result); + rb.PushCopyObjects(out_event); } void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) { @@ -200,9 +204,13 @@ void NfcInterface::AttachDeactivateEvent(HLERequestContext& ctx) { const auto device_handle{rp.Pop<u64>()}; LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); + Kernel::KReadableEvent* out_event = nullptr; + auto result = GetManager()->AttachDeactivateEvent(&out_event, device_handle); + result = TranslateResultToServiceError(result); + IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(GetManager()->AttachDeactivateEvent(device_handle)); + rb.Push(result); + rb.PushCopyObjects(out_event); } void NfcInterface::ReadMifare(HLERequestContext& ctx) { diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h index 715c0e80c..464b5fd69 100644 --- a/src/core/hle/service/nfc/nfc_result.h +++ b/src/core/hle/service/nfc/nfc_result.h @@ -17,7 +17,10 @@ constexpr Result ResultNfcNotInitialized(ErrorModule::NFC, 77); constexpr Result ResultNfcDisabled(ErrorModule::NFC, 80); constexpr Result ResultWriteAmiiboFailed(ErrorModule::NFC, 88); constexpr Result ResultTagRemoved(ErrorModule::NFC, 97); +constexpr Result ResultUnknown112(ErrorModule::NFC, 112); constexpr Result ResultUnableToAccessBackupFile(ErrorModule::NFC, 113); +constexpr Result ResultUnknown114(ErrorModule::NFC, 114); +constexpr Result ResultUnknown115(ErrorModule::NFC, 115); constexpr Result ResultRegistrationIsNotInitialized(ErrorModule::NFC, 120); constexpr Result ResultApplicationAreaIsNotInitialized(ErrorModule::NFC, 128); constexpr Result ResultCorruptedDataWithBackup(ErrorModule::NFC, 136); diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index e7f7e273b..968eaa175 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -128,7 +128,7 @@ NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) { } bool is_out_io{}; ASSERT(system.ApplicationProcess() - ->PageTable() + ->GetPageTable() .LockForMapDeviceAddressSpace(&is_out_io, handle_description->address, handle_description->size, Kernel::KMemoryPermission::None, true, false) @@ -255,7 +255,7 @@ NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) { if (auto freeInfo{file.FreeHandle(params.handle, false)}) { if (freeInfo->can_unlock) { ASSERT(system.ApplicationProcess() - ->PageTable() + ->GetPageTable() .UnlockForDeviceAddressSpace(freeInfo->address, freeInfo->size) .IsSuccess()); } diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index e63b0a357..11f8efbac 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -559,7 +559,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con const std::optional<FileDescriptor>& descriptor = file_descriptors[pollfd.fd]; if (!descriptor) { - LOG_ERROR(Service, "File descriptor handle={} is not allocated", pollfd.fd); + LOG_TRACE(Service, "File descriptor handle={} is not allocated", pollfd.fd); pollfd.revents = PollEvents::Nval; return {0, Errno::SUCCESS}; } diff --git a/src/core/hle/service/sockets/nsd.cpp b/src/core/hle/service/sockets/nsd.cpp index 0dfb0f166..5dfcaabb1 100644 --- a/src/core/hle/service/sockets/nsd.cpp +++ b/src/core/hle/service/sockets/nsd.cpp @@ -10,12 +10,21 @@ namespace Service::Sockets { constexpr Result ResultOverflow{ErrorModule::NSD, 6}; +// This is nn::oe::ServerEnvironmentType +enum class ServerEnvironmentType : u8 { + Dd, + Lp, + Sd, + Sp, + Dp, +}; + NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, name} { // clang-format off static const FunctionInfo functions[] = { {5, nullptr, "GetSettingUrl"}, {10, nullptr, "GetSettingName"}, - {11, nullptr, "GetEnvironmentIdentifier"}, + {11, &NSD::GetEnvironmentIdentifier, "GetEnvironmentIdentifier"}, {12, nullptr, "GetDeviceId"}, {13, nullptr, "DeleteSettings"}, {14, nullptr, "ImportSettings"}, @@ -36,7 +45,7 @@ NSD::NSD(Core::System& system_, const char* name) : ServiceFramework{system_, na {62, nullptr, "DeleteSaveDataOfFsForTest"}, {63, nullptr, "IsChangeEnvironmentIdentifierDisabled"}, {64, nullptr, "SetWithoutDomainExchangeFqdns"}, - {100, nullptr, "GetApplicationServerEnvironmentType"}, + {100, &NSD::GetApplicationServerEnvironmentType, "GetApplicationServerEnvironmentType"}, {101, nullptr, "SetApplicationServerEnvironmentType"}, {102, nullptr, "DeleteApplicationServerEnvironmentType"}, }; @@ -94,6 +103,20 @@ void NSD::ResolveEx(HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void NSD::GetEnvironmentIdentifier(HLERequestContext& ctx) { + const std::string environment_identifier = "lp1"; + ctx.WriteBuffer(environment_identifier); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void NSD::GetApplicationServerEnvironmentType(HLERequestContext& ctx) { + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<u32>(ServerEnvironmentType::Lp)); +} + NSD::~NSD() = default; } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/nsd.h b/src/core/hle/service/sockets/nsd.h index a7379a8a9..b0cfec507 100644 --- a/src/core/hle/service/sockets/nsd.h +++ b/src/core/hle/service/sockets/nsd.h @@ -19,6 +19,8 @@ public: private: void Resolve(HLERequestContext& ctx); void ResolveEx(HLERequestContext& ctx); + void GetEnvironmentIdentifier(HLERequestContext& ctx); + void GetApplicationServerEnvironmentType(HLERequestContext& ctx); }; } // namespace Service::Sockets diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp index 84cc79de8..22e4a6f49 100644 --- a/src/core/hle/service/sockets/sfdnsres.cpp +++ b/src/core/hle/service/sockets/sfdnsres.cpp @@ -24,7 +24,7 @@ SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres" {2, &SFDNSRES::GetHostByNameRequest, "GetHostByNameRequest"}, {3, nullptr, "GetHostByAddrRequest"}, {4, nullptr, "GetHostStringErrorRequest"}, - {5, nullptr, "GetGaiStringErrorRequest"}, + {5, &SFDNSRES::GetGaiStringErrorRequest, "GetGaiStringErrorRequest"}, {6, &SFDNSRES::GetAddrInfoRequest, "GetAddrInfoRequest"}, {7, nullptr, "GetNameInfoRequest"}, {8, nullptr, "RequestCancelHandleRequest"}, @@ -300,6 +300,20 @@ void SFDNSRES::GetAddrInfoRequest(HLERequestContext& ctx) { }); } +void SFDNSRES::GetGaiStringErrorRequest(HLERequestContext& ctx) { + struct InputParameters { + GetAddrInfoError gai_errno; + }; + IPC::RequestParser rp{ctx}; + auto input = rp.PopRaw<InputParameters>(); + + const std::string result = Translate(input.gai_errno); + ctx.WriteBuffer(result); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + void SFDNSRES::GetAddrInfoRequestWithOptions(HLERequestContext& ctx) { // Additional options are ignored auto [data_size, emu_gai_err] = GetAddrInfoRequestImpl(ctx); diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h index d99a9d560..282ef9071 100644 --- a/src/core/hle/service/sockets/sfdnsres.h +++ b/src/core/hle/service/sockets/sfdnsres.h @@ -18,6 +18,7 @@ public: private: void GetHostByNameRequest(HLERequestContext& ctx); + void GetGaiStringErrorRequest(HLERequestContext& ctx); void GetHostByNameRequestWithOptions(HLERequestContext& ctx); void GetAddrInfoRequest(HLERequestContext& ctx); void GetAddrInfoRequestWithOptions(HLERequestContext& ctx); diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp index 2f9a0e39c..c1187209f 100644 --- a/src/core/hle/service/sockets/sockets_translate.cpp +++ b/src/core/hle/service/sockets/sockets_translate.cpp @@ -81,6 +81,44 @@ GetAddrInfoError Translate(Network::GetAddrInfoError error) { } } +const char* Translate(GetAddrInfoError error) { + // https://android.googlesource.com/platform/bionic/+/085543106/libc/dns/net/getaddrinfo.c#254 + switch (error) { + case GetAddrInfoError::SUCCESS: + return "Success"; + case GetAddrInfoError::ADDRFAMILY: + return "Address family for hostname not supported"; + case GetAddrInfoError::AGAIN: + return "Temporary failure in name resolution"; + case GetAddrInfoError::BADFLAGS: + return "Invalid value for ai_flags"; + case GetAddrInfoError::FAIL: + return "Non-recoverable failure in name resolution"; + case GetAddrInfoError::FAMILY: + return "ai_family not supported"; + case GetAddrInfoError::MEMORY: + return "Memory allocation failure"; + case GetAddrInfoError::NODATA: + return "No address associated with hostname"; + case GetAddrInfoError::NONAME: + return "hostname nor servname provided, or not known"; + case GetAddrInfoError::SERVICE: + return "servname not supported for ai_socktype"; + case GetAddrInfoError::SOCKTYPE: + return "ai_socktype not supported"; + case GetAddrInfoError::SYSTEM: + return "System error returned in errno"; + case GetAddrInfoError::BADHINTS: + return "Invalid value for hints"; + case GetAddrInfoError::PROTOCOL: + return "Resolved protocol is unknown"; + case GetAddrInfoError::OVERFLOW_: + return "Argument buffer overflow"; + default: + return "Unknown error"; + } +} + Network::Domain Translate(Domain domain) { switch (domain) { case Domain::Unspecified: diff --git a/src/core/hle/service/sockets/sockets_translate.h b/src/core/hle/service/sockets/sockets_translate.h index 694868b37..bd6721fd3 100644 --- a/src/core/hle/service/sockets/sockets_translate.h +++ b/src/core/hle/service/sockets/sockets_translate.h @@ -20,6 +20,9 @@ std::pair<s32, Errno> Translate(std::pair<s32, Network::Errno> value); /// Translate abstract getaddrinfo error to guest getaddrinfo error GetAddrInfoError Translate(Network::GetAddrInfoError value); +/// Translate guest error to string +const char* Translate(GetAddrInfoError value); + /// Translate guest domain to abstract domain Network::Domain Translate(Domain domain); diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 3be9b71cf..e04ad19db 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -153,7 +153,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect // Load NSO modules modules.clear(); - const VAddr base_address{GetInteger(process.PageTable().GetCodeRegionStart())}; + const VAddr base_address{GetInteger(process.GetPageTable().GetCodeRegionStart())}; VAddr next_load_addr{base_address}; const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(), system.GetContentProvider()}; diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp index 709e2564f..ffe976b94 100644 --- a/src/core/loader/kip.cpp +++ b/src/core/loader/kip.cpp @@ -96,7 +96,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process, } codeset.memory = std::move(program_image); - const VAddr base_address = GetInteger(process.PageTable().GetCodeRegionStart()); + const VAddr base_address = GetInteger(process.GetPageTable().GetCodeRegionStart()); process.LoadModule(std::move(codeset), base_address); LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address); diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 7be6cf5f3..506808b5d 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -203,7 +203,7 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) // Load codeset for current process codeset.memory = std::move(program_image); - process.LoadModule(std::move(codeset), process.PageTable().GetCodeRegionStart()); + process.LoadModule(std::move(codeset), process.GetPageTable().GetCodeRegionStart()); return true; } diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 79639f5e4..74cc9579f 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -167,7 +167,7 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::S modules.clear(); // Load module - const VAddr base_address = GetInteger(process.PageTable().GetCodeRegionStart()); + const VAddr base_address = GetInteger(process.GetPageTable().GetCodeRegionStart()); if (!LoadModule(process, system, *file, base_address, true, true)) { return {ResultStatus::ErrorLoadingNSO, {}}; } diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 805963178..513bc4edb 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -31,10 +31,10 @@ struct Memory::Impl { explicit Impl(Core::System& system_) : system{system_} {} void SetCurrentPageTable(Kernel::KProcess& process, u32 core_id) { - current_page_table = &process.PageTable().PageTableImpl(); + current_page_table = &process.GetPageTable().PageTableImpl(); current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer(); - const std::size_t address_space_width = process.PageTable().GetAddressSpaceWidth(); + const std::size_t address_space_width = process.GetPageTable().GetAddressSpaceWidth(); system.ArmInterface(core_id).PageTableChanged(*current_page_table, address_space_width); } @@ -73,7 +73,7 @@ struct Memory::Impl { return {}; } - return system.DeviceMemory().GetPointer<u8>(paddr) + vaddr; + return system.DeviceMemory().GetPointer<u8>(paddr + vaddr); } [[nodiscard]] u8* GetPointerFromDebugMemory(u64 vaddr) const { @@ -84,7 +84,7 @@ struct Memory::Impl { return {}; } - return system.DeviceMemory().GetPointer<u8>(paddr) + vaddr; + return system.DeviceMemory().GetPointer<u8>(paddr + vaddr); } u8 Read8(const Common::ProcessAddress addr) { @@ -183,13 +183,13 @@ struct Memory::Impl { return string; } - void WalkBlock(const Kernel::KProcess& process, const Common::ProcessAddress addr, - const std::size_t size, auto on_unmapped, auto on_memory, auto on_rasterizer, - auto increment) { - const auto& page_table = process.PageTable().PageTableImpl(); + bool WalkBlock(const Common::ProcessAddress addr, const std::size_t size, auto on_unmapped, + auto on_memory, auto on_rasterizer, auto increment) { + const auto& page_table = system.ApplicationProcess()->GetPageTable().PageTableImpl(); std::size_t remaining_size = size; std::size_t page_index = addr >> YUZU_PAGEBITS; std::size_t page_offset = addr & YUZU_PAGEMASK; + bool user_accessible = true; while (remaining_size) { const std::size_t copy_amount = @@ -200,11 +200,13 @@ struct Memory::Impl { const auto [pointer, type] = page_table.pointers[page_index].PointerType(); switch (type) { case Common::PageType::Unmapped: { + user_accessible = false; on_unmapped(copy_amount, current_vaddr); break; } case Common::PageType::Memory: { - u8* mem_ptr = pointer + page_offset + (page_index << YUZU_PAGEBITS); + u8* mem_ptr = + reinterpret_cast<u8*>(pointer + page_offset + (page_index << YUZU_PAGEBITS)); on_memory(copy_amount, mem_ptr); break; } @@ -227,13 +229,15 @@ struct Memory::Impl { increment(copy_amount); remaining_size -= copy_amount; } + + return user_accessible; } template <bool UNSAFE> - void ReadBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress src_addr, - void* dest_buffer, const std::size_t size) { - WalkBlock( - process, src_addr, size, + bool ReadBlockImpl(const Common::ProcessAddress src_addr, void* dest_buffer, + const std::size_t size) { + return WalkBlock( + src_addr, size, [src_addr, size, &dest_buffer](const std::size_t copy_amount, const Common::ProcessAddress current_vaddr) { LOG_ERROR(HW_Memory, @@ -256,14 +260,14 @@ struct Memory::Impl { }); } - void ReadBlock(const Common::ProcessAddress src_addr, void* dest_buffer, + bool ReadBlock(const Common::ProcessAddress src_addr, void* dest_buffer, const std::size_t size) { - ReadBlockImpl<false>(*system.ApplicationProcess(), src_addr, dest_buffer, size); + return ReadBlockImpl<false>(src_addr, dest_buffer, size); } - void ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_buffer, + bool ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_buffer, const std::size_t size) { - ReadBlockImpl<true>(*system.ApplicationProcess(), src_addr, dest_buffer, size); + return ReadBlockImpl<true>(src_addr, dest_buffer, size); } const u8* GetSpan(const VAddr src_addr, const std::size_t size) const { @@ -283,10 +287,10 @@ struct Memory::Impl { } template <bool UNSAFE> - void WriteBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr, - const void* src_buffer, const std::size_t size) { - WalkBlock( - process, dest_addr, size, + bool WriteBlockImpl(const Common::ProcessAddress dest_addr, const void* src_buffer, + const std::size_t size) { + return WalkBlock( + dest_addr, size, [dest_addr, size](const std::size_t copy_amount, const Common::ProcessAddress current_vaddr) { LOG_ERROR(HW_Memory, @@ -308,20 +312,19 @@ struct Memory::Impl { }); } - void WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer, + bool WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer, const std::size_t size) { - WriteBlockImpl<false>(*system.ApplicationProcess(), dest_addr, src_buffer, size); + return WriteBlockImpl<false>(dest_addr, src_buffer, size); } - void WriteBlockUnsafe(const Common::ProcessAddress dest_addr, const void* src_buffer, + bool WriteBlockUnsafe(const Common::ProcessAddress dest_addr, const void* src_buffer, const std::size_t size) { - WriteBlockImpl<true>(*system.ApplicationProcess(), dest_addr, src_buffer, size); + return WriteBlockImpl<true>(dest_addr, src_buffer, size); } - void ZeroBlock(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr, - const std::size_t size) { - WalkBlock( - process, dest_addr, size, + bool ZeroBlock(const Common::ProcessAddress dest_addr, const std::size_t size) { + return WalkBlock( + dest_addr, size, [dest_addr, size](const std::size_t copy_amount, const Common::ProcessAddress current_vaddr) { LOG_ERROR(HW_Memory, @@ -339,23 +342,23 @@ struct Memory::Impl { [](const std::size_t copy_amount) {}); } - void CopyBlock(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - Common::ProcessAddress src_addr, const std::size_t size) { - WalkBlock( - process, dest_addr, size, + bool CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr, + const std::size_t size) { + return WalkBlock( + dest_addr, size, [&](const std::size_t copy_amount, const Common::ProcessAddress current_vaddr) { LOG_ERROR(HW_Memory, "Unmapped CopyBlock @ 0x{:016X} (start address = 0x{:016X}, size = {})", GetInteger(current_vaddr), GetInteger(src_addr), size); - ZeroBlock(process, dest_addr, copy_amount); + ZeroBlock(dest_addr, copy_amount); }, [&](const std::size_t copy_amount, const u8* const src_ptr) { - WriteBlockImpl<false>(process, dest_addr, src_ptr, copy_amount); + WriteBlockImpl<false>(dest_addr, src_ptr, copy_amount); }, [&](const Common::ProcessAddress current_vaddr, const std::size_t copy_amount, u8* const host_ptr) { HandleRasterizerDownload(GetInteger(current_vaddr), copy_amount); - WriteBlockImpl<false>(process, dest_addr, host_ptr, copy_amount); + WriteBlockImpl<false>(dest_addr, host_ptr, copy_amount); }, [&](const std::size_t copy_amount) { dest_addr += copy_amount; @@ -364,13 +367,13 @@ struct Memory::Impl { } template <typename Callback> - Result PerformCacheOperation(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - std::size_t size, Callback&& cb) { + Result PerformCacheOperation(Common::ProcessAddress dest_addr, std::size_t size, + Callback&& cb) { class InvalidMemoryException : public std::exception {}; try { WalkBlock( - process, dest_addr, size, + dest_addr, size, [&](const std::size_t block_size, const Common::ProcessAddress current_vaddr) { LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", GetInteger(current_vaddr)); @@ -387,37 +390,34 @@ struct Memory::Impl { return ResultSuccess; } - Result InvalidateDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - std::size_t size) { + Result InvalidateDataCache(Common::ProcessAddress dest_addr, std::size_t size) { auto on_rasterizer = [&](const Common::ProcessAddress current_vaddr, const std::size_t block_size) { // dc ivac: Invalidate to point of coherency // GPU flush -> CPU invalidate HandleRasterizerDownload(GetInteger(current_vaddr), block_size); }; - return PerformCacheOperation(process, dest_addr, size, on_rasterizer); + return PerformCacheOperation(dest_addr, size, on_rasterizer); } - Result StoreDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - std::size_t size) { + Result StoreDataCache(Common::ProcessAddress dest_addr, std::size_t size) { auto on_rasterizer = [&](const Common::ProcessAddress current_vaddr, const std::size_t block_size) { // dc cvac: Store to point of coherency // CPU flush -> GPU invalidate system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size); }; - return PerformCacheOperation(process, dest_addr, size, on_rasterizer); + return PerformCacheOperation(dest_addr, size, on_rasterizer); } - Result FlushDataCache(const Kernel::KProcess& process, Common::ProcessAddress dest_addr, - std::size_t size) { + Result FlushDataCache(Common::ProcessAddress dest_addr, std::size_t size) { auto on_rasterizer = [&](const Common::ProcessAddress current_vaddr, const std::size_t block_size) { // dc civac: Store to point of coherency, and invalidate from cache // CPU flush -> GPU invalidate system.GPU().InvalidateRegion(GetInteger(current_vaddr), block_size); }; - return PerformCacheOperation(process, dest_addr, size, on_rasterizer); + return PerformCacheOperation(dest_addr, size, on_rasterizer); } void MarkRegionDebug(u64 vaddr, u64 size, bool debug) { @@ -448,7 +448,7 @@ struct Memory::Impl { break; case Common::PageType::Memory: current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store( - nullptr, Common::PageType::DebugMemory); + 0, Common::PageType::DebugMemory); break; default: UNREACHABLE(); @@ -466,7 +466,8 @@ struct Memory::Impl { case Common::PageType::DebugMemory: { u8* const pointer{GetPointerFromDebugMemory(vaddr & ~YUZU_PAGEMASK)}; current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store( - pointer - (vaddr & ~YUZU_PAGEMASK), Common::PageType::Memory); + reinterpret_cast<uintptr_t>(pointer) - (vaddr & ~YUZU_PAGEMASK), + Common::PageType::Memory); break; } default: @@ -506,7 +507,7 @@ struct Memory::Impl { case Common::PageType::DebugMemory: case Common::PageType::Memory: current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store( - nullptr, Common::PageType::RasterizerCachedMemory); + 0, Common::PageType::RasterizerCachedMemory); break; case Common::PageType::RasterizerCachedMemory: // There can be more than one GPU region mapped per CPU region, so it's common @@ -534,10 +535,11 @@ struct Memory::Impl { // pagetable after unmapping a VMA. In that case the underlying VMA will no // longer exist, and we should just leave the pagetable entry blank. current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store( - nullptr, Common::PageType::Unmapped); + 0, Common::PageType::Unmapped); } else { current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store( - pointer - (vaddr & ~YUZU_PAGEMASK), Common::PageType::Memory); + reinterpret_cast<uintptr_t>(pointer) - (vaddr & ~YUZU_PAGEMASK), + Common::PageType::Memory); } break; } @@ -584,7 +586,7 @@ struct Memory::Impl { "Mapping memory page without a pointer @ {:016x}", base * YUZU_PAGESIZE); while (base != end) { - page_table.pointers[base].Store(nullptr, type); + page_table.pointers[base].Store(0, type); page_table.backing_addr[base] = 0; page_table.blocks[base] = 0; base += 1; @@ -593,7 +595,8 @@ struct Memory::Impl { auto orig_base = base; while (base != end) { auto host_ptr = - system.DeviceMemory().GetPointer<u8>(target) - (base << YUZU_PAGEBITS); + reinterpret_cast<uintptr_t>(system.DeviceMemory().GetPointer<u8>(target)) - + (base << YUZU_PAGEBITS); auto backing = GetInteger(target) - (base << YUZU_PAGEBITS); page_table.pointers[base].Store(host_ptr, type); page_table.backing_addr[base] = backing; @@ -619,8 +622,8 @@ struct Memory::Impl { // Avoid adding any extra logic to this fast-path block const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw(); - if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { - return &pointer[vaddr]; + if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { + return reinterpret_cast<u8*>(pointer + vaddr); } switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) { case Common::PageType::Unmapped: @@ -808,13 +811,13 @@ void Memory::UnmapRegion(Common::PageTable& page_table, Common::ProcessAddress b bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const { const Kernel::KProcess& process = *system.ApplicationProcess(); - const auto& page_table = process.PageTable().PageTableImpl(); + const auto& page_table = process.GetPageTable().PageTableImpl(); const size_t page = vaddr >> YUZU_PAGEBITS; if (page >= page_table.pointers.size()) { return false; } const auto [pointer, type] = page_table.pointers[page].PointerType(); - return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory || + return pointer != 0 || type == Common::PageType::RasterizerCachedMemory || type == Common::PageType::DebugMemory; } @@ -899,14 +902,14 @@ std::string Memory::ReadCString(Common::ProcessAddress vaddr, std::size_t max_le return impl->ReadCString(vaddr, max_length); } -void Memory::ReadBlock(const Common::ProcessAddress src_addr, void* dest_buffer, +bool Memory::ReadBlock(const Common::ProcessAddress src_addr, void* dest_buffer, const std::size_t size) { - impl->ReadBlock(src_addr, dest_buffer, size); + return impl->ReadBlock(src_addr, dest_buffer, size); } -void Memory::ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_buffer, +bool Memory::ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_buffer, const std::size_t size) { - impl->ReadBlockUnsafe(src_addr, dest_buffer, size); + return impl->ReadBlockUnsafe(src_addr, dest_buffer, size); } const u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) const { @@ -917,23 +920,23 @@ u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) { return impl->GetSpan(src_addr, size); } -void Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer, +bool Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer, const std::size_t size) { - impl->WriteBlock(dest_addr, src_buffer, size); + return impl->WriteBlock(dest_addr, src_buffer, size); } -void Memory::WriteBlockUnsafe(const Common::ProcessAddress dest_addr, const void* src_buffer, +bool Memory::WriteBlockUnsafe(const Common::ProcessAddress dest_addr, const void* src_buffer, const std::size_t size) { - impl->WriteBlockUnsafe(dest_addr, src_buffer, size); + return impl->WriteBlockUnsafe(dest_addr, src_buffer, size); } -void Memory::CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr, +bool Memory::CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr, const std::size_t size) { - impl->CopyBlock(*system.ApplicationProcess(), dest_addr, src_addr, size); + return impl->CopyBlock(dest_addr, src_addr, size); } -void Memory::ZeroBlock(Common::ProcessAddress dest_addr, const std::size_t size) { - impl->ZeroBlock(*system.ApplicationProcess(), dest_addr, size); +bool Memory::ZeroBlock(Common::ProcessAddress dest_addr, const std::size_t size) { + return impl->ZeroBlock(dest_addr, size); } void Memory::SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers) { @@ -941,15 +944,15 @@ void Memory::SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers } Result Memory::InvalidateDataCache(Common::ProcessAddress dest_addr, const std::size_t size) { - return impl->InvalidateDataCache(*system.ApplicationProcess(), dest_addr, size); + return impl->InvalidateDataCache(dest_addr, size); } Result Memory::StoreDataCache(Common::ProcessAddress dest_addr, const std::size_t size) { - return impl->StoreDataCache(*system.ApplicationProcess(), dest_addr, size); + return impl->StoreDataCache(dest_addr, size); } Result Memory::FlushDataCache(Common::ProcessAddress dest_addr, const std::size_t size) { - return impl->FlushDataCache(*system.ApplicationProcess(), dest_addr, size); + return impl->FlushDataCache(dest_addr, size); } void Memory::RasterizerMarkRegionCached(Common::ProcessAddress vaddr, u64 size, bool cached) { diff --git a/src/core/memory.h b/src/core/memory.h index ea33c769c..2eb61ffd3 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -24,7 +24,6 @@ class GPUDirtyMemoryManager; } // namespace Core namespace Kernel { -class PhysicalMemory; class KProcess; } // namespace Kernel @@ -330,7 +329,7 @@ public: * @post The range [dest_buffer, size) contains the read bytes from the * current process' address space. */ - void ReadBlock(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size); + bool ReadBlock(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size); /** * Reads a contiguous block of bytes from the current process' address space. @@ -349,7 +348,7 @@ public: * @post The range [dest_buffer, size) contains the read bytes from the * current process' address space. */ - void ReadBlockUnsafe(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size); + bool ReadBlockUnsafe(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size); const u8* GetSpan(const VAddr src_addr, const std::size_t size) const; u8* GetSpan(const VAddr src_addr, const std::size_t size); @@ -373,7 +372,7 @@ public: * and will mark that region as invalidated to caches that the active * graphics backend may be maintaining over the course of execution. */ - void WriteBlock(Common::ProcessAddress dest_addr, const void* src_buffer, std::size_t size); + bool WriteBlock(Common::ProcessAddress dest_addr, const void* src_buffer, std::size_t size); /** * Writes a range of bytes into the current process' address space at the specified @@ -391,7 +390,7 @@ public: * will be ignored and an error will be logged. * */ - void WriteBlockUnsafe(Common::ProcessAddress dest_addr, const void* src_buffer, + bool WriteBlockUnsafe(Common::ProcessAddress dest_addr, const void* src_buffer, std::size_t size); /** @@ -405,7 +404,7 @@ public: * @post The range [dest_addr, size) within the process' address space contains the * same data within the range [src_addr, size). */ - void CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr, + bool CopyBlock(Common::ProcessAddress dest_addr, Common::ProcessAddress src_addr, std::size_t size); /** @@ -418,7 +417,7 @@ public: * @post The range [dest_addr, size) within the process' address space contains the * value 0. */ - void ZeroBlock(Common::ProcessAddress dest_addr, std::size_t size); + bool ZeroBlock(Common::ProcessAddress dest_addr, std::size_t size); /** * Invalidates a range of bytes within the current process' address space at the specified diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 8742dd164..7b52f61a7 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -199,7 +199,7 @@ void CheatEngine::Initialize() { metadata.process_id = system.ApplicationProcess()->GetProcessId(); metadata.title_id = system.GetApplicationProcessProgramID(); - const auto& page_table = system.ApplicationProcess()->PageTable(); + const auto& page_table = system.ApplicationProcess()->GetPageTable(); metadata.heap_extents = { .base = GetInteger(page_table.GetHeapRegionStart()), .size = page_table.GetHeapRegionSize(), diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index 6c3dc7369..b5b3e7eda 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -117,8 +117,8 @@ json GetProcessorStateDataAuto(Core::System& system) { arm.SaveContext(context); return GetProcessorStateData(process->Is64BitProcess() ? "AArch64" : "AArch32", - GetInteger(process->PageTable().GetCodeRegionStart()), context.sp, - context.pc, context.pstate, context.cpu_registers); + GetInteger(process->GetPageTable().GetCodeRegionStart()), + context.sp, context.pc, context.pstate, context.cpu_registers); } json GetBacktraceData(Core::System& system) { diff --git a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp index d0b145860..07cabca43 100644 --- a/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp +++ b/src/shader_recompiler/ir_opt/ssa_rewrite_pass.cpp @@ -14,12 +14,12 @@ // #include <deque> +#include <map> #include <span> +#include <unordered_map> #include <variant> #include <vector> -#include <boost/container/flat_map.hpp> - #include "shader_recompiler/frontend/ir/basic_block.h" #include "shader_recompiler/frontend/ir/opcodes.h" #include "shader_recompiler/frontend/ir/pred.h" @@ -52,7 +52,7 @@ struct IndirectBranchVariable { using Variant = std::variant<IR::Reg, IR::Pred, ZeroFlagTag, SignFlagTag, CarryFlagTag, OverflowFlagTag, GotoVariable, IndirectBranchVariable>; -using ValueMap = boost::container::flat_map<IR::Block*, IR::Value>; +using ValueMap = std::unordered_map<IR::Block*, IR::Value>; struct DefTable { const IR::Value& Def(IR::Block* block, IR::Reg variable) { @@ -112,7 +112,7 @@ struct DefTable { } std::array<ValueMap, IR::NUM_USER_PREDS> preds; - boost::container::flat_map<u32, ValueMap> goto_vars; + std::unordered_map<u32, ValueMap> goto_vars; ValueMap indirect_branch_var; ValueMap zero_flag; ValueMap sign_flag; @@ -295,8 +295,7 @@ private: return same; } - boost::container::flat_map<IR::Block*, boost::container::flat_map<Variant, IR::Inst*>> - incomplete_phis; + std::unordered_map<IR::Block*, std::map<Variant, IR::Inst*>> incomplete_phis; DefTable current_def; }; diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 6ed4b78f2..f0f450edb 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -442,6 +442,11 @@ void BufferCache<P>::UnbindComputeStorageBuffers() { template <class P> void BufferCache<P>::BindComputeStorageBuffer(size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset, bool is_written) { + if (ssbo_index >= channel_state->compute_storage_buffers.size()) [[unlikely]] { + LOG_ERROR(HW_GPU, "Storage buffer index {} exceeds maximum storage buffer count", + ssbo_index); + return; + } channel_state->enabled_compute_storage_buffers |= 1U << ssbo_index; channel_state->written_compute_storage_buffers |= (is_written ? 1U : 0U) << ssbo_index; @@ -464,6 +469,11 @@ void BufferCache<P>::UnbindComputeTextureBuffers() { template <class P> void BufferCache<P>::BindComputeTextureBuffer(size_t tbo_index, GPUVAddr gpu_addr, u32 size, PixelFormat format, bool is_written, bool is_image) { + if (tbo_index >= channel_state->compute_texture_buffers.size()) [[unlikely]] { + LOG_ERROR(HW_GPU, "Texture buffer index {} exceeds maximum texture buffer count", + tbo_index); + return; + } channel_state->enabled_compute_texture_buffers |= 1U << tbo_index; channel_state->written_compute_texture_buffers |= (is_written ? 1U : 0U) << tbo_index; if constexpr (SEPARATE_IMAGE_BUFFERS_BINDINGS) { diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index 460fc7551..0b7135d49 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -67,7 +67,7 @@ constexpr u32 NUM_TRANSFORM_FEEDBACK_BUFFERS = 4; constexpr u32 NUM_GRAPHICS_UNIFORM_BUFFERS = 18; constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8; constexpr u32 NUM_STORAGE_BUFFERS = 16; -constexpr u32 NUM_TEXTURE_BUFFERS = 16; +constexpr u32 NUM_TEXTURE_BUFFERS = 32; constexpr u32 NUM_STAGES = 5; using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>; diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h index 1528cc1dd..7047e2e63 100644 --- a/src/video_core/query_cache.h +++ b/src/video_core/query_cache.h @@ -103,7 +103,9 @@ public: explicit QueryCacheBase(VideoCore::RasterizerInterface& rasterizer_, Core::Memory::Memory& cpu_memory_) : rasterizer{rasterizer_}, - cpu_memory{cpu_memory_}, streams{{CounterStream{static_cast<QueryCache&>(*this), + // Use reinterpret_cast instead of static_cast as workaround for + // UBSan bug (https://github.com/llvm/llvm-project/issues/59060) + cpu_memory{cpu_memory_}, streams{{CounterStream{reinterpret_cast<QueryCache&>(*this), VideoCore::QueryType::SamplesPassed}}} { (void)slot_async_jobs.insert(); // Null value } diff --git a/src/video_core/rasterizer_accelerated.cpp b/src/video_core/rasterizer_accelerated.cpp index 4a197d65d..f200a650f 100644 --- a/src/video_core/rasterizer_accelerated.cpp +++ b/src/video_core/rasterizer_accelerated.cpp @@ -13,7 +13,8 @@ namespace VideoCore { using namespace Core::Memory; -RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_) : cpu_memory{cpu_memory_} {} +RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_) + : cached_pages(std::make_unique<CachedPages>()), cpu_memory{cpu_memory_} {} RasterizerAccelerated::~RasterizerAccelerated() = default; @@ -26,7 +27,7 @@ void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int del std::atomic_thread_fence(std::memory_order_acquire); const u64 page_end = Common::DivCeil(addr + size, YUZU_PAGESIZE); for (u64 page = addr >> YUZU_PAGEBITS; page != page_end; ++page) { - std::atomic_uint16_t& count = cached_pages.at(page >> 2).Count(page); + std::atomic_uint16_t& count = cached_pages->at(page >> 2).Count(page); if (delta > 0) { ASSERT_MSG(count.load(std::memory_order::relaxed) < UINT16_MAX, "Count may overflow!"); diff --git a/src/video_core/rasterizer_accelerated.h b/src/video_core/rasterizer_accelerated.h index 7118b8aff..e6c0ea87a 100644 --- a/src/video_core/rasterizer_accelerated.h +++ b/src/video_core/rasterizer_accelerated.h @@ -41,7 +41,8 @@ private: }; static_assert(sizeof(CacheEntry) == 8, "CacheEntry should be 8 bytes!"); - std::array<CacheEntry, 0x2000000> cached_pages; + using CachedPages = std::array<CacheEntry, 0x2000000>; + std::unique_ptr<CachedPages> cached_pages; Core::Memory::Memory& cpu_memory; }; diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp index 2d3f58201..4002fa72b 100644 --- a/src/video_core/renderer_base.cpp +++ b/src/video_core/renderer_base.cpp @@ -38,8 +38,8 @@ void RendererBase::RequestScreenshot(void* data, std::function<void(bool)> callb LOG_ERROR(Render, "A screenshot is already requested or in progress, ignoring the request"); return; } - auto async_callback{[callback = std::move(callback)](bool invert_y) { - std::thread t{callback, invert_y}; + auto async_callback{[callback_ = std::move(callback)](bool invert_y) { + std::thread t{callback_, invert_y}; t.detach(); }}; renderer_settings.screenshot_bits = data; diff --git a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp index 23a48c6fe..71f720c63 100644 --- a/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_graphics_pipeline.cpp @@ -231,24 +231,25 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c } const bool in_parallel = thread_worker != nullptr; const auto backend = device.GetShaderBackend(); - auto func{[this, sources = std::move(sources), sources_spirv = std::move(sources_spirv), + auto func{[this, sources_ = std::move(sources), sources_spirv_ = std::move(sources_spirv), shader_notify, backend, in_parallel, force_context_flush](ShaderContext::Context*) mutable { for (size_t stage = 0; stage < 5; ++stage) { switch (backend) { case Settings::ShaderBackend::GLSL: - if (!sources[stage].empty()) { - source_programs[stage] = CreateProgram(sources[stage], Stage(stage)); + if (!sources_[stage].empty()) { + source_programs[stage] = CreateProgram(sources_[stage], Stage(stage)); } break; case Settings::ShaderBackend::GLASM: - if (!sources[stage].empty()) { - assembly_programs[stage] = CompileProgram(sources[stage], AssemblyStage(stage)); + if (!sources_[stage].empty()) { + assembly_programs[stage] = + CompileProgram(sources_[stage], AssemblyStage(stage)); } break; case Settings::ShaderBackend::SPIRV: - if (!sources_spirv[stage].empty()) { - source_programs[stage] = CreateProgram(sources_spirv[stage], Stage(stage)); + if (!sources_spirv_[stage].empty()) { + source_programs[stage] = CreateProgram(sources_spirv_[stage], Stage(stage)); } break; } diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 0329ed820..7e1d7f92e 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -288,9 +288,9 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, const auto load_compute{[&](std::ifstream& file, FileEnvironment env) { ComputePipelineKey key; file.read(reinterpret_cast<char*>(&key), sizeof(key)); - queue_work([this, key, env = std::move(env), &state, &callback](Context* ctx) mutable { + queue_work([this, key, env_ = std::move(env), &state, &callback](Context* ctx) mutable { ctx->pools.ReleaseContents(); - auto pipeline{CreateComputePipeline(ctx->pools, key, env, true)}; + auto pipeline{CreateComputePipeline(ctx->pools, key, env_, true)}; std::scoped_lock lock{state.mutex}; if (pipeline) { compute_cache.emplace(key, std::move(pipeline)); @@ -305,9 +305,9 @@ void ShaderCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading, const auto load_graphics{[&](std::ifstream& file, std::vector<FileEnvironment> envs) { GraphicsPipelineKey key; file.read(reinterpret_cast<char*>(&key), sizeof(key)); - queue_work([this, key, envs = std::move(envs), &state, &callback](Context* ctx) mutable { + queue_work([this, key, envs_ = std::move(envs), &state, &callback](Context* ctx) mutable { boost::container::static_vector<Shader::Environment*, 5> env_ptrs; - for (auto& env : envs) { + for (auto& env : envs_) { env_ptrs.push_back(&env); } ctx->pools.ReleaseContents(); diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 51df18ec3..f8cd2a5d8 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -206,8 +206,8 @@ public: const size_t sub_first_offset = static_cast<size_t>(first % 4) * GetQuadsNum(num_indices); const size_t offset = (sub_first_offset + GetQuadsNum(first)) * 6ULL * BytesPerIndex(index_type); - scheduler.Record([buffer = *buffer, index_type_, offset](vk::CommandBuffer cmdbuf) { - cmdbuf.BindIndexBuffer(buffer, offset, index_type_); + scheduler.Record([buffer_ = *buffer, index_type_, offset](vk::CommandBuffer cmdbuf) { + cmdbuf.BindIndexBuffer(buffer_, offset, index_type_); }); } @@ -528,17 +528,18 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bi buffer_handles.push_back(handle); } if (device.IsExtExtendedDynamicStateSupported()) { - scheduler.Record([bindings = std::move(bindings), - buffer_handles = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { - cmdbuf.BindVertexBuffers2EXT( - bindings.min_index, bindings.max_index - bindings.min_index, buffer_handles.data(), - bindings.offsets.data(), bindings.sizes.data(), bindings.strides.data()); + scheduler.Record([bindings_ = std::move(bindings), + buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { + cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, + bindings_.max_index - bindings_.min_index, + buffer_handles_.data(), bindings_.offsets.data(), + bindings_.sizes.data(), bindings_.strides.data()); }); } else { - scheduler.Record([bindings = std::move(bindings), - buffer_handles = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { - cmdbuf.BindVertexBuffers(bindings.min_index, bindings.max_index - bindings.min_index, - buffer_handles.data(), bindings.offsets.data()); + scheduler.Record([bindings_ = std::move(bindings), + buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { + cmdbuf.BindVertexBuffers(bindings_.min_index, bindings_.max_index - bindings_.min_index, + buffer_handles_.data(), bindings_.offsets.data()); }); } } @@ -573,11 +574,11 @@ void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings< for (u32 index = 0; index < bindings.buffers.size(); ++index) { buffer_handles.push_back(bindings.buffers[index]->Handle()); } - scheduler.Record([bindings = std::move(bindings), - buffer_handles = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { - cmdbuf.BindTransformFeedbackBuffersEXT(0, static_cast<u32>(buffer_handles.size()), - buffer_handles.data(), bindings.offsets.data(), - bindings.sizes.data()); + scheduler.Record([bindings_ = std::move(bindings), + buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { + cmdbuf.BindTransformFeedbackBuffersEXT(0, static_cast<u32>(buffer_handles_.size()), + buffer_handles_.data(), bindings_.offsets.data(), + bindings_.sizes.data()); }); } diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index d600c4e61..4f84d8497 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -469,9 +469,9 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading ComputePipelineCacheKey key; file.read(reinterpret_cast<char*>(&key), sizeof(key)); - workers.QueueWork([this, key, env = std::move(env), &state, &callback]() mutable { + workers.QueueWork([this, key, env_ = std::move(env), &state, &callback]() mutable { ShaderPools pools; - auto pipeline{CreateComputePipeline(pools, key, env, state.statistics.get(), false)}; + auto pipeline{CreateComputePipeline(pools, key, env_, state.statistics.get(), false)}; std::scoped_lock lock{state.mutex}; if (pipeline) { compute_cache.emplace(key, std::move(pipeline)); @@ -500,10 +500,10 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading (key.state.dynamic_vertex_input != 0) != dynamic_features.has_dynamic_vertex_input) { return; } - workers.QueueWork([this, key, envs = std::move(envs), &state, &callback]() mutable { + workers.QueueWork([this, key, envs_ = std::move(envs), &state, &callback]() mutable { ShaderPools pools; boost::container::static_vector<Shader::Environment*, 5> env_ptrs; - for (auto& env : envs) { + for (auto& env : envs_) { env_ptrs.push_back(&env); } auto pipeline{CreateGraphicsPipeline(pools, key, MakeSpan(env_ptrs), @@ -702,8 +702,8 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline( if (!pipeline || pipeline_cache_filename.empty()) { return pipeline; } - serialization_thread.QueueWork([this, key, env = std::move(env)] { - SerializePipeline(key, std::array<const GenericEnvironment*, 1>{&env}, + serialization_thread.QueueWork([this, key, env_ = std::move(env)] { + SerializePipeline(key, std::array<const GenericEnvironment*, 1>{&env_}, pipeline_cache_filename, CACHE_VERSION); }); return pipeline; diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index d67490449..29e0b797b 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -98,10 +98,10 @@ HostCounter::HostCounter(QueryCache& cache_, std::shared_ptr<HostCounter> depend : HostCounterBase{std::move(dependency_)}, cache{cache_}, type{type_}, query{cache_.AllocateQuery(type_)}, tick{cache_.GetScheduler().CurrentTick()} { const vk::Device* logical = &cache.GetDevice().GetLogical(); - cache.GetScheduler().Record([logical, query = query](vk::CommandBuffer cmdbuf) { + cache.GetScheduler().Record([logical, query_ = query](vk::CommandBuffer cmdbuf) { const bool use_precise = Settings::IsGPULevelHigh(); - logical->ResetQueryPool(query.first, query.second, 1); - cmdbuf.BeginQuery(query.first, query.second, + logical->ResetQueryPool(query_.first, query_.second, 1); + cmdbuf.BeginQuery(query_.first, query_.second, use_precise ? VK_QUERY_CONTROL_PRECISE_BIT : 0); }); } @@ -111,8 +111,9 @@ HostCounter::~HostCounter() { } void HostCounter::EndQuery() { - cache.GetScheduler().Record( - [query = query](vk::CommandBuffer cmdbuf) { cmdbuf.EndQuery(query.first, query.second); }); + cache.GetScheduler().Record([query_ = query](vk::CommandBuffer cmdbuf) { + cmdbuf.EndQuery(query_.first, query_.second); + }); } u64 HostCounter::BlockingQuery(bool async) const { diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 3aac3cfab..bf6ad6c79 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1412,7 +1412,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<VkDeviceS } scheduler->RequestOutsideRenderPassOperationContext(); scheduler->Record([buffers = std::move(buffers_vector), image = *original_image, - aspect_mask = aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) { + aspect_mask_ = aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) { const VkImageMemoryBarrier read_barrier{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .pNext = nullptr, @@ -1424,7 +1424,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<VkDeviceS .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = image, .subresourceRange{ - .aspectMask = aspect_mask, + .aspectMask = aspect_mask_, .baseMipLevel = 0, .levelCount = VK_REMAINING_MIP_LEVELS, .baseArrayLayer = 0, @@ -1456,7 +1456,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<VkDeviceS .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, .image = image, .subresourceRange{ - .aspectMask = aspect_mask, + .aspectMask = aspect_mask_, .baseMipLevel = 0, .levelCount = VK_REMAINING_MIP_LEVELS, .baseArrayLayer = 0, diff --git a/src/web_service/announce_room_json.cpp b/src/web_service/announce_room_json.cpp index 4c3195efd..f1020a5b8 100644 --- a/src/web_service/announce_room_json.cpp +++ b/src/web_service/announce_room_json.cpp @@ -135,11 +135,11 @@ void RoomJson::Delete() { LOG_ERROR(WebService, "Room must be registered to be deleted"); return; } - Common::DetachedTasks::AddTask( - [host{this->host}, username{this->username}, token{this->token}, room_id{this->room_id}]() { - // create a new client here because the this->client might be destroyed. - Client{host, username, token}.DeleteJson(fmt::format("/lobby/{}", room_id), "", false); - }); + Common::DetachedTasks::AddTask([host_{this->host}, username_{this->username}, + token_{this->token}, room_id_{this->room_id}]() { + // create a new client here because the this->client might be destroyed. + Client{host_, username_, token_}.DeleteJson(fmt::format("/lobby/{}", room_id_), "", false); + }); } } // namespace WebService diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 63326968b..9404365b4 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -235,7 +235,7 @@ GameListWorker::~GameListWorker() = default; void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { using namespace FileSys; - const auto& cache = dynamic_cast<ContentProviderUnion&>(system.GetContentProvider()); + const auto& cache = system.GetContentProviderUnion(); auto installed_games = cache.ListEntriesFilterOrigin(std::nullopt, TitleType::Application, ContentRecordType::Program); @@ -265,7 +265,11 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { std::vector<u8> icon; std::string name; u64 program_id = 0; - loader->ReadProgramId(program_id); + const auto result = loader->ReadProgramId(program_id); + + if (result != Loader::ResultStatus::Success) { + continue; + } const PatchManager patch{program_id, system.GetFileSystemController(), system.GetContentProvider()}; |