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