diff --git a/oi/CodeGen.cpp b/oi/CodeGen.cpp index 2942c2f..f05265a 100644 --- a/oi/CodeGen.cpp +++ b/oi/CodeGen.cpp @@ -29,6 +29,7 @@ #include "type_graph/AddPadding.h" #include "type_graph/AlignmentCalc.h" #include "type_graph/DrgnParser.h" +#include "type_graph/EnforceCompatibility.h" #include "type_graph/Flattener.h" #include "type_graph/NameGen.h" #include "type_graph/Prune.h" @@ -45,6 +46,7 @@ using type_graph::AlignmentCalc; using type_graph::Class; using type_graph::Container; using type_graph::DrgnParser; +using type_graph::EnforceCompatibility; using type_graph::Enum; using type_graph::Flattener; using type_graph::Member; @@ -825,10 +827,13 @@ void CodeGen::transform(TypeGraph& typeGraph) { // influence on the class' overall alignment. pm.addPass(AlignmentCalc::createPass()); pm.addPass(RemoveMembers::createPass(config_.membersToStub)); + if (!config_.features[Feature::TreeBuilderV2]) { + pm.addPass(EnforceCompatibility::createPass()); + } // Add padding to fill in the gaps of removed members and ensure their // alignments - pm.addPass(AddPadding::createPass(config_.features)); + pm.addPass(AddPadding::createPass()); pm.addPass(NameGen::createPass()); pm.addPass(TopoSorter::createPass()); diff --git a/oi/type_graph/AddPadding.cpp b/oi/type_graph/AddPadding.cpp index d429e60..ac87aed 100644 --- a/oi/type_graph/AddPadding.cpp +++ b/oi/type_graph/AddPadding.cpp @@ -17,20 +17,16 @@ #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(FeatureSet features) { - auto fn = [features](TypeGraph& typeGraph) { - AddPadding pass(typeGraph, features); +Pass AddPadding::createPass() { + auto fn = [](TypeGraph& typeGraph) { + AddPadding pass(typeGraph); for (auto& type : typeGraph.rootTypes()) { pass.accept(type); } @@ -79,18 +75,6 @@ void AddPadding::visit(Class& c) { 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 6aac97d..000aa7e 100644 --- a/oi/type_graph/AddPadding.h +++ b/oi/type_graph/AddPadding.h @@ -21,7 +21,6 @@ #include "PassManager.h" #include "Types.h" #include "Visitor.h" -#include "oi/Features.h" namespace type_graph { @@ -36,11 +35,9 @@ class TypeGraph; */ class AddPadding final : public RecursiveVisitor { public: - static Pass createPass(ObjectIntrospection::FeatureSet features); + static Pass createPass(); - explicit AddPadding(TypeGraph& typeGraph, - ObjectIntrospection::FeatureSet features) - : typeGraph_(typeGraph), features_(features) { + explicit AddPadding(TypeGraph& typeGraph) : typeGraph_(typeGraph) { } using RecursiveVisitor::accept; @@ -53,7 +50,6 @@ 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/CMakeLists.txt b/oi/type_graph/CMakeLists.txt index 72b6da4..510d016 100644 --- a/oi/type_graph/CMakeLists.txt +++ b/oi/type_graph/CMakeLists.txt @@ -3,6 +3,7 @@ add_library(type_graph AddPadding.cpp AlignmentCalc.cpp DrgnParser.cpp + EnforceCompatibility.cpp Flattener.cpp NameGen.cpp PassManager.cpp diff --git a/oi/type_graph/EnforceCompatibility.cpp b/oi/type_graph/EnforceCompatibility.cpp new file mode 100644 index 0000000..4a04a40 --- /dev/null +++ b/oi/type_graph/EnforceCompatibility.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "EnforceCompatibility.h" + +#include + +#include "AddPadding.h" +#include "Flattener.h" +#include "TypeGraph.h" +#include "TypeIdentifier.h" + +namespace type_graph { + +Pass EnforceCompatibility::createPass() { + auto fn = [](TypeGraph& typeGraph) { + EnforceCompatibility pass{typeGraph.resetTracker()}; + for (auto& type : typeGraph.rootTypes()) { + pass.accept(type); + } + }; + + return Pass("EnforceCompatibility", fn); +} + +void EnforceCompatibility::accept(Type& type) { + if (tracker_.visit(type)) + return; + + type.accept(*this); +} + +void EnforceCompatibility::visit(Class& c) { + for (auto& param : c.templateParams) { + accept(param.type()); + } + for (auto& parent : c.parents) { + accept(parent.type()); + } + for (auto& member : c.members) { + accept(member.type()); + } + for (auto& child : c.children) { + accept(child); + } + + // CodeGen v1 replaces parent containers with padding + std::erase_if(c.members, [](Member member) { + return member.name.starts_with(Flattener::ParentPrefix); + }); +} + +} // namespace type_graph diff --git a/oi/type_graph/EnforceCompatibility.h b/oi/type_graph/EnforceCompatibility.h new file mode 100644 index 0000000..826d7b7 --- /dev/null +++ b/oi/type_graph/EnforceCompatibility.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +#include "NodeTracker.h" +#include "PassManager.h" +#include "Types.h" +#include "Visitor.h" + +namespace type_graph { + +/* + * EnforceCompatibility + * + * Transforms the type graph so that CodeGen produces code which is compatible + * with OICodeGen. + */ +class EnforceCompatibility : public RecursiveVisitor { + public: + static Pass createPass(); + + EnforceCompatibility(NodeTracker& tracker) : tracker_(tracker) { + } + + using RecursiveVisitor::accept; + + void accept(Type& type) override; + void visit(Class& c) override; + + private: + NodeTracker& tracker_; +}; + +} // namespace type_graph diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e284f4a..06f2ec6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -41,6 +41,7 @@ add_executable(test_type_graph test_alignment_calc.cpp test_codegen.cpp test_drgn_parser.cpp + test_enforce_compatibility.cpp test_flattener.cpp test_name_gen.cpp test_node_tracker.cpp diff --git a/test/test_add_padding.cpp b/test/test_add_padding.cpp index b3bf818..cd96265 100644 --- a/test/test_add_padding.cpp +++ b/test/test_add_padding.cpp @@ -5,17 +5,6 @@ #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}; @@ -24,7 +13,7 @@ TEST(AddPaddingTest, BetweenMembers) { myclass.members.push_back(Member{myint8, "n1", 0}); myclass.members.push_back(Member{myint64, "n2", 8 * 8}); - test({myclass}, R"( + test(AddPadding::createPass(), {myclass}, R"( [0] Class: MyClass (size: 16) Member: n1 (offset: 0) Primitive: int8_t @@ -43,7 +32,7 @@ TEST(AddPaddingTest, AtEnd) { myclass.members.push_back(Member{myint64, "n1", 0}); myclass.members.push_back(Member{myint8, "n2", 8 * 8}); - test({myclass}, R"( + test(AddPadding::createPass(), {myclass}, R"( [0] Struct: MyStruct (size: 16) Member: n1 (offset: 0) Primitive: int64_t @@ -62,7 +51,7 @@ TEST(AddPaddingTest, UnionBetweenMembers) { myclass.members.push_back(Member{myint64, "n1", 0}); myclass.members.push_back(Member{myint8, "n2", 0}); - test({myclass}, R"( + test(AddPadding::createPass(), {myclass}, R"( [0] Union: MyUnion (size: 8) Member: n1 (offset: 0) Primitive: int64_t @@ -72,7 +61,7 @@ TEST(AddPaddingTest, UnionBetweenMembers) { } TEST(AddPaddingTest, UnionAtEnd) { - test(AddPadding::createPass({}), R"( + test(AddPadding::createPass(), R"( [0] Union: MyUnion (size: 16) Member: n1 (offset: 0) Primitive: int64_t @@ -117,7 +106,7 @@ TEST(AddPaddingTest, Bitfields) { myclass.members.push_back(b4); myclass.members.push_back(n); - test({myclass}, R"( + test(AddPadding::createPass(), {myclass}, R"( [0] Class: MyClass (size: 16) Member: b1 (offset: 0, bitsize: 3) Primitive: int64_t @@ -145,39 +134,14 @@ 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 -)"); -} - TEST(AddPaddingTest, EmptyClass) { - testNoChange(AddPadding::createPass({}), R"( + testNoChange(AddPadding::createPass(), R"( [0] Class: MyClass (size: 0) )"); } TEST(AddPaddingTest, MemberlessClass) { - test(AddPadding::createPass({}), R"( + test(AddPadding::createPass(), R"( [0] Class: MyClass (size: 12) )", R"( @@ -189,7 +153,7 @@ TEST(AddPaddingTest, MemberlessClass) { } TEST(AddPaddingTest, MemberlessUnion) { - test(AddPadding::createPass({}), R"( + test(AddPadding::createPass(), R"( [0] Union: MyUnion (size: 16) )", R"( diff --git a/test/test_enforce_compatibility.cpp b/test/test_enforce_compatibility.cpp new file mode 100644 index 0000000..f398a6c --- /dev/null +++ b/test/test_enforce_compatibility.cpp @@ -0,0 +1,19 @@ +#include + +#include "oi/type_graph/EnforceCompatibility.h" +#include "test/type_graph_utils.h" + +using namespace type_graph; + +TEST(EnforceCompatibilityTest, ParentContainers) { + test(EnforceCompatibility::createPass(), 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) +)"); +}