features: switch to bitset

This commit is contained in:
Jake Hillion 2023-04-24 08:35:16 -07:00 committed by Jake Hillion
parent 66a171eedc
commit a9ace14466
10 changed files with 63 additions and 52 deletions

View File

@ -45,4 +45,10 @@ const char* featureToStr(Feature f) {
}
}
FeatureSet::FeatureSet(std::initializer_list<Feature> features) {
for (auto f : features) {
(*this)[f] = true;
}
}
} // namespace ObjectIntrospection

View File

@ -16,6 +16,7 @@
#pragma once
#include <array>
#include <bitset>
#include <string_view>
#define OI_FEATURE_LIST \
@ -43,4 +44,23 @@ constexpr std::array allFeatures = {
#undef X
};
class FeatureSet {
private:
using BitsetType = std::bitset<allFeatures.size() + 1>;
public:
FeatureSet() = default;
FeatureSet(std::initializer_list<Feature>);
constexpr bool operator[](Feature f) const {
return bitset[(size_t)f];
}
BitsetType::reference operator[](Feature f) {
return bitset[(size_t)f];
}
private:
BitsetType bitset;
};
} // namespace ObjectIntrospection

View File

@ -62,13 +62,6 @@ std::unique_ptr<OICodeGen> OICodeGen::buildFromConfig(const Config& c,
OICodeGen::OICodeGen(const Config& c, SymbolService& s)
: config{c}, symbols{s} {
chaseRawPointers = config.features.contains(Feature::ChaseRawPointers);
packStructs = config.features.contains(Feature::PackStructs);
genPaddingStats = config.features.contains(Feature::GenPaddingStats);
captureThriftIsset = config.features.contains(Feature::CaptureThriftIsset);
polymorphicInheritance =
config.features.contains(Feature::PolymorphicInheritance);
// TODO: Should folly::Range just be added as a container?
auto typesToStub = std::array{
"SharedMutex",
@ -998,7 +991,7 @@ bool OICodeGen::recordChildren(drgn_type* type) {
* types in the program to build the reverse mapping.
*/
bool OICodeGen::enumerateChildClasses() {
if (!polymorphicInheritance) {
if (!feature(Feature::PolymorphicInheritance)) {
return true;
}
@ -1327,7 +1320,8 @@ bool OICodeGen::isEmptyClassOrFunctionType(drgn_type* type,
* one or more virtual member functions or virtual base classes).
*/
bool OICodeGen::isDynamic(drgn_type* type) const {
if (!polymorphicInheritance || !drgn_type_has_virtuality(type)) {
if (!feature(Feature::PolymorphicInheritance) ||
!drgn_type_has_virtuality(type)) {
return false;
}
@ -2008,7 +2002,7 @@ bool OICodeGen::getDrgnTypeNameInt(drgn_type* type, std::string& outName) {
name.assign(drgn_type_name(type));
} else if (drgn_type_kind(type) == DRGN_TYPE_POINTER) {
drgn_type* underlyingType = getPtrUnderlyingType(type);
if (chaseRawPointers &&
if (feature(Feature::ChaseRawPointers) &&
drgn_type_kind(underlyingType) != DRGN_TYPE_FUNCTION) {
// For pointers, figure out name for the underlying type then add
// appropriate number of '*'
@ -2278,7 +2272,7 @@ bool OICodeGen::generateStructDef(drgn_type* e, std::string& code) {
std::string structDefinition;
if (paddingInfo.paddingSize != 0 && genPaddingStats) {
if (paddingInfo.paddingSize != 0 && feature(Feature::GenPaddingStats)) {
structDefinition.append("/* offset | size */ ");
}
@ -2294,7 +2288,8 @@ bool OICodeGen::generateStructDef(drgn_type* e, std::string& code) {
std::to_string(*alignment / CHAR_BIT) + ")");
}
if (packStructs && (kind == DRGN_TYPE_STRUCT || kind == DRGN_TYPE_CLASS) &&
if (feature(Feature::PackStructs) &&
(kind == DRGN_TYPE_STRUCT || kind == DRGN_TYPE_CLASS) &&
violatesAlignmentRequirement && paddingInfo.paddingSize == 0) {
structDefinition.append(" __attribute__((__packed__))");
}
@ -2313,7 +2308,7 @@ bool OICodeGen::generateStructDef(drgn_type* e, std::string& code) {
structDefinition.append("};\n");
if (genPaddingStats) {
if (feature(Feature::GenPaddingStats)) {
auto paddedStructFound = paddedStructs.find(*tmpStr);
if (paddedStructFound == paddedStructs.end()) {
@ -2509,7 +2504,8 @@ std::optional<uint64_t> OICodeGen::generateMember(
currOffsetBits = 0;
VLOG(1) << "Member size: " << memberSize;
} else {
addSizeComment(genPaddingStats, code, currOffsetBits, memberSize);
addSizeComment(feature(Feature::GenPaddingStats), code, currOffsetBits,
memberSize);
currOffsetBits = currOffsetBits + memberSize;
}
@ -2709,12 +2705,12 @@ bool OICodeGen::generateStructMembers(
bool isThriftIssetStruct =
typeName.starts_with("isset_bitset<") && memberName == "__isset";
if (captureThriftIsset && isThriftIssetStruct &&
if (feature(Feature::CaptureThriftIsset) && isThriftIssetStruct &&
memberIndex == members.size() - 1) {
thriftIssetStructTypes.insert(e);
}
if (genPaddingStats) {
if (feature(Feature::GenPaddingStats)) {
paddingInfo.isThriftStruct = isThriftIssetStruct;
/*
@ -3258,12 +3254,12 @@ bool OICodeGen::generateJitCode(std::string& code) {
functionsCode.append("namespace OIInternal {\nnamespace {\n");
functionsCode.append("// functions -----\n");
if (!funcGen.DeclareGetSizeFuncs(functionsCode, containerTypesFuncDef,
chaseRawPointers)) {
feature(Feature::ChaseRawPointers))) {
LOG(ERROR) << "declaring get size for containers failed";
return false;
}
if (chaseRawPointers) {
if (feature(Feature::ChaseRawPointers)) {
functionsCode.append(R"(
template<typename T>
void getSizeType(const T* t, size_t& returnArg);
@ -3284,7 +3280,7 @@ bool OICodeGen::generateJitCode(std::string& code) {
}
}
if (config.useDataSegment || chaseRawPointers) {
if (config.useDataSegment || feature(Feature::ChaseRawPointers)) {
funcGen.DeclareStoreData(functionsCode);
}
@ -3296,12 +3292,12 @@ bool OICodeGen::generateJitCode(std::string& code) {
}
if (!funcGen.DefineGetSizeFuncs(functionsCode, containerTypesFuncDef,
chaseRawPointers)) {
feature(Feature::ChaseRawPointers))) {
LOG(ERROR) << "defining get size for containers failed";
return false;
}
if (chaseRawPointers) {
if (feature(Feature::ChaseRawPointers)) {
functionsCode.append(R"(
template<typename T>
void getSizeType(const T* s_ptr, size_t& returnArg)
@ -3780,7 +3776,7 @@ std::vector<std::string> OICodeGen::Config::toOptions() const {
options.reserve(allFeatures.size());
for (const auto f : allFeatures) {
if (features.contains(f)) {
if (features[f]) {
options.emplace_back(std::string("-f") + featureToStr(f));
} else {
options.emplace_back(std::string("-F") + featureToStr(f));

View File

@ -57,7 +57,7 @@ class OICodeGen {
*/
bool useDataSegment;
std::set<Feature> features{};
FeatureSet features{};
std::set<fs::path> containerConfigPaths{};
std::set<std::string> defaultHeaders{};
@ -113,12 +113,6 @@ class OICodeGen {
Config config{};
FuncGen funcGen;
bool chaseRawPointers;
bool packStructs;
bool genPaddingStats;
bool captureThriftIsset;
bool polymorphicInheritance;
using ContainerTypeMapEntry =
std::pair<std::reference_wrapper<const ContainerInfo>,
std::vector<drgn_qualified_type>>;
@ -185,6 +179,9 @@ class OICodeGen {
std::unique_ptr<char, FreeDeleter> _data;
};
bool feature(Feature f) const {
return config.features[f];
}
static void prependQualifiers(enum drgn_qualifiers, std::string& sb);
static std::string stripFullyQualifiedName(
const std::string& fullyQualifiedName);

View File

@ -2852,7 +2852,7 @@ bool OIDebugger::processTargetData() {
const auto& [rootType, typeHierarchy, paddingInfos] = typeInfo->second;
VLOG(1) << "Root type addr: " << (void*)rootType.type.type;
if (treeBuilderConfig.features.contains(Feature::GenPaddingStats)) {
if (treeBuilderConfig.features[Feature::GenPaddingStats]) {
paddingHunter.localPaddedStructs = paddingInfos;
typeTree.setPaddedStructs(&paddingHunter.localPaddedStructs);
}
@ -2876,7 +2876,7 @@ bool OIDebugger::processTargetData() {
continue;
}
if (treeBuilderConfig.features.contains(Feature::GenPaddingStats)) {
if (treeBuilderConfig.features[Feature::GenPaddingStats]) {
paddingHunter.processLocalPaddingInfo();
}
}
@ -2890,7 +2890,7 @@ bool OIDebugger::processTargetData() {
typeTree.dumpJson();
}
if (treeBuilderConfig.features.contains(Feature::GenPaddingStats)) {
if (treeBuilderConfig.features[Feature::GenPaddingStats]) {
paddingHunter.outputPaddingInfo();
}

View File

@ -31,7 +31,7 @@ namespace OIUtils {
using namespace ObjectIntrospection;
using namespace std::literals;
std::optional<std::set<Feature>> processConfigFile(
std::optional<ObjectIntrospection::FeatureSet> processConfigFile(
const std::string& configFilePath,
std::map<Feature, bool> featureMap,
OICompiler::Config& compilerConfig,
@ -153,10 +153,10 @@ std::optional<std::set<Feature>> processConfigFile(
}
}
std::set<Feature> featuresSet;
ObjectIntrospection::FeatureSet featuresSet;
for (auto [k, v] : featureMap) {
if (v) {
featuresSet.insert(k);
featuresSet[k] = true;
}
}
return featuresSet;

View File

@ -24,7 +24,7 @@
namespace OIUtils {
std::optional<std::set<Feature>> processConfigFile(
std::optional<ObjectIntrospection::FeatureSet> processConfigFile(
const std::string& configFilePath,
std::map<Feature, bool> featureMap,
OICompiler::Config& compilerConfig,

View File

@ -53,9 +53,6 @@ enum class TrackPointerTag : uint64_t {
TreeBuilder::TreeBuilder(Config c) : config{std::move(c)} {
buffer = std::make_unique<msgpack::sbuffer>();
chaseRawPointers = config.features.contains(Feature::ChaseRawPointers);
genPaddingStats = config.features.contains(Feature::GenPaddingStats);
auto testdbPath = "/tmp/testdb_" + std::to_string(getpid());
if (auto status = rocksdb::DestroyDB(testdbPath, {}); !status.ok()) {
LOG(FATAL) << "RocksDB error while destroying database: "
@ -429,7 +426,7 @@ TreeBuilder::Node TreeBuilder::process(NodeID id, Variable variable) {
if (!variable.isStubbed) {
switch (drgn_type_kind(variable.type)) {
case DRGN_TYPE_POINTER:
if (chaseRawPointers) {
if (config.features[Feature::ChaseRawPointers]) {
// Pointers to incomplete types are stubbed out
// See OICodeGen::enumeratePointerType
if (th->knownDummyTypeList.contains(variable.type)) {
@ -544,7 +541,7 @@ TreeBuilder::Node TreeBuilder::process(NodeID id, Variable variable) {
break;
}
if (genPaddingStats) {
if (config.features[Feature::GenPaddingStats]) {
auto entry = paddedStructs->find(node.typeName);
if (entry != paddedStructs->end()) {
entry->second.instancesCnt++;

View File

@ -41,7 +41,7 @@ class TreeBuilder {
struct Config {
// Don't set default values for the config so the user gets
// an "unitialized field" warning if he missed any.
std::set<ObjectIntrospection::Feature> features;
ObjectIntrospection::FeatureSet features;
bool logAllStructs;
bool dumpDataSegment;
std::optional<std::string> jsonPath;
@ -69,9 +69,6 @@ class TreeBuilder {
const std::vector<uint64_t>* oidData = nullptr;
std::map<std::string, PaddingInfo>* paddedStructs = nullptr;
bool genPaddingStats;
bool chaseRawPointers;
/*
* The RocksDB output needs versioning so they are imported correctly in
* Scuba. Version 1 had no concept of versioning and no header.

View File

@ -120,10 +120,8 @@ static std::ostream&
operator<<(std::ostream& out, TreeBuilder::Config tbc) {
out << "TreeBuilde::Config = [";
out << "\n logAllStructs = " << tbc.logAllStructs;
out << "\n chaseRawPointers = "
<< tbc.features.contains(Feature::ChaseRawPointers);
out << "\n genPaddingStats = "
<< tbc.features.contains(Feature::GenPaddingStats);
out << "\n chaseRawPointers = " << tbc.features[Feature::ChaseRawPointers];
out << "\n genPaddingStats = " << tbc.features[Feature::GenPaddingStats];
out << "\n dumpDataSegment = " << tbc.dumpDataSegment;
out << "\n jsonPath = " << (tbc.jsonPath ? *tbc.jsonPath : "NONE");
out << "\n]\n";
@ -157,10 +155,10 @@ int main(int argc, char* argv[]) {
true; // Weird that we're setting it to true, again...
break;
case 'n':
tbConfig.features.insert(Feature::ChaseRawPointers);
tbConfig.features[Feature::ChaseRawPointers] = true;
break;
case 'w':
tbConfig.features.erase(Feature::GenPaddingStats);
tbConfig.features[Feature::GenPaddingStats] = false;
break;
case 'J':
tbConfig.jsonPath = optarg ? optarg : "oid_out.json";
@ -189,7 +187,7 @@ int main(int argc, char* argv[]) {
TreeBuilder typeTree(tbConfig);
if (tbConfig.features.contains(Feature::GenPaddingStats)) {
if (tbConfig.features[Feature::GenPaddingStats]) {
LOG(INFO) << "Setting-up PaddingHunter...";
typeTree.setPaddedStructs(&paddingInfos);
}