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_TRANSITIONS_DICTIONARY_H 17 #define ECMASCRIPT_TRANSITIONS_DICTIONARY_H 18 19 #include "ecmascript/accessor_data.h" 20 #include "ecmascript/js_symbol.h" 21 #include "ecmascript/js_tagged_number.h" 22 #include "ecmascript/tagged_hash_table.h" 23 24 namespace panda::ecmascript { 25 class TransitionsDictionary : public TaggedHashTable<TransitionsDictionary> { 26 public: 27 using HashTableT = TaggedHashTable<TransitionsDictionary>; IsMatch(const JSThread * thread,const JSTaggedValue & key,const JSTaggedValue & otherKey)28 static inline bool IsMatch([[maybe_unused]] const JSThread *thread, 29 [[maybe_unused]] const JSTaggedValue &key, 30 [[maybe_unused]] const JSTaggedValue &otherKey) 31 { 32 LOG_ECMA(FATAL) << "this branch is unreachable"; 33 UNREACHABLE(); 34 } Hash(const JSTaggedValue & key)35 static inline int Hash([[maybe_unused]] const JSTaggedValue &key) 36 { 37 LOG_ECMA(FATAL) << "this branch is unreachable"; 38 UNREACHABLE(); 39 } 40 IsMatch(const JSTaggedValue & key,const JSTaggedValue & metaData,const JSTaggedValue & otherKey,const JSTaggedValue & otherDetails)41 static inline bool IsMatch(const JSTaggedValue &key, const JSTaggedValue &metaData, const JSTaggedValue &otherKey, 42 const JSTaggedValue &otherDetails) 43 { 44 return key == otherKey && metaData == otherDetails; 45 } 46 Hash(const JSThread * thread,const JSTaggedValue & key,const JSTaggedValue & metaData)47 static inline int Hash(const JSThread *thread, const JSTaggedValue &key, const JSTaggedValue &metaData) 48 { 49 ASSERT(key.IsStringOrSymbol()); 50 51 uint32_t hash = 0; 52 if (key.IsString()) { 53 hash = EcmaStringAccessor(key).GetHashcode(thread); 54 } else if (key.IsSymbol()) { 55 hash = JSSymbol::Cast(key.GetTaggedObject())->GetHashField(); 56 } 57 int metaDataHash = metaData.IsInt() ? metaData.GetInt() : static_cast<int>(metaData.GetRawData()); 58 return static_cast<int>(hash) + metaDataHash; 59 } 60 GetKeyIndex(int entry)61 inline static int GetKeyIndex(int entry) 62 { 63 return HashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_KEY_INDEX; 64 } GetValueIndex(int entry)65 inline static int GetValueIndex(int entry) 66 { 67 return HashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_VALUE_INDEX; 68 } GetEntryIndex(int entry)69 inline static int GetEntryIndex(int entry) 70 { 71 return HashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize(); 72 } GetEntrySize()73 inline static int GetEntrySize() 74 { 75 return ENTRY_SIZE; 76 } 77 Cast(TaggedObject * object)78 static TransitionsDictionary *Cast(TaggedObject *object) 79 { 80 return reinterpret_cast<TransitionsDictionary *>(object); 81 } 82 83 static constexpr int DEFAULT_ELEMENTS_NUMBER = 16; 84 static JSHandle<TransitionsDictionary> Create(const JSThread *thread, 85 int numberOfElements = DEFAULT_ELEMENTS_NUMBER) 86 { 87 return HashTableT::Create(thread, numberOfElements); 88 } 89 90 // Attempt to shrink the dictionary after deletion of key. Shrink(const JSThread * thread,const JSHandle<TransitionsDictionary> & dictionary)91 inline static JSHandle<TransitionsDictionary> Shrink(const JSThread *thread, 92 const JSHandle<TransitionsDictionary> &dictionary) 93 { 94 return HashTableT::Shrink(thread, dictionary, 0); 95 } 96 GetAttributes(const JSThread * thread,int entry)97 inline JSTaggedValue GetAttributes(const JSThread *thread, int entry) const 98 { 99 int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX; 100 return HashTableT::Get(thread, index); 101 } 102 SetAttributes(const JSThread * thread,int entry,JSTaggedValue metaData)103 inline void SetAttributes(const JSThread *thread, int entry, JSTaggedValue metaData) 104 { 105 int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX; 106 HashTableT::Set(thread, index, metaData); 107 } 108 SetEntry(const JSThread * thread,int entry,const JSTaggedValue & key,const JSTaggedValue & value,const JSTaggedValue & metaData)109 inline void SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value, 110 const JSTaggedValue &metaData) 111 { 112 SetKey(thread, entry, key); 113 JSTaggedValue weakValue = JSTaggedValue(value.CreateAndGetWeakRef()); 114 SetValue(thread, entry, weakValue); 115 if (!metaData.IsHeapObject()) { 116 SetAttributes(thread, entry, metaData); 117 return; 118 } 119 JSTaggedValue weakMetaData = JSTaggedValue(metaData.CreateAndGetWeakRef()); 120 SetAttributes(thread, entry, weakMetaData); 121 } 122 RemoveElement(const JSThread * thread,int entry)123 inline void RemoveElement(const JSThread *thread, int entry) 124 { 125 SetKey(thread, entry, JSTaggedValue::Hole()); 126 SetValue(thread, entry, JSTaggedValue::Hole()); 127 SetAttributes(thread, entry, JSTaggedValue::Hole()); 128 IncreaseHoleEntriesCount(thread); 129 } 130 131 int FindEntry(const JSThread *thread, const JSTaggedValue &key, const JSTaggedValue &metaData); 132 template <typename Callback> IterateEntryValue(const JSThread * thread,Callback callback)133 void IterateEntryValue(const JSThread *thread, Callback callback) 134 { 135 auto number = EntriesCount(); 136 int size = Size(); 137 int hasIteratedNum = 0; 138 for (int entry = 0; entry < size; entry++) { 139 JSTaggedValue ret = GetValue(thread, entry); 140 if (ret.IsWeak()) { 141 auto next = ret.GetTaggedWeakRef(); 142 callback(JSHClass::Cast(next)); 143 hasIteratedNum++; 144 if (hasIteratedNum >= number) { 145 return; 146 } 147 } 148 } 149 } 150 static JSHandle<TransitionsDictionary> PutIfAbsent(const JSThread *thread, 151 const JSHandle<TransitionsDictionary> &dictionary, 152 const JSHandle<JSTaggedValue> &key, 153 const JSHandle<JSTaggedValue> &value, 154 const JSHandle<JSTaggedValue> &metaData); 155 // For test 156 static JSHandle<TransitionsDictionary> Remove(const JSThread *thread, const JSHandle<TransitionsDictionary> &table, 157 const JSHandle<JSTaggedValue> &key, const JSTaggedValue &metaData); 158 void Rehash(const JSThread *thread, TransitionsDictionary *newTable); 159 CheckWeakExist(const JSTaggedValue & value)160 static bool CheckWeakExist(const JSTaggedValue &value) 161 { 162 if (value == JSTaggedValue::Undefined()) { 163 return false; 164 } 165 return true; 166 } 167 ComputeCompactSize(const JSThread * thread,const JSHandle<TransitionsDictionary> & table,int computeHashTableSize,int tableSize,int addedElements)168 static int ComputeCompactSize(const JSThread *thread, const JSHandle<TransitionsDictionary> &table, 169 int computeHashTableSize, int tableSize, int addedElements) 170 { 171 int realEntryCount = 0; 172 for (int i = 0; i < tableSize; i++) { 173 // value is weak reference, if not use will be set undefined. 174 if (TransitionsDictionary::CheckWeakExist(table->GetValue(thread, i))) { 175 realEntryCount++; 176 } 177 } 178 return std::min(computeHashTableSize, 179 static_cast<int>(helpers::math::GetPowerOfTwoValue32(realEntryCount + addedElements) * HASH_TABLE_BUFFER)); 180 } 181 182 static constexpr int ENTRY_SIZE = 3; 183 static constexpr int ENTRY_KEY_INDEX = 0; 184 static constexpr int ENTRY_VALUE_INDEX = 1; 185 static constexpr int ENTRY_DETAILS_INDEX = 2; 186 static constexpr int HASH_TABLE_BUFFER = 2; 187 DECL_DUMP() 188 }; 189 } // namespace panda::ecmascript 190 #endif 191