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