-
Notifications
You must be signed in to change notification settings - Fork 339
[lldb] Resolve Swift-implemented Objective-C classes using Swift runtime #10548
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2022,21 +2022,6 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Pack( | |
return true; | ||
} | ||
|
||
static bool IsPrivateNSClass(NodePointer node) { | ||
if (!node || node->getKind() != Node::Kind::Type || | ||
node->getNumChildren() == 0) | ||
return false; | ||
NodePointer classNode = node->getFirstChild(); | ||
if (!classNode || classNode->getKind() != Node::Kind::Class || | ||
classNode->getNumChildren() < 2) | ||
return false; | ||
for (NodePointer child : *classNode) | ||
if (child->getKind() == Node::Kind::Identifier && child->hasText()) | ||
return child->getText().starts_with("__NS") || | ||
child->getText().starts_with("NSTaggedPointer"); | ||
return false; | ||
} | ||
|
||
CompilerType SwiftLanguageRuntime::GetDynamicTypeAndAddress_EmbeddedClass( | ||
uint64_t instance_ptr, CompilerType class_type) { | ||
ThreadSafeReflectionContext reflection_ctx = GetReflectionContext(); | ||
|
@@ -2091,44 +2076,41 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Class( | |
return false; | ||
|
||
auto tss = class_type.GetTypeSystem().dyn_cast_or_null<TypeSystemSwift>(); | ||
if (!tss) { | ||
// This could be an Objective-C type implemented in Swift. Get the | ||
// Swift typesystem. | ||
if (auto module_sp = in_value.GetModule()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand why this is needed. If the type does not have a Swift type system (even if it's a swiftified objc type), then something has gone wrong, and we shouldn't be asking the Swift Language Runtime, no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good question! Let me try replacing this with an assert(false) to answer how we get here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The answer is
let me see if I can simplify this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was able to eliminate the entire There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this is still an actively used code block. I updated the comment to explain why. |
||
auto type_system_or_err = | ||
module_sp->GetTypeSystemForLanguage(lldb::eLanguageTypeSwift); | ||
if (!type_system_or_err) { | ||
llvm::consumeError(type_system_or_err.takeError()); | ||
return false; | ||
} | ||
auto ts_sp = *type_system_or_err; | ||
tss = | ||
llvm::cast<TypeSystemSwift>(ts_sp.get())->GetTypeSystemSwiftTypeRef(); | ||
} else if (auto target_sp = in_value.GetTargetSP()) { | ||
auto type_system_or_err = | ||
target_sp->GetScratchTypeSystemForLanguage(lldb::eLanguageTypeSwift); | ||
if (!type_system_or_err) { | ||
llvm::consumeError(type_system_or_err.takeError()); | ||
return false; | ||
} | ||
auto ts_sp = *type_system_or_err; | ||
tss = | ||
llvm::cast<TypeSystemSwift>(ts_sp.get())->GetTypeSystemSwiftTypeRef(); | ||
} | ||
} | ||
if (!tss) | ||
return false; | ||
|
||
address.SetRawAddress(instance_ptr); | ||
auto ts = tss->GetTypeSystemSwiftTypeRef(); | ||
if (!ts) | ||
return false; | ||
// Ask the Objective-C runtime about Objective-C types. | ||
if (tss->IsImportedType(class_type.GetOpaqueQualType(), nullptr)) | ||
if (auto *objc_runtime = | ||
SwiftLanguageRuntime::GetObjCRuntime(GetProcess())) { | ||
Value::ValueType value_type; | ||
if (objc_runtime->GetDynamicTypeAndAddress(in_value, use_dynamic, | ||
class_type_or_name, address, | ||
value_type, local_buffer)) { | ||
bool found = false; | ||
// Return the most specific class which we can get the typeref. | ||
ForEachSuperClassType(in_value, [&](SuperClassType sc) -> bool { | ||
if (auto *tr = sc.get_typeref()) { | ||
swift::Demangle::Demangler dem; | ||
swift::Demangle::NodePointer node = tr->getDemangling(dem); | ||
// Skip private Foundation types since it's unlikely that would be | ||
// useful to users. | ||
if (IsPrivateNSClass(node)) | ||
return false; | ||
class_type_or_name.SetCompilerType(ts->RemangleAsType( | ||
dem, node, swift::Mangle::ManglingFlavor::Default)); | ||
found = true; | ||
return true; | ||
} | ||
return false; | ||
}); | ||
return found; | ||
} | ||
return false; | ||
} | ||
Log *log(GetLog(LLDBLog::Types)); | ||
// Scope reflection_ctx to minimize its lock scope. | ||
{ | ||
|
||
auto resolve_swift = [&]() { | ||
// Scope reflection_ctx to minimize its lock scope. | ||
ThreadSafeReflectionContext reflection_ctx = GetReflectionContext(); | ||
if (!reflection_ctx) | ||
return false; | ||
|
@@ -2172,10 +2154,17 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_Class( | |
return false; | ||
} | ||
} | ||
|
||
LLDB_LOG(log, "dynamic type of instance_ptr {0:x} is {1}", instance_ptr, | ||
class_type.GetMangledTypeName()); | ||
class_type_or_name.SetCompilerType(dynamic_type); | ||
LLDB_LOG(GetLog(LLDBLog::Types), | ||
adrian-prantl marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"dynamic type of instance_ptr {0:x} is {1}", instance_ptr, | ||
class_type.GetMangledTypeName()); | ||
return true; | ||
}; | ||
|
||
if (!resolve_swift()) { | ||
// When returning false here, the next compatible runtime (= | ||
// Objective-C) will get ask to resolve this type. | ||
return false; | ||
} | ||
|
||
#ifndef NDEBUG | ||
|
@@ -2833,12 +2822,12 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress_IndirectEnumCase( | |
|
||
return GetDynamicTypeAndAddress(*valobj_sp, use_dynamic, class_type_or_name, | ||
address, value_type, local_buffer); | ||
} else { | ||
// This is most likely a statically known type. | ||
address.SetLoadAddress(box_value, &GetProcess().GetTarget()); | ||
value_type = Value::GetValueTypeFromAddressType(eAddressTypeLoad); | ||
return true; | ||
} | ||
|
||
// This is most likely a statically known type. | ||
address.SetLoadAddress(box_value, &GetProcess().GetTarget()); | ||
value_type = Value::GetValueTypeFromAddressType(eAddressTypeLoad); | ||
return true; | ||
} | ||
|
||
void SwiftLanguageRuntime::DumpTyperef(CompilerType type, | ||
|
@@ -3156,22 +3145,27 @@ bool SwiftLanguageRuntime::GetDynamicTypeAndAddress( | |
return false; | ||
|
||
LLDB_SCOPED_TIMER(); | ||
CompilerType val_type(in_value.GetCompilerType()); | ||
Value::ValueType static_value_type = Value::ValueType::Invalid; | ||
|
||
// Try to import a Clang type into Swift. | ||
if (in_value.GetObjectRuntimeLanguage() == eLanguageTypeObjC) | ||
return GetDynamicTypeAndAddress_ClangType(in_value, use_dynamic, | ||
class_type_or_name, address, | ||
value_type, local_buffer); | ||
if (in_value.GetObjectRuntimeLanguage() == eLanguageTypeObjC) { | ||
if (GetDynamicTypeAndAddress_ClangType(in_value, use_dynamic, | ||
class_type_or_name, address, | ||
value_type, local_buffer)) | ||
return true; | ||
return GetDynamicTypeAndAddress_Class(in_value, val_type, use_dynamic, | ||
class_type_or_name, address, | ||
static_value_type, local_buffer); | ||
} | ||
|
||
if (!CouldHaveDynamicValue(in_value)) | ||
return false; | ||
|
||
CompilerType val_type(in_value.GetCompilerType()); | ||
Flags type_info(val_type.GetTypeInfo()); | ||
if (!type_info.AnySet(eTypeIsSwift)) | ||
return false; | ||
|
||
Value::ValueType static_value_type = Value::ValueType::Invalid; | ||
bool success = false; | ||
bool is_indirect_enum_case = IsIndirectEnumCase(in_value); | ||
// Type kinds with instance metadata don't need generic type resolution. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we always want to use the static type if the dynamic type is an Objective-C type? I guess in the REPL this makes sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, this is a very blunt tool to hide some of the Foundation implementation detail types that users are not meant to see / know / care about.
It doesn't not work for Swift-implemented types like
_SwiftDeferredNSDictionary
, which is going to be more prevalent going forward.