• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- mode: C++ -*-
3 //
4 // Copyright 2023-2024 Google LLC
5 //
6 // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7 // "License"); you may not use this file except in compliance with the
8 // License.  You may obtain a copy of the License at
9 //
10 //     https://llvm.org/LICENSE.txt
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 //
18 // Author: Siddharth Nayyar
19 
20 #include "fidelity.h"
21 
22 #include <map>
23 #include <ostream>
24 #include <set>
25 #include <string>
26 #include <unordered_map>
27 #include <utility>
28 #include <vector>
29 
30 #include "graph.h"
31 #include "naming.h"
32 
33 namespace stg {
34 
35 namespace {
36 
37 struct Fidelity {
Fidelitystg::__anon10f07ef20111::Fidelity38   Fidelity(const Graph& graph, NameCache& name_cache)
39       : graph(graph), describe(graph, name_cache), seen(Id(0), graph.Limit()) {}
40 
41   void operator()(Id);
42   void operator()(const std::vector<Id>&);
43   void operator()(const std::map<std::string, Id>&);
44   void operator()(const Special&, Id);
45   void operator()(const PointerReference&, Id);
46   void operator()(const PointerToMember&, Id);
47   void operator()(const Typedef&, Id);
48   void operator()(const Qualified&, Id);
49   void operator()(const Primitive&, Id);
50   void operator()(const Array&, Id);
51   void operator()(const BaseClass&, Id);
52   void operator()(const Method&, Id);
53   void operator()(const Member&, Id);
54   void operator()(const VariantMember&, Id);
55   void operator()(const StructUnion&, Id);
56   void operator()(const Enumeration&, Id);
57   void operator()(const Variant&, Id);
58   void operator()(const Function&, Id);
59   void operator()(const ElfSymbol&, Id);
60   void operator()(const Interface&, Id);
61 
62   const Graph& graph;
63   Describe describe;
64   DenseIdSet seen;
65   std::unordered_map<std::string, SymbolFidelity> symbols;
66   std::unordered_map<std::string, TypeFidelity> types;
67 };
68 
operator ()(Id id)69 void Fidelity::operator()(Id id) {
70   if (seen.Insert(id)) {
71     graph.Apply(*this, id, id);
72   }
73 }
74 
operator ()(const std::vector<Id> & x)75 void Fidelity::operator()(const std::vector<Id>& x) {
76   for (auto id : x) {
77     (*this)(id);
78   }
79 }
80 
operator ()(const std::map<std::string,Id> & x)81 void Fidelity::operator()(const std::map<std::string, Id>& x) {
82   for (const auto& [_, id] : x) {
83     (*this)(id);
84   }
85 }
86 
operator ()(const Special &,Id)87 void Fidelity::operator()(const Special&, Id) {}
88 
operator ()(const PointerReference & x,Id)89 void Fidelity::operator()(const PointerReference& x, Id) {
90   (*this)(x.pointee_type_id);
91 }
92 
operator ()(const PointerToMember & x,Id)93 void Fidelity::operator()(const PointerToMember& x, Id) {
94   (*this)(x.containing_type_id);
95   (*this)(x.pointee_type_id);
96 }
97 
operator ()(const Typedef & x,Id)98 void Fidelity::operator()(const Typedef& x, Id) {
99   (*this)(x.referred_type_id);
100 }
101 
operator ()(const Qualified & x,Id)102 void Fidelity::operator()(const Qualified& x, Id) {
103   (*this)(x.qualified_type_id);
104 }
105 
operator ()(const Primitive &,Id)106 void Fidelity::operator()(const Primitive&, Id) {}
107 
operator ()(const Array & x,Id)108 void Fidelity::operator()(const Array& x, Id) {
109   (*this)(x.element_type_id);
110 }
111 
operator ()(const BaseClass & x,Id)112 void Fidelity::operator()(const BaseClass& x, Id) {
113   (*this)(x.type_id);
114 }
115 
operator ()(const Method & x,Id)116 void Fidelity::operator()(const Method& x, Id) {
117   (*this)(x.type_id);
118 }
119 
operator ()(const Member & x,Id)120 void Fidelity::operator()(const Member& x, Id) {
121   (*this)(x.type_id);
122 }
123 
operator ()(const VariantMember & x,Id)124 void Fidelity::operator()(const VariantMember& x, Id) {
125   (*this)(x.type_id);
126 }
127 
operator ()(const StructUnion & x,Id id)128 void Fidelity::operator()(const StructUnion& x, Id id) {
129   if (!x.name.empty()) {
130     auto [it, _] =
131         types.emplace(describe(id).ToString(), TypeFidelity::DECLARATION_ONLY);
132     if (x.definition) {
133       it->second = TypeFidelity::FULLY_DEFINED;
134     }
135   }
136   if (x.definition) {
137     (*this)(x.definition->base_classes);
138     (*this)(x.definition->methods);
139     (*this)(x.definition->members);
140   }
141 }
142 
operator ()(const Enumeration & x,Id id)143 void Fidelity::operator()(const Enumeration& x, Id id) {
144   if (!x.name.empty()) {
145     auto [it, _] =
146         types.emplace(describe(id).ToString(), TypeFidelity::DECLARATION_ONLY);
147     if (x.definition) {
148       it->second = TypeFidelity::FULLY_DEFINED;
149     }
150   }
151 }
152 
operator ()(const Variant & x,Id id)153 void Fidelity::operator()(const Variant& x, Id id) {
154   types.emplace(describe(id).ToString(), TypeFidelity::FULLY_DEFINED);
155   (*this)(x.members);
156 }
157 
operator ()(const Function & x,Id)158 void Fidelity::operator()(const Function& x, Id) {
159   (*this)(x.return_type_id);
160   (*this)(x.parameters);
161 }
162 
operator ()(const ElfSymbol & x,Id)163 void Fidelity::operator()(const ElfSymbol& x, Id) {
164   auto symbol = VersionedSymbolName(x);
165   auto [it, _] = symbols.emplace(symbol, SymbolFidelity::UNTYPED);
166   if (x.type_id) {
167     it->second = SymbolFidelity::TYPED;
168     (*this)(*x.type_id);
169   }
170 }
171 
operator ()(const Interface & x,Id)172 void Fidelity::operator()(const Interface& x, Id) {
173   (*this)(x.symbols);
174   (*this)(x.types);
175 }
176 
177 template <typename T>
GetKeys(const std::unordered_map<std::string,T> & x1,const std::unordered_map<std::string,T> & x2)178 std::set<std::string> GetKeys(
179     const std::unordered_map<std::string, T>& x1,
180     const std::unordered_map<std::string, T>& x2) {
181   std::set<std::string> keys;
182   for (const auto& [key, _] : x1) {
183     keys.insert(key);
184   }
185   for (const auto& [key, _] : x2) {
186     keys.insert(key);
187   }
188   return keys;
189 }
190 
InsertTransition(FidelityDiff & diff,SymbolFidelityTransition transition,const std::string & symbol)191 void InsertTransition(FidelityDiff& diff, SymbolFidelityTransition transition,
192                       const std::string& symbol) {
193   diff.symbol_transitions[transition].push_back(symbol);
194 }
195 
InsertTransition(FidelityDiff & diff,TypeFidelityTransition transition,const std::string & type)196 void InsertTransition(FidelityDiff& diff, TypeFidelityTransition transition,
197                       const std::string& type) {
198   diff.type_transitions[transition].push_back(type);
199 }
200 
201 template <typename T>
InsertTransitions(FidelityDiff & diff,const std::unordered_map<std::string,T> & x1,const std::unordered_map<std::string,T> & x2)202 void InsertTransitions(FidelityDiff& diff,
203                        const std::unordered_map<std::string, T>& x1,
204                        const std::unordered_map<std::string, T>& x2) {
205   for (const auto& key : GetKeys(x1, x2)) {
206     auto it1 = x1.find(key);
207     auto it2 = x2.find(key);
208     auto transition = std::make_pair(it1 == x1.end() ? T() : it1->second,
209                                      it2 == x2.end() ? T() : it2->second);
210     InsertTransition(diff, transition, key);
211   }
212 }
213 
214 }  // namespace
215 
operator <<(std::ostream & os,SymbolFidelity x)216 std::ostream& operator<<(std::ostream& os, SymbolFidelity x) {
217   switch (x) {
218     case SymbolFidelity::ABSENT:
219       return os << "ABSENT";
220     case SymbolFidelity::TYPED:
221       return os << "TYPED";
222     case SymbolFidelity::UNTYPED:
223       return os << "UNTYPED";
224   }
225 }
226 
operator <<(std::ostream & os,TypeFidelity x)227 std::ostream& operator<<(std::ostream& os, TypeFidelity x) {
228   switch (x) {
229     case TypeFidelity::ABSENT:
230       return os << "ABSENT";
231     case TypeFidelity::DECLARATION_ONLY:
232       return os << "DECLARATION_ONLY";
233     case TypeFidelity::FULLY_DEFINED:
234       return os << "FULLY_DEFINED";
235   }
236 }
237 
operator <<(std::ostream & os,SymbolFidelityTransition x)238 std::ostream& operator<<(std::ostream& os, SymbolFidelityTransition x) {
239   return os << "symbol(s) changed from " << x.first << " to " << x.second;
240 }
241 
operator <<(std::ostream & os,TypeFidelityTransition x)242 std::ostream& operator<<(std::ostream& os, TypeFidelityTransition x) {
243   return os << "type(s) changed from " << x.first << " to " << x.second;
244 }
245 
GetFidelityTransitions(const Graph & graph,Id root1,Id root2)246 FidelityDiff GetFidelityTransitions(const Graph& graph, Id root1, Id root2) {
247   NameCache name_cache;
248   Fidelity fidelity1(graph, name_cache);
249   Fidelity fidelity2(graph, name_cache);
250   fidelity1(root1);
251   fidelity2(root2);
252 
253   FidelityDiff diff;
254   InsertTransitions(diff, fidelity1.symbols, fidelity2.symbols);
255   InsertTransitions(diff, fidelity1.types, fidelity2.types);
256   return diff;
257 }
258 
259 }  // namespace stg
260