1*9e3b08aeSAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 2*9e3b08aeSAndroid Build Coastguard Worker // -*- mode: C++ -*- 3*9e3b08aeSAndroid Build Coastguard Worker // 4*9e3b08aeSAndroid Build Coastguard Worker // Copyright 2020-2024 Google LLC 5*9e3b08aeSAndroid Build Coastguard Worker // 6*9e3b08aeSAndroid Build Coastguard Worker // Licensed under the Apache License v2.0 with LLVM Exceptions (the 7*9e3b08aeSAndroid Build Coastguard Worker // "License"); you may not use this file except in compliance with the 8*9e3b08aeSAndroid Build Coastguard Worker // License. You may obtain a copy of the License at 9*9e3b08aeSAndroid Build Coastguard Worker // 10*9e3b08aeSAndroid Build Coastguard Worker // https://llvm.org/LICENSE.txt 11*9e3b08aeSAndroid Build Coastguard Worker // 12*9e3b08aeSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 13*9e3b08aeSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 14*9e3b08aeSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15*9e3b08aeSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 16*9e3b08aeSAndroid Build Coastguard Worker // limitations under the License. 17*9e3b08aeSAndroid Build Coastguard Worker // 18*9e3b08aeSAndroid Build Coastguard Worker // Author: Maria Teguiani 19*9e3b08aeSAndroid Build Coastguard Worker // Author: Giuliano Procida 20*9e3b08aeSAndroid Build Coastguard Worker // Author: Ignes Simeonova 21*9e3b08aeSAndroid Build Coastguard Worker 22*9e3b08aeSAndroid Build Coastguard Worker #ifndef STG_GRAPH_H_ 23*9e3b08aeSAndroid Build Coastguard Worker #define STG_GRAPH_H_ 24*9e3b08aeSAndroid Build Coastguard Worker 25*9e3b08aeSAndroid Build Coastguard Worker #include <cstddef> 26*9e3b08aeSAndroid Build Coastguard Worker #include <cstdint> 27*9e3b08aeSAndroid Build Coastguard Worker #include <exception> 28*9e3b08aeSAndroid Build Coastguard Worker #include <functional> 29*9e3b08aeSAndroid Build Coastguard Worker #include <map> 30*9e3b08aeSAndroid Build Coastguard Worker #include <optional> 31*9e3b08aeSAndroid Build Coastguard Worker #include <ostream> 32*9e3b08aeSAndroid Build Coastguard Worker #include <sstream> 33*9e3b08aeSAndroid Build Coastguard Worker #include <string> 34*9e3b08aeSAndroid Build Coastguard Worker #include <type_traits> 35*9e3b08aeSAndroid Build Coastguard Worker #include <utility> 36*9e3b08aeSAndroid Build Coastguard Worker #include <vector> 37*9e3b08aeSAndroid Build Coastguard Worker 38*9e3b08aeSAndroid Build Coastguard Worker #include "error.h" 39*9e3b08aeSAndroid Build Coastguard Worker 40*9e3b08aeSAndroid Build Coastguard Worker namespace stg { 41*9e3b08aeSAndroid Build Coastguard Worker 42*9e3b08aeSAndroid Build Coastguard Worker // A wrapped (for type safety) array index. 43*9e3b08aeSAndroid Build Coastguard Worker struct Id { 44*9e3b08aeSAndroid Build Coastguard Worker // defined in graph.cc as maximum value for index type 45*9e3b08aeSAndroid Build Coastguard Worker static const Id kInvalid; IdId46*9e3b08aeSAndroid Build Coastguard Worker explicit Id(size_t ix) : ix_(ix) {} 47*9e3b08aeSAndroid Build Coastguard Worker auto operator<=>(const Id&) const = default; 48*9e3b08aeSAndroid Build Coastguard Worker size_t ix_; 49*9e3b08aeSAndroid Build Coastguard Worker }; 50*9e3b08aeSAndroid Build Coastguard Worker 51*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, Id id); 52*9e3b08aeSAndroid Build Coastguard Worker 53*9e3b08aeSAndroid Build Coastguard Worker using Pair = std::pair<Id, Id>; 54*9e3b08aeSAndroid Build Coastguard Worker 55*9e3b08aeSAndroid Build Coastguard Worker } // namespace stg 56*9e3b08aeSAndroid Build Coastguard Worker 57*9e3b08aeSAndroid Build Coastguard Worker namespace std { 58*9e3b08aeSAndroid Build Coastguard Worker 59*9e3b08aeSAndroid Build Coastguard Worker template <> 60*9e3b08aeSAndroid Build Coastguard Worker struct hash<stg::Id> { 61*9e3b08aeSAndroid Build Coastguard Worker size_t operator()(const stg::Id& id) const { 62*9e3b08aeSAndroid Build Coastguard Worker return hash<decltype(id.ix_)>()(id.ix_); 63*9e3b08aeSAndroid Build Coastguard Worker } 64*9e3b08aeSAndroid Build Coastguard Worker }; 65*9e3b08aeSAndroid Build Coastguard Worker 66*9e3b08aeSAndroid Build Coastguard Worker template <> 67*9e3b08aeSAndroid Build Coastguard Worker struct hash<stg::Pair> { 68*9e3b08aeSAndroid Build Coastguard Worker size_t operator()(const stg::Pair& comparison) const { 69*9e3b08aeSAndroid Build Coastguard Worker const hash<stg::Id> h; 70*9e3b08aeSAndroid Build Coastguard Worker auto h1 = h(comparison.first); 71*9e3b08aeSAndroid Build Coastguard Worker auto h2 = h(comparison.second); 72*9e3b08aeSAndroid Build Coastguard Worker // assumes 64-bit size_t, would be better if std::hash_combine existed 73*9e3b08aeSAndroid Build Coastguard Worker return h1 ^ (h2 + 0x9e3779b97f4a7c15 + (h1 << 12) + (h1 >> 4)); 74*9e3b08aeSAndroid Build Coastguard Worker } 75*9e3b08aeSAndroid Build Coastguard Worker }; 76*9e3b08aeSAndroid Build Coastguard Worker 77*9e3b08aeSAndroid Build Coastguard Worker } // namespace std 78*9e3b08aeSAndroid Build Coastguard Worker 79*9e3b08aeSAndroid Build Coastguard Worker namespace stg { 80*9e3b08aeSAndroid Build Coastguard Worker 81*9e3b08aeSAndroid Build Coastguard Worker struct Special { 82*9e3b08aeSAndroid Build Coastguard Worker enum class Kind { 83*9e3b08aeSAndroid Build Coastguard Worker VOID, 84*9e3b08aeSAndroid Build Coastguard Worker VARIADIC, 85*9e3b08aeSAndroid Build Coastguard Worker NULLPTR, 86*9e3b08aeSAndroid Build Coastguard Worker }; 87*9e3b08aeSAndroid Build Coastguard Worker explicit Special(Kind kind) 88*9e3b08aeSAndroid Build Coastguard Worker : kind(kind) {} 89*9e3b08aeSAndroid Build Coastguard Worker 90*9e3b08aeSAndroid Build Coastguard Worker Kind kind; 91*9e3b08aeSAndroid Build Coastguard Worker }; 92*9e3b08aeSAndroid Build Coastguard Worker 93*9e3b08aeSAndroid Build Coastguard Worker struct PointerReference { 94*9e3b08aeSAndroid Build Coastguard Worker enum class Kind { 95*9e3b08aeSAndroid Build Coastguard Worker POINTER, 96*9e3b08aeSAndroid Build Coastguard Worker LVALUE_REFERENCE, 97*9e3b08aeSAndroid Build Coastguard Worker RVALUE_REFERENCE, 98*9e3b08aeSAndroid Build Coastguard Worker }; 99*9e3b08aeSAndroid Build Coastguard Worker PointerReference(Kind kind, Id pointee_type_id) 100*9e3b08aeSAndroid Build Coastguard Worker : kind(kind), pointee_type_id(pointee_type_id) {} 101*9e3b08aeSAndroid Build Coastguard Worker 102*9e3b08aeSAndroid Build Coastguard Worker Kind kind; 103*9e3b08aeSAndroid Build Coastguard Worker Id pointee_type_id; 104*9e3b08aeSAndroid Build Coastguard Worker }; 105*9e3b08aeSAndroid Build Coastguard Worker 106*9e3b08aeSAndroid Build Coastguard Worker struct PointerToMember { 107*9e3b08aeSAndroid Build Coastguard Worker PointerToMember(Id containing_type_id, Id pointee_type_id) 108*9e3b08aeSAndroid Build Coastguard Worker : containing_type_id(containing_type_id), pointee_type_id(pointee_type_id) 109*9e3b08aeSAndroid Build Coastguard Worker {} 110*9e3b08aeSAndroid Build Coastguard Worker 111*9e3b08aeSAndroid Build Coastguard Worker Id containing_type_id; 112*9e3b08aeSAndroid Build Coastguard Worker Id pointee_type_id; 113*9e3b08aeSAndroid Build Coastguard Worker }; 114*9e3b08aeSAndroid Build Coastguard Worker 115*9e3b08aeSAndroid Build Coastguard Worker struct Typedef { 116*9e3b08aeSAndroid Build Coastguard Worker Typedef(const std::string& name, Id referred_type_id) 117*9e3b08aeSAndroid Build Coastguard Worker : name(name), referred_type_id(referred_type_id) {} 118*9e3b08aeSAndroid Build Coastguard Worker 119*9e3b08aeSAndroid Build Coastguard Worker std::string name; 120*9e3b08aeSAndroid Build Coastguard Worker Id referred_type_id; 121*9e3b08aeSAndroid Build Coastguard Worker }; 122*9e3b08aeSAndroid Build Coastguard Worker 123*9e3b08aeSAndroid Build Coastguard Worker enum class Qualifier { CONST, VOLATILE, RESTRICT, ATOMIC }; 124*9e3b08aeSAndroid Build Coastguard Worker 125*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, Qualifier qualifier); 126*9e3b08aeSAndroid Build Coastguard Worker 127*9e3b08aeSAndroid Build Coastguard Worker struct Qualified { 128*9e3b08aeSAndroid Build Coastguard Worker Qualified(Qualifier qualifier, Id qualified_type_id) 129*9e3b08aeSAndroid Build Coastguard Worker : qualifier(qualifier), qualified_type_id(qualified_type_id) {} 130*9e3b08aeSAndroid Build Coastguard Worker 131*9e3b08aeSAndroid Build Coastguard Worker Qualifier qualifier; 132*9e3b08aeSAndroid Build Coastguard Worker Id qualified_type_id; 133*9e3b08aeSAndroid Build Coastguard Worker }; 134*9e3b08aeSAndroid Build Coastguard Worker 135*9e3b08aeSAndroid Build Coastguard Worker struct Primitive { 136*9e3b08aeSAndroid Build Coastguard Worker enum class Encoding { 137*9e3b08aeSAndroid Build Coastguard Worker BOOLEAN, 138*9e3b08aeSAndroid Build Coastguard Worker SIGNED_INTEGER, 139*9e3b08aeSAndroid Build Coastguard Worker UNSIGNED_INTEGER, 140*9e3b08aeSAndroid Build Coastguard Worker SIGNED_CHARACTER, 141*9e3b08aeSAndroid Build Coastguard Worker UNSIGNED_CHARACTER, 142*9e3b08aeSAndroid Build Coastguard Worker REAL_NUMBER, 143*9e3b08aeSAndroid Build Coastguard Worker COMPLEX_NUMBER, 144*9e3b08aeSAndroid Build Coastguard Worker UTF, 145*9e3b08aeSAndroid Build Coastguard Worker }; 146*9e3b08aeSAndroid Build Coastguard Worker Primitive(const std::string& name, std::optional<Encoding> encoding, 147*9e3b08aeSAndroid Build Coastguard Worker uint32_t bytesize) 148*9e3b08aeSAndroid Build Coastguard Worker : name(name), encoding(encoding), bytesize(bytesize) {} 149*9e3b08aeSAndroid Build Coastguard Worker 150*9e3b08aeSAndroid Build Coastguard Worker std::string name; 151*9e3b08aeSAndroid Build Coastguard Worker std::optional<Encoding> encoding; 152*9e3b08aeSAndroid Build Coastguard Worker uint32_t bytesize; 153*9e3b08aeSAndroid Build Coastguard Worker }; 154*9e3b08aeSAndroid Build Coastguard Worker 155*9e3b08aeSAndroid Build Coastguard Worker struct Array { 156*9e3b08aeSAndroid Build Coastguard Worker Array(uint64_t number_of_elements, Id element_type_id) 157*9e3b08aeSAndroid Build Coastguard Worker : number_of_elements(number_of_elements), 158*9e3b08aeSAndroid Build Coastguard Worker element_type_id(element_type_id) {} 159*9e3b08aeSAndroid Build Coastguard Worker 160*9e3b08aeSAndroid Build Coastguard Worker uint64_t number_of_elements; 161*9e3b08aeSAndroid Build Coastguard Worker Id element_type_id; 162*9e3b08aeSAndroid Build Coastguard Worker }; 163*9e3b08aeSAndroid Build Coastguard Worker 164*9e3b08aeSAndroid Build Coastguard Worker struct BaseClass { 165*9e3b08aeSAndroid Build Coastguard Worker enum class Inheritance { NON_VIRTUAL, VIRTUAL }; 166*9e3b08aeSAndroid Build Coastguard Worker BaseClass(Id type_id, uint64_t offset, Inheritance inheritance) 167*9e3b08aeSAndroid Build Coastguard Worker : type_id(type_id), offset(offset), inheritance(inheritance) {} 168*9e3b08aeSAndroid Build Coastguard Worker 169*9e3b08aeSAndroid Build Coastguard Worker Id type_id; 170*9e3b08aeSAndroid Build Coastguard Worker uint64_t offset; 171*9e3b08aeSAndroid Build Coastguard Worker Inheritance inheritance; 172*9e3b08aeSAndroid Build Coastguard Worker }; 173*9e3b08aeSAndroid Build Coastguard Worker 174*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, BaseClass::Inheritance inheritance); 175*9e3b08aeSAndroid Build Coastguard Worker 176*9e3b08aeSAndroid Build Coastguard Worker struct Method { 177*9e3b08aeSAndroid Build Coastguard Worker Method(const std::string& mangled_name, const std::string& name, 178*9e3b08aeSAndroid Build Coastguard Worker uint64_t vtable_offset, Id type_id) 179*9e3b08aeSAndroid Build Coastguard Worker : mangled_name(mangled_name), name(name), 180*9e3b08aeSAndroid Build Coastguard Worker vtable_offset(vtable_offset), type_id(type_id) {} 181*9e3b08aeSAndroid Build Coastguard Worker 182*9e3b08aeSAndroid Build Coastguard Worker std::string mangled_name; 183*9e3b08aeSAndroid Build Coastguard Worker std::string name; 184*9e3b08aeSAndroid Build Coastguard Worker uint64_t vtable_offset; 185*9e3b08aeSAndroid Build Coastguard Worker Id type_id; 186*9e3b08aeSAndroid Build Coastguard Worker }; 187*9e3b08aeSAndroid Build Coastguard Worker 188*9e3b08aeSAndroid Build Coastguard Worker struct Member { 189*9e3b08aeSAndroid Build Coastguard Worker Member(const std::string& name, Id type_id, uint64_t offset, uint64_t bitsize) 190*9e3b08aeSAndroid Build Coastguard Worker : name(name), type_id(type_id), offset(offset), bitsize(bitsize) {} 191*9e3b08aeSAndroid Build Coastguard Worker 192*9e3b08aeSAndroid Build Coastguard Worker std::string name; 193*9e3b08aeSAndroid Build Coastguard Worker Id type_id; 194*9e3b08aeSAndroid Build Coastguard Worker uint64_t offset; 195*9e3b08aeSAndroid Build Coastguard Worker uint64_t bitsize; 196*9e3b08aeSAndroid Build Coastguard Worker }; 197*9e3b08aeSAndroid Build Coastguard Worker 198*9e3b08aeSAndroid Build Coastguard Worker struct VariantMember { 199*9e3b08aeSAndroid Build Coastguard Worker VariantMember(const std::string& name, 200*9e3b08aeSAndroid Build Coastguard Worker std::optional<int64_t> discriminant_value, Id type_id) 201*9e3b08aeSAndroid Build Coastguard Worker : name(name), discriminant_value(discriminant_value), type_id(type_id) {} 202*9e3b08aeSAndroid Build Coastguard Worker 203*9e3b08aeSAndroid Build Coastguard Worker std::string name; 204*9e3b08aeSAndroid Build Coastguard Worker std::optional<int64_t> discriminant_value; 205*9e3b08aeSAndroid Build Coastguard Worker Id type_id; 206*9e3b08aeSAndroid Build Coastguard Worker }; 207*9e3b08aeSAndroid Build Coastguard Worker 208*9e3b08aeSAndroid Build Coastguard Worker struct StructUnion { 209*9e3b08aeSAndroid Build Coastguard Worker enum class Kind { STRUCT, UNION }; 210*9e3b08aeSAndroid Build Coastguard Worker struct Definition { 211*9e3b08aeSAndroid Build Coastguard Worker uint64_t bytesize; 212*9e3b08aeSAndroid Build Coastguard Worker std::vector<Id> base_classes; 213*9e3b08aeSAndroid Build Coastguard Worker std::vector<Id> methods; 214*9e3b08aeSAndroid Build Coastguard Worker std::vector<Id> members; 215*9e3b08aeSAndroid Build Coastguard Worker }; 216*9e3b08aeSAndroid Build Coastguard Worker StructUnion(Kind kind, const std::string& name) : kind(kind), name(name) {} 217*9e3b08aeSAndroid Build Coastguard Worker StructUnion(Kind kind, const std::string& name, uint64_t bytesize, 218*9e3b08aeSAndroid Build Coastguard Worker const std::vector<Id>& base_classes, 219*9e3b08aeSAndroid Build Coastguard Worker const std::vector<Id>& methods, const std::vector<Id>& members) 220*9e3b08aeSAndroid Build Coastguard Worker : kind(kind), name(name), 221*9e3b08aeSAndroid Build Coastguard Worker definition({bytesize, base_classes, methods, members}) {} 222*9e3b08aeSAndroid Build Coastguard Worker 223*9e3b08aeSAndroid Build Coastguard Worker Kind kind; 224*9e3b08aeSAndroid Build Coastguard Worker std::string name; 225*9e3b08aeSAndroid Build Coastguard Worker std::optional<Definition> definition; 226*9e3b08aeSAndroid Build Coastguard Worker }; 227*9e3b08aeSAndroid Build Coastguard Worker 228*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, StructUnion::Kind kind); 229*9e3b08aeSAndroid Build Coastguard Worker std::string& operator+=(std::string& os, StructUnion::Kind kind); 230*9e3b08aeSAndroid Build Coastguard Worker 231*9e3b08aeSAndroid Build Coastguard Worker struct Enumeration { 232*9e3b08aeSAndroid Build Coastguard Worker using Enumerators = std::vector<std::pair<std::string, int64_t>>; 233*9e3b08aeSAndroid Build Coastguard Worker struct Definition { 234*9e3b08aeSAndroid Build Coastguard Worker Id underlying_type_id; 235*9e3b08aeSAndroid Build Coastguard Worker Enumerators enumerators; 236*9e3b08aeSAndroid Build Coastguard Worker }; 237*9e3b08aeSAndroid Build Coastguard Worker explicit Enumeration(const std::string& name) : name(name) {} 238*9e3b08aeSAndroid Build Coastguard Worker Enumeration(const std::string& name, Id underlying_type_id, 239*9e3b08aeSAndroid Build Coastguard Worker const Enumerators& enumerators) 240*9e3b08aeSAndroid Build Coastguard Worker : name(name), definition({underlying_type_id, enumerators}) {} 241*9e3b08aeSAndroid Build Coastguard Worker 242*9e3b08aeSAndroid Build Coastguard Worker std::string name; 243*9e3b08aeSAndroid Build Coastguard Worker std::optional<Definition> definition; 244*9e3b08aeSAndroid Build Coastguard Worker }; 245*9e3b08aeSAndroid Build Coastguard Worker 246*9e3b08aeSAndroid Build Coastguard Worker struct Variant { 247*9e3b08aeSAndroid Build Coastguard Worker Variant(const std::string& name, uint64_t bytesize, 248*9e3b08aeSAndroid Build Coastguard Worker std::optional<Id> discriminant, const std::vector<Id>& members) 249*9e3b08aeSAndroid Build Coastguard Worker : name(name), 250*9e3b08aeSAndroid Build Coastguard Worker bytesize(bytesize), 251*9e3b08aeSAndroid Build Coastguard Worker discriminant(discriminant), 252*9e3b08aeSAndroid Build Coastguard Worker members(members) {} 253*9e3b08aeSAndroid Build Coastguard Worker 254*9e3b08aeSAndroid Build Coastguard Worker std::string name; 255*9e3b08aeSAndroid Build Coastguard Worker uint64_t bytesize; 256*9e3b08aeSAndroid Build Coastguard Worker std::optional<Id> discriminant; 257*9e3b08aeSAndroid Build Coastguard Worker std::vector<Id> members; 258*9e3b08aeSAndroid Build Coastguard Worker }; 259*9e3b08aeSAndroid Build Coastguard Worker 260*9e3b08aeSAndroid Build Coastguard Worker struct Function { 261*9e3b08aeSAndroid Build Coastguard Worker Function(Id return_type_id, const std::vector<Id>& parameters) 262*9e3b08aeSAndroid Build Coastguard Worker : return_type_id(return_type_id), parameters(parameters) {} 263*9e3b08aeSAndroid Build Coastguard Worker 264*9e3b08aeSAndroid Build Coastguard Worker Id return_type_id; 265*9e3b08aeSAndroid Build Coastguard Worker std::vector<Id> parameters; 266*9e3b08aeSAndroid Build Coastguard Worker }; 267*9e3b08aeSAndroid Build Coastguard Worker 268*9e3b08aeSAndroid Build Coastguard Worker struct ElfSymbol { 269*9e3b08aeSAndroid Build Coastguard Worker enum class SymbolType { NOTYPE, OBJECT, FUNCTION, COMMON, TLS, GNU_IFUNC }; 270*9e3b08aeSAndroid Build Coastguard Worker enum class Binding { GLOBAL, LOCAL, WEAK, GNU_UNIQUE }; 271*9e3b08aeSAndroid Build Coastguard Worker enum class Visibility { DEFAULT, PROTECTED, HIDDEN, INTERNAL }; 272*9e3b08aeSAndroid Build Coastguard Worker struct VersionInfo { 273*9e3b08aeSAndroid Build Coastguard Worker auto operator<=>(const VersionInfo&) const = default; 274*9e3b08aeSAndroid Build Coastguard Worker bool is_default; 275*9e3b08aeSAndroid Build Coastguard Worker std::string name; 276*9e3b08aeSAndroid Build Coastguard Worker }; 277*9e3b08aeSAndroid Build Coastguard Worker struct CRC { 278*9e3b08aeSAndroid Build Coastguard Worker explicit CRC(uint32_t number) : number(number) {} 279*9e3b08aeSAndroid Build Coastguard Worker auto operator<=>(const CRC&) const = default; 280*9e3b08aeSAndroid Build Coastguard Worker uint32_t number; 281*9e3b08aeSAndroid Build Coastguard Worker }; 282*9e3b08aeSAndroid Build Coastguard Worker ElfSymbol(const std::string& symbol_name, 283*9e3b08aeSAndroid Build Coastguard Worker std::optional<VersionInfo> version_info, 284*9e3b08aeSAndroid Build Coastguard Worker bool is_defined, 285*9e3b08aeSAndroid Build Coastguard Worker SymbolType symbol_type, 286*9e3b08aeSAndroid Build Coastguard Worker Binding binding, 287*9e3b08aeSAndroid Build Coastguard Worker Visibility visibility, 288*9e3b08aeSAndroid Build Coastguard Worker std::optional<CRC> crc, 289*9e3b08aeSAndroid Build Coastguard Worker std::optional<std::string> ns, 290*9e3b08aeSAndroid Build Coastguard Worker std::optional<Id> type_id, 291*9e3b08aeSAndroid Build Coastguard Worker const std::optional<std::string>& full_name) 292*9e3b08aeSAndroid Build Coastguard Worker : symbol_name(symbol_name), 293*9e3b08aeSAndroid Build Coastguard Worker version_info(version_info), 294*9e3b08aeSAndroid Build Coastguard Worker is_defined(is_defined), 295*9e3b08aeSAndroid Build Coastguard Worker symbol_type(symbol_type), 296*9e3b08aeSAndroid Build Coastguard Worker binding(binding), 297*9e3b08aeSAndroid Build Coastguard Worker visibility(visibility), 298*9e3b08aeSAndroid Build Coastguard Worker crc(crc), 299*9e3b08aeSAndroid Build Coastguard Worker ns(ns), 300*9e3b08aeSAndroid Build Coastguard Worker type_id(type_id), 301*9e3b08aeSAndroid Build Coastguard Worker full_name(full_name) {} 302*9e3b08aeSAndroid Build Coastguard Worker 303*9e3b08aeSAndroid Build Coastguard Worker std::string symbol_name; 304*9e3b08aeSAndroid Build Coastguard Worker std::optional<VersionInfo> version_info; 305*9e3b08aeSAndroid Build Coastguard Worker bool is_defined; 306*9e3b08aeSAndroid Build Coastguard Worker SymbolType symbol_type; 307*9e3b08aeSAndroid Build Coastguard Worker Binding binding; 308*9e3b08aeSAndroid Build Coastguard Worker Visibility visibility; 309*9e3b08aeSAndroid Build Coastguard Worker std::optional<CRC> crc; 310*9e3b08aeSAndroid Build Coastguard Worker std::optional<std::string> ns; 311*9e3b08aeSAndroid Build Coastguard Worker std::optional<Id> type_id; 312*9e3b08aeSAndroid Build Coastguard Worker std::optional<std::string> full_name; 313*9e3b08aeSAndroid Build Coastguard Worker }; 314*9e3b08aeSAndroid Build Coastguard Worker 315*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, ElfSymbol::SymbolType); 316*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, ElfSymbol::Binding); 317*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, ElfSymbol::Visibility); 318*9e3b08aeSAndroid Build Coastguard Worker 319*9e3b08aeSAndroid Build Coastguard Worker std::string VersionInfoToString(const ElfSymbol::VersionInfo& version_info); 320*9e3b08aeSAndroid Build Coastguard Worker std::string VersionedSymbolName(const ElfSymbol&); 321*9e3b08aeSAndroid Build Coastguard Worker 322*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, ElfSymbol::CRC crc); 323*9e3b08aeSAndroid Build Coastguard Worker 324*9e3b08aeSAndroid Build Coastguard Worker struct Interface { 325*9e3b08aeSAndroid Build Coastguard Worker explicit Interface(const std::map<std::string, Id>& symbols) 326*9e3b08aeSAndroid Build Coastguard Worker : symbols(symbols) {} 327*9e3b08aeSAndroid Build Coastguard Worker Interface(const std::map<std::string, Id>& symbols, 328*9e3b08aeSAndroid Build Coastguard Worker const std::map<std::string, Id>& types) 329*9e3b08aeSAndroid Build Coastguard Worker : symbols(symbols), types(types) {} 330*9e3b08aeSAndroid Build Coastguard Worker 331*9e3b08aeSAndroid Build Coastguard Worker std::map<std::string, Id> symbols; 332*9e3b08aeSAndroid Build Coastguard Worker std::map<std::string, Id> types; 333*9e3b08aeSAndroid Build Coastguard Worker }; 334*9e3b08aeSAndroid Build Coastguard Worker 335*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, Primitive::Encoding encoding); 336*9e3b08aeSAndroid Build Coastguard Worker 337*9e3b08aeSAndroid Build Coastguard Worker // Concrete graph type. 338*9e3b08aeSAndroid Build Coastguard Worker class Graph { 339*9e3b08aeSAndroid Build Coastguard Worker public: 340*9e3b08aeSAndroid Build Coastguard Worker Id Limit() const { 341*9e3b08aeSAndroid Build Coastguard Worker return Id(indirection_.size()); 342*9e3b08aeSAndroid Build Coastguard Worker } 343*9e3b08aeSAndroid Build Coastguard Worker 344*9e3b08aeSAndroid Build Coastguard Worker bool Is(Id id) const { 345*9e3b08aeSAndroid Build Coastguard Worker return indirection_[id.ix_].first != Which::ABSENT; 346*9e3b08aeSAndroid Build Coastguard Worker } 347*9e3b08aeSAndroid Build Coastguard Worker 348*9e3b08aeSAndroid Build Coastguard Worker Id Allocate() { 349*9e3b08aeSAndroid Build Coastguard Worker const auto id = Limit(); 350*9e3b08aeSAndroid Build Coastguard Worker indirection_.emplace_back(Which::ABSENT, 0); 351*9e3b08aeSAndroid Build Coastguard Worker return id; 352*9e3b08aeSAndroid Build Coastguard Worker } 353*9e3b08aeSAndroid Build Coastguard Worker 354*9e3b08aeSAndroid Build Coastguard Worker template <typename Node, typename... Args> 355*9e3b08aeSAndroid Build Coastguard Worker void Set(Id id, Args&&... args) { 356*9e3b08aeSAndroid Build Coastguard Worker auto& reference = indirection_[id.ix_]; 357*9e3b08aeSAndroid Build Coastguard Worker if (reference.first != Which::ABSENT) { 358*9e3b08aeSAndroid Build Coastguard Worker Die() << "node value already set: " << id; 359*9e3b08aeSAndroid Build Coastguard Worker } 360*9e3b08aeSAndroid Build Coastguard Worker if constexpr (std::is_same_v<Node, Special>) { 361*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::SPECIAL, special_.size()}; 362*9e3b08aeSAndroid Build Coastguard Worker special_.emplace_back(std::forward<Args>(args)...); 363*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, PointerReference>) { 364*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::POINTER_REFERENCE, pointer_reference_.size()}; 365*9e3b08aeSAndroid Build Coastguard Worker pointer_reference_.emplace_back(std::forward<Args>(args)...); 366*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, PointerToMember>) { 367*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::POINTER_TO_MEMBER, pointer_to_member_.size()}; 368*9e3b08aeSAndroid Build Coastguard Worker pointer_to_member_.emplace_back(std::forward<Args>(args)...); 369*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, Typedef>) { 370*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::TYPEDEF, typedef_.size()}; 371*9e3b08aeSAndroid Build Coastguard Worker typedef_.emplace_back(std::forward<Args>(args)...); 372*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, Qualified>) { 373*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::QUALIFIED, qualified_.size()}; 374*9e3b08aeSAndroid Build Coastguard Worker qualified_.emplace_back(std::forward<Args>(args)...); 375*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, Primitive>) { 376*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::PRIMITIVE, primitive_.size()}; 377*9e3b08aeSAndroid Build Coastguard Worker primitive_.emplace_back(std::forward<Args>(args)...); 378*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, Array>) { 379*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::ARRAY, array_.size()}; 380*9e3b08aeSAndroid Build Coastguard Worker array_.emplace_back(std::forward<Args>(args)...); 381*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, BaseClass>) { 382*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::BASE_CLASS, base_class_.size()}; 383*9e3b08aeSAndroid Build Coastguard Worker base_class_.emplace_back(std::forward<Args>(args)...); 384*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, Method>) { 385*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::METHOD, method_.size()}; 386*9e3b08aeSAndroid Build Coastguard Worker method_.emplace_back(std::forward<Args>(args)...); 387*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, Member>) { 388*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::MEMBER, member_.size()}; 389*9e3b08aeSAndroid Build Coastguard Worker member_.emplace_back(std::forward<Args>(args)...); 390*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, VariantMember>) { 391*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::VARIANT_MEMBER, variant_member_.size()}; 392*9e3b08aeSAndroid Build Coastguard Worker variant_member_.emplace_back(std::forward<Args>(args)...); 393*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, StructUnion>) { 394*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::STRUCT_UNION, struct_union_.size()}; 395*9e3b08aeSAndroid Build Coastguard Worker struct_union_.emplace_back(std::forward<Args>(args)...); 396*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, Enumeration>) { 397*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::ENUMERATION, enumeration_.size()}; 398*9e3b08aeSAndroid Build Coastguard Worker enumeration_.emplace_back(std::forward<Args>(args)...); 399*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, Variant>) { 400*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::VARIANT, variant_.size()}; 401*9e3b08aeSAndroid Build Coastguard Worker variant_.emplace_back(std::forward<Args>(args)...); 402*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, Function>) { 403*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::FUNCTION, function_.size()}; 404*9e3b08aeSAndroid Build Coastguard Worker function_.emplace_back(std::forward<Args>(args)...); 405*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, ElfSymbol>) { 406*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::ELF_SYMBOL, elf_symbol_.size()}; 407*9e3b08aeSAndroid Build Coastguard Worker elf_symbol_.emplace_back(std::forward<Args>(args)...); 408*9e3b08aeSAndroid Build Coastguard Worker } else if constexpr (std::is_same_v<Node, Interface>) { 409*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::INTERFACE, interface_.size()}; 410*9e3b08aeSAndroid Build Coastguard Worker interface_.emplace_back(std::forward<Args>(args)...); 411*9e3b08aeSAndroid Build Coastguard Worker } else { 412*9e3b08aeSAndroid Build Coastguard Worker // unfortunately we cannot static_assert(false, "missing case") 413*9e3b08aeSAndroid Build Coastguard Worker static_assert(std::is_same<Node, Node*>::value, "missing case"); 414*9e3b08aeSAndroid Build Coastguard Worker } 415*9e3b08aeSAndroid Build Coastguard Worker } 416*9e3b08aeSAndroid Build Coastguard Worker 417*9e3b08aeSAndroid Build Coastguard Worker template <typename Node, typename... Args> 418*9e3b08aeSAndroid Build Coastguard Worker Id Add(Args&&... args) { 419*9e3b08aeSAndroid Build Coastguard Worker auto id = Allocate(); 420*9e3b08aeSAndroid Build Coastguard Worker Set<Node>(id, std::forward<Args>(args)...); 421*9e3b08aeSAndroid Build Coastguard Worker return id; 422*9e3b08aeSAndroid Build Coastguard Worker } 423*9e3b08aeSAndroid Build Coastguard Worker 424*9e3b08aeSAndroid Build Coastguard Worker void Deallocate(Id) { 425*9e3b08aeSAndroid Build Coastguard Worker // don't actually do anything, not supported 426*9e3b08aeSAndroid Build Coastguard Worker } 427*9e3b08aeSAndroid Build Coastguard Worker 428*9e3b08aeSAndroid Build Coastguard Worker void Unset(Id id) { 429*9e3b08aeSAndroid Build Coastguard Worker auto& reference = indirection_[id.ix_]; 430*9e3b08aeSAndroid Build Coastguard Worker if (reference.first == Which::ABSENT) { 431*9e3b08aeSAndroid Build Coastguard Worker Die() << "node value already unset: " << id; 432*9e3b08aeSAndroid Build Coastguard Worker } 433*9e3b08aeSAndroid Build Coastguard Worker reference = {Which::ABSENT, 0}; 434*9e3b08aeSAndroid Build Coastguard Worker } 435*9e3b08aeSAndroid Build Coastguard Worker 436*9e3b08aeSAndroid Build Coastguard Worker void Remove(Id id) { 437*9e3b08aeSAndroid Build Coastguard Worker Unset(id); 438*9e3b08aeSAndroid Build Coastguard Worker Deallocate(id); 439*9e3b08aeSAndroid Build Coastguard Worker } 440*9e3b08aeSAndroid Build Coastguard Worker 441*9e3b08aeSAndroid Build Coastguard Worker template <typename FunctionObject, typename... Args> 442*9e3b08aeSAndroid Build Coastguard Worker decltype(auto) Apply(FunctionObject&& function, Id id, Args&&... args) const; 443*9e3b08aeSAndroid Build Coastguard Worker 444*9e3b08aeSAndroid Build Coastguard Worker template <typename FunctionObject, typename... Args> 445*9e3b08aeSAndroid Build Coastguard Worker decltype(auto) Apply2( 446*9e3b08aeSAndroid Build Coastguard Worker FunctionObject&& function, Id id1, Id id2, Args&&... args) const; 447*9e3b08aeSAndroid Build Coastguard Worker 448*9e3b08aeSAndroid Build Coastguard Worker template <typename FunctionObject, typename... Args> 449*9e3b08aeSAndroid Build Coastguard Worker decltype(auto) Apply(FunctionObject&& function, Id id, Args&&... args); 450*9e3b08aeSAndroid Build Coastguard Worker 451*9e3b08aeSAndroid Build Coastguard Worker template <typename FunctionObject> 452*9e3b08aeSAndroid Build Coastguard Worker void ForEach(Id start, Id limit, FunctionObject&& function) const { 453*9e3b08aeSAndroid Build Coastguard Worker for (size_t ix = start.ix_; ix < limit.ix_; ++ix) { 454*9e3b08aeSAndroid Build Coastguard Worker const Id id(ix); 455*9e3b08aeSAndroid Build Coastguard Worker if (Is(id)) { 456*9e3b08aeSAndroid Build Coastguard Worker function(id); 457*9e3b08aeSAndroid Build Coastguard Worker } 458*9e3b08aeSAndroid Build Coastguard Worker } 459*9e3b08aeSAndroid Build Coastguard Worker } 460*9e3b08aeSAndroid Build Coastguard Worker 461*9e3b08aeSAndroid Build Coastguard Worker private: 462*9e3b08aeSAndroid Build Coastguard Worker enum class Which { 463*9e3b08aeSAndroid Build Coastguard Worker ABSENT, 464*9e3b08aeSAndroid Build Coastguard Worker SPECIAL, 465*9e3b08aeSAndroid Build Coastguard Worker POINTER_REFERENCE, 466*9e3b08aeSAndroid Build Coastguard Worker POINTER_TO_MEMBER, 467*9e3b08aeSAndroid Build Coastguard Worker TYPEDEF, 468*9e3b08aeSAndroid Build Coastguard Worker QUALIFIED, 469*9e3b08aeSAndroid Build Coastguard Worker PRIMITIVE, 470*9e3b08aeSAndroid Build Coastguard Worker ARRAY, 471*9e3b08aeSAndroid Build Coastguard Worker BASE_CLASS, 472*9e3b08aeSAndroid Build Coastguard Worker METHOD, 473*9e3b08aeSAndroid Build Coastguard Worker MEMBER, 474*9e3b08aeSAndroid Build Coastguard Worker VARIANT_MEMBER, 475*9e3b08aeSAndroid Build Coastguard Worker STRUCT_UNION, 476*9e3b08aeSAndroid Build Coastguard Worker ENUMERATION, 477*9e3b08aeSAndroid Build Coastguard Worker VARIANT, 478*9e3b08aeSAndroid Build Coastguard Worker FUNCTION, 479*9e3b08aeSAndroid Build Coastguard Worker ELF_SYMBOL, 480*9e3b08aeSAndroid Build Coastguard Worker INTERFACE, 481*9e3b08aeSAndroid Build Coastguard Worker }; 482*9e3b08aeSAndroid Build Coastguard Worker 483*9e3b08aeSAndroid Build Coastguard Worker std::vector<std::pair<Which, size_t>> indirection_; 484*9e3b08aeSAndroid Build Coastguard Worker 485*9e3b08aeSAndroid Build Coastguard Worker std::vector<Special> special_; 486*9e3b08aeSAndroid Build Coastguard Worker std::vector<PointerReference> pointer_reference_; 487*9e3b08aeSAndroid Build Coastguard Worker std::vector<PointerToMember> pointer_to_member_; 488*9e3b08aeSAndroid Build Coastguard Worker std::vector<Typedef> typedef_; 489*9e3b08aeSAndroid Build Coastguard Worker std::vector<Qualified> qualified_; 490*9e3b08aeSAndroid Build Coastguard Worker std::vector<Primitive> primitive_; 491*9e3b08aeSAndroid Build Coastguard Worker std::vector<Array> array_; 492*9e3b08aeSAndroid Build Coastguard Worker std::vector<BaseClass> base_class_; 493*9e3b08aeSAndroid Build Coastguard Worker std::vector<Method> method_; 494*9e3b08aeSAndroid Build Coastguard Worker std::vector<Member> member_; 495*9e3b08aeSAndroid Build Coastguard Worker std::vector<VariantMember> variant_member_; 496*9e3b08aeSAndroid Build Coastguard Worker std::vector<StructUnion> struct_union_; 497*9e3b08aeSAndroid Build Coastguard Worker std::vector<Enumeration> enumeration_; 498*9e3b08aeSAndroid Build Coastguard Worker std::vector<Variant> variant_; 499*9e3b08aeSAndroid Build Coastguard Worker std::vector<Function> function_; 500*9e3b08aeSAndroid Build Coastguard Worker std::vector<ElfSymbol> elf_symbol_; 501*9e3b08aeSAndroid Build Coastguard Worker std::vector<Interface> interface_; 502*9e3b08aeSAndroid Build Coastguard Worker }; 503*9e3b08aeSAndroid Build Coastguard Worker 504*9e3b08aeSAndroid Build Coastguard Worker template <typename FunctionObject, typename... Args> 505*9e3b08aeSAndroid Build Coastguard Worker decltype(auto) Graph::Apply( 506*9e3b08aeSAndroid Build Coastguard Worker FunctionObject&& function, Id id, Args&&... args) const { 507*9e3b08aeSAndroid Build Coastguard Worker const auto& [which, ix] = indirection_[id.ix_]; 508*9e3b08aeSAndroid Build Coastguard Worker switch (which) { 509*9e3b08aeSAndroid Build Coastguard Worker case Which::ABSENT: 510*9e3b08aeSAndroid Build Coastguard Worker Die() << "undefined node: " << id; 511*9e3b08aeSAndroid Build Coastguard Worker case Which::SPECIAL: 512*9e3b08aeSAndroid Build Coastguard Worker return function(special_[ix], std::forward<Args>(args)...); 513*9e3b08aeSAndroid Build Coastguard Worker case Which::POINTER_REFERENCE: 514*9e3b08aeSAndroid Build Coastguard Worker return function(pointer_reference_[ix], std::forward<Args>(args)...); 515*9e3b08aeSAndroid Build Coastguard Worker case Which::POINTER_TO_MEMBER: 516*9e3b08aeSAndroid Build Coastguard Worker return function(pointer_to_member_[ix], std::forward<Args>(args)...); 517*9e3b08aeSAndroid Build Coastguard Worker case Which::TYPEDEF: 518*9e3b08aeSAndroid Build Coastguard Worker return function(typedef_[ix], std::forward<Args>(args)...); 519*9e3b08aeSAndroid Build Coastguard Worker case Which::QUALIFIED: 520*9e3b08aeSAndroid Build Coastguard Worker return function(qualified_[ix], std::forward<Args>(args)...); 521*9e3b08aeSAndroid Build Coastguard Worker case Which::PRIMITIVE: 522*9e3b08aeSAndroid Build Coastguard Worker return function(primitive_[ix], std::forward<Args>(args)...); 523*9e3b08aeSAndroid Build Coastguard Worker case Which::ARRAY: 524*9e3b08aeSAndroid Build Coastguard Worker return function(array_[ix], std::forward<Args>(args)...); 525*9e3b08aeSAndroid Build Coastguard Worker case Which::BASE_CLASS: 526*9e3b08aeSAndroid Build Coastguard Worker return function(base_class_[ix], std::forward<Args>(args)...); 527*9e3b08aeSAndroid Build Coastguard Worker case Which::METHOD: 528*9e3b08aeSAndroid Build Coastguard Worker return function(method_[ix], std::forward<Args>(args)...); 529*9e3b08aeSAndroid Build Coastguard Worker case Which::MEMBER: 530*9e3b08aeSAndroid Build Coastguard Worker return function(member_[ix], std::forward<Args>(args)...); 531*9e3b08aeSAndroid Build Coastguard Worker case Which::VARIANT_MEMBER: 532*9e3b08aeSAndroid Build Coastguard Worker return function(variant_member_[ix], std::forward<Args>(args)...); 533*9e3b08aeSAndroid Build Coastguard Worker case Which::STRUCT_UNION: 534*9e3b08aeSAndroid Build Coastguard Worker return function(struct_union_[ix], std::forward<Args>(args)...); 535*9e3b08aeSAndroid Build Coastguard Worker case Which::ENUMERATION: 536*9e3b08aeSAndroid Build Coastguard Worker return function(enumeration_[ix], std::forward<Args>(args)...); 537*9e3b08aeSAndroid Build Coastguard Worker case Which::VARIANT: 538*9e3b08aeSAndroid Build Coastguard Worker return function(variant_[ix], std::forward<Args>(args)...); 539*9e3b08aeSAndroid Build Coastguard Worker case Which::FUNCTION: 540*9e3b08aeSAndroid Build Coastguard Worker return function(function_[ix], std::forward<Args>(args)...); 541*9e3b08aeSAndroid Build Coastguard Worker case Which::ELF_SYMBOL: 542*9e3b08aeSAndroid Build Coastguard Worker return function(elf_symbol_[ix], std::forward<Args>(args)...); 543*9e3b08aeSAndroid Build Coastguard Worker case Which::INTERFACE: 544*9e3b08aeSAndroid Build Coastguard Worker return function(interface_[ix], std::forward<Args>(args)...); 545*9e3b08aeSAndroid Build Coastguard Worker } 546*9e3b08aeSAndroid Build Coastguard Worker } 547*9e3b08aeSAndroid Build Coastguard Worker 548*9e3b08aeSAndroid Build Coastguard Worker template <typename FunctionObject, typename... Args> 549*9e3b08aeSAndroid Build Coastguard Worker decltype(auto) Graph::Apply2( 550*9e3b08aeSAndroid Build Coastguard Worker FunctionObject&& function, Id id1, Id id2, Args&&... args) const { 551*9e3b08aeSAndroid Build Coastguard Worker const auto& [which1, ix1] = indirection_[id1.ix_]; 552*9e3b08aeSAndroid Build Coastguard Worker const auto& [which2, ix2] = indirection_[id2.ix_]; 553*9e3b08aeSAndroid Build Coastguard Worker if (which1 != which2) { 554*9e3b08aeSAndroid Build Coastguard Worker return function.Mismatch(std::forward<Args>(args)...); 555*9e3b08aeSAndroid Build Coastguard Worker } 556*9e3b08aeSAndroid Build Coastguard Worker switch (which1) { 557*9e3b08aeSAndroid Build Coastguard Worker case Which::ABSENT: 558*9e3b08aeSAndroid Build Coastguard Worker Die() << "undefined nodes: " << id1 << ", " << id2; 559*9e3b08aeSAndroid Build Coastguard Worker case Which::SPECIAL: 560*9e3b08aeSAndroid Build Coastguard Worker return function(special_[ix1], special_[ix2], 561*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 562*9e3b08aeSAndroid Build Coastguard Worker case Which::POINTER_REFERENCE: 563*9e3b08aeSAndroid Build Coastguard Worker return function(pointer_reference_[ix1], pointer_reference_[ix2], 564*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 565*9e3b08aeSAndroid Build Coastguard Worker case Which::POINTER_TO_MEMBER: 566*9e3b08aeSAndroid Build Coastguard Worker return function(pointer_to_member_[ix1], pointer_to_member_[ix2], 567*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 568*9e3b08aeSAndroid Build Coastguard Worker case Which::TYPEDEF: 569*9e3b08aeSAndroid Build Coastguard Worker return function(typedef_[ix1], typedef_[ix2], 570*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 571*9e3b08aeSAndroid Build Coastguard Worker case Which::QUALIFIED: 572*9e3b08aeSAndroid Build Coastguard Worker return function(qualified_[ix1], qualified_[ix2], 573*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 574*9e3b08aeSAndroid Build Coastguard Worker case Which::PRIMITIVE: 575*9e3b08aeSAndroid Build Coastguard Worker return function(primitive_[ix1], primitive_[ix2], 576*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 577*9e3b08aeSAndroid Build Coastguard Worker case Which::ARRAY: 578*9e3b08aeSAndroid Build Coastguard Worker return function(array_[ix1], array_[ix2], 579*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 580*9e3b08aeSAndroid Build Coastguard Worker case Which::BASE_CLASS: 581*9e3b08aeSAndroid Build Coastguard Worker return function(base_class_[ix1], base_class_[ix2], 582*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 583*9e3b08aeSAndroid Build Coastguard Worker case Which::METHOD: 584*9e3b08aeSAndroid Build Coastguard Worker return function(method_[ix1], method_[ix2], 585*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 586*9e3b08aeSAndroid Build Coastguard Worker case Which::MEMBER: 587*9e3b08aeSAndroid Build Coastguard Worker return function(member_[ix1], member_[ix2], 588*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 589*9e3b08aeSAndroid Build Coastguard Worker case Which::VARIANT_MEMBER: 590*9e3b08aeSAndroid Build Coastguard Worker return function(variant_member_[ix1], variant_member_[ix2], 591*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 592*9e3b08aeSAndroid Build Coastguard Worker case Which::STRUCT_UNION: 593*9e3b08aeSAndroid Build Coastguard Worker return function(struct_union_[ix1], struct_union_[ix2], 594*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 595*9e3b08aeSAndroid Build Coastguard Worker case Which::ENUMERATION: 596*9e3b08aeSAndroid Build Coastguard Worker return function(enumeration_[ix1], enumeration_[ix2], 597*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 598*9e3b08aeSAndroid Build Coastguard Worker case Which::VARIANT: 599*9e3b08aeSAndroid Build Coastguard Worker return function(variant_[ix1], variant_[ix2], 600*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 601*9e3b08aeSAndroid Build Coastguard Worker case Which::FUNCTION: 602*9e3b08aeSAndroid Build Coastguard Worker return function(function_[ix1], function_[ix2], 603*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 604*9e3b08aeSAndroid Build Coastguard Worker case Which::ELF_SYMBOL: 605*9e3b08aeSAndroid Build Coastguard Worker return function(elf_symbol_[ix1], elf_symbol_[ix2], 606*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 607*9e3b08aeSAndroid Build Coastguard Worker case Which::INTERFACE: 608*9e3b08aeSAndroid Build Coastguard Worker return function(interface_[ix1], interface_[ix2], 609*9e3b08aeSAndroid Build Coastguard Worker std::forward<Args>(args)...); 610*9e3b08aeSAndroid Build Coastguard Worker } 611*9e3b08aeSAndroid Build Coastguard Worker } 612*9e3b08aeSAndroid Build Coastguard Worker 613*9e3b08aeSAndroid Build Coastguard Worker template <typename FunctionObject, typename... Args> 614*9e3b08aeSAndroid Build Coastguard Worker struct ConstAdapter { 615*9e3b08aeSAndroid Build Coastguard Worker explicit ConstAdapter(FunctionObject& function) : function(function) {} 616*9e3b08aeSAndroid Build Coastguard Worker template <typename Node> 617*9e3b08aeSAndroid Build Coastguard Worker decltype(auto) operator()(const Node& node, Args&&... args) { 618*9e3b08aeSAndroid Build Coastguard Worker return function(const_cast<Node&>(node), std::forward<Args>(args)...); 619*9e3b08aeSAndroid Build Coastguard Worker } 620*9e3b08aeSAndroid Build Coastguard Worker FunctionObject& function; 621*9e3b08aeSAndroid Build Coastguard Worker }; 622*9e3b08aeSAndroid Build Coastguard Worker 623*9e3b08aeSAndroid Build Coastguard Worker template <typename FunctionObject, typename... Args> 624*9e3b08aeSAndroid Build Coastguard Worker decltype(auto) Graph::Apply(FunctionObject&& function, Id id, Args&&... args) { 625*9e3b08aeSAndroid Build Coastguard Worker ConstAdapter<FunctionObject, Args&&...> adapter(function); 626*9e3b08aeSAndroid Build Coastguard Worker return static_cast<const Graph&>(*this).Apply( 627*9e3b08aeSAndroid Build Coastguard Worker adapter, id, std::forward<Args>(args)...); 628*9e3b08aeSAndroid Build Coastguard Worker } 629*9e3b08aeSAndroid Build Coastguard Worker 630*9e3b08aeSAndroid Build Coastguard Worker struct InterfaceKey { 631*9e3b08aeSAndroid Build Coastguard Worker explicit InterfaceKey(const Graph& graph) : graph(graph) {} 632*9e3b08aeSAndroid Build Coastguard Worker 633*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(Id id) const { 634*9e3b08aeSAndroid Build Coastguard Worker return graph.Apply(*this, id); 635*9e3b08aeSAndroid Build Coastguard Worker } 636*9e3b08aeSAndroid Build Coastguard Worker 637*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(const stg::Typedef& x) const { 638*9e3b08aeSAndroid Build Coastguard Worker return x.name; 639*9e3b08aeSAndroid Build Coastguard Worker } 640*9e3b08aeSAndroid Build Coastguard Worker 641*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(const stg::StructUnion& x) const { 642*9e3b08aeSAndroid Build Coastguard Worker if (x.name.empty()) { 643*9e3b08aeSAndroid Build Coastguard Worker Die() << "anonymous struct/union interface type"; 644*9e3b08aeSAndroid Build Coastguard Worker } 645*9e3b08aeSAndroid Build Coastguard Worker std::ostringstream os; 646*9e3b08aeSAndroid Build Coastguard Worker os << x.kind << ' ' << x.name; 647*9e3b08aeSAndroid Build Coastguard Worker return os.str(); 648*9e3b08aeSAndroid Build Coastguard Worker } 649*9e3b08aeSAndroid Build Coastguard Worker 650*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(const stg::Enumeration& x) const { 651*9e3b08aeSAndroid Build Coastguard Worker if (x.name.empty()) { 652*9e3b08aeSAndroid Build Coastguard Worker Die() << "anonymous enum interface type"; 653*9e3b08aeSAndroid Build Coastguard Worker } 654*9e3b08aeSAndroid Build Coastguard Worker return "enum " + x.name; 655*9e3b08aeSAndroid Build Coastguard Worker } 656*9e3b08aeSAndroid Build Coastguard Worker 657*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(const stg::Variant& x) const { 658*9e3b08aeSAndroid Build Coastguard Worker if (x.name.empty()) { 659*9e3b08aeSAndroid Build Coastguard Worker Die() << "anonymous variant interface type"; 660*9e3b08aeSAndroid Build Coastguard Worker } 661*9e3b08aeSAndroid Build Coastguard Worker return "variant " + x.name; 662*9e3b08aeSAndroid Build Coastguard Worker } 663*9e3b08aeSAndroid Build Coastguard Worker 664*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(const stg::ElfSymbol& x) const { 665*9e3b08aeSAndroid Build Coastguard Worker return VersionedSymbolName(x); 666*9e3b08aeSAndroid Build Coastguard Worker } 667*9e3b08aeSAndroid Build Coastguard Worker 668*9e3b08aeSAndroid Build Coastguard Worker template <typename Node> 669*9e3b08aeSAndroid Build Coastguard Worker std::string operator()(const Node&) const { 670*9e3b08aeSAndroid Build Coastguard Worker Die() << "unexpected interface type"; 671*9e3b08aeSAndroid Build Coastguard Worker } 672*9e3b08aeSAndroid Build Coastguard Worker 673*9e3b08aeSAndroid Build Coastguard Worker const Graph& graph; 674*9e3b08aeSAndroid Build Coastguard Worker }; 675*9e3b08aeSAndroid Build Coastguard Worker 676*9e3b08aeSAndroid Build Coastguard Worker // Roughly equivalent to std::set<Id> but with constant time operations and 677*9e3b08aeSAndroid Build Coastguard Worker // key set limited to allocated Ids. 678*9e3b08aeSAndroid Build Coastguard Worker class DenseIdSet { 679*9e3b08aeSAndroid Build Coastguard Worker public: 680*9e3b08aeSAndroid Build Coastguard Worker explicit DenseIdSet(Id start) : offset_(start.ix_) {} 681*9e3b08aeSAndroid Build Coastguard Worker void Reserve(Id limit) { 682*9e3b08aeSAndroid Build Coastguard Worker ids_.reserve(limit.ix_ - offset_); 683*9e3b08aeSAndroid Build Coastguard Worker } 684*9e3b08aeSAndroid Build Coastguard Worker bool Insert(Id id) { 685*9e3b08aeSAndroid Build Coastguard Worker const auto ix = id.ix_; 686*9e3b08aeSAndroid Build Coastguard Worker if (ix < offset_) { 687*9e3b08aeSAndroid Build Coastguard Worker Die() << "DenseIdSet: out of range access to " << id; 688*9e3b08aeSAndroid Build Coastguard Worker } 689*9e3b08aeSAndroid Build Coastguard Worker const auto offset_ix = ix - offset_; 690*9e3b08aeSAndroid Build Coastguard Worker if (offset_ix >= ids_.size()) { 691*9e3b08aeSAndroid Build Coastguard Worker ids_.resize(offset_ix + 1, false); 692*9e3b08aeSAndroid Build Coastguard Worker } 693*9e3b08aeSAndroid Build Coastguard Worker if (ids_[offset_ix]) { 694*9e3b08aeSAndroid Build Coastguard Worker return false; 695*9e3b08aeSAndroid Build Coastguard Worker } 696*9e3b08aeSAndroid Build Coastguard Worker ids_[offset_ix] = true; 697*9e3b08aeSAndroid Build Coastguard Worker return true; 698*9e3b08aeSAndroid Build Coastguard Worker } 699*9e3b08aeSAndroid Build Coastguard Worker 700*9e3b08aeSAndroid Build Coastguard Worker private: 701*9e3b08aeSAndroid Build Coastguard Worker size_t offset_; 702*9e3b08aeSAndroid Build Coastguard Worker std::vector<bool> ids_; 703*9e3b08aeSAndroid Build Coastguard Worker }; 704*9e3b08aeSAndroid Build Coastguard Worker 705*9e3b08aeSAndroid Build Coastguard Worker // Roughly equivalent to std::map<Id, Id>, defaulted to the identity mapping, 706*9e3b08aeSAndroid Build Coastguard Worker // but with constant time operations and key set limited to allocated Ids. 707*9e3b08aeSAndroid Build Coastguard Worker class DenseIdMapping { 708*9e3b08aeSAndroid Build Coastguard Worker public: 709*9e3b08aeSAndroid Build Coastguard Worker explicit DenseIdMapping(Id start) : offset_(start.ix_) {} 710*9e3b08aeSAndroid Build Coastguard Worker void Reserve(Id limit) { 711*9e3b08aeSAndroid Build Coastguard Worker ids_.reserve(limit.ix_ - offset_); 712*9e3b08aeSAndroid Build Coastguard Worker } 713*9e3b08aeSAndroid Build Coastguard Worker Id& operator[](Id id) { 714*9e3b08aeSAndroid Build Coastguard Worker const auto ix = id.ix_; 715*9e3b08aeSAndroid Build Coastguard Worker if (ix < offset_) { 716*9e3b08aeSAndroid Build Coastguard Worker Die() << "DenseIdMapping: out of range access to " << id; 717*9e3b08aeSAndroid Build Coastguard Worker } 718*9e3b08aeSAndroid Build Coastguard Worker Populate(ix + 1); 719*9e3b08aeSAndroid Build Coastguard Worker return ids_[ix - offset_]; 720*9e3b08aeSAndroid Build Coastguard Worker } 721*9e3b08aeSAndroid Build Coastguard Worker 722*9e3b08aeSAndroid Build Coastguard Worker private: 723*9e3b08aeSAndroid Build Coastguard Worker void Populate(size_t size) { 724*9e3b08aeSAndroid Build Coastguard Worker for (size_t ix = offset_ + ids_.size(); ix < size; ++ix) { 725*9e3b08aeSAndroid Build Coastguard Worker ids_.emplace_back(ix); 726*9e3b08aeSAndroid Build Coastguard Worker } 727*9e3b08aeSAndroid Build Coastguard Worker } 728*9e3b08aeSAndroid Build Coastguard Worker 729*9e3b08aeSAndroid Build Coastguard Worker size_t offset_; 730*9e3b08aeSAndroid Build Coastguard Worker std::vector<Id> ids_; 731*9e3b08aeSAndroid Build Coastguard Worker }; 732*9e3b08aeSAndroid Build Coastguard Worker 733*9e3b08aeSAndroid Build Coastguard Worker template <typename ExternalId> 734*9e3b08aeSAndroid Build Coastguard Worker class Maker { 735*9e3b08aeSAndroid Build Coastguard Worker public: 736*9e3b08aeSAndroid Build Coastguard Worker explicit Maker(Graph& graph) : graph_(graph) {} 737*9e3b08aeSAndroid Build Coastguard Worker 738*9e3b08aeSAndroid Build Coastguard Worker ~Maker() noexcept(false) { 739*9e3b08aeSAndroid Build Coastguard Worker if (std::uncaught_exceptions() == 0) { 740*9e3b08aeSAndroid Build Coastguard Worker if (undefined_ > 0) { 741*9e3b08aeSAndroid Build Coastguard Worker Die die; 742*9e3b08aeSAndroid Build Coastguard Worker die << "undefined nodes:"; 743*9e3b08aeSAndroid Build Coastguard Worker for (const auto& [external_id, id] : map_) { 744*9e3b08aeSAndroid Build Coastguard Worker if (!graph_.Is(id)) { 745*9e3b08aeSAndroid Build Coastguard Worker die << ' ' << external_id; 746*9e3b08aeSAndroid Build Coastguard Worker } 747*9e3b08aeSAndroid Build Coastguard Worker } 748*9e3b08aeSAndroid Build Coastguard Worker } 749*9e3b08aeSAndroid Build Coastguard Worker } 750*9e3b08aeSAndroid Build Coastguard Worker } 751*9e3b08aeSAndroid Build Coastguard Worker 752*9e3b08aeSAndroid Build Coastguard Worker Id Get(const ExternalId& external_id) { 753*9e3b08aeSAndroid Build Coastguard Worker auto [it, inserted] = map_.emplace(external_id, 0); 754*9e3b08aeSAndroid Build Coastguard Worker if (inserted) { 755*9e3b08aeSAndroid Build Coastguard Worker it->second = graph_.Allocate(); 756*9e3b08aeSAndroid Build Coastguard Worker ++undefined_; 757*9e3b08aeSAndroid Build Coastguard Worker } 758*9e3b08aeSAndroid Build Coastguard Worker return it->second; 759*9e3b08aeSAndroid Build Coastguard Worker } 760*9e3b08aeSAndroid Build Coastguard Worker 761*9e3b08aeSAndroid Build Coastguard Worker template <typename Node, typename... Args> 762*9e3b08aeSAndroid Build Coastguard Worker Id Set(const ExternalId& external_id, Args&&... args) { 763*9e3b08aeSAndroid Build Coastguard Worker return Set<Node>(DieDuplicate, external_id, std::forward<Args>(args)...); 764*9e3b08aeSAndroid Build Coastguard Worker } 765*9e3b08aeSAndroid Build Coastguard Worker 766*9e3b08aeSAndroid Build Coastguard Worker template <typename Node, typename... Args> 767*9e3b08aeSAndroid Build Coastguard Worker Id MaybeSet(const ExternalId& external_id, Args&&... args) { 768*9e3b08aeSAndroid Build Coastguard Worker return Set<Node>(WarnDuplicate, external_id, std::forward<Args>(args)...); 769*9e3b08aeSAndroid Build Coastguard Worker } 770*9e3b08aeSAndroid Build Coastguard Worker 771*9e3b08aeSAndroid Build Coastguard Worker template <typename Node, typename... Args> 772*9e3b08aeSAndroid Build Coastguard Worker Id Add(Args&&... args) { 773*9e3b08aeSAndroid Build Coastguard Worker return graph_.Add<Node>(std::forward<Args>(args)...); 774*9e3b08aeSAndroid Build Coastguard Worker } 775*9e3b08aeSAndroid Build Coastguard Worker 776*9e3b08aeSAndroid Build Coastguard Worker private: 777*9e3b08aeSAndroid Build Coastguard Worker Graph& graph_; 778*9e3b08aeSAndroid Build Coastguard Worker size_t undefined_ = 0; 779*9e3b08aeSAndroid Build Coastguard Worker std::unordered_map<ExternalId, Id> map_; 780*9e3b08aeSAndroid Build Coastguard Worker 781*9e3b08aeSAndroid Build Coastguard Worker template <typename Node, typename... Args> 782*9e3b08aeSAndroid Build Coastguard Worker Id Set(void(& fail)(const ExternalId&), const ExternalId& external_id, 783*9e3b08aeSAndroid Build Coastguard Worker Args&&... args) { 784*9e3b08aeSAndroid Build Coastguard Worker const Id id = Get(external_id); 785*9e3b08aeSAndroid Build Coastguard Worker if (graph_.Is(id)) { 786*9e3b08aeSAndroid Build Coastguard Worker fail(external_id); 787*9e3b08aeSAndroid Build Coastguard Worker } else { 788*9e3b08aeSAndroid Build Coastguard Worker graph_.Set<Node>(id, std::forward<Args>(args)...); 789*9e3b08aeSAndroid Build Coastguard Worker --undefined_; 790*9e3b08aeSAndroid Build Coastguard Worker } 791*9e3b08aeSAndroid Build Coastguard Worker return id; 792*9e3b08aeSAndroid Build Coastguard Worker } 793*9e3b08aeSAndroid Build Coastguard Worker 794*9e3b08aeSAndroid Build Coastguard Worker // These helpers should probably not be inlined. 795*9e3b08aeSAndroid Build Coastguard Worker [[noreturn]] static void DieDuplicate(const ExternalId& external_id) { 796*9e3b08aeSAndroid Build Coastguard Worker Die() << "duplicate definition of node: " << external_id; 797*9e3b08aeSAndroid Build Coastguard Worker } 798*9e3b08aeSAndroid Build Coastguard Worker static void WarnDuplicate(const ExternalId& external_id) { 799*9e3b08aeSAndroid Build Coastguard Worker Warn() << "ignoring duplicate definition of node: " << external_id; 800*9e3b08aeSAndroid Build Coastguard Worker } 801*9e3b08aeSAndroid Build Coastguard Worker }; 802*9e3b08aeSAndroid Build Coastguard Worker 803*9e3b08aeSAndroid Build Coastguard Worker } // namespace stg 804*9e3b08aeSAndroid Build Coastguard Worker 805*9e3b08aeSAndroid Build Coastguard Worker #endif // STG_GRAPH_H_ 806