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