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