Skip to content

Commit be562f5

Browse files
committed
CodeGen v2: Finish polymorphic inheritance support
1 parent 29af4ba commit be562f5

File tree

13 files changed

+255
-67
lines changed

13 files changed

+255
-67
lines changed

.circleci/config.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ workflows:
2020
- build-gcc
2121
oid_test_args: "-ftype-graph"
2222
tests_regex: "OidIntegration\\..*"
23-
exclude_regex: ".*inheritance_polymorphic.*"
2423
- test:
2524
name: test-typed-data-segment-gcc
2625
requires:
@@ -57,7 +56,7 @@ workflows:
5756
oid_test_args: "-ftype-graph"
5857
tests_regex: "OidIntegration\\..*"
5958
# Tests disabled due to bad DWARF generated by the old clang compiler in CI
60-
exclude_regex: ".*inheritance_polymorphic.*|.*fbstring.*|.*std_string_*|.*multi_arg_tb_.*|.*ignored_a"
59+
exclude_regex: ".*fbstring.*|.*std_string_*|.*multi_arg_tb_.*|.*ignored_a"
6160

6261
executors:
6362
ubuntu-docker:

oi/CodeGen.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -366,11 +366,15 @@ void addStandardGetSizeFuncDefs(std::string& code) {
366366
}
367367
)";
368368
}
369+
} // namespace
369370

370-
void getClassSizeFuncDecl(const Class& c, std::string& code) {
371+
void CodeGen::getClassSizeFuncDecl(const Class& c, std::string& code) const {
372+
if (config_.features[Feature::PolymorphicInheritance] && c.isDynamic()) {
373+
code += "void getSizeTypeConcrete(const " + c.name() +
374+
" &t, size_t &returnArg);\n";
375+
}
371376
code += "void getSizeType(const " + c.name() + " &t, size_t &returnArg);\n";
372377
}
373-
} // namespace
374378

375379
/*
376380
* Generates a getSizeType function for the given concrete class.
@@ -421,7 +425,7 @@ void CodeGen::getClassSizeFuncConcrete(std::string_view funcName,
421425
code += "}\n";
422426
}
423427

424-
void CodeGen::getClassSizeFuncDef(const Class& c, std::string& code) {
428+
void CodeGen::getClassSizeFuncDef(const Class& c, std::string& code) const {
425429
if (!config_.features[Feature::PolymorphicInheritance] || !c.isDynamic()) {
426430
// Just directly use the concrete size function as this class' getSizeType()
427431
getClassSizeFuncConcrete("getSizeType", c, code);
@@ -438,9 +442,7 @@ void CodeGen::getClassSizeFuncDef(const Class& c, std::string& code) {
438442
if (childClass == nullptr) {
439443
abort(); // TODO
440444
}
441-
// TODO:
442-
// auto fqChildName = *fullyQualifiedName(child);
443-
auto fqChildName = "TODO - implement me";
445+
auto fqChildName = childClass->fqName();
444446

445447
// We must split this assignment and append because the C++ standard lacks
446448
// an operator for concatenating std::string and std::string_view...
@@ -511,8 +513,10 @@ void getContainerSizeFuncDef(std::unordered_set<const ContainerInfo*>& used,
511513
boost::format(c.containerInfo_.codegen.func) % c.containerInfo_.typeName;
512514
code += fmt.str();
513515
}
516+
} // namespace
514517

515-
void addGetSizeFuncDecls(const TypeGraph& typeGraph, std::string& code) {
518+
void CodeGen::addGetSizeFuncDecls(const TypeGraph& typeGraph,
519+
std::string& code) const {
516520
for (const Type& t : typeGraph.finalTypes) {
517521
if (const auto* c = dynamic_cast<const Class*>(&t)) {
518522
getClassSizeFuncDecl(*c, code);
@@ -522,8 +526,6 @@ void addGetSizeFuncDecls(const TypeGraph& typeGraph, std::string& code) {
522526
}
523527
}
524528

525-
} // namespace
526-
527529
void CodeGen::addGetSizeFuncDefs(const TypeGraph& typeGraph,
528530
std::string& code) {
529531
for (const Type& t : typeGraph.finalTypes) {

oi/CodeGen.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,13 @@ class CodeGen {
6666
thriftIssetMembers_;
6767

6868
void genDefsThrift(const type_graph::TypeGraph& typeGraph, std::string& code);
69+
void addGetSizeFuncDecls(const type_graph::TypeGraph& typeGraph,
70+
std::string& code) const;
71+
void getClassSizeFuncDecl(const type_graph::Class& c,
72+
std::string& code) const;
6973
void addGetSizeFuncDefs(const type_graph::TypeGraph& typeGraph,
7074
std::string& code);
71-
void getClassSizeFuncDef(const type_graph::Class& c, std::string& code);
75+
void getClassSizeFuncDef(const type_graph::Class& c, std::string& code) const;
7276
void getClassSizeFuncConcrete(std::string_view funcName,
7377
const type_graph::Class& c,
7478
std::string& code) const;

oi/type_graph/AddChildren.cpp

Lines changed: 26 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,28 @@ void AddChildren::visit(Class& c) {
7575
dynamic_cast<Class*>(&childType); // TODO don't use dynamic_cast
7676
if (!childClass) // TODO dodgy error handling
7777
abort();
78-
c.children.push_back(*childClass);
7978

80-
// // Add recursive children to this class as well
81-
// enumerateClassChildren(drgnChild, children);
79+
/*
80+
* Confirm that this child is actually our child.
81+
*
82+
* We previously used unqualified names for speed, so types with the same
83+
* name in different namespaces would have been grouped together.
84+
*/
85+
bool isActuallyChild = false;
86+
for (const auto& parent : childClass->parents) {
87+
// TODO support parent containers?
88+
auto* parentClass = dynamic_cast<Class*>(&stripTypedefs(parent.type()));
89+
if (!parentClass)
90+
continue;
91+
92+
if (parentClass->fqName() == c.fqName()) {
93+
isActuallyChild = true;
94+
break;
95+
}
96+
}
97+
98+
if (isActuallyChild)
99+
c.children.push_back(*childClass);
82100
}
83101

