-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #66597 - MaulingMonkey:pr-natvis-std-collections-hash, …
…r=michaelwoerister debuginfo: Support for std::collections::Hash* in windows debuggers. Okay, I finally needed to debug code involving a HashMap! Added support for HashSet s as well. r? @michaelwoerister ### Local Testing Verified these are passing locally: ```cmd :: cmd.exe python x.py test --stage 1 --build x86_64-pc-windows-msvc src/test/debuginfo python x.py test --stage 1 --build i686-pc-windows-msvc src/test/debuginfo python x.py test --stage 1 src/tools/tidy :: MinGW MSYS2 ./x.py test --stage 1 --build x86_64-pc-windows-gnu src/test/debuginfo ``` ### Related Issues * #36503 * #40460 * rust-gamedev/wg#20
- Loading branch information
Showing
3 changed files
with
200 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> | ||
<!-- | ||
std::collection::Hash* container visualizers | ||
Current std impls: | ||
std::collections::hash::set::HashSet<K, S> is implemented in terms of... | ||
std::collections::hash::map::HashMap<K, V, S> is implemented in terms of... | ||
hashbrown::map::HashMap<K, V, S> is implemented in terms of... | ||
hashbrown::raw::RawTable<(K, V)> | ||
Ideally, we'd teach rustc to scan dependencies/crates for .natvis files so | ||
the bulk of this could live alongside the hashbrown crate implementation, | ||
and std would just forward using e.g. <ExpandedItem>base</ExpandedItem>. | ||
However, Given that std...Hash*Set* is currently implemented in terms of | ||
hashbrown...Hash*Map*, which would visualize poorly, we want to customize the | ||
look/feel at the std type level *anyways*... | ||
References: | ||
https://github.com/rust-lang/rust/blob/master/src/libstd/collections/hash/map.rs | ||
https://github.com/rust-lang/rust/blob/master/src/libstd/collections/hash/set.rs | ||
https://github.com/rust-lang/hashbrown/blob/master/src/map.rs | ||
https://github.com/rust-lang/hashbrown/blob/master/src/set.rs | ||
https://github.com/rust-lang/hashbrown/blob/master/src/raw/mod.rs | ||
--> | ||
|
||
<Type Name="std::collections::hash::map::HashMap<*,*,*>"> | ||
<DisplayString>{{ size={base.table.items} }}</DisplayString> | ||
<Expand> | ||
<Item Name="[size]">base.table.items</Item> | ||
<Item Name="[capacity]">base.table.items + base.table.growth_left</Item> | ||
|
||
<CustomListItems> | ||
<Variable Name="i" InitialValue="0" /> | ||
<Variable Name="n" InitialValue="base.table.items" /> | ||
<Size>base.table.items</Size> | ||
<Loop> | ||
<Break Condition="n == 0" /> | ||
<If Condition="(base.table.ctrl.pointer[i] & 0x80) == 0"> | ||
<!-- Bucket is populated --> | ||
<Exec>n--</Exec> | ||
<Item Name="{base.table.data.pointer[i].__0}">base.table.data.pointer[i].__1</Item> | ||
</If> | ||
<Exec>i++</Exec> | ||
</Loop> | ||
</CustomListItems> | ||
</Expand> | ||
</Type> | ||
|
||
<Type Name="std::collections::hash::set::HashSet<*,*>"> | ||
<DisplayString>{{ size={map.base.table.items} }}</DisplayString> | ||
<Expand> | ||
<Item Name="[size]">map.base.table.items</Item> | ||
<Item Name="[capacity]">map.base.table.items + map.base.table.growth_left</Item> | ||
|
||
<CustomListItems> | ||
<Variable Name="i" InitialValue="0" /> | ||
<Variable Name="n" InitialValue="map.base.table.items" /> | ||
<Size>map.base.table.items</Size> | ||
<Loop> | ||
<Break Condition="n == 0" /> | ||
<If Condition="(map.base.table.ctrl.pointer[i] & 0x80) == 0"> | ||
<!-- Bucket is populated --> | ||
<Exec>n--</Exec> | ||
<Item>map.base.table.data.pointer[i].__0</Item> | ||
</If> | ||
<Exec>i++</Exec> | ||
</Loop> | ||
</CustomListItems> | ||
</Expand> | ||
</Type> | ||
|
||
<Type Name="hashbrown::raw::RawTable<*>"> | ||
<!-- RawTable has a nice and simple layout. | ||
items Number of *populated* values in the RawTable (less than the size of ctrl.pointer / data.pointer) | ||
growth_left Remaining capacity before growth | ||
ctrl.pointer[i] & 0x80 Indicates the bucket is empty / should be skipped / doesn't count towards items. | ||
data.pointer[i] The (K,V) tuple, if not empty. | ||
--> | ||
<DisplayString>{{ size={items} }}</DisplayString> | ||
<Expand> | ||
<Item Name="[size]">items</Item> | ||
<Item Name="[capacity]">items + growth_left</Item> | ||
|
||
<CustomListItems> | ||
<Variable Name="i" InitialValue="0" /> | ||
<Variable Name="n" InitialValue="items" /> | ||
<Size>items</Size> | ||
<Loop> | ||
<Break Condition="n == 0" /> | ||
<If Condition="(ctrl.pointer[i] & 0x80) == 0"> | ||
<!-- Bucket is populated --> | ||
<Exec>n--</Exec> | ||
<Item>data.pointer[i]</Item> | ||
</If> | ||
<Exec>i++</Exec> | ||
</Loop> | ||
</CustomListItems> | ||
</Expand> | ||
</Type> | ||
</AutoVisualizer> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
// cdb-only | ||
// compile-flags:-g | ||
|
||
// === CDB TESTS ================================================================================== | ||
|
||
// cdb-command: g | ||
|
||
// cdb-command: dx hash_set,d | ||
// cdb-check:hash_set,d [...] : { size=15 } [Type: [...]::HashSet<u64, [...]>] | ||
// cdb-check: [size] : 15 [Type: [...]] | ||
// cdb-check: [capacity] : [...] | ||
// cdb-check: [[...]] [...] : 0 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 1 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 2 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 3 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 4 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 5 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 6 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 7 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 8 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 9 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 10 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 11 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 12 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 13 [Type: unsigned __int64] | ||
// cdb-command: dx hash_set,d | ||
// cdb-check: [[...]] [...] : 14 [Type: unsigned __int64] | ||
|
||
// cdb-command: dx hash_map,d | ||
// cdb-check:hash_map,d [...] : { size=15 } [Type: [...]::HashMap<u64, u64, [...]>] | ||
// cdb-check: [size] : 15 [Type: [...]] | ||
// cdb-check: [capacity] : [...] | ||
// cdb-check: ["0x0"] : 0 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0x1"] : 1 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0x2"] : 2 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0x3"] : 3 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0x4"] : 4 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0x5"] : 5 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0x6"] : 6 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0x7"] : 7 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0x8"] : 8 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0x9"] : 9 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0xa"] : 10 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0xb"] : 11 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0xc"] : 12 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0xd"] : 13 [Type: unsigned __int64] | ||
// cdb-command: dx hash_map,d | ||
// cdb-check: ["0xe"] : 14 [Type: unsigned __int64] | ||
|
||
#![allow(unused_variables)] | ||
use std::collections::HashSet; | ||
use std::collections::HashMap; | ||
|
||
|
||
fn main() { | ||
// HashSet | ||
let mut hash_set = HashSet::new(); | ||
for i in 0..15 { | ||
hash_set.insert(i as u64); | ||
} | ||
|
||
// HashMap | ||
let mut hash_map = HashMap::new(); | ||
for i in 0..15 { | ||
hash_map.insert(i as u64, i as u64); | ||
} | ||
|
||
zzz(); // #break | ||
} | ||
|
||
fn zzz() { () } |