1 /*
2 * Copyright (c) 2021-2022 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 #include "ecmascript/tagged_dictionary.h"
17
18 #include "ecmascript/tagged_hash_table.h"
19
20 namespace panda::ecmascript {
Hash(const JSTaggedValue & key)21 int NameDictionary::Hash(const JSTaggedValue &key)
22 {
23 if (key.IsHeapObject()) {
24 JSTaggedValue jsKey(key);
25 if (jsKey.IsSymbol()) {
26 auto symbolString = JSSymbol::Cast(key.GetTaggedObject());
27 return symbolString->GetHashField();
28 }
29 if (jsKey.IsString()) {
30 auto keyString = reinterpret_cast<EcmaString *>(key.GetTaggedObject());
31 return EcmaStringAccessor(keyString).GetHashcode();
32 }
33 }
34 // key must be object
35 UNREACHABLE();
36 }
37
IsMatch(const JSTaggedValue & key,const JSTaggedValue & other)38 bool NameDictionary::IsMatch(const JSTaggedValue &key, const JSTaggedValue &other)
39 {
40 return key == other;
41 }
42
GetAllKeys(const JSThread * thread,int offset,TaggedArray * keyArray) const43 void NameDictionary::GetAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray) const
44 {
45 int arrayIndex = 0;
46 int size = Size();
47 CVector<std::pair<JSTaggedValue, PropertyAttributes>> sortArr;
48 for (int hashIndex = 0; hashIndex < size; hashIndex++) {
49 JSTaggedValue key = GetKey(hashIndex);
50 if (!key.IsUndefined() && !key.IsHole()) {
51 PropertyAttributes attr = GetAttributes(hashIndex);
52 std::pair<JSTaggedValue, PropertyAttributes> pair(key, attr);
53 sortArr.push_back(pair);
54 }
55 }
56 std::sort(sortArr.begin(), sortArr.end(), CompKey);
57 for (const auto &entry : sortArr) {
58 keyArray->Set(thread, arrayIndex + offset, entry.first);
59 arrayIndex++;
60 }
61 }
62
GetAllEnumKeys(const JSThread * thread,int offset,TaggedArray * keyArray,uint32_t * keys) const63 void NameDictionary::GetAllEnumKeys(const JSThread *thread, int offset, TaggedArray *keyArray, uint32_t *keys) const
64 {
65 uint32_t arrayIndex = 0;
66 int size = Size();
67 CVector<std::pair<JSTaggedValue, PropertyAttributes>> sortArr;
68 for (int hashIndex = 0; hashIndex < size; hashIndex++) {
69 JSTaggedValue key = GetKey(hashIndex);
70 if (key.IsString()) {
71 PropertyAttributes attr = GetAttributes(hashIndex);
72 if (attr.IsEnumerable()) {
73 std::pair<JSTaggedValue, PropertyAttributes> pair(key, attr);
74 sortArr.push_back(pair);
75 }
76 }
77 }
78 std::sort(sortArr.begin(), sortArr.end(), CompKey);
79 for (auto entry : sortArr) {
80 keyArray->Set(thread, arrayIndex + static_cast<uint32_t>(offset), entry.first);
81 arrayIndex++;
82 }
83 *keys += arrayIndex;
84 }
85
Create(const JSThread * thread,int numberOfElements)86 JSHandle<NameDictionary> NameDictionary::Create(const JSThread *thread, int numberOfElements)
87 {
88 return OrderHashTableT::Create(thread, numberOfElements);
89 }
90
GetAttributes(int entry) const91 PropertyAttributes NameDictionary::GetAttributes(int entry) const
92 {
93 int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
94 return PropertyAttributes(Get(index).GetInt());
95 }
96
SetAttributes(const JSThread * thread,int entry,const PropertyAttributes & metaData)97 void NameDictionary::SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData)
98 {
99 int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
100 Set(thread, index, metaData.GetTaggedValue());
101 }
102
SetEntry(const JSThread * thread,int entry,const JSTaggedValue & key,const JSTaggedValue & value,const PropertyAttributes & metaData)103 void NameDictionary::SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value,
104 const PropertyAttributes &metaData)
105 {
106 SetKey(thread, entry, key);
107 SetValue(thread, entry, value);
108 SetAttributes(thread, entry, metaData);
109 }
110
UpdateValueAndAttributes(const JSThread * thread,int entry,const JSTaggedValue & value,const PropertyAttributes & metaData)111 void NameDictionary::UpdateValueAndAttributes(const JSThread *thread, int entry, const JSTaggedValue &value,
112 const PropertyAttributes &metaData)
113 {
114 SetValue(thread, entry, value);
115 SetAttributes(thread, entry, metaData);
116 }
117
UpdateValue(const JSThread * thread,int entry,const JSTaggedValue & value)118 void NameDictionary::UpdateValue(const JSThread *thread, int entry, const JSTaggedValue &value)
119 {
120 SetValue(thread, entry, value);
121 }
122
ClearEntry(const JSThread * thread,int entry)123 void NameDictionary::ClearEntry(const JSThread *thread, int entry)
124 {
125 JSTaggedValue hole = JSTaggedValue::Hole();
126 PropertyAttributes metaData;
127 SetEntry(thread, entry, hole, hole, metaData);
128 }
129
Hash(const JSTaggedValue & key)130 int NumberDictionary::Hash(const JSTaggedValue &key)
131 {
132 if (key.IsInt()) {
133 int keyValue = key.GetInt();
134 return GetHash32(reinterpret_cast<uint8_t *>(&keyValue), sizeof(keyValue) / sizeof(uint8_t));
135 }
136 // key must be object
137 UNREACHABLE();
138 }
139
IsMatch(const JSTaggedValue & key,const JSTaggedValue & other)140 bool NumberDictionary::IsMatch(const JSTaggedValue &key, const JSTaggedValue &other)
141 {
142 if (key.IsHole() || key.IsUndefined()) {
143 return false;
144 }
145
146 if (key.IsInt()) {
147 if (other.IsInt()) {
148 return key.GetInt() == other.GetInt();
149 }
150 return false;
151 }
152 // key must be integer
153 UNREACHABLE();
154 }
155
GetAllKeys(const JSThread * thread,const JSHandle<NumberDictionary> & obj,int offset,const JSHandle<TaggedArray> & keyArray)156 void NumberDictionary::GetAllKeys(const JSThread *thread, const JSHandle<NumberDictionary> &obj, int offset,
157 const JSHandle<TaggedArray> &keyArray)
158 {
159 ASSERT_PRINT(offset + obj->EntriesCount() <= static_cast<int>(keyArray->GetLength()),
160 "keyArray capacity is not enough for dictionary");
161 int arrayIndex = 0;
162 int size = obj->Size();
163 CVector<JSTaggedValue> sortArr;
164 for (int hashIndex = 0; hashIndex < size; hashIndex++) {
165 JSTaggedValue key = obj->GetKey(hashIndex);
166 if (!key.IsUndefined() && !key.IsHole()) {
167 sortArr.push_back(JSTaggedValue(static_cast<uint32_t>(key.GetInt())));
168 }
169 }
170 std::sort(sortArr.begin(), sortArr.end(), CompKey);
171 for (auto entry : sortArr) {
172 JSHandle<JSTaggedValue> keyHandle(thread, entry);
173 JSHandle<EcmaString> str = JSTaggedValue::ToString(const_cast<JSThread *>(thread), keyHandle);
174 ASSERT_NO_ABRUPT_COMPLETION(thread);
175 keyArray->Set(thread, arrayIndex + offset, str.GetTaggedValue());
176 arrayIndex++;
177 }
178 }
179
GetAllEnumKeys(const JSThread * thread,const JSHandle<NumberDictionary> & obj,int offset,const JSHandle<TaggedArray> & keyArray,uint32_t * keys)180 void NumberDictionary::GetAllEnumKeys(const JSThread *thread, const JSHandle<NumberDictionary> &obj, int offset,
181 const JSHandle<TaggedArray> &keyArray, uint32_t *keys)
182 {
183 ASSERT_PRINT(offset + obj->EntriesCount() <= static_cast<int>(keyArray->GetLength()),
184 "keyArray capacity is not enough for dictionary");
185 uint32_t arrayIndex = 0;
186 int size = obj->Size();
187 CVector<JSTaggedValue> sortArr;
188 for (int hashIndex = 0; hashIndex < size; hashIndex++) {
189 JSTaggedValue key = obj->GetKey(hashIndex);
190 if (!key.IsUndefined() && !key.IsHole()) {
191 PropertyAttributes attr = obj->GetAttributes(hashIndex);
192 if (attr.IsEnumerable()) {
193 sortArr.push_back(JSTaggedValue(static_cast<uint32_t>(key.GetInt())));
194 }
195 }
196 }
197 std::sort(sortArr.begin(), sortArr.end(), CompKey);
198 for (auto entry : sortArr) {
199 JSHandle<JSTaggedValue> key_handle(thread, entry);
200 JSHandle<EcmaString> str = JSTaggedValue::ToString(const_cast<JSThread *>(thread), key_handle);
201 ASSERT_NO_ABRUPT_COMPLETION(thread);
202 keyArray->Set(thread, arrayIndex + static_cast<uint32_t>(offset), str.GetTaggedValue());
203 arrayIndex++;
204 }
205 *keys += arrayIndex;
206 }
207
Create(const JSThread * thread,int numberOfElements)208 JSHandle<NumberDictionary> NumberDictionary::Create(const JSThread *thread, int numberOfElements)
209 {
210 return OrderHashTableT::Create(thread, numberOfElements);
211 }
212
GetAttributes(int entry) const213 PropertyAttributes NumberDictionary::GetAttributes(int entry) const
214 {
215 int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
216 return PropertyAttributes(Get(index).GetInt());
217 }
218
SetAttributes(const JSThread * thread,int entry,const PropertyAttributes & metaData)219 void NumberDictionary::SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData)
220 {
221 int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
222 Set(thread, index, metaData.GetTaggedValue());
223 }
224
SetEntry(const JSThread * thread,int entry,const JSTaggedValue & key,const JSTaggedValue & value,const PropertyAttributes & metaData)225 void NumberDictionary::SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value,
226 const PropertyAttributes &metaData)
227 {
228 SetKey(thread, entry, key);
229 SetValue(thread, entry, value);
230 SetAttributes(thread, entry, metaData);
231 }
232
UpdateValueAndAttributes(const JSThread * thread,int entry,const JSTaggedValue & value,const PropertyAttributes & metaData)233 void NumberDictionary::UpdateValueAndAttributes(const JSThread *thread, int entry, const JSTaggedValue &value,
234 const PropertyAttributes &metaData)
235 {
236 SetValue(thread, entry, value);
237 SetAttributes(thread, entry, metaData);
238 }
239
UpdateValue(const JSThread * thread,int entry,const JSTaggedValue & value)240 void NumberDictionary::UpdateValue(const JSThread *thread, int entry, const JSTaggedValue &value)
241 {
242 SetValue(thread, entry, value);
243 }
244
ClearEntry(const JSThread * thread,int entry)245 void NumberDictionary::ClearEntry(const JSThread *thread, int entry)
246 {
247 JSTaggedValue hole = JSTaggedValue::Hole();
248 PropertyAttributes metaData;
249 SetEntry(thread, entry, hole, hole, metaData);
250 }
251 } // namespace panda::ecmascript
252