mirror of
https://github.com/JakeHillion/object-introspection.git
synced 2024-12-23 05:43:07 +00:00
Flattener: Attempt to take params from parent allocator in case of bad DWARF
This commit is contained in:
parent
5204753497
commit
1bb0c62987
@ -37,6 +37,16 @@ class EnumBitset {
|
||||
return bitset[static_cast<size_t>(v)];
|
||||
}
|
||||
|
||||
bool all() const noexcept {
|
||||
return bitset.all();
|
||||
}
|
||||
bool any() const noexcept {
|
||||
return bitset.any();
|
||||
}
|
||||
bool none() const noexcept {
|
||||
return bitset.none();
|
||||
}
|
||||
|
||||
private:
|
||||
BitsetType bitset;
|
||||
};
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "Flattener.h"
|
||||
|
||||
#include "TypeGraph.h"
|
||||
#include "TypeIdentifier.h"
|
||||
|
||||
namespace type_graph {
|
||||
|
||||
@ -75,6 +76,44 @@ void flattenParent(const Parent& parent,
|
||||
throw std::runtime_error("Invalid type for parent");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Some compilers generate bad DWARF for allocators, such that they are missing
|
||||
* their template parameter (which represents the type to be allocated).
|
||||
*
|
||||
* Try to add this missing parameter back in by pulling it from the allocator's
|
||||
* parent class.
|
||||
*/
|
||||
void fixAllocatorParams(Class& alloc) {
|
||||
if (!TypeIdentifier::isAllocator(alloc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!alloc.templateParams.empty()) {
|
||||
// The DWARF looks ok
|
||||
return;
|
||||
}
|
||||
|
||||
if (alloc.parents.empty()) {
|
||||
// Nothing we can do
|
||||
return;
|
||||
}
|
||||
|
||||
Type& parent = stripTypedefs(*alloc.parents[0].type);
|
||||
Class* parentClass = dynamic_cast<Class*>(&parent);
|
||||
if (!parentClass) {
|
||||
// Not handled
|
||||
return;
|
||||
}
|
||||
|
||||
if (parentClass->templateParams.empty()) {
|
||||
// Nothing we can do
|
||||
return;
|
||||
}
|
||||
|
||||
Type& typeToAllocate = stripTypedefs(*parentClass->templateParams[0].type);
|
||||
alloc.templateParams.push_back(TemplateParam{&typeToAllocate});
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Flattener::visit(Class& c) {
|
||||
@ -152,6 +191,9 @@ void Flattener::visit(Class& c) {
|
||||
flattenParent(parent, flattenedMembers);
|
||||
}
|
||||
|
||||
// Perform fixups for bad DWARF
|
||||
fixAllocatorParams(c);
|
||||
|
||||
c.parents.clear();
|
||||
c.members = std::move(flattenedMembers);
|
||||
|
||||
|
@ -159,6 +159,7 @@ void Printer::print_param(const TemplateParam& param) {
|
||||
} else {
|
||||
print(*param.type);
|
||||
}
|
||||
print_qualifiers(param.qualifiers);
|
||||
depth_--;
|
||||
}
|
||||
|
||||
@ -204,6 +205,20 @@ void Printer::print_value(const std::string& value) {
|
||||
depth_--;
|
||||
}
|
||||
|
||||
void Printer::print_qualifiers(const QualifierSet& qualifiers) {
|
||||
if (qualifiers.none()) {
|
||||
return;
|
||||
}
|
||||
depth_++;
|
||||
prefix();
|
||||
out_ << "Qualifiers:";
|
||||
if (qualifiers[Qualifier::Const]) {
|
||||
out_ << " const";
|
||||
}
|
||||
out_ << std::endl;
|
||||
depth_--;
|
||||
}
|
||||
|
||||
std::string Printer::align_str(uint64_t align) {
|
||||
if (align == 0)
|
||||
return "";
|
||||
|
@ -50,6 +50,7 @@ class Printer : public ConstVisitor {
|
||||
void print_function(const Function& function);
|
||||
void print_child(const Type& child);
|
||||
void print_value(const std::string& value);
|
||||
void print_qualifiers(const QualifierSet& qualifiers);
|
||||
static std::string align_str(uint64_t align);
|
||||
|
||||
std::ostream& out_;
|
||||
|
@ -31,17 +31,8 @@ Pass TypeIdentifier::createPass() {
|
||||
return Pass("TypeIdentifier", fn);
|
||||
}
|
||||
|
||||
void TypeIdentifier::visit(Type& type) {
|
||||
if (visited_.count(&type) != 0)
|
||||
return;
|
||||
|
||||
visited_.insert(&type);
|
||||
type.accept(*this);
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool isAllocator(Type* t) {
|
||||
auto* c = dynamic_cast<Class*>(t);
|
||||
bool TypeIdentifier::isAllocator(Type& t) {
|
||||
auto* c = dynamic_cast<Class*>(&t);
|
||||
if (!c)
|
||||
return false;
|
||||
|
||||
@ -54,7 +45,14 @@ bool isAllocator(Type* t) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void TypeIdentifier::visit(Type& type) {
|
||||
if (visited_.count(&type) != 0)
|
||||
return;
|
||||
|
||||
visited_.insert(&type);
|
||||
type.accept(*this);
|
||||
}
|
||||
|
||||
void TypeIdentifier::visit(Container& c) {
|
||||
const auto& stubParams = c.containerInfo_.stubTemplateParams;
|
||||
@ -78,19 +76,12 @@ void TypeIdentifier::visit(Container& c) {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
if (isAllocator(param.type)) {
|
||||
if (isAllocator(*param.type)) {
|
||||
auto* allocator =
|
||||
dynamic_cast<Class*>(param.type); // TODO please don't do this...
|
||||
Type* typeToAllocate;
|
||||
if (!allocator->templateParams.empty()) {
|
||||
typeToAllocate = allocator->templateParams.at(0).type;
|
||||
} else {
|
||||
// We've encountered some bad DWARF. Let's guess that the type to
|
||||
// allocate is the first parameter of the container.
|
||||
typeToAllocate = c.templateParams[0].type;
|
||||
}
|
||||
auto* dummy = typeGraph_.make_type<DummyAllocator>(
|
||||
*typeToAllocate, size, param.type->align());
|
||||
Type& typeToAllocate = *allocator->templateParams.at(0).type;
|
||||
auto* dummy = typeGraph_.make_type<DummyAllocator>(typeToAllocate, size,
|
||||
param.type->align());
|
||||
c.templateParams[i] = dummy;
|
||||
} else {
|
||||
auto* dummy = typeGraph_.make_type<Dummy>(size, param.type->align());
|
||||
|
@ -33,6 +33,7 @@ class TypeGraph;
|
||||
class TypeIdentifier : public RecursiveVisitor {
|
||||
public:
|
||||
static Pass createPass();
|
||||
static bool isAllocator(Type& t);
|
||||
|
||||
TypeIdentifier(TypeGraph& typeGraph) : typeGraph_(typeGraph) {
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ TEST(CodeGenTest, TransformContainerAllocator) {
|
||||
auto myint = Primitive{Primitive::Kind::Int32};
|
||||
|
||||
auto myalloc = Class{Class::Kind::Struct, "MyAlloc", 8};
|
||||
myalloc.templateParams.push_back(TemplateParam{&myint});
|
||||
myalloc.functions.push_back(Function{"allocate"});
|
||||
myalloc.functions.push_back(Function{"deallocate"});
|
||||
|
||||
@ -52,6 +53,8 @@ TEST(CodeGenTest, TransformContainerAllocator) {
|
||||
Primitive: int32_t
|
||||
Param
|
||||
[1] Struct: MyAlloc (size: 8)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Function: allocate
|
||||
Function: deallocate
|
||||
)",
|
||||
@ -64,3 +67,70 @@ TEST(CodeGenTest, TransformContainerAllocator) {
|
||||
Primitive: int32_t
|
||||
)");
|
||||
}
|
||||
|
||||
TEST(CodeGenTest, TransformContainerAllocatorParamInParent) {
|
||||
ContainerInfo pairInfo{"std::pair", SEQ_TYPE, "utility"};
|
||||
|
||||
ContainerInfo mapInfo{"std::map", STD_MAP_TYPE, "utility"};
|
||||
mapInfo.stubTemplateParams = {2, 3};
|
||||
|
||||
Primitive myint{Primitive::Kind::Int32};
|
||||
|
||||
Container pair{pairInfo, 8};
|
||||
pair.templateParams.push_back(TemplateParam{&myint, {Qualifier::Const}});
|
||||
pair.templateParams.push_back(TemplateParam{&myint});
|
||||
|
||||
Class myallocBase{Class::Kind::Struct,
|
||||
"MyAllocBase<std::pair<const int, int>>", 1};
|
||||
myallocBase.templateParams.push_back(TemplateParam{&pair});
|
||||
myallocBase.functions.push_back(Function{"allocate"});
|
||||
myallocBase.functions.push_back(Function{"deallocate"});
|
||||
|
||||
Class myalloc{Class::Kind::Struct, "MyAlloc<std::pair<const int, int>>", 1};
|
||||
myalloc.parents.push_back(Parent{&myallocBase, 0});
|
||||
myalloc.functions.push_back(Function{"allocate"});
|
||||
myalloc.functions.push_back(Function{"deallocate"});
|
||||
|
||||
Container map{mapInfo, 24};
|
||||
map.templateParams.push_back(TemplateParam{&myint});
|
||||
map.templateParams.push_back(TemplateParam{&myint});
|
||||
map.templateParams.push_back(TemplateParam{&myalloc});
|
||||
|
||||
testTransform(map, R"(
|
||||
[0] Container: std::map (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Param
|
||||
[1] Struct: MyAlloc<std::pair<const int, int>> (size: 1)
|
||||
Parent (offset: 0)
|
||||
[2] Struct: MyAllocBase<std::pair<const int, int>> (size: 1)
|
||||
Param
|
||||
[3] Container: std::pair (size: 8)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Qualifiers: const
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Function: allocate
|
||||
Function: deallocate
|
||||
Function: allocate
|
||||
Function: deallocate
|
||||
)",
|
||||
R"(
|
||||
[0] Container: std::map<int32_t, int32_t, DummyAllocator<std::pair<const int32_t, int32_t>, 0, 0>> (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Param
|
||||
DummyAllocator (size: 0)
|
||||
[1] Container: std::pair<const int32_t, int32_t> (size: 8)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Qualifiers: const
|
||||
Param
|
||||
Primitive: int32_t
|
||||
)");
|
||||
}
|
||||
|
@ -762,3 +762,75 @@ TEST(FlattenerTest, ParentClassAndContainer) {
|
||||
Primitive: int32_t
|
||||
)");
|
||||
}
|
||||
|
||||
TEST(FlattenerTest, AllocatorParamInParent) {
|
||||
ContainerInfo pairInfo{"std::pair", SEQ_TYPE, "utility"};
|
||||
|
||||
ContainerInfo mapInfo{"std::map", STD_MAP_TYPE, "utility"};
|
||||
mapInfo.stubTemplateParams = {2, 3};
|
||||
|
||||
Primitive myint{Primitive::Kind::Int32};
|
||||
|
||||
Container pair{pairInfo, 8};
|
||||
pair.templateParams.push_back(TemplateParam{&myint, {Qualifier::Const}});
|
||||
pair.templateParams.push_back(TemplateParam{&myint});
|
||||
|
||||
Class myallocBase{Class::Kind::Struct,
|
||||
"MyAllocBase<std::pair<const int, int>>", 1};
|
||||
myallocBase.templateParams.push_back(TemplateParam{&pair});
|
||||
myallocBase.functions.push_back(Function{"allocate"});
|
||||
myallocBase.functions.push_back(Function{"deallocate"});
|
||||
|
||||
Class myalloc{Class::Kind::Struct, "MyAlloc<std::pair<const int, int>>", 1};
|
||||
myalloc.parents.push_back(Parent{&myallocBase, 0});
|
||||
myalloc.functions.push_back(Function{"allocate"});
|
||||
myalloc.functions.push_back(Function{"deallocate"});
|
||||
|
||||
Container map{mapInfo, 24};
|
||||
map.templateParams.push_back(TemplateParam{&myint});
|
||||
map.templateParams.push_back(TemplateParam{&myint});
|
||||
map.templateParams.push_back(TemplateParam{&myalloc});
|
||||
|
||||
test(Flattener::createPass(), {map}, R"(
|
||||
[0] Container: std::map (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Param
|
||||
[1] Struct: MyAlloc<std::pair<const int, int>> (size: 1)
|
||||
Parent (offset: 0)
|
||||
[2] Struct: MyAllocBase<std::pair<const int, int>> (size: 1)
|
||||
Param
|
||||
[3] Container: std::pair (size: 8)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Qualifiers: const
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Function: allocate
|
||||
Function: deallocate
|
||||
Function: allocate
|
||||
Function: deallocate
|
||||
)",
|
||||
R"(
|
||||
[0] Container: std::map (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Param
|
||||
[1] Struct: MyAlloc<std::pair<const int, int>> (size: 1)
|
||||
Param
|
||||
[2] Container: std::pair (size: 8)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Qualifiers: const
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Function: allocate
|
||||
Function: deallocate
|
||||
Function: allocate
|
||||
Function: deallocate
|
||||
)");
|
||||
}
|
||||
|
@ -77,32 +77,40 @@ TEST(TypeIdentifierTest, Allocator) {
|
||||
)");
|
||||
}
|
||||
|
||||
TEST(TypeIdentifierTest, AllocatorNoParam) {
|
||||
TEST(TypeIdentifierTest, AllocatorSize1) {
|
||||
auto myint = Primitive{Primitive::Kind::Int32};
|
||||
|
||||
auto myalloc = Class{Class::Kind::Struct, "MyAlloc", 8};
|
||||
auto myalloc = Class{Class::Kind::Struct, "MyAlloc", 1};
|
||||
myalloc.templateParams.push_back(TemplateParam{&myint});
|
||||
myalloc.functions.push_back(Function{"allocate"});
|
||||
myalloc.functions.push_back(Function{"deallocate"});
|
||||
|
||||
auto container = getVector();
|
||||
container.templateParams.push_back(TemplateParam{&myint});
|
||||
container.templateParams.push_back(TemplateParam{&myalloc});
|
||||
container.templateParams.push_back(TemplateParam{&myint});
|
||||
|
||||
test(TypeIdentifier::createPass(), {container}, R"(
|
||||
[0] Container: std::vector (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Param
|
||||
[1] Struct: MyAlloc (size: 8)
|
||||
[1] Struct: MyAlloc (size: 1)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Function: allocate
|
||||
Function: deallocate
|
||||
Param
|
||||
Primitive: int32_t
|
||||
)",
|
||||
R"(
|
||||
[0] Container: std::vector (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
Param
|
||||
DummyAllocator (size: 8)
|
||||
DummyAllocator (size: 0)
|
||||
Primitive: int32_t
|
||||
Param
|
||||
Primitive: int32_t
|
||||
)");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user