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 <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