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
18using namespace lldb_private;
19using 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.
23static const size_t g_num_small_bitvector_bits = 64 - 8;
24static_assert(eNumLanguageTypes < g_num_small_bitvector_bits,
25              "Languages bit vector is no longer small on 64 bit systems");
26LanguageSet::LanguageSet() : bitvector(eNumLanguageTypes, false) {}
27
28std::optional<LanguageType> LanguageSet::GetSingularLanguage() {
29  if (bitvector.count() == 1)
30    return (LanguageType)bitvector.find_first();
31  return {};
32}
33
34void LanguageSet::Insert(LanguageType language) { bitvector.set(language); }
35size_t LanguageSet::Size() const { return bitvector.count(); }
36bool LanguageSet::Empty() const { return bitvector.none(); }
37bool LanguageSet::operator[](unsigned i) const { return bitvector[i]; }
38
39TypeSystem::TypeSystem() = default;
40TypeSystem::~TypeSystem() = default;
41
42static 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
55lldb::TypeSystemSP TypeSystem::CreateInstance(lldb::LanguageType language,
56                                              Module *module) {
57  return CreateInstanceHelper(language, module, nullptr);
58}
59
60lldb::TypeSystemSP TypeSystem::CreateInstance(lldb::LanguageType language,
61                                              Target *target) {
62  return CreateInstanceHelper(language, nullptr, target);
63}
64
65#ifndef NDEBUG
66bool TypeSystem::Verify(lldb::opaque_compiler_type_t type) { return true; }
67#endif
68
69bool TypeSystem::IsAnonymousType(lldb::opaque_compiler_type_t type) {
70  return false;
71}
72
73CompilerType TypeSystem::GetArrayType(lldb::opaque_compiler_type_t type,
74                                      uint64_t size) {
75  return CompilerType();
76}
77
78CompilerType
79TypeSystem::GetLValueReferenceType(lldb::opaque_compiler_type_t type) {
80  return CompilerType();
81}
82
83CompilerType
84TypeSystem::GetRValueReferenceType(lldb::opaque_compiler_type_t type) {
85  return CompilerType();
86}
87
88CompilerType TypeSystem::GetAtomicType(lldb::opaque_compiler_type_t type) {
89  return CompilerType();
90}
91
92CompilerType TypeSystem::AddConstModifier(lldb::opaque_compiler_type_t type) {
93  return CompilerType();
94}
95
96CompilerType
97TypeSystem::AddVolatileModifier(lldb::opaque_compiler_type_t type) {
98  return CompilerType();
99}
100
101CompilerType
102TypeSystem::AddRestrictModifier(lldb::opaque_compiler_type_t type) {
103  return CompilerType();
104}
105
106CompilerType 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
113CompilerType TypeSystem::GetBuiltinTypeByName(ConstString name) {
114  return CompilerType();
115}
116
117CompilerType TypeSystem::GetTypeForFormatters(void *type) {
118  return CompilerType(weak_from_this(), type);
119}
120
121bool TypeSystem::IsTemplateType(lldb::opaque_compiler_type_t type) {
122  return false;
123}
124
125size_t TypeSystem::GetNumTemplateArguments(lldb::opaque_compiler_type_t type,
126                                           bool expand_pack) {
127  return 0;
128}
129
130TemplateArgumentKind
131TypeSystem::GetTemplateArgumentKind(opaque_compiler_type_t type, size_t idx,
132                                    bool expand_pack) {
133  return eTemplateArgumentKindNull;
134}
135
136CompilerType TypeSystem::GetTypeTemplateArgument(opaque_compiler_type_t type,
137                                                 size_t idx, bool expand_pack) {
138  return CompilerType();
139}
140
141std::optional<CompilerType::IntegralTemplateArgument>
142TypeSystem::GetIntegralTemplateArgument(opaque_compiler_type_t type, size_t idx,
143                                        bool expand_pack) {
144  return std::nullopt;
145}
146
147LazyBool TypeSystem::ShouldPrintAsOneLiner(void *type, ValueObject *valobj) {
148  return eLazyBoolCalculate;
149}
150
151bool TypeSystem::IsMeaninglessWithoutDynamicResolution(void *type) {
152  return false;
153}
154
155ConstString TypeSystem::DeclGetMangledName(void *opaque_decl) {
156  return ConstString();
157}
158
159CompilerDeclContext TypeSystem::DeclGetDeclContext(void *opaque_decl) {
160  return CompilerDeclContext();
161}
162
163CompilerType TypeSystem::DeclGetFunctionReturnType(void *opaque_decl) {
164  return CompilerType();
165}
166
167size_t TypeSystem::DeclGetFunctionNumArguments(void *opaque_decl) { return 0; }
168
169CompilerType TypeSystem::DeclGetFunctionArgumentType(void *opaque_decl,
170                                                     size_t arg_idx) {
171  return CompilerType();
172}
173
174std::vector<lldb_private::CompilerContext>
175TypeSystem::DeclGetCompilerContext(void *opaque_decl) {
176  return {};
177}
178
179std::vector<lldb_private::CompilerContext>
180TypeSystem::DeclContextGetCompilerContext(void *opaque_decl_ctx) {
181  return {};
182}
183
184std::vector<CompilerDecl>
185TypeSystem::DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name,
186                                      bool ignore_imported_decls) {
187  return std::vector<CompilerDecl>();
188}
189
190std::unique_ptr<UtilityFunction>
191TypeSystem::CreateUtilityFunction(std::string text, std::string name) {
192  return {};
193}
194
195std::optional<llvm::json::Value> TypeSystem::ReportStatistics() {
196  return std::nullopt;
197}
198
199CompilerDeclContext
200TypeSystem::GetCompilerDeclContextForType(const CompilerType &type) {
201  return CompilerDeclContext();
202}
203
204#pragma mark TypeSystemMap
205
206TypeSystemMap::TypeSystemMap() : m_mutex(), m_map() {}
207
208TypeSystemMap::~TypeSystemMap() = default;
209
210void 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
233void 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
260llvm::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
316llvm::Expected<lldb::TypeSystemSP>
317TypeSystemMap::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
328llvm::Expected<lldb::TypeSystemSP>
329TypeSystemMap::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