10b57cec5SDimitry Andric //===-- ObjCLanguageRuntime.h -----------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 95ffd83dbSDimitry Andric #ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H 105ffd83dbSDimitry Andric #define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include <functional> 130b57cec5SDimitry Andric #include <map> 140b57cec5SDimitry Andric #include <memory> 15bdd1243dSDimitry Andric #include <optional> 160b57cec5SDimitry Andric #include <unordered_set> 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointPrecondition.h" 210b57cec5SDimitry Andric #include "lldb/Core/PluginInterface.h" 220b57cec5SDimitry Andric #include "lldb/Symbol/CompilerType.h" 230b57cec5SDimitry Andric #include "lldb/Symbol/Type.h" 240b57cec5SDimitry Andric #include "lldb/Target/LanguageRuntime.h" 2581ad6265SDimitry Andric #include "lldb/Utility/ConstString.h" 2606c3fb27SDimitry Andric #include "lldb/Utility/ThreadSafeDenseMap.h" 2706c3fb27SDimitry Andric #include "lldb/lldb-enumerations.h" 280b57cec5SDimitry Andric #include "lldb/lldb-private.h" 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric class CommandObjectObjC_ClassTable_Dump; 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric namespace lldb_private { 330b57cec5SDimitry Andric 345ffd83dbSDimitry Andric class TypeSystemClang; 350b57cec5SDimitry Andric class UtilityFunction; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric class ObjCLanguageRuntime : public LanguageRuntime { 380b57cec5SDimitry Andric public: 390b57cec5SDimitry Andric enum class ObjCRuntimeVersions { 400b57cec5SDimitry Andric eObjC_VersionUnknown = 0, 410b57cec5SDimitry Andric eAppleObjC_V1 = 1, 4206c3fb27SDimitry Andric eAppleObjC_V2 = 2, 4306c3fb27SDimitry Andric eGNUstep_libobjc2 = 3, 440b57cec5SDimitry Andric }; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric typedef lldb::addr_t ObjCISA; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric class ClassDescriptor; 490b57cec5SDimitry Andric typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP; 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric // the information that we want to support retrieving from an ObjC class this 520b57cec5SDimitry Andric // needs to be pure virtual since there are at least 2 different 530b57cec5SDimitry Andric // implementations of the runtime, and more might come 540b57cec5SDimitry Andric class ClassDescriptor { 550b57cec5SDimitry Andric public: ClassDescriptor()56fe6060f1SDimitry Andric ClassDescriptor() : m_type_wp() {} 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric virtual ~ClassDescriptor() = default; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric virtual ConstString GetClassName() = 0; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric virtual ClassDescriptorSP GetSuperclass() = 0; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric virtual ClassDescriptorSP GetMetaclass() const = 0; 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric // virtual if any implementation has some other version-specific rules but 670b57cec5SDimitry Andric // for the known v1/v2 this is all that needs to be done IsKVO()680b57cec5SDimitry Andric virtual bool IsKVO() { 690b57cec5SDimitry Andric if (m_is_kvo == eLazyBoolCalculate) { 700b57cec5SDimitry Andric const char *class_name = GetClassName().AsCString(); 710b57cec5SDimitry Andric if (class_name && *class_name) 720b57cec5SDimitry Andric m_is_kvo = 730b57cec5SDimitry Andric (LazyBool)(strstr(class_name, "NSKVONotifying_") == class_name); 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric return (m_is_kvo == eLazyBoolYes); 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric // virtual if any implementation has some other version-specific rules but 790b57cec5SDimitry Andric // for the known v1/v2 this is all that needs to be done IsCFType()800b57cec5SDimitry Andric virtual bool IsCFType() { 810b57cec5SDimitry Andric if (m_is_cf == eLazyBoolCalculate) { 820b57cec5SDimitry Andric const char *class_name = GetClassName().AsCString(); 830b57cec5SDimitry Andric if (class_name && *class_name) 840b57cec5SDimitry Andric m_is_cf = (LazyBool)(strcmp(class_name, "__NSCFType") == 0 || 850b57cec5SDimitry Andric strcmp(class_name, "NSCFType") == 0); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric return (m_is_cf == eLazyBoolYes); 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 9006c3fb27SDimitry Andric /// Determine whether this class is implemented in Swift. GetImplementationLanguage()9106c3fb27SDimitry Andric virtual lldb::LanguageType GetImplementationLanguage() const { 9206c3fb27SDimitry Andric return lldb::eLanguageTypeObjC; 9306c3fb27SDimitry Andric } 9406c3fb27SDimitry Andric 950b57cec5SDimitry Andric virtual bool IsValid() = 0; 960b57cec5SDimitry Andric 97fe6060f1SDimitry Andric /// There are two routines in the ObjC runtime that tagged pointer clients 98fe6060f1SDimitry Andric /// can call to get the value from their tagged pointer, one that retrieves 99fe6060f1SDimitry Andric /// it as an unsigned value and one a signed value. These two 100fe6060f1SDimitry Andric /// GetTaggedPointerInfo methods mirror those two ObjC runtime calls. 101fe6060f1SDimitry Andric /// @{ 1020b57cec5SDimitry Andric virtual bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, 1030b57cec5SDimitry Andric uint64_t *value_bits = nullptr, 1040b57cec5SDimitry Andric uint64_t *payload = nullptr) = 0; 1050b57cec5SDimitry Andric 106fe6060f1SDimitry Andric virtual bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr, 107fe6060f1SDimitry Andric int64_t *value_bits = nullptr, 108fe6060f1SDimitry Andric uint64_t *payload = nullptr) = 0; 109fe6060f1SDimitry Andric /// @} 110fe6060f1SDimitry Andric 1110b57cec5SDimitry Andric virtual uint64_t GetInstanceSize() = 0; 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric // use to implement version-specific additional constraints on pointers CheckPointer(lldb::addr_t value,uint32_t ptr_size)1140b57cec5SDimitry Andric virtual bool CheckPointer(lldb::addr_t value, uint32_t ptr_size) const { 1150b57cec5SDimitry Andric return true; 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric virtual ObjCISA GetISA() = 0; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // This should return true iff the interface could be completed 1210b57cec5SDimitry Andric virtual bool Describe(std::function<void (ObjCISA)> const & superclass_func,std::function<bool (const char *,const char *)> const & instance_method_func,std::function<bool (const char *,const char *)> const & class_method_func,std::function<bool (const char *,const char *,lldb::addr_t,uint64_t)> const & ivar_func)1220b57cec5SDimitry Andric Describe(std::function<void(ObjCISA)> const &superclass_func, 1230b57cec5SDimitry Andric std::function<bool(const char *, const char *)> const 1240b57cec5SDimitry Andric &instance_method_func, 1250b57cec5SDimitry Andric std::function<bool(const char *, const char *)> const 1260b57cec5SDimitry Andric &class_method_func, 1270b57cec5SDimitry Andric std::function<bool(const char *, const char *, lldb::addr_t, 1280b57cec5SDimitry Andric uint64_t)> const &ivar_func) const { 1290b57cec5SDimitry Andric return false; 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric GetType()1320b57cec5SDimitry Andric lldb::TypeSP GetType() { return m_type_wp.lock(); } 1330b57cec5SDimitry Andric SetType(const lldb::TypeSP & type_sp)1340b57cec5SDimitry Andric void SetType(const lldb::TypeSP &type_sp) { m_type_wp = type_sp; } 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric struct iVarDescriptor { 1370b57cec5SDimitry Andric ConstString m_name; 1380b57cec5SDimitry Andric CompilerType m_type; 1390b57cec5SDimitry Andric uint64_t m_size; 1400b57cec5SDimitry Andric int32_t m_offset; 1410b57cec5SDimitry Andric }; 1420b57cec5SDimitry Andric GetNumIVars()1430b57cec5SDimitry Andric virtual size_t GetNumIVars() { return 0; } 1440b57cec5SDimitry Andric GetIVarAtIndex(size_t idx)1450b57cec5SDimitry Andric virtual iVarDescriptor GetIVarAtIndex(size_t idx) { 1460b57cec5SDimitry Andric return iVarDescriptor(); 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric protected: 1500b57cec5SDimitry Andric bool IsPointerValid(lldb::addr_t value, uint32_t ptr_size, 1510b57cec5SDimitry Andric bool allow_NULLs = false, bool allow_tagged = false, 1520b57cec5SDimitry Andric bool check_version_specific = false) const; 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric private: 155fe6060f1SDimitry Andric LazyBool m_is_kvo = eLazyBoolCalculate; 156fe6060f1SDimitry Andric LazyBool m_is_cf = eLazyBoolCalculate; 1570b57cec5SDimitry Andric lldb::TypeWP m_type_wp; 1580b57cec5SDimitry Andric }; 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric class EncodingToType { 1610b57cec5SDimitry Andric public: 1620b57cec5SDimitry Andric virtual ~EncodingToType(); 1630b57cec5SDimitry Andric 1645ffd83dbSDimitry Andric virtual CompilerType RealizeType(TypeSystemClang &ast_ctx, const char *name, 165480093f4SDimitry Andric bool for_expression) = 0; 1660b57cec5SDimitry Andric virtual CompilerType RealizeType(const char *name, bool for_expression); 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric protected: 169bdd1243dSDimitry Andric std::shared_ptr<TypeSystemClang> m_scratch_ast_ctx_sp; 1700b57cec5SDimitry Andric }; 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric class ObjCExceptionPrecondition : public BreakpointPrecondition { 1730b57cec5SDimitry Andric public: 1740b57cec5SDimitry Andric ObjCExceptionPrecondition(); 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric ~ObjCExceptionPrecondition() override = default; 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric bool EvaluatePrecondition(StoppointCallbackContext &context) override; 1790b57cec5SDimitry Andric void GetDescription(Stream &stream, lldb::DescriptionLevel level) override; 1800b57cec5SDimitry Andric Status ConfigurePrecondition(Args &args) override; 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric protected: 1830b57cec5SDimitry Andric void AddClassName(const char *class_name); 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric private: 1860b57cec5SDimitry Andric std::unordered_set<std::string> m_class_names; 1870b57cec5SDimitry Andric }; 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric static lldb::BreakpointPreconditionSP 1900b57cec5SDimitry Andric GetBreakpointExceptionPrecondition(lldb::LanguageType language, 1910b57cec5SDimitry Andric bool throw_bp); 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric class TaggedPointerVendor { 1940b57cec5SDimitry Andric public: 1950b57cec5SDimitry Andric virtual ~TaggedPointerVendor() = default; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric virtual bool IsPossibleTaggedPointer(lldb::addr_t ptr) = 0; 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric virtual ObjCLanguageRuntime::ClassDescriptorSP 2000b57cec5SDimitry Andric GetClassDescriptor(lldb::addr_t ptr) = 0; 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric protected: 2030b57cec5SDimitry Andric TaggedPointerVendor() = default; 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric private: 2065ffd83dbSDimitry Andric TaggedPointerVendor(const TaggedPointerVendor &) = delete; 2075ffd83dbSDimitry Andric const TaggedPointerVendor &operator=(const TaggedPointerVendor &) = delete; 2080b57cec5SDimitry Andric }; 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric ~ObjCLanguageRuntime() override; 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric static char ID; 2130b57cec5SDimitry Andric isA(const void * ClassID)2140b57cec5SDimitry Andric bool isA(const void *ClassID) const override { 2150b57cec5SDimitry Andric return ClassID == &ID || LanguageRuntime::isA(ClassID); 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric classof(const LanguageRuntime * runtime)2180b57cec5SDimitry Andric static bool classof(const LanguageRuntime *runtime) { 2190b57cec5SDimitry Andric return runtime->isA(&ID); 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric Get(Process & process)2220b57cec5SDimitry Andric static ObjCLanguageRuntime *Get(Process &process) { 2230b57cec5SDimitry Andric return llvm::cast_or_null<ObjCLanguageRuntime>( 2240b57cec5SDimitry Andric process.GetLanguageRuntime(lldb::eLanguageTypeObjC)); 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric GetTaggedPointerVendor()2270b57cec5SDimitry Andric virtual TaggedPointerVendor *GetTaggedPointerVendor() { return nullptr; } 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric typedef std::shared_ptr<EncodingToType> EncodingToTypeSP; 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric virtual EncodingToTypeSP GetEncodingToType(); 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value); 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric ClassDescriptorSP GetNonKVOClassDescriptor(ValueObject &in_value); 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric virtual ClassDescriptorSP 2380b57cec5SDimitry Andric GetClassDescriptorFromClassName(ConstString class_name); 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa); 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric ClassDescriptorSP GetNonKVOClassDescriptor(ObjCISA isa); 2430b57cec5SDimitry Andric GetLanguageType()2440b57cec5SDimitry Andric lldb::LanguageType GetLanguageType() const override { 2450b57cec5SDimitry Andric return lldb::eLanguageTypeObjC; 2460b57cec5SDimitry Andric } 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric virtual bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp) = 0; 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric virtual bool ReadObjCLibrary(const lldb::ModuleSP &module_sp) = 0; 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric virtual bool HasReadObjCLibrary() = 0; 2530b57cec5SDimitry Andric 25481ad6265SDimitry Andric // These two methods actually use different caches. The only time we'll 25581ad6265SDimitry Andric // cache a sel_str is if we found a "selector specific stub" for the selector 25681ad6265SDimitry Andric // and conversely we only add to the SEL cache if we saw a regular dispatch. 2570b57cec5SDimitry Andric lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr, lldb::addr_t sel); 25881ad6265SDimitry Andric lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr, 25981ad6265SDimitry Andric llvm::StringRef sel_str); 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric void AddToMethodCache(lldb::addr_t class_addr, lldb::addr_t sel, 2620b57cec5SDimitry Andric lldb::addr_t impl_addr); 2630b57cec5SDimitry Andric 26481ad6265SDimitry Andric void AddToMethodCache(lldb::addr_t class_addr, llvm::StringRef sel_str, 26581ad6265SDimitry Andric lldb::addr_t impl_addr); 26681ad6265SDimitry Andric 2670b57cec5SDimitry Andric TypeAndOrName LookupInClassNameCache(lldb::addr_t class_addr); 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric void AddToClassNameCache(lldb::addr_t class_addr, const char *name, 2700b57cec5SDimitry Andric lldb::TypeSP type_sp); 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric void AddToClassNameCache(lldb::addr_t class_addr, 2730b57cec5SDimitry Andric const TypeAndOrName &class_or_type_name); 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric lldb::TypeSP LookupInCompleteClassCache(ConstString &name); 2760b57cec5SDimitry Andric 277bdd1243dSDimitry Andric std::optional<CompilerType> GetRuntimeType(CompilerType base_type) override; 2780b57cec5SDimitry Andric 279e8d8bef9SDimitry Andric virtual llvm::Expected<std::unique_ptr<UtilityFunction>> 280e8d8bef9SDimitry Andric CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) = 0; 2810b57cec5SDimitry Andric GetRuntimeVersion()2820b57cec5SDimitry Andric virtual ObjCRuntimeVersions GetRuntimeVersion() const { 2830b57cec5SDimitry Andric return ObjCRuntimeVersions::eObjC_VersionUnknown; 2840b57cec5SDimitry Andric } 2850b57cec5SDimitry Andric IsValidISA(ObjCISA isa)2860b57cec5SDimitry Andric bool IsValidISA(ObjCISA isa) { 2870b57cec5SDimitry Andric UpdateISAToDescriptorMap(); 2880b57cec5SDimitry Andric return m_isa_to_descriptor.count(isa) > 0; 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric virtual void UpdateISAToDescriptorMapIfNeeded() = 0; 2920b57cec5SDimitry Andric UpdateISAToDescriptorMap()2930b57cec5SDimitry Andric void UpdateISAToDescriptorMap() { 2940b57cec5SDimitry Andric if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id) { 2950b57cec5SDimitry Andric UpdateISAToDescriptorMapIfNeeded(); 2960b57cec5SDimitry Andric } 2970b57cec5SDimitry Andric } 2980b57cec5SDimitry Andric 2990b57cec5SDimitry Andric virtual ObjCISA GetISA(ConstString name); 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric virtual ObjCISA GetParentClass(ObjCISA isa); 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric // Finds the byte offset of the child_type ivar in parent_type. If it can't 3040b57cec5SDimitry Andric // find the offset, returns LLDB_INVALID_IVAR_OFFSET. 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric virtual size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, 3070b57cec5SDimitry Andric const char *ivar_name); 3080b57cec5SDimitry Andric HasNewLiteralsAndIndexing()3090b57cec5SDimitry Andric bool HasNewLiteralsAndIndexing() { 3100b57cec5SDimitry Andric if (m_has_new_literals_and_indexing == eLazyBoolCalculate) { 3110b57cec5SDimitry Andric if (CalculateHasNewLiteralsAndIndexing()) 3120b57cec5SDimitry Andric m_has_new_literals_and_indexing = eLazyBoolYes; 3130b57cec5SDimitry Andric else 3140b57cec5SDimitry Andric m_has_new_literals_and_indexing = eLazyBoolNo; 3150b57cec5SDimitry Andric } 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric return (m_has_new_literals_and_indexing == eLazyBoolYes); 3180b57cec5SDimitry Andric } 3190b57cec5SDimitry Andric SymbolsDidLoad(const ModuleList & module_list)3200b57cec5SDimitry Andric void SymbolsDidLoad(const ModuleList &module_list) override { 3210b57cec5SDimitry Andric m_negative_complete_class_cache.clear(); 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric bool GetTypeBitSize(const CompilerType &compiler_type, 3250b57cec5SDimitry Andric uint64_t &size) override; 3260b57cec5SDimitry Andric 3270b57cec5SDimitry Andric /// Check whether the name is "self" or "_cmd" and should show up in 3280b57cec5SDimitry Andric /// "frame variable". 3295ffd83dbSDimitry Andric bool IsAllowedRuntimeValue(ConstString name) override; 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric protected: 3320b57cec5SDimitry Andric // Classes that inherit from ObjCLanguageRuntime can see and modify these 3330b57cec5SDimitry Andric ObjCLanguageRuntime(Process *process); 3340b57cec5SDimitry Andric CalculateHasNewLiteralsAndIndexing()3350b57cec5SDimitry Andric virtual bool CalculateHasNewLiteralsAndIndexing() { return false; } 3360b57cec5SDimitry Andric ISAIsCached(ObjCISA isa)3370b57cec5SDimitry Andric bool ISAIsCached(ObjCISA isa) const { 3380b57cec5SDimitry Andric return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end(); 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric AddClass(ObjCISA isa,const ClassDescriptorSP & descriptor_sp)3410b57cec5SDimitry Andric bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp) { 3420b57cec5SDimitry Andric if (isa != 0) { 3430b57cec5SDimitry Andric m_isa_to_descriptor[isa] = descriptor_sp; 3440b57cec5SDimitry Andric return true; 3450b57cec5SDimitry Andric } 3460b57cec5SDimitry Andric return false; 3470b57cec5SDimitry Andric } 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp, 3500b57cec5SDimitry Andric const char *class_name); 3510b57cec5SDimitry Andric AddClass(ObjCISA isa,const ClassDescriptorSP & descriptor_sp,uint32_t class_name_hash)3520b57cec5SDimitry Andric bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp, 3530b57cec5SDimitry Andric uint32_t class_name_hash) { 3540b57cec5SDimitry Andric if (isa != 0) { 3550b57cec5SDimitry Andric m_isa_to_descriptor[isa] = descriptor_sp; 3560b57cec5SDimitry Andric m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa)); 3570b57cec5SDimitry Andric return true; 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric return false; 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric private: 36381ad6265SDimitry Andric // We keep two maps of <Class,Selector>->Implementation so we don't have 36481ad6265SDimitry Andric // to call the resolver function over and over. 36581ad6265SDimitry Andric // The first comes from regular obj_msgSend type dispatch, and maps the 36681ad6265SDimitry Andric // class + uniqued SEL value to an implementation. 36781ad6265SDimitry Andric // The second comes from the "selector-specific stubs", which are always 36881ad6265SDimitry Andric // of the form _objc_msgSend$SelectorName, so we don't know the uniqued 36981ad6265SDimitry Andric // selector, only the string name. 3700b57cec5SDimitry Andric 3710b57cec5SDimitry Andric // FIXME: We need to watch for the loading of Protocols, and flush the cache 3720b57cec5SDimitry Andric // for any 3730b57cec5SDimitry Andric // class that we see so changed. 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric struct ClassAndSel { 37681ad6265SDimitry Andric ClassAndSel() = default; 3770b57cec5SDimitry Andric ClassAndSelClassAndSel37881ad6265SDimitry Andric ClassAndSel(lldb::addr_t in_class_addr, lldb::addr_t in_sel_addr) 3790b57cec5SDimitry Andric : class_addr(in_class_addr), sel_addr(in_sel_addr) {} 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric bool operator==(const ClassAndSel &rhs) { 3820b57cec5SDimitry Andric if (class_addr == rhs.class_addr && sel_addr == rhs.sel_addr) 3830b57cec5SDimitry Andric return true; 3840b57cec5SDimitry Andric else 3850b57cec5SDimitry Andric return false; 3860b57cec5SDimitry Andric } 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric bool operator<(const ClassAndSel &rhs) const { 3890b57cec5SDimitry Andric if (class_addr < rhs.class_addr) 3900b57cec5SDimitry Andric return true; 3910b57cec5SDimitry Andric else if (class_addr > rhs.class_addr) 3920b57cec5SDimitry Andric return false; 3930b57cec5SDimitry Andric else { 3940b57cec5SDimitry Andric if (sel_addr < rhs.sel_addr) 3950b57cec5SDimitry Andric return true; 3960b57cec5SDimitry Andric else 3970b57cec5SDimitry Andric return false; 3980b57cec5SDimitry Andric } 3990b57cec5SDimitry Andric } 4000b57cec5SDimitry Andric 40181ad6265SDimitry Andric lldb::addr_t class_addr = LLDB_INVALID_ADDRESS; 40281ad6265SDimitry Andric lldb::addr_t sel_addr = LLDB_INVALID_ADDRESS; 40381ad6265SDimitry Andric }; 40481ad6265SDimitry Andric 40581ad6265SDimitry Andric struct ClassAndSelStr { 40681ad6265SDimitry Andric ClassAndSelStr() = default; 40781ad6265SDimitry Andric ClassAndSelStrClassAndSelStr40881ad6265SDimitry Andric ClassAndSelStr(lldb::addr_t in_class_addr, llvm::StringRef in_sel_name) 40981ad6265SDimitry Andric : class_addr(in_class_addr), sel_name(in_sel_name) {} 41081ad6265SDimitry Andric 41181ad6265SDimitry Andric bool operator==(const ClassAndSelStr &rhs) { 41281ad6265SDimitry Andric return class_addr == rhs.class_addr && sel_name == rhs.sel_name; 41381ad6265SDimitry Andric } 41481ad6265SDimitry Andric 41581ad6265SDimitry Andric bool operator<(const ClassAndSelStr &rhs) const { 41681ad6265SDimitry Andric if (class_addr < rhs.class_addr) 41781ad6265SDimitry Andric return true; 41881ad6265SDimitry Andric else if (class_addr > rhs.class_addr) 41981ad6265SDimitry Andric return false; 42081ad6265SDimitry Andric else 42181ad6265SDimitry Andric return ConstString::Compare(sel_name, rhs.sel_name); 42281ad6265SDimitry Andric } 42381ad6265SDimitry Andric 42481ad6265SDimitry Andric lldb::addr_t class_addr = LLDB_INVALID_ADDRESS; 42581ad6265SDimitry Andric ConstString sel_name; 4260b57cec5SDimitry Andric }; 4270b57cec5SDimitry Andric 4280b57cec5SDimitry Andric typedef std::map<ClassAndSel, lldb::addr_t> MsgImplMap; 42981ad6265SDimitry Andric typedef std::map<ClassAndSelStr, lldb::addr_t> MsgImplStrMap; 4300b57cec5SDimitry Andric typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap; 4310b57cec5SDimitry Andric typedef std::multimap<uint32_t, ObjCISA> HashToISAMap; 4320b57cec5SDimitry Andric typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator; 4330b57cec5SDimitry Andric typedef HashToISAMap::iterator HashToISAIterator; 4340b57cec5SDimitry Andric typedef ThreadSafeDenseMap<void *, uint64_t> TypeSizeCache; 4350b57cec5SDimitry Andric 4360b57cec5SDimitry Andric MsgImplMap m_impl_cache; 43781ad6265SDimitry Andric MsgImplStrMap m_impl_str_cache; 4380b57cec5SDimitry Andric LazyBool m_has_new_literals_and_indexing; 4390b57cec5SDimitry Andric ISAToDescriptorMap m_isa_to_descriptor; 4400b57cec5SDimitry Andric HashToISAMap m_hash_to_isa_map; 4410b57cec5SDimitry Andric TypeSizeCache m_type_size_cache; 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric protected: 4440b57cec5SDimitry Andric uint32_t m_isa_to_descriptor_stop_id; 4450b57cec5SDimitry Andric 4460b57cec5SDimitry Andric typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap; 4470b57cec5SDimitry Andric CompleteClassMap m_complete_class_cache; 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric struct ConstStringSetHelpers { operatorConstStringSetHelpers4500b57cec5SDimitry Andric size_t operator()(ConstString arg) const // for hashing 4510b57cec5SDimitry Andric { 4520b57cec5SDimitry Andric return (size_t)arg.GetCString(); 4530b57cec5SDimitry Andric } operatorConstStringSetHelpers4540b57cec5SDimitry Andric bool operator()(ConstString arg1, 4550b57cec5SDimitry Andric ConstString arg2) const // for equality 4560b57cec5SDimitry Andric { 4570b57cec5SDimitry Andric return arg1.operator==(arg2); 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric }; 4600b57cec5SDimitry Andric typedef std::unordered_set<ConstString, ConstStringSetHelpers, 4610b57cec5SDimitry Andric ConstStringSetHelpers> 4620b57cec5SDimitry Andric CompleteClassSet; 4630b57cec5SDimitry Andric CompleteClassSet m_negative_complete_class_cache; 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric ISAToDescriptorIterator GetDescriptorIterator(ConstString name); 4660b57cec5SDimitry Andric 4670b57cec5SDimitry Andric friend class ::CommandObjectObjC_ClassTable_Dump; 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric std::pair<ISAToDescriptorIterator, ISAToDescriptorIterator> 4700b57cec5SDimitry Andric GetDescriptorIteratorPair(bool update_if_needed = true); 4710b57cec5SDimitry Andric 4720b57cec5SDimitry Andric void ReadObjCLibraryIfNeeded(const ModuleList &module_list); 4730b57cec5SDimitry Andric 4745ffd83dbSDimitry Andric ObjCLanguageRuntime(const ObjCLanguageRuntime &) = delete; 4755ffd83dbSDimitry Andric const ObjCLanguageRuntime &operator=(const ObjCLanguageRuntime &) = delete; 4760b57cec5SDimitry Andric }; 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric } // namespace lldb_private 4790b57cec5SDimitry Andric 4805ffd83dbSDimitry Andric #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H 481