aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-28 21:12:31 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-02-28 21:12:31 +0000
commit4d05b61640a3668740029b6b660c136975690ca3 (patch)
tree816a39318cf25a492bac3026fab8d5ad5d2a9ea5
parentc83ae6994732498fd9161cc8f009dbf64f4bde37 (diff)
parenteb4bb7c513362eea24833fd9989ef6b7c6dccd98 (diff)
downloadstg-simpleperf-release.tar.gz
Snap for 11510257 from eb4bb7c513362eea24833fd9989ef6b7c6dccd98 to simpleperf-releasesimpleperf-release
Change-Id: I797e552e747b1f1708d278793755eddcb245950d
-rw-r--r--Android.bp4
-rw-r--r--CMakeLists.txt4
-rw-r--r--abigail_reader.cc45
-rw-r--r--abigail_reader.h6
-rw-r--r--abigail_reader_test.cc18
-rw-r--r--btf_reader.cc2
-rw-r--r--comparison.cc22
-rw-r--r--comparison.h22
-rw-r--r--deduplication.cc36
-rw-r--r--deduplication.h4
-rw-r--r--dwarf_processor.cc115
-rw-r--r--elf_reader.cc32
-rw-r--r--elf_reader.h10
-rw-r--r--equality.h2
-rw-r--r--equality_cache.h46
-rw-r--r--error.h2
-rw-r--r--fingerprint.cc20
-rw-r--r--fingerprint.h4
-rw-r--r--fuzz/elf_reader_fuzzer.cc12
-rw-r--r--input.cc27
-rw-r--r--input.h7
-rw-r--r--naming.cc22
-rw-r--r--naming.h4
-rw-r--r--proto_writer.cc3
-rw-r--r--runtime.cc (renamed from metrics.cc)49
-rw-r--r--runtime.h (renamed from metrics.h)63
-rw-r--r--runtime_test.cc (renamed from metrics_test.cc)86
-rw-r--r--stg.cc31
-rw-r--r--stg.proto2
-rw-r--r--stgdiff.cc54
-rw-r--r--stgdiff_test.cc37
-rw-r--r--substitution.h4
-rw-r--r--test_cases/info_tests/template/expected/template_parameter_cc.elf_stg210
-rw-r--r--test_cases/info_tests/template/expected/value_parameter_cc.elf_stg231
-rw-r--r--test_cases/info_tests/template/template_parameter.cc37
-rw-r--r--test_cases/info_tests/template/value_parameter.cc41
-rw-r--r--testdata/abigail_duplicate_types_9.xml28
-rw-r--r--type_normalisation.cc4
-rw-r--r--type_resolution.cc30
-rw-r--r--type_resolution.h6
-rw-r--r--unification.h22
41 files changed, 980 insertions, 424 deletions
diff --git a/Android.bp b/Android.bp
index 24fe287..1d0a4e3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -61,6 +61,8 @@ cc_defaults {
enabled: false,
},
},
+ // TODO(b/324274771): figure out a better solution
+ native_coverage: false,
}
cc_library_host_static {
@@ -81,12 +83,12 @@ cc_library_host_static {
"fingerprint.cc",
"graph.cc",
"input.cc",
- "metrics.cc",
"naming.cc",
"post_processing.cc",
"proto_reader.cc",
"proto_writer.cc",
"reporting.cc",
+ "runtime.cc",
"stable_hash.cc",
"stg.proto",
"type_normalisation.cc",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index bb112da..9587c6a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -92,12 +92,12 @@ add_library(libstg OBJECT
fingerprint.cc
graph.cc
input.cc
- metrics.cc
naming.cc
post_processing.cc
proto_reader.cc
proto_writer.cc
reporting.cc
+ runtime.cc
stable_hash.cc
type_normalisation.cc
type_resolution.cc
@@ -139,9 +139,9 @@ else()
error_test
file_descriptor_test
filter_test
- metrics_test
order_test
reporting_test
+ runtime_test
scc_test
stgdiff_test
)
diff --git a/abigail_reader.cc b/abigail_reader.cc
index 2682c49..f1deff3 100644
--- a/abigail_reader.cc
+++ b/abigail_reader.cc
@@ -28,7 +28,6 @@
#include <cstddef>
#include <cstdint>
#include <functional>
-#include <iomanip>
#include <ios>
#include <map>
#include <memory>
@@ -47,7 +46,7 @@
#include "error.h"
#include "file_descriptor.h"
#include "graph.h"
-#include "metrics.h"
+#include "runtime.h"
#include "scope.h"
#include "type_normalisation.h"
@@ -88,7 +87,7 @@ xmlNodePtr Next(xmlNodePtr node) {
}
xmlNodePtr GetOnlyChild(xmlNodePtr element) {
- xmlNodePtr child = Child(element);
+ const xmlNodePtr child = Child(element);
if (child == nullptr || Next(child) != nullptr) {
Die() << "element '" << GetName(element) << "' without exactly one child";
}
@@ -119,7 +118,7 @@ std::string GetAttributeOrDie(xmlNodePtr node, const char* name) {
}
// Set an attribute value.
-void SetAttribute(xmlNodePtr node, const char* name, const std::string &value) {
+void SetAttribute(xmlNodePtr node, const char* name, const std::string& value) {
xmlSetProp(node, ToLibxml(name), ToLibxml(value.c_str()));
}
@@ -275,7 +274,7 @@ void StripNonElements(xmlNodePtr node) {
case XML_ELEMENT_NODE: {
xmlNodePtr child = Child(node);
while (child) {
- xmlNodePtr next = Next(child);
+ const xmlNodePtr next = Next(child);
StripNonElements(child);
child = next;
}
@@ -1148,7 +1147,8 @@ void Abigail::ProcessStructUnion(Id id, bool is_struct,
}
void Abigail::ProcessEnum(Id id, xmlNodePtr enumeration) {
- bool forward = ReadAttribute<bool>(enumeration, "is-declaration-only", false);
+ const bool forward =
+ ReadAttribute<bool>(enumeration, "is-declaration-only", false);
const auto name = ReadAttribute<bool>(enumeration, "is-anonymous", false)
? std::string()
: scope_name_ + GetAttributeOrDie(enumeration, "name");
@@ -1157,8 +1157,8 @@ void Abigail::ProcessEnum(Id id, xmlNodePtr enumeration) {
return;
}
- xmlNodePtr underlying = Child(enumeration);
- Check(underlying) << "enum-decl has no child elements";
+ const xmlNodePtr underlying = Child(enumeration);
+ Check(underlying != nullptr) << "enum-decl has no child elements";
CheckName("underlying-type", underlying);
const auto type = GetEdge(underlying);
@@ -1188,16 +1188,17 @@ Id Abigail::ProcessBaseClass(xmlNodePtr base_class) {
std::optional<Id> Abigail::ProcessDataMember(bool is_struct,
xmlNodePtr data_member) {
- xmlNodePtr decl = GetOnlyChild(data_member);
+ const xmlNodePtr decl = GetOnlyChild(data_member);
CheckName("var-decl", decl);
if (ReadAttribute<bool>(data_member, "static", false)) {
ProcessDecl(true, decl);
return {};
}
- size_t offset = is_struct
- ? ReadAttributeOrDie<size_t>(data_member, "layout-offset-in-bits")
- : 0;
+ const auto offset = is_struct
+ ? ReadAttributeOrDie<size_t>(data_member,
+ "layout-offset-in-bits")
+ : 0;
const auto name = GetAttributeOrDie(decl, "name");
const auto type = GetEdge(decl);
@@ -1207,7 +1208,7 @@ std::optional<Id> Abigail::ProcessDataMember(bool is_struct,
void Abigail::ProcessMemberFunction(std::vector<Id>& methods,
xmlNodePtr method) {
- xmlNodePtr decl = GetOnlyChild(method);
+ const xmlNodePtr decl = GetOnlyChild(method);
CheckName("function-decl", decl);
// ProcessDecl creates symbol references so must be called unconditionally.
const auto type = ProcessDecl(false, decl);
@@ -1222,7 +1223,7 @@ void Abigail::ProcessMemberFunction(std::vector<Id>& methods,
}
void Abigail::ProcessMemberType(xmlNodePtr member_type) {
- xmlNodePtr decl = GetOnlyChild(member_type);
+ const xmlNodePtr decl = GetOnlyChild(member_type);
const auto type_id = GetAttributeOrDie(decl, "id");
const auto id = GetNode(type_id);
if (graph_.Is(id)) {
@@ -1284,15 +1285,15 @@ Id Abigail::BuildSymbols() {
return graph_.Add<Interface>(symbols);
}
-Document Read(const std::string& path, Metrics& metrics) {
+Document Read(Runtime& runtime, const std::string& path) {
// Open input for reading.
- FileDescriptor fd(path.c_str(), O_RDONLY);
+ const FileDescriptor fd(path.c_str(), O_RDONLY);
// Read the XML.
Document document(nullptr, xmlFreeDoc);
{
- Time t(metrics, "abigail.libxml_parse");
- std::unique_ptr<
+ const Time t(runtime, "abigail.libxml_parse");
+ const std::unique_ptr<
std::remove_pointer_t<xmlParserCtxtPtr>, void(*)(xmlParserCtxtPtr)>
context(xmlNewParserCtxt(), xmlFreeParserCtxt);
document.reset(
@@ -1304,10 +1305,10 @@ Document Read(const std::string& path, Metrics& metrics) {
return document;
}
-Id Read(Graph& graph, const std::string& path, Metrics& metrics) {
- const Document document = Read(path, metrics);
- xmlNodePtr root = xmlDocGetRootElement(document.get());
- Check(root) << "XML document has no root element";
+Id Read(Runtime& runtime, Graph& graph, const std::string& path) {
+ const Document document = Read(runtime, path);
+ const xmlNodePtr root = xmlDocGetRootElement(document.get());
+ Check(root != nullptr) << "XML document has no root element";
return Abigail(graph).ProcessRoot(root);
}
diff --git a/abigail_reader.h b/abigail_reader.h
index 21ada8d..3123f93 100644
--- a/abigail_reader.h
+++ b/abigail_reader.h
@@ -32,7 +32,7 @@
#include <libxml/tree.h>
#include "graph.h"
-#include "metrics.h"
+#include "runtime.h"
#include "scope.h"
namespace stg {
@@ -146,7 +146,7 @@ class Abigail {
Id BuildSymbols();
};
-Id Read(Graph& graph, const std::string& path, Metrics& metrics);
+Id Read(Runtime& runtime, Graph& graph, const std::string& path);
// Exposed for testing.
void Clean(xmlNodePtr root);
@@ -154,7 +154,7 @@ bool EqualTree(xmlNodePtr left, xmlNodePtr right);
bool SubTree(xmlNodePtr left, xmlNodePtr right);
using Document =
std::unique_ptr<std::remove_pointer_t<xmlDocPtr>, void(*)(xmlDocPtr)>;
-Document Read(const std::string& path, Metrics& metrics);
+Document Read(Runtime& runtime, const std::string& path);
} // namespace abixml
} // namespace stg
diff --git a/abigail_reader_test.cc b/abigail_reader_test.cc
index 2396b77..25c5121 100644
--- a/abigail_reader_test.cc
+++ b/abigail_reader_test.cc
@@ -28,9 +28,9 @@
#include <catch2/catch.hpp>
#include "abigail_reader.h"
-#include "graph.h"
-#include "metrics.h"
#include "equality.h"
+#include "graph.h"
+#include "runtime.h"
namespace {
@@ -39,13 +39,13 @@ std::filesystem::path filename_to_path(const char* f) {
}
stg::abixml::Document Read(const char* input) {
- stg::Metrics metrics;
- return stg::abixml::Read(filename_to_path(input), metrics);
+ stg::Runtime runtime(std::cerr, false);
+ return stg::abixml::Read(runtime, filename_to_path(input));
}
stg::Id Read(stg::Graph& graph, const char* input) {
- stg::Metrics metrics;
- return stg::abixml::Read(graph, filename_to_path(input), metrics);
+ stg::Runtime runtime(std::cerr, false);
+ return stg::abixml::Read(runtime, graph, filename_to_path(input));
}
struct EqualTreeTestCase {
@@ -199,7 +199,11 @@ TEST_CASE("Tidy") {
TidyTestCase(
{"duplicate type resolution - stray anonymous member",
{"abigail_duplicate_types_7.xml",
- "abigail_duplicate_types_8.xml"}}));
+ "abigail_duplicate_types_8.xml"}}),
+ TidyTestCase(
+ {"corpus group handling",
+ {"abigail_duplicate_types_0.xml",
+ "abigail_duplicate_types_9.xml"}}));
SECTION(test.name) {
// Read inputs.
diff --git a/btf_reader.cc b/btf_reader.cc
index a228e31..75ec360 100644
--- a/btf_reader.cc
+++ b/btf_reader.cc
@@ -41,8 +41,8 @@
#include <linux/btf.h>
#include "elf_loader.h"
#include "error.h"
-#include "graph.h"
#include "file_descriptor.h"
+#include "graph.h"
#include "reader_options.h"
namespace stg {
diff --git a/comparison.cc b/comparison.cc
index 0115d05..ca821f9 100644
--- a/comparison.cc
+++ b/comparison.cc
@@ -428,6 +428,13 @@ Result Compare::operator()(const BaseClass& x1, const BaseClass& x2) {
return result;
}
+Result Compare::operator()(const Method& x1, const Method& x2) {
+ Result result;
+ result.MaybeAddNodeDiff("vtable offset", x1.vtable_offset, x2.vtable_offset);
+ result.MaybeAddEdgeDiff("", (*this)(x1.type_id, x2.type_id));
+ return result;
+}
+
Result Compare::operator()(const Member& x1, const Member& x2) {
Result result;
result.MaybeAddNodeDiff("offset", x1.offset, x2.offset);
@@ -447,13 +454,6 @@ Result Compare::operator()(const Member& x1, const Member& x2) {
return result;
}
-Result Compare::operator()(const Method& x1, const Method& x2) {
- Result result;
- result.MaybeAddNodeDiff("vtable offset", x1.vtable_offset, x2.vtable_offset);
- result.MaybeAddEdgeDiff("", (*this)(x1.type_id, x2.type_id));
- return result;
-}
-
Result Compare::operator()(const StructUnion& x1, const StructUnion& x2) {
Result result;
// Compare two anonymous types recursively, not holding diffs.
@@ -740,6 +740,10 @@ std::string MatchingKey::operator()(const BaseClass& x) {
return (*this)(x.type_id);
}
+std::string MatchingKey::operator()(const Method& x) {
+ return x.name + ',' + x.mangled_name;
+}
+
std::string MatchingKey::operator()(const Member& x) {
if (!x.name.empty()) {
return x.name;
@@ -747,10 +751,6 @@ std::string MatchingKey::operator()(const Member& x) {
return (*this)(x.type_id);
}
-std::string MatchingKey::operator()(const Method& x) {
- return x.name + ',' + x.mangled_name;
-}
-
std::string MatchingKey::operator()(const StructUnion& x) {
if (!x.name.empty()) {
return x.name;
diff --git a/comparison.h b/comparison.h
index de2c562..693c55a 100644
--- a/comparison.h
+++ b/comparison.h
@@ -38,7 +38,7 @@
#include <vector>
#include "graph.h"
-#include "metrics.h"
+#include "runtime.h"
#include "scc.h"
namespace stg {
@@ -212,8 +212,8 @@ struct MatchingKey {
explicit MatchingKey(const Graph& graph) : graph(graph) {}
std::string operator()(Id id);
std::string operator()(const BaseClass&);
- std::string operator()(const Member&);
std::string operator()(const Method&);
+ std::string operator()(const Member&);
std::string operator()(const StructUnion&);
template <typename Node>
std::string operator()(const Node&);
@@ -258,15 +258,15 @@ struct ResolveQualifier {
};
struct Compare {
- Compare(const Graph& graph, const Ignore& ignore, Metrics& metrics)
+ Compare(Runtime& runtime, const Graph& graph, const Ignore& ignore)
: graph(graph), ignore(ignore),
- queried(metrics, "compare.queried"),
- already_compared(metrics, "compare.already_compared"),
- being_compared(metrics, "compare.being_compared"),
- really_compared(metrics, "compare.really_compared"),
- equivalent(metrics, "compare.equivalent"),
- inequivalent(metrics, "compare.inequivalent"),
- scc_size(metrics, "compare.scc_size") {}
+ queried(runtime, "compare.queried"),
+ already_compared(runtime, "compare.already_compared"),
+ being_compared(runtime, "compare.being_compared"),
+ really_compared(runtime, "compare.really_compared"),
+ equivalent(runtime, "compare.equivalent"),
+ inequivalent(runtime, "compare.inequivalent"),
+ scc_size(runtime, "compare.scc_size") {}
std::pair<bool, std::optional<Comparison>> operator()(Id id1, Id id2);
Comparison Removed(Id id);
@@ -282,8 +282,8 @@ struct Compare {
Result operator()(const Primitive&, const Primitive&);
Result operator()(const Array&, const Array&);
Result operator()(const BaseClass&, const BaseClass&);
- Result operator()(const Member&, const Member&);
Result operator()(const Method&, const Method&);
+ Result operator()(const Member&, const Member&);
Result operator()(const StructUnion&, const StructUnion&);
Result operator()(const Enumeration&, const Enumeration&);
Result operator()(const Function&, const Function&);
diff --git a/deduplication.cc b/deduplication.cc
index a3b1f9d..b71c599 100644
--- a/deduplication.cc
+++ b/deduplication.cc
@@ -21,31 +21,33 @@
#include <cstddef>
#include <unordered_map>
+#include <utility>
#include <vector>
#include "equality.h"
#include "equality_cache.h"
#include "graph.h"
-#include "metrics.h"
+#include "hashing.h"
+#include "runtime.h"
#include "substitution.h"
namespace stg {
-Id Deduplicate(Graph& graph, Id root, const Hashes& hashes, Metrics& metrics) {
+Id Deduplicate(Runtime& runtime, Graph& graph, Id root, const Hashes& hashes) {
// Partition the nodes by hash.
std::unordered_map<HashValue, std::vector<Id>> partitions;
{
- Time x(metrics, "partition nodes");
+ const Time x(runtime, "partition nodes");
for (const auto& [id, fp] : hashes) {
partitions[fp].push_back(id);
}
}
- Counter(metrics, "deduplicate.nodes") = hashes.size();
- Counter(metrics, "deduplicate.hashes") = partitions.size();
+ Counter(runtime, "deduplicate.nodes") = hashes.size();
+ Counter(runtime, "deduplicate.hashes") = partitions.size();
- Histogram hash_partition_size(metrics, "deduplicate.hash_partition_size");
- Counter min_comparisons(metrics, "deduplicate.min_comparisons");
- Counter max_comparisons(metrics, "deduplicate.max_comparisons");
+ Histogram hash_partition_size(runtime, "deduplicate.hash_partition_size");
+ Counter min_comparisons(runtime, "deduplicate.min_comparisons");
+ Counter max_comparisons(runtime, "deduplicate.max_comparisons");
for (const auto& [fp, ids] : partitions) {
const auto n = ids.size();
hash_partition_size.Add(n);
@@ -54,16 +56,16 @@ Id Deduplicate(Graph& graph, Id root, const Hashes& hashes, Metrics& metrics) {
}
// Refine partitions of nodes with the same fingerprints.
- EqualityCache cache(hashes, metrics);
+ EqualityCache cache(runtime, hashes);
Equals<EqualityCache> equals(graph, cache);
- Counter equalities(metrics, "deduplicate.equalities");
- Counter inequalities(metrics, "deduplicate.inequalities");
+ Counter equalities(runtime, "deduplicate.equalities");
+ Counter inequalities(runtime, "deduplicate.inequalities");
{
- Time x(metrics, "find duplicates");
+ const Time x(runtime, "find duplicates");
for (auto& [fp, ids] : partitions) {
while (ids.size() > 1) {
std::vector<Id> todo;
- Id candidate = ids[0];
+ const Id candidate = ids[0];
for (size_t i = 1; i < ids.size(); ++i) {
if (equals(ids[i], candidate)) {
++equalities;
@@ -78,8 +80,8 @@ Id Deduplicate(Graph& graph, Id root, const Hashes& hashes, Metrics& metrics) {
}
// Keep one representative of each set of duplicates.
- Counter unique(metrics, "deduplicate.unique");
- Counter duplicate(metrics, "deduplicate.duplicate");
+ Counter unique(runtime, "deduplicate.unique");
+ Counter duplicate(runtime, "deduplicate.duplicate");
auto remap = [&cache](Id& id) {
// update id to representative id, avoiding silent stores
const Id fid = cache.Find(id);
@@ -89,9 +91,9 @@ Id Deduplicate(Graph& graph, Id root, const Hashes& hashes, Metrics& metrics) {
};
Substitute substitute(graph, remap);
{
- Time x(metrics, "rewrite");
+ const Time x(runtime, "rewrite");
for (const auto& [id, fp] : hashes) {
- Id fid = cache.Find(id);
+ const Id fid = cache.Find(id);
if (fid != id) {
graph.Remove(id);
++duplicate;
diff --git a/deduplication.h b/deduplication.h
index 73e0dea..adb8c89 100644
--- a/deduplication.h
+++ b/deduplication.h
@@ -25,13 +25,13 @@
#include "graph.h"
#include "hashing.h"
-#include "metrics.h"
+#include "runtime.h"
namespace stg {
using Hashes = std::unordered_map<Id, HashValue>;
-Id Deduplicate(Graph& graph, Id root, const Hashes& hashes, Metrics& metrics);
+Id Deduplicate(Runtime& runtime, Graph& graph, Id root, const Hashes& hashes);
} // namespace stg
diff --git a/dwarf_processor.cc b/dwarf_processor.cc
index 48d6e26..99278d8 100644
--- a/dwarf_processor.cc
+++ b/dwarf_processor.cc
@@ -96,7 +96,7 @@ size_t GetByteSize(Entry& entry) {
}
Primitive::Encoding GetEncoding(Entry& entry) {
- auto dwarf_encoding = entry.MaybeGetUnsignedConstant(DW_AT_encoding);
+ const auto dwarf_encoding = entry.MaybeGetUnsignedConstant(DW_AT_encoding);
if (!dwarf_encoding) {
Die() << "Encoding was not found for " << EntryToString(entry);
}
@@ -313,7 +313,7 @@ class Processor {
void ProcessInternal(Entry& entry) {
++result_.processed_entries;
- auto tag = entry.GetTag();
+ const auto tag = entry.GetTag();
switch (tag) {
case DW_TAG_array_type:
ProcessArray(entry);
@@ -414,7 +414,7 @@ class Processor {
}
void ProcessNamespace(Entry& entry) {
- auto name = GetNameOrEmpty(entry);
+ const auto name = GetNameOrEmpty(entry);
const PushScopeName push_scope_name(scope_, "namespace", name);
ProcessAllChildren(entry);
}
@@ -432,9 +432,10 @@ class Processor {
}
void ProcessTypedef(Entry& entry) {
- const std::string type_name = scope_ + GetName(entry);
- auto referred_type_id = GetIdForReferredType(MaybeGetReferredType(entry));
- const Id id = AddProcessedNode<Typedef>(entry, type_name, referred_type_id);
+ const auto type_name = GetName(entry);
+ const auto full_name = scope_ + type_name;
+ const Id referred_type_id = GetReferredTypeId(MaybeGetReferredType(entry));
+ const Id id = AddProcessedNode<Typedef>(entry, full_name, referred_type_id);
if (!ShouldKeepDefinition(entry, type_name)) {
// We always model (and keep) typedef definitions. But we should exclude
// filtered out types from being type roots.
@@ -445,15 +446,14 @@ class Processor {
template<typename Node, typename KindType>
void ProcessReference(Entry& entry, KindType kind) {
- auto referred_type_id = GetIdForReferredType(MaybeGetReferredType(entry));
+ const Id referred_type_id = GetReferredTypeId(MaybeGetReferredType(entry));
AddProcessedNode<Node>(entry, kind, referred_type_id);
}
void ProcessPointerToMember(Entry& entry) {
const Id containing_type_id =
- GetIdForReferredType(entry.MaybeGetReference(DW_AT_containing_type));
- const Id pointee_type_id =
- GetIdForReferredType(MaybeGetReferredType(entry));
+ GetReferredTypeId(entry.MaybeGetReference(DW_AT_containing_type));
+ const Id pointee_type_id = GetReferredTypeId(MaybeGetReferredType(entry));
AddProcessedNode<PointerToMember>(entry, containing_type_id,
pointee_type_id);
}
@@ -477,16 +477,16 @@ class Processor {
if (name.substr(0, kBuiltinPrefix.size()) == kBuiltinPrefix) {
return true;
}
- Die() << "File filter is provided, but DWARF entry << "
- << EntryToString(entry) << " << doesn't have DW_AT_decl_file";
+ Die() << "File filter is provided, but " << name << " ("
+ << EntryToString(entry) << ") doesn't have DW_AT_decl_file";
}
return (*file_filter_)(*file);
}
void ProcessStructUnion(Entry& entry, StructUnion::Kind kind) {
- std::string name = GetNameOrEmpty(entry);
- const std::string full_name = name.empty() ? std::string() : scope_ + name;
- const PushScopeName push_scope_name(scope_, kind, name);
+ const auto type_name = GetNameOrEmpty(entry);
+ const auto full_name = type_name.empty() ? type_name : scope_ + type_name;
+ const PushScopeName push_scope_name(scope_, kind, type_name);
std::vector<Id> base_classes;
std::vector<Id> members;
@@ -544,6 +544,9 @@ class Processor {
// We just skip these as neither GCC nor Clang seem to use them
// properly (resulting in no references to such DIEs).
break;
+ case DW_TAG_variant_part:
+ // TODO: Add a DWARF processor to process variants.
+ break;
default:
Die() << "Unexpected tag for child of struct/class/union: "
<< Hex(child_tag) << ", " << EntryToString(child);
@@ -551,7 +554,7 @@ class Processor {
}
if (entry.GetFlag(DW_AT_declaration) ||
- !ShouldKeepDefinition(entry, name)) {
+ !ShouldKeepDefinition(entry, type_name)) {
// Declaration may have partial information about members or method.
// We only need to parse children for information that will be needed in
// complete definition, but don't need to store them in incomplete node.
@@ -570,9 +573,9 @@ class Processor {
}
void ProcessMember(Entry& entry) {
- std::string name = GetNameOrEmpty(entry);
+ const auto name = GetNameOrEmpty(entry);
auto referred_type = GetReferredType(entry);
- auto referred_type_id = GetIdForEntry(referred_type);
+ const Id referred_type_id = GetIdForEntry(referred_type);
auto optional_bit_size = entry.MaybeGetUnsignedConstant(DW_AT_bit_size);
// Member has DW_AT_bit_size if and only if it is bit field.
// STG uses bit_size == 0 to mark that the member is not a bit field.
@@ -618,7 +621,7 @@ class Processor {
}
void ProcessBaseClass(Entry& entry) {
- const auto type_id = GetIdForReferredType(GetReferredType(entry));
+ const Id type_id = GetReferredTypeId(GetReferredType(entry));
const auto byte_offset = entry.MaybeGetMemberByteOffset();
if (!byte_offset) {
Die() << "No offset found for base class " << EntryToString(entry);
@@ -639,7 +642,7 @@ class Processor {
void ProcessArray(Entry& entry) {
auto referred_type = GetReferredType(entry);
- auto referred_type_id = GetIdForEntry(referred_type);
+ Id referred_type_id = GetIdForEntry(referred_type);
auto children = entry.GetChildren();
// Multiple children in array describe multiple dimensions of this array.
// For example, int[M][N] contains two children, M located in the first
@@ -663,43 +666,57 @@ class Processor {
}
void ProcessEnum(Entry& entry) {
- const std::optional<std::string> name_optional = MaybeGetName(entry);
- const std::string name =
- name_optional.has_value() ? scope_ + *name_optional : "";
+ const auto type_name = GetNameOrEmpty(entry);
+ const auto full_name = type_name.empty() ? type_name : scope_ + type_name;
if (entry.GetFlag(DW_AT_declaration)) {
// It is expected to have only name and no children in declaration.
// However, it is not guaranteed and we should do something if we find an
// example.
CheckNoChildren(entry);
- AddProcessedNode<Enumeration>(entry, name);
+ AddProcessedNode<Enumeration>(entry, full_name);
return;
}
- auto underlying_type_id = GetIdForReferredType(MaybeGetReferredType(entry));
+ const Id underlying_type_id =
+ GetReferredTypeId(MaybeGetReferredType(entry));
auto children = entry.GetChildren();
Enumeration::Enumerators enumerators;
enumerators.reserve(children.size());
for (auto& child : children) {
- Check(child.GetTag() == DW_TAG_enumerator)
- << "Enum expects child of DW_TAG_enumerator";
- std::string enumerator_name = GetName(child);
- // TODO: detect signedness of underlying type and call
- // an appropriate method.
- std::optional<size_t> value_optional =
- child.MaybeGetUnsignedConstant(DW_AT_const_value);
- Check(value_optional.has_value()) << "Enumerator should have value";
- // TODO: support both uint64_t and int64_t, depending on
- // signedness of underlying type.
- enumerators.emplace_back(enumerator_name,
- static_cast<int64_t>(*value_optional));
- }
- if (!ShouldKeepDefinition(entry, name)) {
- AddProcessedNode<Enumeration>(entry, name);
+ auto child_tag = child.GetTag();
+ switch (child_tag) {
+ case DW_TAG_enumerator: {
+ const std::string enumerator_name = GetName(child);
+ // TODO: detect signedness of underlying type and call
+ // an appropriate method.
+ std::optional<size_t> value_optional =
+ child.MaybeGetUnsignedConstant(DW_AT_const_value);
+ Check(value_optional.has_value()) << "Enumerator should have value";
+ // TODO: support both uint64_t and int64_t, depending on
+ // signedness of underlying type.
+ enumerators.emplace_back(enumerator_name,
+ static_cast<int64_t>(*value_optional));
+ break;
+ }
+ case DW_TAG_subprogram:
+ // STG does not support virtual methods for enums.
+ Check(child.MaybeGetUnsignedConstant(DW_AT_virtuality)
+ .value_or(DW_VIRTUALITY_none) == DW_VIRTUALITY_none)
+ << "Enums can not have virtual methods: " << EntryToString(child);
+ ProcessFunction(child);
+ break;
+ default:
+ Die() << "Unexpected tag for child of enum: " << Hex(child_tag)
+ << ", " << EntryToString(child);
+ }
+ }
+ if (!ShouldKeepDefinition(entry, type_name)) {
+ AddProcessedNode<Enumeration>(entry, full_name);
return;
}
- const Id id = AddProcessedNode<Enumeration>(entry, name, underlying_type_id,
- std::move(enumerators));
- if (!name.empty()) {
+ const Id id = AddProcessedNode<Enumeration>(
+ entry, full_name, underlying_type_id, std::move(enumerators));
+ if (!full_name.empty()) {
AddNamedTypeNode(id);
}
}
@@ -787,7 +804,7 @@ class Processor {
auto name_with_context = GetNameWithContext(entry);
auto referred_type = GetReferredType(entry);
- auto referred_type_id = GetIdForEntry(referred_type);
+ const Id referred_type_id = GetIdForEntry(referred_type);
if (auto address = entry.MaybeGetAddress(DW_AT_location)) {
// Only external variables with address are useful for ABI monitoring
@@ -824,14 +841,14 @@ class Processor {
};
Subprogram GetSubprogram(Entry& entry) {
- auto return_type_id = GetIdForReferredType(MaybeGetReferredType(entry));
+ const Id return_type_id = GetReferredTypeId(MaybeGetReferredType(entry));
std::vector<Id> parameters;
for (auto& child : entry.GetChildren()) {
auto child_tag = child.GetTag();
switch (child_tag) {
case DW_TAG_formal_parameter:
- parameters.push_back(GetIdForReferredType(GetReferredType(child)));
+ parameters.push_back(GetReferredTypeId(GetReferredType(child)));
break;
case DW_TAG_unspecified_parameters:
// Note: C++ allows a single ... argument specification but C does
@@ -908,19 +925,19 @@ class Processor {
// Same as GetIdForEntry, but returns "void_id_" for "unspecified" references,
// because it is normal for DWARF (5.2 Unspecified Type Entries).
- Id GetIdForReferredType(std::optional<Entry> referred_type) {
+ Id GetReferredTypeId(std::optional<Entry> referred_type) {
return referred_type ? GetIdForEntry(*referred_type) : void_id_;
}
// Wrapper for GetIdForEntry to allow lvalues.
- Id GetIdForReferredType(Entry referred_type) {
+ Id GetReferredTypeId(Entry referred_type) {
return GetIdForEntry(referred_type);
}
// Populate Id from method above with processed Node.
template <typename Node, typename... Args>
Id AddProcessedNode(Entry& entry, Args&&... args) {
- auto id = GetIdForEntry(entry);
+ const Id id = GetIdForEntry(entry);
graph_.Set<Node>(id, std::forward<Args>(args)...);
return id;
}
diff --git a/elf_reader.cc b/elf_reader.cc
index 2913007..31d39cb 100644
--- a/elf_reader.cc
+++ b/elf_reader.cc
@@ -35,8 +35,8 @@
#include "error.h"
#include "filter.h"
#include "graph.h"
-#include "metrics.h"
#include "reader_options.h"
+#include "runtime.h"
#include "type_normalisation.h"
#include "type_resolution.h"
#include "unification.h"
@@ -191,23 +191,23 @@ namespace {
class Reader {
public:
- Reader(Graph& graph, const std::string& path, ReadOptions options,
- const std::unique_ptr<Filter>& file_filter, Metrics& metrics)
+ Reader(Runtime& runtime, Graph& graph, const std::string& path,
+ ReadOptions options, const std::unique_ptr<Filter>& file_filter)
: graph_(graph),
dwarf_(path),
elf_(dwarf_.GetElf()),
options_(options),
file_filter_(file_filter),
- metrics_(metrics) {}
+ runtime_(runtime) {}
- Reader(Graph& graph, char* data, size_t size, ReadOptions options,
- const std::unique_ptr<Filter>& file_filter, Metrics& metrics)
+ Reader(Runtime& runtime, Graph& graph, char* data, size_t size,
+ ReadOptions options, const std::unique_ptr<Filter>& file_filter)
: graph_(graph),
dwarf_(data, size),
elf_(dwarf_.GetElf()),
options_(options),
file_filter_(file_filter),
- metrics_(metrics) {}
+ runtime_(runtime) {}
Id Read();
@@ -223,7 +223,7 @@ class Reader {
// the nodes in consideration to the ones allocated by the DWARF processor
// here and any symbol or type roots that follow. This is done by setting
// the starting node ID to be the current graph limit.
- Unification unification(graph_, graph_.Limit(), metrics_);
+ Unification unification(runtime_, graph_, graph_.Limit());
const dwarf::Types types = dwarf::Process(
dwarf_, elf_.IsLittleEndianBinary(), file_filter_, graph_);
@@ -289,7 +289,7 @@ class Reader {
}
roots.push_back(root);
- stg::ResolveTypes(graph_, unification, {roots}, metrics_);
+ stg::ResolveTypes(runtime_, graph_, unification, {roots});
unification.Update(root);
return root;
@@ -392,7 +392,7 @@ class Reader {
elf::ElfLoader elf_;
ReadOptions options_;
const std::unique_ptr<Filter>& file_filter_;
- Metrics& metrics_;
+ Runtime& runtime_;
};
Id Reader::Read() {
@@ -437,14 +437,14 @@ Id Reader::Read() {
} // namespace
} // namespace internal
-Id Read(Graph& graph, const std::string& path, ReadOptions options,
- const std::unique_ptr<Filter>& file_filter, Metrics& metrics) {
- return internal::Reader(graph, path, options, file_filter, metrics).Read();
+Id Read(Runtime& runtime, Graph& graph, const std::string& path,
+ ReadOptions options, const std::unique_ptr<Filter>& file_filter) {
+ return internal::Reader(runtime, graph, path, options, file_filter).Read();
}
-Id Read(Graph& graph, char* data, size_t size, ReadOptions options,
- const std::unique_ptr<Filter>& file_filter, Metrics& metrics) {
- return internal::Reader(graph, data, size, options, file_filter, metrics)
+Id Read(Runtime& runtime, Graph& graph, char* data, size_t size,
+ ReadOptions options, const std::unique_ptr<Filter>& file_filter) {
+ return internal::Reader(runtime, graph, data, size, options, file_filter)
.Read();
}
diff --git a/elf_reader.h b/elf_reader.h
index 12d5711..159096a 100644
--- a/elf_reader.h
+++ b/elf_reader.h
@@ -31,16 +31,16 @@
#include "elf_loader.h"
#include "filter.h"
#include "graph.h"
-#include "metrics.h"
#include "reader_options.h"
+#include "runtime.h"
namespace stg {
namespace elf {
-Id Read(Graph& graph, const std::string& path, ReadOptions options,
- const std::unique_ptr<Filter>& file_filter, Metrics& metrics);
-Id Read(Graph& graph, char* data, size_t size, ReadOptions options,
- const std::unique_ptr<Filter>& file_filter, Metrics& metrics);
+Id Read(Runtime& runtime, Graph& graph, const std::string& path,
+ ReadOptions options, const std::unique_ptr<Filter>& file_filter);
+Id Read(Runtime& runtime, Graph& graph, char* data, size_t size,
+ ReadOptions options, const std::unique_ptr<Filter>& file_filter);
// For unit tests only
namespace internal {
diff --git a/equality.h b/equality.h
index 0747073..77cd1a4 100644
--- a/equality.h
+++ b/equality.h
@@ -58,7 +58,7 @@ struct Equals {
}
// Comparison opened, need to close it before returning.
- bool result = graph.Apply2<bool>(*this, id1, id2);
+ const auto result = graph.Apply2<bool>(*this, id1, id2);
// Check for a complete Strongly-Connected Component.
auto comparisons = scc.Close(*handle);
diff --git a/equality_cache.h b/equality_cache.h
index 0b15b39..9373aa2 100644
--- a/equality_cache.h
+++ b/equality_cache.h
@@ -29,7 +29,7 @@
#include "graph.h"
#include "hashing.h"
-#include "metrics.h"
+#include "runtime.h"
namespace stg {
@@ -46,25 +46,25 @@ namespace stg {
// Node hashes such as those generated by the Fingerprint function object may be
// supplied to avoid equality testing when hashes differ.
struct EqualityCache {
- EqualityCache(const std::unordered_map<Id, HashValue>& hashes,
- Metrics& metrics)
+ EqualityCache(Runtime& runtime,
+ const std::unordered_map<Id, HashValue>& hashes)
: hashes(hashes),
- query_count(metrics, "cache.query_count"),
- query_equal_ids(metrics, "cache.query_equal_ids"),
- query_unequal_hashes(metrics, "cache.query_unequal_hashes"),
- query_equal_representatives(metrics,
+ query_count(runtime, "cache.query_count"),
+ query_equal_ids(runtime, "cache.query_equal_ids"),
+ query_unequal_hashes(runtime, "cache.query_unequal_hashes"),
+ query_equal_representatives(runtime,
"cache.query_equal_representatives"),
- query_inequality_found(metrics, "cache.query_inequality_found"),
- query_not_found(metrics, "cache.query_not_found"),
- find_halved(metrics, "cache.find_halved"),
- union_known(metrics, "cache.union_known"),
- union_rank_swap(metrics, "cache.union_rank_swap"),
- union_rank_increase(metrics, "cache.union_rank_increase"),
- union_rank_zero(metrics, "cache.union_rank_zero"),
- union_unknown(metrics, "cache.union_unknown"),
- disunion_known_hash(metrics, "cache.disunion_known_hash"),
- disunion_known_inequality(metrics, "cache.disunion_known_inequality"),
- disunion_unknown(metrics, "cache.disunion_unknown") {}
+ query_inequality_found(runtime, "cache.query_inequality_found"),
+ query_not_found(runtime, "cache.query_not_found"),
+ find_halved(runtime, "cache.find_halved"),
+ union_known(runtime, "cache.union_known"),
+ union_rank_swap(runtime, "cache.union_rank_swap"),
+ union_rank_increase(runtime, "cache.union_rank_increase"),
+ union_rank_zero(runtime, "cache.union_rank_zero"),
+ union_unknown(runtime, "cache.union_unknown"),
+ disunion_known_hash(runtime, "cache.disunion_known_hash"),
+ disunion_known_inequality(runtime, "cache.disunion_known_inequality"),
+ disunion_unknown(runtime, "cache.disunion_unknown") {}
std::optional<bool> Query(const Pair& comparison) {
++query_count;
@@ -226,11 +226,11 @@ struct EqualityCache {
};
struct SimpleEqualityCache {
- explicit SimpleEqualityCache(Metrics& metrics)
- : query_count(metrics, "simple_cache.query_count"),
- query_equal_ids(metrics, "simple_cache.query_equal_ids"),
- query_known_equality(metrics, "simple_cache.query_known_equality"),
- known_equality_inserts(metrics, "simple_cache.known_equality_inserts") {
+ explicit SimpleEqualityCache(Runtime& runtime)
+ : query_count(runtime, "simple_cache.query_count"),
+ query_equal_ids(runtime, "simple_cache.query_equal_ids"),
+ query_known_equality(runtime, "simple_cache.query_known_equality"),
+ known_equality_inserts(runtime, "simple_cache.known_equality_inserts") {
}
std::optional<bool> Query(const Pair& comparison) {
diff --git a/error.h b/error.h
index 5ca6c57..b72faaf 100644
--- a/error.h
+++ b/error.h
@@ -124,7 +124,7 @@ template <typename T>
std::ostream& operator<<(std::ostream& os, const Hex<T>& hex_value) {
// not quite right if an exception is thrown
const auto flags = os.flags();
- os << std::hex << std::showbase << hex_value.value;
+ os << "0x" << std::hex << hex_value.value;
os.flags(flags);
return os;
}
diff --git a/fingerprint.cc b/fingerprint.cc
index 5d87677..b97b2ff 100644
--- a/fingerprint.cc
+++ b/fingerprint.cc
@@ -19,6 +19,7 @@
#include "fingerprint.h"
+#include <cstdint>
#include <map>
#include <string>
#include <unordered_map>
@@ -28,17 +29,18 @@
#include "graph.h"
#include "hashing.h"
-#include "metrics.h"
+#include "runtime.h"
#include "scc.h"
namespace stg {
namespace {
struct Hasher {
- Hasher(const Graph& graph, std::unordered_map<Id, HashValue>& hashes,
- std::unordered_set<Id>& todo, Metrics& metrics)
+ Hasher(Runtime& runtime, const Graph& graph,
+ std::unordered_map<Id, HashValue>& hashes,
+ std::unordered_set<Id>& todo)
: graph(graph), hashes(hashes), todo(todo),
- non_trivial_scc_size(metrics, "fingerprint.non_trivial_scc_size") {}
+ non_trivial_scc_size(runtime, "fingerprint.non_trivial_scc_size") {}
// Graph function implementation
HashValue operator()(const Special& x) {
@@ -94,7 +96,7 @@ struct Hasher {
auto h = hash('U', static_cast<uint32_t>(x.kind), x.name);
if (x.definition.has_value()) {
h = hash(h, '1');
- auto& definition = *x.definition;
+ const auto& definition = *x.definition;
ToDo(definition.base_classes);
ToDo(definition.methods);
if (x.name.empty()) {
@@ -166,7 +168,7 @@ struct Hasher {
}
// Comparison opened, need to close it before returning.
- HashValue result = graph.Apply<HashValue>(*this, id);
+ auto result = graph.Apply<HashValue>(*this, id);
// Check for a complete Strongly-Connected Component.
auto ids = scc.Close(*handle);
@@ -218,11 +220,11 @@ struct Hasher {
} // namespace
std::unordered_map<Id, HashValue> Fingerprint(
- const Graph& graph, Id root, Metrics& metrics) {
- Time x(metrics, "hash nodes");
+ Runtime& runtime, const Graph& graph, Id root) {
+ const Time x(runtime, "hash nodes");
std::unordered_map<Id, HashValue> hashes;
std::unordered_set<Id> todo;
- Hasher hasher(graph, hashes, todo, metrics);
+ Hasher hasher(runtime, graph, hashes, todo);
todo.insert(root);
while (!todo.empty()) {
for (auto id : std::exchange(todo, {})) {
diff --git a/fingerprint.h b/fingerprint.h
index f5f8042..43fe694 100644
--- a/fingerprint.h
+++ b/fingerprint.h
@@ -25,7 +25,7 @@
#include "graph.h"
#include "hashing.h"
-#include "metrics.h"
+#include "runtime.h"
namespace stg {
@@ -35,7 +35,7 @@ namespace stg {
// Given any mutual dependencies between hashes, it falls back to a very poor
// but safe hash for the affected nodes: the size of the SCC.
std::unordered_map<Id, HashValue> Fingerprint(
- const Graph& graph, Id root, Metrics& metrics);
+ Runtime& runtime, const Graph& graph, Id root);
} // namespace stg
diff --git a/fuzz/elf_reader_fuzzer.cc b/fuzz/elf_reader_fuzzer.cc
index e2d8f55..d83b012 100644
--- a/fuzz/elf_reader_fuzzer.cc
+++ b/fuzz/elf_reader_fuzzer.cc
@@ -18,24 +18,26 @@
// Author: Matthias Maennich
// Author: Aleksei Vetrov
+#include <sstream>
#include <vector>
#include "elf_reader.h"
#include "error.h"
#include "graph.h"
-#include "metrics.h"
#include "reader_options.h"
+#include "runtime.h"
extern "C" int LLVMFuzzerTestOneInput(char* data, size_t size) {
try {
// Fuzzer forbids changing "data", but libdwfl, used in elf::Read, requires
// read and write access to memory.
// Luckily, such trivial copy can be easily tracked by fuzzer.
- std::vector<char> data_copy(data, data + size);
+ std::ostringstream os;
+ stg::Runtime runtime(os, false);
stg::Graph graph;
- stg::Metrics metrics;
- stg::elf::Read(graph, data_copy.data(), size, stg::ReadOptions(), nullptr,
- metrics);
+ std::vector<char> data_copy(data, data + size);
+ stg::elf::Read(runtime, graph, data_copy.data(), size, stg::ReadOptions(),
+ nullptr);
} catch (const stg::Exception&) {
// Pass as this is us catching invalid ELF properly.
}
diff --git a/input.cc b/input.cc
index f30cdca..239cb07 100644
--- a/input.cc
+++ b/input.cc
@@ -28,32 +28,32 @@
#include "error.h"
#include "filter.h"
#include "graph.h"
-#include "metrics.h"
#include "proto_reader.h"
#include "reader_options.h"
+#include "runtime.h"
namespace stg {
namespace {
-Id ReadInternal(Graph& graph, InputFormat format, const char* input,
- ReadOptions options, const std::unique_ptr<Filter>& file_filter,
- Metrics& metrics) {
+Id ReadInternal(Runtime& runtime, Graph& graph, InputFormat format,
+ const char* input, ReadOptions options,
+ const std::unique_ptr<Filter>& file_filter) {
switch (format) {
case InputFormat::ABI: {
- Time read(metrics, "read ABI");
- return abixml::Read(graph, input, metrics);
+ const Time read(runtime, "read ABI");
+ return abixml::Read(runtime, graph, input);
}
case InputFormat::BTF: {
- Time read(metrics, "read BTF");
+ const Time read(runtime, "read BTF");
return btf::ReadFile(graph, input, options);
}
case InputFormat::ELF: {
- Time read(metrics, "read ELF");
- return elf::Read(graph, input, options, file_filter, metrics);
+ const Time read(runtime, "read ELF");
+ return elf::Read(runtime, graph, input, options, file_filter);
}
case InputFormat::STG: {
- Time read(metrics, "read STG");
+ const Time read(runtime, "read STG");
return proto::Read(graph, input);
}
}
@@ -61,11 +61,10 @@ Id ReadInternal(Graph& graph, InputFormat format, const char* input,
} // namespace
-Id Read(Graph& graph, InputFormat format, const char* input,
- ReadOptions options, const std::unique_ptr<Filter>& file_filter,
- Metrics& metrics) {
+Id Read(Runtime& runtime, Graph& graph, InputFormat format, const char* input,
+ ReadOptions options, const std::unique_ptr<Filter>& file_filter) {
try {
- return ReadInternal(graph, format, input, options, file_filter, metrics);
+ return ReadInternal(runtime, graph, format, input, options, file_filter);
} catch (Exception& e) {
std::ostringstream os;
os << "processing file '" << input << '\'';
diff --git a/input.h b/input.h
index 51894a2..8a1e560 100644
--- a/input.h
+++ b/input.h
@@ -24,16 +24,15 @@
#include "filter.h"
#include "graph.h"
-#include "metrics.h"
#include "reader_options.h"
+#include "runtime.h"
namespace stg {
enum class InputFormat { ABI, BTF, ELF, STG };
-Id Read(Graph& graph, InputFormat format, const char* input,
- ReadOptions options, const std::unique_ptr<Filter>& file_filter,
- Metrics& metrics);
+Id Read(Runtime& runtime, Graph& graph, InputFormat format, const char* input,
+ ReadOptions options, const std::unique_ptr<Filter>& file_filter);
} // namespace stg
diff --git a/naming.cc b/naming.cc
index 8395291..8cf2c09 100644
--- a/naming.cc
+++ b/naming.cc
@@ -173,6 +173,13 @@ Name Describe::operator()(const BaseClass& x) {
return (*this)(x.type_id);
}
+Name Describe::operator()(const Method& x) {
+ if (x.mangled_name == x.name) {
+ return Name{x.name};
+ }
+ return Name{x.name + " {" + x.mangled_name + "}"};
+}
+
Name Describe::operator()(const Member& x) {
auto description = (*this)(x.type_id);
if (!x.name.empty()) {
@@ -185,13 +192,6 @@ Name Describe::operator()(const Member& x) {
return description;
}
-Name Describe::operator()(const Method& x) {
- if (x.mangled_name == x.name) {
- return Name{x.name};
- }
- return Name{x.name + " {" + x.mangled_name + "}"};
-}
-
Name Describe::operator()(const StructUnion& x) {
std::ostringstream os;
os << x.kind << ' ';
@@ -258,14 +258,14 @@ std::string DescribeKind::operator()(const BaseClass&) {
return "base class";
}
-std::string DescribeKind::operator()(const Member&) {
- return "member";
-}
-
std::string DescribeKind::operator()(const Method&) {
return "method";
}
+std::string DescribeKind::operator()(const Member&) {
+ return "member";
+}
+
std::string DescribeKind::operator()(const ElfSymbol& x) {
std::ostringstream os;
os << x.symbol_type << " symbol";
diff --git a/naming.h b/naming.h
index 1aaae39..163627f 100644
--- a/naming.h
+++ b/naming.h
@@ -66,8 +66,8 @@ struct Describe {
Name operator()(const Primitive&);
Name operator()(const Array&);
Name operator()(const BaseClass&);
- Name operator()(const Member&);
Name operator()(const Method&);
+ Name operator()(const Member&);
Name operator()(const StructUnion&);
Name operator()(const Enumeration&);
Name operator()(const Function&);
@@ -81,8 +81,8 @@ struct DescribeKind {
explicit DescribeKind(const Graph& graph) : graph(graph) {}
std::string operator()(Id id);
std::string operator()(const BaseClass&);
- std::string operator()(const Member&);
std::string operator()(const Method&);
+ std::string operator()(const Member&);
std::string operator()(const ElfSymbol&);
std::string operator()(const Interface&);
template <typename Node>
diff --git a/proto_writer.cc b/proto_writer.cc
index 122872a..d3de03d 100644
--- a/proto_writer.cc
+++ b/proto_writer.cc
@@ -497,8 +497,7 @@ class HexPrinter : public google::protobuf::TextFormat::FastFieldValuePrinter {
google::protobuf::TextFormat::BaseTextGenerator* generator) const override {
std::ostringstream os;
// 0x01234567
- os << std::showbase << std::hex << std::setfill('0') << std::internal
- << std::setw(10) << value;
+ os << "0x" << std::hex << std::setfill('0') << std::setw(8) << value;
generator->PrintString(os.str());
}
};
diff --git a/metrics.cc b/runtime.cc
index 23594cc..025f87c 100644
--- a/metrics.cc
+++ b/runtime.cc
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
-// Copyright 2021-2022 Google LLC
+// Copyright 2021-2023 Google LLC
//
// Licensed under the Apache License v2.0 with LLVM Exceptions (the
// "License"); you may not use this file except in compliance with the
@@ -17,27 +17,18 @@
//
// Author: Giuliano Procida
-#include "metrics.h"
+#include "runtime.h"
#include <cstddef>
#include <iomanip>
#include <map>
#include <ostream>
-#include <utility>
-#include <variant>
namespace stg {
-namespace {
-
-std::ostream& operator<<(std::ostream& os, std::monostate) {
- return os << "<incomplete>";
-}
-
-std::ostream& operator<<(std::ostream& os,
- const std::map<size_t, size_t>& frequencies) {
+std::ostream& operator<<(std::ostream& os, const Frequencies& frequencies) {
bool separate = false;
- for (const auto& [item, frequency] : frequencies) {
+ for (const auto& [item, frequency] : frequencies.counts) {
if (separate) {
os << ' ';
} else {
@@ -56,20 +47,9 @@ std::ostream& operator<<(std::ostream& os, const Nanoseconds& value) {
<< std::setfill(' ') << " ms";
}
-} // namespace
-
-void Report(const Metrics& metrics, std::ostream& os) {
- for (const auto& metric : metrics) {
- std::visit([&](auto&& value) {
- os << metric.name << ": " << value << '\n';
- }, metric.value);
- }
-}
-
-Time::Time(Metrics& metrics, const char* name)
- : metrics_(metrics), index_(metrics.size()) {
+Time::Time(Runtime& runtime, const char* name)
+ : runtime_(runtime), name_(name) {
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_);
- metrics_.push_back(Metric{name, std::monostate()});
}
Time::~Time() {
@@ -77,25 +57,24 @@ Time::~Time() {
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &finish);
const auto seconds = finish.tv_sec - start_.tv_sec;
const auto nanos = finish.tv_nsec - start_.tv_nsec;
- metrics_[index_].value.emplace<1>(seconds * 1'000'000'000 + nanos);
+ const Nanoseconds value(seconds * 1'000'000'000 + nanos);
+ runtime_.PrintMetric(name_, value);
}
-Counter::Counter(Metrics& metrics, const char* name)
- : metrics_(metrics), index_(metrics.size()), value_(0) {
- metrics_.push_back(Metric{name, std::monostate()});
+Counter::Counter(Runtime& runtime, const char* name)
+ : runtime_(runtime), name_(name), value_(0) {
}
Counter::~Counter() {
- metrics_[index_].value = value_;
+ runtime_.PrintMetric(name_, value_);
}
-Histogram::Histogram(Metrics& metrics, const char* name)
- : metrics_(metrics), index_(metrics.size()) {
- metrics_.push_back(Metric{name, std::monostate()});
+Histogram::Histogram(Runtime& runtime, const char* name)
+ : runtime_(runtime), name_(name) {
}
Histogram::~Histogram() {
- metrics_[index_].value.emplace<3>(std::move(frequencies_));
+ runtime_.PrintMetric(name_, frequencies_);
}
} // namespace stg
diff --git a/metrics.h b/runtime.h
index 6fc8dab..ad78c72 100644
--- a/metrics.h
+++ b/runtime.h
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
-// Copyright 2021-2022 Google LLC
+// Copyright 2021-2023 Google LLC
//
// Licensed under the Apache License v2.0 with LLVM Exceptions (the
// "License"); you may not use this file except in compliance with the
@@ -17,16 +17,14 @@
//
// Author: Giuliano Procida
-#ifndef STG_METRICS_H_
-#define STG_METRICS_H_
+#ifndef STG_RUNTIME_H_
+#define STG_RUNTIME_H_
#include <cstddef>
#include <cstdint>
#include <ctime>
#include <map>
#include <ostream>
-#include <variant>
-#include <vector>
namespace stg {
@@ -35,36 +33,43 @@ struct Nanoseconds {
uint64_t ns;
};
-struct Metric {
- const char* name;
- std::variant<
- std::monostate,
- Nanoseconds,
- size_t,
- std::map<size_t, size_t>
- > value;
+struct Frequencies {
+ std::map<size_t, size_t> counts;
};
-using Metrics = std::vector<Metric>;
-
-void Report(const Metrics& metrics, std::ostream& os);
+struct Runtime {
+ Runtime(std::ostream& output, bool print_metrics)
+ : output(output), print_metrics(print_metrics) {}
+ template <typename V>
+ void PrintMetric(const char* name, const V& value) {
+ if (print_metrics) {
+ output << name << ": " << value << '\n';
+ }
+ }
+ std::ostream& output;
+ bool print_metrics;
+};
// These objects only record values on destruction, so scope them!
class Time {
public:
- Time(Metrics& metrics, const char* name);
+ Time(Runtime& runtime, const char* name);
+ Time(Time&& other) = delete;
+ Time& operator=(Time&& other) = delete;
~Time();
private:
- Metrics& metrics_;
- size_t index_;
+ Runtime& runtime_;
+ const char* name_;
struct timespec start_;
};
class Counter {
public:
- Counter(Metrics& metrics, const char* name);
+ Counter(Runtime& runtime, const char* name);
+ Counter(Counter&& other) = delete;
+ Counter& operator=(Counter&& other) = delete;
~Counter();
Counter& operator=(size_t x) {
@@ -83,26 +88,28 @@ class Counter {
}
private:
- Metrics& metrics_;
- size_t index_;
+ Runtime& runtime_;
+ const char* name_;
size_t value_;
};
class Histogram {
public:
- Histogram(Metrics& metrics, const char* name);
+ Histogram(Runtime& runtime, const char* name);
+ Histogram(Histogram&& other) = delete;
+ Histogram& operator=(Histogram&& other) = delete;
~Histogram();
void Add(size_t item) {
- ++frequencies_[item];
+ ++frequencies_.counts[item];
}
private:
- Metrics& metrics_;
- size_t index_;
- std::map<size_t, size_t> frequencies_;
+ Runtime& runtime_;
+ const char* name_;
+ Frequencies frequencies_;
};
} // namespace stg
-#endif // STG_METRICS_H_
+#endif // STG_RUNTIME_H_
diff --git a/metrics_test.cc b/runtime_test.cc
index 71b5929..78075af 100644
--- a/metrics_test.cc
+++ b/runtime_test.cc
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
-// Copyright 2022 Google LLC
+// Copyright 2022-2023 Google LLC
//
// Licensed under the Apache License v2.0 with LLVM Exceptions (the
// "License"); you may not use this file except in compliance with the
@@ -17,49 +17,53 @@
//
// Author: Giuliano Procida
-#include "metrics.h"
+#include "runtime.h"
+#include <array>
#include <cstddef>
-#include <cstdint>
#include <sstream>
#include <string>
-#include <vector>
#include <catch2/catch.hpp>
namespace Test {
TEST_CASE("empty") {
- stg::Metrics metrics;
std::ostringstream os;
- stg::Report(metrics, os);
+ {
+ const stg::Runtime runtime(os, true);
+ }
CHECK(os.str().empty());
}
-TEST_CASE("incomplete") {
- stg::Metrics metrics;
- std::ostringstream os;
- stg::Time a(metrics, "a");
- stg::Counter b(metrics, "b");
- stg::Histogram c(metrics, "c");
- stg::Report(metrics, os);
- const std::string expected =
- "a: <incomplete>\nb: <incomplete>\nc: <incomplete>\n";
- CHECK(os.str() == expected);
-}
-
TEST_CASE("times") {
- stg::Metrics metrics;
const size_t count = 20;
- std::vector<stg::Time> times;
- for (size_t i = 0; i < count; ++i) {
- times.emplace_back(metrics, "name");
- }
- for (size_t i = 0; i < count; ++i) {
- times.pop_back();
- }
std::ostringstream os;
- stg::Report(metrics, os);
+ {
+ stg::Runtime runtime(os, true);
+ const std::array<const stg::Time, count> timers = {
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ stg::Time(runtime, "name"),
+ };
+ }
std::istringstream is(os.str());
const std::string name = "name:";
const std::string ms = "ms";
@@ -71,9 +75,7 @@ TEST_CASE("times") {
std::string second;
is >> first >> time >> second;
CHECK(first == name);
- if (last_time != 0.0) {
- CHECK(time < last_time);
- }
+ CHECK(time > last_time);
CHECK(second == ms);
last_time = time;
++index;
@@ -86,13 +88,14 @@ TEST_CASE("times") {
}
TEST_CASE("counters") {
- stg::Metrics metrics;
+ std::ostringstream os;
{
- stg::Counter a(metrics, "a");
- stg::Counter b(metrics, "b");
- stg::Counter c(metrics, "c");
- stg::Counter d(metrics, "d");
- stg::Counter e(metrics, "e");
+ stg::Runtime runtime(os, true);
+ stg::Counter a(runtime, "a");
+ stg::Counter b(runtime, "b");
+ stg::Counter c(runtime, "c");
+ const stg::Counter d(runtime, "d");
+ stg::Counter e(runtime, "e");
c = 17;
++b;
++b;
@@ -100,23 +103,20 @@ TEST_CASE("counters") {
a = 3;
c += 2;
}
- std::ostringstream os;
- Report(metrics, os);
- const std::string expected = "a: 3\nb: 2\nc: 19\nd: 0\ne: 1\n";
+ const std::string expected = "e: 1\nd: 0\nc: 19\nb: 2\na: 3\n";
CHECK(os.str() == expected);
}
TEST_CASE("histogram") {
- stg::Metrics metrics;
+ std::ostringstream os;
{
- stg::Histogram h(metrics, "h");
+ stg::Runtime runtime(os, true);
+ stg::Histogram h(runtime, "h");
h.Add(13);
h.Add(14);
h.Add(13);
h.Add(12);
}
- std::ostringstream os;
- Report(metrics, os);
const std::string expected = "h: [12]=1 [13]=2 [14]=1\n";
CHECK(os.str() == expected);
}
diff --git a/stg.cc b/stg.cc
index 82a372e..8a4711a 100644
--- a/stg.cc
+++ b/stg.cc
@@ -35,9 +35,9 @@
#include "fingerprint.h"
#include "graph.h"
#include "input.h"
-#include "metrics.h"
#include "proto_writer.h"
#include "reader_options.h"
+#include "runtime.h"
#include "type_resolution.h"
#include "unification.h"
@@ -55,10 +55,10 @@ struct GetInterface {
}
};
-Id Merge(Graph& graph, const std::vector<Id>& roots, Metrics& metrics) {
+Id Merge(Runtime& runtime, Graph& graph, const std::vector<Id>& roots) {
bool failed = false;
// this rewrites the graph on destruction
- Unification unification(graph, Id(0), metrics);
+ Unification unification(runtime, graph, Id(0));
unification.Reserve(graph.Limit());
std::map<std::string, Id> symbols;
std::map<std::string, Id> types;
@@ -99,10 +99,10 @@ void FilterSymbols(Graph& graph, Id root, const Filter& filter) {
std::swap(interface.symbols, symbols);
}
-void Write(const Graph& graph, Id root, const char* output, Metrics& metrics) {
+void Write(Runtime& runtime, const Graph& graph, Id root, const char* output) {
std::ofstream os(output);
{
- Time x(metrics, "write");
+ const Time x(runtime, "write");
proto::Writer writer(graph);
writer.Write(root, os);
os << std::flush;
@@ -204,33 +204,30 @@ int main(int argc, char* argv[]) {
try {
stg::Graph graph;
- stg::Metrics metrics;
+ stg::Runtime runtime(std::cerr, opt_metrics);
std::vector<stg::Id> roots;
roots.reserve(inputs.size());
for (auto& [format, input] : inputs) {
- roots.push_back(stg::Read(graph, format, input, opt_read_options,
- opt_file_filter, metrics));
+ roots.push_back(stg::Read(runtime, graph, format, input, opt_read_options,
+ opt_file_filter));
}
stg::Id root =
- roots.size() == 1 ? roots[0] : stg::Merge(graph, roots, metrics);
+ roots.size() == 1 ? roots[0] : stg::Merge(runtime, graph, roots);
if (opt_symbol_filter) {
stg::FilterSymbols(graph, root, *opt_symbol_filter);
}
if (!opt_keep_duplicates) {
{
- stg::Unification unification(graph, stg::Id(0), metrics);
+ stg::Unification unification(runtime, graph, stg::Id(0));
unification.Reserve(graph.Limit());
- stg::ResolveTypes(graph, unification, {root}, metrics);
+ stg::ResolveTypes(runtime, graph, unification, {root});
unification.Update(root);
}
- const auto hashes = stg::Fingerprint(graph, root, metrics);
- root = stg::Deduplicate(graph, root, hashes, metrics);
+ const auto hashes = stg::Fingerprint(runtime, graph, root);
+ root = stg::Deduplicate(runtime, graph, root, hashes);
}
for (auto output : outputs) {
- stg::Write(graph, root, output, metrics);
- }
- if (opt_metrics) {
- stg::Report(metrics, std::cerr);
+ stg::Write(runtime, graph, root, output);
}
return 0;
} catch (const stg::Exception& e) {
diff --git a/stg.proto b/stg.proto
index 0937299..6f5ce91 100644
--- a/stg.proto
+++ b/stg.proto
@@ -120,7 +120,7 @@ message Primitive {
fixed32 id = 1;
string name = 2;
optional Encoding encoding = 3;
- fixed32 bytesize = 4;
+ uint32 bytesize = 4;
}
message Array {
diff --git a/stgdiff.cc b/stgdiff.cc
index 18cc733..ecc7fdb 100644
--- a/stgdiff.cc
+++ b/stgdiff.cc
@@ -31,14 +31,16 @@
#include <utility>
#include <vector>
+#include "comparison.h"
#include "equality.h"
#include "error.h"
#include "fidelity.h"
#include "graph.h"
#include "input.h"
-#include "metrics.h"
+#include "naming.h"
#include "reader_options.h"
#include "reporting.h"
+#include "runtime.h"
namespace {
@@ -50,12 +52,12 @@ using Inputs = std::vector<std::pair<stg::InputFormat, const char*>>;
using Outputs =
std::vector<std::pair<stg::reporting::OutputFormat, const char*>>;
-std::vector<stg::Id> Read(const Inputs& inputs, stg::Graph& graph,
- stg::ReadOptions options, stg::Metrics& metrics) {
+std::vector<stg::Id> Read(stg::Runtime& runtime, const Inputs& inputs,
+ stg::Graph& graph, stg::ReadOptions options) {
std::vector<stg::Id> roots;
for (const auto& [format, filename] : inputs) {
- roots.push_back(stg::Read(graph, format, filename, options, nullptr,
- metrics));
+ roots.push_back(stg::Read(runtime, graph, format, filename, options,
+ nullptr));
}
return roots;
}
@@ -74,10 +76,10 @@ int RunFidelity(const char* filename, const stg::Graph& graph,
return diffs_reported ? kFidelityChange : 0;
}
-int RunExact(const Inputs& inputs, stg::ReadOptions options,
- stg::Metrics& metrics) {
+int RunExact(stg::Runtime& runtime, const Inputs& inputs,
+ stg::ReadOptions options) {
stg::Graph graph;
- const auto roots = Read(inputs, graph, options, metrics);
+ const auto roots = Read(runtime, inputs, graph, options);
struct PairCache {
std::optional<bool> Query(const stg::Pair& comparison) const {
@@ -94,25 +96,25 @@ int RunExact(const Inputs& inputs, stg::ReadOptions options,
std::unordered_set<stg::Pair> equalities;
};
- stg::Time compute(metrics, "equality check");
+ const stg::Time compute(runtime, "equality check");
PairCache equalities;
return stg::Equals<PairCache>(graph, equalities)(roots[0], roots[1])
? 0
: kAbiChange;
}
-int Run(const Inputs& inputs, const Outputs& outputs, stg::Ignore ignore,
- stg::ReadOptions options, std::optional<const char*> fidelity,
- stg::Metrics& metrics) {
+int Run(stg::Runtime& runtime, const Inputs& inputs, const Outputs& outputs,
+ stg::Ignore ignore, stg::ReadOptions options,
+ std::optional<const char*> fidelity) {
// Read inputs.
stg::Graph graph;
- const auto roots = Read(inputs, graph, options, metrics);
+ const auto roots = Read(runtime, inputs, graph, options);
// Compute differences.
- stg::Compare compare{graph, ignore, metrics};
+ stg::Compare compare{runtime, graph, ignore};
std::pair<bool, std::optional<stg::Comparison>> result;
{
- stg::Time compute(metrics, "compute diffs");
+ const stg::Time compute(runtime, "compute diffs");
result = compare(roots[0], roots[1]);
}
stg::Check(compare.scc.Empty()) << "internal error: SCC state broken";
@@ -124,10 +126,10 @@ int Run(const Inputs& inputs, const Outputs& outputs, stg::Ignore ignore,
for (const auto& [format, filename] : outputs) {
std::ofstream output(filename);
if (comparison) {
- stg::Time report(metrics, "report diffs");
- stg::reporting::Options options{format, kMaxCrcOnlyChanges};
- stg::reporting::Reporting reporting{graph, compare.outcomes, options,
- names};
+ const stg::Time report(runtime, "report diffs");
+ const stg::reporting::Options options{format, kMaxCrcOnlyChanges};
+ const stg::reporting::Reporting reporting{graph, compare.outcomes,
+ options, names};
Report(reporting, *comparison, output);
output << std::flush;
}
@@ -138,7 +140,7 @@ int Run(const Inputs& inputs, const Outputs& outputs, stg::Ignore ignore,
// Compute fidelity diff if requested.
if (fidelity) {
- const stg::Time report(metrics, "fidelity");
+ const stg::Time report(runtime, "fidelity");
status |= RunFidelity(*fidelity, graph, roots);
}
@@ -261,14 +263,10 @@ int main(int argc, char* argv[]) {
}
try {
- stg::Metrics metrics;
- const int status = opt_exact ? RunExact(inputs, opt_read_options, metrics)
- : Run(inputs, outputs, opt_ignore,
- opt_read_options, opt_fidelity, metrics);
- if (opt_metrics) {
- stg::Report(metrics, std::cerr);
- }
- return status;
+ stg::Runtime runtime(std::cerr, opt_metrics);
+ return opt_exact ? RunExact(runtime, inputs, opt_read_options)
+ : Run(runtime, inputs, outputs, opt_ignore,
+ opt_read_options, opt_fidelity);
} catch (const stg::Exception& e) {
std::cerr << e.what();
return 1;
diff --git a/stgdiff_test.cc b/stgdiff_test.cc
index a09a868..306ddc3 100644
--- a/stgdiff_test.cc
+++ b/stgdiff_test.cc
@@ -19,8 +19,6 @@
#include <filesystem>
#include <fstream>
-#include <iostream>
-#include <ostream>
#include <sstream>
#include <string>
@@ -28,9 +26,9 @@
#include "comparison.h"
#include "graph.h"
#include "input.h"
-#include "metrics.h"
#include "reader_options.h"
#include "reporting.h"
+#include "runtime.h"
namespace {
@@ -49,10 +47,10 @@ std::string filename_to_path(const std::string& f) {
return std::filesystem::path("testdata") / f;
}
-stg::Id Read(stg::Graph& graph, stg::InputFormat format,
- const std::string& input, stg::Metrics& metrics) {
- return stg::Read(graph, format, filename_to_path(input).c_str(),
- stg::ReadOptions(), nullptr, metrics);
+stg::Id Read(stg::Runtime& runtime, stg::Graph& graph, stg::InputFormat format,
+ const std::string& input) {
+ return stg::Read(runtime, graph, format, filename_to_path(input).c_str(),
+ stg::ReadOptions(), nullptr);
}
TEST_CASE("ignore") {
@@ -240,15 +238,16 @@ TEST_CASE("ignore") {
);
SECTION(test.name) {
- stg::Metrics metrics;
+ std::ostringstream os;
+ stg::Runtime runtime(os, false);
// Read inputs.
stg::Graph graph;
- const auto id0 = Read(graph, test.format0, test.file0, metrics);
- const auto id1 = Read(graph, test.format1, test.file1, metrics);
+ const auto id0 = Read(runtime, graph, test.format0, test.file0);
+ const auto id1 = Read(runtime, graph, test.format1, test.file1);
// Compute differences.
- stg::Compare compare{graph, test.ignore, metrics};
+ stg::Compare compare{runtime, graph, test.ignore};
const auto& [equals, comparison] = compare(id0, id1);
// Write SMALL reports.
@@ -294,15 +293,16 @@ TEST_CASE("short report") {
"added_removed_symbols_only_short_diff"}));
SECTION(test.name) {
- stg::Metrics metrics;
+ std::ostringstream os;
+ stg::Runtime runtime(os, false);
// Read inputs.
stg::Graph graph;
- const auto id0 = Read(graph, stg::InputFormat::ABI, test.xml0, metrics);
- const auto id1 = Read(graph, stg::InputFormat::ABI, test.xml1, metrics);
+ const auto id0 = Read(runtime, graph, stg::InputFormat::ABI, test.xml0);
+ const auto id1 = Read(runtime, graph, stg::InputFormat::ABI, test.xml1);
// Compute differences.
- stg::Compare compare{graph, {}, metrics};
+ stg::Compare compare{runtime, graph, {}};
const auto& [equals, comparison] = compare(id0, id1);
// Write SHORT reports.
@@ -325,14 +325,15 @@ TEST_CASE("short report") {
}
TEST_CASE("fidelity diff") {
- stg::Metrics metrics;
+ std::ostringstream os;
+ stg::Runtime runtime(os, false);
// Read inputs.
stg::Graph graph;
const auto id0 =
- Read(graph, stg::InputFormat::STG, "fidelity_diff_0.stg", metrics);
+ Read(runtime, graph, stg::InputFormat::STG, "fidelity_diff_0.stg");
const auto id1 =
- Read(graph, stg::InputFormat::STG, "fidelity_diff_1.stg", metrics);
+ Read(runtime, graph, stg::InputFormat::STG, "fidelity_diff_1.stg");
// Compute fidelity diff.
auto fidelity_diff = stg::GetFidelityTransitions(graph, id0, id1);
diff --git a/substitution.h b/substitution.h
index 5d3ba55..67f74b4 100644
--- a/substitution.h
+++ b/substitution.h
@@ -91,11 +91,11 @@ struct Substitute {
Update(x.type_id);
}
- void operator()(Member& x) {
+ void operator()(Method& x) {
Update(x.type_id);
}
- void operator()(Method& x) {
+ void operator()(Member& x) {
Update(x.type_id);
}
diff --git a/test_cases/info_tests/template/expected/template_parameter_cc.elf_stg b/test_cases/info_tests/template/expected/template_parameter_cc.elf_stg
new file mode 100644
index 0000000..f44fb07
--- /dev/null
+++ b/test_cases/info_tests/template/expected/template_parameter_cc.elf_stg
@@ -0,0 +1,210 @@
+version: 0x00000002
+root_id: 0x84ea5130
+primitive {
+ id: 0x6720d32f
+ name: "int"
+ encoding: SIGNED_INTEGER
+ bytesize: 0x00000004
+}
+array {
+ id: 0x9d362140
+ number_of_elements: 17
+ element_type_id: 0x6720d32f
+}
+member {
+ id: 0x80bcb4cd
+ name: "a"
+ type_id: 0x6720d32f
+}
+member {
+ id: 0x4cff5574
+ name: "b"
+ type_id: 0x6720d32f
+ offset: 32
+}
+member {
+ id: 0x4cff584f
+ name: "b"
+ type_id: 0x6720d32f
+}
+member {
+ id: 0x0f3f9186
+ name: "c"
+ type_id: 0x6720d32f
+ offset: 32
+}
+member {
+ id: 0xc37de7d7
+ name: "d"
+ type_id: 0x6720d32f
+ offset: 64
+}
+member {
+ id: 0x874410b0
+ name: "e"
+ type_id: 0x9d362140
+}
+member {
+ id: 0x41fcdfad
+ name: "f"
+ type_id: 0x6720d32f
+ offset: 544
+}
+member {
+ id: 0x023d43d4
+ name: "g"
+ type_id: 0x6720d32f
+ offset: 576
+}
+member {
+ id: 0xa8938b2e
+ name: "h"
+ type_id: 0x7578447d
+}
+member {
+ id: 0x86c14d13
+ name: "i"
+ type_id: 0x6720d32f
+}
+member {
+ id: 0x2d952030
+ name: "j"
+ type_id: 0xa5c1eab5
+}
+member {
+ id: 0x6940985f
+ name: "k"
+ type_id: 0x6720d32f
+}
+member {
+ id: 0xc5d22295
+ name: "l"
+ type_id: 0xcb978265
+}
+member {
+ id: 0x8dbf3d30
+ name: "m"
+ type_id: 0x6720d32f
+}
+member {
+ id: 0x46ee5fe7
+ name: "n"
+ type_id: 0x8891f0f8
+}
+member {
+ id: 0x04420382
+ name: "o"
+ type_id: 0x6720d32f
+ offset: 608
+}
+struct_union {
+ id: 0x7578447d
+ kind: STRUCT
+ name: "T1<int>"
+ definition {
+ bytesize: 8
+ member_id: 0x80bcb4cd
+ member_id: 0x4cff5574
+ }
+}
+struct_union {
+ id: 0xa5c1eab5
+ kind: STRUCT
+ name: "T2<int, int>"
+ definition {
+ bytesize: 12
+ member_id: 0x4cff584f
+ member_id: 0x0f3f9186
+ member_id: 0xc37de7d7
+ }
+}
+struct_union {
+ id: 0xcb978265
+ kind: STRUCT
+ name: "T3<17, int>"
+ definition {
+ bytesize: 76
+ member_id: 0x874410b0
+ member_id: 0x41fcdfad
+ member_id: 0x023d43d4
+ }
+}
+struct_union {
+ id: 0xd94d74b0
+ kind: UNION
+ name: "T4<T1>"
+ definition {
+ bytesize: 8
+ member_id: 0xa8938b2e
+ member_id: 0x86c14d13
+ }
+}
+struct_union {
+ id: 0x5e0ea2b4
+ kind: UNION
+ name: "T5<T2>"
+ definition {
+ bytesize: 12
+ member_id: 0x2d952030
+ member_id: 0x6940985f
+ }
+}
+struct_union {
+ id: 0x8891f0f8
+ kind: UNION
+ name: "T6<T3>"
+ definition {
+ bytesize: 76
+ member_id: 0xc5d22295
+ member_id: 0x8dbf3d30
+ }
+}
+struct_union {
+ id: 0x886d9bb6
+ kind: STRUCT
+ name: "T7<T6>"
+ definition {
+ bytesize: 80
+ member_id: 0x46ee5fe7
+ member_id: 0x04420382
+ }
+}
+elf_symbol {
+ id: 0xab18a5e8
+ name: "v1"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0xd94d74b0
+ full_name: "v1"
+}
+elf_symbol {
+ id: 0x975e59cf
+ name: "v2"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0x5e0ea2b4
+ full_name: "v2"
+}
+elf_symbol {
+ id: 0x2999e447
+ name: "v3"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0x8891f0f8
+ full_name: "v3"
+}
+elf_symbol {
+ id: 0x19de9370
+ name: "v4"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0x886d9bb6
+ full_name: "v4"
+}
+interface {
+ id: 0x84ea5130
+ symbol_id: 0xab18a5e8
+ symbol_id: 0x975e59cf
+ symbol_id: 0x2999e447
+ symbol_id: 0x19de9370
+}
diff --git a/test_cases/info_tests/template/expected/value_parameter_cc.elf_stg b/test_cases/info_tests/template/expected/value_parameter_cc.elf_stg
new file mode 100644
index 0000000..24f9d2d
--- /dev/null
+++ b/test_cases/info_tests/template/expected/value_parameter_cc.elf_stg
@@ -0,0 +1,231 @@
+version: 0x00000002
+root_id: 0x84ea5130
+special {
+ id: 0x48b5725f
+ kind: VOID
+}
+pointer_reference {
+ id: 0xc3b63b14
+ kind: LVALUE_REFERENCE
+ pointee_type_id: 0x10985193
+}
+pointer_reference {
+ id: 0xf6e6592a
+ kind: LVALUE_REFERENCE
+ pointee_type_id: 0xc5d9d969
+}
+qualified {
+ id: 0xc5d9d969
+ qualifier: CONST
+ qualified_type_id: 0x6720d32f
+}
+primitive {
+ id: 0x6720d32f
+ name: "int"
+ encoding: SIGNED_INTEGER
+ bytesize: 0x00000004
+}
+struct_union {
+ id: 0x04d4366e
+ kind: STRUCT
+ name: "S<&H::i2>"
+ definition {
+ bytesize: 1
+ }
+}
+struct_union {
+ id: 0x8fd5ff58
+ kind: STRUCT
+ name: "S<&H::j2>"
+ definition {
+ bytesize: 1
+ }
+}
+struct_union {
+ id: 0xe4d3d1c9
+ kind: STRUCT
+ name: "S<&a>"
+ definition {
+ bytesize: 1
+ }
+}
+struct_union {
+ id: 0x3a75138f
+ kind: STRUCT
+ name: "S<&d>"
+ definition {
+ bytesize: 1
+ }
+}
+struct_union {
+ id: 0x31dac610
+ kind: STRUCT
+ name: "S<&e>"
+ definition {
+ bytesize: 1
+ }
+}
+struct_union {
+ id: 0x54943dbe
+ kind: STRUCT
+ name: "S<\'p\'>"
+ definition {
+ bytesize: 1
+ }
+}
+struct_union {
+ id: 0x2119c209
+ kind: STRUCT
+ name: "S<(K)0>"
+ definition {
+ bytesize: 1
+ }
+}
+struct_union {
+ id: 0x3bb4a383
+ kind: STRUCT
+ name: "S<15>"
+ definition {
+ bytesize: 1
+ }
+}
+struct_union {
+ id: 0x0e0f27de
+ kind: STRUCT
+ name: "S<4>"
+ definition {
+ bytesize: 1
+ }
+}
+struct_union {
+ id: 0x0257c3b9
+ kind: STRUCT
+ name: "S<nullptr>"
+ definition {
+ bytesize: 1
+ }
+}
+function {
+ id: 0x10985193
+ return_type_id: 0x48b5725f
+}
+elf_symbol {
+ id: 0x65e66866
+ name: "_Z1ev"
+ is_defined: true
+ symbol_type: FUNCTION
+ type_id: 0x10985193
+ full_name: "e"
+}
+elf_symbol {
+ id: 0x2230fb28
+ name: "c"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0xf6e6592a
+ full_name: "c"
+}
+elf_symbol {
+ id: 0xe0778f95
+ name: "f"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0xc3b63b14
+ full_name: "f"
+}
+elf_symbol {
+ id: 0xea07c015
+ name: "v_char"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0x54943dbe
+ full_name: "v_char"
+}
+elf_symbol {
+ id: 0xc31d4af7
+ name: "v_enumerator"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0x2119c209
+ full_name: "v_enumerator"
+}
+elf_symbol {
+ id: 0x87e5aa8a
+ name: "v_function_pointer"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0x3a75138f
+ full_name: "v_function_pointer"
+}
+elf_symbol {
+ id: 0x2c4cacfa
+ name: "v_function_reference"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0x31dac610
+ full_name: "v_function_reference"
+}
+elf_symbol {
+ id: 0x40715147
+ name: "v_int"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0x3bb4a383
+ full_name: "v_int"
+}
+elf_symbol {
+ id: 0x575714fe
+ name: "v_int_pointer"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0xe4d3d1c9
+ full_name: "v_int_pointer"
+}
+elf_symbol {
+ id: 0xe323633f
+ name: "v_int_reference"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0x0e0f27de
+ full_name: "v_int_reference"
+}
+elf_symbol {
+ id: 0x481dfc0e
+ name: "v_nullptr"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0x0257c3b9
+ full_name: "v_nullptr"
+}
+elf_symbol {
+ id: 0xcb9e41aa
+ name: "v_pointer_to_member"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0x04d4366e
+ full_name: "v_pointer_to_member"
+}
+elf_symbol {
+ id: 0x3dc86173
+ name: "v_pointer_to_method"
+ is_defined: true
+ symbol_type: OBJECT
+ type_id: 0x8fd5ff58
+ full_name: "v_pointer_to_method"
+}
+interface {
+ id: 0x84ea5130
+ symbol_id: 0x65e66866
+ symbol_id: 0x2230fb28
+ symbol_id: 0xe0778f95
+ symbol_id: 0xea07c015
+ symbol_id: 0xc31d4af7
+ symbol_id: 0x87e5aa8a
+ symbol_id: 0x2c4cacfa
+ symbol_id: 0x40715147
+ symbol_id: 0x575714fe
+ symbol_id: 0xe323633f
+ symbol_id: 0x481dfc0e
+ symbol_id: 0xcb9e41aa
+ symbol_id: 0x3dc86173
+}
diff --git a/test_cases/info_tests/template/template_parameter.cc b/test_cases/info_tests/template/template_parameter.cc
new file mode 100644
index 0000000..2fc54f0
--- /dev/null
+++ b/test_cases/info_tests/template/template_parameter.cc
@@ -0,0 +1,37 @@
+template<typename A1> struct T1 {
+ A1 a;
+ int b;
+};
+template<typename B1, typename B2> struct T2 {
+ B1 b;
+ B2 c;
+ int d;
+};
+template<int C1, typename C2> struct T3 {
+ int e[C1];
+ C2 f;
+ int g;
+};
+
+template<template<typename> typename P1> union T4{
+ P1<int> h;
+ int i;
+};
+template<template<typename, typename> typename P2> union T5{
+ P2<int, int> j;
+ int k;
+};
+template<template<auto, typename> typename P3> union T6{
+ P3<17, int> l;
+ int m;
+};
+
+template<template<template<auto, typename> typename> typename P4> struct T7 {
+ P4<T3> n;
+ int o;
+};
+
+T4<T1> v1;
+T5<T2> v2;
+T6<T3> v3;
+T7<T6> v4;
diff --git a/test_cases/info_tests/template/value_parameter.cc b/test_cases/info_tests/template/value_parameter.cc
new file mode 100644
index 0000000..3aa7b1f
--- /dev/null
+++ b/test_cases/info_tests/template/value_parameter.cc
@@ -0,0 +1,41 @@
+template<auto V> struct S {};
+
+S<15> v_int;
+S<'p'> v_char;
+// Not supported by Clang yet.
+//S<4.2> v_double;
+
+extern const int a;
+S<&a> v_int_pointer;
+
+const int b = 4;
+const int& c = b;
+S<c> v_int_reference;
+
+extern void d();
+S<&d> v_function_pointer;
+
+void e() {}
+void (&f)() = e;
+S<f> v_function_reference;
+
+struct H {
+ int i1;
+ int i2;
+ void j1();
+ void j2();
+};
+S<&H::i2> v_pointer_to_member;
+S<&H::j2> v_pointer_to_method;
+
+enum class K { l };
+S<K::l> v_enumerator;
+
+S<nullptr> v_nullptr;
+
+// C++20 only.
+//int m[2] = { 10, 4 };
+//S<&(m[1])> v_pointer_to_subobject;
+
+// C++20 only and cannot appear in ABI anyway.
+//S<[](){}> v_lambda;
diff --git a/testdata/abigail_duplicate_types_9.xml b/testdata/abigail_duplicate_types_9.xml
new file mode 100644
index 0000000..a447fd3
--- /dev/null
+++ b/testdata/abigail_duplicate_types_9.xml
@@ -0,0 +1,28 @@
+<!-- Output from libabigail, split into two corpora -->
+<abi-corpus-group>
+ <abi-corpus version='2.1' architecture='elf-amd-x86_64'>
+ <elf-variable-symbols>
+ <elf-symbol name='t' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ </elf-variable-symbols>
+ </abi-corpus>
+ <abi-corpus version='2.1' architecture='elf-amd-x86_64'>
+ <abi-instr address-size='64' path='mt.cc' language='LANG_C_plus_plus_14'>
+ <type-decl name='int' size-in-bits='32' id='95e97e5e'/>
+ <namespace-decl name='N'>
+ <class-decl name='S' size-in-bits='8' is-struct='yes' visibility='default' id='af2c111e'>
+ <member-type access='public'>
+ <class-decl name='T' size-in-bits='32' is-struct='yes' visibility='default' id='500730c2'>
+ <data-member access='public' layout-offset-in-bits='0'>
+ <var-decl name='x' type-id='95e97e5e' visibility='default'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='32'>
+ <var-decl name='y' type-id='95e97e5e' visibility='default'/>
+ </data-member>
+ </class-decl>
+ </member-type>
+ </class-decl>
+ </namespace-decl>
+ <var-decl name='t' type-id='500730c2' mangled-name='t' visibility='default' elf-symbol-id='t'/>
+ </abi-instr>
+ </abi-corpus>
+</abi-corpus-group>
diff --git a/type_normalisation.cc b/type_normalisation.cc
index 50a59b1..377198f 100644
--- a/type_normalisation.cc
+++ b/type_normalisation.cc
@@ -118,11 +118,11 @@ struct FindQualifiedTypesAndFunctions {
(*this)(x.type_id);
}
- void operator()(const Member& x, Id) {
+ void operator()(const Method& x, Id) {
(*this)(x.type_id);
}
- void operator()(const Method& x, Id) {
+ void operator()(const Member& x, Id) {
(*this)(x.type_id);
}
diff --git a/type_resolution.cc b/type_resolution.cc
index b32d535..928332c 100644
--- a/type_resolution.cc
+++ b/type_resolution.cc
@@ -26,7 +26,7 @@
#include <vector>
#include "graph.h"
-#include "metrics.h"
+#include "runtime.h"
#include "unification.h"
namespace stg {
@@ -35,13 +35,13 @@ namespace {
// Collect named type definition and declaration nodes.
struct NamedTypes {
- NamedTypes(const Graph& graph, Metrics& metrics)
+ NamedTypes(Runtime& runtime, const Graph& graph)
: graph(graph),
seen(Id(0)),
- nodes(metrics, "named_types.nodes"),
- types(metrics, "named_types.types"),
- definitions(metrics, "named_types.definitions"),
- declarations(metrics, "named_types.declarations") {
+ nodes(runtime, "named_types.nodes"),
+ types(runtime, "named_types.types"),
+ definitions(runtime, "named_types.definitions"),
+ declarations(runtime, "named_types.declarations") {
seen.Reserve(graph.Limit());
}
@@ -184,24 +184,24 @@ struct NamedTypes {
} // namespace
-void ResolveTypes(Graph& graph, Unification& unification,
- const std::vector<Id>& roots, Metrics& metrics) {
- const Time total(metrics, "resolve.total");
+void ResolveTypes(Runtime& runtime, Graph& graph, Unification& unification,
+ const std::vector<Id>& roots) {
+ const Time total(runtime, "resolve.total");
// collect named types
- NamedTypes named_types(graph, metrics);
+ NamedTypes named_types(runtime, graph);
{
- const Time time(metrics, "resolve.collection");
+ const Time time(runtime, "resolve.collection");
for (const Id& root : roots) {
named_types(root);
}
}
{
- const Time time(metrics, "resolve.unification");
- Counter definition_unified(metrics, "resolve.definition.unified");
- Counter definition_not_unified(metrics, "resolve.definition.not_unified");
- Counter declaration_unified(metrics, "resolve.declaration.unified");
+ const Time time(runtime, "resolve.unification");
+ Counter definition_unified(runtime, "resolve.definition.unified");
+ Counter definition_not_unified(runtime, "resolve.definition.not_unified");
+ Counter declaration_unified(runtime, "resolve.declaration.unified");
for (auto& [_, info] : named_types.type_info) {
// try to unify the type definitions
auto& definitions = info.definitions;
diff --git a/type_resolution.h b/type_resolution.h
index 326b241..1d511d0 100644
--- a/type_resolution.h
+++ b/type_resolution.h
@@ -23,13 +23,13 @@
#include <vector>
#include "graph.h"
-#include "metrics.h"
+#include "runtime.h"
#include "unification.h"
namespace stg {
-void ResolveTypes(Graph& graph, Unification& unification,
- const std::vector<Id>& roots, Metrics& metrics);
+void ResolveTypes(Runtime& runtime, Graph& graph, Unification& unification,
+ const std::vector<Id>& roots);
} // namespace stg
diff --git a/unification.h b/unification.h
index 3f6ee9a..d8fde2e 100644
--- a/unification.h
+++ b/unification.h
@@ -25,7 +25,7 @@
#include <unordered_set>
#include "graph.h"
-#include "metrics.h"
+#include "runtime.h"
#include "substitution.h"
namespace stg {
@@ -34,15 +34,15 @@ namespace stg {
// destruction.
class Unification {
public:
- Unification(Graph& graph, Id start, Metrics& metrics)
+ Unification(Runtime& runtime, Graph& graph, Id start)
: graph_(graph),
start_(start),
mapping_(start),
- metrics_(metrics),
- find_query_(metrics, "unification.find_query"),
- find_halved_(metrics, "unification.find_halved"),
- union_known_(metrics, "unification.union_known"),
- union_unknown_(metrics, "unification.union_unknown") {}
+ runtime_(runtime),
+ find_query_(runtime, "unification.find_query"),
+ find_halved_(runtime, "unification.find_halved"),
+ union_known_(runtime, "unification.union_known"),
+ union_unknown_(runtime, "unification.union_unknown") {}
~Unification() {
if (std::uncaught_exceptions() > 0) {
@@ -50,9 +50,9 @@ class Unification {
return;
}
// apply substitutions to the entire graph
- const Time time(metrics_, "unification.rewrite");
- Counter removed(metrics_, "unification.removed");
- Counter retained(metrics_, "unification.retained");
+ const Time time(runtime_, "unification.rewrite");
+ Counter removed(runtime_, "unification.removed");
+ Counter retained(runtime_, "unification.retained");
auto remap = [&](Id& id) {
Update(id);
};
@@ -118,7 +118,7 @@ class Unification {
Graph& graph_;
Id start_;
DenseIdMapping mapping_;
- Metrics& metrics_;
+ Runtime& runtime_;
Counter find_query_;
Counter find_halved_;
Counter union_known_;