diff --git a/lldb/include/lldb/Target/LanguageRuntime.h b/lldb/include/lldb/Target/LanguageRuntime.h --- a/lldb/include/lldb/Target/LanguageRuntime.h +++ b/lldb/include/lldb/Target/LanguageRuntime.h @@ -67,6 +67,12 @@ virtual lldb::LanguageType GetLanguageType() const = 0; + /// Return the preferred language runtime instance, which in most cases will + /// be the current instance. + virtual LanguageRuntime *GetPreferredLanguageRuntime(ValueObject &in_value) { + return nullptr; + } + virtual bool GetObjectDescription(Stream &str, ValueObject &object) = 0; virtual bool GetObjectDescription(Stream &str, Value &value, diff --git a/lldb/source/Core/ValueObjectDynamicValue.cpp b/lldb/source/Core/ValueObjectDynamicValue.cpp --- a/lldb/source/Core/ValueObjectDynamicValue.cpp +++ b/lldb/source/Core/ValueObjectDynamicValue.cpp @@ -149,7 +149,18 @@ if (known_type != lldb::eLanguageTypeUnknown && known_type != lldb::eLanguageTypeC) { runtime = process->GetLanguageRuntime(known_type); - if (runtime) + if (auto *preferred_runtime = + runtime->GetPreferredLanguageRuntime(*m_parent)) { + // Try the preferred runtime first. + found_dynamic_type = preferred_runtime->GetDynamicTypeAndAddress( + *m_parent, m_use_dynamic, class_type_or_name, dynamic_address, + value_type); + if (found_dynamic_type) + // Set the operative `runtime` for later use in this function. + runtime = preferred_runtime; + } + if (!found_dynamic_type) + // Fallback to the runtime for `known_type`. found_dynamic_type = runtime->GetDynamicTypeAndAddress( *m_parent, m_use_dynamic, class_type_or_name, dynamic_address, value_type); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h @@ -12,6 +12,7 @@ #include #include "AppleObjCRuntimeV2.h" +#include "lldb/lldb-enumerations.h" #include "lldb/lldb-private.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" @@ -34,6 +35,8 @@ return true; // any Objective-C v2 runtime class descriptor we vend is valid } + lldb::LanguageType GetImplementationLanguage() const override; + // a custom descriptor is used for tagged pointers bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, uint64_t *value_bits = nullptr, diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp @@ -10,8 +10,10 @@ #include "lldb/Expression/FunctionCaller.h" #include "lldb/Target/ABI.h" +#include "lldb/Target/Language.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" +#include "lldb/lldb-enumerations.h" using namespace lldb; using namespace lldb_private; @@ -668,6 +670,19 @@ return 0; } +// From the ObjC runtime. +static uint8_t IS_SWIFT_STABLE = 1U << 1; + +LanguageType ClassDescriptorV2::GetImplementationLanguage() const { + std::unique_ptr objc_class; + if (auto *process = m_runtime.GetProcess()) + if (Read_objc_class(process, objc_class)) + if (objc_class->m_flags & IS_SWIFT_STABLE) + return lldb::eLanguageTypeSwift; + + return lldb::eLanguageTypeObjC; +} + ClassDescriptorV2::iVarsStorage::iVarsStorage() : m_ivars(), m_mutex() {} size_t ClassDescriptorV2::iVarsStorage::size() { return m_ivars.size(); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h @@ -38,6 +38,8 @@ static llvm::StringRef GetPluginNameStatic() { return "apple-objc-v2"; } + LanguageRuntime *GetPreferredLanguageRuntime(ValueObject &in_value) override; + static char ID; bool isA(const void *ClassID) const override { diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -33,6 +33,7 @@ #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" @@ -753,6 +754,19 @@ RegisterObjCExceptionRecognizer(process); } +LanguageRuntime * +AppleObjCRuntimeV2::GetPreferredLanguageRuntime(ValueObject &in_value) { + if (auto process_sp = in_value.GetProcessSP()) { + assert(process_sp.get() == m_process); + if (auto descriptor_sp = GetNonKVOClassDescriptor(in_value)) { + LanguageType impl_lang = descriptor_sp->GetImplementationLanguage(); + if (impl_lang != eLanguageTypeUnknown) + return process_sp->GetLanguageRuntime(impl_lang); + } + } + return nullptr; +} + bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress( ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &address, diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h @@ -24,6 +24,7 @@ #include "lldb/Target/LanguageRuntime.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/ThreadSafeDenseMap.h" +#include "lldb/lldb-enumerations.h" #include "lldb/lldb-private.h" class CommandObjectObjC_ClassTable_Dump; @@ -86,6 +87,11 @@ return (m_is_cf == eLazyBoolYes); } + /// Determine whether this class is implemented in Swift. + virtual lldb::LanguageType GetImplementationLanguage() const { + return lldb::eLanguageTypeObjC; + } + virtual bool IsValid() = 0; /// There are two routines in the ObjC runtime that tagged pointer clients