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 TypeSystem::~TypeSystem() = default;
41 
CreateInstanceHelper(lldb::LanguageType language,Module * module,Target * target)42 static TypeSystemSP CreateInstanceHelper(lldb::LanguageType language,
43                                          Module *module, Target *target) {
44   uint32_t i = 0;
45   TypeSystemCreateInstance create_callback;
46   while ((create_callback = PluginManager::GetTypeSystemCreateCallbackAtIndex(
47               i++)) != nullptr) {
48     if (auto type_system_sp = create_callback(language, module, target))
49       return type_system_sp;
50   }
51 
52   return {};
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(weak_from_this(), type);
119 }
120 
IsTemplateType(lldb::opaque_compiler_type_t type)121 bool TypeSystem::IsTemplateType(lldb::opaque_compiler_type_t type) {
122   return false;
123 }
124 
GetNumTemplateArguments(lldb::opaque_compiler_type_t type,bool expand_pack)125 size_t TypeSystem::GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
126                                            bool expand_pack) {
127   return 0;
128 }
129 
130 TemplateArgumentKind
GetTemplateArgumentKind(opaque_compiler_type_t type,size_t idx,bool expand_pack)131 TypeSystem::GetTemplateArgumentKind(opaque_compiler_type_t type, size_t idx,
132                                     bool expand_pack) {
133   return eTemplateArgumentKindNull;
134 }
135 
GetTypeTemplateArgument(opaque_compiler_type_t type,size_t idx,bool expand_pack)136 CompilerType TypeSystem::GetTypeTemplateArgument(opaque_compiler_type_t type,
137                                                  size_t idx, bool expand_pack) {
138   return CompilerType();
139 }
140 
141 std::optional<CompilerType::IntegralTemplateArgument>
GetIntegralTemplateArgument(opaque_compiler_type_t type,size_t idx,bool expand_pack)142 TypeSystem::GetIntegralTemplateArgument(opaque_compiler_type_t type, size_t idx,
143                                         bool expand_pack) {
144   return std::nullopt;
145 }
146 
ShouldPrintAsOneLiner(void * type,ValueObject * valobj)147 LazyBool TypeSystem::ShouldPrintAsOneLiner(void *type, ValueObject *valobj) {
148   return eLazyBoolCalculate;
149 }
150 
IsMeaninglessWithoutDynamicResolution(void * type)151 bool TypeSystem::IsMeaninglessWithoutDynamicResolution(void *type) {
152   return false;
153 }
154 
DeclGetMangledName(void * opaque_decl)155 ConstString TypeSystem::DeclGetMangledName(void *opaque_decl) {
156   return ConstString();
157 }
158 
DeclGetDeclContext(void * opaque_decl)159 CompilerDeclContext TypeSystem::DeclGetDeclContext(void *opaque_decl) {
160   return CompilerDeclContext();
161 }
162 
DeclGetFunctionReturnType(void * opaque_decl)163 CompilerType TypeSystem::DeclGetFunctionReturnType(void *opaque_decl) {
164   return CompilerType();
165 }
166 
DeclGetFunctionNumArguments(void * opaque_decl)167 size_t TypeSystem::DeclGetFunctionNumArguments(void *opaque_decl) { return 0; }
168 
DeclGetFunctionArgumentType(void * opaque_decl,size_t arg_idx)169 CompilerType TypeSystem::DeclGetFunctionArgumentType(void *opaque_decl,
170                                                      size_t arg_idx) {
171   return CompilerType();
172 }
173 
174 std::vector<lldb_private::CompilerContext>
DeclGetCompilerContext(void * opaque_decl)175 TypeSystem::DeclGetCompilerContext(void *opaque_decl) {
176   return {};
177 }
178 
179 std::vector<lldb_private::CompilerContext>
DeclContextGetCompilerContext(void * opaque_decl_ctx)180 TypeSystem::DeclContextGetCompilerContext(void *opaque_decl_ctx) {
181   return {};
182 }
183 
184 std::vector<CompilerDecl>
DeclContextFindDeclByName(void * opaque_decl_ctx,ConstString name,bool ignore_imported_decls)185 TypeSystem::DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name,
186                                       bool ignore_imported_decls) {
187   return std::vector<CompilerDecl>();
188 }
189 
190 std::unique_ptr<UtilityFunction>
CreateUtilityFunction(std::string text,std::string name)191 TypeSystem::CreateUtilityFunction(std::string text, std::string name) {
192   return {};
193 }
194 
ReportStatistics()195 std::optional<llvm::json::Value> TypeSystem::ReportStatistics() {
196   return std::nullopt;
197 }
198 
199 CompilerDeclContext
GetCompilerDeclContextForType(const CompilerType & type)200 TypeSystem::GetCompilerDeclContextForType(const CompilerType &type) {
201   return CompilerDeclContext();
202 }
203 
204 #pragma mark TypeSystemMap
205 
TypeSystemMap()206 TypeSystemMap::TypeSystemMap() : m_mutex(), m_map() {}
207 
208 TypeSystemMap::~TypeSystemMap() = default;
209 
Clear()210 void TypeSystemMap::Clear() {
211   collection map;
212   {
213     std::lock_guard<std::mutex> guard(m_mutex);
214     map = m_map;
215     m_clear_in_progress = true;
216   }
217   llvm::DenseSet<TypeSystem *> visited;
218   for (auto &pair : map) {
219     if (visited.count(pair.second.get()))
220       continue;
221     visited.insert(pair.second.get());
222     if (lldb::TypeSystemSP type_system = pair.second)
223       type_system->Finalize();
224   }
225   map.clear();
226   {
227     std::lock_guard<std::mutex> guard(m_mutex);
228     m_map.clear();
229     m_clear_in_progress = false;
230   }
231 }
232 
ForEach(std::function<bool (lldb::TypeSystemSP)> const & callback)233 void TypeSystemMap::ForEach(
234     std::function<bool(lldb::TypeSystemSP)> const &callback) {
235 
236   // The callback may call into this function again causing
237   // us to lock m_mutex twice if we held it across the callback.
238   // Since we just care about guarding access to 'm_map', make
239   // a local copy and iterate over that instead.
240   collection map_snapshot;
241   {
242       std::lock_guard<std::mutex> guard(m_mutex);
243       map_snapshot = m_map;
244   }
245 
246   // Use a std::set so we only call the callback once for each unique
247   // TypeSystem instance.
248   llvm::DenseSet<TypeSystem *> visited;
249   for (auto &pair : map_snapshot) {
250     TypeSystem *type_system = pair.second.get();
251     if (!type_system || visited.count(type_system))
252       continue;
253     visited.insert(type_system);
254     assert(type_system);
255     if (!callback(pair.second))
256       break;
257   }
258 }
259 
GetTypeSystemForLanguage(lldb::LanguageType language,std::optional<CreateCallback> create_callback)260 llvm::Expected<lldb::TypeSystemSP> TypeSystemMap::GetTypeSystemForLanguage(
261     lldb::LanguageType language,
262     std::optional<CreateCallback> create_callback) {
263   std::lock_guard<std::mutex> guard(m_mutex);
264   if (m_clear_in_progress)
265     return llvm::make_error<llvm::StringError>(
266         "Unable to get TypeSystem because TypeSystemMap is being cleared",
267         llvm::inconvertibleErrorCode());
268 
269   collection::iterator pos = m_map.find(language);
270   if (pos != m_map.end()) {
271     if (pos->second) {
272       assert(!pos->second->weak_from_this().expired());
273       return pos->second;
274     }
275     return llvm::make_error<llvm::StringError>(
276         "TypeSystem for language " +
277             llvm::StringRef(Language::GetNameForLanguageType(language)) +
278             " doesn't exist",
279         llvm::inconvertibleErrorCode());
280   }
281 
282   for (const auto &pair : m_map) {
283     if (pair.second && pair.second->SupportsLanguage(language)) {
284       // Add a new mapping for "language" to point to an already existing
285       // TypeSystem that supports this language
286       m_map[language] = pair.second;
287       if (pair.second)
288         return pair.second;
289       return llvm::make_error<llvm::StringError>(
290           "TypeSystem for language " +
291               llvm::StringRef(Language::GetNameForLanguageType(language)) +
292               " doesn't exist",
293           llvm::inconvertibleErrorCode());
294     }
295   }
296 
297   if (!create_callback)
298     return llvm::make_error<llvm::StringError>(
299         "Unable to find type system for language " +
300             llvm::StringRef(Language::GetNameForLanguageType(language)),
301         llvm::inconvertibleErrorCode());
302 
303   // Cache even if we get a shared pointer that contains a null type system
304   // back.
305   TypeSystemSP type_system_sp = (*create_callback)();
306   m_map[language] = type_system_sp;
307   if (type_system_sp)
308     return type_system_sp;
309   return llvm::make_error<llvm::StringError>(
310       "TypeSystem for language " +
311           llvm::StringRef(Language::GetNameForLanguageType(language)) +
312           " doesn't exist",
313       llvm::inconvertibleErrorCode());
314 }
315 
316 llvm::Expected<lldb::TypeSystemSP>
GetTypeSystemForLanguage(lldb::LanguageType language,Module * module,bool can_create)317 TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language,
318                                         Module *module, bool can_create) {
319   if (can_create) {
320     return GetTypeSystemForLanguage(
321         language, std::optional<CreateCallback>([language, module]() {
322           return TypeSystem::CreateInstance(language, module);
323         }));
324   }
325   return GetTypeSystemForLanguage(language);
326 }
327 
328 llvm::Expected<lldb::TypeSystemSP>
GetTypeSystemForLanguage(lldb::LanguageType language,Target * target,bool can_create)329 TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language,
330                                         Target *target, bool can_create) {
331   if (can_create) {
332     return GetTypeSystemForLanguage(
333         language, std::optional<CreateCallback>([language, target]() {
334           return TypeSystem::CreateInstance(language, target);
335         }));
336   }
337   return GetTypeSystemForLanguage(language);
338 }
339