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