1 //===-- TypeSystem.cpp ----------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Symbol/TypeSystem.h"
10 #include "lldb/Core/PluginManager.h"
11 #include "lldb/Expression/UtilityFunction.h"
12 #include "lldb/Symbol/CompilerType.h"
13 #include "lldb/Target/Language.h"
14 
15 #include "llvm/ADT/DenseSet.h"
16 #include <optional>
17 
18 using namespace lldb_private;
19 using namespace lldb;
20 
21 /// A 64-bit SmallBitVector is only small up to 64-7 bits, and the
22 /// setBitsInMask interface wants to write full bytes.
23 static const size_t g_num_small_bitvector_bits = 64 - 8;
24 static_assert(eNumLanguageTypes < g_num_small_bitvector_bits,
25               "Languages bit vector is no longer small on 64 bit systems");
26 LanguageSet::LanguageSet() : bitvector(eNumLanguageTypes, false) {}
27 
28 std::optional<LanguageType> LanguageSet::GetSingularLanguage() {
29   if (bitvector.count() == 1)
30     return (LanguageType)bitvector.find_first();
31   return {};
32 }
33 
34 void LanguageSet::Insert(LanguageType language) { bitvector.set(language); }
35 size_t LanguageSet::Size() const { return bitvector.count(); }
36 bool LanguageSet::Empty() const { return bitvector.none(); }
37 bool LanguageSet::operator[](unsigned i) const { return bitvector[i]; }
38 
39 TypeSystem::TypeSystem() = default;
40 TypeSystem::~TypeSystem() = default;
41 
42 static TypeSystemSP CreateInstanceHelper(lldb::LanguageType language,
43                                          Module *module, Target *target) {
44   uint32_t i = 0;
45   TypeSystemCreateInstance create_callback;
46   while ((create_callback = PluginManager::GetTypeSystemCreateCallbackAtIndex(
47               i++)) != nullptr) {
48     if (auto type_system_sp = create_callback(language, module, target))
49       return type_system_sp;
50   }
51 
52   return {};
53 }
54 
55 lldb::TypeSystemSP TypeSystem::CreateInstance(lldb::LanguageType language,
56                                               Module *module) {
57   return CreateInstanceHelper(language, module, nullptr);
58 }
59 
60 lldb::TypeSystemSP TypeSystem::CreateInstance(lldb::LanguageType language,
61                                               Target *target) {
62   return CreateInstanceHelper(language, nullptr, target);
63 }
64 
65 #ifndef NDEBUG
66 bool TypeSystem::Verify(lldb::opaque_compiler_type_t type) { return true; }
67 #endif
68 
69 bool TypeSystem::IsAnonymousType(lldb::opaque_compiler_type_t type) {
70   return false;
71 }
72 
73 CompilerType TypeSystem::GetArrayType(lldb::opaque_compiler_type_t type,
74                                       uint64_t size) {
75   return CompilerType();
76 }
77 
78 CompilerType
79 TypeSystem::GetLValueReferenceType(lldb::opaque_compiler_type_t type) {
80   return CompilerType();
81 }
82 
83 CompilerType
84 TypeSystem::GetRValueReferenceType(lldb::opaque_compiler_type_t type) {
85   return CompilerType();
86 }
87 
88 CompilerType TypeSystem::GetAtomicType(lldb::opaque_compiler_type_t type) {
89   return CompilerType();
90 }
91 
92 CompilerType TypeSystem::AddConstModifier(lldb::opaque_compiler_type_t type) {
93   return CompilerType();
94 }
95 
96 CompilerType
97 TypeSystem::AddVolatileModifier(lldb::opaque_compiler_type_t type) {
98   return CompilerType();
99 }
100 
101 CompilerType
102 TypeSystem::AddRestrictModifier(lldb::opaque_compiler_type_t type) {
103   return CompilerType();
104 }
105 
106 CompilerType TypeSystem::CreateTypedef(lldb::opaque_compiler_type_t type,
107                                        const char *name,
108                                        const CompilerDeclContext &decl_ctx,
109                                        uint32_t opaque_payload) {
110   return CompilerType();
111 }
112 
113 CompilerType TypeSystem::GetBuiltinTypeByName(ConstString name) {
114   return CompilerType();
115 }
116 
117 CompilerType TypeSystem::GetTypeForFormatters(void *type) {
118   return CompilerType(weak_from_this(), type);
119 }
120 
121 bool TypeSystem::IsTemplateType(lldb::opaque_compiler_type_t type) {
122   return false;
123 }
124 
125 size_t TypeSystem::GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
126                                            bool expand_pack) {
127   return 0;
128 }
129 
130 TemplateArgumentKind
131 TypeSystem::GetTemplateArgumentKind(opaque_compiler_type_t type, size_t idx,
132                                     bool expand_pack) {
133   return eTemplateArgumentKindNull;
134 }
135 
136 CompilerType TypeSystem::GetTypeTemplateArgument(opaque_compiler_type_t type,
137                                                  size_t idx, bool expand_pack) {
138   return CompilerType();
139 }
140 
141 std::optional<CompilerType::IntegralTemplateArgument>
142 TypeSystem::GetIntegralTemplateArgument(opaque_compiler_type_t type, size_t idx,
143                                         bool expand_pack) {
144   return std::nullopt;
145 }
146 
147 LazyBool TypeSystem::ShouldPrintAsOneLiner(void *type, ValueObject *valobj) {
148   return eLazyBoolCalculate;
149 }
150 
151 bool TypeSystem::IsMeaninglessWithoutDynamicResolution(void *type) {
152   return false;
153 }
154 
155 ConstString TypeSystem::DeclGetMangledName(void *opaque_decl) {
156   return ConstString();
157 }
158 
159 CompilerDeclContext TypeSystem::DeclGetDeclContext(void *opaque_decl) {
160   return CompilerDeclContext();
161 }
162 
163 CompilerType TypeSystem::DeclGetFunctionReturnType(void *opaque_decl) {
164   return CompilerType();
165 }
166 
167 size_t TypeSystem::DeclGetFunctionNumArguments(void *opaque_decl) { return 0; }
168 
169 CompilerType TypeSystem::DeclGetFunctionArgumentType(void *opaque_decl,
170                                                      size_t arg_idx) {
171   return CompilerType();
172 }
173 
174 std::vector<CompilerDecl>
175 TypeSystem::DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name,
176                                       bool ignore_imported_decls) {
177   return std::vector<CompilerDecl>();
178 }
179 
180 std::unique_ptr<UtilityFunction>
181 TypeSystem::CreateUtilityFunction(std::string text, std::string name) {
182   return {};
183 }
184 
185 std::optional<llvm::json::Value> TypeSystem::ReportStatistics() {
186   return std::nullopt;
187 }
188 
189 #pragma mark TypeSystemMap
190 
191 TypeSystemMap::TypeSystemMap() : m_mutex(), m_map() {}
192 
193 TypeSystemMap::~TypeSystemMap() = default;
194 
195 void TypeSystemMap::Clear() {
196   collection map;
197   {
198     std::lock_guard<std::mutex> guard(m_mutex);
199     map = m_map;
200     m_clear_in_progress = true;
201   }
202   llvm::DenseSet<TypeSystem *> visited;
203   for (auto &pair : map) {
204     if (visited.count(pair.second.get()))
205       continue;
206     visited.insert(pair.second.get());
207     if (lldb::TypeSystemSP type_system = pair.second)
208       type_system->Finalize();
209   }
210   map.clear();
211   {
212     std::lock_guard<std::mutex> guard(m_mutex);
213     m_map.clear();
214     m_clear_in_progress = false;
215   }
216 }
217 
218 void TypeSystemMap::ForEach(
219     std::function<bool(lldb::TypeSystemSP)> const &callback) {
220 
221   // The callback may call into this function again causing
222   // us to lock m_mutex twice if we held it across the callback.
223   // Since we just care about guarding access to 'm_map', make
224   // a local copy and iterate over that instead.
225   collection map_snapshot;
226   {
227       std::lock_guard<std::mutex> guard(m_mutex);
228       map_snapshot = m_map;
229   }
230 
231   // Use a std::set so we only call the callback once for each unique
232   // TypeSystem instance.
233   llvm::DenseSet<TypeSystem *> visited;
234   for (auto &pair : map_snapshot) {
235     TypeSystem *type_system = pair.second.get();
236     if (!type_system || visited.count(type_system))
237       continue;
238     visited.insert(type_system);
239     assert(type_system);
240     if (!callback(pair.second))
241       break;
242   }
243 }
244 
245 llvm::Expected<lldb::TypeSystemSP> TypeSystemMap::GetTypeSystemForLanguage(
246     lldb::LanguageType language,
247     std::optional<CreateCallback> create_callback) {
248   std::lock_guard<std::mutex> guard(m_mutex);
249   if (m_clear_in_progress)
250     return llvm::make_error<llvm::StringError>(
251         "Unable to get TypeSystem because TypeSystemMap is being cleared",
252         llvm::inconvertibleErrorCode());
253 
254   collection::iterator pos = m_map.find(language);
255   if (pos != m_map.end()) {
256     if (pos->second) {
257       assert(!pos->second->weak_from_this().expired());
258       return pos->second;
259     }
260     return llvm::make_error<llvm::StringError>(
261         "TypeSystem for language " +
262             llvm::StringRef(Language::GetNameForLanguageType(language)) +
263             " doesn't exist",
264         llvm::inconvertibleErrorCode());
265   }
266 
267   for (const auto &pair : m_map) {
268     if (pair.second && pair.second->SupportsLanguage(language)) {
269       // Add a new mapping for "language" to point to an already existing
270       // TypeSystem that supports this language
271       m_map[language] = pair.second;
272       if (pair.second)
273         return pair.second;
274       return llvm::make_error<llvm::StringError>(
275           "TypeSystem for language " +
276               llvm::StringRef(Language::GetNameForLanguageType(language)) +
277               " doesn't exist",
278           llvm::inconvertibleErrorCode());
279     }
280   }
281 
282   if (!create_callback)
283     return llvm::make_error<llvm::StringError>(
284         "Unable to find type system for language " +
285             llvm::StringRef(Language::GetNameForLanguageType(language)),
286         llvm::inconvertibleErrorCode());
287 
288   // Cache even if we get a shared pointer that contains a null type system
289   // back.
290   TypeSystemSP type_system_sp = (*create_callback)();
291   m_map[language] = type_system_sp;
292   if (type_system_sp)
293     return type_system_sp;
294   return llvm::make_error<llvm::StringError>(
295       "TypeSystem for language " +
296           llvm::StringRef(Language::GetNameForLanguageType(language)) +
297           " doesn't exist",
298       llvm::inconvertibleErrorCode());
299 }
300 
301 llvm::Expected<lldb::TypeSystemSP>
302 TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language,
303                                         Module *module, bool can_create) {
304   if (can_create) {
305     return GetTypeSystemForLanguage(
306         language, std::optional<CreateCallback>([language, module]() {
307           return TypeSystem::CreateInstance(language, module);
308         }));
309   }
310   return GetTypeSystemForLanguage(language);
311 }
312 
313 llvm::Expected<lldb::TypeSystemSP>
314 TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language,
315                                         Target *target, bool can_create) {
316   if (can_create) {
317     return GetTypeSystemForLanguage(
318         language, std::optional<CreateCallback>([language, target]() {
319           return TypeSystem::CreateInstance(language, target);
320         }));
321   }
322   return GetTypeSystemForLanguage(language);
323 }
324