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 ECMASCRIPT_IC_MEGA_IC_CACHE_H 17 #define ECMASCRIPT_IC_MEGA_IC_CACHE_H 18 19 #include <array> 20 21 #include "ecmascript/js_hclass.h" 22 #include "ecmascript/js_tagged_value.h" 23 #include "ecmascript/ecma_macros.h" 24 #include "ecmascript/log_wrapper.h" 25 #include "ecmascript/log_wrapper.h" 26 #include "jsnapi_expo.h" 27 28 namespace panda::ecmascript { 29 class EcmaVM; 30 class MegaICCache { 31 public: 32 enum MegaICKind { 33 None, 34 Load, 35 Store, 36 }; Get(const JSThread * thread,JSHClass * jsHclass,JSTaggedValue key)37 JSTaggedValue Get(const JSThread *thread, JSHClass *jsHclass, JSTaggedValue key) 38 { 39 int hash = PrimaryHash(thread, jsHclass, key); 40 PropertyKey &prop = primary_[hash]; 41 if ((prop.hclass_ == jsHclass) && (prop.key_ == key)) { 42 return primary_[hash].results_; 43 } 44 int secondaryHash = SecondaryHash(jsHclass, key); 45 PropertyKey &secondaryProp = secondary_[secondaryHash]; 46 if ((secondaryProp.hclass_ == jsHclass) && (secondaryProp.key_ == key)) { 47 return secondary_[secondaryHash].results_; 48 } 49 return NOT_FOUND; 50 } 51 void Set(JSHClass *jsHclass, JSTaggedValue key, JSTaggedValue handler, JSThread* thread); Clear()52 inline void Clear() 53 { 54 for (auto &key : primary_) { 55 key.hclass_ = nullptr; 56 key.key_ = JSTaggedValue::Hole(); 57 } 58 for (auto &key : secondary_) { 59 key.hclass_ = nullptr; 60 key.key_ = JSTaggedValue::Hole(); 61 } 62 } IsCleared()63 bool IsCleared() const 64 { 65 for (auto &key : primary_) { 66 if (key.hclass_ != nullptr) { 67 return false; 68 } 69 } 70 for (auto &key : secondary_) { 71 if (key.hclass_ != nullptr) { 72 return false; 73 } 74 } 75 return true; 76 } 77 PrintLoadFactor()78 bool PrintLoadFactor() const 79 { 80 int tot = 0; 81 for (auto &key : primary_) { 82 if (key.hclass_ != nullptr) { 83 tot++; 84 } 85 } 86 LOG_JIT(INFO) << "PrimaryTable LoadFactor:" << (double)tot / PRIMARY_LENGTH; 87 tot = 0; 88 for (auto &key : secondary_) { 89 if (key.hclass_ != nullptr) { 90 tot++; 91 } 92 } 93 LOG_JIT(INFO) << "SecondaryTable LoadFactor:" << (double)tot / SECONDARY_LENGTH; 94 95 return true; 96 } 97 Iterate(RootVisitor & v)98 void Iterate(RootVisitor &v) 99 { 100 for (auto &key : primary_) { 101 if (key.hclass_ != nullptr) { 102 auto value = JSTaggedValue::Cast(key.hclass_); 103 v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(value)))); 104 } 105 v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(key.key_)))); 106 v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(key.results_)))); 107 } 108 for (auto &key : secondary_) { 109 if (key.hclass_ != nullptr) { 110 auto value = JSTaggedValue::Cast(key.hclass_); 111 v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(value)))); 112 } 113 v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(key.key_)))); 114 v.VisitRoot(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(key.results_)))); 115 } 116 } 117 GetSecondaryOffset()118 static size_t GetSecondaryOffset() 119 { 120 return sizeof(PropertyKey) * PRIMARY_LENGTH; 121 } 122 123 constexpr static const JSTaggedValue NOT_FOUND = JSTaggedValue::Hole(); 124 static const uint32_t PRIMARY_LENGTH_BIT = 10; 125 static const uint32_t PRIMARY_LENGTH = (1U << PRIMARY_LENGTH_BIT); 126 static const uint32_t PRIMARY_LENGTH_MASK = PRIMARY_LENGTH - 1; 127 static const uint32_t SECONDARY_LENGTH_BIT = 9; 128 static const uint32_t SECONDARY_LENGTH = (1U << SECONDARY_LENGTH_BIT); 129 static const uint32_t SECONDARY_LENGTH_MASK = SECONDARY_LENGTH - 1; 130 static const uint32_t HCLASS_SHIFT = 3; 131 struct PropertyKey : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(), 132 base::AlignedPointer, 133 JSTaggedValue, 134 JSTaggedValue> { 135 enum class Index : size_t { 136 HclassIndex = 0, 137 KeyIndex, 138 ResultsIndex, 139 NumOfMembers 140 }; 141 static size_t GetHclassOffset(bool isArch32 = false) 142 { 143 return GetOffset<static_cast<size_t>(Index::HclassIndex)>(isArch32); 144 } 145 146 static size_t GetKeyOffset(bool isArch32 = false) 147 { 148 return GetOffset<static_cast<size_t>(Index::KeyIndex)>(isArch32); 149 } 150 151 static size_t GetResultsOffset(bool isArch32 = false) 152 { 153 return GetOffset<static_cast<size_t>(Index::ResultsIndex)>(isArch32); 154 } 155 GetPropertyKeySizePropertyKey156 static size_t GetPropertyKeySize() 157 { 158 return static_cast<size_t>(Index::NumOfMembers) * static_cast<size_t>(JSTaggedValue::TaggedTypeSize()); 159 } 160 161 static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes); 162 alignas(EAS) JSHClass *hclass_ {nullptr}; 163 alignas(EAS) JSTaggedValue key_ {JSTaggedValue::Hole()}; 164 alignas(EAS) JSTaggedValue results_ {JSTaggedValue::Hole()}; 165 }; 166 167 private: MegaICCache()168 MegaICCache() 169 { 170 for (uint32_t i = 0; i < PRIMARY_LENGTH; ++i) { 171 primary_[i].hclass_ = nullptr; 172 primary_[i].key_ = JSTaggedValue::Hole(); 173 primary_[i].results_ = NOT_FOUND; 174 } 175 for (uint32_t i = 0; i < SECONDARY_LENGTH; ++i) { 176 secondary_[i].hclass_ = nullptr; 177 secondary_[i].key_ = JSTaggedValue::Hole(); 178 secondary_[i].results_ = NOT_FOUND; 179 } 180 } 181 ~MegaICCache() = default; 182 183 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) PrimaryHash(const JSThread * thread,JSHClass * cls,JSTaggedValue key)184 static inline int PrimaryHash(const JSThread *thread, JSHClass *cls, JSTaggedValue key) 185 { 186 uint32_t clsHash = static_cast<uint32_t>( 187 reinterpret_cast<uintptr_t>(cls) ^ 188 (reinterpret_cast<uintptr_t>(cls) >> PRIMARY_LENGTH_BIT)); 189 uint32_t keyHash = key.GetStringKeyHashCode(thread); 190 uint32_t hash = clsHash + keyHash; 191 return static_cast<int>((hash) & PRIMARY_LENGTH_MASK); 192 } 193 SecondaryHash(JSHClass * cls,JSTaggedValue key)194 static inline int SecondaryHash(JSHClass *cls, JSTaggedValue key) 195 { 196 uint32_t clsHash = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(cls)) >> HCLASS_SHIFT; // skip 8bytes 197 uint32_t keyHash = static_cast<uint32_t>(key.GetRawData()); 198 uint32_t hash = clsHash + keyHash; 199 hash = hash + (hash >> SECONDARY_LENGTH_BIT); 200 return static_cast<int>((hash) & SECONDARY_LENGTH_MASK); 201 } 202 203 PropertyKey primary_[PRIMARY_LENGTH]; 204 PropertyKey secondary_[SECONDARY_LENGTH]; 205 206 friend class JSThread; 207 }; 208 } // namespace panda::ecmascript 209 #endif // ECMASCRIPT_IC_MEGA_IC_CACHE_H 210