1 /* 2 * Copyright (C) 2015 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 #include <algorithm> 18 #include <ostream> 19 20 #include "compiled_method_storage.h" 21 22 #include "base/logging.h" 23 #include "compiled_method.h" 24 #include "thread-inl.h" 25 #include "utils.h" 26 #include "utils/dedupe_set-inl.h" 27 #include "utils/swap_space.h" 28 29 namespace art { 30 31 namespace { // anonymous namespace 32 33 template <typename T> 34 const LengthPrefixedArray<T>* CopyArray(SwapSpace* swap_space, const ArrayRef<const T>& array) { 35 DCHECK(!array.empty()); 36 SwapAllocator<uint8_t> allocator(swap_space); 37 void* storage = allocator.allocate(LengthPrefixedArray<T>::ComputeSize(array.size())); 38 LengthPrefixedArray<T>* array_copy = new(storage) LengthPrefixedArray<T>(array.size()); 39 std::copy(array.begin(), array.end(), array_copy->begin()); 40 return array_copy; 41 } 42 43 template <typename T> 44 void ReleaseArray(SwapSpace* swap_space, const LengthPrefixedArray<T>* array) { 45 SwapAllocator<uint8_t> allocator(swap_space); 46 size_t size = LengthPrefixedArray<T>::ComputeSize(array->size()); 47 array->~LengthPrefixedArray<T>(); 48 allocator.deallocate(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(array)), size); 49 } 50 51 } // anonymous namespace 52 53 template <typename T, typename DedupeSetType> 54 inline const LengthPrefixedArray<T>* CompiledMethodStorage::AllocateOrDeduplicateArray( 55 const ArrayRef<const T>& data, 56 DedupeSetType* dedupe_set) { 57 if (data.empty()) { 58 return nullptr; 59 } else if (!DedupeEnabled()) { 60 return CopyArray(swap_space_.get(), data); 61 } else { 62 return dedupe_set->Add(Thread::Current(), data); 63 } 64 } 65 66 template <typename T> 67 inline void CompiledMethodStorage::ReleaseArrayIfNotDeduplicated( 68 const LengthPrefixedArray<T>* array) { 69 if (array != nullptr && !DedupeEnabled()) { 70 ReleaseArray(swap_space_.get(), array); 71 } 72 } 73 74 template <typename ContentType> 75 class CompiledMethodStorage::DedupeHashFunc { 76 private: 77 static constexpr bool kUseMurmur3Hash = true; 78 79 public: 80 size_t operator()(const ArrayRef<ContentType>& array) const { 81 const uint8_t* data = reinterpret_cast<const uint8_t*>(array.data()); 82 // TODO: More reasonable assertion. 83 // static_assert(IsPowerOfTwo(sizeof(ContentType)), 84 // "ContentType is not power of two, don't know whether array layout is as assumed"); 85 uint32_t len = sizeof(ContentType) * array.size(); 86 if (kUseMurmur3Hash) { 87 static constexpr uint32_t c1 = 0xcc9e2d51; 88 static constexpr uint32_t c2 = 0x1b873593; 89 static constexpr uint32_t r1 = 15; 90 static constexpr uint32_t r2 = 13; 91 static constexpr uint32_t m = 5; 92 static constexpr uint32_t n = 0xe6546b64; 93 94 uint32_t hash = 0; 95 96 const int nblocks = len / 4; 97 typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t; 98 const unaligned_uint32_t *blocks = reinterpret_cast<const uint32_t*>(data); 99 int i; 100 for (i = 0; i < nblocks; i++) { 101 uint32_t k = blocks[i]; 102 k *= c1; 103 k = (k << r1) | (k >> (32 - r1)); 104 k *= c2; 105 106 hash ^= k; 107 hash = ((hash << r2) | (hash >> (32 - r2))) * m + n; 108 } 109 110 const uint8_t *tail = reinterpret_cast<const uint8_t*>(data + nblocks * 4); 111 uint32_t k1 = 0; 112 113 switch (len & 3) { 114 case 3: 115 k1 ^= tail[2] << 16; 116 FALLTHROUGH_INTENDED; 117 case 2: 118 k1 ^= tail[1] << 8; 119 FALLTHROUGH_INTENDED; 120 case 1: 121 k1 ^= tail[0]; 122 123 k1 *= c1; 124 k1 = (k1 << r1) | (k1 >> (32 - r1)); 125 k1 *= c2; 126 hash ^= k1; 127 } 128 129 hash ^= len; 130 hash ^= (hash >> 16); 131 hash *= 0x85ebca6b; 132 hash ^= (hash >> 13); 133 hash *= 0xc2b2ae35; 134 hash ^= (hash >> 16); 135 136 return hash; 137 } else { 138 size_t hash = 0x811c9dc5; 139 for (uint32_t i = 0; i < len; ++i) { 140 hash = (hash * 16777619) ^ data[i]; 141 } 142 hash += hash << 13; 143 hash ^= hash >> 7; 144 hash += hash << 3; 145 hash ^= hash >> 17; 146 hash += hash << 5; 147 return hash; 148 } 149 } 150 }; 151 152 template <typename T> 153 class CompiledMethodStorage::LengthPrefixedArrayAlloc { 154 public: 155 explicit LengthPrefixedArrayAlloc(SwapSpace* swap_space) 156 : swap_space_(swap_space) { 157 } 158 159 const LengthPrefixedArray<T>* Copy(const ArrayRef<const T>& array) { 160 return CopyArray(swap_space_, array); 161 } 162 163 void Destroy(const LengthPrefixedArray<T>* array) { 164 ReleaseArray(swap_space_, array); 165 } 166 167 private: 168 SwapSpace* const swap_space_; 169 }; 170 171 CompiledMethodStorage::CompiledMethodStorage(int swap_fd) 172 : swap_space_(swap_fd == -1 ? nullptr : new SwapSpace(swap_fd, 10 * MB)), 173 dedupe_enabled_(true), 174 dedupe_code_("dedupe code", LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())), 175 dedupe_src_mapping_table_("dedupe source mapping table", 176 LengthPrefixedArrayAlloc<SrcMapElem>(swap_space_.get())), 177 dedupe_vmap_table_("dedupe vmap table", 178 LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())), 179 dedupe_cfi_info_("dedupe cfi info", LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())), 180 dedupe_linker_patches_("dedupe cfi info", 181 LengthPrefixedArrayAlloc<LinkerPatch>(swap_space_.get())) { 182 } 183 184 CompiledMethodStorage::~CompiledMethodStorage() { 185 // All done by member destructors. 186 } 187 188 void CompiledMethodStorage::DumpMemoryUsage(std::ostream& os, bool extended) const { 189 if (swap_space_.get() != nullptr) { 190 const size_t swap_size = swap_space_->GetSize(); 191 os << " swap=" << PrettySize(swap_size) << " (" << swap_size << "B)"; 192 } 193 if (extended) { 194 Thread* self = Thread::Current(); 195 os << "\nCode dedupe: " << dedupe_code_.DumpStats(self); 196 os << "\nVmap table dedupe: " << dedupe_vmap_table_.DumpStats(self); 197 os << "\nCFI info dedupe: " << dedupe_cfi_info_.DumpStats(self); 198 } 199 } 200 201 const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateCode( 202 const ArrayRef<const uint8_t>& code) { 203 return AllocateOrDeduplicateArray(code, &dedupe_code_); 204 } 205 206 void CompiledMethodStorage::ReleaseCode(const LengthPrefixedArray<uint8_t>* code) { 207 ReleaseArrayIfNotDeduplicated(code); 208 } 209 210 const LengthPrefixedArray<SrcMapElem>* CompiledMethodStorage::DeduplicateSrcMappingTable( 211 const ArrayRef<const SrcMapElem>& src_map) { 212 return AllocateOrDeduplicateArray(src_map, &dedupe_src_mapping_table_); 213 } 214 215 void CompiledMethodStorage::ReleaseSrcMappingTable(const LengthPrefixedArray<SrcMapElem>* src_map) { 216 ReleaseArrayIfNotDeduplicated(src_map); 217 } 218 219 const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateVMapTable( 220 const ArrayRef<const uint8_t>& table) { 221 return AllocateOrDeduplicateArray(table, &dedupe_vmap_table_); 222 } 223 224 void CompiledMethodStorage::ReleaseVMapTable(const LengthPrefixedArray<uint8_t>* table) { 225 ReleaseArrayIfNotDeduplicated(table); 226 } 227 228 const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateCFIInfo( 229 const ArrayRef<const uint8_t>& cfi_info) { 230 return AllocateOrDeduplicateArray(cfi_info, &dedupe_cfi_info_); 231 } 232 233 void CompiledMethodStorage::ReleaseCFIInfo(const LengthPrefixedArray<uint8_t>* cfi_info) { 234 ReleaseArrayIfNotDeduplicated(cfi_info); 235 } 236 237 const LengthPrefixedArray<LinkerPatch>* CompiledMethodStorage::DeduplicateLinkerPatches( 238 const ArrayRef<const LinkerPatch>& linker_patches) { 239 return AllocateOrDeduplicateArray(linker_patches, &dedupe_linker_patches_); 240 } 241 242 void CompiledMethodStorage::ReleaseLinkerPatches( 243 const LengthPrefixedArray<LinkerPatch>* linker_patches) { 244 ReleaseArrayIfNotDeduplicated(linker_patches); 245 } 246 247 } // namespace art 248