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