1 //===-- TypeSystem.cpp ------------------------------------------*- C++ -*-===//
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 //
10 //  TypeSystem.cpp
11 //  lldb
12 //
13 //  Created by Ryan Brown on 3/29/15.
14 //
15 //
16 
17 #include "lldb/Symbol/TypeSystem.h"
18 
19 #include <set>
20 
21 #include "lldb/Core/PluginManager.h"
22 #include "lldb/Symbol/CompilerType.h"
23 #include "lldb/Target/Language.h"
24 
25 using namespace lldb_private;
26 using namespace lldb;
27 
28 /// A 64-bit SmallBitVector is only small up to 64-7 bits, and the
29 /// setBitsInMask interface wants to write full bytes.
30 static const size_t num_small_bitvector_bits = 64 - 8;
31 static_assert(eNumLanguageTypes < num_small_bitvector_bits,
32               "Languages bit vector is no longer small on 64 bit systems");
33 
34 llvm::Optional<LanguageType> LanguageSet::GetSingularLanguage() {
35   if (bitvector.count() == 1)
36     return (LanguageType)bitvector.find_first();
37   return {};
38 }
39 
40 void LanguageSet::Insert(LanguageType language) { bitvector.set(language); }
41 size_t LanguageSet::Size() const { return bitvector.count(); }
42 bool LanguageSet::Empty() const { return bitvector.none(); }
43 bool LanguageSet::operator[](unsigned i) const { return bitvector[i]; }
44 
45 TypeSystem::TypeSystem(LLVMCastKind kind) : m_kind(kind), m_sym_file(nullptr) {}
46 
47 TypeSystem::~TypeSystem() {}
48 
49 static lldb::TypeSystemSP CreateInstanceHelper(lldb::LanguageType language,
50                                                Module *module, Target *target) {
51   uint32_t i = 0;
52   TypeSystemCreateInstance create_callback;
53   while ((create_callback = PluginManager::GetTypeSystemCreateCallbackAtIndex(
54               i++)) != nullptr) {
55     lldb::TypeSystemSP type_system_sp =
56         create_callback(language, module, target);
57     if (type_system_sp)
58       return type_system_sp;
59   }
60 
61   return lldb::TypeSystemSP();
62 }
63 
64 lldb::TypeSystemSP TypeSystem::CreateInstance(lldb::LanguageType language,
65                                               Module *module) {
66   return CreateInstanceHelper(language, module, nullptr);
67 }
68 
69 lldb::TypeSystemSP TypeSystem::CreateInstance(lldb::LanguageType language,
70                                               Target *target) {
71   return CreateInstanceHelper(language, nullptr, target);
72 }
73 
74 bool TypeSystem::IsAnonymousType(lldb::opaque_compiler_type_t type) {
75   return false;
76 }
77 
78 CompilerType TypeSystem::GetArrayType(lldb::opaque_compiler_type_t type,
79                                       uint64_t size) {
80   return CompilerType();
81 }
82 
83 CompilerType
84 TypeSystem::GetLValueReferenceType(lldb::opaque_compiler_type_t type) {
85   return CompilerType();
86 }
87 
88 CompilerType
89 TypeSystem::GetRValueReferenceType(lldb::opaque_compiler_type_t type) {
90   return CompilerType();
91 }
92 
93 CompilerType TypeSystem::AddConstModifier(lldb::opaque_compiler_type_t type) {
94   return CompilerType();
95 }
96 
97 CompilerType
98 TypeSystem::AddVolatileModifier(lldb::opaque_compiler_type_t type) {
99   return CompilerType();
100 }
101 
102 CompilerType
103 TypeSystem::AddRestrictModifier(lldb::opaque_compiler_type_t type) {
104   return CompilerType();
105 }
106 
107 CompilerType TypeSystem::CreateTypedef(lldb::opaque_compiler_type_t type,
108                                        const char *name,
109                                        const CompilerDeclContext &decl_ctx) {
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(this, type);
119 }
120 
121 size_t TypeSystem::GetNumTemplateArguments(lldb::opaque_compiler_type_t type) {
122   return 0;
123 }
124 
125 TemplateArgumentKind
126 TypeSystem::GetTemplateArgumentKind(opaque_compiler_type_t type, size_t idx) {
127   return eTemplateArgumentKindNull;
128 }
129 
130 CompilerType TypeSystem::GetTypeTemplateArgument(opaque_compiler_type_t type,
131                                                  size_t idx) {
132   return CompilerType();
133 }
134 
135 llvm::Optional<CompilerType::IntegralTemplateArgument>
136 TypeSystem::GetIntegralTemplateArgument(opaque_compiler_type_t type,
137                                         size_t idx) {
138   return llvm::None;
139 }
140 
141 LazyBool TypeSystem::ShouldPrintAsOneLiner(void *type, ValueObject *valobj) {
142   return eLazyBoolCalculate;
143 }
144 
145 bool TypeSystem::IsMeaninglessWithoutDynamicResolution(void *type) {
146   return false;
147 }
148 
149 ConstString TypeSystem::DeclGetMangledName(void *opaque_decl) {
150   return ConstString();
151 }
152 
153 CompilerDeclContext TypeSystem::DeclGetDeclContext(void *opaque_decl) {
154   return CompilerDeclContext();
155 }
156 
157 CompilerType TypeSystem::DeclGetFunctionReturnType(void *opaque_decl) {
158   return CompilerType();
159 }
160 
161 size_t TypeSystem::DeclGetFunctionNumArguments(void *opaque_decl) { return 0; }
162 
163 CompilerType TypeSystem::DeclGetFunctionArgumentType(void *opaque_decl,
164                                                      size_t arg_idx) {
165   return CompilerType();
166 }
167 
168 std::vector<CompilerDecl>
169 TypeSystem::DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name,
170                                       bool ignore_imported_decls) {
171   return std::vector<CompilerDecl>();
172 }
173 
174 #pragma mark TypeSystemMap
175 
176 TypeSystemMap::TypeSystemMap()
177     : m_mutex(), m_map(), m_clear_in_progress(false) {}
178 
179 TypeSystemMap::~TypeSystemMap() {}
180 
181 void TypeSystemMap::Clear() {
182   collection map;
183   {
184     std::lock_guard<std::mutex> guard(m_mutex);
185     map = m_map;
186     m_clear_in_progress = true;
187   }
188   std::set<TypeSystem *> visited;
189   for (auto pair : map) {
190     TypeSystem *type_system = pair.second.get();
191     if (type_system && !visited.count(type_system)) {
192       visited.insert(type_system);
193       type_system->Finalize();
194     }
195   }
196   map.clear();
197   {
198     std::lock_guard<std::mutex> guard(m_mutex);
199     m_map.clear();
200     m_clear_in_progress = false;
201   }
202 }
203 
204 void TypeSystemMap::ForEach(std::function<bool(TypeSystem *)> const &callback) {
205   std::lock_guard<std::mutex> guard(m_mutex);
206   // Use a std::set so we only call the callback once for each unique
207   // TypeSystem instance
208   std::set<TypeSystem *> visited;
209   for (auto pair : m_map) {
210     TypeSystem *type_system = pair.second.get();
211     if (type_system && !visited.count(type_system)) {
212       visited.insert(type_system);
213       if (!callback(type_system))
214         break;
215     }
216   }
217 }
218 
219 llvm::Expected<TypeSystem &>
220 TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language,
221                                         Module *module, bool can_create) {
222   llvm::Error error = llvm::Error::success();
223   assert(!error); // Check the success value when assertions are enabled
224   std::lock_guard<std::mutex> guard(m_mutex);
225   if (m_clear_in_progress) {
226     error = llvm::make_error<llvm::StringError>(
227         "Unable to get TypeSystem because TypeSystemMap is being cleared",
228         llvm::inconvertibleErrorCode());
229   } else {
230     collection::iterator pos = m_map.find(language);
231     if (pos != m_map.end()) {
232       auto *type_system = pos->second.get();
233       if (type_system) {
234         llvm::consumeError(std::move(error));
235         return *type_system;
236       }
237       error = llvm::make_error<llvm::StringError>(
238           "TypeSystem for language " +
239               llvm::toStringRef(Language::GetNameForLanguageType(language)) +
240               " doesn't exist",
241           llvm::inconvertibleErrorCode());
242       return std::move(error);
243     }
244 
245     for (const auto &pair : m_map) {
246       if (pair.second && pair.second->SupportsLanguage(language)) {
247         // Add a new mapping for "language" to point to an already existing
248         // TypeSystem that supports this language
249         m_map[language] = pair.second;
250         if (pair.second.get()) {
251           llvm::consumeError(std::move(error));
252           return *pair.second.get();
253         }
254         error = llvm::make_error<llvm::StringError>(
255             "TypeSystem for language " +
256                 llvm::toStringRef(Language::GetNameForLanguageType(language)) +
257                 " doesn't exist",
258             llvm::inconvertibleErrorCode());
259         return std::move(error);
260       }
261     }
262 
263     if (!can_create) {
264       error = llvm::make_error<llvm::StringError>(
265           "Unable to find type system for language " +
266               llvm::toStringRef(Language::GetNameForLanguageType(language)),
267           llvm::inconvertibleErrorCode());
268     } else {
269       // Cache even if we get a shared pointer that contains a null type system
270       // back
271       auto type_system_sp = TypeSystem::CreateInstance(language, module);
272       m_map[language] = type_system_sp;
273       if (type_system_sp.get()) {
274         llvm::consumeError(std::move(error));
275         return *type_system_sp.get();
276       }
277       error = llvm::make_error<llvm::StringError>(
278           "TypeSystem for language " +
279               llvm::toStringRef(Language::GetNameForLanguageType(language)) +
280               " doesn't exist",
281           llvm::inconvertibleErrorCode());
282     }
283   }
284 
285   return std::move(error);
286 }
287 
288 llvm::Expected<TypeSystem &>
289 TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language,
290                                         Target *target, bool can_create) {
291   llvm::Error error = llvm::Error::success();
292   assert(!error); // Check the success value when assertions are enabled
293   std::lock_guard<std::mutex> guard(m_mutex);
294   if (m_clear_in_progress) {
295     error = llvm::make_error<llvm::StringError>(
296         "Unable to get TypeSystem because TypeSystemMap is being cleared",
297         llvm::inconvertibleErrorCode());
298   } else {
299     collection::iterator pos = m_map.find(language);
300     if (pos != m_map.end()) {
301       auto *type_system = pos->second.get();
302       if (type_system) {
303         llvm::consumeError(std::move(error));
304         return *type_system;
305       }
306       error = llvm::make_error<llvm::StringError>(
307           "TypeSystem for language " +
308               llvm::toStringRef(Language::GetNameForLanguageType(language)) +
309               " doesn't exist",
310           llvm::inconvertibleErrorCode());
311       return std::move(error);
312     }
313 
314     for (const auto &pair : m_map) {
315       if (pair.second && pair.second->SupportsLanguage(language)) {
316         // Add a new mapping for "language" to point to an already existing
317         // TypeSystem that supports this language
318         m_map[language] = pair.second;
319         if (pair.second.get()) {
320           llvm::consumeError(std::move(error));
321           return *pair.second.get();
322         }
323         error = llvm::make_error<llvm::StringError>(
324             "TypeSystem for language " +
325                 llvm::toStringRef(Language::GetNameForLanguageType(language)) +
326                 " doesn't exist",
327             llvm::inconvertibleErrorCode());
328         return std::move(error);
329       }
330     }
331 
332     if (!can_create) {
333       error = llvm::make_error<llvm::StringError>(
334           "Unable to find type system for language " +
335               llvm::toStringRef(Language::GetNameForLanguageType(language)),
336           llvm::inconvertibleErrorCode());
337     } else {
338       // Cache even if we get a shared pointer that contains a null type system
339       // back
340       auto type_system_sp = TypeSystem::CreateInstance(language, target);
341       m_map[language] = type_system_sp;
342       if (type_system_sp.get()) {
343         llvm::consumeError(std::move(error));
344         return *type_system_sp.get();
345       }
346       error = llvm::make_error<llvm::StringError>(
347           "TypeSystem for language " +
348               llvm::toStringRef(Language::GetNameForLanguageType(language)) +
349               " doesn't exist",
350           llvm::inconvertibleErrorCode());
351     }
352   }
353 
354   return std::move(error);
355 }
356