84102
// Recurse to find children-of-children
@@ -87,35 +105,6 @@ void AddChildren::visit(Class& c) {
87105
}
88106
}
89107

90-
// TODO how to flatten children of children?
91-
// void AddChildren::enumerateClassChildren(struct drgn_type *type,
92-
// std::vector<std::reference_wrapper<Class>> &children) {
93-
// // This function is called recursively to find children-of-children, so the
94-
// // "children" vector argument will not necessarily be empty.
95-
//
96-
// const char* tag = drgn_type_tag(type);
97-
// if (tag == nullptr) {
98-
// return;
99-
// }
100-
// auto it = childClasses_.find(tag);
101-
// if (it == childClasses_.end()) {
102-
// return;
103-
// }
104-
//
105-
// const auto& drgnChildren = it->second;
106-
// for (drgn_type* drgnChild : drgnChildren) {
107-
// // TODO there shouldn't be any need for a dynamic cast here...
108-
// Type *ttt = enumerateClass(drgnChild);
109-
// auto *child = dynamic_cast<Class*>(ttt);
110-
// if (!child)
111-
// abort();
112-
// children.push_back(*child);
113-
//
114-
// // Add recursive children to this class as well
115-
// enumerateClassChildren(drgnChild, children);
116-
// }
117-
//}
118-
119108
void AddChildren::recordChildren(drgn_type* type) {
120109
drgn_type_template_parameter* parents = drgn_type_parents(type);
121110

@@ -141,20 +130,20 @@ void AddChildren::recordChildren(drgn_type* type) {
141130
}
142131

143132
const char* parentName = drgn_type_tag(parent);
144-
if (parentName == nullptr) {
145-
// VLOG(1) << "No name for parent class (" << parent << ") of "
146-
// << drgn_type_tag(type);
133+
if (!parentName) {
147134
continue;
148135
}
149136

150137
/*
151138
* drgn pointers are not stable, so use string representation for reverse
152139
* mapping for now. We need to find a better way of creating this
153140
* childClasses map - ideally drgn would do this for us.
141+
*
142+
* Use unqualified names because fully-qualified names are too slow. We'll
143+
* check against fully-qualified names once we've narrowed down the number
144+
* of types to compare.
154145
*/
155146
childClasses_[parentName].push_back(type);
156-
// VLOG(1) << drgn_type_tag(type) << "(" << type << ") is a child of "
157-
// << drgn_type_tag(parent) << "(" << parent << ")";
158147
}
159148
}
160149

