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_GLOBAL_DICTIONARY_INL_H
17 #define ECMASCRIPT_GLOBAL_DICTIONARY_INL_H
18
19 #include "ecmascript/filter_helper.h"
20 #include "ecmascript/js_symbol.h"
21 #include "ecmascript/global_dictionary.h"
22 #include "ecmascript/ic/property_box.h"
23 #include "ecmascript/mem/c_containers.h"
24 #include "ecmascript/tagged_hash_table.h"
25
26 namespace panda {
27 namespace ecmascript {
Hash(const JSTaggedValue & key)28 int GlobalDictionary::Hash(const JSTaggedValue &key)
29 {
30 if (key.IsHeapObject()) {
31 if (key.IsSymbol()) {
32 auto symbolString = JSSymbol::Cast(key.GetTaggedObject());
33 return symbolString->GetHashField();
34 }
35 if (key.IsString()) {
36 auto keyString = EcmaString::Cast(key.GetTaggedObject());
37 return EcmaStringAccessor(keyString).GetHashcode();
38 }
39 }
40 // key must be object
41 LOG_ECMA(FATAL) << "this branch is unreachable";
42 UNREACHABLE();
43 }
44
IsMatch(const JSTaggedValue & key,const JSTaggedValue & other)45 bool GlobalDictionary::IsMatch(const JSTaggedValue &key, const JSTaggedValue &other)
46 {
47 return key == other;
48 }
49
GetBox(int entry)50 PropertyBox *GlobalDictionary::GetBox(int entry) const
51 {
52 int index = GetEntryIndex(entry) + ENTRY_VALUE_INDEX;
53 return PropertyBox::Cast(Get(index).GetTaggedObject());
54 }
55
GetValue(int entry)56 JSTaggedValue GlobalDictionary::GetValue(int entry) const
57 {
58 return GetBox(entry)->GetValue();
59 }
60
GetAttributes(int entry)61 PropertyAttributes GlobalDictionary::GetAttributes(int entry) const
62 {
63 int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
64 return PropertyAttributes(Get(index).GetInt());
65 }
66
SetEntry(const JSThread * thread,int entry,const JSTaggedValue & key,const JSTaggedValue & value,const PropertyAttributes & attributes)67 void GlobalDictionary::SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value,
68 const PropertyAttributes &attributes)
69 {
70 SetKey(thread, entry, key);
71 SetAttributes(thread, entry, attributes);
72 UpdateValueAndAttributes(thread, entry, value, attributes);
73 }
74
ClearEntry(const JSThread * thread,int entry)75 void GlobalDictionary::ClearEntry(const JSThread *thread, int entry)
76 {
77 JSTaggedValue hole = JSTaggedValue::Hole();
78 PropertyAttributes metaData;
79 SetEntry(thread, entry, hole, hole, metaData);
80 }
81
UpdateValueAndAttributes(const JSThread * thread,int entry,const JSTaggedValue & value,const PropertyAttributes & metaData)82 void GlobalDictionary::UpdateValueAndAttributes(const JSThread *thread, int entry, const JSTaggedValue &value,
83 const PropertyAttributes &metaData)
84 {
85 UpdateValue(thread, entry, value);
86 SetAttributes(thread, entry, metaData);
87 }
88
SetAttributes(const JSThread * thread,int entry,const PropertyAttributes & metaData)89 void GlobalDictionary::SetAttributes(const JSThread *thread, int entry, const PropertyAttributes &metaData)
90 {
91 int index = static_cast<int>(GetEntryIndex(entry) + ENTRY_DETAILS_INDEX);
92 Set(thread, index, metaData.GetTaggedValue());
93 }
94
UpdateValue(const JSThread * thread,int entry,const JSTaggedValue & value)95 void GlobalDictionary::UpdateValue(const JSThread *thread, int entry, const JSTaggedValue &value)
96 {
97 SetValue(thread, entry, value);
98 }
99
GetAllKeys(const JSThread * thread,int offset,TaggedArray * keyArray)100 void GlobalDictionary::GetAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray) const
101 {
102 ASSERT_PRINT(offset + EntriesCount() <= static_cast<int>(keyArray->GetLength()),
103 "keyArray capacity is not enough for dictionary");
104 int arrayIndex = 0;
105 int size = Size();
106
107 CVector<std::pair<JSTaggedValue, uint32_t>> sortArr;
108 for (int hashIndex = 0; hashIndex < size; hashIndex++) {
109 JSTaggedValue key = GetKey(hashIndex);
110 if (!key.IsUndefined() && !key.IsHole()) {
111 PropertyAttributes attr = GetAttributes(hashIndex);
112 std::pair<JSTaggedValue, uint32_t> pair(key, attr.GetOffset());
113 sortArr.push_back(pair);
114 }
115 }
116 std::sort(sortArr.begin(), sortArr.end(), CompKey);
117 for (auto entry : sortArr) {
118 JSTaggedValue nameKey = entry.first;
119 keyArray->Set(thread, arrayIndex + offset, nameKey);
120 arrayIndex++;
121 }
122 }
123
GetAllKeysByFilter(const JSThread * thread,uint32_t & keyArrayEffectivelength,TaggedArray * keyArray,uint32_t filter)124 void GlobalDictionary::GetAllKeysByFilter(const JSThread *thread,
125 uint32_t &keyArrayEffectivelength, TaggedArray *keyArray, uint32_t filter) const
126 {
127 ASSERT_PRINT(keyArrayEffectivelength + static_cast<uint32_t>(EntriesCount()) <= keyArray->GetLength(),
128 "keyArray capacity is not enough for dictionary");
129 int size = Size();
130
131 CVector<std::pair<JSTaggedValue, uint32_t>> sortArr;
132 for (int hashIndex = 0; hashIndex < size; hashIndex++) {
133 JSTaggedValue key = GetKey(hashIndex);
134 if (!key.IsUndefined() && !key.IsHole()) {
135 PropertyAttributes attr = GetAttributes(hashIndex);
136 bool bIgnore = FilterHelper::IgnoreKeyByFilter<PropertyAttributes>(attr, filter);
137 if (bIgnore) {
138 continue;
139 }
140 if (key.IsString() && (filter & NATIVE_KEY_SKIP_STRINGS)) {
141 continue;
142 }
143 if (key.IsSymbol() && (filter & NATIVE_KEY_SKIP_SYMBOLS)) {
144 continue;
145 }
146 std::pair<JSTaggedValue, uint32_t> pair(key, attr.GetOffset());
147 sortArr.push_back(pair);
148 }
149 }
150 std::sort(sortArr.begin(), sortArr.end(), CompKey);
151 for (auto entry : sortArr) {
152 JSTaggedValue nameKey = entry.first;
153 keyArray->Set(thread, keyArrayEffectivelength, nameKey);
154 keyArrayEffectivelength++;
155 }
156 }
157
GetEnumAllKeys(const JSThread * thread,int offset,TaggedArray * keyArray,uint32_t * keys)158 void GlobalDictionary::GetEnumAllKeys(const JSThread *thread, int offset, TaggedArray *keyArray,
159 uint32_t *keys) const
160 {
161 ASSERT_PRINT(offset + EntriesCount() <= static_cast<int>(keyArray->GetLength()),
162 "keyArray capacity is not enough for dictionary");
163 int arrayIndex = 0;
164 int size = Size();
165
166 CVector<std::pair<JSTaggedValue, uint32_t>> sortArr;
167 for (int hashIndex = 0; hashIndex < size; hashIndex++) {
168 JSTaggedValue key = GetKey(hashIndex);
169 if (key.IsString()) {
170 PropertyAttributes attr = GetAttributes(hashIndex);
171 if (attr.IsEnumerable()) {
172 std::pair<JSTaggedValue, uint32_t> pair(key, attr.GetOffset());
173 sortArr.push_back(pair);
174 }
175 }
176 }
177 std::sort(sortArr.begin(), sortArr.end(), CompKey);
178 for (const auto &entry : sortArr) {
179 JSTaggedValue nameKey = entry.first;
180 keyArray->Set(thread, arrayIndex + offset, nameKey);
181 arrayIndex++;
182 }
183 *keys += arrayIndex;
184 }
185
CompKey(const std::pair<JSTaggedValue,uint32_t> & a,const std::pair<JSTaggedValue,uint32_t> & b)186 bool GlobalDictionary::CompKey(const std::pair<JSTaggedValue, uint32_t> &a, const std::pair<JSTaggedValue, uint32_t> &b)
187 {
188 return a.second < b.second;
189 }
190
InvalidatePropertyBox(JSThread * thread,const JSHandle<GlobalDictionary> & dictHandle,int entry,const PropertyAttributes & metaData)191 void GlobalDictionary::InvalidatePropertyBox(JSThread *thread, const JSHandle<GlobalDictionary> &dictHandle, int entry,
192 const PropertyAttributes &metaData)
193 {
194 PropertyBox *box = dictHandle->GetBox(entry);
195 PropertyAttributes originAttr = dictHandle->GetAttributes(entry);
196 PropertyAttributes newAttr(metaData);
197
198 ASSERT(!box->GetValue().IsHole());
199 int index = static_cast<int>(originAttr.GetDictionaryOrder());
200 JSHandle<JSTaggedValue> oldValue(thread, box->GetValue());
201 GlobalDictionary::InvalidateAndReplaceEntry(thread, dictHandle, index, oldValue);
202 dictHandle->SetAttributes(thread, entry, newAttr);
203 }
204
InvalidateAndReplaceEntry(JSThread * thread,const JSHandle<GlobalDictionary> & dictHandle,int entry,const JSHandle<JSTaggedValue> & oldValue)205 void GlobalDictionary::InvalidateAndReplaceEntry(JSThread *thread, const JSHandle<GlobalDictionary> &dictHandle,
206 int entry, const JSHandle<JSTaggedValue> &oldValue)
207 {
208 if (!dictHandle->IsValidateBox(entry)) {
209 return;
210 }
211 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
212 // Swap with a copy.
213 JSHandle<PropertyBox> newBox = factory->NewPropertyBox(oldValue);
214 PropertyBox *box = dictHandle->GetBox(entry);
215 PropertyAttributes attr = dictHandle->GetAttributes(entry);
216 if (!attr.IsConfigurable() || box->GetValue().IsHole()) {
217 return;
218 }
219 ASSERT_PRINT(attr.IsConfigurable(), "property must be configurable");
220 ASSERT_PRINT(!box->GetValue().IsHole(), "value must not be hole");
221
222 // Cell is officially mutable henceforth.
223 attr.SetBoxType(PropertyBoxType::MUTABLE);
224 dictHandle->SetAttributes(thread, entry, attr);
225 dictHandle->UpdateValue(thread, entry, newBox.GetTaggedValue());
226 box->Clear(thread);
227 }
228
IsValidateBox(int entry)229 bool GlobalDictionary::IsValidateBox(int entry) const
230 {
231 int index = GetEntryIndex(entry) + ENTRY_VALUE_INDEX;
232 return !Get(index).IsUndefined();
233 }
234 } // namespace ecmascript
235 } // namespace panda
236
237 #endif
238