1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_RUNTIME_DEX_REFERENCE_COLLECTION_H_
18 #define ART_RUNTIME_DEX_REFERENCE_COLLECTION_H_
19 
20 #include <map>
21 #include <vector>
22 
23 #include "base/macros.h"
24 
25 namespace art {
26 
27 class DexFile;
28 
29 // Collection of dex references that is more memory efficient than a vector of <dex, index> pairs.
30 // Also allows quick lookups of all of the references for a single dex.
31 template <class IndexType, template<typename Type> class Allocator>
32 class DexReferenceCollection {
33  public:
34   using VectorAllocator = Allocator<IndexType>;
35   using IndexVector = std::vector<IndexType, VectorAllocator>;
36   using MapAllocator = Allocator<std::pair<const DexFile*, IndexVector>>;
37   using DexFileMap = std::map<
38       const DexFile*,
39       IndexVector,
40       std::less<const DexFile*>,
41       Allocator<std::pair<const DexFile* const, IndexVector>>>;
42 
43   DexReferenceCollection(const MapAllocator& map_allocator = MapAllocator(),
44                          const VectorAllocator& vector_allocator = VectorAllocator())
map_(map_allocator)45       : map_(map_allocator),
46         vector_allocator_(vector_allocator) {}
47 
AddReference(const DexFile * dex,IndexType index)48   void AddReference(const DexFile* dex, IndexType index) {
49     GetOrInsertVector(dex)->push_back(index);
50   }
51 
GetMap()52   DexFileMap& GetMap() {
53     return map_;
54   }
55 
NumReferences()56   size_t NumReferences() const {
57     size_t ret = 0;
58     for (auto&& pair : map_) {
59       ret += pair.second.size();
60     }
61     return ret;
62   }
63 
64  private:
65   DexFileMap map_;
66   const DexFile* current_dex_file_ = nullptr;
67   IndexVector* current_vector_ = nullptr;
68   VectorAllocator vector_allocator_;
69 
GetOrInsertVector(const DexFile * dex)70   ALWAYS_INLINE IndexVector* GetOrInsertVector(const DexFile* dex) {
71     // Optimize for adding to same vector in succession, the cached dex file and vector aims to
72     // prevent map lookups.
73     if (UNLIKELY(current_dex_file_ != dex)) {
74       // There is an assumption that constructing an empty vector wont do any allocations. If this
75       // incorrect, this might leak for the arena case.
76       current_vector_ = &map_.emplace(dex, IndexVector(vector_allocator_)).first->second;
77       current_dex_file_ = dex;
78     }
79     return current_vector_;
80   }
81 };
82 
83 }  // namespace art
84 
85 #endif  // ART_RUNTIME_DEX_REFERENCE_COLLECTION_H_
86