huangs | 7a2fea25 | 2015-12-08 01:27:46 | [diff] [blame] | 1 | // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef COURGETTE_LABEL_MANAGER_H_ |
| 6 | #define COURGETTE_LABEL_MANAGER_H_ |
| 7 | |
avi | ab98dcc9 | 2015-12-21 19:35:33 | [diff] [blame] | 8 | #include <stddef.h> |
| 9 | #include <stdint.h> |
| 10 | |
huangs | bb4b8a9 | 2016-01-19 22:09:03 | [diff] [blame] | 11 | #include <map> |
huangs | 7a2fea25 | 2015-12-08 01:27:46 | [diff] [blame] | 12 | #include <vector> |
| 13 | |
huangs | 0827d11c | 2016-01-08 18:16:37 | [diff] [blame] | 14 | #include "base/gtest_prod_util.h" |
huangs | 7a2fea25 | 2015-12-08 01:27:46 | [diff] [blame] | 15 | #include "base/macros.h" |
| 16 | #include "courgette/image_utils.h" |
| 17 | |
| 18 | namespace courgette { |
| 19 | |
huangs | 2913c85 | 2016-01-06 01:34:44 | [diff] [blame] | 20 | using LabelVector = std::vector<Label>; |
huangs | bb4b8a9 | 2016-01-19 22:09:03 | [diff] [blame] | 21 | using RVAToLabel = std::map<RVA, Label*>; |
huangs | 2913c85 | 2016-01-06 01:34:44 | [diff] [blame] | 22 | |
huangs | 9faa303 | 2016-04-07 03:37:11 | [diff] [blame] | 23 | // A container to store and manage Label instances, dedicated to reducing peak |
| 24 | // memory usage. To this end we preallocate Label instances in bulk, and |
| 25 | // carefully control transient memory usage when initializing Labels. |
huangs | 7a2fea25 | 2015-12-08 01:27:46 | [diff] [blame] | 26 | class LabelManager { |
| 27 | public: |
huangs | 2913c85 | 2016-01-06 01:34:44 | [diff] [blame] | 28 | // A helper class to heuristically complete index assignment for a list of |
| 29 | // Labels that have partially assigned indexes. |
| 30 | // Goal: An address table compresses best when each index is associated with |
| 31 | // an address that is slightly larger than the previous index. |
| 32 | // For example, suppose we have RVAs |
| 33 | // [0x0000, 0x0070, 0x00E0, 0x0150]. |
| 34 | // Consider candidate (RVA, index) assignments A and B: |
| 35 | // A: [(0x0000, 0), (0x0070, 1), (0x00E0, 2), (0x0150, 3)], |
| 36 | // B: [(0x0000, 2), (0x0070, 1), (0x00E0, 0), (0x0150, 3)]. |
| 37 | // To form the address table, we first sort by indexes: |
| 38 | // A: [(0x0000, 0), (0x0070, 1), (0x00E0, 2), (0x0150, 3)], |
| 39 | // B: [(0x00E0, 0), (0x0070, 1), (0x0000, 2), (0x0150, 3)]. |
| 40 | // Then we extract the RVAs for storage: |
| 41 | // A: [0x0000, 0x0070, 0x00E0, 0x0150], |
| 42 | // B: [0x00E0, 0x0070, 0x0000, 0x0150]. |
| 43 | // Clearly A compresses better than B under (signed) delta encoding. |
| 44 | // In Courgette-gen, an assignment algorithm (subclass of AdjustmentMethod) |
| 45 | // creates partial and arbitrary index assignments (to attempt to match one |
| 46 | // file against another). So the sorted case (like A) won't happen in general. |
| 47 | // Our helper class fills in the missing assignments by creating runs of |
| 48 | // consecutive indexes, so once RVAs are sorted by these indexes we'd reduce |
| 49 | // distances between successive RVAs. |
| 50 | class SimpleIndexAssigner { |
| 51 | public: |
huangs | 9faa303 | 2016-04-07 03:37:11 | [diff] [blame] | 52 | explicit SimpleIndexAssigner(LabelVector* labels); |
huangs | 2913c85 | 2016-01-06 01:34:44 | [diff] [blame] | 53 | ~SimpleIndexAssigner(); |
| 54 | |
| 55 | // Scans forward to assign successive indexes to Labels, using existing |
| 56 | // indexes as start-anchors. |
| 57 | void DoForwardFill(); |
| 58 | |
| 59 | // Scans backward to assign successive indexes to Labels, using existing |
| 60 | // indexes as end-anchors. |
| 61 | void DoBackwardFill(); |
| 62 | |
| 63 | // Assigns all unsigned indexes using what's available, disregarding current |
| 64 | // Label assignment. |
| 65 | void DoInFill(); |
| 66 | |
| 67 | private: |
huangs | 9faa303 | 2016-04-07 03:37:11 | [diff] [blame] | 68 | // The target LabelVector, owned by the caller. |
huangs | 2913c85 | 2016-01-06 01:34:44 | [diff] [blame] | 69 | LabelVector* labels_; |
| 70 | |
| 71 | // A bound on indexes. |
| 72 | int num_index_ = 0; |
| 73 | |
| 74 | // Tracker for index usage to ensure uniqueness of indexes. |
| 75 | std::vector<bool> available_; |
| 76 | |
| 77 | DISALLOW_COPY_AND_ASSIGN(SimpleIndexAssigner); |
| 78 | }; |
| 79 | |
huangs | 9faa303 | 2016-04-07 03:37:11 | [diff] [blame] | 80 | LabelManager(); |
| 81 | ~LabelManager(); |
huangs | 7a2fea25 | 2015-12-08 01:27:46 | [diff] [blame] | 82 | |
huangs | 9faa303 | 2016-04-07 03:37:11 | [diff] [blame] | 83 | // Returns an exclusive upper bound for all assigned indexes in |labels|. |
| 84 | static int GetLabelIndexBound(const LabelVector& labels); |
| 85 | |
| 86 | // Accessor to stored Label instances. |
| 87 | const LabelVector& Labels() const { return labels_; } |
| 88 | |
| 89 | // Efficiently searches for a Label that targets |rva|. Returns the pointer to |
| 90 | // the stored Label instance if found, or null otherwise. Non-const to support |
| 91 | // implementations that allocate-on-read. |
| 92 | Label* Find(RVA rva); |
| 93 | |
| 94 | // Removes Label instances whose |count_| is less than |count_threshold|. |
| 95 | void RemoveUnderusedLabels(int32_t count_threshold); |
| 96 | |
| 97 | // Resets all indexes to an unassigned state. |
| 98 | void UnassignIndexes(); |
| 99 | |
| 100 | // Assigns indexes to successive integers from 0, ordered by RVA. |
| 101 | void DefaultAssignIndexes(); |
| 102 | |
| 103 | // Assigns indexes to any Label instances that don't have one yet. |
| 104 | void AssignRemainingIndexes(); |
huangs | 0827d11c | 2016-01-08 18:16:37 | [diff] [blame] | 105 | |
| 106 | // Populates |labels_| using RVAs from |rva_visitor|. Each distinct RVA from |
huangs | 7a2fea25 | 2015-12-08 01:27:46 | [diff] [blame] | 107 | // |rva_visitor| yields a Label with |rva_| assigned as the RVA, and |count_| |
| 108 | // assigned as the repeat. |
| 109 | void Read(RvaVisitor* rva_visitor); |
| 110 | |
huangs | 7a2fea25 | 2015-12-08 01:27:46 | [diff] [blame] | 111 | protected: |
huangs | 9faa303 | 2016-04-07 03:37:11 | [diff] [blame] | 112 | FRIEND_TEST_ALL_PREFIXES(LabelManagerTest, TrivialAssign); |
| 113 | FRIEND_TEST_ALL_PREFIXES(LabelManagerTest, AssignRemainingIndexes); |
| 114 | |
huangs | 7a2fea25 | 2015-12-08 01:27:46 | [diff] [blame] | 115 | // The main list of Label instances, sorted by the |rva_| member. |
huangs | 2913c85 | 2016-01-06 01:34:44 | [diff] [blame] | 116 | LabelVector labels_; |
huangs | 7a2fea25 | 2015-12-08 01:27:46 | [diff] [blame] | 117 | |
| 118 | private: |
huangs | 9faa303 | 2016-04-07 03:37:11 | [diff] [blame] | 119 | DISALLOW_COPY_AND_ASSIGN(LabelManager); |
huangs | 7a2fea25 | 2015-12-08 01:27:46 | [diff] [blame] | 120 | }; |
| 121 | |
| 122 | } // namespace courgette |
| 123 | |
| 124 | #endif // COURGETTE_LABEL_MANAGER_H_ |