• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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