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