This is an archive of the discontinued LLVM Phabricator instance.

[lldb] Expose std::pair children for unordered_map
ClosedPublic

Authored by kastiglione on Jan 14 2022, 8:35 PM.

Details

Summary

Change the behavior of the libc++ std::unordered_map synthetic provider to
present children as std::pair values, just like std::map does. This change
also applies equally to std::unordered_multimap.

Before this change, the synthetic provider for libc++ std::unordered_map has
returned children whose type is an trivial wrapper struct
(__hash_value_type). For example, given an unordered map initialized with
{{1,2}, {3, 4}}, the output is:

(std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<const int, int> > >) map = size=2 {
  [0] = {
    __cc = (first = 3, second = 4)
  }
  [1] = {
    __cc = (first = 1, second = 2)
  }
}

Compare this output to std::map:

(std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >) map = size=2 {
  [0] = (first = 1, second = 2)
  [1] = (first = 3, second = 4)

The children of std::map have the type std::pair<const Key, T>.

For std::unordered_map, it's not useful to expose the internal wrapper type.
This type is structurally a trivial wrapper, having a single field (__cc)
whose type is std::pair. This change exposes the pair instead of the internal
wrapper type.

It appears the synthetic provider implementation for unordered_map was meant
to provide this behavior (see rGd22a94377f7554a7e9df050f6dfc3ee42384e3fe). The
code has both an m_node_type and an m_element_type, but has only used the
former. The latter, m_element_type, is exactly the type needed for the
children pairs. With this existing code, it's not much of a change to make this
work.

Diff Detail

Event Timeline

kastiglione requested review of this revision.Jan 14 2022, 8:35 PM
kastiglione created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptJan 14 2022, 8:35 PM

some tabs snuck in

kastiglione added inline comments.Jan 14 2022, 8:47 PM
lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
143

This block of changes is needed to support unordered_set, because this synthetic provider is shared by unordered_set and unordered_map.

For unordered_map, the element type is an internal hash node. For unoredered_set, it's the type T from unordered_set<T>. This part of the code needs to know whether there's a hash node here, and to step down through the __cc field.

I am not sure what the best way to do this is. I could do a string prefix check against std::__hash_value_type. I could do a smarter full string equality check, but could that possibly have false negatives if the wrong string type name is constructed. As it currently is, I assume if there's a one or more fields, and if the first one is named __cc, then it's assumed to be an internal hash node.

Suggestions welcome.

181

This change is the fix needed to get unordered_map working.

lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/unordered/TestDataFormatterGenericUnordered.py
50

This regex checks that the string __cc = is not in the output.

kastiglione edited the summary of this revision. (Show Details)Feb 12 2022, 9:28 AM
kastiglione retitled this revision from [lldb] From unordered_map synthetic provider, return std::pair children to [lldb] Expose std::pair children for unordered_map.Feb 14 2022, 11:58 AM
kastiglione edited the summary of this revision. (Show Details)

Sorry for the delay here.

This output is definitely nicer than the previous version, so this change is desirable.

If you really are switching on unordered_map vrs. unordered_set behavior, can you check the backend ValueObject's type to determine whether you are dealing with a map or set? It might be nice to make that a little more explicit. I can't see anything in this file that indicates that this synthetic child provider is used for both classes, so having something conditional on it being a map is surprising.

lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
143

IIUC, this depends on whether the backend is of type unordered_map or unordered_set? Can you just check the type of the backend?

Herald added a project: Restricted Project. · View Herald TranscriptApr 29 2022, 10:53 AM

Use backend's type name to differentiate between unordered_{map,set}

kastiglione marked an inline comment as done.Aug 12 2022, 8:00 PM

Ignore the internal field name and use type names for conditions

Handle GetTypeName() returning strings both with and without std:: namespace

fix comment grammar

kastiglione edited the summary of this revision. (Show Details)Aug 15 2022, 10:16 AM
This revision is now accepted and ready to land.Aug 18 2022, 5:05 AM

@jingham what do you think of this update?

JDevlieghere added inline comments.Aug 26 2022, 10:24 AM
lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
75–76

Maybe a little helper could avoid some duplication here and below. Something like:

static bool isStdType(llvm::StringRef name, llvm::StringRef type) {
	return name.startswith(type) || name.startswith(llvm::Twine("std::__1::") + type);
}
kastiglione added inline comments.Aug 27 2022, 9:05 AM
lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
75–76

good idea. Since startswith doesn't accept a Twine I went with a slightly different approach, to the same effect.

rsmith added a subscriber: rsmith.Sep 2 2022, 1:21 PM
rsmith added inline comments.
lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
74

This is not right -- libc++ allows customizing its inline namespace name for versioning purpose; it's not __1 across all deployments. For example, with the libc++ unstable ABI, it will likely be something else. To handle this properly I think you'll need to look for either std::name< or something like std::[a-zA-Z0-9_]*::name<.

kastiglione added inline comments.Sep 3 2022, 10:42 AM
lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
74

thanks. Looks like CPPLanguageRuntime.cpp has makes some similar assumptions.

kastiglione added inline comments.Sep 3 2022, 11:36 AM
lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp
74