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