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