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