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