1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef PANDA_LIBPANDAFILE_PANDA_CACHE_H_ 17 #define PANDA_LIBPANDAFILE_PANDA_CACHE_H_ 18 19 #include "file.h" 20 #include "os/mutex.h" 21 #include "libpandabase/utils/math_helpers.h" 22 23 #include <atomic> 24 #include <vector> 25 26 namespace panda { 27 28 class Method; 29 class Field; 30 class Class; 31 32 namespace panda_file { 33 34 // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions, hicpp-special-member-functions) 35 class PandaCache { 36 public: 37 struct MethodCachePair { 38 File::EntityId id_; 39 Method *ptr_ {nullptr}; 40 }; 41 42 struct FieldCachePair { 43 File::EntityId id_; 44 Field *ptr_ {nullptr}; 45 }; 46 47 struct ClassCachePair { 48 File::EntityId id_; 49 Class *ptr_ {nullptr}; 50 }; 51 PandaCache()52 PandaCache() 53 : METHOD_CACHE_SIZE(DEFAULT_METHOD_CACHE_SIZE), 54 FIELD_CACHE_SIZE(DEFAULT_FIELD_CACHE_SIZE), 55 CLASS_CACHE_SIZE(DEFAULT_CLASS_CACHE_SIZE) 56 { 57 method_cache_.resize(METHOD_CACHE_SIZE, MethodCachePair()); 58 field_cache_.resize(FIELD_CACHE_SIZE, FieldCachePair()); 59 class_cache_.resize(CLASS_CACHE_SIZE, ClassCachePair()); 60 } 61 62 ~PandaCache() = default; 63 GetMethodIndex(File::EntityId id)64 inline uint32_t GetMethodIndex(File::EntityId id) const 65 { 66 return panda::helpers::math::PowerOfTwoTableSlot(id.GetOffset(), METHOD_CACHE_SIZE); 67 } 68 GetFieldIndex(File::EntityId id)69 inline uint32_t GetFieldIndex(File::EntityId id) const 70 { 71 // lowest one or two bits are very likely same between different fields 72 return panda::helpers::math::PowerOfTwoTableSlot(id.GetOffset(), FIELD_CACHE_SIZE, 2U); 73 } 74 GetClassIndex(File::EntityId id)75 inline uint32_t GetClassIndex(File::EntityId id) const 76 { 77 return panda::helpers::math::PowerOfTwoTableSlot(id.GetOffset(), CLASS_CACHE_SIZE); 78 } 79 GetMethodFromCache(File::EntityId id)80 inline Method *GetMethodFromCache(File::EntityId id) const 81 { 82 uint32_t index = GetMethodIndex(id); 83 auto *pair_ptr = 84 reinterpret_cast<std::atomic<MethodCachePair> *>(reinterpret_cast<uintptr_t>(&(method_cache_[index]))); 85 auto pair = pair_ptr->load(std::memory_order_acquire); 86 TSAN_ANNOTATE_HAPPENS_AFTER(pair_ptr); 87 if (pair.id_ == id) { 88 return pair.ptr_; 89 } 90 return nullptr; 91 } 92 SetMethodCache(File::EntityId id,Method * method)93 inline void SetMethodCache(File::EntityId id, Method *method) 94 { 95 MethodCachePair pair; 96 pair.id_ = id; 97 pair.ptr_ = method; 98 uint32_t index = GetMethodIndex(id); 99 auto *pair_ptr = 100 reinterpret_cast<std::atomic<MethodCachePair> *>(reinterpret_cast<uintptr_t>(&(method_cache_[index]))); 101 TSAN_ANNOTATE_HAPPENS_BEFORE(pair_ptr); 102 pair_ptr->store(pair, std::memory_order_release); 103 } 104 GetFieldFromCache(File::EntityId id)105 inline Field *GetFieldFromCache(File::EntityId id) const 106 { 107 uint32_t index = GetFieldIndex(id); 108 auto *pair_ptr = 109 reinterpret_cast<std::atomic<FieldCachePair> *>(reinterpret_cast<uintptr_t>(&(field_cache_[index]))); 110 auto pair = pair_ptr->load(std::memory_order_acquire); 111 TSAN_ANNOTATE_HAPPENS_AFTER(pair_ptr); 112 if (pair.id_ == id) { 113 return pair.ptr_; 114 } 115 return nullptr; 116 } 117 SetFieldCache(File::EntityId id,Field * field)118 inline void SetFieldCache(File::EntityId id, Field *field) 119 { 120 uint32_t index = GetFieldIndex(id); 121 auto *pair_ptr = 122 reinterpret_cast<std::atomic<FieldCachePair> *>(reinterpret_cast<uintptr_t>(&(field_cache_[index]))); 123 FieldCachePair pair; 124 pair.id_ = id; 125 pair.ptr_ = field; 126 TSAN_ANNOTATE_HAPPENS_BEFORE(pair_ptr); 127 pair_ptr->store(pair, std::memory_order_release); 128 } 129 GetClassFromCache(File::EntityId id)130 inline Class *GetClassFromCache(File::EntityId id) const 131 { 132 uint32_t index = GetClassIndex(id); 133 auto *pair_ptr = 134 reinterpret_cast<std::atomic<ClassCachePair> *>(reinterpret_cast<uintptr_t>(&(class_cache_[index]))); 135 auto pair = pair_ptr->load(std::memory_order_acquire); 136 TSAN_ANNOTATE_HAPPENS_AFTER(pair_ptr); 137 if (pair.id_ == id) { 138 return pair.ptr_; 139 } 140 return nullptr; 141 } 142 SetClassCache(File::EntityId id,Class * clazz)143 inline void SetClassCache(File::EntityId id, Class *clazz) 144 { 145 ClassCachePair pair; 146 pair.id_ = id; 147 pair.ptr_ = clazz; 148 uint32_t index = GetClassIndex(id); 149 auto *pair_ptr = 150 reinterpret_cast<std::atomic<ClassCachePair> *>(reinterpret_cast<uintptr_t>(&(class_cache_[index]))); 151 TSAN_ANNOTATE_HAPPENS_BEFORE(pair_ptr); 152 pair_ptr->store(pair, std::memory_order_release); 153 } 154 155 template <class Callback> EnumerateCachedClasses(const Callback & cb)156 bool EnumerateCachedClasses(const Callback &cb) 157 { 158 for (uint32_t i = 0; i < CLASS_CACHE_SIZE; i++) { 159 auto *pair_ptr = 160 reinterpret_cast<std::atomic<ClassCachePair> *>(reinterpret_cast<uintptr_t>(&(class_cache_[i]))); 161 auto pair = pair_ptr->load(std::memory_order_acquire); 162 TSAN_ANNOTATE_HAPPENS_AFTER(pair_ptr); 163 if (pair.ptr_ != nullptr) { 164 if (!cb(pair.ptr_)) { 165 return false; 166 } 167 } 168 } 169 return true; 170 } 171 172 private: 173 static constexpr uint32_t DEFAULT_FIELD_CACHE_SIZE = 1024U; 174 static constexpr uint32_t DEFAULT_METHOD_CACHE_SIZE = 1024U; 175 static constexpr uint32_t DEFAULT_CLASS_CACHE_SIZE = 1024U; 176 static_assert(panda::helpers::math::IsPowerOfTwo(DEFAULT_FIELD_CACHE_SIZE)); 177 static_assert(panda::helpers::math::IsPowerOfTwo(DEFAULT_METHOD_CACHE_SIZE)); 178 static_assert(panda::helpers::math::IsPowerOfTwo(DEFAULT_CLASS_CACHE_SIZE)); 179 180 const uint32_t METHOD_CACHE_SIZE; 181 const uint32_t FIELD_CACHE_SIZE; 182 const uint32_t CLASS_CACHE_SIZE; 183 184 std::vector<MethodCachePair> method_cache_; 185 std::vector<FieldCachePair> field_cache_; 186 std::vector<ClassCachePair> class_cache_; 187 }; 188 189 } // namespace panda_file 190 } // namespace panda 191 192 #endif // PANDA_LIBPANDAFILE_PANDA_CACHE_H_ 193