Skip to content

Commit 9fe3bee

Browse files
Nikolai Tillmannfacebook-github-bot
Nikolai Tillmann
authored andcommitted
Making ConcurrentContainers require UnorderedIterable
Summary: Look at ConcurrentContainers.h to see how all concurrent container types are adapted to pull out the iterable functionality. This also adapts *all* uses in the codebase. Reviewed By: agampe Differential Revision: D72023602 fbshipit-source-id: 2630aa312138ee5183c6ed3401cfc495416b098f
1 parent 2ae9fb1 commit 9fe3bee

File tree

82 files changed

+432
-286
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+432
-286
lines changed

analysis/ip-reflection-analysis/IPReflectionAnalysis.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ void IPReflectionAnalysisPass::run_pass(DexStoresVector& stores,
237237
analysis.run();
238238
const auto& summaries = analysis.registry.get_map();
239239
m_result = std::make_shared<Result>();
240-
for (const auto& entry : summaries) {
240+
for (const auto& entry : UnorderedIterable(summaries)) {
241241
(*m_result)[entry.first] = entry.second.get_reflection_sites();
242242
}
243243
if (m_export_results) {

analysis/max-depth/MaxDepthAnalysis.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ void MaxDepthAnalysisPass::run_pass(DexStoresVector& stores,
191191
analysis.run();
192192
m_result = std::make_shared<UnorderedMap<const DexMethod*, int>>();
193193

194-
for (const auto& entry : analysis.registry.get_map()) {
194+
for (const auto& entry : UnorderedIterable(analysis.registry.get_map())) {
195195
if (entry.second.is_value()) {
196196
(*m_result)[entry.first] = entry.second.depth();
197197
}

libredex/BinarySerialization.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class GraphWriter {
8080
template <class NodeContainer>
8181
void write(std::ostream& os, const NodeContainer& nodes) {
8282
// Give each node a unique ID.
83-
for (const auto& node : nodes) {
83+
for (const auto& node : UnorderedIterable(nodes)) {
8484
number_node_recursive(node);
8585
}
8686
// Emit the node label and adjacency list.

libredex/CallGraph.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ RootAndDynamic MultipleCalleeBaseStrategy::get_roots() const {
161161
});
162162
// Gather methods that override or implement external or native methods
163163
// as well.
164-
for (auto& pair : m_method_override_graph.nodes()) {
164+
for (auto& pair : UnorderedIterable(m_method_override_graph.nodes())) {
165165
auto method = pair.first;
166166
if (method->is_external()) {
167167
dynamic_methods.emplace(method);
@@ -254,7 +254,7 @@ RootAndDynamic CompleteCallGraphStrategy::get_roots() const {
254254
}
255255
});
256256
// Gather methods that override or implement external methods
257-
for (auto& pair : m_method_override_graph.nodes()) {
257+
for (auto& pair : UnorderedIterable(m_method_override_graph.nodes())) {
258258
auto method = pair.first;
259259
if (method->is_external()) {
260260
const auto& overriding_methods =
@@ -353,9 +353,8 @@ RootAndDynamic MultipleCalleeStrategy::get_roots() const {
353353
root_and_dynamic.roots.insert(method);
354354
}
355355
};
356-
std::for_each(m_big_virtuals.begin(), m_big_virtuals.end(), add_root);
357-
std::for_each(m_big_virtual_overrides.begin(), m_big_virtual_overrides.end(),
358-
add_root);
356+
unordered_for_each(m_big_virtuals, add_root);
357+
unordered_for_each(m_big_virtual_overrides, add_root);
359358
return root_and_dynamic;
360359
}
361360

libredex/ClassChecker.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "ClassChecker.h"
1111
#include "ClassHierarchy.h"
12+
#include "DeterministicContainers.h"
1213
#include "DexClass.h"
1314
#include "Show.h"
1415
#include "Timer.h"
@@ -21,7 +22,7 @@ void print_failed_things(const Collection& items,
2122
const size_t print_limit,
2223
std::ostringstream* oss) {
2324
size_t counter = 0;
24-
for (auto& fail : items) {
25+
for (auto& fail : UnorderedIterable(items)) {
2526
*oss << show(fail)
2627
<< " (deobfuscated: " << fail->get_deobfuscated_name_or_empty_copy()
2728
<< ")\n";

libredex/ConcurrentContainers.h

Lines changed: 183 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <utility>
2121

2222
#include "Debug.h"
23+
#include "DeterministicContainers.h"
2324
#include "Timer.h"
2425

2526
namespace cc_impl {
@@ -985,6 +986,12 @@ class ConcurrentContainer {
985986
using const_iterator =
986987
cc_impl::ConcurrentContainerIterator<const ConcurrentHashtable, n_slots>;
987988

989+
using key_type = typename Container::key_type;
990+
using value_type = typename iterator::value_type;
991+
using hasher = typename Container::hasher;
992+
using key_equal = typename Container::key_equal;
993+
using difference_type = typename Container::difference_type;
994+
988995
virtual ~ConcurrentContainer() {
989996
auto timer_scope = cc_impl::s_destructor.scope();
990997
if (!cc_impl::is_thread_pool_active() ||
@@ -998,41 +1005,180 @@ class ConcurrentContainer {
9981005
0, n_slots, [this](size_t slot) { m_slots[slot].destroy(); });
9991006
}
10001007

1008+
class FixedIterator;
1009+
1010+
class ConstFixedIterator {
1011+
const_iterator m_entry;
1012+
friend class FixedIterator;
1013+
1014+
public:
1015+
const value_type* operator->() const { return &*m_entry; }
1016+
1017+
const value_type& operator*() const { return *m_entry; }
1018+
1019+
bool operator==(const FixedIterator& other) const {
1020+
return m_entry == other.m_entry;
1021+
}
1022+
1023+
bool operator!=(const FixedIterator& other) const {
1024+
return m_entry != other.m_entry;
1025+
}
1026+
1027+
bool operator==(const ConstFixedIterator& other) const {
1028+
return m_entry == other.m_entry;
1029+
}
1030+
1031+
bool operator!=(const ConstFixedIterator& other) const {
1032+
return m_entry != other.m_entry;
1033+
}
1034+
1035+
explicit ConstFixedIterator(const_iterator entry) : m_entry(entry) {}
1036+
1037+
const_iterator _internal_unsafe_unwrap() { return m_entry; }
1038+
};
1039+
1040+
class FixedIterator {
1041+
iterator m_entry;
1042+
friend class ConstFixedIterator;
1043+
1044+
public:
1045+
value_type* operator->() { return &*m_entry; }
1046+
1047+
value_type& operator*() { return *m_entry; }
1048+
1049+
bool operator==(const FixedIterator& other) const {
1050+
return m_entry == other.m_entry;
1051+
}
1052+
1053+
bool operator!=(const FixedIterator& other) const {
1054+
return m_entry != other.m_entry;
1055+
}
1056+
1057+
bool operator==(const ConstFixedIterator& other) const {
1058+
return m_entry == other.m_entry;
1059+
}
1060+
1061+
bool operator!=(const ConstFixedIterator& other) const {
1062+
return m_entry != other.m_entry;
1063+
}
1064+
1065+
explicit FixedIterator(iterator entry) : m_entry(entry) {}
1066+
1067+
iterator _internal_unsafe_unwrap() { return m_entry; }
1068+
};
1069+
1070+
// TODO: Make extra non-deterministic in debug builds
1071+
class UnorderedIterable {
1072+
ConcurrentHashtable* m_slots;
1073+
1074+
public:
1075+
explicit UnorderedIterable(ConcurrentHashtable* slots) : m_slots(slots) {}
1076+
1077+
iterator begin() { return iterator(&m_slots[0], 0, m_slots[0].begin()); }
1078+
1079+
iterator end() { return iterator(&m_slots[0]); }
1080+
1081+
const_iterator begin() const {
1082+
const auto* cslots = m_slots;
1083+
return const_iterator(&cslots[0], 0, cslots[0].begin());
1084+
}
1085+
1086+
const_iterator end() const {
1087+
const auto* cslots = m_slots;
1088+
return const_iterator(&cslots[0]);
1089+
}
1090+
1091+
const_iterator cbegin() const { return begin(); }
1092+
1093+
const_iterator cend() const { return end(); }
1094+
1095+
iterator find(const Key& key) {
1096+
size_t slot = Hash()(key) % n_slots;
1097+
const auto& it = m_slots[slot].find(key);
1098+
if (it == m_slots[slot].end()) {
1099+
return end();
1100+
}
1101+
return iterator(&m_slots[0], slot, it);
1102+
}
1103+
1104+
const_iterator find(const Key& key) const {
1105+
size_t slot = Hash()(key) % n_slots;
1106+
const auto* cslots = m_slots;
1107+
const auto& it = cslots[slot].find(key);
1108+
if (it == cslots[slot].end()) {
1109+
return end();
1110+
}
1111+
return const_iterator(&cslots[0], slot, it);
1112+
}
1113+
};
1114+
1115+
// TODO: Make extra non-deterministic in debug builds
1116+
class ConstUnorderedIterable {
1117+
const ConcurrentHashtable* m_slots;
1118+
1119+
public:
1120+
explicit ConstUnorderedIterable(const ConcurrentHashtable* slots)
1121+
: m_slots(slots) {}
1122+
1123+
const_iterator begin() const {
1124+
return const_iterator(&m_slots[0], 0, m_slots[0].begin());
1125+
}
1126+
1127+
const_iterator end() const { return const_iterator(&m_slots[0]); }
1128+
1129+
const_iterator cbegin() const { return begin(); }
1130+
1131+
const_iterator cend() const { return end(); }
1132+
1133+
const_iterator find(const Key& key) const {
1134+
size_t slot = Hash()(key) % n_slots;
1135+
const auto& it = m_slots[slot].find(key);
1136+
if (it == m_slots[slot].end()) {
1137+
return end();
1138+
}
1139+
return const_iterator(&m_slots[0], slot, it);
1140+
}
1141+
};
1142+
10011143
/*
10021144
* Using iterators or accessor functions while the container is concurrently
10031145
* modified will result in undefined behavior.
10041146
*/
10051147

1006-
iterator begin() { return iterator(&m_slots[0], 0, m_slots[0].begin()); }
1148+
UnorderedIterable _internal_unordered_iterable() {
1149+
return UnorderedIterable(m_slots);
1150+
}
10071151

1008-
iterator end() { return iterator(&m_slots[0]); }
1152+
ConstUnorderedIterable _internal_unordered_iterable() const {
1153+
return ConstUnorderedIterable(m_slots);
1154+
}
10091155

1010-
const_iterator begin() const {
1011-
return const_iterator(&m_slots[0], 0, m_slots[0].begin());
1156+
FixedIterator _internal_unordered_any() {
1157+
return FixedIterator(_internal_unordered_iterable().begin());
1158+
}
1159+
1160+
ConstFixedIterator _internal_unordered_any() const {
1161+
return ConstFixedIterator(_internal_unordered_iterable().begin());
10121162
}
10131163

1014-
const_iterator end() const { return const_iterator(&m_slots[0]); }
1164+
FixedIterator find(const Key& key) {
1165+
return FixedIterator(_internal_unordered_iterable().find(key));
1166+
}
10151167

1016-
const_iterator cbegin() const { return begin(); }
1168+
ConstFixedIterator find(const Key& key) const {
1169+
return ConstFixedIterator(_internal_unordered_iterable().find(key));
1170+
}
10171171

1018-
const_iterator cend() const { return end(); }
1172+
ConstFixedIterator end() const {
1173+
return ConstFixedIterator(_internal_unordered_iterable().cend());
1174+
}
10191175

1020-
iterator find(const Key& key) {
1021-
size_t slot = Hash()(key) % n_slots;
1022-
const auto& it = m_slots[slot].find(key);
1023-
if (it == m_slots[slot].end()) {
1024-
return end();
1025-
}
1026-
return iterator(&m_slots[0], slot, it);
1176+
FixedIterator end() {
1177+
return FixedIterator(_internal_unordered_iterable().end());
10271178
}
10281179

1029-
const_iterator find(const Key& key) const {
1030-
size_t slot = Hash()(key) % n_slots;
1031-
const auto& it = m_slots[slot].find(key);
1032-
if (it == m_slots[slot].end()) {
1033-
return end();
1034-
}
1035-
return const_iterator(&m_slots[0], slot, it);
1180+
ConstFixedIterator cend() const {
1181+
return ConstFixedIterator(_internal_unordered_iterable().cend());
10361182
}
10371183

10381184
/*
@@ -1167,7 +1313,8 @@ template <typename Key,
11671313
size_t n_slots = cc_impl::kDefaultSlots>
11681314
class ConcurrentMap final
11691315
: public ConcurrentContainer<std::unordered_map<Key, Value, Hash, KeyEqual>,
1170-
n_slots> {
1316+
n_slots>,
1317+
public UnorderedBase<ConcurrentMap<Key, Value, Hash, KeyEqual, n_slots>> {
11711318
public:
11721319
using Base =
11731320
ConcurrentContainer<std::unordered_map<Key, Value, Hash, KeyEqual>,
@@ -1181,6 +1328,8 @@ class ConcurrentMap final
11811328

11821329
using KeyValuePair = typename Base::Value;
11831330

1331+
using mapped_type = Value;
1332+
11841333
ConcurrentMap() = default;
11851334

11861335
ConcurrentMap(const ConcurrentMap& container) noexcept : Base(container) {}
@@ -1482,7 +1631,9 @@ template <typename Key,
14821631
size_t n_slots = cc_impl::kDefaultSlots>
14831632
class InsertOnlyConcurrentMap final
14841633
: public ConcurrentContainer<std::unordered_map<Key, Value, Hash, KeyEqual>,
1485-
n_slots> {
1634+
n_slots>,
1635+
public UnorderedBase<
1636+
InsertOnlyConcurrentMap<Key, Value, Hash, KeyEqual, n_slots>> {
14861637
public:
14871638
using Base =
14881639
ConcurrentContainer<std::unordered_map<Key, Value, Hash, KeyEqual>,
@@ -1495,6 +1646,8 @@ class InsertOnlyConcurrentMap final
14951646

14961647
using KeyValuePair = typename Base::Value;
14971648

1649+
using mapped_type = Value;
1650+
14981651
InsertOnlyConcurrentMap() = default;
14991652

15001653
InsertOnlyConcurrentMap(const InsertOnlyConcurrentMap& container) noexcept
@@ -1782,7 +1935,8 @@ template <typename Key,
17821935
class AtomicMap final
17831936
: public ConcurrentContainer<
17841937
std::unordered_map<Key, std::atomic<Value>, Hash, KeyEqual>,
1785-
n_slots> {
1938+
n_slots>,
1939+
public UnorderedBase<AtomicMap<Key, Value, Hash, KeyEqual, n_slots>> {
17861940
public:
17871941
using Base = ConcurrentContainer<
17881942
std::unordered_map<Key, std::atomic<Value>, Hash, KeyEqual>,
@@ -1975,7 +2129,8 @@ template <typename Key,
19752129
size_t n_slots = cc_impl::kDefaultSlots>
19762130
class ConcurrentSet final
19772131
: public ConcurrentContainer<std::unordered_set<Key, Hash, KeyEqual>,
1978-
n_slots> {
2132+
n_slots>,
2133+
public UnorderedBase<ConcurrentSet<Key, Hash, KeyEqual, n_slots>> {
19792134
public:
19802135
using Base =
19812136
ConcurrentContainer<std::unordered_set<Key, Hash, KeyEqual>, n_slots>;
@@ -2056,7 +2211,9 @@ template <typename Key,
20562211
size_t n_slots = cc_impl::kDefaultSlots>
20572212
class InsertOnlyConcurrentSet final
20582213
: public ConcurrentContainer<std::unordered_set<Key, Hash, KeyEqual>,
2059-
n_slots> {
2214+
n_slots>,
2215+
public UnorderedBase<
2216+
InsertOnlyConcurrentSet<Key, Hash, KeyEqual, n_slots>> {
20602217
public:
20612218
using Base =
20622219
ConcurrentContainer<std::unordered_set<Key, Hash, KeyEqual>, n_slots>;

libredex/DeterministicContainers.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
* - `unordered_copy(collection, ...)` / `unordered_copy_if(collection, ...)`
4242
* provides the same functionality as `std::copy` / `std::copy_if`, except
4343
* that it works on (potentially) unordered collections.
44+
* - `unordered_count(collection, ...)` / `unordered_count_if(collection, ...)`
45+
* provides the same functionality as `std::count` / `std::count_if`, except
46+
* that it works on (potentially) unordered collections.
4447
* - `unordered_erase_if(collection, ...)` provides the same functionality as
4548
* `std::erase_if`, except that it works on (potentially) unordered
4649
* collections.
@@ -897,6 +900,20 @@ OutputIt unordered_copy_if(const Collection& collection,
897900
return std::copy_if(ui.begin(), ui.end(), target, std::move(pred));
898901
}
899902

903+
template <class Collection, class T>
904+
typename Collection::difference_type unordered_count(
905+
const Collection& collection, const T& value) {
906+
auto ui = UnorderedIterable(collection);
907+
return std::count(ui.begin(), ui.end(), value);
908+
}
909+
910+
template <class Collection, class UnaryPred>
911+
typename Collection::difference_type unordered_count_if(
912+
const Collection& collection, UnaryPred pred) {
913+
auto ui = UnorderedIterable(collection);
914+
return std::count_if(ui.begin(), ui.end(), std::move(pred));
915+
}
916+
900917
template <class Collection, typename Pred>
901918
size_t unordered_erase_if(Collection& collection, const Pred& pred) {
902919
size_t removed = 0;

0 commit comments

Comments
 (0)