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