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