diff --git a/oi/CodeGen.cpp b/oi/CodeGen.cpp index 5c6cd01..5e043cf 100644 --- a/oi/CodeGen.cpp +++ b/oi/CodeGen.cpp @@ -778,7 +778,7 @@ void CodeGen::transform(type_graph::TypeGraph& typeGraph) { type_graph::TypeIdentifier::createPass(config_.passThroughTypes)); } pm.addPass(type_graph::RemoveIgnored::createPass(config_.membersToStub)); - pm.addPass(type_graph::AddPadding::createPass()); + pm.addPass(type_graph::AddPadding::createPass(config_.features)); pm.addPass(type_graph::NameGen::createPass()); pm.addPass(type_graph::AlignmentCalc::createPass()); pm.addPass(type_graph::RemoveTopLevelPointer::createPass()); diff --git a/oi/Features.cpp b/oi/Features.cpp index f105191..37e9795 100644 --- a/oi/Features.cpp +++ b/oi/Features.cpp @@ -33,9 +33,11 @@ std::string_view featureHelp(Feature f) { case Feature::CaptureThriftIsset: return "Capture isset data for Thrift object."; case Feature::TypeGraph: - return "Use Type Graph for code generation (CodeGen V2)."; + return "Use Type Graph for code generation (CodeGen v2)."; case Feature::TypedDataSegment: return "Use Typed Data Segment in generated code."; + case Feature::TreeBuilderV2: + return "Use Tree Builder v2 for reading the data segment"; case Feature::GenJitDebug: return "Generate debug information for the JIT object."; case Feature::JitLogging: diff --git a/oi/Features.h b/oi/Features.h index eb73493..caa4197 100644 --- a/oi/Features.h +++ b/oi/Features.h @@ -28,6 +28,7 @@ X(CaptureThriftIsset, "capture-thrift-isset") \ X(TypeGraph, "type-graph") \ X(TypedDataSegment, "typed-data-segment") \ + X(TreeBuilderV2, "tree-builder-v2") \ X(GenJitDebug, "gen-jit-debug") \ X(JitLogging, "jit-logging") \ X(JitTiming, "jit-timing") \ diff --git a/oi/type_graph/AddPadding.cpp b/oi/type_graph/AddPadding.cpp index 1d32e29..c841226 100644 --- a/oi/type_graph/AddPadding.cpp +++ b/oi/type_graph/AddPadding.cpp @@ -17,16 +17,20 @@ #include +#include "Flattener.h" #include "TypeGraph.h" template using ref = std::reference_wrapper; +using ObjectIntrospection::Feature; +using ObjectIntrospection::FeatureSet; + namespace type_graph { -Pass AddPadding::createPass() { - auto fn = [](TypeGraph& typeGraph) { - AddPadding pass(typeGraph); +Pass AddPadding::createPass(FeatureSet features) { + auto fn = [features](TypeGraph& typeGraph) { + AddPadding pass(typeGraph, features); for (auto& type : typeGraph.rootTypes()) { pass.visit(type); } @@ -67,6 +71,19 @@ void AddPadding::visit(Class& c) { if (i >= 1) { addPadding(c.members[i - 1], c.members[i].bitOffset, paddedMembers); } + + if (!features_[Feature::TreeBuilderV2] && + c.members[i].name.starts_with(Flattener::ParentPrefix)) { + // CodeGen v1 can't handle parent containers. It replaces them with + // padding. + auto& primitive = typeGraph_.makeType(Primitive::Kind::Int8); + auto& paddingArray = + typeGraph_.makeType(primitive, c.members[i].type().size()); + paddedMembers.emplace_back(paddingArray, MemberPrefix, + c.members[i].bitOffset); + continue; + } + paddedMembers.push_back(c.members[i]); } diff --git a/oi/type_graph/AddPadding.h b/oi/type_graph/AddPadding.h index dec7302..d643d24 100644 --- a/oi/type_graph/AddPadding.h +++ b/oi/type_graph/AddPadding.h @@ -15,12 +15,13 @@ */ #pragma once -#include +#include #include #include "PassManager.h" #include "Types.h" #include "Visitor.h" +#include "oi/Features.h" namespace type_graph { @@ -35,9 +36,11 @@ class TypeGraph; */ class AddPadding final : public RecursiveVisitor { public: - static Pass createPass(); + static Pass createPass(ObjectIntrospection::FeatureSet features); - explicit AddPadding(TypeGraph& typeGraph) : typeGraph_(typeGraph) { + explicit AddPadding(TypeGraph& typeGraph, + ObjectIntrospection::FeatureSet features) + : typeGraph_(typeGraph), features_(features) { } using RecursiveVisitor::visit; @@ -50,6 +53,7 @@ class AddPadding final : public RecursiveVisitor { private: std::unordered_set visited_; TypeGraph& typeGraph_; + ObjectIntrospection::FeatureSet features_; void addPadding(const Member& prevMember, uint64_t paddingEndBits, diff --git a/oi/type_graph/Flattener.cpp b/oi/type_graph/Flattener.cpp index ad8660d..b28267f 100644 --- a/oi/type_graph/Flattener.cpp +++ b/oi/type_graph/Flattener.cpp @@ -71,7 +71,7 @@ void flattenParent(const Parent& parent, } else if (Container* parentContainer = dynamic_cast(&parentType)) { // Create a new member to represent this parent container - flattenedMembers.emplace_back(*parentContainer, "__parent", + flattenedMembers.emplace_back(*parentContainer, Flattener::ParentPrefix, parent.bitOffset); } else { throw std::runtime_error("Invalid type for parent"); diff --git a/oi/type_graph/Flattener.h b/oi/type_graph/Flattener.h index 62b5d7d..dfdeb48 100644 --- a/oi/type_graph/Flattener.h +++ b/oi/type_graph/Flattener.h @@ -15,6 +15,7 @@ */ #pragma once +#include #include #include @@ -42,6 +43,8 @@ class Flattener : public RecursiveVisitor { void visit(Class& c) override; void visit(Container& c) override; + static const inline std::string ParentPrefix = "__oi_parent"; + private: std::unordered_set visited_; std::vector flattened_members_; diff --git a/test/test_add_padding.cpp b/test/test_add_padding.cpp index cf0e01f..16f97c8 100644 --- a/test/test_add_padding.cpp +++ b/test/test_add_padding.cpp @@ -5,6 +5,17 @@ #include "test/type_graph_utils.h" using namespace type_graph; +using ObjectIntrospection::Feature; +using ObjectIntrospection::FeatureSet; + +namespace { +void test(std::vector> rootTypes, + std::string_view expectedAfter) { + FeatureSet features; + features[Feature::TreeBuilderV2] = true; + ::test(AddPadding::createPass({}), rootTypes, expectedAfter); +} +} // namespace TEST(AddPaddingTest, BetweenMembers) { auto myclass = Class{0, Class::Kind::Class, "MyClass", 16}; @@ -13,7 +24,7 @@ TEST(AddPaddingTest, BetweenMembers) { myclass.members.push_back(Member{myint8, "n1", 0}); myclass.members.push_back(Member{myint64, "n2", 8 * 8}); - test(AddPadding::createPass(), {myclass}, R"( + test({myclass}, R"( [0] Class: MyClass (size: 16) Member: n1 (offset: 0) Primitive: int8_t @@ -32,7 +43,7 @@ TEST(AddPaddingTest, AtEnd) { myclass.members.push_back(Member{myint64, "n1", 0}); myclass.members.push_back(Member{myint8, "n2", 8 * 8}); - test(AddPadding::createPass(), {myclass}, R"( + test({myclass}, R"( [0] Struct: MyStruct (size: 16) Member: n1 (offset: 0) Primitive: int64_t @@ -51,7 +62,7 @@ TEST(AddPaddingTest, UnionNotPadded) { myclass.members.push_back(Member{myint64, "n1", 0}); myclass.members.push_back(Member{myint8, "n2", 0}); - test(AddPadding::createPass(), {myclass}, R"( + test({myclass}, R"( [0] Union: MyUnion (size: 8) Member: n1 (offset: 0) Primitive: int64_t @@ -86,7 +97,7 @@ TEST(AddPaddingTest, Bitfields) { myclass.members.push_back(b4); myclass.members.push_back(n); - test(AddPadding::createPass(), {myclass}, R"( + test({myclass}, R"( [0] Class: MyClass (size: 16) Member: b1 (offset: 0, bitsize: 3) Primitive: int64_t @@ -111,4 +122,29 @@ TEST(AddPaddingTest, Bitfields) { )"); } +TEST(AddPaddingTest, CodeGenCompatibility) { + auto myint = Primitive{Primitive::Kind::Int32}; + auto vector = getVector(1); + vector.templateParams.push_back(TemplateParam{myint}); + + auto myclass = Class{0, Class::Kind::Class, "MyClass", 24}; + myclass.members.push_back(Member{vector, "__oi_parent", 0}); + + FeatureSet features; + features[Feature::TreeBuilderV2] = false; + test(AddPadding::createPass(features), {myclass}, R"( +[0] Class: MyClass (size: 24) + Member: __oi_parent (offset: 0) +[1] Container: std::vector (size: 24) + Param + Primitive: int32_t +)", + R"( +[0] Class: MyClass (size: 24) + Member: __oi_padding (offset: 0) +[1] Array: (length: 24) + Primitive: int8_t +)"); +} + // TODO test we follow class members, templates, children diff --git a/test/test_flattener.cpp b/test/test_flattener.cpp index c7f18cb..ea24c98 100644 --- a/test/test_flattener.cpp +++ b/test/test_flattener.cpp @@ -705,7 +705,7 @@ TEST(FlattenerTest, ParentContainer) { )", R"( [0] Class: ClassA (size: 32) - Member: __parent (offset: 0) + Member: __oi_parent (offset: 0) [1] Container: std::vector (size: 24) Param Primitive: int32_t @@ -735,11 +735,11 @@ TEST(FlattenerTest, ParentTwoContainers) { )", R"( [0] Class: ClassA (size: 48) - Member: __parent (offset: 0) + Member: __oi_parent (offset: 0) [1] Container: std::vector (size: 24) Param Primitive: int32_t - Member: __parent (offset: 24) + Member: __oi_parent (offset: 24) [1] )"); } @@ -772,7 +772,7 @@ TEST(FlattenerTest, ParentClassAndContainer) { [0] Class: ClassA (size: 32) Member: b (offset: 0) Primitive: int32_t - Member: __parent (offset: 8) + Member: __oi_parent (offset: 8) [1] Container: std::vector (size: 24) Param Primitive: int32_t