oi/type_graph/AddChildren.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ class TypeGraph;
3434
/*
3535
* AddChildren
3636
*
37+
* Populates the "children" field of Class types.
38+
*
39+
* DWARF only stores a mapping of [child -> parent], but sometimes we want the
40+
* invserse: [parent -> child]. We must iterate over every single type to build
41+
* up our own inverse mapping, before applying it to the relevant type nodes.
42+
*
43+
* This is expensive and only useful for types which make use of dynamic
44+
* inheritance hierarchies (e.g. polymorphism), so is not done as part of the
45+
* standard DrgnParser stage.
46+
*
3747
* TODO
3848
* what about children which inherit through a typedef? don't think that'll
3949
* work yet

oi/type_graph/Flattener.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,6 @@ void Flattener::accept(Type& type) {
4646
}
4747

4848
namespace {
49-
// TODO this function is a massive hack. don't do it like this please
50-
Type& stripTypedefs(Type& type) {
51-
Type* t = &type;
52-
while (const Typedef* td = dynamic_cast<Typedef*>(t)) {
53-
t = &td->underlyingType();
54-
}
55-
return *t;
56-
}
57-
5849
void flattenParent(const Parent& parent,
5950
std::vector<Member>& flattenedMembers) {
6051
Type& parentType = stripTypedefs(parent.type());

oi/type_graph/NameGen.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ void NameGen::visit(Class& c) {
6666
// Deduplicate member names. Duplicates may be present after flattening.
6767
for (size_t i = 0; i < c.members.size(); i++) {
6868
c.members[i].name += "_" + std::to_string(i);
69+
70+
// GCC includes dots in vptr member names, e.g. "_vptr.MyClass"
71+
// These aren't valid in C++, so we must replace them
72+
std::replace(c.members[i].name.begin(), c.members[i].name.end(), '.', '$');
6973
}
7074

7175
for (const auto& param : c.templateParams) {

oi/type_graph/Types.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,13 @@ bool Class::isDynamic() const {
122122
return false;
123123
}
124124

125+
// TODO this function is a massive hack. don't do it like this please
126+
Type& stripTypedefs(Type& type) {
127+
Type* t = &type;
128+
while (const Typedef* td = dynamic_cast<Typedef*>(t)) {
129+
t = &td->underlyingType();
130+
}
131+
return *t;
132+
}
133+
125134
} // namespace type_graph

oi/type_graph/Types.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,8 @@ class Container : public Type {
295295

296296
class Enum : public Type {
297297
public:
298-
explicit Enum(const std::string& name, size_t size)
299-
: name_(name), size_(size) {
298+
explicit Enum(std::string name, size_t size)
299+
: name_(std::move(name)), size_(size) {
300300
}
301301

302302
DECLARE_ACCEPT
@@ -395,8 +395,8 @@ class Primitive : public Type {
395395

396396
class Typedef : public Type {
397397
public:
398-
explicit Typedef(NodeId id, const std::string& name, Type& underlyingType)
399-
: name_(name), underlyingType_(underlyingType), id_(id) {
398+
explicit Typedef(NodeId id, std::string name, Type& underlyingType)
399+
: name_(std::move(name)), underlyingType_(underlyingType), id_(id) {
400400
}
401401

402402
DECLARE_ACCEPT
@@ -520,6 +520,8 @@ class DummyAllocator : public Type {
520520
uint64_t align_;
521521
};
522522

523+
Type& stripTypedefs(Type& type);
524+
523525
} // namespace type_graph
524526

525527
#undef DECLARE_ACCEPT

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ target_link_libraries(integration_sleepy folly_headers)
4949

5050
add_executable(test_type_graph
5151
main.cpp
52+
test_add_children.cpp
5253
test_add_padding.cpp
5354
test_alignment_calc.cpp
5455
test_codegen.cpp

0 commit comments

Comments
 (0)