-
Notifications
You must be signed in to change notification settings - Fork 344
[lldb] Implement TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName #2260
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
[lldb] Implement TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName #2260
Conversation
@adrian-prantl this doesn't need a review yet, but can you let me know what you think about the plumbing changes added in
In summary, all this is setup to implement and use If this is all fine, a follow up commit will add commits to implement the behavior. |
@@ -324,7 +324,7 @@ class CompilerType { | |||
|
|||
/// Lookup a child given a name. This function will match base class names and | |||
/// member member names in "clang_type" only, not descendants. | |||
uint32_t GetIndexOfChildWithName(const char *name, | |||
uint32_t GetIndexOfChildWithName(const char *name, ExecutionContext *exe_ctx, |
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.
We should eventually upstream this change, but I don't see an issue with doing so. @jimingham previously pointed out that requiring a ValueObject in CompilerType is problematic, but there is prior art for requiring an optional ExecutionContext in calls like GetBitSize(). @jimingham do you agree with that characterization?
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.
for what it's worth, the functions I've seen need the process, so passing a process instead of ExecutionContext
makes the dependency clearer, at the cost of being less flexible if in the future something else from the context is needed instead of or in addition to the process.
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.
Since this is an API for all TypeSystems, maybe keeping it more general is actually desirable? It also looks like most CompilerType methods (https://lldb.llvm.org/cpp_reference/classlldb__private_1_1CompilerType.html) take an ExecutionContextScope. Maybe we should also do that here too, for symmetry?
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.
The use cases and distinction between ExecutionContext
and ExecutionContextScope
is not clear to me at all. I read their docs and looked at their APIs. The primary reason I went with ExecutionContext
here is because from ValueObject
it's more direct/convenient.
Within ValueObject
, both of these patterns exist:
ExecutionContext exe_ctx(GetExecutionContextRef());
ExecutionContext exe_ctx(GetExecutionContextRef());
someFunction(exe_ctx.GetBestExecutionContextScope());
What's unclear to me, is why bring ExecutionContextScope
into the equation? From its documentation, ExecutionContext
says:
These objects are designed to be used for short term execution context object storage while a function might be trying to evaluate something that requires a thread or frame.
Which does describe the needs of SwiftLanguageRuntime
.
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.
We should eventually upstream this change, but I don't see an issue with doing so. @jimingham previously pointed out that requiring a ValueObject in CompilerType is problematic, but there is prior art for requiring an optional ExecutionContext in calls like GetBitSize(). @jimingham do you agree with that characterization?
That's right. Since you really only want the process, or maybe a frame if you are trying to bind some generic, a ValueObject is way more than you need. But that you might need a process to determine some aspects of the type system, it makes sense to have API's into the type system that provide an ExecutionContext in some form.
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.
The use cases and distinction between ExecutionContext and ExecutionContextScope is not clear to me at all. I read their docs and looked at their APIs.
Before I guess an answer — @jimingham ^ ?
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.
As I understand it, the ExecutionContextScope is there because it is really handy to be able to use one of the objects in the Execution Context hierarchy to stand in for a scope specifier regardless of where you are in the hierarchy. I'm not sure for local passing of contexts there's a hard and fast rule on which to use, so far as I can tell it's more a matter of convenience. If you know you will mostly always have a process/thread/frame object on hand when calling the API, then ExecutionContextScope is way more convenient as you can bypass the conversion to ExecutionContext.
But you might also want to check with Greg in case I'm misremembering something. These were his designs originally.
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.
Let's make the minimal API change to just add the context pointer here and then separately refurbish the API on llvm.org where we get rid of the char *, etc...
llvm::Optional<size_t> GetIndexOfChildMemberWithName( | ||
CompilerType type, const char *name, ExecutionContext *exe_ctx, | ||
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes); | ||
|
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.
This looks good — but it would be better to use an llvm::StringRef
instead of a const char*
for name
.
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.
Similarly, a MutableArrayRef http://llvm.org/doxygen/classllvm_1_1MutableArrayRef.html is preferred over a std::vector&. Then call sites can also use SmallVectors if they wish to do so.
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.
thanks will do! TIL about MutableArrayRef
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.
done
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.
Seems MutableArrayRef
won't work here, I don't see any way to modify an underlying vector, in particular to append to it.
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.
Whoops, you're right! We could go to a SmallVectorImpl<uint32_t>
but the returns are marginal.
Side note: Having now read the documentation for child_indexes
(https://lldb.llvm.org/cpp_reference/classlldb__private_1_1CompilerType.html#abbeabd29258512dc7869c3f01afff93d) this method's entire API is weird.
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.
haha very weird
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.
For posteriority: The point of the child_indexes array is to support returning more than one match. I have no idea in which language this would even be possible. To top that off, the return value is that of child_indexes[0] or INT_MAX, and the comment has a TODO mark in it. We might want to check if this is even wired up in any language backend and otherwise potentially even remove it.
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.
sounds good to me.
In the case of multiple children with the same name, a class can have a property of the same name as a property in its base class if the base class property is private.
In my quick check of c++, it allows duplicate members names regardless of access control.
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.
It really depends on what we decide to mean by "ChildMember". If it means any member of the current object, then in C++ you can have two with the same name since they can come from different base classes. If it only means "any member contributed by the most specific class of the object, and you have to get to the others by recursing through the base class by hand", then I can't think of a way you could have two members with the same name.
I think the first meaning is more useful, but I'm not 100% set on that.
@@ -832,7 +832,8 @@ class TypeSystemClang : public TypeSystem { | |||
// so we catch all names that match a given child name, not just the first. | |||
size_t | |||
GetIndexOfChildMemberWithName(lldb::opaque_compiler_type_t type, | |||
const char *name, bool omit_empty_base_classes, |
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.
When we upstream the change to add the exe_ctx, we can also modernize the signature to use StringRef and ArrayRef. And perhaps even return an Optional<>!
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.
💯
e80330f
to
4bd5d15
Compare
@adrian-prantl d0a8d14 is the meat of this PR. Still to do:
Note: there's now a lot of common structure (logic and flow control) in a few of these functions, which I am planning to refactor as a follow up. |
Now that `TypeSystemSwiftTypeRef::GetNumChildren` is implemented, if the runtime knows of more children than the AST contains, then the runtime should be used (`impl`), not the AST (`fallback`).
|
Follow up: |
@swift-ci test |
@adrian-prantl I think this is ready to review, the core changes are here 95dd368...ff5203d. |
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.
Great! Some minor suggestions inside.
@@ -324,7 +324,7 @@ class CompilerType { | |||
|
|||
/// Lookup a child given a name. This function will match base class names and | |||
/// member member names in "clang_type" only, not descendants. | |||
uint32_t GetIndexOfChildWithName(const char *name, | |||
uint32_t GetIndexOfChildWithName(const char *name, ExecutionContext *exe_ctx, |
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.
Let's make the minimal API change to just add the context pointer here and then separately refurbish the API on llvm.org where we get rid of the char *, etc...
using namespace swift::reflection; | ||
// Try the static type metadata. | ||
const TypeRef *tr = nullptr; | ||
auto *ti = GetTypeInfo(type, exe_ctx->GetFramePtr(), &tr); |
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.
this is outside of this patch, but maybe we should return a std::pair or a struct here.
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.
I was thinking that too. Initially, only one caller used the TypeRef
, it was less disruptive to add as an optional out-param. But now more callers are using it, so I will make that follow up change.
@@ -35,6 +35,9 @@ | |||
#include "clang/APINotes/APINotesManager.h" | |||
#include "clang/APINotes/APINotesReader.h" | |||
|
|||
#include <algorithm> | |||
#include <sstream> |
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.
We can avoid this...
|
||
auto fail = [&]() { | ||
auto join = [](const auto &v) { | ||
std::ostringstream buf; |
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.
... by calling llvm::join from StringExtras.h http://llvm.org/doxygen/namespacellvm.html#aa1fd1719afe5b07ebe55f1d105c98916
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.
I went to use llvm::join
, but it's for containers of strings, and this case is a vector<int>
basically. Since I'd need to convert to strings, it was shorter to do this, and since it will hopefully soon be deleted (that's the plan for the validation code right?), I didn't force the issue of using llvm::join
.
lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp
Outdated
Show resolved
Hide resolved
lldb/test/API/lang/swift/parseable_interfaces/shared/TestSwiftInterfaceNoDebugInfo.py
Outdated
Show resolved
Hide resolved
@swift-ci test |
@swift-ci test |
@swift-ci test |
This ports the implementation of
GetIndexOfChildMemberWithName
, fromSwiftASTContext
toTypeSystemSwiftTypeRef
.With this change, when compiling with swiftinterfaces, private properties in Swift types are now visible to lldb through the TypeRef metadata contained in the binary. Tests that expected private properties to not be accessible have been updated.
rdar://68171371