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