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_TAGGED_DICTIONARY_H 17 #define ECMASCRIPT_TAGGED_DICTIONARY_H 18 19 #include "ecmascript/js_tagged_value-inl.h" 20 #include "ecmascript/platform/mutex.h" 21 #include "ecmascript/tagged_array-inl.h" 22 #include "ecmascript/tagged_hash_table.h" 23 24 namespace panda::ecmascript { 25 class NameDictionary : public OrderTaggedHashTable<NameDictionary> { 26 public: 27 using OrderHashTableT = OrderTaggedHashTable<NameDictionary>; GetKeyIndex(int entry)28 inline static int GetKeyIndex(int entry) 29 { 30 return OrderHashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_KEY_INDEX; 31 } GetValueIndex(int entry)32 inline static int GetValueIndex(int entry) 33 { 34 return OrderHashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_VALUE_INDEX; 35 } GetEntryIndex(int entry)36 inline static int GetEntryIndex(int entry) 37 { 38 return OrderHashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize(); 39 } GetEntrySize()40 inline static int GetEntrySize() 41 { 42 return ENTRY_SIZE; 43 } 44 static int PUBLIC_API Hash(const JSThread *thread, const JSTaggedValue &key); 45 static int Hash(const uint8_t* str, int strSize); 46 47 static bool PUBLIC_API IsMatch([[maybe_unused]] const JSThread *thread, const JSTaggedValue &key, 48 const JSTaggedValue &other); 49 static bool IsMatch(const uint8_t* str, int size, const JSTaggedValue &other); 50 51 static JSHandle<NameDictionary> Create(const JSThread *thread, 52 int numberOfElements = OrderHashTableT::DEFAULT_ELEMENTS_NUMBER); 53 static JSHandle<NameDictionary> PUBLIC_API CreateInSharedHeap(const JSThread *thread, 54 int numberOfElements = OrderHashTableT::DEFAULT_ELEMENTS_NUMBER); 55 // Returns the property metaData for the property at entry. 56 PropertyAttributes PUBLIC_API GetAttributes(const JSThread *thread, int entry) const; 57 void PUBLIC_API SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData); 58 void PUBLIC_API SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value, 59 const PropertyAttributes &metaData); 60 void UpdateValueAndAttributes(const JSThread *thread, int entry, const JSTaggedValue &value, 61 const PropertyAttributes &metaData); 62 void PUBLIC_API UpdateValue(const JSThread *thread, int entry, const JSTaggedValue &value); 63 void UpdateAttributes(int entry, const PropertyAttributes &metaData); 64 void UpdateAllAttributesToNoWitable(const JSThread *thread); 65 void ClearEntry(const JSThread *thread, int entry); 66 void GetAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray) const; 67 void GetAllKeysByFilter(const JSThread *thread, uint32_t &keyArrayEffectivelength, 68 TaggedArray *keyArray, uint32_t filter) const; 69 std::pair<uint32_t, uint32_t> GetNumOfEnumKeys(const JSThread *thread) const; 70 void GetAllEnumKeys(JSThread *thread, int offset, JSHandle<TaggedArray> keyArray, uint32_t *keys, 71 JSHandle<TaggedQueue> shadowQueue, int32_t lastLength) const; 72 void GetAllEnumKeys(JSThread *thread, int offset, JSHandle<TaggedArray> keyArray, uint32_t *keys) const; CompHandleKey(const std::pair<JSHandle<JSTaggedValue>,PropertyAttributes> & a,const std::pair<JSHandle<JSTaggedValue>,PropertyAttributes> & b)73 static inline bool CompHandleKey(const std::pair<JSHandle<JSTaggedValue>, PropertyAttributes> &a, 74 const std::pair<JSHandle<JSTaggedValue>, PropertyAttributes> &b) 75 { 76 return a.second.GetDictionaryOrder() < b.second.GetDictionaryOrder(); 77 } CompKey(const std::pair<JSTaggedValue,PropertyAttributes> & a,const std::pair<JSTaggedValue,PropertyAttributes> & b)78 static inline bool CompKey(const std::pair<JSTaggedValue, PropertyAttributes> &a, 79 const std::pair<JSTaggedValue, PropertyAttributes> &b) 80 { 81 return a.second.GetDictionaryOrder() < b.second.GetDictionaryOrder(); 82 } CompIndex(const PropertyAttributes & a,const PropertyAttributes & b)83 static inline bool CompIndex(const PropertyAttributes &a, 84 const PropertyAttributes &b) 85 { 86 return a.GetDictionaryOrder() < b.GetDictionaryOrder(); 87 } 88 void Dump(const JSThread *thread, std::ostream &os, bool isPrivacy = false) const DUMP_API_ATTR; Dump(const JSThread * thread)89 void Dump(const JSThread *thread) const DUMP_API_ATTR 90 { 91 Dump(thread, std::cout); 92 } 93 void DumpForSnapshot(const JSThread *thread, std::vector<Reference> &vec) const; 94 95 static constexpr int ENTRY_KEY_INDEX = 0; 96 static constexpr int ENTRY_VALUE_INDEX = 1; 97 static constexpr int ENTRY_DETAILS_INDEX = 2; 98 static constexpr int ENTRY_SIZE = 3; 99 }; 100 101 class NumberDictionary : public OrderTaggedHashTable<NumberDictionary> { 102 public: 103 using OrderHashTableT = OrderTaggedHashTable<NumberDictionary>; GetKeyIndex(int entry)104 inline static int GetKeyIndex(int entry) 105 { 106 return OrderHashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_KEY_INDEX; 107 } GetValueIndex(int entry)108 inline static int GetValueIndex(int entry) 109 { 110 return OrderHashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_VALUE_INDEX; 111 } GetEntryIndex(int entry)112 inline static int GetEntryIndex(int entry) 113 { 114 return OrderHashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize(); 115 } GetEntrySize()116 inline static int GetEntrySize() 117 { 118 return ENTRY_SIZE; 119 } 120 static int PUBLIC_API Hash([[maybe_unused]] const JSThread *thread, const JSTaggedValue &key); 121 static bool PUBLIC_API IsMatch([[maybe_unused]] const JSThread *thread, const JSTaggedValue &key, 122 const JSTaggedValue &other); 123 static JSHandle<NumberDictionary> Create(const JSThread *thread, 124 int numberOfElements = OrderHashTableT::DEFAULT_ELEMENTS_NUMBER); 125 static JSHandle<NumberDictionary> CreateInSharedHeap( 126 const JSThread *thread, int numberOfElements = OrderHashTableT::DEFAULT_ELEMENTS_NUMBER); 127 // Returns the property metaData for the property at entry. 128 PropertyAttributes PUBLIC_API GetAttributes(const JSThread *thread, int entry) const; 129 void SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData); 130 void SetEntry([[maybe_unused]] const JSThread *thread, int entry, const JSTaggedValue &key, 131 const JSTaggedValue &value, const PropertyAttributes &metaData); 132 void UpdateValueAndAttributes(const JSThread *thread, int entry, const JSTaggedValue &value, 133 const PropertyAttributes &metaData); 134 void PUBLIC_API UpdateValue(const JSThread *thread, int entry, const JSTaggedValue &value); 135 void UpdateAttributes(int entry, const PropertyAttributes &metaData); 136 void ClearEntry(const JSThread *thread, int entry); 137 138 static void GetAllKeys(const JSThread *thread, const JSHandle<NumberDictionary> &obj, int offset, 139 const JSHandle<TaggedArray> &keyArray); 140 static void GetAllKeysByFilter(const JSThread *thread, const JSHandle<NumberDictionary> &obj, 141 uint32_t &keyArrayEffectivelength, const JSHandle<TaggedArray> &keyArray, uint32_t filter); 142 static void GetAllEnumKeys(JSThread *thread, const JSHandle<NumberDictionary> &obj, int offset, 143 const JSHandle<TaggedArray> &keyArray, uint32_t *keys, int32_t lastLength = -1); CompKey(const JSTaggedValue & a,const JSTaggedValue & b)144 static inline bool CompKey(const JSTaggedValue &a, const JSTaggedValue &b) 145 { 146 ASSERT(a.IsNumber() && b.IsNumber()); 147 return a.GetNumber() < b.GetNumber(); 148 } 149 void Dump(const JSThread *thread, std::ostream &os, bool isPrivacy = false) const DUMP_API_ATTR; Dump(const JSThread * thread)150 void Dump(const JSThread *thread) const DUMP_API_ATTR 151 { 152 Dump(thread, std::cout); 153 } 154 void DumpForSnapshot(const JSThread *thread, std::vector<Reference> &vec) const; 155 156 static constexpr int ENTRY_KEY_INDEX = 0; 157 static constexpr int ENTRY_VALUE_INDEX = 1; 158 static constexpr int ENTRY_DETAILS_INDEX = 2; 159 static constexpr int ENTRY_SIZE = 3; 160 }; 161 162 class PointerToIndexDictionary : public OrderTaggedHashTable<PointerToIndexDictionary> { 163 public: 164 using OrderHashTableT = OrderTaggedHashTable<PointerToIndexDictionary>; GetKeyIndex(int entry)165 inline static int GetKeyIndex(int entry) 166 { 167 return OrderHashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_KEY_INDEX; 168 } 169 GetValueIndex(int entry)170 inline static int GetValueIndex(int entry) 171 { 172 return OrderHashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_VALUE_INDEX; 173 } 174 GetEntryIndex(int entry)175 inline static int GetEntryIndex(int entry) 176 { 177 return OrderHashTableT::TABLE_HEADER_SIZE + entry * GetEntrySize(); 178 } 179 GetEntrySize()180 inline static int GetEntrySize() 181 { 182 return ENTRY_SIZE; 183 } 184 SetEntry(const JSThread * thread,int entry,const JSTaggedValue & key,const JSTaggedValue & value)185 inline void SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value) 186 { 187 SetKey(thread, entry, key); 188 SetValue(thread, entry, value); 189 } 190 Hash(const JSThread * thread,const JSTaggedValue & key)191 static int32_t Hash([[maybe_unused]] const JSThread *thread, const JSTaggedValue &key) 192 { 193 return static_cast<int32_t>(key.GetRawData()); 194 } 195 IsMatch(const JSThread * thread,const JSTaggedValue & key,const JSTaggedValue & other)196 static bool IsMatch([[maybe_unused]] const JSThread *thread, const JSTaggedValue &key, const JSTaggedValue &other) 197 { 198 return key == other; 199 } 200 static JSHandle<PointerToIndexDictionary> Create(const JSThread *thread, 201 int numberOfElements = OrderHashTableT::DEFAULT_ELEMENTS_NUMBER); 202 static JSHandle<PointerToIndexDictionary> PutIfAbsent( 203 const JSThread *thread, const JSHandle<PointerToIndexDictionary> &dictionary, 204 const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value); 205 206 // DECL_DUMP() 207 208 static constexpr int ENTRY_KEY_INDEX = 0; 209 static constexpr int ENTRY_VALUE_INDEX = 1; 210 static constexpr int ENTRY_SIZE = 2; 211 }; 212 213 class FunctionProtoTransitionTable { 214 public: 215 explicit FunctionProtoTransitionTable(const JSThread *thread); 216 virtual ~FunctionProtoTransitionTable(); 217 218 void Iterate(RootVisitor &v); 219 220 void InsertTransitionItem(const JSThread *thread, 221 JSHandle<JSTaggedValue> ihc, 222 JSHandle<JSTaggedValue> baseIhc, 223 JSHandle<JSTaggedValue> transIhc, 224 JSHandle<JSTaggedValue> transPhc); 225 226 std::pair<JSTaggedValue, JSTaggedValue> FindTransitionByHClass(const JSThread *thread, 227 JSHandle<JSTaggedValue> ihc, 228 JSHandle<JSTaggedValue> baseIhc) const; 229 230 bool TryInsertFakeParentItem(JSTaggedType child, JSTaggedType parent); 231 JSTaggedType GetFakeParent(JSTaggedType child); 232 GetProtoTransitionTable()233 JSTaggedValue GetProtoTransitionTable() const 234 { 235 return protoTransitionTable_; 236 } 237 238 void UpdateProtoTransitionTable(const JSThread *thread, JSHandle<PointerToIndexDictionary> map); 239 240 class ProtoArray : public TaggedArray { 241 public: 242 CAST_CHECK(ProtoArray, IsTaggedArray); 243 244 static JSHandle<ProtoArray> Create(const JSThread *thread); 245 void SetEntry(const JSThread *thread, uint32_t index, JSTaggedValue key, JSTaggedValue transIhc, 246 JSTaggedValue transPhc); 247 JSTaggedValue GetKey(const JSThread *thread, uint32_t index) const; 248 std::pair<JSTaggedValue, JSTaggedValue> GetTransition(const JSThread *thread, uint32_t index) const; 249 int32_t FindEntry(const JSThread *thread, JSTaggedValue key) const; 250 std::pair<JSTaggedValue, JSTaggedValue> FindTransition(const JSThread *thread, JSTaggedValue key) const; 251 static bool GetEntry(JSHandle<JSHClass> hclass); 252 253 private: 254 static constexpr uint32_t ENTRY_NUMBER = 2; 255 static constexpr uint32_t INIT_ENTRY_INDEX = 0; 256 static constexpr uint32_t CLONED_ENTRY_INDEX = 1; 257 258 static constexpr uint32_t ENTRY_SIZE = 3; 259 static constexpr uint32_t KEY_INDEX = 0; 260 static constexpr uint32_t TRANS_IHC_INDEX = 1; 261 static constexpr uint32_t TRANS_PHC_INDEX = 2; 262 }; 263 264 private: 265 static constexpr uint32_t DEFAULT_FIRST_LEVEL_SIZE = 2; 266 // second level table: 267 // <PointerToIndexDictionary(n): 268 // [ihc, 269 // <ProtoArray(2): 270 // [base.ihc, 271 // (trans_ihc, trans_phc) 272 // ] 273 // [base.ihc(cloned), 274 // (trans_ihc, trans_phc) 275 // ] 276 // > 277 // ] 278 // ... 279 // > 280 JSTaggedValue protoTransitionTable_ {JSTaggedValue::Hole()}; 281 // hclasses after set prototype maps to hclasses before set prototype 282 CUnorderedMap<JSTaggedType, JSTaggedType> fakeParentMap_ {}; 283 // reverse fakeParentMap_ 284 CUnorderedMap<JSTaggedType, JSTaggedType> fakeChildMap_ {}; 285 Mutex fakeParentMutex_; 286 }; 287 } // namespace panda::ecmascript 288 #endif // ECMASCRIPT_NEW_DICTIONARY_H 289