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" ); |
26 | LanguageSet::LanguageSet() : bitvector(eNumLanguageTypes, false) {} |
27 | |
28 | std::optional<LanguageType> LanguageSet::GetSingularLanguage() { |
29 | if (bitvector.count() == 1) |
30 | return (LanguageType)bitvector.find_first(); |
31 | return {}; |
32 | } |
33 | |
34 | void LanguageSet::Insert(LanguageType language) { bitvector.set(language); } |
35 | size_t LanguageSet::Size() const { return bitvector.count(); } |
36 | bool LanguageSet::Empty() const { return bitvector.none(); } |
37 | bool LanguageSet::operator[](unsigned i) const { return bitvector[i]; } |
38 | |
39 | TypeSystem::TypeSystem() = default; |
40 | TypeSystem::~TypeSystem() = default; |
41 | |
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 | idx: i++)) != nullptr) { |
48 | if (auto type_system_sp = create_callback(language, module, target)) |
49 | return type_system_sp; |
50 | } |
51 | |
52 | return {}; |
53 | } |
54 | |
55 | lldb::TypeSystemSP TypeSystem::CreateInstance(lldb::LanguageType language, |
56 | Module *module) { |
57 | return CreateInstanceHelper(language, module, target: nullptr); |
58 | } |
59 | |
60 | lldb::TypeSystemSP TypeSystem::CreateInstance(lldb::LanguageType language, |
61 | Target *target) { |
62 | return CreateInstanceHelper(language, module: nullptr, target); |
63 | } |
64 | |
65 | #ifndef NDEBUG |
66 | bool TypeSystem::Verify(lldb::opaque_compiler_type_t type) { return true; } |
67 | #endif |
68 | |
69 | bool TypeSystem::IsAnonymousType(lldb::opaque_compiler_type_t type) { |
70 | return false; |
71 | } |
72 | |
73 | CompilerType TypeSystem::GetArrayType(lldb::opaque_compiler_type_t type, |
74 | uint64_t size) { |
75 | return CompilerType(); |
76 | } |
77 | |
78 | CompilerType |
79 | TypeSystem::GetLValueReferenceType(lldb::opaque_compiler_type_t type) { |
80 | return CompilerType(); |
81 | } |
82 | |
83 | CompilerType |
84 | TypeSystem::GetRValueReferenceType(lldb::opaque_compiler_type_t type) { |
85 | return CompilerType(); |
86 | } |
87 | |
88 | CompilerType TypeSystem::GetAtomicType(lldb::opaque_compiler_type_t type) { |
89 | return CompilerType(); |
90 | } |
91 | |
92 | CompilerType TypeSystem::AddConstModifier(lldb::opaque_compiler_type_t type) { |
93 | return CompilerType(); |
94 | } |
95 | |
96 | CompilerType |
97 | TypeSystem::AddVolatileModifier(lldb::opaque_compiler_type_t type) { |
98 | return CompilerType(); |
99 | } |
100 | |
101 | CompilerType |
102 | TypeSystem::AddRestrictModifier(lldb::opaque_compiler_type_t type) { |
103 | return CompilerType(); |
104 | } |
105 | |
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 | |
113 | CompilerType TypeSystem::GetBuiltinTypeByName(ConstString name) { |
114 | return CompilerType(); |
115 | } |
116 | |
117 | CompilerType TypeSystem::GetTypeForFormatters(void *type) { |
118 | return CompilerType(weak_from_this(), type); |
119 | } |
120 | |
121 | bool TypeSystem::IsTemplateType(lldb::opaque_compiler_type_t type) { |
122 | return false; |
123 | } |
124 | |
125 | size_t TypeSystem::GetNumTemplateArguments(lldb::opaque_compiler_type_t type, |
126 | bool expand_pack) { |
127 | return 0; |
128 | } |
129 | |
130 | TemplateArgumentKind |
131 | TypeSystem::GetTemplateArgumentKind(opaque_compiler_type_t type, size_t idx, |
132 | bool expand_pack) { |
133 | return eTemplateArgumentKindNull; |
134 | } |
135 | |
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> |
142 | TypeSystem::GetIntegralTemplateArgument(opaque_compiler_type_t type, size_t idx, |
143 | bool expand_pack) { |
144 | return std::nullopt; |
145 | } |
146 | |
147 | LazyBool TypeSystem::ShouldPrintAsOneLiner(void *type, ValueObject *valobj) { |
148 | return eLazyBoolCalculate; |
149 | } |
150 | |
151 | bool TypeSystem::IsMeaninglessWithoutDynamicResolution(void *type) { |
152 | return false; |
153 | } |
154 | |
155 | ConstString TypeSystem::DeclGetMangledName(void *opaque_decl) { |
156 | return ConstString(); |
157 | } |
158 | |
159 | CompilerDeclContext TypeSystem::DeclGetDeclContext(void *opaque_decl) { |
160 | return CompilerDeclContext(); |
161 | } |
162 | |
163 | CompilerType TypeSystem::DeclGetFunctionReturnType(void *opaque_decl) { |
164 | return CompilerType(); |
165 | } |
166 | |
167 | size_t TypeSystem::DeclGetFunctionNumArguments(void *opaque_decl) { return 0; } |
168 | |
169 | CompilerType TypeSystem::DeclGetFunctionArgumentType(void *opaque_decl, |
170 | size_t arg_idx) { |
171 | return CompilerType(); |
172 | } |
173 | |
174 | std::vector<lldb_private::CompilerContext> |
175 | TypeSystem::DeclGetCompilerContext(void *opaque_decl) { |
176 | return {}; |
177 | } |
178 | |
179 | std::vector<lldb_private::CompilerContext> |
180 | TypeSystem::DeclContextGetCompilerContext(void *opaque_decl_ctx) { |
181 | return {}; |
182 | } |
183 | |
184 | std::vector<CompilerDecl> |
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> |
191 | TypeSystem::CreateUtilityFunction(std::string text, std::string name) { |
192 | return {}; |
193 | } |
194 | |
195 | std::optional<llvm::json::Value> TypeSystem::ReportStatistics() { |
196 | return std::nullopt; |
197 | } |
198 | |
199 | CompilerDeclContext |
200 | TypeSystem::GetCompilerDeclContextForType(const CompilerType &type) { |
201 | return CompilerDeclContext(); |
202 | } |
203 | |
204 | #pragma mark TypeSystemMap |
205 | |
206 | TypeSystemMap::TypeSystemMap() : m_mutex(), m_map() {} |
207 | |
208 | TypeSystemMap::~TypeSystemMap() = default; |
209 | |
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(V: pair.second.get())) |
220 | continue; |
221 | visited.insert(V: 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 | |
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(V: type_system)) |
252 | continue; |
253 | visited.insert(V: type_system); |
254 | assert(type_system); |
255 | if (!callback(pair.second)) |
256 | break; |
257 | } |
258 | } |
259 | |
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 | Args: "Unable to get TypeSystem because TypeSystemMap is being cleared" , |
267 | Args: llvm::inconvertibleErrorCode()); |
268 | |
269 | collection::iterator pos = m_map.find(Val: 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 | Args: "TypeSystem for language " + |
277 | llvm::StringRef(Language::GetNameForLanguageType(language)) + |
278 | " doesn't exist" , |
279 | Args: 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 | Args: "TypeSystem for language " + |
291 | llvm::StringRef(Language::GetNameForLanguageType(language)) + |
292 | " doesn't exist" , |
293 | Args: llvm::inconvertibleErrorCode()); |
294 | } |
295 | } |
296 | |
297 | if (!create_callback) |
298 | return llvm::make_error<llvm::StringError>( |
299 | Args: "Unable to find type system for language " + |
300 | llvm::StringRef(Language::GetNameForLanguageType(language)), |
301 | Args: 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 | Args: "TypeSystem for language " + |
311 | llvm::StringRef(Language::GetNameForLanguageType(language)) + |
312 | " doesn't exist" , |
313 | Args: llvm::inconvertibleErrorCode()); |
314 | } |
315 | |
316 | llvm::Expected<lldb::TypeSystemSP> |
317 | TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, |
318 | Module *module, bool can_create) { |
319 | if (can_create) { |
320 | return GetTypeSystemForLanguage( |
321 | language, create_callback: std::optional<CreateCallback>([language, module]() { |
322 | return TypeSystem::CreateInstance(language, module); |
323 | })); |
324 | } |
325 | return GetTypeSystemForLanguage(language); |
326 | } |
327 | |
328 | llvm::Expected<lldb::TypeSystemSP> |
329 | TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, |
330 | Target *target, bool can_create) { |
331 | if (can_create) { |
332 | return GetTypeSystemForLanguage( |
333 | language, create_callback: std::optional<CreateCallback>([language, target]() { |
334 | return TypeSystem::CreateInstance(language, target); |
335 | })); |
336 | } |
337 | return GetTypeSystemForLanguage(language); |
338 | } |
339 | |