Home | History | Annotate | Download | only in driver
      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_method_info_("dedupe method info",
    176                           LengthPrefixedArrayAlloc<uint8_t>(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<uint8_t>* CompiledMethodStorage::DeduplicateMethodInfo(
    211     const ArrayRef<const uint8_t>& src_map) {
    212   return AllocateOrDeduplicateArray(src_map, &dedupe_method_info_);
    213 }
    214 
    215 void CompiledMethodStorage::ReleaseMethodInfo(const LengthPrefixedArray<uint8_t>* method_info) {
    216   ReleaseArrayIfNotDeduplicated(method_info);
    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