Skip to content

Commit d9f04b1

Browse files
jll63claude
andcommitted
trace: summarize used slots per inheritance lattice
The trace showed slot assignment only as it happened, interleaved with the recursive walk, so the picture was scattered and the fact that numbering restarts in each disjoint hierarchy was invisible. Add a block at the end of the trace listing, for each lattice, the used slots with the method and virtual parameter assigned to each, then every class's occupied v-table range. A lattice is a connected component of the class graph, identified by its root classes - multiple inheritance is what gives it more than one. The listing is driven off used_by_vp and method::slots rather than used_slots, which assign_tree_slots never fills in. Sibling branches of a tree lattice restart from the same next_slot, so a slot number can repeat within a lattice; the owning class is printed to disambiguate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 25d13ee commit d9f04b1

1 file changed

Lines changed: 113 additions & 0 deletions

File tree

include/boost/openmethod/initialize.hpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,7 @@ struct registry<Policies...>::compiler : detail::generic_compiler {
564564
bool concrete);
565565
void write_global_data();
566566
void print(const method_report& report) const;
567+
void print_slots();
567568
static void select_dominant_overriders(
568569
std::vector<overrider*>& dominants, std::size_t& pick,
569570
std::size_t& remaining);
@@ -594,6 +595,7 @@ void registry<Policies...>::compiler<Options...>::install_global_tables() {
594595
write_global_data();
595596

596597
print(report);
598+
print_slots();
597599
++tr << "Finished\n";
598600
}
599601

@@ -1834,6 +1836,117 @@ void registry<Policies...>::compiler<Options...>::print(
18341836
<< " ambiguous\n";
18351837
}
18361838

1839+
template<class... Policies>
1840+
template<class... Options>
1841+
void registry<Policies...>::compiler<Options...>::print_slots() {
1842+
if constexpr (has_trace) {
1843+
if (!tr.on) {
1844+
return;
1845+
}
1846+
1847+
using namespace detail;
1848+
1849+
// Slot numbering is scoped to a connected component of the class
1850+
// graph, so partition the classes into components first. A component
1851+
// is identified by the classes in it that have no direct bases; there
1852+
// is more than one only in presence of multiple inheritance.
1853+
std::unordered_map<const class_*, std::size_t> component;
1854+
std::size_t component_count = 0;
1855+
1856+
for (auto& seed : classes) {
1857+
if (component.find(&seed) != component.end()) {
1858+
continue;
1859+
}
1860+
1861+
auto id = component_count++;
1862+
component[&seed] = id;
1863+
std::vector<class_*> todo{&seed};
1864+
1865+
while (!todo.empty()) {
1866+
auto cls = todo.back();
1867+
todo.pop_back();
1868+
1869+
for (auto neighbors :
1870+
{&cls->direct_bases, &cls->direct_derived}) {
1871+
for (auto next : *neighbors) {
1872+
if (component.emplace(next, id).second) {
1873+
todo.push_back(next);
1874+
}
1875+
}
1876+
}
1877+
}
1878+
}
1879+
1880+
// Collect the members in 'classes' order, for a deterministic trace.
1881+
std::vector<std::vector<class_*>> lattices(component_count);
1882+
1883+
for (auto& cls : classes) {
1884+
lattices[component[&cls]].push_back(&cls);
1885+
}
1886+
1887+
++tr << "Used slots:\n";
1888+
indent _(tr);
1889+
1890+
for (auto& lattice : lattices) {
1891+
std::vector<class_*> roots;
1892+
1893+
for (auto cls : lattice) {
1894+
if (cls->direct_bases.empty()) {
1895+
roots.push_back(cls);
1896+
}
1897+
}
1898+
1899+
++tr << roots << "\n";
1900+
indent _2(tr);
1901+
1902+
struct entry {
1903+
std::size_t slot;
1904+
class_* cls;
1905+
parameter mp;
1906+
};
1907+
1908+
std::vector<entry> slots;
1909+
1910+
for (auto cls : lattice) {
1911+
for (const auto& mp : cls->used_by_vp) {
1912+
slots.push_back({mp.method->slots[mp.param], cls, mp});
1913+
}
1914+
}
1915+
1916+
std::stable_sort(
1917+
slots.begin(), slots.end(),
1918+
[](const entry& a, const entry& b) { return a.slot < b.slot; });
1919+
1920+
++tr << "slots:\n";
1921+
1922+
{
1923+
indent _3(tr);
1924+
1925+
for (const auto& e : slots) {
1926+
++tr << e.slot << ": in " << *e.cls << " for "
1927+
<< type_name(e.mp.method->infos[0]->method_type_id)
1928+
<< " parameter " << e.mp.param << "\n";
1929+
}
1930+
}
1931+
1932+
++tr << "v-tables:\n";
1933+
1934+
{
1935+
indent _3(tr);
1936+
1937+
for (auto cls : lattice) {
1938+
if (cls->vtbl.empty()) {
1939+
continue;
1940+
}
1941+
1942+
++tr << *cls << " slots " << cls->first_slot << "-"
1943+
<< (cls->first_slot + cls->vtbl.size() - 1) << "\n";
1944+
}
1945+
}
1946+
}
1947+
}
1948+
}
1949+
18371950
//! Initialize a registry.
18381951
//!
18391952
//! Initialize the @ref registry passed as an explicit function template

0 commit comments

Comments
 (0)