mirror of
https://github.com/JakeHillion/object-introspection.git
synced 2024-11-09 21:24:14 +00:00
codegenv2: improve multi argument generation (#395)
Summary: Adds a new function `CodeGen::codegenFromDrgns` which runs multiple drgn root types through one `DrgnParser`. Stores the naming for the output within this function as we previously decided that when doing the actual codegen, which is too late with multiple root types. This new function is used in `OIGenerator` when you have multiple OIL calls within one input object. Rather than producing separate `.o`s with likely duplicate code for each callsite, we produce a single `.o` that contains both calls. For calls with types with significant overlap this should be a significant reduction in work. The downside is the calls can't have different features, but this could be solved in the future by namespacing the code based on features/config within the generated `.cpp` - the pros seem to outweigh the con. This should also be used with `oid` in multi probe mode as it would again significantly reduce the work it has to do. I didn't do this yet as it requires changing the cache. As I've got a big refactor cache ongoing at the minute it makes sense to wait until after that's landed to make this change. Test Plan: Generally tested with GitHub CI. Tested the new multi call OILGen with the new example seen below. Outputs the following code with two root calls: P869569859 - note that `VectorOfStrings_0` is the only instance, whereas previously we'd have generated it in two files. Differential Revision: D50835153 Pulled By: JakeHillion
This commit is contained in:
parent
6e1635ce1e
commit
a49f0e7410
128
oi/CodeGen.cpp
128
oi/CodeGen.cpp
@ -42,6 +42,9 @@
|
|||||||
#include "type_graph/TypeIdentifier.h"
|
#include "type_graph/TypeIdentifier.h"
|
||||||
#include "type_graph/Types.h"
|
#include "type_graph/Types.h"
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline constexpr bool always_false_v = false;
|
||||||
|
|
||||||
namespace oi::detail {
|
namespace oi::detail {
|
||||||
|
|
||||||
using type_graph::AddChildren;
|
using type_graph::AddChildren;
|
||||||
@ -74,6 +77,13 @@ using ref = std::reference_wrapper<T>;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
std::string rootTypedefName(Type& t) {
|
||||||
|
std::string out{"RootType"};
|
||||||
|
out += std::to_string(std::hash<std::string>{}(t.name()));
|
||||||
|
out += '_';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string_view> enumerateTypeNames(Type& type) {
|
std::vector<std::string_view> enumerateTypeNames(Type& type) {
|
||||||
std::vector<std::string_view> names;
|
std::vector<std::string_view> names;
|
||||||
Type* t = &type;
|
Type* t = &type;
|
||||||
@ -1106,14 +1116,7 @@ void CodeGen::addTypeHandlers(const TypeGraph& typeGraph, std::string& code) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CodeGen::codegenFromDrgn(struct drgn_type* drgnType,
|
bool CodeGen::codegenFromDrgns(std::span<DrgnRequest> reqs, std::string& code) {
|
||||||
std::string linkageName,
|
|
||||||
std::string& code) {
|
|
||||||
linkageName_ = std::move(linkageName);
|
|
||||||
return codegenFromDrgn(drgnType, code);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CodeGen::codegenFromDrgn(struct drgn_type* drgnType, std::string& code) {
|
|
||||||
try {
|
try {
|
||||||
containerInfos_.reserve(config_.containerConfigPaths.size());
|
containerInfos_.reserve(config_.containerConfigPaths.size());
|
||||||
for (const auto& path : config_.containerConfigPaths) {
|
for (const auto& path : config_.containerConfigPaths) {
|
||||||
@ -1125,18 +1128,40 @@ bool CodeGen::codegenFromDrgn(struct drgn_type* drgnType, std::string& code) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TypeGraph typeGraph;
|
TypeGraph typeGraph;
|
||||||
|
DrgnParserOptions options{
|
||||||
|
.chaseRawPointers = config_.features[Feature::ChaseRawPointers],
|
||||||
|
};
|
||||||
|
DrgnParser drgnParser{typeGraph, containerInfos_, options};
|
||||||
|
|
||||||
|
for (auto& req : reqs) {
|
||||||
try {
|
try {
|
||||||
addDrgnRoot(drgnType, typeGraph);
|
Type& parsedRoot = drgnParser.parse(req.ty);
|
||||||
|
typeGraph.addRoot(parsedRoot);
|
||||||
|
if (req.linkageName.has_value()) {
|
||||||
|
rootNames_.emplace_back(ExactName{.name = std::move(*req.linkageName)});
|
||||||
|
} else {
|
||||||
|
rootNames_.emplace_back(
|
||||||
|
HashedComponent{.name = SymbolService::getTypeName(req.ty)});
|
||||||
|
}
|
||||||
} catch (const type_graph::DrgnParserError& err) {
|
} catch (const type_graph::DrgnParserError& err) {
|
||||||
LOG(ERROR) << "Error parsing DWARF: " << err.what();
|
LOG(ERROR) << "Error parsing DWARF: " << err.what();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
transform(typeGraph);
|
transform(typeGraph);
|
||||||
generate(typeGraph, code, drgnType);
|
generate(typeGraph, code);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CodeGen::codegenFromDrgn(struct drgn_type* drgnType, std::string& code) {
|
||||||
|
std::array<DrgnRequest, 1> reqs{DrgnRequest{
|
||||||
|
.ty = drgnType,
|
||||||
|
.linkageName = std::nullopt,
|
||||||
|
}};
|
||||||
|
return codegenFromDrgns(reqs, code);
|
||||||
|
}
|
||||||
|
|
||||||
void CodeGen::registerContainer(const fs::path& path) {
|
void CodeGen::registerContainer(const fs::path& path) {
|
||||||
auto info = std::make_unique<ContainerInfo>(path);
|
auto info = std::make_unique<ContainerInfo>(path);
|
||||||
if (info->requiredFeatures != (config_.features & info->requiredFeatures)) {
|
if (info->requiredFeatures != (config_.features & info->requiredFeatures)) {
|
||||||
@ -1147,15 +1172,6 @@ void CodeGen::registerContainer(const fs::path& path) {
|
|||||||
containerInfos_.emplace_back(std::move(info));
|
containerInfos_.emplace_back(std::move(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGen::addDrgnRoot(struct drgn_type* drgnType, TypeGraph& typeGraph) {
|
|
||||||
DrgnParserOptions options{
|
|
||||||
.chaseRawPointers = config_.features[Feature::ChaseRawPointers],
|
|
||||||
};
|
|
||||||
DrgnParser drgnParser{typeGraph, containerInfos_, options};
|
|
||||||
Type& parsedRoot = drgnParser.parse(drgnType);
|
|
||||||
typeGraph.addRoot(parsedRoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeGen::transform(TypeGraph& typeGraph) {
|
void CodeGen::transform(TypeGraph& typeGraph) {
|
||||||
type_graph::PassManager pm;
|
type_graph::PassManager pm;
|
||||||
|
|
||||||
@ -1207,11 +1223,7 @@ void CodeGen::transform(TypeGraph& typeGraph) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGen::generate(
|
void CodeGen::generate(TypeGraph& typeGraph, std::string& code) {
|
||||||
TypeGraph& typeGraph,
|
|
||||||
std::string& code,
|
|
||||||
struct drgn_type* drgnType /* TODO: this argument should not be required */
|
|
||||||
) {
|
|
||||||
code = headers::oi_OITraceCode_cpp;
|
code = headers::oi_OITraceCode_cpp;
|
||||||
if (!config_.features[Feature::Library]) {
|
if (!config_.features[Feature::Library]) {
|
||||||
FuncGen::DeclareExterns(code);
|
FuncGen::DeclareExterns(code);
|
||||||
@ -1280,30 +1292,66 @@ void CodeGen::generate(
|
|||||||
addGetSizeFuncDefs(typeGraph, code);
|
addGetSizeFuncDefs(typeGraph, code);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(typeGraph.rootTypes().size() == 1);
|
// Give each root type a unique typedef in the OIInternal namespace so they
|
||||||
Type& rootType = typeGraph.rootTypes()[0];
|
// don't have naming issues from outside.
|
||||||
code += "\nusing __ROOT_TYPE__ = " + rootType.name() + ";\n";
|
for (Type& rootType : typeGraph.rootTypes()) {
|
||||||
|
code += "using ";
|
||||||
|
code += rootTypedefName(rootType);
|
||||||
|
code += " = ";
|
||||||
|
code += rootType.name();
|
||||||
|
code += ";\n";
|
||||||
|
}
|
||||||
|
|
||||||
code += "} // namespace\n} // namespace OIInternal\n";
|
code += "} // namespace\n} // namespace OIInternal\n";
|
||||||
|
|
||||||
const auto typeName = SymbolService::getTypeName(drgnType);
|
assert(typeGraph.rootTypes().size() == rootNames_.size());
|
||||||
if (config_.features[Feature::Library]) {
|
// should be std::ranges::zip_view(typeGraph.rootTypes(), rootNames_)
|
||||||
FuncGen::DefineTopLevelIntrospect(code, typeName);
|
auto rootTypeIt = typeGraph.rootTypes().begin();
|
||||||
} else if (config_.features[Feature::TypedDataSegment]) {
|
for (auto rootNameIt = rootNames_.cbegin();
|
||||||
FuncGen::DefineTopLevelGetSizeRefTyped(code, typeName, config_.features);
|
rootNameIt != rootNames_.cend() &&
|
||||||
} else {
|
rootTypeIt != typeGraph.rootTypes().end();
|
||||||
FuncGen::DefineTopLevelGetSizeRef(code, typeName, config_.features);
|
++rootNameIt, ++rootTypeIt) {
|
||||||
}
|
Type& rootType = *rootTypeIt;
|
||||||
|
const auto& rootName = *rootNameIt;
|
||||||
|
|
||||||
|
const auto typedefName = rootTypedefName(rootType);
|
||||||
|
|
||||||
if (config_.features[Feature::TreeBuilderV2]) {
|
if (config_.features[Feature::TreeBuilderV2]) {
|
||||||
FuncGen::DefineTreeBuilderInstructions(code, typeName,
|
std::visit(
|
||||||
|
[&](const auto& name) {
|
||||||
|
using T = std::decay_t<decltype(name)>;
|
||||||
|
if constexpr (std::is_same_v<ExactName, T>) {
|
||||||
|
FuncGen::DefineTopLevelIntrospectNamed(
|
||||||
|
code, typedefName, name.name,
|
||||||
calculateExclusiveSize(rootType),
|
calculateExclusiveSize(rootType),
|
||||||
enumerateTypeNames(rootType));
|
enumerateTypeNames(rootType));
|
||||||
} else if (config_.features[Feature::TreeBuilderTypeChecking]) {
|
} else if constexpr (std::is_same_v<HashedComponent, T>) {
|
||||||
FuncGen::DefineOutputType(code, typeName);
|
FuncGen::DefineTopLevelIntrospect(code, typedefName, name.name);
|
||||||
|
FuncGen::DefineTreeBuilderInstructions(
|
||||||
|
code, typedefName, name.name,
|
||||||
|
calculateExclusiveSize(rootType),
|
||||||
|
enumerateTypeNames(rootType));
|
||||||
|
} else {
|
||||||
|
static_assert(always_false_v<T>);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rootName);
|
||||||
|
} else if (config_.features[Feature::TypedDataSegment]) {
|
||||||
|
const auto& name = std::get<HashedComponent>(rootName).name;
|
||||||
|
FuncGen::DefineTopLevelGetSizeRefTyped(code, typedefName, name,
|
||||||
|
config_.features);
|
||||||
|
} else {
|
||||||
|
const auto& name = std::get<HashedComponent>(rootName).name;
|
||||||
|
FuncGen::DefineTopLevelGetSizeRef(code, typedefName, name,
|
||||||
|
config_.features);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!linkageName_.empty())
|
if (config_.features[Feature::TreeBuilderTypeChecking] &&
|
||||||
FuncGen::DefineTopLevelIntrospectNamed(code, typeName, linkageName_);
|
!config_.features[Feature::TreeBuilderV2]) {
|
||||||
|
const auto& name = std::get<HashedComponent>(rootName).name;
|
||||||
|
FuncGen::DefineOutputType(code, typedefName, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (VLOG_IS_ON(3)) {
|
if (VLOG_IS_ON(3)) {
|
||||||
VLOG(3) << "Generated trace code:\n";
|
VLOG(3) << "Generated trace code:\n";
|
||||||
|
31
oi/CodeGen.h
31
oi/CodeGen.h
@ -18,9 +18,11 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "ContainerInfo.h"
|
#include "ContainerInfo.h"
|
||||||
@ -40,6 +42,11 @@ namespace oi::detail {
|
|||||||
|
|
||||||
class CodeGen {
|
class CodeGen {
|
||||||
public:
|
public:
|
||||||
|
struct DrgnRequest {
|
||||||
|
drgn_type* ty = nullptr;
|
||||||
|
std::optional<std::string> linkageName;
|
||||||
|
};
|
||||||
|
|
||||||
CodeGen(const OICodeGen::Config& config, SymbolService& symbols)
|
CodeGen(const OICodeGen::Config& config, SymbolService& symbols)
|
||||||
: config_(config), symbols_(symbols) {
|
: config_(config), symbols_(symbols) {
|
||||||
}
|
}
|
||||||
@ -48,29 +55,29 @@ class CodeGen {
|
|||||||
* Helper function to perform all the steps required for code generation for a
|
* Helper function to perform all the steps required for code generation for a
|
||||||
* single drgn_type.
|
* single drgn_type.
|
||||||
*/
|
*/
|
||||||
bool codegenFromDrgn(struct drgn_type* drgnType, std::string& code);
|
bool codegenFromDrgn(drgn_type* drgnType, std::string& code);
|
||||||
bool codegenFromDrgn(struct drgn_type* drgnType,
|
bool codegenFromDrgns(std::span<DrgnRequest> reqs, std::string& code);
|
||||||
std::string linkageName,
|
|
||||||
std::string& code);
|
|
||||||
|
|
||||||
void registerContainer(const std::filesystem::path& path);
|
void registerContainer(const std::filesystem::path& path);
|
||||||
void addDrgnRoot(struct drgn_type* drgnType,
|
|
||||||
type_graph::TypeGraph& typeGraph);
|
|
||||||
void transform(type_graph::TypeGraph& typeGraph);
|
void transform(type_graph::TypeGraph& typeGraph);
|
||||||
void generate(type_graph::TypeGraph& typeGraph,
|
void generate(type_graph::TypeGraph& typeGraph, std::string& code);
|
||||||
std::string& code,
|
|
||||||
struct drgn_type*
|
|
||||||
drgnType /* TODO: this argument should not be required */
|
|
||||||
);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct ExactName {
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
struct HashedComponent {
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
using RootFunctionName = std::variant<ExactName, HashedComponent>;
|
||||||
|
|
||||||
const OICodeGen::Config& config_;
|
const OICodeGen::Config& config_;
|
||||||
SymbolService& symbols_;
|
SymbolService& symbols_;
|
||||||
std::vector<std::unique_ptr<ContainerInfo>> containerInfos_;
|
std::vector<std::unique_ptr<ContainerInfo>> containerInfos_;
|
||||||
std::unordered_set<const ContainerInfo*> definedContainers_;
|
std::unordered_set<const ContainerInfo*> definedContainers_;
|
||||||
std::unordered_map<const type_graph::Class*, const type_graph::Member*>
|
std::unordered_map<const type_graph::Class*, const type_graph::Member*>
|
||||||
thriftIssetMembers_;
|
thriftIssetMembers_;
|
||||||
std::string linkageName_;
|
std::vector<RootFunctionName> rootNames_;
|
||||||
|
|
||||||
void genDefsThrift(const type_graph::TypeGraph& typeGraph, std::string& code);
|
void genDefsThrift(const type_graph::TypeGraph& typeGraph, std::string& code);
|
||||||
void addGetSizeFuncDefs(const type_graph::TypeGraph& typeGraph,
|
void addGetSizeFuncDefs(const type_graph::TypeGraph& typeGraph,
|
||||||
|
@ -252,13 +252,13 @@ void FuncGen::DefineStoreData(std::string& testCode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FuncGen::DefineTopLevelIntrospect(std::string& code,
|
void FuncGen::DefineTopLevelIntrospect(std::string& code,
|
||||||
const std::string& type) {
|
const std::string& type,
|
||||||
|
const std::string& idToHash) {
|
||||||
std::string func = R"(
|
std::string func = R"(
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wunknown-attributes"
|
#pragma GCC diagnostic ignored "-Wunknown-attributes"
|
||||||
/* RawType: %1% */
|
|
||||||
void __attribute__((used, retain)) introspect_%2$016x(
|
void __attribute__((used, retain)) introspect_%2$016x(
|
||||||
const OIInternal::__ROOT_TYPE__& t,
|
const OIInternal::%1%& t,
|
||||||
std::vector<uint8_t>& v)
|
std::vector<uint8_t>& v)
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
{
|
{
|
||||||
@ -269,7 +269,7 @@ void __attribute__((used, retain)) introspect_%2$016x(
|
|||||||
v.reserve(4096);
|
v.reserve(4096);
|
||||||
|
|
||||||
using DataBufferType = DataBuffer::BackInserter<std::vector<uint8_t>>;
|
using DataBufferType = DataBuffer::BackInserter<std::vector<uint8_t>>;
|
||||||
using ContentType = OIInternal::TypeHandler<DataBufferType, OIInternal::__ROOT_TYPE__>::type;
|
using ContentType = OIInternal::TypeHandler<DataBufferType, OIInternal::%1%>::type;
|
||||||
|
|
||||||
ContentType ret{DataBufferType{v}};
|
ContentType ret{DataBufferType{v}};
|
||||||
OIInternal::getSizeType<DataBufferType>(t, ret);
|
OIInternal::getSizeType<DataBufferType>(t, ret);
|
||||||
@ -277,39 +277,47 @@ void __attribute__((used, retain)) introspect_%2$016x(
|
|||||||
)";
|
)";
|
||||||
|
|
||||||
code.append(
|
code.append(
|
||||||
(boost::format(func) % type % std::hash<std::string>{}(type)).str());
|
(boost::format(func) % type % std::hash<std::string>{}(idToHash)).str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FuncGen::DefineTopLevelIntrospectNamed(std::string& code,
|
void FuncGen::DefineTopLevelIntrospectNamed(
|
||||||
|
std::string& code,
|
||||||
const std::string& type,
|
const std::string& type,
|
||||||
const std::string& linkageName) {
|
const std::string& linkageName,
|
||||||
std::string typeHash =
|
size_t exclusiveSize,
|
||||||
(boost::format("%1$016x") % std::hash<std::string>{}(type)).str();
|
std::span<const std::string_view> typeNames) {
|
||||||
|
code += "namespace {\n";
|
||||||
|
DefineTreeBuilderInstructions(code, type, linkageName, exclusiveSize,
|
||||||
|
typeNames);
|
||||||
|
DefineTopLevelIntrospect(code, type, linkageName);
|
||||||
|
code += "} // namespace\n";
|
||||||
|
|
||||||
|
std::string internalId =
|
||||||
|
(boost::format("%1$016x") % std::hash<std::string>{}(linkageName)).str();
|
||||||
|
|
||||||
code += "/* RawType: ";
|
|
||||||
code += type;
|
|
||||||
code += " */\n";
|
|
||||||
code += "extern \"C\" IntrospectionResult ";
|
code += "extern \"C\" IntrospectionResult ";
|
||||||
code += linkageName;
|
code += linkageName;
|
||||||
code += "(const OIInternal::__ROOT_TYPE__& t) {\n";
|
code += "(const OIInternal::";
|
||||||
|
code += type;
|
||||||
|
code += "& t) {\n";
|
||||||
code += " std::vector<uint8_t> v{};\n";
|
code += " std::vector<uint8_t> v{};\n";
|
||||||
code += " introspect_";
|
code += " introspect_";
|
||||||
code += typeHash;
|
code += internalId;
|
||||||
code += "(t, v);\n";
|
code += "(t, v);\n";
|
||||||
code += " return IntrospectionResult{std::move(v), treeBuilderInstructions";
|
code += " return IntrospectionResult{std::move(v), treeBuilderInstructions";
|
||||||
code += typeHash;
|
code += internalId;
|
||||||
code += "};\n";
|
code += "};\n";
|
||||||
code += "}\n";
|
code += "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void FuncGen::DefineTopLevelGetSizeRef(std::string& testCode,
|
void FuncGen::DefineTopLevelGetSizeRef(std::string& testCode,
|
||||||
const std::string& rawType,
|
const std::string& type,
|
||||||
|
const std::string& idToHash,
|
||||||
FeatureSet features) {
|
FeatureSet features) {
|
||||||
std::string func = R"(
|
std::string func = R"(
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wunknown-attributes"
|
#pragma GCC diagnostic ignored "-Wunknown-attributes"
|
||||||
/* RawType: %1% */
|
void __attribute__((used, retain)) getSize_%2$016x(const OIInternal::%1%& t)
|
||||||
void __attribute__((used, retain)) getSize_%2$016x(const OIInternal::__ROOT_TYPE__& t)
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
{
|
{
|
||||||
)";
|
)";
|
||||||
@ -348,7 +356,7 @@ void FuncGen::DefineTopLevelGetSizeRef(std::string& testCode,
|
|||||||
)";
|
)";
|
||||||
|
|
||||||
boost::format fmt =
|
boost::format fmt =
|
||||||
boost::format(func) % rawType % std::hash<std::string>{}(rawType);
|
boost::format(func) % type % std::hash<std::string>{}(idToHash);
|
||||||
testCode.append(fmt.str());
|
testCode.append(fmt.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,13 +367,13 @@ void FuncGen::DefineTopLevelGetSizeRef(std::string& testCode,
|
|||||||
* with feature '-ftyped-data-segment'.
|
* with feature '-ftyped-data-segment'.
|
||||||
*/
|
*/
|
||||||
void FuncGen::DefineTopLevelGetSizeRefTyped(std::string& testCode,
|
void FuncGen::DefineTopLevelGetSizeRefTyped(std::string& testCode,
|
||||||
const std::string& rawType,
|
const std::string& type,
|
||||||
|
const std::string& idToHash,
|
||||||
FeatureSet features) {
|
FeatureSet features) {
|
||||||
std::string func = R"(
|
std::string func = R"(
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wunknown-attributes"
|
#pragma GCC diagnostic ignored "-Wunknown-attributes"
|
||||||
/* RawType: %1% */
|
void __attribute__((used, retain)) getSize_%2$016x(const OIInternal::%1%& t)
|
||||||
void __attribute__((used, retain)) getSize_%2$016x(const OIInternal::__ROOT_TYPE__& t)
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
{
|
{
|
||||||
)";
|
)";
|
||||||
@ -390,7 +398,7 @@ void FuncGen::DefineTopLevelGetSizeRefTyped(std::string& testCode,
|
|||||||
JLOG("%1% @");
|
JLOG("%1% @");
|
||||||
JLOGPTR(&t);
|
JLOGPTR(&t);
|
||||||
|
|
||||||
using ContentType = OIInternal::TypeHandler<DataBuffer::DataSegment, OIInternal::__ROOT_TYPE__>::type;
|
using ContentType = OIInternal::TypeHandler<DataBuffer::DataSegment, OIInternal::%1%>::type;
|
||||||
using SuffixType = types::st::Pair<
|
using SuffixType = types::st::Pair<
|
||||||
DataBuffer::DataSegment,
|
DataBuffer::DataSegment,
|
||||||
types::st::VarInt<DataBuffer::DataSegment>,
|
types::st::VarInt<DataBuffer::DataSegment>,
|
||||||
@ -425,7 +433,7 @@ void FuncGen::DefineTopLevelGetSizeRefTyped(std::string& testCode,
|
|||||||
)";
|
)";
|
||||||
|
|
||||||
boost::format fmt =
|
boost::format fmt =
|
||||||
boost::format(func) % rawType % std::hash<std::string>{}(rawType);
|
boost::format(func) % type % std::hash<std::string>{}(idToHash);
|
||||||
testCode.append(fmt.str());
|
testCode.append(fmt.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,28 +442,30 @@ void FuncGen::DefineTopLevelGetSizeRefTyped(std::string& testCode,
|
|||||||
*
|
*
|
||||||
* Present the dynamic type of an object for OID/OIL/OITB to link against.
|
* Present the dynamic type of an object for OID/OIL/OITB to link against.
|
||||||
*/
|
*/
|
||||||
void FuncGen::DefineOutputType(std::string& code, const std::string& rawType) {
|
void FuncGen::DefineOutputType(std::string& code,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& idToHash) {
|
||||||
std::string func = R"(
|
std::string func = R"(
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wunknown-attributes"
|
#pragma GCC diagnostic ignored "-Wunknown-attributes"
|
||||||
/* RawType: %1% */
|
|
||||||
extern const types::dy::Dynamic __attribute__((used, retain)) outputType%2$016x =
|
extern const types::dy::Dynamic __attribute__((used, retain)) outputType%2$016x =
|
||||||
OIInternal::TypeHandler<DataBuffer::DataSegment, OIInternal::__ROOT_TYPE__>::type::describe;
|
OIInternal::TypeHandler<DataBuffer::DataSegment, OIInternal::%1%>::type::describe;
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
)";
|
)";
|
||||||
|
|
||||||
boost::format fmt =
|
boost::format fmt =
|
||||||
boost::format(func) % rawType % std::hash<std::string>{}(rawType);
|
boost::format(func) % type % std::hash<std::string>{}(idToHash);
|
||||||
code.append(fmt.str());
|
code.append(fmt.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FuncGen::DefineTreeBuilderInstructions(
|
void FuncGen::DefineTreeBuilderInstructions(
|
||||||
std::string& code,
|
std::string& code,
|
||||||
const std::string& rawType,
|
const std::string& type,
|
||||||
|
const std::string& idToHash,
|
||||||
size_t exclusiveSize,
|
size_t exclusiveSize,
|
||||||
std::span<const std::string_view> typeNames) {
|
std::span<const std::string_view> typeNames) {
|
||||||
std::string typeHash =
|
std::string typeHash =
|
||||||
(boost::format("%1$016x") % std::hash<std::string>{}(rawType)).str();
|
(boost::format("%1$016x") % std::hash<std::string>{}(idToHash)).str();
|
||||||
|
|
||||||
code += R"(
|
code += R"(
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
@ -474,13 +484,17 @@ const std::array<std::string_view, )";
|
|||||||
code += "};\n";
|
code += "};\n";
|
||||||
code += "const exporters::inst::Field rootInstructions";
|
code += "const exporters::inst::Field rootInstructions";
|
||||||
code += typeHash;
|
code += typeHash;
|
||||||
code += "{sizeof(OIInternal::__ROOT_TYPE__), ";
|
code += "{sizeof(OIInternal::";
|
||||||
|
code += type;
|
||||||
|
code += "), ";
|
||||||
code += std::to_string(exclusiveSize);
|
code += std::to_string(exclusiveSize);
|
||||||
code += ", \"a0\", typeNames";
|
code += ", \"a0\", typeNames";
|
||||||
code += typeHash;
|
code += typeHash;
|
||||||
code +=
|
code += ", OIInternal::TypeHandler<int, OIInternal::";
|
||||||
", OIInternal::TypeHandler<int, OIInternal::__ROOT_TYPE__>::fields, "
|
code += type;
|
||||||
"OIInternal::TypeHandler<int, OIInternal::__ROOT_TYPE__>::processors};\n";
|
code += ">::fields, OIInternal::TypeHandler<int, OIInternal::";
|
||||||
|
code += type;
|
||||||
|
code += ">::processors};\n";
|
||||||
code += "} // namespace\n";
|
code += "} // namespace\n";
|
||||||
code +=
|
code +=
|
||||||
"extern const exporters::inst::Inst __attribute__((used, retain)) "
|
"extern const exporters::inst::Inst __attribute__((used, retain)) "
|
||||||
|
22
oi/FuncGen.h
22
oi/FuncGen.h
@ -53,22 +53,30 @@ class FuncGen {
|
|||||||
static void DeclareGetSize(std::string& testCode, const std::string& type);
|
static void DeclareGetSize(std::string& testCode, const std::string& type);
|
||||||
|
|
||||||
static void DefineTopLevelIntrospect(std::string& code,
|
static void DefineTopLevelIntrospect(std::string& code,
|
||||||
const std::string& type);
|
|
||||||
static void DefineTopLevelIntrospectNamed(std::string& code,
|
|
||||||
const std::string& type,
|
const std::string& type,
|
||||||
const std::string& linkageName);
|
const std::string& idToHash);
|
||||||
|
static void DefineTopLevelIntrospectNamed(
|
||||||
|
std::string& code,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& linkageName,
|
||||||
|
size_t exclusiveSize,
|
||||||
|
std::span<const std::string_view> typeNames);
|
||||||
|
|
||||||
static void DefineTopLevelGetSizeRef(std::string& testCode,
|
static void DefineTopLevelGetSizeRef(std::string& testCode,
|
||||||
const std::string& rawType,
|
const std::string& type,
|
||||||
|
const std::string& idToHash,
|
||||||
FeatureSet features);
|
FeatureSet features);
|
||||||
static void DefineTopLevelGetSizeRefTyped(std::string& testCode,
|
static void DefineTopLevelGetSizeRefTyped(std::string& testCode,
|
||||||
const std::string& rawType,
|
const std::string& type,
|
||||||
|
const std::string& idToHash,
|
||||||
FeatureSet features);
|
FeatureSet features);
|
||||||
static void DefineOutputType(std::string& testCode,
|
static void DefineOutputType(std::string& testCode,
|
||||||
const std::string& rawType);
|
const std::string& type,
|
||||||
|
const std::string& idToHash);
|
||||||
static void DefineTreeBuilderInstructions(
|
static void DefineTreeBuilderInstructions(
|
||||||
std::string& testCode,
|
std::string& testCode,
|
||||||
const std::string& rawType,
|
const std::string& type,
|
||||||
|
const std::string& idToHash,
|
||||||
size_t exclusiveSize,
|
size_t exclusiveSize,
|
||||||
std::span<const std::string_view> typeNames);
|
std::span<const std::string_view> typeNames);
|
||||||
|
|
||||||
|
@ -3331,8 +3331,8 @@ bool OICodeGen::generateJitCode(std::string& code) {
|
|||||||
funcGen.DefineTopLevelGetSizeSmartPtr(functionsCode, rawTypeName,
|
funcGen.DefineTopLevelGetSizeSmartPtr(functionsCode, rawTypeName,
|
||||||
config.features);
|
config.features);
|
||||||
} else {
|
} else {
|
||||||
funcGen.DefineTopLevelGetSizeRef(functionsCode, rawTypeName,
|
funcGen.DefineTopLevelGetSizeRef(functionsCode, "__ROOT_TYPE__",
|
||||||
config.features);
|
rawTypeName, config.features);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,9 +29,16 @@
|
|||||||
#include "oi/Config.h"
|
#include "oi/Config.h"
|
||||||
#include "oi/DrgnUtils.h"
|
#include "oi/DrgnUtils.h"
|
||||||
#include "oi/Headers.h"
|
#include "oi/Headers.h"
|
||||||
|
#include "oi/type_graph/DrgnParser.h"
|
||||||
|
#include "oi/type_graph/TypeGraph.h"
|
||||||
|
|
||||||
namespace oi::detail {
|
namespace oi::detail {
|
||||||
|
|
||||||
|
using type_graph::DrgnParser;
|
||||||
|
using type_graph::DrgnParserOptions;
|
||||||
|
using type_graph::Type;
|
||||||
|
using type_graph::TypeGraph;
|
||||||
|
|
||||||
std::unordered_map<std::string, std::string>
|
std::unordered_map<std::string, std::string>
|
||||||
OIGenerator::oilStrongToWeakSymbolsMap(drgnplusplus::program& prog) {
|
OIGenerator::oilStrongToWeakSymbolsMap(drgnplusplus::program& prog) {
|
||||||
static constexpr std::string_view strongSymbolPrefix =
|
static constexpr std::string_view strongSymbolPrefix =
|
||||||
@ -128,42 +135,6 @@ OIGenerator::findOilTypesAndNames(drgnplusplus::program& prog) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path OIGenerator::generateForType(const OICodeGen::Config& generatorConfig,
|
|
||||||
const OICompiler::Config& compilerConfig,
|
|
||||||
const drgn_qualified_type& type,
|
|
||||||
const std::string& linkageName,
|
|
||||||
SymbolService& symbols) {
|
|
||||||
CodeGen codegen{generatorConfig, symbols};
|
|
||||||
|
|
||||||
std::string code;
|
|
||||||
if (!codegen.codegenFromDrgn(type.type, linkageName, code)) {
|
|
||||||
LOG(ERROR) << "codegen failed!";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string sourcePath = sourceFileDumpPath;
|
|
||||||
if (sourceFileDumpPath.empty()) {
|
|
||||||
// This is the path Clang acts as if it has compiled from e.g. for debug
|
|
||||||
// information. It does not need to exist.
|
|
||||||
sourcePath = "oil_jit.cpp";
|
|
||||||
} else {
|
|
||||||
std::ofstream outputFile(sourcePath);
|
|
||||||
outputFile << code;
|
|
||||||
}
|
|
||||||
|
|
||||||
OICompiler compiler{{}, compilerConfig};
|
|
||||||
|
|
||||||
// TODO: Revert to outputPath and remove printing when typegraph is done.
|
|
||||||
fs::path tmpObject = outputPath;
|
|
||||||
tmpObject.replace_extension(
|
|
||||||
"." + std::to_string(std::hash<std::string>{}(linkageName)) + ".o");
|
|
||||||
|
|
||||||
if (!compiler.compile(code, sourcePath, tmpObject)) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return tmpObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
int OIGenerator::generate(fs::path& primaryObject, SymbolService& symbols) {
|
int OIGenerator::generate(fs::path& primaryObject, SymbolService& symbols) {
|
||||||
drgnplusplus::program prog;
|
drgnplusplus::program prog;
|
||||||
|
|
||||||
@ -202,26 +173,34 @@ int OIGenerator::generate(fs::path& primaryObject, SymbolService& symbols) {
|
|||||||
generatorConfig.features = *features;
|
generatorConfig.features = *features;
|
||||||
compilerConfig.features = *features;
|
compilerConfig.features = *features;
|
||||||
|
|
||||||
size_t failures = 0;
|
std::vector<CodeGen::DrgnRequest> reqs{};
|
||||||
|
reqs.reserve(oilTypes.size());
|
||||||
for (const auto& [linkageName, type] : oilTypes) {
|
for (const auto& [linkageName, type] : oilTypes) {
|
||||||
if (auto obj = generateForType(generatorConfig, compilerConfig, type,
|
reqs.emplace_back(
|
||||||
linkageName, symbols);
|
CodeGen::DrgnRequest{.ty = type.type, .linkageName = linkageName});
|
||||||
!obj.empty()) {
|
}
|
||||||
std::cout << obj.string() << std::endl;
|
|
||||||
|
CodeGen codegen{generatorConfig, symbols};
|
||||||
|
std::string code;
|
||||||
|
codegen.codegenFromDrgns(reqs, code);
|
||||||
|
|
||||||
|
std::string sourcePath = sourceFileDumpPath;
|
||||||
|
if (sourceFileDumpPath.empty()) {
|
||||||
|
// This is the path Clang acts as if it has compiled from e.g. for debug
|
||||||
|
// information. It does not need to exist.
|
||||||
|
sourcePath = "oil_jit.cpp";
|
||||||
} else {
|
} else {
|
||||||
LOG(WARNING) << "failed to generate for symbol `" << linkageName
|
std::ofstream outputFile(sourcePath);
|
||||||
<< "`. this is non-fatal but the call will not work.";
|
outputFile << code;
|
||||||
failures++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
OICompiler compiler{{}, compilerConfig};
|
||||||
|
|
||||||
size_t successes = oilTypes.size() - failures;
|
if (!compiler.compile(code, sourcePath, outputPath)) {
|
||||||
LOG(INFO) << "object introspection generation complete. " << successes
|
|
||||||
<< " successes and " << failures << " failures.";
|
|
||||||
|
|
||||||
if (failures > 0 || (failIfNothingGenerated && successes == 0)) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG(INFO) << "object introspection generation complete, generated for "
|
||||||
|
<< oilTypes.size() << "sites.";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ struct DrgnParserOptions {
|
|||||||
class DrgnParser {
|
class DrgnParser {
|
||||||
public:
|
public:
|
||||||
DrgnParser(TypeGraph& typeGraph,
|
DrgnParser(TypeGraph& typeGraph,
|
||||||
const std::vector<std::unique_ptr<ContainerInfo>>& containers,
|
std::span<const std::unique_ptr<ContainerInfo>> containers,
|
||||||
DrgnParserOptions options)
|
DrgnParserOptions options)
|
||||||
: typeGraph_(typeGraph), containers_(containers), options_(options) {
|
: typeGraph_(typeGraph), containers_(containers), options_(options) {
|
||||||
}
|
}
|
||||||
@ -90,6 +91,7 @@ class DrgnParser {
|
|||||||
drgn_types_.insert({drgnType, newType});
|
drgn_types_.insert({drgnType, newType});
|
||||||
return newType;
|
return newType;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool chasePointer() const;
|
bool chasePointer() const;
|
||||||
|
|
||||||
// Store a mapping of drgn types to type graph nodes for deduplication during
|
// Store a mapping of drgn types to type graph nodes for deduplication during
|
||||||
@ -98,7 +100,7 @@ class DrgnParser {
|
|||||||
drgn_types_;
|
drgn_types_;
|
||||||
|
|
||||||
TypeGraph& typeGraph_;
|
TypeGraph& typeGraph_;
|
||||||
const std::vector<std::unique_ptr<ContainerInfo>>& containers_;
|
std::span<const std::unique_ptr<ContainerInfo>> containers_;
|
||||||
int depth_;
|
int depth_;
|
||||||
DrgnParserOptions options_;
|
DrgnParserOptions options_;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user